Skip to content

Commit 13c5fa9

Browse files
committed
More coverage
1 parent 554958b commit 13c5fa9

File tree

2 files changed

+364
-8
lines changed

2 files changed

+364
-8
lines changed

modules/yup_core/text/yup_String.cpp

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2031,17 +2031,32 @@ bool String::containsNonWhitespaceChars() const noexcept
20312031

20322032
String String::reversed() const
20332033
{
2034-
auto end = text.findTerminatingNull();
2035-
String t;
2034+
if (isEmpty())
2035+
return *this;
20362036

2037-
while (end > text)
2038-
{
2039-
--end;
2037+
// Count characters first to know how much space we need
2038+
int numChars = length();
2039+
if (numChars <= 0)
2040+
return {};
20402041

2041-
t.append (end, 1);
2042-
}
2042+
// Create array to store character positions
2043+
HeapBlock<CharPointerType> positions (numChars);
20432044

2044-
return t;
2045+
// Build the result by iterating backwards through characters
2046+
StringCreationHelper builder (text);
2047+
2048+
// Store the start position of each character
2049+
int index = 0;
2050+
for (auto it = text; ! it.isEmpty() && index < numChars; ++it, ++index)
2051+
positions[index] = it;
2052+
2053+
// Now write characters in reverse order
2054+
for (int i = index - 1; i >= 0; --i)
2055+
builder.write (*positions[i]);
2056+
2057+
builder.write (0); // null terminator
2058+
2059+
return String (std::move (builder.result));
20452060
}
20462061

20472062
String String::formattedRaw (const char* pf, ...)

tests/yup_core/yup_String.cpp

