Skip to content

Commit 05ca6ca

Browse files
committed
More tests
1 parent ac00e77 commit 05ca6ca

4 files changed

Lines changed: 282 additions & 3 deletions

File tree

modules/yup_graphics/fonts/yup_StyledText.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,17 @@ StyledText::TextModifier StyledText::startUpdate()
178178
void StyledText::clear()
179179
{
180180
styledTexts.clear();
181+
shape = {};
182+
lines = {};
183+
orderedLines.clear();
184+
ellipsisRun = {};
181185
styles.clear();
182-
183-
update();
186+
renderStyles.clear();
187+
glyphLookup.clear();
188+
bounds = {};
189+
paragraphYOffsets.clear();
190+
defaultLineHeight = 0.0f;
191+
isDirty = false;
184192
}
185193

186194
//==============================================================================

modules/yup_gui/widgets/yup_TextEditor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ void TextEditor::insertText (const String& textToInsert, NotificationType notifi
8080
if (readOnly)
8181
return;
8282

83-
deleteSelectedText();
83+
deleteSelectedText (dontSendNotification);
8484

8585
String filteredText = textToInsert.removeCharacters ("\r");
8686
if (! multiLine)

tests/yup_graphics/yup_StyledText.cpp

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,32 @@
2525

2626
using namespace yup;
2727

28+
namespace
29+
{
30+
File getStyledTextTestFontFile()
31+
{
32+
return
33+
#if YUP_EMSCRIPTEN
34+
File ("/")
35+
#else
36+
File (__FILE__)
37+
.getParentDirectory()
38+
.getParentDirectory()
39+
#endif
40+
.getChildFile ("data")
41+
.getChildFile ("fonts")
42+
.getChildFile ("Linefont-VariableFont_wdth,wght.ttf");
43+
}
44+
45+
Font loadStyledTextTestFont (float height = 16.0f)
46+
{
47+
Font font;
48+
auto result = font.loadFromFile (getStyledTextTestFontFile());
49+
EXPECT_TRUE (result.wasOk());
50+
return font.withHeight (height);
51+
}
52+
} // namespace
53+
2854
// ==============================================================================
2955
// Default Constructor and State Tests
3056
// ==============================================================================
@@ -963,3 +989,121 @@ TEST (StyledTextTests, AllAlignmentCombinations)
963989
}
964990
}
965991
}
992+
993+
// ==============================================================================
994+
// Shaped Text Tests
995+
// ==============================================================================
996+
997+
TEST (StyledTextTests, AppendingTextProducesLinesBoundsAndRenderStyles)
998+
{
999+
StyledText text;
1000+
auto font = loadStyledTextTestFont();
1001+
const String testText = "Hello shaped text";
1002+
1003+
{
1004+
auto modifier = text.startUpdate();
1005+
modifier.setMaxSize ({ 400.0f, 200.0f });
1006+
modifier.appendText (testText, font);
1007+
}
1008+
1009+
EXPECT_FALSE (text.isEmpty());
1010+
EXPECT_FALSE (text.needsUpdate());
1011+
EXPECT_FALSE (text.getOrderedLines().empty());
1012+
EXPECT_FALSE (text.getRenderStyles().empty());
1013+
1014+
const auto bounds = text.getComputedTextBounds();
1015+
EXPECT_GT (bounds.getWidth(), 0.0f);
1016+
EXPECT_GT (bounds.getHeight(), 0.0f);
1017+
1018+
EXPECT_TRUE (text.isValidCharacterIndex (0));
1019+
EXPECT_TRUE (text.isValidCharacterIndex (testText.length()));
1020+
EXPECT_FALSE (text.isValidCharacterIndex (testText.length() + 1));
1021+
1022+
EXPECT_FALSE (text.getCaretBounds (0).isEmpty());
1023+
EXPECT_FALSE (text.getCaretBounds (testText.length()).isEmpty());
1024+
}
1025+
1026+
TEST (StyledTextTests, CaretBoundsHandleNewlinesEmptyParagraphsAndTrailingNewline)
1027+
{
1028+
StyledText text;
1029+
auto font = loadStyledTextTestFont();
1030+
1031+
{
1032+
auto modifier = text.startUpdate();
1033+
modifier.setMaxSize ({ 400.0f, 400.0f });
1034+
modifier.setWrap (StyledText::wrap);
1035+
modifier.appendText ("first\n\nlast\n", font);
1036+
}
1037+
1038+
const auto firstLineNewline = text.getCaretBounds (5);
1039+
const auto emptyParagraphNewline = text.getCaretBounds (6);
1040+
const auto trailingNewline = text.getCaretBounds (12);
1041+
1042+
ASSERT_FALSE (firstLineNewline.isEmpty());
1043+
ASSERT_FALSE (emptyParagraphNewline.isEmpty());
1044+
ASSERT_FALSE (trailingNewline.isEmpty());
1045+
1046+
EXPECT_GT (emptyParagraphNewline.getY(), firstLineNewline.getY());
1047+
EXPECT_GT (trailingNewline.getY(), emptyParagraphNewline.getY());
1048+
}
1049+
1050+
TEST (StyledTextTests, SelectionRectanglesCoverMultipleVisualLines)
1051+
{
1052+
StyledText text;
1053+
auto font = loadStyledTextTestFont();
1054+
1055+
{
1056+
auto modifier = text.startUpdate();
1057+
modifier.setMaxSize ({ 400.0f, 400.0f });
1058+
modifier.appendText ("one\ntwo\nthree", font);
1059+
}
1060+
1061+
const auto rectangles = text.getSelectionRectangles (1, 11);
1062+
1063+
ASSERT_GE (rectangles.size(), 3u);
1064+
EXPECT_LT (rectangles[0].getY(), rectangles[1].getY());
1065+
EXPECT_LT (rectangles[1].getY(), rectangles[2].getY());
1066+
}
1067+
1068+
TEST (StyledTextTests, ClearRemovesPreviouslyShapedLineAndRenderData)
1069+
{
1070+
StyledText text;
1071+
auto font = loadStyledTextTestFont();
1072+
1073+
{
1074+
auto modifier = text.startUpdate();
1075+
modifier.setMaxSize ({ 400.0f, 400.0f });
1076+
modifier.appendText ("temporary text", font);
1077+
}
1078+
1079+
ASSERT_FALSE (text.getOrderedLines().empty());
1080+
ASSERT_FALSE (text.getRenderStyles().empty());
1081+
ASSERT_GT (text.getComputedTextBounds().getWidth(), 0.0f);
1082+
1083+
{
1084+
auto modifier = text.startUpdate();
1085+
modifier.clear();
1086+
}
1087+
1088+
EXPECT_TRUE (text.isEmpty());
1089+
EXPECT_TRUE (text.getOrderedLines().empty());
1090+
EXPECT_TRUE (text.getRenderStyles().empty());
1091+
EXPECT_TRUE (text.getComputedTextBounds().isEmpty());
1092+
EXPECT_TRUE (text.isValidCharacterIndex (0));
1093+
EXPECT_FALSE (text.isValidCharacterIndex (1));
1094+
}
1095+
1096+
TEST (StyledTextTests, AdjacentLineMovementClampsAtDocumentEdges)
1097+
{
1098+
StyledText text;
1099+
auto font = loadStyledTextTestFont();
1100+
1101+
{
1102+
auto modifier = text.startUpdate();
1103+
modifier.setMaxSize ({ 400.0f, 400.0f });
1104+
modifier.appendText ("one\ntwo", font);
1105+
}
1106+
1107+
EXPECT_EQ (0, text.getGlyphIndexOnAdjacentLine (0, false));
1108+
EXPECT_EQ (7, text.getGlyphIndexOnAdjacentLine (7, true));
1109+
}

