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