1 // Copyright 2010 The RE2 Authors. All Rights Reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 #include "re2/set.h"
6
7 #include <stddef.h>
8
9 #include <utility>
10 #include <vector>
11
12 #include "gtest/gtest.h"
13 #include "re2/re2.h"
14
15 namespace re2 {
16
TEST(Set,Unanchored)17 TEST(Set, Unanchored) {
18 RE2::Set s(RE2::DefaultOptions, RE2::UNANCHORED);
19
20 ASSERT_EQ(s.Add("foo", NULL), 0);
21 ASSERT_EQ(s.Add("(", NULL), -1);
22 ASSERT_EQ(s.Add("bar", NULL), 1);
23 ASSERT_EQ(s.Compile(), true);
24
25 ASSERT_EQ(s.Match("foobar", NULL), true);
26 ASSERT_EQ(s.Match("fooba", NULL), true);
27 ASSERT_EQ(s.Match("oobar", NULL), true);
28
29 std::vector<int> v;
30 ASSERT_EQ(s.Match("foobar", &v), true);
31 ASSERT_EQ(v.size(), size_t{2});
32 ASSERT_EQ(v[0], 0);
33 ASSERT_EQ(v[1], 1);
34
35 ASSERT_EQ(s.Match("fooba", &v), true);
36 ASSERT_EQ(v.size(), size_t{1});
37 ASSERT_EQ(v[0], 0);
38
39 ASSERT_EQ(s.Match("oobar", &v), true);
40 ASSERT_EQ(v.size(), size_t{1});
41 ASSERT_EQ(v[0], 1);
42 }
43
TEST(Set,UnanchoredFactored)44 TEST(Set, UnanchoredFactored) {
45 RE2::Set s(RE2::DefaultOptions, RE2::UNANCHORED);
46
47 ASSERT_EQ(s.Add("foo", NULL), 0);
48 ASSERT_EQ(s.Add("(", NULL), -1);
49 ASSERT_EQ(s.Add("foobar", NULL), 1);
50 ASSERT_EQ(s.Compile(), true);
51
52 ASSERT_EQ(s.Match("foobar", NULL), true);
53 ASSERT_EQ(s.Match("obarfoobaroo", NULL), true);
54 ASSERT_EQ(s.Match("fooba", NULL), true);
55 ASSERT_EQ(s.Match("oobar", NULL), false);
56
57 std::vector<int> v;
58 ASSERT_EQ(s.Match("foobar", &v), true);
59 ASSERT_EQ(v.size(), size_t{2});
60 ASSERT_EQ(v[0], 0);
61 ASSERT_EQ(v[1], 1);
62
63 ASSERT_EQ(s.Match("obarfoobaroo", &v), true);
64 ASSERT_EQ(v.size(), size_t{2});
65 ASSERT_EQ(v[0], 0);
66 ASSERT_EQ(v[1], 1);
67
68 ASSERT_EQ(s.Match("fooba", &v), true);
69 ASSERT_EQ(v.size(), size_t{1});
70 ASSERT_EQ(v[0], 0);
71
72 ASSERT_EQ(s.Match("oobar", &v), false);
73 ASSERT_EQ(v.size(), size_t{0});
74 }
75
TEST(Set,UnanchoredDollar)76 TEST(Set, UnanchoredDollar) {
77 RE2::Set s(RE2::DefaultOptions, RE2::UNANCHORED);
78
79 ASSERT_EQ(s.Add("foo$", NULL), 0);
80 ASSERT_EQ(s.Compile(), true);
81
82 ASSERT_EQ(s.Match("foo", NULL), true);
83 ASSERT_EQ(s.Match("foobar", NULL), false);
84
85 std::vector<int> v;
86 ASSERT_EQ(s.Match("foo", &v), true);
87 ASSERT_EQ(v.size(), size_t{1});
88 ASSERT_EQ(v[0], 0);
89
90 ASSERT_EQ(s.Match("foobar", &v), false);
91 ASSERT_EQ(v.size(), size_t{0});
92 }
93
TEST(Set,UnanchoredWordBoundary)94 TEST(Set, UnanchoredWordBoundary) {
95 RE2::Set s(RE2::DefaultOptions, RE2::UNANCHORED);
96
97 ASSERT_EQ(s.Add("foo\\b", NULL), 0);
98 ASSERT_EQ(s.Compile(), true);
99
100 ASSERT_EQ(s.Match("foo", NULL), true);
101 ASSERT_EQ(s.Match("foobar", NULL), false);
102 ASSERT_EQ(s.Match("foo bar", NULL), true);
103
104 std::vector<int> v;
105 ASSERT_EQ(s.Match("foo", &v), true);
106 ASSERT_EQ(v.size(), size_t{1});
107 ASSERT_EQ(v[0], 0);
108
109 ASSERT_EQ(s.Match("foobar", &v), false);
110 ASSERT_EQ(v.size(), size_t{0});
111
112 ASSERT_EQ(s.Match("foo bar", &v), true);
113 ASSERT_EQ(v.size(), size_t{1});
114 ASSERT_EQ(v[0], 0);
115 }
116
TEST(Set,Anchored)117 TEST(Set, Anchored) {
118 RE2::Set s(RE2::DefaultOptions, RE2::ANCHOR_BOTH);
119
120 ASSERT_EQ(s.Add("foo", NULL), 0);
121 ASSERT_EQ(s.Add("(", NULL), -1);
122 ASSERT_EQ(s.Add("bar", NULL), 1);
123 ASSERT_EQ(s.Compile(), true);
124
125 ASSERT_EQ(s.Match("foobar", NULL), false);
126 ASSERT_EQ(s.Match("fooba", NULL), false);
127 ASSERT_EQ(s.Match("oobar", NULL), false);
128 ASSERT_EQ(s.Match("foo", NULL), true);
129 ASSERT_EQ(s.Match("bar", NULL), true);
130
131 std::vector<int> v;
132 ASSERT_EQ(s.Match("foobar", &v), false);
133 ASSERT_EQ(v.size(), size_t{0});
134
135 ASSERT_EQ(s.Match("fooba", &v), false);
136 ASSERT_EQ(v.size(), size_t{0});
137
138 ASSERT_EQ(s.Match("oobar", &v), false);
139 ASSERT_EQ(v.size(), size_t{0});
140
141 ASSERT_EQ(s.Match("foo", &v), true);
142 ASSERT_EQ(v.size(), size_t{1});
143 ASSERT_EQ(v[0], 0);
144
145 ASSERT_EQ(s.Match("bar", &v), true);
146 ASSERT_EQ(v.size(), size_t{1});
147 ASSERT_EQ(v[0], 1);
148 }
149
TEST(Set,EmptyUnanchored)150 TEST(Set, EmptyUnanchored) {
151 RE2::Set s(RE2::DefaultOptions, RE2::UNANCHORED);
152
153 ASSERT_EQ(s.Compile(), true);
154
155 ASSERT_EQ(s.Match("", NULL), false);
156 ASSERT_EQ(s.Match("foobar", NULL), false);
157
158 std::vector<int> v;
159 ASSERT_EQ(s.Match("", &v), false);
160 ASSERT_EQ(v.size(), size_t{0});
161
162 ASSERT_EQ(s.Match("foobar", &v), false);
163 ASSERT_EQ(v.size(), size_t{0});
164 }
165
TEST(Set,EmptyAnchored)166 TEST(Set, EmptyAnchored) {
167 RE2::Set s(RE2::DefaultOptions, RE2::ANCHOR_BOTH);
168
169 ASSERT_EQ(s.Compile(), true);
170
171 ASSERT_EQ(s.Match("", NULL), false);
172 ASSERT_EQ(s.Match("foobar", NULL), false);
173
174 std::vector<int> v;
175 ASSERT_EQ(s.Match("", &v), false);
176 ASSERT_EQ(v.size(), size_t{0});
177
178 ASSERT_EQ(s.Match("foobar", &v), false);
179 ASSERT_EQ(v.size(), size_t{0});
180 }
181
TEST(Set,Prefix)182 TEST(Set, Prefix) {
183 RE2::Set s(RE2::DefaultOptions, RE2::ANCHOR_BOTH);
184
185 ASSERT_EQ(s.Add("/prefix/\\d*", NULL), 0);
186 ASSERT_EQ(s.Compile(), true);
187
188 ASSERT_EQ(s.Match("/prefix", NULL), false);
189 ASSERT_EQ(s.Match("/prefix/", NULL), true);
190 ASSERT_EQ(s.Match("/prefix/42", NULL), true);
191
192 std::vector<int> v;
193 ASSERT_EQ(s.Match("/prefix", &v), false);
194 ASSERT_EQ(v.size(), size_t{0});
195
196 ASSERT_EQ(s.Match("/prefix/", &v), true);
197 ASSERT_EQ(v.size(), size_t{1});
198 ASSERT_EQ(v[0], 0);
199
200 ASSERT_EQ(s.Match("/prefix/42", &v), true);
201 ASSERT_EQ(v.size(), size_t{1});
202 ASSERT_EQ(v[0], 0);
203 }
204
TEST(Set,MoveSemantics)205 TEST(Set, MoveSemantics) {
206 RE2::Set s1(RE2::DefaultOptions, RE2::UNANCHORED);
207 ASSERT_EQ(s1.Add("foo\\d+", NULL), 0);
208 ASSERT_EQ(s1.Compile(), true);
209 ASSERT_EQ(s1.Match("abc foo1 xyz", NULL), true);
210 ASSERT_EQ(s1.Match("abc bar2 xyz", NULL), false);
211
212 // The moved-to object should do what the moved-from object did.
213 RE2::Set s2 = std::move(s1);
214 ASSERT_EQ(s2.Match("abc foo1 xyz", NULL), true);
215 ASSERT_EQ(s2.Match("abc bar2 xyz", NULL), false);
216
217 // The moved-from object should have been reset and be reusable.
218 ASSERT_EQ(s1.Add("bar\\d+", NULL), 0);
219 ASSERT_EQ(s1.Compile(), true);
220 ASSERT_EQ(s1.Match("abc foo1 xyz", NULL), false);
221 ASSERT_EQ(s1.Match("abc bar2 xyz", NULL), true);
222
223 // Verify that "overwriting" works and also doesn't leak memory.
224 // (The latter will need a leak detector such as LeakSanitizer.)
225 s1 = std::move(s2);
226 ASSERT_EQ(s1.Match("abc foo1 xyz", NULL), true);
227 ASSERT_EQ(s1.Match("abc bar2 xyz", NULL), false);
228 }
229
230 } // namespace re2
231