text:
namespace fxcrt {

TEST(WideString, ElementAccess) {
  const WideString abc(L"abc");
  EXPECT_EQ(L'a', abc[0]);
  EXPECT_EQ(L'b', abc[1]);
  EXPECT_EQ(L'c', abc[2]);
#ifndef NDEBUG
  EXPECT_DEATH({ abc[4]; }, ".*");
#endif

  pdfium::span<const wchar_t> abc_span = abc.span();
  EXPECT_EQ(3u, abc_span.size());
  EXPECT_EQ(0, wmemcmp(abc_span.data(), L"abc", 3));

  WideString mutable_abc = abc;
  EXPECT_EQ(abc.c_str(), mutable_abc.c_str());
  EXPECT_EQ(L'a', mutable_abc[0]);
  EXPECT_EQ(L'b', mutable_abc[1]);
  EXPECT_EQ(L'c', mutable_abc[2]);
  EXPECT_EQ(abc.c_str(), mutable_abc.c_str());
  EXPECT_EQ(L"abc", abc);

  const wchar_t* c_str = abc.c_str();
  mutable_abc.SetAt(0, L'd');
  EXPECT_EQ(c_str, abc.c_str());
  EXPECT_NE(c_str, mutable_abc.c_str());
  EXPECT_EQ(L"abc", abc);
  EXPECT_EQ(L"dbc", mutable_abc);

  mutable_abc.SetAt(1, L'e');
  EXPECT_EQ(L"abc", abc);
  EXPECT_EQ(L"dec", mutable_abc);

  mutable_abc.SetAt(2, L'f');
  EXPECT_EQ(L"abc", abc);
  EXPECT_EQ(L"def", mutable_abc);
#ifndef NDEBUG
  EXPECT_DEATH({ mutable_abc.SetAt(3, L'g'); }, ".*");
  EXPECT_EQ(L"abc", abc);
#endif
}

TEST(WideString, Construct) {
  {
    // Copy-construct.
    WideString string1(L"abc");
    WideString string2(string1);
    EXPECT_EQ(L"abc", string1);
    EXPECT_EQ(L"abc", string2);
    EXPECT_EQ(2, string1.ReferenceCountForTesting());
    EXPECT_EQ(2, string2.ReferenceCountForTesting());
  }
  {
    // Move-construct.
    WideString string1(L"abc");
    WideString string2(std::move(string1));
    EXPECT_TRUE(string1.IsEmpty());
    EXPECT_EQ(L"abc", string2);
    EXPECT_EQ(0, string1.ReferenceCountForTesting());
    EXPECT_EQ(1, string2.ReferenceCountForTesting());
  }
}

TEST(WideString, Assign) {
  {
    // Copy-assign.
    WideString string1;
    EXPECT_EQ(0, string1.ReferenceCountForTesting());
    {
      WideString string2(L"abc");
      EXPECT_EQ(1, string2.ReferenceCountForTesting());

      string1 = string2;
      EXPECT_EQ(2, string1.ReferenceCountForTesting());
      EXPECT_EQ(2, string2.ReferenceCountForTesting());
    }
    EXPECT_EQ(1, string1.ReferenceCountForTesting());
  }
  {
    // Move-assign.
    WideString string1;
    EXPECT_EQ(0, string1.ReferenceCountForTesting());
    {
      WideString string2(L"abc");
      EXPECT_EQ(1, string2.ReferenceCountForTesting());

      string1 = std::move(string2);
      EXPECT_EQ(L"abc", string1);
      EXPECT_TRUE(string2.IsEmpty());
      EXPECT_EQ(1, string1.ReferenceCountForTesting());
      EXPECT_EQ(0, string2.ReferenceCountForTesting());
    }
    EXPECT_EQ(1, string1.ReferenceCountForTesting());
  }
}

TEST(WideString, OperatorLT) {
  WideString empty;
  WideString a(L"a");
  WideString ab(L"ab");
  WideString abc(L"\x0110qq");  // Comes before despite endianness.
  WideString def(L"\x1001qq");  // Comes after despite endianness.
  WideStringView v_empty;
  WideStringView v_a(L"a");
  WideStringView v_ab(L"ab");
  WideStringView v_abc(L"\x0110qq");
  WideStringView v_def(L"\x1001qq");
  const wchar_t* const c_null = nullptr;
  const wchar_t* const c_empty = L"";
  const wchar_t* const c_a = L"a";
  const wchar_t* const c_ab = L"ab";
  const wchar_t* const c_abc = L"\x0110qq";
  const wchar_t* const c_def = L"\x1001qq";

  EXPECT_FALSE(empty < empty);
  EXPECT_FALSE(a < a);
  EXPECT_FALSE(abc < abc);
  EXPECT_FALSE(def < def);
  EXPECT_FALSE(c_null < empty);
  EXPECT_FALSE(c_empty < empty);
  EXPECT_FALSE(c_a < a);
  EXPECT_FALSE(c_abc < abc);
  EXPECT_FALSE(c_def < def);
  EXPECT_FALSE(empty < c_null);
  EXPECT_FALSE(empty < c_empty);
  EXPECT_FALSE(a < c_a);
  EXPECT_FALSE(abc < c_abc);
  EXPECT_FALSE(def < c_def);
  EXPECT_FALSE(empty < v_empty);
  EXPECT_FALSE(a < v_a);
  EXPECT_FALSE(abc < v_abc);
  EXPECT_FALSE(def < v_def);

  EXPECT_TRUE(empty < a);
  EXPECT_FALSE(a < empty);
  EXPECT_TRUE(c_null < a);
  EXPECT_TRUE(c_empty < a);
  EXPECT_FALSE(c_a < empty);
  EXPECT_TRUE(empty < c_a);
  EXPECT_FALSE(a < c_null);
  EXPECT_FALSE(a < c_empty);
  EXPECT_TRUE(empty < v_a);
  EXPECT_FALSE(a < v_empty);

  EXPECT_TRUE(empty < abc);
  EXPECT_FALSE(abc < empty);
  EXPECT_TRUE(c_null < abc);
  EXPECT_TRUE(c_empty < abc);
  EXPECT_FALSE(c_abc < empty);
  EXPECT_TRUE(empty < c_abc);
  EXPECT_FALSE(abc < c_null);
  EXPECT_FALSE(abc < c_empty);
  EXPECT_TRUE(empty < v_abc);
  EXPECT_FALSE(abc < v_empty);

  EXPECT_TRUE(empty < def);
  EXPECT_FALSE(def < empty);
  EXPECT_TRUE(c_null < def);
  EXPECT_TRUE(c_empty < def);
  EXPECT_FALSE(c_def < empty);
  EXPECT_TRUE(empty < c_def);
  EXPECT_FALSE(def < c_null);
  EXPECT_FALSE(def < c_empty);
  EXPECT_TRUE(empty < v_def);
  EXPECT_FALSE(def < v_empty);

  EXPECT_TRUE(a < abc);
  EXPECT_FALSE(abc < a);
  EXPECT_TRUE(c_a < abc);
  EXPECT_FALSE(c_abc < a);
  EXPECT_TRUE(a < c_abc);
  EXPECT_FALSE(abc < c_a);
  EXPECT_TRUE(a < v_abc);
  EXPECT_FALSE(abc < v_a);

  EXPECT_TRUE(a < def);
  EXPECT_FALSE(def < a);
  EXPECT_TRUE(c_a < def);
  EXPECT_FALSE(c_def < a);
  EXPECT_TRUE(a < c_def);
  EXPECT_FALSE(def < c_a);
  EXPECT_TRUE(a < v_def);
  EXPECT_FALSE(def < v_a);

  EXPECT_TRUE(abc < def);
  EXPECT_FALSE(def < abc);
  EXPECT_TRUE(c_abc < def);
  EXPECT_FALSE(c_def < abc);
  EXPECT_TRUE(abc < c_def);
  EXPECT_FALSE(def < c_abc);
  EXPECT_TRUE(abc < v_def);
  EXPECT_FALSE(def < v_abc);

  EXPECT_TRUE(a < ab);
  EXPECT_TRUE(a < c_ab);
  EXPECT_TRUE(a < v_ab);
  EXPECT_TRUE(c_a < ab);
  EXPECT_TRUE(c_a < v_ab);
  EXPECT_TRUE(v_a < c_ab);
  EXPECT_TRUE(v_a < v_ab);
}

TEST(WideString, OperatorEQ) {
  WideString null_string;
  EXPECT_TRUE(null_string == null_string);

  WideString empty_string(L"");
  EXPECT_TRUE(empty_string == empty_string);
  EXPECT_TRUE(empty_string == null_string);
  EXPECT_TRUE(null_string == empty_string);

  WideString deleted_string(L"hello");
  deleted_string.Delete(0, 5);
  EXPECT_TRUE(deleted_string == deleted_string);
  EXPECT_TRUE(deleted_string == null_string);
  EXPECT_TRUE(deleted_string == empty_string);
  EXPECT_TRUE(null_string == deleted_string);
  EXPECT_TRUE(null_string == empty_string);

  WideString wide_string(L"hello");
  EXPECT_TRUE(wide_string == wide_string);
  EXPECT_FALSE(wide_string == null_string);
  EXPECT_FALSE(wide_string == empty_string);
  EXPECT_FALSE(wide_string == deleted_string);
  EXPECT_FALSE(null_string == wide_string);
  EXPECT_FALSE(empty_string == wide_string);
  EXPECT_FALSE(deleted_string == wide_string);

  WideString wide_string_same1(L"hello");
  EXPECT_TRUE(wide_string == wide_string_same1);
  EXPECT_TRUE(wide_string_same1 == wide_string);

  WideString wide_string_same2(wide_string);
  EXPECT_TRUE(wide_string == wide_string_same2);
  EXPECT_TRUE(wide_string_same2 == wide_string);

  WideString wide_string1(L"he");
  WideString wide_string2(L"hellp");
  WideString wide_string3(L"hellod");
  EXPECT_FALSE(wide_string == wide_string1);
  EXPECT_FALSE(wide_string == wide_string2);
  EXPECT_FALSE(wide_string == wide_string3);
  EXPECT_FALSE(wide_string1 == wide_string);
  EXPECT_FALSE(wide_string2 == wide_string);
  EXPECT_FALSE(wide_string3 == wide_string);

  WideStringView null_string_c;
  WideStringView empty_string_c(L"");
  EXPECT_TRUE(null_string == null_string_c);
  EXPECT_TRUE(null_string == empty_string_c);
  EXPECT_TRUE(empty_string == null_string_c);
  EXPECT_TRUE(empty_string == empty_string_c);
  EXPECT_TRUE(deleted_string == null_string_c);
  EXPECT_TRUE(deleted_string == empty_string_c);
  EXPECT_TRUE(null_string_c == null_string);
  EXPECT_TRUE(empty_string_c == null_string);
  EXPECT_TRUE(null_string_c == empty_string);
  EXPECT_TRUE(empty_string_c == empty_string);
  EXPECT_TRUE(null_string_c == deleted_string);
  EXPECT_TRUE(empty_string_c == deleted_string);

  WideStringView wide_string_c_same1(L"hello");
  EXPECT_TRUE(wide_string == wide_string_c_same1);
  EXPECT_TRUE(wide_string_c_same1 == wide_string);

  WideStringView wide_string_c1(L"he");
  WideStringView wide_string_c2(L"hellp");
  WideStringView wide_string_c3(L"hellod");
  EXPECT_FALSE(wide_string == wide_string_c1);
  EXPECT_FALSE(wide_string == wide_string_c2);
  EXPECT_FALSE(wide_string == wide_string_c3);
  EXPECT_FALSE(wide_string_c1 == wide_string);
  EXPECT_FALSE(wide_string_c2 == wide_string);
  EXPECT_FALSE(wide_string_c3 == wide_string);

  const wchar_t* const c_null_string = nullptr;
  const wchar_t* const c_empty_string = L"";
  EXPECT_TRUE(null_string == c_null_string);
  EXPECT_TRUE(null_string == c_empty_string);
  EXPECT_TRUE(empty_string == c_null_string);
  EXPECT_TRUE(empty_string == c_empty_string);
  EXPECT_TRUE(deleted_string == c_null_string);
  EXPECT_TRUE(deleted_string == c_empty_string);
  EXPECT_TRUE(c_null_string == null_string);
  EXPECT_TRUE(c_empty_string == null_string);
  EXPECT_TRUE(c_null_string == empty_string);
  EXPECT_TRUE(c_empty_string == empty_string);
  EXPECT_TRUE(c_null_string == deleted_string);
  EXPECT_TRUE(c_empty_string == deleted_string);

  const wchar_t* const c_string_same1 = L"hello";
  EXPECT_TRUE(wide_string == c_string_same1);
  EXPECT_TRUE(c_string_same1 == wide_string);

  const wchar_t* const c_string1 = L"he";
  const wchar_t* const c_string2 = L"hellp";
  const wchar_t* const c_string3 = L"hellod";
  EXPECT_FALSE(wide_string == c_string1);
  EXPECT_FALSE(wide_string == c_string2);
  EXPECT_FALSE(wide_string == c_string3);
  EXPECT_FALSE(c_string1 == wide_string);
  EXPECT_FALSE(c_string2 == wide_string);
  EXPECT_FALSE(c_string3 == wide_string);
}

TEST(WideString, OperatorNE) {
  WideString null_string;
  EXPECT_FALSE(null_string != null_string);

  WideString empty_string(L"");
  EXPECT_FALSE(empty_string != empty_string);
  EXPECT_FALSE(empty_string != null_string);
  EXPECT_FALSE(null_string != empty_string);

  WideString deleted_string(L"hello");
  deleted_string.Delete(0, 5);
  EXPECT_FALSE(deleted_string != deleted_string);
  EXPECT_FALSE(deleted_string != null_string);
  EXPECT_FALSE(deleted_string != empty_string);
  EXPECT_FALSE(null_string != deleted_string);
  EXPECT_FALSE(null_string != empty_string);

  WideString wide_string(L"hello");
  EXPECT_FALSE(wide_string != wide_string);
  EXPECT_TRUE(wide_string != null_string);
  EXPECT_TRUE(wide_string != empty_string);
  EXPECT_TRUE(wide_string != deleted_string);
  EXPECT_TRUE(null_string != wide_string);
  EXPECT_TRUE(empty_string != wide_string);
  EXPECT_TRUE(deleted_string != wide_string);

  WideString wide_string_same1(L"hello");
  EXPECT_FALSE(wide_string != wide_string_same1);
  EXPECT_FALSE(wide_string_same1 != wide_string);

  WideString wide_string_same2(wide_string);
  EXPECT_FALSE(wide_string != wide_string_same2);
  EXPECT_FALSE(wide_string_same2 != wide_string);

  WideString wide_string1(L"he");
  WideString wide_string2(L"hellp");
  WideString wide_string3(L"hellod");
  EXPECT_TRUE(wide_string != wide_string1);
  EXPECT_TRUE(wide_string != wide_string2);
  EXPECT_TRUE(wide_string != wide_string3);
  EXPECT_TRUE(wide_string1 != wide_string);
  EXPECT_TRUE(wide_string2 != wide_string);
  EXPECT_TRUE(wide_string3 != wide_string);

  WideStringView null_string_c;
  WideStringView empty_string_c(L"");
  EXPECT_FALSE(null_string != null_string_c);
  EXPECT_FALSE(null_string != empty_string_c);
  EXPECT_FALSE(empty_string != null_string_c);
  EXPECT_FALSE(empty_string != empty_string_c);
  EXPECT_FALSE(deleted_string != null_string_c);
  EXPECT_FALSE(deleted_string != empty_string_c);
  EXPECT_FALSE(null_string_c != null_string);
  EXPECT_FALSE(empty_string_c != null_string);
  EXPECT_FALSE(null_string_c != empty_string);
  EXPECT_FALSE(empty_string_c != empty_string);

  WideStringView wide_string_c_same1(L"hello");
  EXPECT_FALSE(wide_string != wide_string_c_same1);
  EXPECT_FALSE(wide_string_c_same1 != wide_string);

  WideStringView wide_string_c1(L"he");
  WideStringView wide_string_c2(L"hellp");
  WideStringView wide_string_c3(L"hellod");
  EXPECT_TRUE(wide_string != wide_string_c1);
  EXPECT_TRUE(wide_string != wide_string_c2);
  EXPECT_TRUE(wide_string != wide_string_c3);
  EXPECT_TRUE(wide_string_c1 != wide_string);
  EXPECT_TRUE(wide_string_c2 != wide_string);
  EXPECT_TRUE(wide_string_c3 != wide_string);

  const wchar_t* const c_null_string = nullptr;
  const wchar_t* const c_empty_string = L"";
  EXPECT_FALSE(null_string != c_null_string);
  EXPECT_FALSE(null_string != c_empty_string);
  EXPECT_FALSE(empty_string != c_null_string);
  EXPECT_FALSE(empty_string != c_empty_string);
  EXPECT_FALSE(deleted_string != c_null_string);
  EXPECT_FALSE(deleted_string != c_empty_string);
  EXPECT_FALSE(c_null_string != null_string);
  EXPECT_FALSE(c_empty_string != null_string);
  EXPECT_FALSE(c_null_string != empty_string);
  EXPECT_FALSE(c_empty_string != empty_string);
  EXPECT_FALSE(c_null_string != deleted_string);
  EXPECT_FALSE(c_empty_string != deleted_string);

  const wchar_t* const c_string_same1 = L"hello";
  EXPECT_FALSE(wide_string != c_string_same1);
  EXPECT_FALSE(c_string_same1 != wide_string);

  const wchar_t* const c_string1 = L"he";
  const wchar_t* const c_string2 = L"hellp";
  const wchar_t* const c_string3 = L"hellod";
  EXPECT_TRUE(wide_string != c_string1);
  EXPECT_TRUE(wide_string != c_string2);
  EXPECT_TRUE(wide_string != c_string3);
  EXPECT_TRUE(c_string1 != wide_string);
  EXPECT_TRUE(c_string2 != wide_string);
  EXPECT_TRUE(c_string3 != wide_string);
}

TEST(WideString, OperatorPlus) {
  EXPECT_EQ(L"I like dogs", L"I like " + WideString(L"dogs"));
  EXPECT_EQ(L"Dogs like me", WideString(L"Dogs") + L" like me");
  EXPECT_EQ(L"Oh no, error number 42",
            L"Oh no, error number " + WideString::Format(L"%d", 42));

  {
    // Make sure operator+= and Concat() increases string memory allocation
    // geometrically.
    int allocations = 0;
    WideString str(L"ABCDEFGHIJKLMN");
    const wchar_t* buffer = str.c_str();
    for (size_t i = 0; i < 10000; ++i) {
      str += L"!";
      const wchar_t* new_buffer = str.c_str();
      if (new_buffer != buffer) {
        buffer = new_buffer;
        ++allocations;
      }
    }
    EXPECT_LT(allocations, 25);
    EXPECT_GT(allocations, 10);
  }
}

TEST(WideString, ConcatInPlace) {
  WideString fred;
  fred.Concat(L"FRED", 4);
  EXPECT_EQ(L"FRED", fred);

  fred.Concat(L"DY", 2);
  EXPECT_EQ(L"FREDDY", fred);

  fred.Delete(3, 3);
  EXPECT_EQ(L"FRE", fred);

  fred.Concat(L"D", 1);
  EXPECT_EQ(L"FRED", fred);

  WideString copy = fred;
  fred.Concat(L"DY", 2);
  EXPECT_EQ(L"FREDDY", fred);
  EXPECT_EQ(L"FRED", copy);
}

TEST(WideString, Remove) {
  WideString freed(L"FREED");
  freed.Remove(L'E');
  EXPECT_EQ(L"FRD", freed);
  freed.Remove(L'F');
  EXPECT_EQ(L"RD", freed);
  freed.Remove(L'D');
  EXPECT_EQ(L"R", freed);
  freed.Remove(L'X');
  EXPECT_EQ(L"R", freed);
  freed.Remove(L'R');
  EXPECT_EQ(L"", freed);

  WideString empty;
  empty.Remove(L'X');
  EXPECT_EQ(L"", empty);
}

TEST(WideString, RemoveCopies) {
  WideString freed(L"FREED");
  const wchar_t* old_buffer = freed.c_str();

  // No change with single reference - no copy.
  freed.Remove(L'Q');
  EXPECT_EQ(L"FREED", freed);
  EXPECT_EQ(old_buffer, freed.c_str());

  // Change with single reference - no copy.
  freed.Remove(L'E');
  EXPECT_EQ(L"FRD", freed);
  EXPECT_EQ(old_buffer, freed.c_str());

  // No change with multiple references - no copy.
  WideString shared(freed);
  freed.Remove(L'Q');
  EXPECT_EQ(L"FRD", freed);
  EXPECT_EQ(old_buffer, freed.c_str());
  EXPECT_EQ(old_buffer, shared.c_str());

  // Change with multiple references -- must copy.
  freed.Remove(L'D');
  EXPECT_EQ(L"FR", freed);
  EXPECT_NE(old_buffer, freed.c_str());
  EXPECT_EQ(L"FRD", shared);
  EXPECT_EQ(old_buffer, shared.c_str());
}

TEST(WideString, Replace) {
  WideString empty;
  empty.Replace(L"", L"CLAMS");
  empty.Replace(L"xx", L"CLAMS");
  EXPECT_EQ(L"", empty);

  WideString fred(L"FRED");
  fred.Replace(L"", L"");
  EXPECT_EQ(L"FRED", fred);
  fred.Replace(L"", L"CLAMS");
  EXPECT_EQ(L"FRED", fred);
  fred.Replace(L"FR", L"BL");
  EXPECT_EQ(L"BLED", fred);
  fred.Replace(L"D", L"DDY");
  EXPECT_EQ(L"BLEDDY", fred);
  fred.Replace(L"LEDD", L"");
  EXPECT_EQ(L"BY", fred);
  fred.Replace(L"X", L"CLAMS");
  EXPECT_EQ(L"BY", fred);
  fred.Replace(L"BY", L"HI");
  EXPECT_EQ(L"HI", fred);
  fred.Replace(L"I", L"IHIHI");
  EXPECT_EQ(L"HIHIHI", fred);
  fred.Replace(L"HI", L"HO");
  EXPECT_EQ(L"HOHOHO", fred);
  fred.Replace(L"HO", L"");
  EXPECT_EQ(L"", fred);

  WideString five_xs(L"xxxxx");
  five_xs.Replace(L"xx", L"xxx");
  EXPECT_EQ(L"xxxxxxx", five_xs);

  WideString five_ys(L"yyyyy");
  five_ys.Replace(L"yy", L"y");
  EXPECT_EQ(L"yyy", five_ys);
}

TEST(WideString, Insert) {
  WideString fred(L"FRED");
  EXPECT_EQ(5u, fred.Insert(0, 'S'));
  EXPECT_EQ(L"SFRED", fred);
  EXPECT_EQ(6u, fred.Insert(1, 'T'));
  EXPECT_EQ(L"STFRED", fred);
  EXPECT_EQ(7u, fred.Insert(4, 'U'));
  EXPECT_EQ(L"STFRUED", fred);
  EXPECT_EQ(8u, fred.Insert(7, 'V'));
  EXPECT_EQ(L"STFRUEDV", fred);
  EXPECT_EQ(8u, fred.Insert(12, 'P'));
  EXPECT_EQ(L"STFRUEDV", fred);
  {
    WideString empty;
    EXPECT_EQ(1u, empty.Insert(0, 'X'));
    EXPECT_EQ(L"X", empty);
  }
  {
    WideString empty;
    EXPECT_EQ(0u, empty.Insert(5, 'X'));
    EXPECT_NE(L"X", empty);
  }
}

TEST(WideString, InsertAtFrontAndInsertAtBack) {
  {
    WideString empty;
    EXPECT_EQ(1u, empty.InsertAtFront('D'));
    EXPECT_EQ(L"D", empty);
    EXPECT_EQ(2u, empty.InsertAtFront('E'));
    EXPECT_EQ(L"ED", empty);
    EXPECT_EQ(3u, empty.InsertAtFront('R'));
    EXPECT_EQ(L"RED", empty);
    EXPECT_EQ(4u, empty.InsertAtFront('F'));
    EXPECT_EQ(L"FRED", empty);
  }
  {
    WideString empty;
    EXPECT_EQ(1u, empty.InsertAtBack('F'));
    EXPECT_EQ(L"F", empty);
    EXPECT_EQ(2u, empty.InsertAtBack('R'));
    EXPECT_EQ(L"FR", empty);
    EXPECT_EQ(3u, empty.InsertAtBack('E'));
    EXPECT_EQ(L"FRE", empty);
    EXPECT_EQ(4u, empty.InsertAtBack('D'));
    EXPECT_EQ(L"FRED", empty);
  }
  {
    WideString empty;
    EXPECT_EQ(1u, empty.InsertAtBack('E'));
    EXPECT_EQ(L"E", empty);
    EXPECT_EQ(2u, empty.InsertAtFront('R'));
    EXPECT_EQ(L"RE", empty);
    EXPECT_EQ(3u, empty.InsertAtBack('D'));
    EXPECT_EQ(L"RED", empty);
    EXPECT_EQ(4u, empty.InsertAtFront('F'));
    EXPECT_EQ(L"FRED", empty);
  }
}

TEST(WideString, Delete) {
  WideString fred(L"FRED");
  EXPECT_EQ(4u, fred.Delete(0, 0));
  EXPECT_EQ(L"FRED", fred);
  EXPECT_EQ(2u, fred.Delete(0, 2));
  EXPECT_EQ(L"ED", fred);
  EXPECT_EQ(1u, fred.Delete(1));
  EXPECT_EQ(L"E", fred);
  EXPECT_EQ(0u, fred.Delete(0));
  EXPECT_EQ(L"", fred);
  EXPECT_EQ(0u, fred.Delete(0));
  EXPECT_EQ(L"", fred);

  WideString empty;
  EXPECT_EQ(0u, empty.Delete(0));
  EXPECT_EQ(L"", empty);
  EXPECT_EQ(0u, empty.Delete(1));
  EXPECT_EQ(L"", empty);
}

TEST(WideString, Substr) {
  WideString fred(L"FRED");
  EXPECT_EQ(L"", fred.Substr(0, 0));
  EXPECT_EQ(L"", fred.Substr(3, 0));
  EXPECT_EQ(L"FRED", fred.Substr(0, 4));
  EXPECT_EQ(L"RED", fred.Substr(1, 3));
  EXPECT_EQ(L"ED", fred.Substr(2, 2));
  EXPECT_EQ(L"D", fred.Substr(3, 1));
  EXPECT_EQ(L"F", fred.Substr(0, 1));
  EXPECT_EQ(L"R", fred.Substr(1, 1));
  EXPECT_EQ(L"E", fred.Substr(2, 1));
  EXPECT_EQ(L"D", fred.Substr(3, 1));
  EXPECT_EQ(L"FR", fred.Substr(0, 2));
  EXPECT_EQ(L"FRED", fred.Substr(0, 4));
  EXPECT_EQ(L"", fred.Substr(0, 10));

  EXPECT_EQ(L"", fred.Substr(1, 4));
  EXPECT_EQ(L"", fred.Substr(4, 1));

  WideString empty;
  EXPECT_EQ(L"", empty.Substr(0, 0));
}

TEST(WideString, First) {
  WideString fred(L"FRED");
  EXPECT_EQ(L"", fred.First(0));
  EXPECT_EQ(L"F", fred.First(1));
  EXPECT_EQ(L"FR", fred.First(2));
  EXPECT_EQ(L"FRE", fred.First(3));
  EXPECT_EQ(L"FRED", fred.First(4));

  EXPECT_EQ(L"", fred.First(5));

  WideString empty;
  EXPECT_EQ(L"", empty.First(0));
  EXPECT_EQ(L"", empty.First(1));
}

TEST(WideString, Last) {
  WideString fred(L"FRED");
  EXPECT_EQ(L"", fred.Last(0));
  EXPECT_EQ(L"D", fred.Last(1));
  EXPECT_EQ(L"ED", fred.Last(2));
  EXPECT_EQ(L"RED", fred.Last(3));
  EXPECT_EQ(L"FRED", fred.Last(4));

  EXPECT_EQ(L"", fred.Last(5));

  WideString empty;
  EXPECT_EQ(L"", empty.Last(0));
  EXPECT_EQ(L"", empty.Last(1));
}

TEST(WideString, Find) {
  WideString null_string;
  EXPECT_FALSE(null_string.Find(L'a').has_value());
  EXPECT_FALSE(null_string.Find(L'\0').has_value());

  WideString empty_string(L"");
  EXPECT_FALSE(empty_string.Find(L'a').has_value());
  EXPECT_FALSE(empty_string.Find(L'\0').has_value());

  Optional<size_t> result;
  WideString single_string(L"a");
  result = single_string.Find(L'a');
  ASSERT_TRUE(result.has_value());
  EXPECT_EQ(0u, result.value());
  EXPECT_FALSE(single_string.Find(L'b').has_value());
  EXPECT_FALSE(single_string.Find(L'\0').has_value());

  WideString longer_string(L"abccc");
  result = longer_string.Find(L'a');
  ASSERT_TRUE(result.has_value());
  EXPECT_EQ(0u, result.value());
  result = longer_string.Find(L'c');
  ASSERT_TRUE(result.has_value());
  EXPECT_EQ(2u, result.value());
  result = longer_string.Find(L'c', 3);
  ASSERT_TRUE(result.has_value());
  EXPECT_EQ(3u, result.value());
  EXPECT_FALSE(longer_string.Find(L'\0').has_value());

  result = longer_string.Find(L"ab");
  ASSERT_TRUE(result.has_value());
  EXPECT_EQ(0u, result.value());
  result = longer_string.Find(L"ccc");
  ASSERT_TRUE(result.has_value());
  EXPECT_EQ(2u, result.value());
  result = longer_string.Find(L"cc", 3);
  ASSERT_TRUE(result.has_value());
  EXPECT_EQ(3u, result.value());
  EXPECT_FALSE(longer_string.Find(L"d").has_value());

  WideString hibyte_string(
      L"ab\xff8c"
      L"def");
  result = hibyte_string.Find(L'\xff8c');
  ASSERT_TRUE(result.has_value());
  EXPECT_EQ(2u, result.value());
}

TEST(WideString, ReverseFind) {
  WideString null_string;
  EXPECT_FALSE(null_string.ReverseFind(L'a').has_value());
  EXPECT_FALSE(null_string.ReverseFind(L'\0').has_value());

  WideString empty_string(L"");
  EXPECT_FALSE(empty_string.ReverseFind(L'a').has_value());
  EXPECT_FALSE(empty_string.ReverseFind(L'\0').has_value());

  Optional<size_t> result;
  WideString single_string(L"a");
  result = single_string.ReverseFind(L'a');
  ASSERT_TRUE(result.has_value());
  EXPECT_EQ(0u, result.value());
  EXPECT_FALSE(single_string.ReverseFind(L'b').has_value());
  EXPECT_FALSE(single_string.ReverseFind(L'\0').has_value());

  WideString longer_string(L"abccc");
  result = longer_string.ReverseFind(L'a');
  ASSERT_TRUE(result.has_value());
  EXPECT_EQ(0u, result.value());
  result = longer_string.ReverseFind(L'c');
  ASSERT_TRUE(result.has_value());
  EXPECT_EQ(4u, result.value());
  EXPECT_FALSE(longer_string.ReverseFind(L'\0').has_value());

  WideString hibyte_string(
      L"ab\xff8c"
      L"def");
  result = hibyte_string.ReverseFind(L'\xff8c');
  ASSERT_TRUE(result.has_value());
  EXPECT_EQ(2u, result.value());
}

TEST(WideString, UpperLower) {
  WideString fred(L"F-Re.42D");
  fred.MakeLower();
  EXPECT_EQ(L"f-re.42d", fred);
  fred.MakeUpper();
  EXPECT_EQ(L"F-RE.42D", fred);

  WideString empty;
  empty.MakeLower();
  EXPECT_EQ(L"", empty);
  empty.MakeUpper();
  EXPECT_EQ(L"", empty);
}

TEST(WideString, Trim) {
  WideString fred(L"  FRED  ");
  fred.Trim();
  EXPECT_EQ(L"FRED", fred);
  fred.Trim(L'E');
  EXPECT_EQ(L"FRED", fred);
  fred.Trim(L'F');
  EXPECT_EQ(L"RED", fred);
  fred.Trim(L"ERP");
  EXPECT_EQ(L"D", fred);

  WideString blank(L"   ");
  blank.Trim(L"ERP");
  EXPECT_EQ(L"   ", blank);
  blank.Trim(L'E');
  EXPECT_EQ(L"   ", blank);
  blank.Trim();
  EXPECT_EQ(L"", blank);

  WideString empty;
  empty.Trim(L"ERP");
  EXPECT_EQ(L"", empty);
  empty.Trim(L'E');
  EXPECT_EQ(L"", empty);
  empty.Trim();
  EXPECT_EQ(L"", empty);

  WideString abc(L"  ABCCBA  ");
  abc.Trim(L"A");
  EXPECT_EQ(L"  ABCCBA  ", abc);
  abc.Trim(L" A");
  EXPECT_EQ(L"BCCB", abc);
}

TEST(WideString, TrimLeft) {
  WideString fred(L"  FRED  ");
  fred.TrimLeft();
  EXPECT_EQ(L"FRED  ", fred);
  fred.TrimLeft(L'E');
  EXPECT_EQ(L"FRED  ", fred);
  fred.TrimLeft(L'F');
  EXPECT_EQ(L"RED  ", fred);
  fred.TrimLeft(L"ERP");
  EXPECT_EQ(L"D  ", fred);

  WideString blank(L"   ");
  blank.TrimLeft(L"ERP");
  EXPECT_EQ(L"   ", blank);
  blank.TrimLeft(L'E');
  EXPECT_EQ(L"   ", blank);
  blank.TrimLeft();
  EXPECT_EQ(L"", blank);

  WideString empty;
  empty.TrimLeft(L"ERP");
  EXPECT_EQ(L"", empty);
  empty.TrimLeft(L'E');
  EXPECT_EQ(L"", empty);
  empty.TrimLeft();
  EXPECT_EQ(L"", empty);
}

TEST(WideString, TrimLeftCopies) {
  {
    // With a single reference, no copy takes place.
    WideString fred(L"  FRED  ");
    const wchar_t* old_buffer = fred.c_str();
    fred.TrimLeft();
    EXPECT_EQ(L"FRED  ", fred);
    EXPECT_EQ(old_buffer, fred.c_str());
  }
  {
    // With multiple references, we must copy.
    WideString fred(L"  FRED  ");
    WideString other_fred = fred;
    const wchar_t* old_buffer = fred.c_str();
    fred.TrimLeft();
    EXPECT_EQ(L"FRED  ", fred);
    EXPECT_EQ(L"  FRED  ", other_fred);
    EXPECT_NE(old_buffer, fred.c_str());
  }
  {
    // With multiple references, but no modifications, no copy.
    WideString fred(L"FRED");
    WideString other_fred = fred;
    const wchar_t* old_buffer = fred.c_str();
    fred.TrimLeft();
    EXPECT_EQ(L"FRED", fred);
    EXPECT_EQ(L"FRED", other_fred);
    EXPECT_EQ(old_buffer, fred.c_str());
  }
}

TEST(WideString, TrimRight) {
  WideString fred(L"  FRED  ");
  fred.TrimRight();
  EXPECT_EQ(L"  FRED", fred);
  fred.TrimRight(L'E');
  EXPECT_EQ(L"  FRED", fred);
  fred.TrimRight(L'D');
  EXPECT_EQ(L"  FRE", fred);
  fred.TrimRight(L"ERP");
  EXPECT_EQ(L"  F", fred);

  WideString blank(L"   ");
  blank.TrimRight(L"ERP");
  EXPECT_EQ(L"   ", blank);
  blank.TrimRight(L'E');
  EXPECT_EQ(L"   ", blank);
  blank.TrimRight();
  EXPECT_EQ(L"", blank);

  WideString empty;
  empty.TrimRight(L"ERP");
  EXPECT_EQ(L"", empty);
  empty.TrimRight(L'E');
  EXPECT_EQ(L"", empty);
  empty.TrimRight();
  EXPECT_EQ(L"", empty);
}

TEST(WideString, TrimRightCopies) {
  {
    // With a single reference, no copy takes place.
    WideString fred(L"  FRED  ");
    const wchar_t* old_buffer = fred.c_str();
    fred.TrimRight();
    EXPECT_EQ(L"  FRED", fred);
    EXPECT_EQ(old_buffer, fred.c_str());
  }
  {
    // With multiple references, we must copy.
    WideString fred(L"  FRED  ");
    WideString other_fred = fred;
    const wchar_t* old_buffer = fred.c_str();
    fred.TrimRight();
    EXPECT_EQ(L"  FRED", fred);
    EXPECT_EQ(L"  FRED  ", other_fred);
    EXPECT_NE(old_buffer, fred.c_str());
  }
  {
    // With multiple references, but no modifications, no copy.
    WideString fred(L"FRED");
    WideString other_fred = fred;
    const wchar_t* old_buffer = fred.c_str();
    fred.TrimRight();
    EXPECT_EQ(L"FRED", fred);
    EXPECT_EQ(L"FRED", other_fred);
    EXPECT_EQ(old_buffer, fred.c_str());
  }
}

TEST(WideString, Reserve) {
  {
    WideString str;
    str.Reserve(6);
    const wchar_t* old_buffer = str.c_str();
    str += L"ABCDEF";
    EXPECT_EQ(old_buffer, str.c_str());
    str += L"Blah Blah Blah Blah Blah Blah";
    EXPECT_NE(old_buffer, str.c_str());
  }
  {
    WideString str(L"A");
    str.Reserve(6);
    const wchar_t* old_buffer = str.c_str();
    str += L"BCDEF";
    EXPECT_EQ(old_buffer, str.c_str());
    str += L"Blah Blah Blah Blah Blah Blah";
    EXPECT_NE(old_buffer, str.c_str());
  }
}

TEST(WideString, GetBuffer) {
  WideString str1;
  {
    pdfium::span<wchar_t> buffer = str1.GetBuffer(12);
    wcscpy(buffer.data(), L"clams");
  }
  str1.ReleaseBuffer(str1.GetStringLength());
  EXPECT_EQ(L"clams", str1);

  WideString str2(L"cl");
  {
    pdfium::span<wchar_t> buffer = str2.GetBuffer(12);
    wcscpy(buffer.data() + 2, L"ams");
  }
  str2.ReleaseBuffer(str2.GetStringLength());
  EXPECT_EQ(L"clams", str2);
}

TEST(WideString, ReleaseBuffer) {
  {
    WideString str;
    str.Reserve(12);
    str += L"clams";
    const wchar_t* old_buffer = str.c_str();
    str.ReleaseBuffer(4);
    EXPECT_EQ(old_buffer, str.c_str());
    EXPECT_EQ(L"clam", str);
  }
  {
    WideString str(L"c");
    str.Reserve(12);
    str += L"lams";
    const wchar_t* old_buffer = str.c_str();
    str.ReleaseBuffer(4);
    EXPECT_EQ(old_buffer, str.c_str());
    EXPECT_EQ(L"clam", str);
  }
  {
    WideString str;
    str.Reserve(200);
    str += L"clams";
    const wchar_t* old_buffer = str.c_str();
    str.ReleaseBuffer(4);
    EXPECT_NE(old_buffer, str.c_str());
    EXPECT_EQ(L"clam", str);
  }
  {
    WideString str(L"c");
    str.Reserve(200);
    str += L"lams";
    const wchar_t* old_buffer = str.c_str();
    str.ReleaseBuffer(4);
    EXPECT_NE(old_buffer, str.c_str());
    EXPECT_EQ(L"clam", str);
  }
}

TEST(WideString, EmptyReverseIterator) {
  WideString empty;
  auto iter = empty.rbegin();
  EXPECT_TRUE(iter == empty.rend());
  EXPECT_FALSE(iter != empty.rend());
  EXPECT_FALSE(iter < empty.rend());
}

TEST(WideString, OneCharReverseIterator) {
  WideString one_str(L"a");
  auto iter = one_str.rbegin();
  EXPECT_FALSE(iter == one_str.rend());
  EXPECT_TRUE(iter != one_str.rend());
  EXPECT_TRUE(iter < one_str.rend());

  char ch = *iter++;
  EXPECT_EQ('a', ch);
  EXPECT_TRUE(iter == one_str.rend());
  EXPECT_FALSE(iter != one_str.rend());
  EXPECT_FALSE(iter < one_str.rend());
}

TEST(WideString, MultiCharReverseIterator) {
  WideString multi_str(L"abcd");
  auto iter = multi_str.rbegin();
  EXPECT_NE(iter, multi_str.rend());
  EXPECT_EQ(4, multi_str.rend() - iter);
  EXPECT_EQ(0, iter - multi_str.rbegin());

  char ch = *iter++;
  EXPECT_EQ('d', ch);
  EXPECT_EQ('c', *iter);
  EXPECT_NE(iter, multi_str.rend());
  EXPECT_EQ(3, multi_str.rend() - iter);
  EXPECT_EQ(1, iter - multi_str.rbegin());

  ch = *(++iter);
  EXPECT_EQ('b', ch);
  EXPECT_EQ('b', *iter);
  EXPECT_NE(iter, multi_str.rend());
  EXPECT_EQ(2, multi_str.rend() - iter);
  EXPECT_EQ(2, iter - multi_str.rbegin());

  ch = *iter++;
  EXPECT_EQ('b', ch);
  EXPECT_EQ('a', *iter);
  EXPECT_NE(iter, multi_str.rend());
  EXPECT_EQ(1, multi_str.rend() - iter);
  EXPECT_EQ(3, iter - multi_str.rbegin());

  ch = *iter++;
  EXPECT_EQ('a', ch);
  EXPECT_EQ(iter, multi_str.rend());
  EXPECT_EQ(0, multi_str.rend() - iter);
  EXPECT_EQ(4, iter - multi_str.rbegin());

  ch = *(--iter);
  EXPECT_EQ('a', ch);
  EXPECT_EQ('a', *iter);
  EXPECT_NE(iter, multi_str.rend());
  EXPECT_EQ(1, multi_str.rend() - iter);
  EXPECT_EQ(3, iter - multi_str.rbegin());

  ch = *iter--;
  EXPECT_EQ('a', ch);
  EXPECT_EQ('b', *iter);
  EXPECT_NE(iter, multi_str.rend());
  EXPECT_EQ(2, multi_str.rend() - iter);
  EXPECT_EQ(2, iter - multi_str.rbegin());

  ch = *iter--;
  EXPECT_EQ('b', ch);
  EXPECT_EQ('c', *iter);
  EXPECT_NE(iter, multi_str.rend());
  EXPECT_EQ(3, multi_str.rend() - iter);
  EXPECT_EQ(1, iter - multi_str.rbegin());

  ch = *(--iter);
  EXPECT_EQ('d', ch);
  EXPECT_EQ('d', *iter);
  EXPECT_EQ(iter, multi_str.rbegin());
  EXPECT_EQ(4, multi_str.rend() - iter);
  EXPECT_EQ(0, iter - multi_str.rbegin());
}

TEST(WideString, ToUTF16LE) {
  struct UTF16LEEncodeCase {
    WideString ws;
    ByteString bs;
  } const utf16le_encode_cases[] = {
      {L"", ByteString("\0\0", 2)},
      {L"abc", ByteString("a\0b\0c\0\0\0", 8)},
      {L"abcdef", ByteString("a\0b\0c\0d\0e\0f\0\0\0", 14)},
      {L"abc\0def", ByteString("a\0b\0c\0\0\0", 8)},
      {L"\xaabb\xccdd", ByteString("\xbb\xaa\xdd\xcc\0\0", 6)},
      {L"\x3132\x6162", ByteString("\x32\x31\x62\x61\0\0", 6)},
  };

  for (size_t i = 0; i < FX_ArraySize(utf16le_encode_cases); ++i) {
    EXPECT_EQ(utf16le_encode_cases[i].bs,
              utf16le_encode_cases[i].ws.ToUTF16LE())
        << " for case number " << i;
  }
}

TEST(WideString, IsASCII) {
  EXPECT_TRUE(WideString(L"xy\u007fz").IsASCII());
  EXPECT_FALSE(WideString(L"xy\u0080z").IsASCII());
  EXPECT_FALSE(WideString(L"xy\u2041z").IsASCII());
}

TEST(WideString, EqualsASCII) {
  EXPECT_TRUE(WideString(L"").EqualsASCII(""));
  EXPECT_FALSE(WideString(L"A").EqualsASCII(""));
  EXPECT_FALSE(WideString(L"").EqualsASCII("A"));
  EXPECT_FALSE(WideString(L"A").EqualsASCII("B"));
  EXPECT_TRUE(WideString(L"ABC").EqualsASCII("ABC"));
  EXPECT_FALSE(WideString(L"ABC").EqualsASCII("AEC"));
  EXPECT_FALSE(WideString(L"\u00c1").EqualsASCII("\x41"));
  EXPECT_FALSE(WideString(L"\u0141").EqualsASCII("\x41"));
}

TEST(WideString, EqualsASCIINoCase) {
  EXPECT_TRUE(WideString(L"").EqualsASCIINoCase(""));
  EXPECT_FALSE(WideString(L"A").EqualsASCIINoCase("b"));
  EXPECT_TRUE(WideString(L"AbC").EqualsASCIINoCase("aBc"));
  EXPECT_FALSE(WideString(L"ABc").EqualsASCIINoCase("AeC"));
  EXPECT_FALSE(WideString(L"\u00c1").EqualsASCIINoCase("\x41"));
  EXPECT_FALSE(WideString(L"\u0141").EqualsASCIINoCase("\x41"));
}

TEST(WideString, ToASCII) {
  const char* kResult =
      "x"
      "\x02"
      "\x7f"
      "\x22"
      "\x0c"
      "y";
  EXPECT_EQ(kResult, WideString(L"x"
                                L"\u0082"
                                L"\u00ff"
                                L"\u0122"
                                L"\u208c"
                                L"y")
                         .ToASCII());
}

TEST(WideString, ToLatin1) {
  const char* kResult =
      "x"
      "\x82"
      "\xff"
      "\x22"
      "\x8c"
      "y";
  EXPECT_EQ(kResult, WideString(L"x"
                                L"\u0082"
                                L"\u00ff"
                                L"\u0122"
                                L"\u208c"
                                L"y")
                         .ToLatin1());
}

TEST(WideString, ToDefANSI) {
  EXPECT_EQ("", WideString().ToDefANSI());
#if defined(OS_WIN)
  const char* kResult =
      "x"
      "?"
      "\xff"
      "A"
      "?"
      "y";
#else
  const char* kResult =
      "x"
      "\x80"
      "\xff"
      "y";
#endif
  EXPECT_EQ(kResult, WideString(L"x"
                                L"\u0080"
                                L"\u00ff"
                                L"\u0100"
                                L"\u208c"
                                L"y")
                         .ToDefANSI());
}

TEST(WideString, FromASCII) {
  EXPECT_EQ(L"", WideString::FromASCII(ByteStringView()));
  const wchar_t* kResult =
      L"x"
      L"\u0002"
      L"\u007f"
      L"y";
  EXPECT_EQ(kResult, WideString::FromASCII("x"
                                           "\x82"
                                           "\xff"
                                           "y"));
}

TEST(WideString, FromLatin1) {
  EXPECT_EQ(L"", WideString::FromLatin1(ByteStringView()));
  const wchar_t* kResult =
      L"x"
      L"\u0082"
      L"\u00ff"
      L"y";
  EXPECT_EQ(kResult, WideString::FromLatin1("x"
                                            "\x82"
                                            "\xff"
                                            "y"));
}

TEST(WideString, FromDefANSI) {
  EXPECT_EQ(L"", WideString::FromDefANSI(ByteStringView()));
#if defined(OS_WIN)
  const wchar_t* kResult =
      L"x"
      L"\u20ac"
      L"\u00ff"
      L"y";
#else
  const wchar_t* kResult =
      L"x"
      L"\u0080"
      L"\u00ff"
      L"y";
#endif
  EXPECT_EQ(kResult, WideString::FromDefANSI("x"
                                             "\x80"
                                             "\xff"
                                             "y"));
}

TEST(WideStringView, FromVector) {
  std::vector<WideStringView::UnsignedType> null_vec;
  WideStringView null_string(null_vec);
  EXPECT_EQ(0u, null_string.GetLength());

  std::vector<WideStringView::UnsignedType> lower_a_vec(
      10, static_cast<WideStringView::UnsignedType>(L'a'));
  WideStringView lower_a_string(lower_a_vec);
  EXPECT_EQ(10u, lower_a_string.GetLength());
  EXPECT_EQ(L"aaaaaaaaaa", lower_a_string);

  std::vector<WideStringView::UnsignedType> cleared_vec;
  cleared_vec.push_back(42);
  cleared_vec.pop_back();
  WideStringView cleared_string(cleared_vec);
  EXPECT_EQ(0u, cleared_string.GetLength());
  EXPECT_EQ(nullptr, cleared_string.raw_str());
}

TEST(WideStringView, ElementAccess) {
  WideStringView abc(L"abc");
  EXPECT_EQ(L'a', static_cast<wchar_t>(abc[0]));
  EXPECT_EQ(L'b', static_cast<wchar_t>(abc[1]));
  EXPECT_EQ(L'c', static_cast<wchar_t>(abc[2]));
#ifndef NDEBUG
  EXPECT_DEATH({ abc[4]; }, ".*");
#endif
}

TEST(WideStringView, OperatorLT) {
  WideStringView empty;
  WideStringView a(L"a");
  WideStringView abc(L"\x0110qq");  // Comes InsertAtFront despite endianness.
  WideStringView def(L"\x1001qq");  // Comes InsertAtBack despite endianness.
  const wchar_t* const c_null = nullptr;
  const wchar_t* const c_empty = L"";
  const wchar_t* const c_a = L"a";
  const wchar_t* const c_abc = L"\x0110qq";
  const wchar_t* const c_def = L"\x1001qq";

  EXPECT_FALSE(empty < empty);
  EXPECT_FALSE(a < a);
  EXPECT_FALSE(abc < abc);
  EXPECT_FALSE(def < def);
  EXPECT_FALSE(c_null < empty);
  EXPECT_FALSE(c_empty < empty);
  EXPECT_FALSE(c_a < a);
  EXPECT_FALSE(c_abc < abc);
  EXPECT_FALSE(c_def < def);
  EXPECT_FALSE(empty < c_null);
  EXPECT_FALSE(empty < c_empty);
  EXPECT_FALSE(a < c_a);
  EXPECT_FALSE(abc < c_abc);
  EXPECT_FALSE(def < c_def);

  EXPECT_TRUE(empty < a);
  EXPECT_FALSE(a < empty);
  EXPECT_TRUE(empty < c_a);
  EXPECT_FALSE(a < c_null);
  EXPECT_FALSE(a < c_empty);

  EXPECT_TRUE(empty < abc);
  EXPECT_FALSE(abc < empty);
  EXPECT_TRUE(empty < c_abc);
  EXPECT_FALSE(abc < c_null);
  EXPECT_FALSE(abc < c_empty);

  EXPECT_TRUE(empty < def);
  EXPECT_FALSE(def < empty);
  EXPECT_TRUE(empty < c_def);
  EXPECT_FALSE(def < c_null);
  EXPECT_FALSE(def < c_empty);

  EXPECT_TRUE(a < abc);
  EXPECT_FALSE(abc < a);
  EXPECT_TRUE(a < c_abc);
  EXPECT_FALSE(abc < c_a);

  EXPECT_TRUE(a < def);
  EXPECT_FALSE(def < a);
  EXPECT_TRUE(a < c_def);
  EXPECT_FALSE(def < c_a);

  EXPECT_TRUE(abc < def);
  EXPECT_FALSE(def < abc);
  EXPECT_TRUE(abc < c_def);
  EXPECT_FALSE(def < c_abc);
}

TEST(WideStringView, OperatorEQ) {
  WideStringView wide_string_c(L"hello");
  EXPECT_TRUE(wide_string_c == wide_string_c);

  WideStringView wide_string_c_same1(L"hello");
  EXPECT_TRUE(wide_string_c == wide_string_c_same1);
  EXPECT_TRUE(wide_string_c_same1 == wide_string_c);

  WideStringView wide_string_c_same2(wide_string_c);
  EXPECT_TRUE(wide_string_c == wide_string_c_same2);
  EXPECT_TRUE(wide_string_c_same2 == wide_string_c);

  WideStringView wide_string_c1(L"he");
  WideStringView wide_string_c2(L"hellp");
  WideStringView wide_string_c3(L"hellod");
  EXPECT_FALSE(wide_string_c == wide_string_c1);
  EXPECT_FALSE(wide_string_c == wide_string_c2);
  EXPECT_FALSE(wide_string_c == wide_string_c3);
  EXPECT_FALSE(wide_string_c1 == wide_string_c);
  EXPECT_FALSE(wide_string_c2 == wide_string_c);
  EXPECT_FALSE(wide_string_c3 == wide_string_c);

  WideString wide_string_same1(L"hello");
  EXPECT_TRUE(wide_string_c == wide_string_same1);
  EXPECT_TRUE(wide_string_same1 == wide_string_c);

  WideString wide_string1(L"he");
  WideString wide_string2(L"hellp");
  WideString wide_string3(L"hellod");
  EXPECT_FALSE(wide_string_c == wide_string1);
  EXPECT_FALSE(wide_string_c == wide_string2);
  EXPECT_FALSE(wide_string_c == wide_string3);
  EXPECT_FALSE(wide_string1 == wide_string_c);
  EXPECT_FALSE(wide_string2 == wide_string_c);
  EXPECT_FALSE(wide_string3 == wide_string_c);

  const wchar_t* const c_string_same1 = L"hello";
  EXPECT_TRUE(wide_string_c == c_string_same1);
  EXPECT_TRUE(c_string_same1 == wide_string_c);

  const wchar_t* const c_string1 = L"he";
  const wchar_t* const c_string2 = L"hellp";
  const wchar_t* const c_string3 = L"hellod";
  EXPECT_FALSE(wide_string_c == c_string1);
  EXPECT_FALSE(wide_string_c == c_string2);
  EXPECT_FALSE(wide_string_c == c_string3);

  EXPECT_FALSE(c_string1 == wide_string_c);
  EXPECT_FALSE(c_string2 == wide_string_c);
  EXPECT_FALSE(c_string3 == wide_string_c);
}

TEST(WideStringView, OperatorNE) {
  WideStringView wide_string_c(L"hello");
  EXPECT_FALSE(wide_string_c != wide_string_c);

  WideStringView wide_string_c_same1(L"hello");
  EXPECT_FALSE(wide_string_c != wide_string_c_same1);
  EXPECT_FALSE(wide_string_c_same1 != wide_string_c);

  WideStringView wide_string_c_same2(wide_string_c);
  EXPECT_FALSE(wide_string_c != wide_string_c_same2);
  EXPECT_FALSE(wide_string_c_same2 != wide_string_c);

  WideStringView wide_string_c1(L"he");
  WideStringView wide_string_c2(L"hellp");
  WideStringView wide_string_c3(L"hellod");
  EXPECT_TRUE(wide_string_c != wide_string_c1);
  EXPECT_TRUE(wide_string_c != wide_string_c2);
  EXPECT_TRUE(wide_string_c != wide_string_c3);
  EXPECT_TRUE(wide_string_c1 != wide_string_c);
  EXPECT_TRUE(wide_string_c2 != wide_string_c);
  EXPECT_TRUE(wide_string_c3 != wide_string_c);

  WideString wide_string_same1(L"hello");
  EXPECT_FALSE(wide_string_c != wide_string_same1);
  EXPECT_FALSE(wide_string_same1 != wide_string_c);

  WideString wide_string1(L"he");
  WideString wide_string2(L"hellp");
  WideString wide_string3(L"hellod");
  EXPECT_TRUE(wide_string_c != wide_string1);
  EXPECT_TRUE(wide_string_c != wide_string2);
  EXPECT_TRUE(wide_string_c != wide_string3);
  EXPECT_TRUE(wide_string1 != wide_string_c);
  EXPECT_TRUE(wide_string2 != wide_string_c);
  EXPECT_TRUE(wide_string3 != wide_string_c);

  const wchar_t* const c_string_same1 = L"hello";
  EXPECT_FALSE(wide_string_c != c_string_same1);
  EXPECT_FALSE(c_string_same1 != wide_string_c);

  const wchar_t* const c_string1 = L"he";
  const wchar_t* const c_string2 = L"hellp";
  const wchar_t* const c_string3 = L"hellod";
  EXPECT_TRUE(wide_string_c != c_string1);
  EXPECT_TRUE(wide_string_c != c_string2);
  EXPECT_TRUE(wide_string_c != c_string3);

  EXPECT_TRUE(c_string1 != wide_string_c);
  EXPECT_TRUE(c_string2 != wide_string_c);
  EXPECT_TRUE(c_string3 != wide_string_c);
}

TEST(WideStringView, Find) {
  WideStringView null_string;
  EXPECT_FALSE(null_string.Find(L'a').has_value());
  EXPECT_FALSE(null_string.Find(L'\0').has_value());

  WideStringView empty_string(L"");
  EXPECT_FALSE(empty_string.Find(L'a').has_value());
  EXPECT_FALSE(empty_string.Find(L'\0').has_value());

  Optional<size_t> result;
  WideStringView single_string(L"a");
  result = single_string.Find(L'a');
  ASSERT_TRUE(result.has_value());
  EXPECT_EQ(0u, result.value());
  EXPECT_FALSE(single_string.Find(L'b').has_value());
  EXPECT_FALSE(single_string.Find(L'\0').has_value());

  WideStringView longer_string(L"abccc");
  result = longer_string.Find(L'a');
  ASSERT_TRUE(result.has_value());
  EXPECT_EQ(0u, result.value());
  result = longer_string.Find(L'c');
  ASSERT_TRUE(result.has_value());
  EXPECT_EQ(2u, result.value());
  EXPECT_FALSE(longer_string.Find(L'd').has_value());
  EXPECT_FALSE(longer_string.Find(L'\0').has_value());

  WideStringView hibyte_string(
      L"ab\xFF8c"
      L"def");
  result = hibyte_string.Find(L'\xFF8c');
  ASSERT_TRUE(result.has_value());
  EXPECT_EQ(2u, result.value());
}

TEST(WideStringView, NullIterator) {
  WideStringView null_str;
  int32_t sum = 0;
  bool any_present = false;
  for (const auto& c : null_str) {
    sum += c;  // Avoid unused arg warnings.
    any_present = true;
  }
  EXPECT_FALSE(any_present);
  EXPECT_EQ(0, sum);
}

TEST(WideStringView, EmptyIterator) {
  WideStringView empty_str(L"");
  int32_t sum = 0;
  bool any_present = false;
  for (const auto& c : empty_str) {
    any_present = true;
    sum += c;  // Avoid unused arg warnings.
  }
  EXPECT_FALSE(any_present);
  EXPECT_EQ(0, sum);
}

TEST(WideStringView, OneCharIterator) {
  WideStringView one_str(L"a");
  int32_t sum = 0;
  bool any_present = false;
  for (const auto& c : one_str) {
    any_present = true;
    sum += c;  // Avoid unused arg warnings.
  }
  EXPECT_TRUE(any_present);
  EXPECT_EQ(static_cast<int32_t>(L'a'), sum);
}

TEST(WideStringView, MultiCharIterator) {
  WideStringView one_str(L"abc");
  int32_t sum = 0;
  bool any_present = false;
  for (const auto& c : one_str) {
    any_present = true;
    sum += c;  // Avoid unused arg warnings.
  }
  EXPECT_TRUE(any_present);
  EXPECT_EQ(static_cast<int32_t>(L'a' + L'b' + L'c'), sum);
}

TEST(WideStringView, EmptyReverseIterator) {
  WideStringView empty;
  auto iter = empty.rbegin();
  EXPECT_TRUE(iter == empty.rend());
  EXPECT_FALSE(iter != empty.rend());
  EXPECT_FALSE(iter < empty.rend());
}

TEST(WideStringView, OneCharReverseIterator) {
  WideStringView one_str(L"a");
  auto iter = one_str.rbegin();
  EXPECT_FALSE(iter == one_str.rend());
  EXPECT_TRUE(iter != one_str.rend());
  EXPECT_TRUE(iter < one_str.rend());

  char ch = *iter++;
  EXPECT_EQ('a', ch);
  EXPECT_TRUE(iter == one_str.rend());
  EXPECT_FALSE(iter != one_str.rend());
  EXPECT_FALSE(iter < one_str.rend());
}

TEST(WideStringView, MultiCharReverseIterator) {
  WideStringView multi_str(L"abcd");
  auto iter = multi_str.rbegin();
  EXPECT_FALSE(iter == multi_str.rend());

  char ch = *iter++;
  EXPECT_EQ('d', ch);
  EXPECT_EQ('c', *iter);
  EXPECT_FALSE(iter == multi_str.rend());

  ch = *(++iter);
  EXPECT_EQ('b', ch);
  EXPECT_EQ('b', *iter);
  EXPECT_FALSE(iter == multi_str.rend());

  ch = *iter++;
  EXPECT_EQ('b', ch);
  EXPECT_EQ('a', *iter);
  EXPECT_FALSE(iter == multi_str.rend());

  ch = *iter++;
  EXPECT_EQ('a', ch);
  EXPECT_TRUE(iter == multi_str.rend());

  ch = *(--iter);
  EXPECT_EQ('a', ch);
  EXPECT_EQ('a', *iter);
  EXPECT_FALSE(iter == multi_str.rend());

  ch = *iter--;
  EXPECT_EQ('a', ch);
  EXPECT_EQ('b', *iter);
  EXPECT_FALSE(iter == multi_str.rend());

  ch = *iter--;
  EXPECT_EQ('b', ch);
  EXPECT_EQ('c', *iter);
  EXPECT_FALSE(iter == multi_str.rend());

  ch = *(--iter);
  EXPECT_EQ('d', ch);
  EXPECT_EQ('d', *iter);
  EXPECT_TRUE(iter == multi_str.rbegin());
}

TEST(WideStringView, AnyAllNoneOf) {
  WideStringView str(L"aaaaaaaaaaaaaaaaab");
  EXPECT_FALSE(std::all_of(str.begin(), str.end(),
                           [](const wchar_t& c) { return c == L'a'; }));

  EXPECT_FALSE(std::none_of(str.begin(), str.end(),
                            [](const wchar_t& c) { return c == L'a'; }));

  EXPECT_TRUE(std::any_of(str.begin(), str.end(),
                          [](const wchar_t& c) { return c == L'a'; }));

  EXPECT_TRUE(pdfium::ContainsValue(str, L'a'));
  EXPECT_TRUE(pdfium::ContainsValue(str, L'b'));
  EXPECT_FALSE(pdfium::ContainsValue(str, L'z'));
}

TEST(WideStringView, TrimmedRight) {
  WideStringView fred(L"FRED");
  EXPECT_EQ(L"FRED", fred.TrimmedRight(L'E'));
  EXPECT_EQ(L"FRE", fred.TrimmedRight(L'D'));
  WideStringView fredd(L"FREDD");
  EXPECT_EQ(L"FRE", fred.TrimmedRight(L'D'));
}

TEST(WideString, FormatWidth) {
  EXPECT_EQ(L"    1", WideString::Format(L"%5d", 1));
  EXPECT_EQ(L"1", WideString::Format(L"%d", 1));
  EXPECT_EQ(L"    1", WideString::Format(L"%*d", 5, 1));
  EXPECT_EQ(L"1", WideString::Format(L"%-1d", 1));
  EXPECT_EQ(L"1", WideString::Format(L"%0d", 1));
  EXPECT_EQ(L"", WideString::Format(L"%1048576d", 1));
}

TEST(WideString, FormatPrecision) {
  EXPECT_EQ(L"1.12", WideString::Format(L"%.2f", 1.12345));
  EXPECT_EQ(L"1.123", WideString::Format(L"%.*f", 3, 1.12345));
  EXPECT_EQ(L"1.123450", WideString::Format(L"%f", 1.12345));
  EXPECT_EQ(L"1.123450", WideString::Format(L"%-1f", 1.12345));
  EXPECT_EQ(L"1.123450", WideString::Format(L"%0f", 1.12345));
  EXPECT_EQ(L"", WideString::Format(L"%.1048576f", 1.2));
}

TEST(WideString, FormatOutOfRangeChar) {
  EXPECT_NE(L"", WideString::Format(L"unsupported char '%c'", 0x00FF00FF));
}

TEST(WideString, FormatString) {
  // %ls and wide characters are the reliable combination across platforms.
  EXPECT_EQ(L"", WideString::Format(L"%ls", L""));
  EXPECT_EQ(L"", WideString::Format(L"%ls", WideString().c_str()));
  EXPECT_EQ(L"clams", WideString::Format(L"%ls", L"clams"));
  EXPECT_EQ(L"cla", WideString::Format(L"%.3ls", L"clams"));
  EXPECT_EQ(L"\u043e\u043f", WideString(L"\u043e\u043f"));

#if !defined(OS_MACOSX)
  // See https://bugs.chromium.org/p/pdfium/issues/detail?id=1132
  EXPECT_EQ(L"\u043e\u043f", WideString::Format(L"\u043e\u043f"));
  EXPECT_EQ(L"\u043e\u043f", WideString::Format(L"%ls", L"\u043e\u043f"));
  EXPECT_EQ(L"\u043e", WideString::Format(L"%.1ls", L"\u043e\u043f"));
#endif
}

TEST(WideString, Empty) {
  WideString empty_str;
  EXPECT_TRUE(empty_str.IsEmpty());
  EXPECT_EQ(0u, empty_str.GetLength());

  const wchar_t* cstr = empty_str.c_str();
  EXPECT_NE(nullptr, cstr);
  EXPECT_EQ(0u, wcslen(cstr));

  pdfium::span<const wchar_t> cspan = empty_str.span();
  EXPECT_TRUE(cspan.empty());
  EXPECT_EQ(nullptr, cspan.data());
}

TEST(CFX_WidString, InitializerList) {
  WideString many_str({L"clams", L" and ", L"oysters"});
  EXPECT_EQ(L"clams and oysters", many_str);
  many_str = {L"fish", L" and ", L"chips", L" and ", L"soda"};
  EXPECT_EQ(L"fish and chips and soda", many_str);
}

TEST(WideString, NullIterator) {
  WideString null_str;
  int32_t sum = 0;
  bool any_present = false;
  for (const auto& c : null_str) {
    sum += c;  // Avoid unused arg warnings.
    any_present = true;
  }
  EXPECT_FALSE(any_present);
  EXPECT_EQ(0, sum);
}

TEST(WideString, EmptyIterator) {
  WideString empty_str(L"");
  int32_t sum = 0;
  bool any_present = false;
  for (const auto& c : empty_str) {
    any_present = true;
    sum += c;  // Avoid unused arg warnings.
  }
  EXPECT_FALSE(any_present);
  EXPECT_EQ(0, sum);
}

TEST(WideString, OneCharIterator) {
  WideString one_str(L"a");
  int32_t sum = 0;
  bool any_present = false;
  for (const auto& c : one_str) {
    any_present = true;
    sum += c;  // Avoid unused arg warnings.
  }
  EXPECT_TRUE(any_present);
  EXPECT_EQ(static_cast<int32_t>(L'a'), sum);
}

TEST(WideString, MultiCharIterator) {
  WideString one_str(L"abc");
  int32_t sum = 0;
  bool any_present = false;
  for (const auto& c : one_str) {
    any_present = true;
    sum += c;  // Avoid unused arg warnings.
  }
  EXPECT_TRUE(any_present);
  EXPECT_EQ(static_cast<int32_t>(L'a' + L'b' + L'c'), sum);
}

TEST(WideString, StdBegin) {
  WideString one_str(L"abc");
  std::vector<wchar_t> vec(std::begin(one_str), std::end(one_str));
  ASSERT_EQ(3u, vec.size());
  EXPECT_EQ(L'a', vec[0]);
  EXPECT_EQ(L'b', vec[1]);
  EXPECT_EQ(L'c', vec[2]);
}

TEST(WideString, AnyAllNoneOf) {
  WideString str(L"aaaaaaaaaaaaaaaaab");
  EXPECT_FALSE(std::all_of(str.begin(), str.end(),
                           [](const wchar_t& c) { return c == L'a'; }));

  EXPECT_FALSE(std::none_of(str.begin(), str.end(),
                            [](const wchar_t& c) { return c == L'a'; }));

  EXPECT_TRUE(std::any_of(str.begin(), str.end(),
                          [](const wchar_t& c) { return c == L'a'; }));

  EXPECT_TRUE(pdfium::ContainsValue(str, L'a'));
  EXPECT_TRUE(pdfium::ContainsValue(str, L'b'));
  EXPECT_FALSE(pdfium::ContainsValue(str, L'z'));
}

TEST(WideString, OStreamOverload) {
  std::ostringstream stream;

  // Basic case, empty string
  WideString str;
  stream << str;
  EXPECT_EQ("", stream.str());

  // Basic case, wide character
  str = L"\u20AC";
  stream << str;
  EXPECT_EQ("\u20AC", stream.str());

  // Basic case, non-empty string
  str = L"def";
  stream.str("");
  stream << "abc" << str << "ghi";
  EXPECT_EQ("abcdefghi", stream.str());

  // Changing the WideString does not change the stream it was written to.
  str = L"123";
  EXPECT_EQ("abcdefghi", stream.str());

  // Writing it again to the stream will use the latest value.
  stream.str("");
  stream << "abc" << str << "ghi";
  EXPECT_EQ("abc123ghi", stream.str());

  wchar_t stringWithNulls[]{'x', 'y', '\0', 'z'};

  // Writing a WideString with nulls and no specified length treats it as
  // a C-style null-terminated string.
  str = WideString(stringWithNulls);
  EXPECT_EQ(2u, str.GetLength());
  stream.str("");
  stream << str;
  EXPECT_EQ(2u, stream.tellp());

  // Writing a WideString with nulls but specifying its length treats it as
  // a C++-style string.
  str = WideString(stringWithNulls, 4);
  EXPECT_EQ(4u, str.GetLength());
  stream.str("");
  stream << str;
  EXPECT_EQ(4u, stream.tellp());

  // << operators can be chained.
  WideString str1(L"abc");
  WideString str2(L"def");
  stream.str("");
  stream << str1 << str2;
  EXPECT_EQ("abcdef", stream.str());
}

TEST(WideString, WideOStreamOverload) {
  std::wostringstream stream;

  // Basic case, empty string
  WideString str;
  stream << str;
  EXPECT_EQ(L"", stream.str());

  // Basic case, wide character
  str = L"\u20AC";
  stream << str;
  EXPECT_EQ(L"\u20AC", stream.str());

  // Basic case, non-empty string
  str = L"def";
  stream.str(L"");
  stream << L"abc" << str << L"ghi";
  EXPECT_EQ(L"abcdefghi", stream.str());

  // Changing the WideString does not change the stream it was written to.
  str = L"123";
  EXPECT_EQ(L"abcdefghi", stream.str());

  // Writing it again to the stream will use the latest value.
  stream.str(L"");
  stream << L"abc" << str << L"ghi";
  EXPECT_EQ(L"abc123ghi", stream.str());

  wchar_t stringWithNulls[]{'x', 'y', '\0', 'z'};

  // Writing a WideString with nulls and no specified length treats it as
  // a C-style null-terminated string.
  str = WideString(stringWithNulls);
  EXPECT_EQ(2u, str.GetLength());
  stream.str(L"");
  stream << str;
  EXPECT_EQ(2u, stream.tellp());

  // Writing a WideString with nulls but specifying its length treats it as
  // a C++-style string.
  str = WideString(stringWithNulls, 4);
  EXPECT_EQ(4u, str.GetLength());
  stream.str(L"");
  stream << str;
  EXPECT_EQ(4u, stream.tellp());

  // << operators can be chained.
  WideString str1(L"abc");
  WideString str2(L"def");
  stream.str(L"");
  stream << str1 << str2;
  EXPECT_EQ(L"abcdef", stream.str());
}

TEST(WideStringView, OStreamOverload) {
  // Basic case, empty string
  {
    std::ostringstream stream;
    WideStringView str;
    stream << str;
    EXPECT_EQ("", stream.str());
  }

  // Basic case, non-empty string
  {
    std::ostringstream stream;
    WideStringView str(L"def");
    stream << "abc" << str << "ghi";
    EXPECT_EQ("abcdefghi", stream.str());
  }

  // Basic case, wide character
  {
    std::ostringstream stream;
    WideStringView str(L"\u20AC");
    stream << str;
    EXPECT_EQ("\u20AC", stream.str());
  }

  // Changing the WideStringView does not change the stream it was written to.
  {
    std::ostringstream stream;
    WideStringView str(L"abc");
    stream << str;
    str = L"123";
    EXPECT_EQ("abc", stream.str());
  }

  // Writing it again to the stream will use the latest value.
  {
    std::ostringstream stream;
    WideStringView str(L"abc");
    stream << str;
    stream.str("");
    str = L"123";
    stream << str;
    EXPECT_EQ("123", stream.str());
  }

  // Writing a WideStringView with nulls and no specified length treats it as
  // a C-style null-terminated string.
  {
    wchar_t stringWithNulls[]{'x', 'y', '\0', 'z'};
    std::ostringstream stream;
    WideStringView str(stringWithNulls);
    EXPECT_EQ(2u, str.GetLength());
    stream << str;
    EXPECT_EQ(2u, stream.tellp());
    str = L"";
  }

  // Writing a WideStringView with nulls but specifying its length treats it as
  // a C++-style string.
  {
    wchar_t stringWithNulls[]{'x', 'y', '\0', 'z'};
    std::ostringstream stream;
    WideStringView str(stringWithNulls, 4);
    EXPECT_EQ(4u, str.GetLength());
    stream << str;
    EXPECT_EQ(4u, stream.tellp());
    str = L"";
  }

  // << operators can be chained.
  {
    std::ostringstream stream;
    WideStringView str1(L"abc");
    WideStringView str2(L"def");
    stream << str1 << str2;
    EXPECT_EQ("abcdef", stream.str());
  }
}

TEST(WideStringView, WideOStreamOverload) {
  // Basic case, empty string
  {
    std::wostringstream stream;
    WideStringView str;
    stream << str;
    EXPECT_EQ(L"", stream.str());
  }

  // Basic case, non-empty string
  {
    std::wostringstream stream;
    WideStringView str(L"def");
    stream << "abc" << str << "ghi";
    EXPECT_EQ(L"abcdefghi", stream.str());
  }

  // Basic case, wide character
  {
    std::wostringstream stream;
    WideStringView str(L"\u20AC");
    stream << str;
    EXPECT_EQ(L"\u20AC", stream.str());
  }

  // Changing the WideStringView does not change the stream it was written to.
  {
    std::wostringstream stream;
    WideStringView str(L"abc");
    stream << str;
    str = L"123";
    EXPECT_EQ(L"abc", stream.str());
  }

  // Writing it again to the stream will use the latest value.
  {
    std::wostringstream stream;
    WideStringView str(L"abc");
    stream << str;
    stream.str(L"");
    str = L"123";
    stream << str;
    EXPECT_EQ(L"123", stream.str());
  }

  // Writing a WideStringView with nulls and no specified length treats it as
  // a C-style null-terminated string.
  {
    wchar_t stringWithNulls[]{'x', 'y', '\0', 'z'};
    std::wostringstream stream;
    WideStringView str(stringWithNulls);
    EXPECT_EQ(2u, str.GetLength());
    stream << str;
    EXPECT_EQ(2u, stream.tellp());
  }

  // Writing a WideStringView with nulls but specifying its length treats it as
  // a C++-style string.
  {
    wchar_t stringWithNulls[]{'x', 'y', '\0', 'z'};
    std::wostringstream stream;
    WideStringView str(stringWithNulls, 4);
    EXPECT_EQ(4u, str.GetLength());
    stream << str;
    EXPECT_EQ(4u, stream.tellp());
  }

  // << operators can be chained.
  {
    std::wostringstream stream;
    WideStringView str1(L"abc");
    WideStringView str2(L"def");
    stream << str1 << str2;
    EXPECT_EQ(L"abcdef", stream.str());
  }
}

TEST(WideString, FX_HashCode_Wide) {
  EXPECT_EQ(0u, FX_HashCode_GetW(L"", false));
  EXPECT_EQ(65u, FX_HashCode_GetW(L"A", false));
  EXPECT_EQ(97u, FX_HashCode_GetW(L"A", true));
  EXPECT_EQ(1313 * 65u + 66u, FX_HashCode_GetW(L"AB", false));
  EXPECT_EQ(FX_HashCode_GetAsIfW("AB\xff", false),
            FX_HashCode_GetW(L"AB\xff", false));
  EXPECT_EQ(FX_HashCode_GetAsIfW("AB\xff", true),
            FX_HashCode_GetW(L"AB\xff", true));
}

}  // namespace fxcrt