Lines changed: 341 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,3 +678,344 @@ TEST_F (StringTests, Loops)
678678
for (auto c : str)
679679
EXPECT_EQ (c, parts[index++]);
680680
}
681+
682+
TEST_F (StringTests, LineManipulation)
683+
{
684+
String multiline ("line1\nline2\n line3\n\nline4");
685+
686+
// Test indentLines
687+
String indented = multiline.indentLines (" ");
688+
EXPECT_EQ (indented, String (" line1\n line2\n line3\n\n line4"));
689+
690+
String indentedWithBlanks = multiline.indentLines (">>", true);
691+
EXPECT_EQ (indentedWithBlanks, String (">>line1\n>>line2\n>> line3\n>>\n>>line4"));
692+
693+
// Test dedentLines
694+
String indentedText (" line1\n line2\n line3\n line4");
695+
String dedented = indentedText.dedentLines();
696+
EXPECT_EQ (dedented, String ("line1\nline2\n line3\nline4"));
697+
698+
// Test dedentLines with mixed indentation
699+
String mixedIndent (" \tline1\n \tline2\n \t line3");
700+
String dedentedMixed = mixedIndent.dedentLines();
701+
EXPECT_EQ (dedentedMixed, String ("line1\nline2\n line3"));
702+
}
703+
704+
TEST_F (StringTests, PaddingMethods)
705+
{
706+
String short_str ("abc");
707+
708+
// Test paddedLeft
709+
EXPECT_EQ (short_str.paddedLeft (' ', 10), String (" abc"));
710+
EXPECT_EQ (short_str.paddedLeft ('*', 5), String ("**abc"));
711+
EXPECT_EQ (short_str.paddedLeft ('-', 3), String ("abc")); // No padding needed
712+
EXPECT_EQ (short_str.paddedLeft ('0', 1), String ("abc")); // Shorter than minimum
713+
714+
// Test paddedRight
715+
EXPECT_EQ (short_str.paddedRight (' ', 10), String ("abc "));
716+
EXPECT_EQ (short_str.paddedRight ('*', 5), String ("abc**"));
717+
EXPECT_EQ (short_str.paddedRight ('-', 3), String ("abc")); // No padding needed
718+
EXPECT_EQ (short_str.paddedRight ('0', 1), String ("abc")); // Shorter than minimum
719+
}
720+
721+
TEST_F (StringTests, CharacterTrimming)
722+
{
723+
String test_str ("...Hello World!!!");
724+
725+
// Test trimCharactersAtStart
726+
EXPECT_EQ (test_str.trimCharactersAtStart ("."), String ("Hello World!!!"));
727+
EXPECT_EQ (test_str.trimCharactersAtStart (".*"), String ("Hello World!!!"));
728+
EXPECT_EQ (String (" \t text").trimCharactersAtStart (" \t"), String ("text"));
729+
730+
// Test trimCharactersAtEnd
731+
EXPECT_EQ (test_str.trimCharactersAtEnd ("!"), String ("...Hello World"));
732+
EXPECT_EQ (test_str.trimCharactersAtEnd ("!."), String ("...Hello World"));
733+
EXPECT_EQ (String ("text \t ").trimCharactersAtEnd (" \t"), String ("text"));
734+
735+
// Test with empty string
736+
EXPECT_EQ (String().trimCharactersAtStart ("abc"), String());
737+
EXPECT_EQ (String().trimCharactersAtEnd ("abc"), String());
738+
}
739+
740+
TEST_F (StringTests, SectionReplacement)
741+
{
742+
String base ("Hello World");
743+
744+
// Test replaceSection
745+
EXPECT_EQ (base.replaceSection (0, 5, "Hi"), String ("Hi World"));
746+
EXPECT_EQ (base.replaceSection (6, 5, "Universe"), String ("Hello Universe"));
747+
EXPECT_EQ (base.replaceSection (5, 1, ""), String ("HelloWorld"));
748+
EXPECT_EQ (base.replaceSection (0, 0, "Well, "), String ("Well, Hello World"));
749+
750+
// Test replaceFirstOccurrenceOf
751+
String repeated ("abc abc abc");
752+
EXPECT_EQ (repeated.replaceFirstOccurrenceOf ("abc", "xyz"), String ("xyz abc abc"));
753+
EXPECT_EQ (repeated.replaceFirstOccurrenceOf ("abc", "xyz", true), String ("xyz abc abc"));
754+
EXPECT_EQ (repeated.replaceFirstOccurrenceOf ("ABC", "xyz", true), String ("xyz abc abc"));
755+
EXPECT_EQ (repeated.replaceFirstOccurrenceOf ("ABC", "xyz", false), String ("abc abc abc"));
756+
EXPECT_EQ (repeated.replaceFirstOccurrenceOf ("def", "xyz"), String ("abc abc abc"));
757+
}
758+
759+
TEST_F (StringTests, StringReversing)
760+
{
761+
// Test reversed with basic ASCII strings
762+
EXPECT_EQ (String ("hello").reversed(), String ("olleh"));
763+
EXPECT_EQ (String ("a").reversed(), String ("a"));
764+
EXPECT_EQ (String().reversed(), String());
765+
EXPECT_EQ (String ("12345").reversed(), String ("54321"));
766+
767+
// Test with Unicode characters - this is the critical test for UTF-8 handling
768+
String unicode_str (L"café");
769+
String reversed_unicode = unicode_str.reversed();
770+
EXPECT_EQ (reversed_unicode, String (L"éfac")); // Should correctly reverse Unicode characters
771+
772+
// Test with more complex Unicode strings
773+
String unicode_complex (CharPointer_UTF8 ("Hello, 世界!"));
774+
String reversed_complex = unicode_complex.reversed();
775+
EXPECT_EQ (reversed_complex, String (CharPointer_UTF8 ("!界世 ,olleH")));
776+
777+
// Test with emojis and other complex Unicode
778+
String emoji_str (CharPointer_UTF8 ("🌟⭐"));
779+
String reversed_emoji = emoji_str.reversed();
780+
EXPECT_EQ (reversed_emoji, String (CharPointer_UTF8 ("⭐🌟")));
781+
782+
// Test reversibility (reversing twice should give original)
783+
String original (CharPointer_UTF8 ("Test string with UTF-8: café"));
784+
String double_reversed = original.reversed().reversed();
785+
EXPECT_EQ (double_reversed, original);
786+
787+
// Test with mixed ASCII and Unicode
788+
String mixed (CharPointer_UTF8 ("abc世界def"));
789+
String reversed_mixed = mixed.reversed();
790+
EXPECT_EQ (reversed_mixed, String (CharPointer_UTF8 ("fed界世cba")));
791+
}
792+
793+
TEST_F (StringTests, RepeatedString)
794+
{
795+
// Test repeatedString
796+
EXPECT_EQ (String::repeatedString ("abc", 3), String ("abcabcabc"));
797+
EXPECT_EQ (String::repeatedString ("x", 5), String ("xxxxx"));
798+
EXPECT_EQ (String::repeatedString ("hello", 0), String());
799+
EXPECT_EQ (String::repeatedString ("", 10), String());
800+
EXPECT_EQ (String::repeatedString ("test", 1), String ("test"));
801+
}
802+
803+
TEST_F (StringTests, BufferCopyMethods)
804+
{
805+
String test_str (L"Hello, 世界!");
806+
807+
// Test copyToUTF8
808+
char utf8_buffer[100];
809+
size_t utf8_bytes = test_str.copyToUTF8 (utf8_buffer, sizeof (utf8_buffer));
810+
EXPECT_GT (utf8_bytes, 0);
811+
EXPECT_EQ (String::fromUTF8 (utf8_buffer), test_str);
812+
813+
// Test getNumBytesAsUTF8
814+
size_t required_bytes = test_str.getNumBytesAsUTF8();
815+
EXPECT_GT (required_bytes, test_str.length()); // Should be more due to unicode chars
816+
817+
// Test copyToUTF16
818+
CharPointer_UTF16::CharType utf16_buffer[100];
819+
size_t utf16_bytes = test_str.copyToUTF16 (utf16_buffer, sizeof (utf16_buffer));
820+
EXPECT_GT (utf16_bytes, 0);
821+
822+
// Test copyToUTF32
823+
CharPointer_UTF32::CharType utf32_buffer[100];
824+
size_t utf32_bytes = test_str.copyToUTF32 (utf32_buffer, sizeof (utf32_buffer));
825+
EXPECT_GT (utf32_bytes, 0);
826+
827+
// Test with null buffer (should return required size)
828+
size_t utf8_required = test_str.copyToUTF8 (nullptr, 0);
829+
EXPECT_GT (utf8_required, 0);
830+
}
831+
832+
TEST_F (StringTests, PreallocationAndReferenceCounting)
833+
{
834+
String str1 ("test");
835+
String str2 = str1; // This should share the same data
836+
837+
// Test getReferenceCount
838+
EXPECT_EQ (str1.getReferenceCount(), str2.getReferenceCount());
839+
EXPECT_GE (str1.getReferenceCount(), 2);
840+
841+
// Test preallocateBytes
842+
String growing_str;
843+
growing_str.preallocateBytes (1000);
844+
// After preallocation, adding strings should be more efficient
845+
for (int i = 0; i < 10; ++i)
846+
growing_str += "some text ";
847+
EXPECT_GT (growing_str.length(), 0);
848+
}
849+
850+
TEST_F (StringTests, FormattedStrings)
851+
{
852+
// Test formatted (basic cases)
853+
String formatted_str = String::formatted ("Hello %s", "World");
854+
EXPECT_TRUE (formatted_str.contains ("Hello"));
855+
EXPECT_TRUE (formatted_str.contains ("World"));
856+
857+
String formatted_int = String::formatted ("Number: %d", 42);
858+
EXPECT_TRUE (formatted_int.contains ("Number"));
859+
EXPECT_TRUE (formatted_int.contains ("42"));
860+
861+
String formatted_float = String::formatted ("Value: %.2f", 3.14159);
862+
EXPECT_TRUE (formatted_float.contains ("Value"));
863+
EXPECT_TRUE (formatted_float.contains ("3.14"));
864+
}
865+
866+
TEST_F (StringTests, StringCreationFromData)
867+
{
868+
// Test createStringFromData
869+
const char* ascii_data = "Hello World";
870+
String from_ascii = String::createStringFromData (ascii_data, (int) strlen (ascii_data));
871+
EXPECT_EQ (from_ascii, String ("Hello World"));
872+
873+
// Test with UTF-8 data
874+
const char* utf8_data = "Hello, 世界!";
875+
String from_utf8 = String::createStringFromData (utf8_data, (int) strlen (utf8_data));
876+
EXPECT_TRUE (from_utf8.contains ("Hello"));
877+
EXPECT_TRUE (from_utf8.contains ("世界"));
878+
879+
// Test with zero size
880+
String empty_from_data = String::createStringFromData (ascii_data, 0);
881+
EXPECT_TRUE (empty_from_data.isEmpty());
882+
}
883+
884+
TEST_F (StringTests, FromUTF8)
885+
{
886+
// Test fromUTF8
887+
const char* utf8_text = "Hello, 世界!";
888+
String from_utf8 = String::fromUTF8 (utf8_text);
889+
EXPECT_TRUE (from_utf8.contains ("Hello"));
890+
EXPECT_TRUE (from_utf8.contains ("世界"));
891+
892+
// Test with explicit length
893+
String partial_utf8 = String::fromUTF8 (utf8_text, 5);
894+
EXPECT_EQ (partial_utf8, String ("Hello"));
895+
896+
// Test with null input
897+
String null_utf8 = String::fromUTF8 (nullptr);
898+
EXPECT_TRUE (null_utf8.isEmpty());
899+
}
900+
901+
TEST_F (StringTests, NaturalComparison)
902+
{
903+
// Test compareNatural
904+
EXPECT_EQ (String ("file1.txt").compareNatural ("file1.txt"), 0);
905+
EXPECT_LT (String ("file1.txt").compareNatural ("file10.txt"), 0);
906+
EXPECT_GT (String ("file10.txt").compareNatural ("file2.txt"), 0);
907+
EXPECT_EQ (String ("abc").compareNatural ("ABC", false), 0); // Case insensitive
908+
EXPECT_NE (String ("abc").compareNatural ("ABC", true), 0); // Case sensitive
909+
910+
// Test with numbers
911+
EXPECT_LT (String ("version1.2").compareNatural ("version1.10"), 0);
912+
EXPECT_GT (String ("version2.0").compareNatural ("version1.10"), 0);
913+
}
914+
915+
TEST_F (StringTests, StandardLibraryIntegration)
916+
{
917+
// Test std::string integration
918+
std::string std_str = "Hello from std::string";
919+
String yup_str (std_str);
920+
EXPECT_EQ (yup_str.toStdString(), std_str);
921+
922+
// Test std::wstring integration
923+
std::wstring wide_str = L"Hello from std::wstring";
924+
String yup_wide_str (wide_str);
925+
EXPECT_TRUE (yup_wide_str.contains ("Hello"));
926+
927+
// Test std::string_view integration
928+
std::string_view string_view = "Hello from string_view";
929+
String yup_view_str (string_view);
930+
EXPECT_EQ (yup_view_str, String ("Hello from string_view"));
931+
932+
// Test std::wstring_view integration
933+
std::wstring_view wide_view = L"Hello from wstring_view";
934+
String yup_wide_view_str (wide_view);
935+
EXPECT_TRUE (yup_wide_view_str.contains ("Hello"));
936+
}
937+
938+
TEST_F (StringTests, CaseConversionEdgeCases)
939+
{
940+
// Test toUpperCase with edge cases
941+
String mixed_case (L"Hello, 世界! 123");
942+
String upper_case = mixed_case.toUpperCase();
943+
EXPECT_EQ (upper_case, String (L"HELLO, 世界! 123"));
944+
945+
// Test toLowerCase with edge cases
946+
String lower_case = mixed_case.toLowerCase();
947+
EXPECT_EQ (lower_case, String (L"hello, 世界! 123"));
948+
949+
// Test with empty string
950+
EXPECT_EQ (String().toUpperCase(), String());
951+
EXPECT_EQ (String().toLowerCase(), String());
952+
953+
// Test with numbers only
954+
String numbers ("12345");
955+
EXPECT_EQ (numbers.toUpperCase(), String ("12345"));
956+
EXPECT_EQ (numbers.toLowerCase(), String ("12345"));
957+
}
958+
959+
TEST_F (StringTests, AdditionalUtilityMethods)
960+
{
961+
// Test swapWith
962+
String str1 ("Hello");
963+
String str2 ("World");
964+
String original1 = str1;
965+
String original2 = str2;
966+
967+
str1.swapWith (str2);
968+
EXPECT_EQ (str1, original2);
969+
EXPECT_EQ (str2, original1);
970+
971+
// Test hash method
972+
String hash_test ("test string");
973+
size_t hash1 = hash_test.hash();
974+
size_t hash2 = String ("test string").hash();
975+
size_t hash3 = String ("different string").hash();
976+
977+
EXPECT_EQ (hash1, hash2); // Same strings should have same hash
978+
EXPECT_NE (hash1, hash3); // Different strings should have different hashes
979+
980+
// Test begin/end iterators
981+
String iter_test ("abc");
982+
auto it = iter_test.begin();
983+
EXPECT_EQ (*it, 'a');
984+
++it;
985+
EXPECT_EQ (*it, 'b');
986+
++it;
987+
EXPECT_EQ (*it, 'c');
988+
++it;
989+
EXPECT_EQ (it, iter_test.end());
990+
}
991+
992+
TEST_F (StringTests, EdgeCasesAndBoundaryConditions)
993+
{
994+
// Test with very long strings
995+
String long_str = String::repeatedString ("a", 10000);
996+
EXPECT_EQ (long_str.length(), 10000);
997+
EXPECT_TRUE (long_str.startsWith ("aaa"));
998+
EXPECT_TRUE (long_str.endsWith ("aaa"));
999+
1000+
// Test with single character
1001+
String single_char ("x");
1002+
EXPECT_EQ (single_char.length(), 1);
1003+
EXPECT_EQ (single_char[0], 'x');
1004+
EXPECT_EQ (single_char.getLastCharacter(), 'x');
1005+
1006+
// Test boundary conditions for substring
1007+
String boundary_test ("hello");
1008+
EXPECT_EQ (boundary_test.substring (-5, 10), String ("hello"));
1009+
EXPECT_EQ (boundary_test.substring (0, 0), String());
1010+
EXPECT_EQ (boundary_test.substring (5, 5), String());
1011+
EXPECT_EQ (boundary_test.substring (100, 200), String());
1012+
1013+
// Test with null characters
1014+
String null_char_test = String::charToString (0);
1015+
EXPECT_EQ (null_char_test, String());
1016+
1017+
// Test very large numbers
1018+
String large_num (std::numeric_limits<long long>::max());
1019+
EXPECT_GT (large_num.length(), 0);
1020+
EXPECT_EQ (large_num.getLargeIntValue(), std::numeric_limits<long long>::max());
1021+
}

0 commit comments

Comments
 (0)