1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <fuzz-utils/string-list.h>
6 #include <unittest/unittest.h>
7
8 namespace fuzzing {
9 namespace testing {
10 namespace {
11
12 #define arraysize(x) sizeof(x) / sizeof(x[0])
13
14 // Helper function to find expected strings in a list
Match(StringList * list,const char ** expected,size_t off,size_t len)15 bool Match(StringList* list, const char** expected, size_t off, size_t len) {
16 BEGIN_HELPER;
17 EXPECT_EQ(list->length(), len);
18 const char* elem = list->first();
19 for (size_t i = 0; i < len; ++i) {
20 ASSERT_NONNULL(elem);
21 EXPECT_STR_EQ(elem, expected[off + i]);
22 elem = list->next();
23 }
24 EXPECT_NULL(elem);
25 END_HELPER;
26 }
27
TestEmpty()28 bool TestEmpty() {
29 BEGIN_TEST;
30 StringList list;
31
32 EXPECT_TRUE(list.is_empty());
33 EXPECT_NULL(list.first());
34 EXPECT_NULL(list.next());
35
36 END_TEST;
37 }
38
TestPushFrontAndBack()39 bool TestPushFrontAndBack() {
40 BEGIN_TEST;
41 StringList list;
42 const char* expected[] = {"", "foo", "bar", "baz", ""};
43
44 // Strings can be pushed from either end
45 list.push_front("bar");
46 list.push_back("baz");
47 list.push_front("foo");
48 EXPECT_TRUE(Match(&list, expected, 1, 3));
49
50 // Empty strings are fine
51 list.push_front("");
52 list.push_back("");
53 EXPECT_TRUE(Match(&list, expected, 0, 5));
54
55 // Null strings are ignored
56 list.push_front(nullptr);
57 list.push_back(nullptr);
58 EXPECT_TRUE(Match(&list, expected, 0, 5));
59
60 // Test the new constructor
61 StringList list2(expected, arraysize(expected));
62 EXPECT_TRUE(Match(&list, expected, 0, 5));
63
64 END_TEST;
65 }
66
TestKeepIf()67 bool TestKeepIf() {
68 BEGIN_TEST;
69 StringList list;
70 const char* original[] = {"", "foo", "bar", "baz", "qux",
71 "quux", "corge", "grault", "garply", "waldo",
72 "fred", "plugh", "xyzzy", "thud", ""};
73
74 const char* expected1[] = {"bar", "corge", "grault", "garply", "plugh"};
75
76 const char* expected2[] = {"corge", "grault", "garply", "plugh"};
77
78 const char* expected3[] = {"garply"};
79
80 for (size_t i = 0; i < arraysize(original); ++i) {
81 list.push_back(original[i]);
82 }
83
84 // Null string has no effect
85 list.keep_if(nullptr);
86 EXPECT_TRUE(Match(&list, original, 0, arraysize(original)));
87
88 // Empty string matches everything
89 list.keep_if("");
90 EXPECT_TRUE(Match(&list, original, 0, arraysize(original)));
91
92 // Match a string
93 list.keep_if("g");
94 EXPECT_TRUE(Match(&list, expected2, 0, arraysize(expected2)));
95
96 // Match a string that would have matched elements in the original list
97 list.keep_if("ar");
98 EXPECT_TRUE(Match(&list, expected3, 0, arraysize(expected3)));
99
100 // Use a string that doesn't match anything
101 list.keep_if("zzz");
102 EXPECT_TRUE(list.is_empty());
103
104 // Reset and apply both matches at once with logical-or
105 StringList substrs;
106 substrs.push_back("g");
107 substrs.push_back("ar");
108
109 list.clear();
110 for (size_t i = 0; i < arraysize(original); ++i) {
111 list.push_back(original[i]);
112 }
113 list.keep_if_any(&substrs);
114 EXPECT_TRUE(Match(&list, expected1, 0, arraysize(expected1)));
115
116 // Reset and apply both matches at once with logical-and
117 list.clear();
118 for (size_t i = 0; i < arraysize(original); ++i) {
119 list.push_back(original[i]);
120 }
121 list.keep_if_all(&substrs);
122 EXPECT_TRUE(Match(&list, expected3, 0, arraysize(expected3)));
123
124 END_TEST;
125 }
126
TestEraseIf()127 bool TestEraseIf() {
128 BEGIN_TEST;
129 StringList list;
130 const char* original[] = {"", "foo", "bar", "baz", ""};
131
132 const char* expected1[] = {"", "foo", "baz", ""};
133
134 const char* expected2[] = {"foo", "baz"};
135
136 for (size_t i = 0; i < sizeof(original) / sizeof(original[0]); ++i) {
137 list.push_back(original[i]);
138 }
139
140 // Null and empty strings have no effect
141 list.erase_if(nullptr);
142 EXPECT_TRUE(Match(&list, original, 0, arraysize(original)));
143
144 // Use a string that doesn't match anything
145 list.erase_if("zzz");
146 EXPECT_TRUE(Match(&list, original, 0, arraysize(original)));
147
148 // Match a string
149 list.erase_if("bar");
150 EXPECT_TRUE(Match(&list, expected1, 0, arraysize(expected1)));
151
152 // Idempotent
153 list.erase_if("bar");
154 EXPECT_TRUE(Match(&list, expected1, 0, arraysize(expected1)));
155
156 // Able to erase empty strings
157 list.erase_if("");
158 EXPECT_TRUE(Match(&list, expected2, 0, arraysize(expected2)));
159
160 END_TEST;
161 }
162
TestClear()163 bool TestClear() {
164 BEGIN_TEST;
165
166 StringList list;
167 list.push_front("bar");
168
169 EXPECT_NONNULL(list.first());
170 list.clear();
171 EXPECT_NULL(list.next());
172 EXPECT_NULL(list.first());
173 EXPECT_EQ(list.length(), 0);
174
175 END_TEST;
176 }
177
178 BEGIN_TEST_CASE(StringListTest)
179 RUN_TEST(TestEmpty)
180 RUN_TEST(TestPushFrontAndBack)
181 RUN_TEST(TestKeepIf)
182 RUN_TEST(TestEraseIf)
183 RUN_TEST(TestClear)
184 END_TEST_CASE(StringListTest)
185
186 } // namespace
187 } // namespace testing
188 } // namespace fuzzing
189