text:
from __future__ import print_function

'''
Parses the files in the input directory using bllip parser.
'''

import logging
import sys
import argparse
import os.path
import glob
from bllipparser import RerankingParser
from bllipbioc.bllip_wrapper import init_model, parse_file

__author__ = 'Yifan Peng'

def parse_argv():
    """
    Parses arguments.

    :return: filelist
    :rtype: list
    """
    parser = argparse.ArgumentParser(description="Parses the input files using bllip parser.")
    parser.add_argument("-v", "--verbose", action="store_true", help="print debug information")
    parser.add_argument("pathnames", nargs='+', help="input files (support pattens by the Unix "
                                                     "shell)")
    args = parser.parse_args()

    if args.verbose:
        logging.basicConfig(level=logging.DEBUG)

    logging.info('Pathnames: %s' % args.pathnames)
    return args.pathnames

if __name__ == "__main__":
    pathnames = parse_argv()

    model_dir = init_model()
    logging.info('loading model %s ...' % model_dir)
    rrp = RerankingParser.from_unified_model_dir(model_dir)

    for pathname in pathnames:

        inputfilenames = glob.glob(pathname)

        for inputfilename in inputfilenames:

            if not os.path.isfile(inputfilename):
                sys.stderr.write('Cannot find input file: %s\n' % inputfilename)
                continue

            outputfilename = inputfilename + ".ptb"

            # create lck
            lckfilename = outputfilename + ".lck"
            logging.info('create lck file: %s' % lckfilename)
            open(lckfilename, 'w').close()

            # parse file
            parse_file(rrp, inputfilename, outputfilename)

            # remove lck
            logging.info('remove lck file: %s' % lckfilename)
            os.remove(lckfilename)

