@@ -747,6 +747,151 @@ TEST_P(ByteStringTest, EndsWith) {
747747 GetMediumOrLargeCord ().size () - kSmallByteStringCapacity )));
748748}
749749
750+ TEST_P (ByteStringTest, Find) {
751+ ByteString byte_string = ByteString (GetAllocator (), GetMediumStringView ());
752+
753+ // Find string_view
754+ EXPECT_THAT (byte_string.Find (" A string" ), Optional (0 ));
755+ EXPECT_THAT (
756+ byte_string.Find (" small string optimization!" ),
757+ Optional (GetMediumStringView ().find (" small string optimization!" )));
758+ EXPECT_THAT (byte_string.Find (" not found" ), Eq (absl::nullopt ));
759+ EXPECT_THAT (byte_string.Find (" " ), Optional (0 ));
760+ EXPECT_THAT (byte_string.Find (" " , 3 ), Optional (3 ));
761+ EXPECT_THAT (byte_string.Find (" A string" , 1 ), Eq (absl::nullopt ));
762+
763+ // Find cord
764+ EXPECT_THAT (byte_string.Find (absl::Cord (" A string" )), Optional (0 ));
765+ EXPECT_THAT (
766+ byte_string.Find (absl::Cord (" small string optimization!" )),
767+ Optional (GetMediumStringView ().find (" small string optimization!" )));
768+ EXPECT_THAT (
769+ byte_string.Find (absl::MakeFragmentedCord (
770+ {" A string" , " that is too large for the small string optimization!" ,
771+ " extra" })),
772+ Eq (absl::nullopt ));
773+ EXPECT_THAT (byte_string.Find (GetMediumOrLargeFragmentedCord ()), Optional (0 ));
774+ EXPECT_THAT (byte_string.Find (absl::Cord (" not found" )), Eq (absl::nullopt ));
775+ EXPECT_THAT (byte_string.Find (absl::Cord (" " )), Optional (0 ));
776+ EXPECT_THAT (byte_string.Find (absl::Cord (" " ), 3 ), Optional (3 ));
777+ }
778+
779+ TEST_P (ByteStringTest, FindEdgeCases) {
780+ ByteString empty_byte_string (GetAllocator (), " " );
781+ EXPECT_THAT (empty_byte_string.Find (" a" ), Eq (absl::nullopt ));
782+ EXPECT_THAT (empty_byte_string.Find (" " ), Optional (0 ));
783+ ByteString cord_byte_string =
784+ ByteString (GetAllocator (), GetMediumOrLargeCord ());
785+ EXPECT_THAT (cord_byte_string.Find (" not found" ), Eq (absl::nullopt ));
786+ ByteString byte_string = ByteString (GetAllocator (), GetMediumStringView ());
787+
788+ // Needle longer than haystack.
789+ EXPECT_THAT (byte_string.Find (std::string (byte_string.size () + 1 , ' a' )),
790+ Eq (absl::nullopt ));
791+
792+ // Needle at the end.
793+ absl::string_view suffix = " optimization!" ;
794+ EXPECT_THAT (byte_string.Find (suffix),
795+ Optional (byte_string.size () - suffix.size ()));
796+
797+ // pos at the end.
798+ EXPECT_THAT (byte_string.Find (" a" , byte_string.size ()), Eq (absl::nullopt ));
799+ EXPECT_THAT (byte_string.Find (" " , byte_string.size ()),
800+ Optional (byte_string.size ()));
801+
802+ // Search in a cord-backed ByteString with pos > 0.
803+ EXPECT_THAT (cord_byte_string.Find (" string" , 1 ),
804+ Optional (GetMediumStringView ().find (" string" , 1 )));
805+
806+ // Needle at the end of a cord-backed ByteString.
807+ absl::string_view suffix_sv = " optimization!" ;
808+ EXPECT_THAT (cord_byte_string.Find (suffix_sv),
809+ Optional (cord_byte_string.size () - suffix_sv.size ()));
810+ EXPECT_THAT (cord_byte_string.Find (absl::Cord (suffix_sv)),
811+ Optional (cord_byte_string.size () - suffix_sv.size ()));
812+
813+ // Fragmented needle with empty first chunk.
814+ absl::Cord fragmented_with_empty_chunk;
815+ fragmented_with_empty_chunk.Append (" " );
816+ fragmented_with_empty_chunk.Append (" A string" );
817+ EXPECT_THAT (byte_string.Find (fragmented_with_empty_chunk), Optional (0 ));
818+
819+ // Search with fragmented cord needle on string_view backed ByteString with
820+ // partial match.
821+ ByteString partial_match_haystack (GetAllocator (), " abababac" );
822+ absl::Cord partial_match_needle = absl::MakeFragmentedCord ({" aba" , " c" });
823+ EXPECT_THAT (partial_match_haystack.Find (partial_match_needle), Optional (4 ));
824+
825+ // Search with fragmented cord needle where first chunk is found but not
826+ // enough space for the rest.
827+ ByteString short_haystack (GetAllocator (), " abcdefg" );
828+ absl::Cord needle_too_long = absl::MakeFragmentedCord ({" ef" , " gh" });
829+ EXPECT_THAT (short_haystack.Find (needle_too_long), Eq (absl::nullopt ));
830+
831+ // Search with a fragmented empty cord.
832+ absl::Cord fragmented_empty_cord = absl::MakeFragmentedCord ({" " , " " });
833+ EXPECT_THAT (byte_string.Find (fragmented_empty_cord), Optional (0 ));
834+ EXPECT_THAT (byte_string.Find (fragmented_empty_cord, 3 ), Optional (3 ));
835+
836+ // Search for suffix in a fragmented cord.
837+ ByteString fragmented_cord_byte_string (GetAllocator (),
838+ GetMediumOrLargeFragmentedCord ());
839+ EXPECT_THAT (fragmented_cord_byte_string.Find (suffix_sv),
840+ Optional (fragmented_cord_byte_string.size () - suffix_sv.size ()));
841+ EXPECT_THAT (fragmented_cord_byte_string.Find (absl::Cord (suffix_sv)),
842+ Optional (fragmented_cord_byte_string.size () - suffix_sv.size ()));
843+ }
844+
845+ #ifndef NDEBUG
846+ TEST_P (ByteStringTest, FindOutOfBounds) {
847+ ByteString byte_string = ByteString (GetAllocator (), " test" );
848+ EXPECT_DEATH (byte_string.Find (" t" , 5 ), _);
849+ }
850+ #endif
851+
852+ TEST_P (ByteStringTest, Substring) {
853+ // small byte_string substring
854+ ByteString small_byte_string =
855+ ByteString (GetAllocator (), GetSmallStringView ());
856+ EXPECT_EQ (small_byte_string.Substring (1 , 5 ),
857+ GetSmallStringView ().substr (1 , 4 ));
858+ EXPECT_EQ (small_byte_string.Substring (0 , small_byte_string.size ()),
859+ GetSmallStringView ());
860+ EXPECT_EQ (small_byte_string.Substring (1 , 1 ), " " );
861+ // medium byte_string substring
862+ ByteString medium_byte_string =
863+ ByteString (GetAllocator (), GetMediumStringView ());
864+ EXPECT_EQ (medium_byte_string.Substring (2 , 12 ),
865+ GetMediumStringView ().substr (2 , 10 ));
866+ EXPECT_EQ (medium_byte_string.Substring (0 , medium_byte_string.size ()),
867+ GetMediumStringView ());
868+ // large byte_string substring
869+ ByteString large_byte_string =
870+ ByteString (GetAllocator (), GetMediumOrLargeCord ());
871+ EXPECT_EQ (large_byte_string.Substring (3 , 15 ),
872+ GetMediumOrLargeCord ().Subcord (3 , 12 ));
873+ EXPECT_EQ (large_byte_string.Substring (0 , large_byte_string.size ()),
874+ GetMediumOrLargeCord ());
875+ // substring with one parameter
876+ ByteString tacocat_byte_string = ByteString (GetAllocator (), " tacocat" );
877+ EXPECT_EQ (tacocat_byte_string.Substring (4 ), " cat" );
878+ }
879+
880+ TEST_P (ByteStringTest, SubstringEdgeCases) {
881+ ByteString byte_string = ByteString (GetAllocator (), GetSmallStringView ());
882+ EXPECT_EQ (byte_string.Substring (byte_string.size (), byte_string.size ()), " " );
883+ EXPECT_EQ (byte_string.Substring (0 , 0 ), " " );
884+ }
885+
886+ #ifndef NDEBUG
887+ TEST_P (ByteStringTest, SubstringOutOfBounds) {
888+ ByteString byte_string = ByteString (GetAllocator (), " test" );
889+ EXPECT_DEATH (static_cast <void >(byte_string.Substring (5 , 5 )), _);
890+ EXPECT_DEATH (static_cast <void >(byte_string.Substring (0 , 5 )), _);
891+ EXPECT_DEATH (static_cast <void >(byte_string.Substring (3 , 2 )), _);
892+ }
893+ #endif
894+
750895TEST_P (ByteStringTest, RemovePrefixSmall) {
751896 ByteString byte_string = ByteString (GetAllocator (), GetSmallStringView ());
752897 byte_string.RemovePrefix (1 );
0 commit comments