| Index: third_party/re2/re2/testing/charclass_test.cc
|
| diff --git a/third_party/re2/re2/testing/charclass_test.cc b/third_party/re2/re2/testing/charclass_test.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a3764d4be3a5dd039a4f487473e941e9ae3a8fdf
|
| --- /dev/null
|
| +++ b/third_party/re2/re2/testing/charclass_test.cc
|
| @@ -0,0 +1,223 @@
|
| +// Copyright 2006 The RE2 Authors. All Rights Reserved.
|
| +// Use of this source code is governed by a BSD-style
|
| +// license that can be found in the LICENSE file.
|
| +
|
| +// Test character class manipulations.
|
| +
|
| +#include "util/test.h"
|
| +#include "re2/regexp.h"
|
| +
|
| +namespace re2 {
|
| +
|
| +struct CCTest {
|
| + struct {
|
| + Rune lo;
|
| + Rune hi;
|
| + } add[10];
|
| + int remove;
|
| + struct {
|
| + Rune lo;
|
| + Rune hi;
|
| + } final[10];
|
| +};
|
| +
|
| +static CCTest tests[] = {
|
| + { { { 10, 20 }, {-1} }, -1,
|
| + { { 10, 20 }, {-1} } },
|
| +
|
| + { { { 10, 20 }, { 20, 30 }, {-1} }, -1,
|
| + { { 10, 30 }, {-1} } },
|
| +
|
| + { { { 10, 20 }, { 30, 40 }, { 20, 30 }, {-1} }, -1,
|
| + { { 10, 40 }, {-1} } },
|
| +
|
| + { { { 0, 50 }, { 20, 30 }, {-1} }, -1,
|
| + { { 0, 50 }, {-1} } },
|
| +
|
| + { { { 10, 11 }, { 13, 14 }, { 16, 17 }, { 19, 20 }, { 22, 23 }, {-1} }, -1,
|
| + { { 10, 11 }, { 13, 14 }, { 16, 17 }, { 19, 20 }, { 22, 23 }, {-1} } },
|
| +
|
| + { { { 13, 14 }, { 10, 11 }, { 22, 23 }, { 19, 20 }, { 16, 17 }, {-1} }, -1,
|
| + { { 10, 11 }, { 13, 14 }, { 16, 17 }, { 19, 20 }, { 22, 23 }, {-1} } },
|
| +
|
| + { { { 13, 14 }, { 10, 11 }, { 22, 23 }, { 19, 20 }, { 16, 17 }, {-1} }, -1,
|
| + { { 10, 11 }, { 13, 14 }, { 16, 17 }, { 19, 20 }, { 22, 23 }, {-1} } },
|
| +
|
| + { { { 13, 14 }, { 10, 11 }, { 22, 23 }, { 19, 20 }, { 16, 17 }, { 5, 25 }, {-1} }, -1,
|
| + { { 5, 25 }, {-1} } },
|
| +
|
| + { { { 13, 14 }, { 10, 11 }, { 22, 23 }, { 19, 20 }, { 16, 17 }, { 12, 21 }, {-1} }, -1,
|
| + { { 10, 23 }, {-1} } },
|
| +
|
| + // These check boundary cases during negation.
|
| + { { { 0, Runemax }, {-1} }, -1,
|
| + { { 0, Runemax }, {-1} } },
|
| +
|
| + { { { 0, 50 }, {-1} }, -1,
|
| + { { 0, 50 }, {-1} } },
|
| +
|
| + { { { 50, Runemax }, {-1} }, -1,
|
| + { { 50, Runemax }, {-1} } },
|
| +
|
| + // Check RemoveAbove.
|
| + { { { 50, Runemax }, {-1} }, 255,
|
| + { { 50, 255 }, {-1} } },
|
| +
|
| + { { { 50, Runemax }, {-1} }, 65535,
|
| + { { 50, 65535 }, {-1} } },
|
| +
|
| + { { { 50, Runemax }, {-1} }, Runemax,
|
| + { { 50, Runemax }, {-1} } },
|
| +
|
| + { { { 50, 60 }, { 250, 260 }, { 350, 360 }, {-1} }, 255,
|
| + { { 50, 60 }, { 250, 255 }, {-1} } },
|
| +
|
| + { { { 50, 60 }, {-1} }, 255,
|
| + { { 50, 60 }, {-1} } },
|
| +
|
| + { { { 350, 360 }, {-1} }, 255,
|
| + { {-1} } },
|
| +
|
| + { { {-1} }, 255,
|
| + { {-1} } },
|
| +};
|
| +
|
| +template<class CharClass>
|
| +static void Broke(const char *desc, const CCTest* t, CharClass* cc) {
|
| + if (t == NULL) {
|
| + printf("\t%s:", desc);
|
| + } else {
|
| + printf("\n");
|
| + printf("CharClass added: [%s]", desc);
|
| + for (int k = 0; t->add[k].lo >= 0; k++)
|
| + printf(" %d-%d", t->add[k].lo, t->add[k].hi);
|
| + printf("\n");
|
| + if (t->remove >= 0)
|
| + printf("Removed > %d\n", t->remove);
|
| + printf("\twant:");
|
| + for (int k = 0; t->final[k].lo >= 0; k++)
|
| + printf(" %d-%d", t->final[k].lo, t->final[k].hi);
|
| + printf("\n");
|
| + printf("\thave:");
|
| + }
|
| +
|
| + for (typename CharClass::iterator it = cc->begin(); it != cc->end(); ++it)
|
| + printf(" %d-%d", it->lo, it->hi);
|
| + printf("\n");
|
| +}
|
| +
|
| +bool ShouldContain(CCTest *t, int x) {
|
| + for (int j = 0; t->final[j].lo >= 0; j++)
|
| + if (t->final[j].lo <= x && x <= t->final[j].hi)
|
| + return true;
|
| + return false;
|
| +}
|
| +
|
| +// Helpers to make templated CorrectCC work with both CharClass and CharClassBuilder.
|
| +
|
| +CharClass* Negate(CharClass *cc) {
|
| + return cc->Negate();
|
| +}
|
| +
|
| +void Delete(CharClass* cc) {
|
| + cc->Delete();
|
| +}
|
| +
|
| +CharClassBuilder* Negate(CharClassBuilder* cc) {
|
| + CharClassBuilder* ncc = cc->Copy();
|
| + ncc->Negate();
|
| + return ncc;
|
| +}
|
| +
|
| +void Delete(CharClassBuilder* cc) {
|
| + delete cc;
|
| +}
|
| +
|
| +template<class CharClass>
|
| +bool CorrectCC(CharClass *cc, CCTest *t, const char *desc) {
|
| + typename CharClass::iterator it = cc->begin();
|
| + int size = 0;
|
| + for (int j = 0; t->final[j].lo >= 0; j++, ++it) {
|
| + if (it == cc->end() ||
|
| + it->lo != t->final[j].lo ||
|
| + it->hi != t->final[j].hi) {
|
| + Broke(desc, t, cc);
|
| + return false;
|
| + }
|
| + size += it->hi - it->lo + 1;
|
| + }
|
| + if (it != cc->end()) {
|
| + Broke(desc, t, cc);
|
| + return false;
|
| + }
|
| + if (cc->size() != size) {
|
| + Broke(desc, t, cc);
|
| + printf("wrong size: want %d have %d\n", size, cc->size());
|
| + return false;
|
| + }
|
| +
|
| + for (int j = 0; j < 101; j++) {
|
| + if (j == 100)
|
| + j = Runemax;
|
| + if (ShouldContain(t, j) != cc->Contains(j)) {
|
| + Broke(desc, t, cc);
|
| + printf("want contains(%d)=%d, got %d\n",
|
| + j, ShouldContain(t, j), cc->Contains(j));
|
| + return false;
|
| + }
|
| + }
|
| +
|
| + CharClass* ncc = Negate(cc);
|
| + for (int j = 0; j < 101; j++) {
|
| + if (j == 100)
|
| + j = Runemax;
|
| + if (ShouldContain(t, j) == ncc->Contains(j)) {
|
| + Broke(desc, t, cc);
|
| + Broke("ncc", NULL, ncc);
|
| + printf("want ncc contains(%d)!=%d, got %d\n",
|
| + j, ShouldContain(t, j), ncc->Contains(j));
|
| + Delete(ncc);
|
| + return false;
|
| + }
|
| + if (ncc->size() != Runemax+1 - cc->size()) {
|
| + Broke(desc, t, cc);
|
| + Broke("ncc", NULL, ncc);
|
| + printf("ncc size should be %d is %d\n",
|
| + Runemax+1 - cc->size(), ncc->size());
|
| + Delete(ncc);
|
| + return false;
|
| + }
|
| + }
|
| + Delete(ncc);
|
| + return true;
|
| +}
|
| +
|
| +TEST(TestCharClassBuilder, Adds) {
|
| + int nfail = 0;
|
| + for (int i = 0; i < arraysize(tests); i++) {
|
| + CharClassBuilder ccb;
|
| + CCTest* t = &tests[i];
|
| + for (int j = 0; t->add[j].lo >= 0; j++)
|
| + ccb.AddRange(t->add[j].lo, t->add[j].hi);
|
| + if (t->remove >= 0)
|
| + ccb.RemoveAbove(t->remove);
|
| + if (!CorrectCC(&ccb, t, "before copy (CharClassBuilder)"))
|
| + nfail++;
|
| + CharClass* cc = ccb.GetCharClass();
|
| + if (!CorrectCC(cc, t, "before copy (CharClass)"))
|
| + nfail++;
|
| + cc->Delete();
|
| +
|
| + CharClassBuilder *ccb1 = ccb.Copy();
|
| + if (!CorrectCC(ccb1, t, "after copy (CharClassBuilder)"))
|
| + nfail++;
|
| + cc = ccb.GetCharClass();
|
| + if (!CorrectCC(cc, t, "after copy (CharClass)"))
|
| + nfail++;
|
| + cc->Delete();
|
| + delete ccb1;
|
| + }
|
| + EXPECT_EQ(nfail, 0);
|
| +}
|
| +
|
| +} // namespace re2
|
|
|