2 ** Common functionality for tests.
5 #ifndef UPB_TEST_UTIL_H_
6 #define UPB_TEST_UTIL_H_
10 #include "tests/upb_test.h"
13 #include "upb/port_def.inc"
17 upb_bufhandle global_handle;
19 /* A convenience class for parser tests. Provides some useful features:
21 * - can support multiple calls to parse, to test the parser's handling
24 * - can output verbose output about each parse call when requested, for
27 * - can pass NULL for skipped regions of the input if requested.
29 * - allocates and passes a separate buffer for each parsed region, to
30 * ensure that the parser is not erroneously overreading its buffer.
32 class VerboseParserEnvironment {
34 /* Pass verbose=true to print detailed diagnostics to stderr. */
35 VerboseParserEnvironment(bool verbose) : verbose_(verbose) {}
37 void Reset(const char *buf, size_t len, bool may_skip, bool expect_error) {
41 expect_error_ = expect_error;
43 skip_until_ = may_skip ? 0 : -1;
44 skipped_with_null_ = false;
47 /* The user should call a series of:
49 * Reset(buf, len, may_skip);
53 * // Repeat ParseBuffer as desired, but last call should pass -1.
61 fprintf(stderr, "Calling start()\n");
63 return sink_.Start(len_, &subc_);
68 fprintf(stderr, "Calling end()\n");
70 end_ok_ = sink_.End();
76 bool CheckConsistency() {
77 /* If we called end (which we should only do when previous bytes are fully
78 * accepted), then end() should return true iff there were no errors. */
79 if (end_ok_set_ && end_ok_ != status_.ok()) {
80 fprintf(stderr, "End() status and saw_error didn't match.\n");
84 if (expect_error_ && status_.ok()) {
85 fprintf(stderr, "Expected error but saw none.\n");
90 if (expect_error_ && verbose_) {
91 fprintf(stderr, "Encountered error, as expected: %s",
92 status_.error_message());
93 } else if (!expect_error_) {
94 fprintf(stderr, "Encountered unexpected error: %s",
95 status_.error_message());
103 bool ParseBuffer(int bytes) {
108 ASSERT((size_t)bytes <= (len_ - ofs_));
110 /* Copy buffer into a separate, temporary buffer.
111 * This is necessary to verify that the parser is not erroneously
112 * reading outside the specified bounds. */
115 if ((int)(ofs_ + bytes) <= skip_until_) {
116 skipped_with_null_ = true;
118 buf2 = (char*)malloc(bytes);
120 memcpy(buf2, buf_ + ofs_, bytes);
123 if (buf2 == NULL && bytes == 0) {
124 /* Decoders dont' support buf=NULL, bytes=0. */
129 fprintf(stderr, "Calling parse(%u) for bytes %u-%u of the input\n",
130 (unsigned)bytes, (unsigned)ofs_, (unsigned)(ofs_ + bytes));
133 int parsed = sink_.PutBuffer(subc_, buf2, bytes, &global_handle);
137 if (parsed == bytes) {
139 "parse(%u) = %u, complete byte count indicates success\n",
140 (unsigned)bytes, (unsigned)bytes);
141 } else if (parsed > bytes) {
143 "parse(%u) = %u, long byte count indicates success and skip "
144 "of the next %u bytes\n",
145 (unsigned)bytes, (unsigned)parsed, (unsigned)(parsed - bytes));
148 "parse(%u) = %u, short byte count indicates failure; "
149 "last %u bytes were not consumed\n",
150 (unsigned)bytes, (unsigned)parsed, (unsigned)(bytes - parsed));
158 if (parsed > bytes && skip_until_ >= 0) {
159 skip_until_ = ofs_ + parsed;
162 ofs_ += UPB_MIN(parsed, bytes);
167 void ResetBytesSink(upb::BytesSink sink) {
171 size_t ofs() { return ofs_; }
173 bool SkippedWithNull() { return skipped_with_null_; }
175 upb::Arena* arena() { return &arena_; }
176 upb::Status* status() { return &status_; }
181 upb::BytesSink sink_;
191 /* When our parse call returns a value greater than the number of bytes
192 * we passed in, the decoder is indicating to us that the next N bytes
193 * in the stream are not needed and can be skipped. The user is allowed
194 * to pass a NULL buffer for those N bytes.
196 * skip_until_ is initially set to 0 if we should do this NULL-buffer
197 * skipping or -1 if we should not. If we are open to doing NULL-buffer
198 * skipping and we get an opportunity to do it, we set skip_until to the
199 * stream offset where we can skip until. The user can then test whether
200 * this happened by testing SkippedWithNull(). */
202 bool skipped_with_null_;
205 #endif /* __cplusplus */
207 UPB_INLINE char *upb_readfile(const char *filename, size_t *len) {
210 FILE *f = fopen(filename, "rb");
212 if(fseek(f, 0, SEEK_END) != 0) goto error;
214 if(size < 0) goto error;
215 if(fseek(f, 0, SEEK_SET) != 0) goto error;
216 buf = (char*)malloc(size + 1);
217 if(size && fread(buf, size, 1, f) != 1) goto error;
219 if (len) *len = size;
228 #include "upb/port_undef.inc"
230 #endif /* UPB_TEST_UTIL_H_ */