redpajama_set_name: RedPajamaGithub


text:
package com.intellij.vcs.log.graph;

import com.intellij.openapi.vfs.newvfs.impl.StubVirtualFile;
import com.intellij.vcs.log.GraphCommit;
import com.intellij.vcs.log.VcsRef;
import com.intellij.vcs.log.graph.elements.Branch;
import com.intellij.vcs.log.graph.elements.Node;
import com.intellij.vcs.log.graph.elements.NodeRow;
import com.intellij.vcs.log.graph.mutable.GraphBuilder;
import com.intellij.vcs.log.graph.mutable.MutableGraph;
import com.intellij.vcs.log.parser.SimpleCommitListParser;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.io.StringReader;
import java.util.*;

/**
 * @author erokhins
 */
public class GraphTestUtils {

  @NotNull
  public static Node getCommitNode(Graph graph, int rowIndex) {
    NodeRow row = graph.getNodeRows().get(rowIndex);
    for (Node node : row.getNodes()) {
      if (node.getType() == Node.NodeType.COMMIT_NODE) {
        return node;
      }
    }
    throw new IllegalArgumentException();
  }

  @NotNull
  public static MutableGraph getNewMutableGraph(@NotNull String inputStr) {
    SimpleCommitListParser parser = new SimpleCommitListParser(new StringReader(inputStr));
    List<GraphCommit> vcsCommitParentses;
    try {
      vcsCommitParentses = parser.readAllCommits();
    }
    catch (IOException e) {
      throw new IllegalStateException();
    }
    return buildGraph(vcsCommitParentses, Collections.<VcsRef>emptyList());
  }

