tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TestCharacterDataBuffer.cpp (24098B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #include "gtest/gtest.h"
      7 #include "mozilla/BasePrincipal.h"
      8 #include "mozilla/OriginAttributes.h"
      9 #include "mozilla/dom/CharacterDataBuffer.h"
     10 #include "mozilla/dom/Document.h"
     11 #include "nsCOMPtr.h"
     12 #include "nsIURI.h"
     13 #include "nsNetUtil.h"
     14 #include "nsString.h"
     15 #include "nsTextNode.h"
     16 
     17 namespace mozilla::dom {
     18 
     19 using WhitespaceOption = CharacterDataBuffer::WhitespaceOption;
     20 using WhitespaceOptions = CharacterDataBuffer::WhitespaceOptions;
     21 
     22 static already_AddRefed<Document> CreateHTMLDoc() {
     23  nsCOMPtr<nsIURI> uri;
     24  NS_NewURI(getter_AddRefs(uri), "data:text/html,");
     25 
     26  RefPtr<BasePrincipal> principal =
     27      BasePrincipal::CreateContentPrincipal(uri, OriginAttributes());
     28  MOZ_RELEASE_ASSERT(principal);
     29 
     30  nsCOMPtr<mozilla::dom::Document> doc;
     31  MOZ_ALWAYS_SUCCEEDS(NS_NewDOMDocument(getter_AddRefs(doc),
     32                                        u""_ns,   // aNamespaceURI
     33                                        u""_ns,   // aQualifiedName
     34                                        nullptr,  // aDoctype
     35                                        uri, uri, principal,
     36                                        LoadedAsData::No,  // aLoadedAsData
     37                                        nullptr,           // aEventObject
     38                                        DocumentFlavor::HTML));
     39  MOZ_RELEASE_ASSERT(doc);
     40  return doc.forget();
     41 }
     42 
     43 struct TestData {
     44  TestData(const char16_t* aData, const char16_t* aScanData,
     45           uint32_t aStartOffset, uint32_t aExpectedOffset)
     46      : mData(aData),
     47        mScanData(aScanData),
     48        mStartOffset(aStartOffset),
     49        mExpectedOffset(aExpectedOffset) {}
     50 
     51  friend std::ostream& operator<<(std::ostream& aStream,
     52                                  const TestData& aData) {
     53    return aStream << "Scan \"" << NS_ConvertUTF16toUTF8(aData.mScanData).get()
     54                   << "\" in \"" << NS_ConvertUTF16toUTF8(aData.mData).get()
     55                   << "\" starting from " << aData.mStartOffset;
     56  }
     57 
     58  const char16_t* const mData;
     59  const char16_t* const mScanData;
     60  const uint32_t mStartOffset;
     61  const uint32_t mExpectedOffset;
     62 };
     63 
     64 TEST(CharacterDataBufferTest, FindChar1b)
     65 {
     66  const RefPtr<Document> doc = CreateHTMLDoc();
     67  const RefPtr<nsTextNode> textNode = doc->CreateTextNode(EmptyString());
     68  MOZ_RELEASE_ASSERT(textNode);
     69  const CharacterDataBuffer& characterDataBuffer = textNode->DataBuffer();
     70 
     71  for (const auto& testData : {
     72           TestData(u"", u"a", 0, CharacterDataBuffer::kNotFound),
     73           TestData(u"abc", u"a", 0, 0),
     74           TestData(u"abc", u"A", 0, CharacterDataBuffer::kNotFound),
     75           TestData(u"abc", u"b", 0, 1),
     76           TestData(u"abc", u"c", 0, 2),
     77           TestData(u"abc", u"a", 1, CharacterDataBuffer::kNotFound),
     78           TestData(u"abc", u"b", 1, 1),
     79           TestData(u"abc", u"c", 2, 2),
     80           TestData(u"a\u00A0b", u"\u00A0", 0, 1),
     81       }) {
     82    textNode->SetData(nsDependentString(testData.mData), IgnoreErrors());
     83    MOZ_ASSERT(!characterDataBuffer.Is2b());
     84    const uint32_t ret = characterDataBuffer.FindChar(testData.mScanData[0],
     85                                                      testData.mStartOffset);
     86    EXPECT_EQ(ret, testData.mExpectedOffset) << testData;
     87  }
     88 }
     89 
     90 TEST(CharacterDataBufferTest, FindChar2b)
     91 {
     92  const RefPtr<Document> doc = CreateHTMLDoc();
     93  const RefPtr<nsTextNode> textNode = doc->CreateTextNode(EmptyString());
     94  MOZ_RELEASE_ASSERT(textNode);
     95  textNode->MarkAsMaybeModifiedFrequently();
     96  const CharacterDataBuffer& characterDataBuffer = textNode->DataBuffer();
     97 
     98  for (const auto& testData : {
     99           TestData(u"abc", u"a", 0, 0),
    100           TestData(u"abc", u"A", 0, CharacterDataBuffer::kNotFound),
    101           TestData(u"abc", u"b", 0, 1),
    102           TestData(u"abc", u"c", 0, 2),
    103           TestData(u"abc", u"a", 1, CharacterDataBuffer::kNotFound),
    104           TestData(u"abc", u"b", 1, 1),
    105           TestData(u"abc", u"c", 2, 2),
    106           TestData(u"a\u00A0b", u"\u00A0", 0, 1),
    107       }) {
    108    textNode->SetData(nsDependentString(testData.mData), IgnoreErrors());
    109    MOZ_ASSERT(characterDataBuffer.Is2b());
    110    const uint32_t ret = characterDataBuffer.FindChar(testData.mScanData[0],
    111                                                      testData.mStartOffset);
    112    EXPECT_EQ(ret, testData.mExpectedOffset) << testData;
    113  }
    114 }
    115 
    116 TEST(CharacterDataBufferTest, RFindChar1b)
    117 {
    118  const RefPtr<Document> doc = CreateHTMLDoc();
    119  const RefPtr<nsTextNode> textNode = doc->CreateTextNode(EmptyString());
    120  MOZ_RELEASE_ASSERT(textNode);
    121  const CharacterDataBuffer& characterDataBuffer = textNode->DataBuffer();
    122 
    123  for (const auto& testData : {
    124           TestData(u"", u"a", UINT32_MAX, CharacterDataBuffer::kNotFound),
    125           TestData(u"abc", u"a", UINT32_MAX, 0),
    126           TestData(u"abc", u"A", UINT32_MAX, CharacterDataBuffer::kNotFound),
    127           TestData(u"abc", u"b", UINT32_MAX, 1),
    128           TestData(u"abc", u"c", UINT32_MAX, 2),
    129           TestData(u"abca", u"a", UINT32_MAX, 3),
    130           TestData(u"abc", u"a", 0, 0),
    131           TestData(u"abc", u"c", 2, 2),
    132           TestData(u"a\u00A0b", u"\u00A0", UINT32_MAX, 1),
    133       }) {
    134    textNode->SetData(nsDependentString(testData.mData), IgnoreErrors());
    135    MOZ_ASSERT(!characterDataBuffer.Is2b());
    136    const uint32_t ret = characterDataBuffer.RFindChar(testData.mScanData[0],
    137                                                       testData.mStartOffset);
    138    EXPECT_EQ(ret, testData.mExpectedOffset) << testData;
    139  }
    140 }
    141 
    142 TEST(CharacterDataBufferTest, RFindChar2b)
    143 {
    144  const RefPtr<Document> doc = CreateHTMLDoc();
    145  const RefPtr<nsTextNode> textNode = doc->CreateTextNode(EmptyString());
    146  MOZ_RELEASE_ASSERT(textNode);
    147  textNode->MarkAsMaybeModifiedFrequently();
    148  const CharacterDataBuffer& characterDataBuffer = textNode->DataBuffer();
    149 
    150  for (const auto& testData : {
    151           TestData(u"abc", u"a", UINT32_MAX, 0),
    152           TestData(u"abc", u"A", UINT32_MAX, CharacterDataBuffer::kNotFound),
    153           TestData(u"abc", u"b", UINT32_MAX, 1),
    154           TestData(u"abc", u"c", UINT32_MAX, 2),
    155           TestData(u"abca", u"a", UINT32_MAX, 3),
    156           TestData(u"abc", u"a", 0, 0),
    157           TestData(u"abc", u"c", 2, 2),
    158           TestData(u"a\u00A0b", u"\u00A0", UINT32_MAX, 1),
    159       }) {
    160    textNode->SetData(nsDependentString(testData.mData), IgnoreErrors());
    161    MOZ_ASSERT(characterDataBuffer.Is2b());
    162    const uint32_t ret = characterDataBuffer.RFindChar(testData.mScanData[0],
    163                                                       testData.mStartOffset);
    164    EXPECT_EQ(ret, testData.mExpectedOffset) << testData;
    165  }
    166 }
    167 
    168 TEST(CharacterDataBufferTest, FindFirstDifferentCharOffsetIn1b)
    169 {
    170  const RefPtr<Document> doc = CreateHTMLDoc();
    171  const RefPtr<nsTextNode> textNode = doc->CreateTextNode(EmptyString());
    172  MOZ_RELEASE_ASSERT(textNode);
    173  const CharacterDataBuffer& characterDataBuffer = textNode->DataBuffer();
    174 
    175  for (const auto& testData : {
    176           TestData(u"abcdef", u"abc", 0, CharacterDataBuffer::kNotFound),
    177           TestData(u"abcdef", u"Abc", 0, 0),
    178           TestData(u"abcdef", u"aBc", 0, 1),
    179           TestData(u"abcdef", u"abC", 0, 2),
    180           TestData(u"abcdef", u"def", 3, CharacterDataBuffer::kNotFound),
    181           TestData(u"abcdef", u"Def", 3, 3),
    182           TestData(u"abcdef", u"dEf", 3, 4),
    183           TestData(u"abcdef", u"deF", 3, 5),
    184       }) {
    185    textNode->SetData(nsDependentString(testData.mData), IgnoreErrors());
    186    MOZ_ASSERT(!characterDataBuffer.Is2b());
    187    const uint32_t ret = characterDataBuffer.FindFirstDifferentCharOffset(
    188        NS_ConvertUTF16toUTF8(testData.mScanData), testData.mStartOffset);
    189    EXPECT_EQ(ret, testData.mExpectedOffset) << testData;
    190  }
    191 }
    192 
    193 TEST(CharacterDataBufferTest, FindFirstDifferentCharOffsetIn2b)
    194 {
    195  const RefPtr<Document> doc = CreateHTMLDoc();
    196  const RefPtr<nsTextNode> textNode = doc->CreateTextNode(EmptyString());
    197  MOZ_RELEASE_ASSERT(textNode);
    198  textNode->MarkAsMaybeModifiedFrequently();
    199  const CharacterDataBuffer& characterDataBuffer = textNode->DataBuffer();
    200 
    201  for (const auto& testData : {
    202           TestData(u"abcdef", u"abc", 0, CharacterDataBuffer::kNotFound),
    203           TestData(u"abcdef", u"Abc", 0, 0),
    204           TestData(u"abcdef", u"aBc", 0, 1),
    205           TestData(u"abcdef", u"abC", 0, 2),
    206           TestData(u"abcdef", u"def", 3, CharacterDataBuffer::kNotFound),
    207           TestData(u"abcdef", u"Def", 3, 3),
    208           TestData(u"abcdef", u"dEf", 3, 4),
    209           TestData(u"abcdef", u"deF", 3, 5),
    210       }) {
    211    textNode->SetData(nsDependentString(testData.mData), IgnoreErrors());
    212    MOZ_ASSERT(characterDataBuffer.Is2b());
    213    const uint32_t ret = characterDataBuffer.FindFirstDifferentCharOffset(
    214        NS_ConvertUTF16toUTF8(testData.mScanData), testData.mStartOffset);
    215    EXPECT_EQ(ret, testData.mExpectedOffset) << testData;
    216  }
    217 }
    218 
    219 TEST(CharacterDataBufferTest, RFindFirstDifferentCharOffsetIn1b)
    220 {
    221  const RefPtr<Document> doc = CreateHTMLDoc();
    222  const RefPtr<nsTextNode> textNode = doc->CreateTextNode(EmptyString());
    223  MOZ_RELEASE_ASSERT(textNode);
    224  const CharacterDataBuffer& characterDataBuffer = textNode->DataBuffer();
    225 
    226  for (const auto& testData : {
    227           TestData(u"abcdef", u"abc", 3, CharacterDataBuffer::kNotFound),
    228           TestData(u"abcdef", u"Abc", 3, 0),
    229           TestData(u"abcdef", u"aBc", 3, 1),
    230           TestData(u"abcdef", u"abC", 3, 2),
    231           TestData(u"abcdef", u"def", 6, CharacterDataBuffer::kNotFound),
    232           TestData(u"abcdef", u"Def", 6, 3),
    233           TestData(u"abcdef", u"dEf", 6, 4),
    234           TestData(u"abcdef", u"deF", 6, 5),
    235       }) {
    236    textNode->SetData(nsDependentString(testData.mData), IgnoreErrors());
    237    MOZ_ASSERT(!characterDataBuffer.Is2b());
    238    const uint32_t ret = characterDataBuffer.RFindFirstDifferentCharOffset(
    239        NS_ConvertUTF16toUTF8(testData.mScanData), testData.mStartOffset);
    240    EXPECT_EQ(ret, testData.mExpectedOffset) << testData;
    241  }
    242 }
    243 
    244 TEST(CharacterDataBufferTest, RFindFirstDifferentCharOffsetIn2b)
    245 {
    246  const RefPtr<Document> doc = CreateHTMLDoc();
    247  const RefPtr<nsTextNode> textNode = doc->CreateTextNode(EmptyString());
    248  MOZ_RELEASE_ASSERT(textNode);
    249  textNode->MarkAsMaybeModifiedFrequently();
    250  const CharacterDataBuffer& characterDataBuffer = textNode->DataBuffer();
    251 
    252  for (const auto& testData : {
    253           TestData(u"abcdef", u"abc", 3, CharacterDataBuffer::kNotFound),
    254           TestData(u"abcdef", u"Abc", 3, 0),
    255           TestData(u"abcdef", u"aBc", 3, 1),
    256           TestData(u"abcdef", u"abC", 3, 2),
    257           TestData(u"abcdef", u"def", 6, CharacterDataBuffer::kNotFound),
    258           TestData(u"abcdef", u"Def", 6, 3),
    259           TestData(u"abcdef", u"dEf", 6, 4),
    260           TestData(u"abcdef", u"deF", 6, 5),
    261       }) {
    262    textNode->SetData(nsDependentString(testData.mData), IgnoreErrors());
    263    MOZ_ASSERT(characterDataBuffer.Is2b());
    264    const uint32_t ret = characterDataBuffer.RFindFirstDifferentCharOffset(
    265        NS_ConvertUTF16toUTF8(testData.mScanData), testData.mStartOffset);
    266    EXPECT_EQ(ret, testData.mExpectedOffset) << testData;
    267  }
    268 }
    269 
    270 struct TestDataForFindNonWhitespace {
    271  TestDataForFindNonWhitespace(const char16_t* aData, uint32_t aOffset,
    272                               const WhitespaceOptions& aOptions,
    273                               uint32_t aExpectedOffset)
    274      : mData(aData),
    275        mOffset(aOffset),
    276        mExpectedOffset(aExpectedOffset),
    277        mOptions(aOptions) {}
    278 
    279  friend std::ostream& operator<<(std::ostream& aStream,
    280                                  const TestDataForFindNonWhitespace& aData) {
    281    aStream << "Scan with options={";
    282    bool isFirstOption = true;
    283    if (aData.mOptions.contains(WhitespaceOption::FormFeedIsSignificant)) {
    284      aStream << "WhitespaceOption::FormFeedIsSignificant";
    285      isFirstOption = false;
    286    }
    287    if (aData.mOptions.contains(WhitespaceOption::NewLineIsSignificant)) {
    288      if (!isFirstOption) {
    289        aStream << ", ";
    290      }
    291      aStream << "WhitespaceOption::NewLineIsSignificant";
    292      isFirstOption = false;
    293    }
    294    if (aData.mOptions.contains(WhitespaceOption::TreatNBSPAsCollapsible)) {
    295      if (!isFirstOption) {
    296        aStream << ", ";
    297      }
    298      aStream << "WhitespaceOption::TreatNBSPAsCollapsible";
    299      isFirstOption = false;
    300    }
    301    return aStream << "} in \"" << aData.FormatUTF8Data().get()
    302                   << "\" starting from " << aData.mOffset;
    303  }
    304 
    305  nsAutoCString FormatUTF8Data() const {
    306    nsAutoString data(mData);
    307    data.ReplaceSubstring(u"\n"_ns, u"\\n"_ns);
    308    data.ReplaceSubstring(u"\t"_ns, u"\\t"_ns);
    309    data.ReplaceSubstring(u"\r"_ns, u"\\r"_ns);
    310    data.ReplaceSubstring(u"\f"_ns, u"\\f"_ns);
    311    data.ReplaceSubstring(u"\u00A0"_ns, u"&nbsp;"_ns);
    312    return NS_ConvertUTF16toUTF8(data);
    313  }
    314 
    315  const char16_t* const mData;
    316  const uint32_t mOffset;
    317  const uint32_t mExpectedOffset;
    318  const WhitespaceOptions mOptions;
    319 };
    320 
    321 TEST(CharacterDataBufferTest, FindNonWhitespaceIn1b)
    322 {
    323  const RefPtr<Document> doc = CreateHTMLDoc();
    324  const RefPtr<nsTextNode> textNode = doc->CreateTextNode(EmptyString());
    325  MOZ_RELEASE_ASSERT(textNode);
    326  const CharacterDataBuffer& characterDataBuffer = textNode->DataBuffer();
    327 
    328  for (const auto& testData : {
    329           TestDataForFindNonWhitespace(u"", 0, {},
    330                                        CharacterDataBuffer::kNotFound),
    331           TestDataForFindNonWhitespace(u" ", 0, {},
    332                                        CharacterDataBuffer::kNotFound),
    333           TestDataForFindNonWhitespace(u"  ", 0, {},
    334                                        CharacterDataBuffer::kNotFound),
    335           TestDataForFindNonWhitespace(u"\t\n\r\f", 0, {},
    336                                        CharacterDataBuffer::kNotFound),
    337           TestDataForFindNonWhitespace(u" \t\n\r\f", 0, {},
    338                                        CharacterDataBuffer::kNotFound),
    339           TestDataForFindNonWhitespace(u"a", 0, {}, 0),
    340           TestDataForFindNonWhitespace(u" a", 0, {}, 1),
    341           TestDataForFindNonWhitespace(u"\u00A0", 0, {}, 0),
    342           TestDataForFindNonWhitespace(u" \u00A0", 0, {}, 1),
    343           TestDataForFindNonWhitespace(u"a b", 1, {}, 2),
    344           TestDataForFindNonWhitespace(u"a b", 2, {}, 2),
    345           TestDataForFindNonWhitespace(
    346               u"\fa", 0, {WhitespaceOption::FormFeedIsSignificant}, 0),
    347           TestDataForFindNonWhitespace(
    348               u" \fa", 0, {WhitespaceOption::FormFeedIsSignificant}, 1),
    349           TestDataForFindNonWhitespace(
    350               u"\n", 0, {WhitespaceOption::NewLineIsSignificant}, 0),
    351           TestDataForFindNonWhitespace(
    352               u" \n", 0, {WhitespaceOption::NewLineIsSignificant}, 1),
    353           TestDataForFindNonWhitespace(
    354               u"\u00A0", 0, {WhitespaceOption::TreatNBSPAsCollapsible},
    355               CharacterDataBuffer::kNotFound),
    356           TestDataForFindNonWhitespace(
    357               u" \u00A0", 0, {WhitespaceOption::TreatNBSPAsCollapsible},
    358               CharacterDataBuffer::kNotFound),
    359       }) {
    360    textNode->SetData(nsDependentString(testData.mData), IgnoreErrors());
    361    MOZ_ASSERT(!characterDataBuffer.Is2b());
    362    const uint32_t ret = characterDataBuffer.FindNonWhitespaceChar(
    363        testData.mOptions, testData.mOffset);
    364    EXPECT_EQ(ret, testData.mExpectedOffset) << testData;
    365  }
    366 }
    367 
    368 TEST(CharacterDataBufferTest, FindNonWhitespaceIn2b)
    369 {
    370  const RefPtr<Document> doc = CreateHTMLDoc();
    371  const RefPtr<nsTextNode> textNode = doc->CreateTextNode(EmptyString());
    372  MOZ_RELEASE_ASSERT(textNode);
    373  textNode->MarkAsMaybeModifiedFrequently();
    374  const CharacterDataBuffer& characterDataBuffer = textNode->DataBuffer();
    375 
    376  for (const auto& testData : {
    377           TestDataForFindNonWhitespace(u" ", 0, {},
    378                                        CharacterDataBuffer::kNotFound),
    379           TestDataForFindNonWhitespace(u"  ", 0, {},
    380                                        CharacterDataBuffer::kNotFound),
    381           TestDataForFindNonWhitespace(u"\t\n\r\f", 0, {},
    382                                        CharacterDataBuffer::kNotFound),
    383           TestDataForFindNonWhitespace(u" \t\n\r\f", 0, {},
    384                                        CharacterDataBuffer::kNotFound),
    385           TestDataForFindNonWhitespace(u"a", 0, {}, 0),
    386           TestDataForFindNonWhitespace(u" a", 0, {}, 1),
    387           TestDataForFindNonWhitespace(u"\u00A0", 0, {}, 0),
    388           TestDataForFindNonWhitespace(u" \u00A0", 0, {}, 1),
    389           TestDataForFindNonWhitespace(u"a b", 1, {}, 2),
    390           TestDataForFindNonWhitespace(u"a b", 2, {}, 2),
    391           TestDataForFindNonWhitespace(
    392               u"\fa", 0, {WhitespaceOption::FormFeedIsSignificant}, 0),
    393           TestDataForFindNonWhitespace(
    394               u" \fa", 0, {WhitespaceOption::FormFeedIsSignificant}, 1),
    395           TestDataForFindNonWhitespace(
    396               u"\n", 0, {WhitespaceOption::NewLineIsSignificant}, 0),
    397           TestDataForFindNonWhitespace(
    398               u" \n", 0, {WhitespaceOption::NewLineIsSignificant}, 1),
    399           TestDataForFindNonWhitespace(
    400               u"\u00A0", 0, {WhitespaceOption::TreatNBSPAsCollapsible},
    401               CharacterDataBuffer::kNotFound),
    402           TestDataForFindNonWhitespace(
    403               u" \u00A0", 0, {WhitespaceOption::TreatNBSPAsCollapsible},
    404               CharacterDataBuffer::kNotFound),
    405       }) {
    406    textNode->SetData(nsDependentString(testData.mData), IgnoreErrors());
    407    MOZ_ASSERT(characterDataBuffer.Is2b());
    408    const uint32_t ret = characterDataBuffer.FindNonWhitespaceChar(
    409        testData.mOptions, testData.mOffset);
    410    EXPECT_EQ(ret, testData.mExpectedOffset) << testData;
    411  }
    412 }
    413 
    414 TEST(CharacterDataBufferTest, RFindNonWhitespaceIn1b)
    415 {
    416  const RefPtr<Document> doc = CreateHTMLDoc();
    417  const RefPtr<nsTextNode> textNode = doc->CreateTextNode(EmptyString());
    418  MOZ_RELEASE_ASSERT(textNode);
    419  const CharacterDataBuffer& characterDataBuffer = textNode->DataBuffer();
    420 
    421  for (const auto& testData : {
    422           TestDataForFindNonWhitespace(u"", UINT32_MAX, {},
    423                                        CharacterDataBuffer::kNotFound),
    424           TestDataForFindNonWhitespace(u" ", UINT32_MAX, {},
    425                                        CharacterDataBuffer::kNotFound),
    426           TestDataForFindNonWhitespace(u"  ", UINT32_MAX, {},
    427                                        CharacterDataBuffer::kNotFound),
    428           TestDataForFindNonWhitespace(u"\t\n\r\f", UINT32_MAX, {},
    429                                        CharacterDataBuffer::kNotFound),
    430           TestDataForFindNonWhitespace(u"\t\n\r\f ", UINT32_MAX, {},
    431                                        CharacterDataBuffer::kNotFound),
    432           TestDataForFindNonWhitespace(u"a", UINT32_MAX, {}, 0),
    433           TestDataForFindNonWhitespace(u"a ", UINT32_MAX, {}, 0),
    434           TestDataForFindNonWhitespace(u"ab", UINT32_MAX, {}, 1),
    435           TestDataForFindNonWhitespace(u"ab ", UINT32_MAX, {}, 1),
    436           TestDataForFindNonWhitespace(u"a\u00A0", UINT32_MAX, {}, 1),
    437           TestDataForFindNonWhitespace(u"a\u00A0 ", UINT32_MAX, {}, 1),
    438           TestDataForFindNonWhitespace(u"a b", 1, {}, 0),
    439           TestDataForFindNonWhitespace(u"a b", 0, {}, 0),
    440           TestDataForFindNonWhitespace(
    441               u"a\f", UINT32_MAX, {WhitespaceOption::FormFeedIsSignificant},
    442               1),
    443           TestDataForFindNonWhitespace(
    444               u"a\f ", UINT32_MAX, {WhitespaceOption::FormFeedIsSignificant},
    445               1),
    446           TestDataForFindNonWhitespace(
    447               u"a\n", UINT32_MAX, {WhitespaceOption::NewLineIsSignificant}, 1),
    448           TestDataForFindNonWhitespace(
    449               u"a\n ", UINT32_MAX, {WhitespaceOption::NewLineIsSignificant},
    450               1),
    451           TestDataForFindNonWhitespace(
    452               u"a\u00A0", UINT32_MAX,
    453               {WhitespaceOption::TreatNBSPAsCollapsible}, 0),
    454           TestDataForFindNonWhitespace(
    455               u"a\u00A0 ", UINT32_MAX,
    456               {WhitespaceOption::TreatNBSPAsCollapsible}, 0),
    457       }) {
    458    textNode->SetData(nsDependentString(testData.mData), IgnoreErrors());
    459    MOZ_ASSERT(!characterDataBuffer.Is2b());
    460    const uint32_t ret = characterDataBuffer.RFindNonWhitespaceChar(
    461        testData.mOptions, testData.mOffset);
    462    EXPECT_EQ(ret, testData.mExpectedOffset) << testData;
    463  }
    464 }
    465 
    466 TEST(CharacterDataBufferTest, RFindNonWhitespaceIn2b)
    467 {
    468  const RefPtr<Document> doc = CreateHTMLDoc();
    469  const RefPtr<nsTextNode> textNode = doc->CreateTextNode(EmptyString());
    470  MOZ_RELEASE_ASSERT(textNode);
    471  textNode->MarkAsMaybeModifiedFrequently();
    472  const CharacterDataBuffer& characterDataBuffer = textNode->DataBuffer();
    473 
    474  for (const auto& testData : {
    475           TestDataForFindNonWhitespace(u" ", UINT32_MAX, {},
    476                                        CharacterDataBuffer::kNotFound),
    477           TestDataForFindNonWhitespace(u"  ", UINT32_MAX, {},
    478                                        CharacterDataBuffer::kNotFound),
    479           TestDataForFindNonWhitespace(u"\t\n\r\f", UINT32_MAX, {},
    480                                        CharacterDataBuffer::kNotFound),
    481           TestDataForFindNonWhitespace(u"\t\n\r\f ", UINT32_MAX, {},
    482                                        CharacterDataBuffer::kNotFound),
    483           TestDataForFindNonWhitespace(u"a", UINT32_MAX, {}, 0),
    484           TestDataForFindNonWhitespace(u"a ", UINT32_MAX, {}, 0),
    485           TestDataForFindNonWhitespace(u"ab", UINT32_MAX, {}, 1),
    486           TestDataForFindNonWhitespace(u"ab ", UINT32_MAX, {}, 1),
    487           TestDataForFindNonWhitespace(u"a\u00A0", UINT32_MAX, {}, 1),
    488           TestDataForFindNonWhitespace(u"a\u00A0 ", UINT32_MAX, {}, 1),
    489           TestDataForFindNonWhitespace(u"a b", 1, {}, 0),
    490           TestDataForFindNonWhitespace(u"a b", 0, {}, 0),
    491           TestDataForFindNonWhitespace(
    492               u"a\f", UINT32_MAX, {WhitespaceOption::FormFeedIsSignificant},
    493               1),
    494           TestDataForFindNonWhitespace(
    495               u"a\f ", UINT32_MAX, {WhitespaceOption::FormFeedIsSignificant},
    496               1),
    497           TestDataForFindNonWhitespace(
    498               u"a\n", UINT32_MAX, {WhitespaceOption::NewLineIsSignificant}, 1),
    499           TestDataForFindNonWhitespace(
    500               u"a\n ", UINT32_MAX, {WhitespaceOption::NewLineIsSignificant},
    501               1),
    502           TestDataForFindNonWhitespace(
    503               u"a\u00A0", UINT32_MAX,
    504               {WhitespaceOption::TreatNBSPAsCollapsible}, 0),
    505           TestDataForFindNonWhitespace(
    506               u"a\u00A0 ", UINT32_MAX,
    507               {WhitespaceOption::TreatNBSPAsCollapsible}, 0),
    508       }) {
    509    textNode->SetData(nsDependentString(testData.mData), IgnoreErrors());
    510    MOZ_ASSERT(characterDataBuffer.Is2b());
    511    const uint32_t ret = characterDataBuffer.RFindNonWhitespaceChar(
    512        testData.mOptions, testData.mOffset);
    513    EXPECT_EQ(ret, testData.mExpectedOffset) << testData;
    514  }
    515 }
    516 
    517 TEST(CharacterDataBufferTest, SafeAPIsChar1b)
    518 {
    519  const RefPtr<Document> doc = CreateHTMLDoc();
    520  const RefPtr<nsTextNode> textNode = doc->CreateTextNode(EmptyString());
    521  MOZ_RELEASE_ASSERT(textNode);
    522  const CharacterDataBuffer& characterDataBuffer = textNode->DataBuffer();
    523 
    524  // Test empty data buffer.
    525  EXPECT_EQ(characterDataBuffer.SafeFirstChar(), u'\0');
    526  EXPECT_EQ(characterDataBuffer.SafeLastChar(), u'\0');
    527  EXPECT_EQ(characterDataBuffer.SafeCharAt(100), u'\0');
    528 
    529  // Test non-empty data buffer.
    530  const char16_t* testStr = u"abcdef";
    531  textNode->SetData(nsDependentString(testStr), IgnoreErrors());
    532  MOZ_ASSERT(!characterDataBuffer.Is2b());
    533 
    534  EXPECT_EQ(characterDataBuffer.SafeFirstChar(), u'a');
    535  EXPECT_EQ(characterDataBuffer.SafeLastChar(), u'f');
    536  EXPECT_EQ(characterDataBuffer.SafeCharAt(2), u'c');
    537  EXPECT_EQ(characterDataBuffer.SafeCharAt(100), u'\0');
    538 }
    539 
    540 };  // namespace mozilla::dom