tests/yup_gui/yup_TextEditor.cpp

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,47 @@ namespace
2929
{
3030
constexpr auto kSingleText = "Hello World";
3131
constexpr auto kMultilineText = "Line 1\nLine 2\nLine 3";
32+
33+
File getTextEditorTestFontFile()
34+
{
35+
return File (__FILE__)
36+
.getParentDirectory()
37+
.getParentDirectory()
38+
.getChildFile ("data")
39+
.getChildFile ("fonts")
40+
.getChildFile ("Linefont-VariableFont_wdth,wght.ttf");
41+
}
3242
} // namespace
3343

3444
class TextEditorTests : public ::testing::Test
3545
{
3646
protected:
3747
void SetUp() override
3848
{
49+
oldTheme = ApplicationTheme::getGlobalTheme();
50+
51+
theme = new ApplicationTheme();
52+
53+
Font font;
54+
auto result = font.loadFromFile (getTextEditorTestFontFile());
55+
ASSERT_TRUE (result.wasOk());
56+
57+
theme->setDefaultFont (std::move (font));
58+
ApplicationTheme::setGlobalTheme (theme);
59+
3960
editor = std::make_unique<TextEditor> ("testEditor");
4061
}
4162

4263
void TearDown() override
4364
{
4465
editor.reset();
66+
ApplicationTheme::setGlobalTheme (oldTheme.get());
67+
theme = nullptr;
68+
oldTheme = nullptr;
4569
}
4670

71+
ApplicationTheme::Ptr theme;
72+
ApplicationTheme::Ptr oldTheme;
4773
std::unique_ptr<TextEditor> editor;
4874
};
4975

@@ -63,6 +89,13 @@ TEST_F (TextEditorTests, SetTextUpdatesContent)
6389
EXPECT_EQ (0, editor->getCaretPosition());
6490
}
6591

92+
TEST_F (TextEditorTests, SetTextStripsCarriageReturns)
93+
{
94+
editor->setText ("Hello\r\nWorld\r");
95+
96+
EXPECT_EQ (String ("Hello\nWorld"), editor->getText());
97+
}
98+
6699
TEST_F (TextEditorTests, CaretPositionHandling)
67100
{
68101
editor->setText (kSingleText);
@@ -106,6 +139,55 @@ TEST_F (TextEditorTests, TextInsertion)
106139
EXPECT_EQ (11, editor->getCaretPosition());
107140
}
108141