  @NotNull
  public static MutableGraph buildGraph(@NotNull List<GraphCommit> commitParentses, @NotNull List<VcsRef> refs) {
    GraphBuilder builder = new GraphBuilder(commitParentses.size() - 1, GraphBuilder.calcCommitLogIndices(commitParentses), refs) {
      @NotNull
      @Override
      protected Branch createBranch(int commitHash, @NotNull Collection<VcsRef> refs) {
        // allow no refs in tests
        return createBranchWithFakeRoot(commitHash, refs);
      }
    };
    return builder.runBuild(commitParentses);
  }

  @NotNull
  public static Branch createBranchWithFakeRoot(int commitHash, @NotNull Collection<VcsRef> refs) {
    return new Branch(commitHash, refs, new StubVirtualFile());
  }

  // "1 20 3" -> {1,20,3}
  @NotNull
  public static Set<Integer> parseIntegers(@NotNull String str) {
    if (str.length() == 0) {
      return Collections.emptySet();
    }
    String[] strings = str.split(" ");
    Set<Integer> integers = new HashSet<Integer>();
    for (String s : strings) {
      integers.add(Integer.parseInt(s));
    }
    return integers;
  }
}


text:
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE html
    PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "DTD/xhtml1-strict.dtd">

  <title>Qt 4.3: List of All Members for QStyleOptionQ3ListViewItem</title>
  <link href="classic.css" rel="stylesheet" type="text/css" />

  	Home · All Classes · Main Classes · Grouped Classes · Modules · Functions

