1 #include "upb/wire/eps_copy_input_stream.h"
2
3 #include <string.h>
4
5 #include <string>
6
7 #include "gtest/gtest.h"
8 #include "upb/upb.hpp"
9 // begin:google_only
10 // #include "testing/fuzzing/fuzztest.h"
11 // end:google_only
12
13 namespace {
14
TEST(EpsCopyInputStreamTest,ZeroSize)15 TEST(EpsCopyInputStreamTest, ZeroSize) {
16 upb_EpsCopyInputStream stream;
17 const char* ptr = NULL;
18 upb_EpsCopyInputStream_Init(&stream, &ptr, 0, false);
19 EXPECT_TRUE(upb_EpsCopyInputStream_IsDoneWithCallback(&stream, &ptr, NULL));
20 }
21
22 // begin:google_only
23 //
24 // // We create a simple, trivial implementation of the stream that we can test
25 // // our real implementation against.
26 //
27 // class FakeStream {
28 // public:
29 // FakeStream(const std::string& data) : data_(data), offset_(0) {
30 // limits_.push_back(data.size());
31 // }
32 //
33 // // If we reached one or more limits correctly, returns the number of limits
34 // // ended. If we tried to read beyond the current limit, returns -1.
35 // // Otherwise, for simple success, returns 0.
36 // int ReadData(int n, std::string* data) {
37 // if (n > BytesUntilLimit()) return -1;
38 //
39 // data->assign(data_.data() + offset_, n);
40 // offset_ += n;
41 //
42 // int end_limit_count = 0;
43 //
44 // while (BytesUntilLimit() == 0) {
45 // if (PopLimit()) {
46 // end_limit_count++;
47 // } else {
48 // eof_ = true;
49 // break;
50 // }
51 // }
52 //
53 // return end_limit_count;
54 // }
55 //
56 // bool TryPushLimit(int limit) {
57 // if (!CheckSize(limit)) return false;
58 // limits_.push_back(offset_ + limit);
59 // return true;
60 // }
61 //
62 // bool IsEof() const { return eof_; }
63 //
64 // private:
65 // int BytesUntilLimit() const { return limits_.back() - offset_; }
66 // bool CheckSize(int size) const { return BytesUntilLimit() >= size; }
67 //
68 // // Return false on EOF.
69 // bool PopLimit() {
70 // limits_.pop_back();
71 // return !limits_.empty();
72 // }
73 //
74 // std::string data_;
75 // // Limits, specified in absolute stream terms.
76 // std::vector<int> limits_;
77 // int offset_;
78 // bool eof_ = false;
79 // };
80 //
81 // char tmp_buf[kUpb_EpsCopyInputStream_SlopBytes];
82 //
83 // class EpsStream {
84 // public:
85 // EpsStream(const std::string& data, bool enable_aliasing)
86 // : data_(data), enable_aliasing_(enable_aliasing) {
87 // ptr_ = data_.data();
88 // upb_EpsCopyInputStream_Init(&eps_, &ptr_, data_.size(), enable_aliasing);
89 // }
90 //
91 // // Returns false at EOF or error.
92 // int ReadData(int n, std::string* data) {
93 // EXPECT_LE(n, kUpb_EpsCopyInputStream_SlopBytes);
94 // if (enable_aliasing_) {
95 // EXPECT_TRUE(upb_EpsCopyInputStream_AliasingAvailable(&eps_, ptr_, n));
96 // }
97 // // We want to verify that we can read kUpb_EpsCopyInputStream_SlopBytes
98 // // safely, even if we haven't actually been requested to read that much.
99 // // We copy to a global buffer so the copy can't be optimized away.
100 // memcpy(&tmp_buf, ptr_, kUpb_EpsCopyInputStream_SlopBytes);
101 // data->assign(tmp_buf, n);
102 // ptr_ += n;
103 // if (enable_aliasing_) {
104 // EXPECT_TRUE(upb_EpsCopyInputStream_AliasingAvailable(&eps_, ptr_, 0));
105 // }
106 // return PopLimits();
107 // }
108 //
109 // int ReadString(int n, std::string* data) {
110 // if (!upb_EpsCopyInputStream_CheckSize(&eps_, ptr_, n)) return -1;
111 // const char* str_data = ptr_;
112 // if (enable_aliasing_) {
113 // EXPECT_TRUE(upb_EpsCopyInputStream_AliasingAvailable(&eps_, ptr_, n));
114 // }
115 // ptr_ = upb_EpsCopyInputStream_ReadString(&eps_, &str_data, n, arena_.ptr());
116 // if (!ptr_) return -1;
117 // if (enable_aliasing_ && n) {
118 // EXPECT_GE(reinterpret_cast<uintptr_t>(str_data),
119 // reinterpret_cast<uintptr_t>(data_.data()));
120 // EXPECT_LT(reinterpret_cast<uintptr_t>(str_data),
121 // reinterpret_cast<uintptr_t>(data_.data() + data_.size()));
122 // EXPECT_TRUE(upb_EpsCopyInputStream_AliasingAvailable(&eps_, ptr_, 0));
123 // }
124 // data->assign(str_data, n);
125 // return PopLimits();
126 // }
127 //
128 // bool TryPushLimit(int limit) {
129 // if (!upb_EpsCopyInputStream_CheckSize(&eps_, ptr_, limit)) return false;
130 // deltas_.push_back(upb_EpsCopyInputStream_PushLimit(&eps_, ptr_, limit));
131 // return true;
132 // }
133 //
134 // bool IsEof() const { return eof_; }
135 //
136 // private:
137 // int PopLimits() {
138 // int end_limit_count = 0;
139 //
140 // while (IsAtLimit()) {
141 // if (error_) return -1;
142 // if (PopLimit()) {
143 // end_limit_count++;
144 // } else {
145 // eof_ = true; // EOF.
146 // break;
147 // }
148 // }
149 //
150 // return error_ ? -1 : end_limit_count;
151 // }
152 //
153 // bool IsAtLimit() {
154 // return upb_EpsCopyInputStream_IsDoneWithCallback(
155 // &eps_, &ptr_, &EpsStream::IsDoneFallback);
156 // }
157 //
158 // // Return false on EOF.
159 // bool PopLimit() {
160 // if (deltas_.empty()) return false;
161 // upb_EpsCopyInputStream_PopLimit(&eps_, ptr_, deltas_.back());
162 // deltas_.pop_back();
163 // return true;
164 // }
165 //
166 // static const char* IsDoneFallback(upb_EpsCopyInputStream* e, const char* ptr,
167 // int overrun) {
168 // return _upb_EpsCopyInputStream_IsDoneFallbackInline(
169 // e, ptr, overrun, &EpsStream::BufferFlipCallback);
170 // }
171 //
172 // static const char* BufferFlipCallback(upb_EpsCopyInputStream* e,
173 // const char* old_end,
174 // const char* new_start) {
175 // EpsStream* stream = reinterpret_cast<EpsStream*>(e);
176 // if (!old_end) stream->error_ = true;
177 // return new_start;
178 // }
179 //
180 // upb_EpsCopyInputStream eps_;
181 // std::string data_;
182 // const char* ptr_;
183 // std::vector<int> deltas_;
184 // upb::Arena arena_;
185 // bool error_ = false;
186 // bool eof_ = false;
187 // bool enable_aliasing_;
188 // };
189 //
190 // // Reads N bytes from the given position.
191 // struct ReadOp {
192 // int bytes; // Must be <= kUpb_EpsCopyInputStream_SlopBytes.
193 // };
194 //
195 // struct ReadStringOp {
196 // int bytes;
197 // };
198 //
199 // // Pushes a new limit of N bytes from the current position.
200 // struct PushLimitOp {
201 // int bytes;
202 // };
203 //
204 // typedef std::variant<ReadOp, ReadStringOp, PushLimitOp> Op;
205 //
206 // struct EpsCopyTestScript {
207 // int data_size;
208 // bool enable_aliasing;
209 // std::vector<Op> ops;
210 // };
211 //
212 // auto ArbitraryEpsCopyTestScript() {
213 // using ::fuzztest::Arbitrary;
214 // using ::fuzztest::InRange;
215 // using ::fuzztest::NonNegative;
216 // using ::fuzztest::StructOf;
217 // using ::fuzztest::VariantOf;
218 // using ::fuzztest::VectorOf;
219 //
220 // int max_data_size = 512;
221 //
222 // return StructOf<EpsCopyTestScript>(
223 // InRange(0, max_data_size), // data_size
224 // Arbitrary<bool>(), // enable_aliasing
225 // VectorOf(VariantOf(
226 // // ReadOp
227 // StructOf<ReadOp>(InRange(0, kUpb_EpsCopyInputStream_SlopBytes)),
228 // // ReadStringOp
229 // StructOf<ReadStringOp>(NonNegative<int>()),
230 // // PushLimitOp
231 // StructOf<PushLimitOp>(NonNegative<int>()))));
232 // }
233 //
234 // // Run a test that creates both real stream and a fake stream, and validates
235 // // that they have the same behavior.
236 // void TestAgainstFakeStream(const EpsCopyTestScript& script) {
237 // std::string data(script.data_size, 'x');
238 // for (int i = 0; i < script.data_size; ++i) {
239 // data[i] = static_cast<char>(i & 0xff);
240 // }
241 //
242 // FakeStream fake_stream(data);
243 // EpsStream eps_stream(data, script.enable_aliasing);
244 //
245 // for (const auto& op : script.ops) {
246 // if (const ReadOp* read_op = std::get_if<ReadOp>(&op)) {
247 // std::string data_fake;
248 // std::string data_eps;
249 // int fake_result = fake_stream.ReadData(read_op->bytes, &data_fake);
250 // int eps_result = eps_stream.ReadData(read_op->bytes, &data_eps);
251 // EXPECT_EQ(fake_result, eps_result);
252 // if (fake_result == -1) break; // Error
253 // EXPECT_EQ(data_fake, data_eps);
254 // EXPECT_EQ(fake_stream.IsEof(), eps_stream.IsEof());
255 // if (fake_stream.IsEof()) break;
256 // } else if (const ReadStringOp* read_op = std::get_if<ReadStringOp>(&op)) {
257 // std::string data_fake;
258 // std::string data_eps;
259 // int fake_result = fake_stream.ReadData(read_op->bytes, &data_fake);
260 // int eps_result = eps_stream.ReadString(read_op->bytes, &data_eps);
261 // EXPECT_EQ(fake_result, eps_result);
262 // if (fake_result == -1) break; // Error
263 // EXPECT_EQ(data_fake, data_eps);
264 // EXPECT_EQ(fake_stream.IsEof(), eps_stream.IsEof());
265 // if (fake_stream.IsEof()) break;
266 // } else if (const PushLimitOp* push = std::get_if<PushLimitOp>(&op)) {
267 // EXPECT_EQ(fake_stream.TryPushLimit(push->bytes),
268 // eps_stream.TryPushLimit(push->bytes));
269 // } else {
270 // EXPECT_TRUE(false); // Unknown op.
271 // }
272 // }
273 // }
274 //
275 // // Test with:
276 // // $ blaze run --config=fuzztest third_party/upb:eps_copy_input_stream_test \
277 // // -- --gunit_fuzz=
278 // FUZZ_TEST(EpsCopyFuzzTest, TestAgainstFakeStream)
279 // .WithDomains(ArbitraryEpsCopyTestScript());
280 //
281 // TEST(EpsCopyFuzzTest, TestAgainstFakeStreamRegression) {
282 // TestAgainstFakeStream({299,
283 // false,
284 // {
285 // PushLimitOp{2},
286 // ReadOp{14},
287 // }});
288 // }
289 //
290 // TEST(EpsCopyFuzzTest, AliasingEnabledZeroSizeReadString) {
291 // TestAgainstFakeStream({510, true, {ReadStringOp{0}}});
292 // }
293 //
294 // TEST(EpsCopyFuzzTest, AliasingDisabledZeroSizeReadString) {
295 // TestAgainstFakeStream({510, false, {ReadStringOp{0}}});
296 // }
297 //
298 // TEST(EpsCopyFuzzTest, ReadStringZero) {
299 // TestAgainstFakeStream({0, true, {ReadStringOp{0}}});
300 // }
301 //
302 // TEST(EpsCopyFuzzTest, ReadZero) {
303 // TestAgainstFakeStream({0, true, {ReadOp{0}}});
304 // }
305 //
306 // TEST(EpsCopyFuzzTest, ReadZeroTwice) {
307 // TestAgainstFakeStream({0, true, {ReadOp{0}, ReadOp{0}}});
308 // }
309 //
310 // TEST(EpsCopyFuzzTest, ReadStringZeroThenRead) {
311 // TestAgainstFakeStream({0, true, {ReadStringOp{0}, ReadOp{0}}});
312 // }
313 //
314 // TEST(EpsCopyFuzzTest, ReadStringOverflowsBufferButNotLimit) {
315 // TestAgainstFakeStream({351,
316 // false,
317 // {
318 // ReadOp{7},
319 // PushLimitOp{2147483647},
320 // ReadStringOp{344},
321 // }});
322 // }
323 //
324 // TEST(EpsCopyFuzzTest, LastBufferAliasing) {
325 // TestAgainstFakeStream({27, true, {ReadOp{12}, ReadStringOp{3}}});
326 // }
327 //
328 // TEST(EpsCopyFuzzTest, FirstBufferAliasing) {
329 // TestAgainstFakeStream({7, true, {ReadStringOp{3}}});
330 // }
331 //
332 // end:google_only
333
334 } // namespace
335