+TEST(String, stripLeftMargin_really_empty) {
+ auto input = "";
+ auto expected = "";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_empty) {
+ auto input = R"TEXT(
+ )TEXT";
+ auto expected = "";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_only_whitespace) {
+ // using ~ as a marker
+ string input = R"TEXT(
+ ~
+ )TEXT";
+ input = boost::regex_replace(input, boost::regex("~"), "");
+ EXPECT_EQ("\n \n ", input);
+ auto expected = "\n";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_only_uneven_whitespace) {
+ // using ~ as a marker1
+ string input = R"TEXT(
+ ~
+ ~
+ )TEXT";
+ input = boost::regex_replace(input, boost::regex("~"), "");
+ EXPECT_EQ("\n \n \n ", input);
+ auto expected = "\n\n";
+
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_one_line) {
+ auto input = R"TEXT(
+ hi there bob!
+ )TEXT";
+ auto expected = "hi there bob!\n";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_two_lines) {
+ auto input = R"TEXT(
+ hi there bob!
+ nice weather today!
+ )TEXT";
+ auto expected = "hi there bob!\nnice weather today!\n";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_three_lines_uneven) {
+ auto input = R"TEXT(
+ hi there bob!
+ nice weather today!
+ so long!
+ )TEXT";
+ auto expected = " hi there bob!\nnice weather today!\n so long!\n";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_preceding_blank_lines) {
+ auto input = R"TEXT(
+
+
+ hi there bob!
+ )TEXT";
+ auto expected = "\n\nhi there bob!\n";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_succeeding_blank_lines) {
+ auto input = R"TEXT(
+ hi there bob!
+
+
+ )TEXT";
+ auto expected = "hi there bob!\n\n\n";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_interstitial_undented_whiteline) {
+ // using ~ as a marker
+ string input = R"TEXT(
+ hi there bob!
+ ~
+ so long!
+ )TEXT";
+ input = boost::regex_replace(input, boost::regex(" +~"), "");
+ EXPECT_EQ("\n hi there bob!\n\n so long!\n ", input);
+ auto expected = "hi there bob!\n\nso long!\n";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_interstitial_dedented_whiteline) {
+ // using ~ as a marker
+ string input = R"TEXT(
+ hi there bob!
+ ~
+ so long!
+ )TEXT";
+ input = boost::regex_replace(input, boost::regex("~"), "");
+ EXPECT_EQ("\n hi there bob!\n \n so long!\n ", input);
+ auto expected = "hi there bob!\n\nso long!\n";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_interstitial_equidented_whiteline) {
+ // using ~ as a marker
+ string input = R"TEXT(
+ hi there bob!
+ ~
+ so long!
+ )TEXT";
+ input = boost::regex_replace(input, boost::regex("~"), "");
+ EXPECT_EQ("\n hi there bob!\n \n so long!\n ", input);
+ auto expected = "hi there bob!\n\nso long!\n";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_interstitial_indented_whiteline) {
+ // using ~ as a marker
+ string input = R"TEXT(
+ hi there bob!
+ ~
+ so long!
+ )TEXT";
+ input = boost::regex_replace(input, boost::regex("~"), "");
+ EXPECT_EQ("\n hi there bob!\n \n so long!\n ", input);
+ auto expected = "hi there bob!\n \nso long!\n";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_no_pre_whitespace) {
+ // using ~ as a marker
+ string input = R"TEXT( hi there bob!
+ ~
+ so long!
+ )TEXT";
+ input = boost::regex_replace(input, boost::regex("~"), "");
+ EXPECT_EQ(" hi there bob!\n \n so long!\n ", input);
+ auto expected = "hi there bob!\n \nso long!\n";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+TEST(String, stripLeftMargin_no_post_whitespace) {
+ // using ~ as a marker
+ string input = R"TEXT(
+ hi there bob!
+ ~
+ so long! )TEXT";
+ input = boost::regex_replace(input, boost::regex("~"), "");
+ EXPECT_EQ("\n hi there bob!\n \n so long! ", input);
+ auto expected = "hi there bob!\n \nso long! ";
+ EXPECT_EQ(expected, stripLeftMargin(input));
+}
+
+const folly::StringPiece kTestUTF8 = u8"This is \U0001F602 stuff!";
+
+TEST(UTF8StringPiece, valid_utf8) {
+ folly::StringPiece sp = kTestUTF8;
+ UTF8StringPiece utf8 = sp;
+ // utf8.size() not available since it's not a random-access range
+ EXPECT_EQ(16, utf8.walk_size());
+}
+
+TEST(UTF8StringPiece, valid_suffix) {
+ UTF8StringPiece utf8 = kTestUTF8.subpiece(8);
+ EXPECT_EQ(8, utf8.walk_size());
+}
+
+TEST(UTF8StringPiece, empty_mid_codepoint) {
+ UTF8StringPiece utf8 = kTestUTF8.subpiece(9, 0); // okay since it's empty
+ EXPECT_EQ(0, utf8.walk_size());
+}
+
+TEST(UTF8StringPiece, invalid_mid_codepoint) {
+ EXPECT_THROW(UTF8StringPiece(kTestUTF8.subpiece(9, 1)), std::out_of_range);
+}
+
+TEST(UTF8StringPiece, valid_implicit_conversion) {
+ std::string input = u8"\U0001F602\U0001F602\U0001F602";
+ auto checkImplicitCtor = [](UTF8StringPiece implicitCtor) {
+ return implicitCtor.walk_size();
+ };
+ EXPECT_EQ(3, checkImplicitCtor(input));