List of All Members for QStyleOptionQ3ListViewItem

This is the complete list of members for QStyleOptionQ3ListViewItem, including inherited members.

enum OptionType

enum Q3ListViewItemFeature

flags Q3ListViewItemFeatures

enum StyleOptionType

enum StyleOptionVersion

QStyleOptionQ3ListViewItem ()

QStyleOptionQ3ListViewItem ( const QStyleOptionQ3ListViewItem & )

childCount : int

direction : Qt::LayoutDirection

features : Q3ListViewItemFeatures

fontMetrics : QFontMetrics

height : int

initFrom ( const QWidget * )

itemY : int

palette : QPalette

rect : QRect

state : QStyle::State

totalHeight : int

type : int

version : int

operator= ( const QStyleOption & ) : QStyleOption &

<address>

Copyright © 2008 Trolltech
Trademarks

Qt 4.3.5

</address>


text:
import actionTypes from './actions';
import Action from './Action';
import * as actionClasses from 'glob:action-classes/*.js';

export class ActionFactory {

	getActionSpecification(actionName, actionTypes) {
		let actionSpec = actionTypes[actionName];

		if (typeof actionSpec === 'undefined') {
			throw new Error('Action type '+actionName+' does not exist.')
		}
		if (typeof actionSpec.type == 'undefined') {
			throw new Error('Mandatory field "type" not specified for action '+actionName+' in actions.json.');
		}
		if (typeof actionSpec.args == 'undefined') {
			throw new Error('Mandatory field "args" not specified for action '+actionName+' in actions.json.');
		}
		if (!Array.isArray(actionSpec.args)) {
			throw new Error('Field "args" should be an array for action '+actionName+' in actions.json');
		}

		return actionSpec;
	}