142+
TEST_F (TextEditorTests, InsertTextNormalizesNewlinesInSingleLineMode)
143+
{
144+
editor->setText ("Hello");
145+
editor->setCaretPosition (5);
146+
147+
editor->insertText ("\r\nWorld");
148+
149+
EXPECT_EQ (String ("Hello World"), editor->getText());
150+
EXPECT_EQ (11, editor->getCaretPosition());
151+
}
152+
153+
TEST_F (TextEditorTests, InsertTextReplacesSelectionWithSingleNotification)
154+
{
155+
editor->setText ("Hello brave world", dontSendNotification);
156+
editor->setSelection (Range<int> (6, 11));
157+
158+
int callCount = 0;
159+
editor->onTextChange = [&callCount]
160+
{
161+
++callCount;
162+
};
163+
164+
editor->insertText ("small", sendNotification);
165+
166+
EXPECT_EQ (String ("Hello small world"), editor->getText());
167+
EXPECT_EQ (11, editor->getCaretPosition());
168+
EXPECT_FALSE (editor->hasSelection());
169+
EXPECT_EQ (1, callCount);
170+
}
171+
172+
TEST_F (TextEditorTests, InsertTextReplacingSelectionHonorsDontSendNotification)
173+
{
174+
editor->setText ("abcdef", dontSendNotification);
175+
editor->setSelection (Range<int> (1, 5));
176+
177+
int callCount = 0;
178+
editor->onTextChange = [&callCount]
179+
{
180+
++callCount;
181+
};
182+
183+
editor->insertText ("X", dontSendNotification);
184+
185+
EXPECT_EQ (String ("aXf"), editor->getText());
186+
EXPECT_EQ (2, editor->getCaretPosition());
187+
EXPECT_FALSE (editor->hasSelection());
188+
EXPECT_EQ (0, callCount);
189+
}
190+
109191
TEST_F (TextEditorTests, TextDeletion)
110192
{
111193
editor->setText (kSingleText);
@@ -126,6 +208,19 @@ TEST_F (TextEditorTests, MultiLineMode)
126208
EXPECT_EQ (String (kMultilineText), editor->getText());
127209
}
128210

211+
TEST_F (TextEditorTests, StyledTextWrapModeFollowsMultiLineMode)
212+
{
213+
editor->setBounds (0.0f, 0.0f, 200.0f, 100.0f);
214+
editor->setText ("A long enough line to exercise styled text setup");
215+
216+
editor->getCaretBounds();
217+
EXPECT_EQ (StyledText::noWrap, editor->getStyledText().getWrap());
218+
219+
editor->setMultiLine (true);
220+
editor->moveCaretDown();
221+
EXPECT_EQ (StyledText::wrap, editor->getStyledText().getWrap());
222+
}
223+
129224
TEST_F (TextEditorTests, ReadOnlyMode)
130225
{
131226
editor->setText (kSingleText);
@@ -283,6 +378,38 @@ TEST_F (TextEditorTests, MoveCaretLeftRight)
283378
EXPECT_EQ (String ("o"), editor->getSelectedText());
284379
}
285380

381+
TEST_F (TextEditorTests, MoveCaretToLineBoundariesInMultilineText)
382+
{
383+
editor->setMultiLine (true);
384+
editor->setText ("abc\ndefg\nhi");
385+
editor->setCaretPosition (6);
386+
387+
editor->moveCaretToStartOfLine();
388+
EXPECT_EQ (4, editor->getCaretPosition());
389+
EXPECT_FALSE (editor->hasSelection());
390+
391+
editor->setCaretPosition (6);
392+
editor->moveCaretToEndOfLine (true);
393+
EXPECT_EQ (8, editor->getCaretPosition());
394+
EXPECT_TRUE (editor->hasSelection());
395+
EXPECT_EQ (String ("fg"), editor->getSelectedText());
396+
}
397+
398+
TEST_F (TextEditorTests, ControlArrowKeysMoveAcrossWords)
399+
{
400+
editor->setText ("Hello, brave world");
401+
editor->setCaretPosition (7);
402+
403+
editor->keyDown (KeyPress (KeyPress::rightKey, KeyModifiers (KeyModifiers::controlMask)), {});
404+
EXPECT_EQ (12, editor->getCaretPosition());
405+
EXPECT_FALSE (editor->hasSelection());
406+
407+
editor->keyDown (KeyPress (KeyPress::leftKey, KeyModifiers (KeyModifiers::controlMask | KeyModifiers::shiftMask)), {});
408+
EXPECT_EQ (7, editor->getCaretPosition());
409+
EXPECT_TRUE (editor->hasSelection());
410+
EXPECT_EQ (String ("brave"), editor->getSelectedText());
411+
}
412+
286413
/* TODO: moveCaretToWordEnd/moveCaretToWordStart is private
287414
TEST_F (TextEditorTests, WordNavigation)
288415
{

0 commit comments

Comments
 (0)