	getValidatedData(actionName, actionSpec, data) {
		return actionSpec.args.reduce((previous, item) => {
			let arg = data[item];
			if (typeof arg === 'undefined') {
				throw new SyntaxError('Field '+item+' missing in action '+actionName+'.');
			}
			return {...previous, [item]: arg};
		}, {});
	}

	getActionClass(className, actionClasses) {
		let actionClass = actionClasses[className];

		if (typeof actionClass == 'undefined') {
			actionClass = Action;
		}

		return actionClass;
	}

	getActionObject(actionName, actionData) {
		const spec = this.getActionSpecification(actionName, actionTypes);

		const ActionClass = this.getActionClass(spec.class, actionClasses);

		return new ActionClass(spec.type, this.getValidatedData(actionName, spec, actionData));
	}

	/**
	 * Returns a dispatchable object/function for this action, if data fits the specs in actions.json.
	 *
	 * @param actionName {string} The name of the action in actions.json.
	 * @param actionData {object} The named parameters that action takes.
	 * @returns {*|mixed} If no class is defined in actions.json for this actionName, a raw action object with
	 *  the actionData as params and an additional param type. If otherwise a class is defined, whatever that class's
	 *  getDispatchable() returns.
	 */
	createAction(actionName, actionData) {
		let action = this.getActionObject(actionName, actionData);
		return action.getDispatchable();
	}

	/**
	 * Always returns a synchronously dispatchable object, never a function. Warning: Intended use for testing,
	 *  do not use in production.
	 *
	 * @param actionName {string} The name of the action in actions.json.
	 * @param actionData {object} The named parameters that action takes.
	 * @return A raw action object with the actionData as params and an additional param type.
	 */
	createRawAction(actionName, actionData) {
		let action = this.getActionObject(actionName, actionData);
		return action.rawAction();
	}

}

const actionFactory = new ActionFactory();

export default actionFactory.createAction.bind(actionFactory);


text:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">

	<import resource="applicationContext-persistence.xml" />

	<beans profile="default">
		<context:property-placeholder
			location="classpath*:META-INF/spring/*.properties,classpath*:META-INF/spring/default/*.properties" />
	</beans>
	<beans profile="heroku">
		<context:property-placeholder
			location="classpath*:META-INF/spring/*.properties,classpath*:META-INF/spring/heroku/*.properties" />
	</beans>
</beans>


text: © 2011–{{ site.time | date: '%Y' }} {{ site.data.custom.title }}


text:
package us.stump.imgurapitest.api.service;

import java.util.List;

import okhttp3.MultipartBody;
import retrofit2.Call;
import retrofit2.http.DELETE;
import retrofit2.http.Field;
import retrofit2.http.GET;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.Part;
import retrofit2.http.Path;
import us.stump.imgurapitest.api.model.ImgurBasicResponse;
import us.stump.imgurapitest.api.model.ImgurImage;
import us.stump.imgurapitest.api.model.ImgurImagesResponse;

/**
 * Retrofit2 interface for the Imgur API.
 */
public interface ImgurClient {

    /**
     * Get a list of images for the given user
     * @param username The username for the user (or "me" for the currently logged in user)
     * @param page The page of data you want, for pagination (starting at 0)
     * @return A List of image objects
     */
    @GET("account/{username}/images/{page}")
    Call<ImgurImagesResponse> imagesForUser(@Path("username") String username, @Path("page") Integer page);

    /**
     * Get the data for an image, by id.
     * @param id The id for the image
     * @return Image object representing the given image
     */
    @GET("image/{id}")
    Call<ImgurImage> imageById(@Path("id") String id);

    /**
     * Upload a new image
     * @return
     */
    @Multipart
    @POST("image")
    Call<ImgurBasicResponse> addImage(@Part MultipartBody.Part image);

    /**
     * Delete a new image
     * @param username
     * @param deletehash
     * @return
     */
    @DELETE("account/{username}/image/{deletehash}")
    Call<Void> deleteImage(@Path("username") String username, @Path("deletehash") String deletehash);
}


text:
(function () {
    'use strict';

    /* Base functionality for an extension which will display
     * a 'form' inside the toolbar
     */
    var FormExtension = MediumEditor.extensions.button.extend({

        init: function () {
            MediumEditor.extensions.button.prototype.init.apply(this, arguments);
        },

        // default labels for the form buttons
        formSaveLabel: '✓',
        formCloseLabel: '×',

        /* activeClass: [string]
         * set class which added to shown form
         */
        activeClass: 'medium-editor-toolbar-form-active',

        /* hasForm: [boolean]
         *
         * Setting this to true will cause getForm() to be called
         * when the toolbar is created, so the form can be appended
         * inside the toolbar container
         */
        hasForm: true,

        /* getForm: [function ()]
         *
         * When hasForm is true, this function must be implemented
         * and return a DOM Element which will be appended to
         * the toolbar container. The form should start hidden, and
         * the extension can choose when to hide/show it
         */
        getForm: function () {},

        /* isDisplayed: [function ()]
         *
         * This function should return true/false reflecting
         * whether the form is currently displayed
         */
        isDisplayed: function () {
            if (this.hasForm) {
                return this.getForm().classList.contains(this.activeClass);
            }
            return false;
        },

        /* hideForm: [function ()]
         *
         * This function should show the form element inside
         * the toolbar container
         */
        showForm: function () {
            if (this.hasForm) {
                this.getForm().classList.add(this.activeClass);
            }
        },

        /* hideForm: [function ()]
         *
         * This function should hide the form element inside
         * the toolbar container
         */
        hideForm: function () {
            if (this.hasForm) {
                this.getForm().classList.remove(this.activeClass);
            }
        },

        /************************ Helpers ************************
         * The following are helpers that are either set by MediumEditor
         * during initialization, or are helper methods which either
         * route calls to the MediumEditor instance or provide common
         * functionality for all form extensions
         *********************************************************/

        /* showToolbarDefaultActions: [function ()]
         *
         * Helper method which will turn back the toolbar after canceling
         * the customized form
         */
        showToolbarDefaultActions: function () {
            var toolbar = this.base.getExtensionByName('toolbar');
            if (toolbar) {
                toolbar.showToolbarDefaultActions();
            }
        },

        /* hideToolbarDefaultActions: [function ()]
         *
         * Helper function which will hide the default contents of the
         * toolbar, but leave the toolbar container in the same state
         * to allow a form to display its custom contents inside the toolbar
         */
        hideToolbarDefaultActions: function () {
            var toolbar = this.base.getExtensionByName('toolbar');
            if (toolbar) {
                toolbar.hideToolbarDefaultActions();
            }
        },

        /* setToolbarPosition: [function ()]
         *
         * Helper function which will update the size and position
         * of the toolbar based on the toolbar content and the current
         * position of the user's selection
         */
        setToolbarPosition: function () {
            var toolbar = this.base.getExtensionByName('toolbar');
            if (toolbar) {
                toolbar.setToolbarPosition();
            }
        }
    });

    MediumEditor.extensions.form = FormExtension;
})();


text:
from django import template
from django.conf import settings
from django.template.loader import get_template

register = template.Library()

def _preprocess_fields(form):
    for field in form.fields:
        name = form.fields[field].widget.__class__.__name__.lower()
        if not name.startswith("radio") and not name.startswith("checkbox"):
            try:
                form.fields[field].widget.attrs["class"] += " form-control"
            except KeyError:
                form.fields[field].widget.attrs["class"] = " form-control"
    return form

@register.filter
def render_form(form):
    """same than  {{ form|crispy }} if crispy_forms is installed.
    render using a bootstrap3 templating otherwise"""

    if 'crispy_forms' in settings.INSTALLED_APPS:
        from crispy_forms.templatetags.crispy_forms_filters import as_crispy_form
        return as_crispy_form(form)

    template = get_template("bootstrap/form.html")
    form = _preprocess_fields(form)

    return template.render({"form": form})

@register.filter
def as_bootstrap_inline(form):
    template = get_template("bootstrap/form.html")
    form = _preprocess_fields(form)

    for field in form.fields:
        name = form.fields[field].widget.__class__.__name__.lower()
        if not name.startswith("radio") and not name.startswith("checkbox"):
            form.fields[field].widget.attrs["placeholder"] = form.fields[field].label
    css_classes = {
        "label": "sr-only",
        "single_container": "",
        "wrap": "",
    }
    context = {
        "form": form,
        "css_classes": css_classes,
    }
    return template.render(contex)

@register.filter
def as_bootstrap_horizontal(form, label_classes=""):
    template = get_template("bootstrap/form.html")
    form = _preprocess_fields(form)

    if label_classes == "":
        label_classes = "col-md-2"

    css_classes = {
        "label": label_classes,
        "single_container": "",
        "wrap": "",
    }

    for label_class in label_classes.split(" "):
        split_class, column_count = label_class.rsplit("-", 1)
        column_count = int(column_count)

        if column_count < 12:
            offset_class = "{split_class}-offset-{column_count}".format(
                split_class=split_class,
                column_count=column_count,
            )
            wrap_class = "{split_class}-{column_count}".format(
                split_class=split_class,
                column_count=12 - column_count,
            )
            css_classes["single_container"] += offset_class + " " + wrap_class + " "
            css_classes["wrap"] += wrap_class + " "
    context = {
        "form": form,
        "css_classes": css_classes,
    }
    return template.render(context)

@register.filter
def css_class(field):
    return field.field.widget.__class__.__name__.lower()


text:
import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';

import {DiveRulesComponent} from './dive-rules.component';
import {DayDirective} from './yw-day.directive';
import {NightDirective} from './yw-night.directive';

@NgModule({
  imports: [BrowserModule],
  declarations: [
    DiveRulesComponent,
    DayDirective,
    NightDirective
  ],
  bootstrap: [DiveRulesComponent]
})
export class AppModule { }


text:
"""A very basic test class derived from mox.MoxTestBase, used by mox_test.py.

The class defined in this module is used to test the features of
MoxTestBase and is not intended to be a standalone test.  It needs to
be in a separate module, because otherwise the tests in this class
(which should not all pass) would be executed as part of the
mox_test.py test suite.

See mox_test.MoxTestBaseTest for how this class is actually used.
"""

import os

import mox

class ExampleMoxTestMixin(object):
  """Mix-in class for mox test case class.

  It stubs out the same function as one of the test methods in
  the example test case.  Both tests must pass as meta class wraps
  test methods in all base classes.
  """

  def testStat(self):
    self.mox.StubOutWithMock(os, 'stat')
    os.stat(self.DIR_PATH)
    self.mox.ReplayAll()
    os.stat(self.DIR_PATH)

class ExampleMoxTest(mox.MoxTestBase, ExampleMoxTestMixin):

  DIR_PATH = '/path/to/some/directory'

  def testSuccess(self):
    self.mox.StubOutWithMock(os, 'listdir')
    os.listdir(self.DIR_PATH)
    self.mox.ReplayAll()
    os.listdir(self.DIR_PATH)

  def testExpectedNotCalled(self):
    self.mox.StubOutWithMock(os, 'listdir')
    os.listdir(self.DIR_PATH)
    self.mox.ReplayAll()

  def testUnexpectedCall(self):
    self.mox.StubOutWithMock(os, 'listdir')
    os.listdir(self.DIR_PATH)
    self.mox.ReplayAll()
    os.listdir('/path/to/some/other/directory')
    os.listdir(self.DIR_PATH)

  def testFailure(self):
    self.assertTrue(False)

  def testStatOther(self):
    self.mox.StubOutWithMock(os, 'stat')
    os.stat(self.DIR_PATH)
    self.mox.ReplayAll()
    os.stat(self.DIR_PATH)

  def testHasStubs(self):
    listdir_list = []

    def MockListdir(directory):
      listdir_list.append(directory)

    self.stubs.Set(os, 'listdir', MockListdir)
    os.listdir(self.DIR_PATH)
    self.assertEqual([self.DIR_PATH], listdir_list)

class TestClassFromAnotherModule(object):

  def __init__(self):
    return None

  def Value(self):
    return 'Not mock'

class ChildClassFromAnotherModule(TestClassFromAnotherModule):
  """A child class of TestClassFromAnotherModule.

  Used to test stubbing out unbound methods, where child classes
  are eventually bound.
  """

  def __init__(self):
    TestClassFromAnotherModule.__init__(self)

class CallableClass(object):

  def __init__(self, one, two, nine=None):
    pass

  def __call__(self, one):
    return 'Not mock'

  def Value():
    return 'Not mock'

try:
  import abc

  class MyDictABC(object):
    __metaclass__ = abc.ABCMeta

  MyDictABC.register(dict)

  class CallableSubclassOfMyDictABC(MyDictABC):

    def __call__(self, one):
      return 'Not mock'

    def __getitem__(self, key, default=None):
      return 'Not mock'
except ImportError:
  pass  # Python 2.5 or earlier

def MyTestFunction(one, two, nine=None):
  pass

class ExampleClass(object):
  def __init__(self, foo='bar'):
    pass

  def TestMethod(self, one, two, nine=None):
    pass

  def NamedParams(self, ignore, foo='bar', baz='qux'):
    pass

  def SpecialArgs(self, *args, **kwargs):
    pass

# This class is used to test stubbing out __init__ of a parent class.
class ChildExampleClass(ExampleClass):
  def __init__(self):
    ExampleClass.__init__(self)


text:
import mysql.connector

class SQL:
    """
    database: account
    tables: account
        account:
            bankcard char(20)
            amount   int(11)
    """

    def __init__(self, **kw):
        # 默认设置
        self.config = {
                'user': 'root',
                'password': 'root',
                'host': 'localhost',
                'database': 'account',
                'raise_on_warnings': True
                };

        # read config from kw
        for key in kw.keys():
            if self.config[key] != None:
                self.config[key] = kw[key]

    def connect(self):
        try:
            self.cnx = mysql.connector.connect(**self.config)
            self.cursor = self.cnx.cursor()
            flag = True
        except Exception as e:
            flag = False
        finally:
            return flag

    def close(self):
        try:
            self.cnx.close()
        except:
            pass

    def execute(self, query):
        try:
            self.cursor.execute(query)
            flag = True
        except Exception as e:
            flag = False
        finally:
            return flag

    def commit(self):
        try:
            self.cnx.commit()
            flag = True
        except:
            flag = False
        finally:
            return flag

    def rollback(self):
        try:
            self.cnx.rollback()
            flag = True
        except:
            flag = False
        finally:
            return flag


text:
#region License
// Copyright (c) Amos Voron. All rights reserved.
// Licensed under the Apache 2.0 License. See LICENSE in the project root for license information.
#endregion

using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
using QueryTalk.Wall;

namespace QueryTalk
{
    public static partial class Extensions
    {

        #region Reload

        /// <summary>
        /// Reloads the specified row from the database.
        /// </summary>
        /// <typeparam name="T">The type of the row object.</typeparam>
        /// <param name="row">The row to reload.</param>
        /// <param name="forceMirroring">If true, then the optimistic concurrency check is done which throws an exception if the check fails.</param>
        public static Result<T> ReloadGo<T>(this T row, bool forceMirroring = true)
            where T : DbRow
        {
            if (row == null)
            {
                throw new QueryTalkException("extensions.ReloadGo<T>", QueryTalkExceptionType.ArgumentNull, "row = null", Text.Method.ReloadGo);
            }

            return Crud.ReloadGo<T>(Assembly.GetCallingAssembly(), row, forceMirroring, null);
        }

        #endregion

        #region Insert

        /// <summary>
        /// Inserts the specified row in the database.
        /// </summary>
        /// <typeparam name="T">The type of the row object.</typeparam>
        /// <param name="row">The row to insert.</param>
        /// <param name="identityInsert">If true, then the explicit value can be inserted into the identity column of a table.</param>
        public static Result<T> InsertGo<T>(this T row, bool identityInsert = false)
            where T : DbRow
        {
            if (row == null)
            {
                throw new QueryTalkException("extensions.InsertGo<T>", QueryTalkExceptionType.ArgumentNull, "row = null", Text.Method.InsertGo);
            }

            return Crud.InsertGo<T>(Assembly.GetCallingAssembly(), row, identityInsert, null);
        }

        /// <summary>
        /// Inserts the specified row in the database asynchronously.
        /// </summary>
        /// <typeparam name="T">The type of the row object.</typeparam>
        /// <param name="row">The row to insert.</param>
        /// <param name="identityInsert">If true, then the explicit value can be inserted into the identity column of a table.</param>
        /// <param name="onCompleted">A delegate method that is called when the asynchronous operation completes.</param>
        /// <returns>The object of the asynchronous operation.</returns>
        public static Async<Result<T>> InsertGoAsync<T>(this T row, bool identityInsert = false, Action<Result<T>> onCompleted = null)
            where T : DbRow
        {
            if (row == null)
            {
                throw new QueryTalkException("extensions.InsertGoAsync<T>", QueryTalkExceptionType.ArgumentNull, "row = null", Text.Method.InsertGoAsync);
            }

            return Crud.InsertGoAsync<T>(Assembly.GetCallingAssembly(), row, identityInsert, null, onCompleted);
        }

        /// <summary>
        /// Inserts the specified row in the database asynchronously.
        /// </summary>
        /// <typeparam name="T">The type of the row object.</typeparam>
        /// <param name="row">The row to insert.</param>
        /// <param name="onCompleted">A delegate method that is called when the asynchronous operation completes.</param>
        /// <returns>The object of the asynchronous operation.</returns>
        public static Async<Result<T>> InsertGoAsync<T>(this T row, Action<Result<T>> onCompleted)
            where T : DbRow
        {
            if (row == null)
            {
                throw new QueryTalkException("extensions.InsertGoAsync<T>", QueryTalkExceptionType.ArgumentNull, "row = null", Text.Method.InsertGoAsync);
            }

            return Crud.InsertGoAsync<T>(Assembly.GetCallingAssembly(), row, false, null, onCompleted);
        }

        /// <summary>
        /// Inserts the row with the associated children rows.
        /// </summary>
        /// <typeparam name="T">The type of the row object.</typeparam>
        /// <param name="row">The row to insert.</param>
        public static Result<T> InsertCascadeGo<T>(this T row)
            where T : DbRow
        {
            if (row == null)
            {
                throw new QueryTalkException("extensions.InsertCascadeGo<T>", QueryTalkExceptionType.ArgumentNull, "row = null", Text.Method.InsertCascadeGo);
            }

            return Crud.InsertCascadeGo<T>(Assembly.GetCallingAssembly(), row, null);
        }

        /// <summary>
        /// Inserts the specified rows in the database.
        /// </summary>
        /// <typeparam name="T">The type of the row object.</typeparam>
        /// <param name="rows">The rows to insert.</param>
        /// <param name="identityInsert">If true, then the explicit value can be inserted into the identity column of a table.</param>
        public static Result<T> InsertRowsGo<T>(this IEnumerable<T> rows, bool identityInsert = true)
            where T : DbRow
        {
            if (rows == null)
            {
                throw new QueryTalkException("extensions.InsertRowsGo<T>", QueryTalkExceptionType.ArgumentNull, "rows = null", Text.Method.InsertRowsGo);
            }

            return Crud.InsertRowsGo<T>(Assembly.GetCallingAssembly(), rows, identityInsert, null);
        }

        #endregion

        #region Update

        /// <summary>
        /// Updates the specified row in the database.
        /// </summary>
        /// <typeparam name="T">The type of the row object.</typeparam>
        /// <param name="row">The row to update.</param>
        /// <param name="forceMirroring">If true, then the optimistic concurrency check is done which throws an exception if the check fails.</param>
        public static Result<T> UpdateGo<T>(this T row, bool forceMirroring = true)
            where T : DbRow
        {
            if (row == null)
            {
                throw new QueryTalkException("extensions.UpdateGo<T>", QueryTalkExceptionType.ArgumentNull, "row = null", Text.Method.UpdateGo);
            }

            return Crud.UpdateGo<T>(Assembly.GetCallingAssembly(), row, forceMirroring, null);
        }

        /// <summary>
        /// Updates the specified row in the database asynchronously.
        /// </summary>
        /// <typeparam name="T">The type of the row object.</typeparam>
        /// <param name="row">The row to update.</param>
        /// <param name="forceMirroring">If true, then the optimistic concurrency check is done which throws an exception if the check fails.</param>
        /// <param name="onCompleted">A delegate method that is called when the asynchronous operation completes.</param>
        /// <returns>The object of the asynchronous operation.</returns>
        public static Async<Result<T>> UpdateGoAsync<T>(this T row, bool forceMirroring = true, Action<Result<T>> onCompleted = null)
            where T : DbRow
        {
            if (row == null)
            {
                throw new QueryTalkException("extensions.UpdateGoAsync<T>", QueryTalkExceptionType.ArgumentNull, "row = null", Text.Method.UpdateGoAsync);
            }

            return Crud.UpdateGoAsync<T>(Assembly.GetCallingAssembly(), row, forceMirroring, null, onCompleted);
        }

        /// <summary>
        /// Updates the specified row in the database asynchronously.
        /// </summary>
        /// <typeparam name="T">The type of the row object.</typeparam>
        /// <param name="row">The row to update.</param>
        /// <param name="onCompleted">A delegate method that is called when the asynchronous operation completes.</param>
        /// <returns>The object of the asynchronous operation.</returns>
        public static Async<Result<T>> UpdateGoAsync<T>(this T row, Action<Result<T>> onCompleted)
            where T : DbRow
        {
            if (row == null)
            {
                throw new QueryTalkException("extensions.UpdateGoAsync<T>", QueryTalkExceptionType.ArgumentNull, "row = null", Text.Method.UpdateGoAsync);
            }

            return Crud.UpdateGoAsync<T>(Assembly.GetCallingAssembly(), row, true, null, onCompleted);
        }

        /// <summary>
        /// Updates the specified rows in the database.
        /// </summary>
        /// <typeparam name="T">The type of the row object.</typeparam>
        /// <param name="rows">The rows to update.</param>
        /// <param name="forceMirroring">If true, then the optimistic concurrency check is done which throws an exception if the check fails.</param>
        public static Result<T> UpdateRowsGo<T>(this IEnumerable<T> rows, bool forceMirroring = true)
            where T : DbRow
        {
            if (rows == null)
            {
                throw new QueryTalkException("extensions.UpdateRowsGo<T>", QueryTalkExceptionType.ArgumentNull, "rows = null", Text.Method.UpdateRowsGo);
            }

            return Crud.UpdateRowsGo<T>(Assembly.GetCallingAssembly(), rows, forceMirroring, null);
        }

        #endregion

        #region Delete

        /// <summary>
        /// Deletes the specified row in the database.
        /// </summary>
        /// <typeparam name="T">The type of the row object.</typeparam>
        /// <param name="row">The row to delete.</param>
        /// <param name="forceMirroring">If true, then the optimistic concurrency check is done which throws an exception if the check fails.</param>
        public static Result<T> DeleteGo<T>(this T row, bool forceMirroring = true)
            where T : DbRow
        {
            if (row == null)
            {
                throw new QueryTalkException("extensions.DeleteGo<T>", QueryTalkExceptionType.ArgumentNull, "row = null", Text.Method.DeleteGo);
            }

            return Crud.DeleteGo<T>(Assembly.GetCallingAssembly(), row, forceMirroring, null);
        }

        /// <summary>
        /// Deletes the specified row in the database asynchronously.
        /// </summary>
        /// <typeparam name="T">The type of the row object.</typeparam>
        /// <param name="row">The row to delete.</param>
        /// <param name="forceMirroring">If true, then the optimistic concurrency check is done which throws an exception if the check fails.</param>
        /// <param name="onCompleted">A delegate method that is called when the asynchronous operation completes.</param>
        /// <returns>The object of the asynchronous operation.</returns>
        public static Async<Result<T>> DeleteGoAsync<T>(this T row, bool forceMirroring = true, Action<Result<T>> onCompleted = null)
            where T : DbRow
        {
            if (row == null)
            {
                throw new QueryTalkException("extensions.DeleteGoAsync<T>", QueryTalkExceptionType.ArgumentNull, "row = null", Text.Method.DeleteGoAsync);
            }

            return Crud.DeleteGoAsync<T>(Assembly.GetCallingAssembly(), row, forceMirroring, null, onCompleted);
        }

        /// <summary>
        /// Deletes the specified row in the database asynchronously.
        /// </summary>
        /// <typeparam name="T">The type of the row object.</typeparam>
        /// <param name="row">The row to delete.</param>
        /// <param name="onCompleted">A delegate method that is called when the asynchronous operation completes.</param>
        /// <returns>The object of the asynchronous operation.</returns>
        public static Async<Result<T>> DeleteGoAsync<T>(this T row, Action<Result<T>> onCompleted)
            where T : DbRow
        {
            if (row == null)
            {
                throw new QueryTalkException("extensions.DeleteGoAsync<T>", QueryTalkExceptionType.ArgumentNull, "row = null", Text.Method.DeleteGoAsync);
            }

            return Crud.DeleteGoAsync<T>(Assembly.GetCallingAssembly(), row, true, null, onCompleted);
        }

        /// <summary>
        /// Deletes the specified rows in the database.
        /// </summary>
        /// <typeparam name="T">The type of the row object.</typeparam>
        /// <param name="rows">The rows to delete.</param>
        /// <param name="forceMirroring">If true, then the optimistic concurrency check is done which throws an exception if the check fails.</param>
        public static Result<T> DeleteRowsGo<T>(this IEnumerable<T> rows, bool forceMirroring = true)
            where T : DbRow
        {
            if (rows == null)
            {
                throw new QueryTalkException("extensions.DeleteRowsGo<T>", QueryTalkExceptionType.ArgumentNull, "row = null", Text.Method.DeleteRowsGo);
            }

            return Crud.DeleteRowsGo<T>(Assembly.GetCallingAssembly(), rows, forceMirroring, null);
        }

        /// <summary>
        /// Deletes the row with the associated children rows.
        /// </summary>
        /// <typeparam name="T">The type of the row object.</typeparam>
        /// <param name="row">The row to delete.</param>
        /// <param name="maxLevels">Specifies the maximum number of cascading levels that can be included in the deletion. If more levels than maxLevels are needed to complete the cascade deletion, an exception is thrown.</param>
        public static Result<T> DeleteCascadeGo<T>(this T row, int maxLevels = 5)
            where T : DbRow
        {
            // check null
            if (row == null)
            {
                throw new QueryTalkException("extensions.DeleteCascadeGo<T>", QueryTalkExceptionType.ArgumentNull, "row = null", Text.Method.DeleteCascadeGo);
            }

            return Crud.DeleteCascadeGo<T>(Assembly.GetCallingAssembly(), row, maxLevels, null);
        }

        #endregion

        #region BulkInsert

        /// <summary>
        /// Executes a bulk insert.
        /// </summary>
        /// <param name="rows">The data to be inserted.</param>
        public static Result<T> BulkInsertGo<T>(this IEnumerable<T> rows)
            where T : DbRow
        {
            if (rows == null)
            {
                throw new QueryTalkException("extensions.BulkInsertGo<T>", QueryTalkExceptionType.ArgumentNull, "rows = null", Text.Method.BulkInsertGo);
            }

            return Importer.ExecuteBulkInsert<T>(Assembly.GetCallingAssembly(), rows, null);
        }

        /// <summary>
        /// Executes a bulk insert.
        /// </summary>
        /// <param name="data">The data to be inserted.</param>
        /// <param name="table">Is a target table where the data is inserted.</param>
        public static Result BulkInsertGo(this DataTable data, TableArgument table)
        {
            if (data == null)
            {
                throw new QueryTalkException("extensions.BulkInsertGo<T>", QueryTalkExceptionType.ArgumentNull, "rows = null", Text.Method.BulkInsertGo);
            }

            return Importer.ExecuteBulkInsert(Assembly.GetCallingAssembly(), data, table, null);
        }

        /// <summary>
        /// Executes a bulk insert.
        /// </summary>
        /// <param name="data">The data to be inserted.</param>
        /// <param name="table">Is a target table where the data is inserted.</param>
        public static Result BulkInsertGo(this Result<DataTable> data, TableArgument table)
        {
            if (data == null)
            {
                throw new QueryTalkException("extensions.BulkInsertGo<T>", QueryTalkExceptionType.ArgumentNull, "result = null", Text.Method.BulkInsertGo);
            }

            return Importer.ExecuteBulkInsert(Assembly.GetCallingAssembly(), data.ToDataTable(), table, null);
        }

        #endregion

    }
}


text:
/**
 * Package for calculator task.
 *
 * @author Andrew Ermolaev (mailto:goodwin039@gmail.com)
 * @version $Id$
 * @since 0.1
 */
package ru.job4j.calculator;


text:
[instagram-private-api](../../README.md) / [responses](../../modules/responses.md) / NewsRepositoryInboxResponseMediaItem

# Interface: NewsRepositoryInboxResponseMediaItem

[responses](../../modules/responses.md).NewsRepositoryInboxResponseMediaItem

## Table of contents

### Properties

- [comment\_threading\_enabled](NewsRepositoryInboxResponseMediaItem.md#comment_threading_enabled)
- [id](NewsRepositoryInboxResponseMediaItem.md#id)
- [image](NewsRepositoryInboxResponseMediaItem.md#image)

## Properties

### comment\_threading\_enabled

• `Optional` **comment\_threading\_enabled**: `boolean`

#### Defined in

[src/responses/news.repository.inbox.response.ts:96](https://github.com/Nerixyz/instagram-private-api/blob/b3351b9/src/responses/news.repository.inbox.response.ts#L96)

___

### id

• **id**: `string`

#### Defined in

[src/responses/news.repository.inbox.response.ts:94](https://github.com/Nerixyz/instagram-private-api/blob/b3351b9/src/responses/news.repository.inbox.response.ts#L94)

___

### image

• **image**: `string`

#### Defined in

[src/responses/news.repository.inbox.response.ts:95](https://github.com/Nerixyz/instagram-private-api/blob/b3351b9/src/responses/news.repository.inbox.response.ts#L95)


text:
def make():
    from tartist.app.rl.simulator import automake
    game = automake('custom.MazeEnv', map_size=15, visible_size=7)
    game.restart()
    return game

name = 'custom.MazeEnv'
action_names = ['NOOP', 'UP', 'RIGHT', 'DOWN', 'LEFT']
action_keys = [32, 65362, 65363, 65364, 65361]
quit_action_key = 113

# default min size is a tuple (min_dim, max_dim)
default_winsize = (600, 800)
# ignore no-action (action=0) in logging
mute_noaction = True