parent
7876639e50
commit
2e83d5c98f
2 changed files with 1 additions and 232 deletions
@ -1,230 +0,0 @@ |
|||||||
/*
|
|
||||||
** Common functionality for tests. |
|
||||||
**/ |
|
||||||
|
|
||||||
#ifndef UPB_TEST_UTIL_H_ |
|
||||||
#define UPB_TEST_UTIL_H_ |
|
||||||
|
|
||||||
#include <stdio.h> |
|
||||||
#include <math.h> |
|
||||||
#include "tests/upb_test.h" |
|
||||||
#include "upb/sink.h" |
|
||||||
|
|
||||||
#include "upb/port_def.inc" |
|
||||||
|
|
||||||
#ifdef __cplusplus |
|
||||||
|
|
||||||
upb_bufhandle global_handle; |
|
||||||
|
|
||||||
/* A convenience class for parser tests. Provides some useful features:
|
|
||||||
* |
|
||||||
* - can support multiple calls to parse, to test the parser's handling |
|
||||||
* of buffer seams. |
|
||||||
* |
|
||||||
* - can output verbose output about each parse call when requested, for |
|
||||||
* ease of debugging. |
|
||||||
* |
|
||||||
* - can pass NULL for skipped regions of the input if requested. |
|
||||||
* |
|
||||||
* - allocates and passes a separate buffer for each parsed region, to |
|
||||||
* ensure that the parser is not erroneously overreading its buffer. |
|
||||||
*/ |
|
||||||
class VerboseParserEnvironment { |
|
||||||
public: |
|
||||||
/* Pass verbose=true to print detailed diagnostics to stderr. */ |
|
||||||
VerboseParserEnvironment(bool verbose) : verbose_(verbose) {} |
|
||||||
|
|
||||||
void Reset(const char *buf, size_t len, bool may_skip, bool expect_error) { |
|
||||||
buf_ = buf; |
|
||||||
len_ = len; |
|
||||||
ofs_ = 0; |
|
||||||
expect_error_ = expect_error; |
|
||||||
end_ok_set_ = false; |
|
||||||
skip_until_ = may_skip ? 0 : -1; |
|
||||||
skipped_with_null_ = false; |
|
||||||
} |
|
||||||
|
|
||||||
/* The user should call a series of:
|
|
||||||
* |
|
||||||
* Reset(buf, len, may_skip); |
|
||||||
* Start() |
|
||||||
* ParseBuffer(X); |
|
||||||
* ParseBuffer(Y); |
|
||||||
* // Repeat ParseBuffer as desired, but last call should pass -1.
|
|
||||||
* ParseBuffer(-1); |
|
||||||
* End(); |
|
||||||
*/ |
|
||||||
|
|
||||||
|
|
||||||
bool Start() { |
|
||||||
if (verbose_) { |
|
||||||
fprintf(stderr, "Calling start()\n"); |
|
||||||
} |
|
||||||
return sink_.Start(len_, &subc_); |
|
||||||
} |
|
||||||
|
|
||||||
bool End() { |
|
||||||
if (verbose_) { |
|
||||||
fprintf(stderr, "Calling end()\n"); |
|
||||||
} |
|
||||||
end_ok_ = sink_.End(); |
|
||||||
end_ok_set_ = true; |
|
||||||
|
|
||||||
return end_ok_; |
|
||||||
} |
|
||||||
|
|
||||||
bool CheckConsistency() { |
|
||||||
/* If we called end (which we should only do when previous bytes are fully
|
|
||||||
* accepted), then end() should return true iff there were no errors. */ |
|
||||||
if (end_ok_set_ && end_ok_ != status_.ok()) { |
|
||||||
fprintf(stderr, "End() status and saw_error didn't match.\n"); |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
if (expect_error_ && status_.ok()) { |
|
||||||
fprintf(stderr, "Expected error but saw none.\n"); |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
if (!status_.ok()) { |
|
||||||
if (expect_error_ && verbose_) { |
|
||||||
fprintf(stderr, "Encountered error, as expected: %s", |
|
||||||
status_.error_message()); |
|
||||||
} else if (!expect_error_) { |
|
||||||
fprintf(stderr, "Encountered unexpected error: %s", |
|
||||||
status_.error_message()); |
|
||||||
return false; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
bool ParseBuffer(int bytes) { |
|
||||||
if (bytes < 0) { |
|
||||||
bytes = (int)(len_ - ofs_); |
|
||||||
} |
|
||||||
|
|
||||||
ASSERT((size_t)bytes <= (len_ - ofs_)); |
|
||||||
|
|
||||||
/* Copy buffer into a separate, temporary buffer.
|
|
||||||
* This is necessary to verify that the parser is not erroneously |
|
||||||
* reading outside the specified bounds. */ |
|
||||||
char *buf2 = NULL; |
|
||||||
|
|
||||||
if ((int)(ofs_ + bytes) <= skip_until_) { |
|
||||||
skipped_with_null_ = true; |
|
||||||
} else { |
|
||||||
buf2 = (char*)malloc(bytes); |
|
||||||
UPB_ASSERT(buf2); |
|
||||||
memcpy(buf2, buf_ + ofs_, bytes); |
|
||||||
} |
|
||||||
|
|
||||||
if (buf2 == NULL && bytes == 0) { |
|
||||||
/* Decoders dont' support buf=NULL, bytes=0. */ |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
if (verbose_) { |
|
||||||
fprintf(stderr, "Calling parse(%u) for bytes %u-%u of the input\n", |
|
||||||
(unsigned)bytes, (unsigned)ofs_, (unsigned)(ofs_ + bytes)); |
|
||||||
} |
|
||||||
|
|
||||||
int parsed = (int)sink_.PutBuffer(subc_, buf2, bytes, &global_handle); |
|
||||||
free(buf2); |
|
||||||
|
|
||||||
if (verbose_) { |
|
||||||
if (parsed == bytes) { |
|
||||||
fprintf(stderr, |
|
||||||
"parse(%u) = %u, complete byte count indicates success\n", |
|
||||||
(unsigned)bytes, (unsigned)bytes); |
|
||||||
} else if (parsed > bytes) { |
|
||||||
fprintf(stderr, |
|
||||||
"parse(%u) = %u, long byte count indicates success and skip " |
|
||||||
"of the next %u bytes\n", |
|
||||||
(unsigned)bytes, (unsigned)parsed, (unsigned)(parsed - bytes)); |
|
||||||
} else { |
|
||||||
fprintf(stderr, |
|
||||||
"parse(%u) = %u, short byte count indicates failure; " |
|
||||||
"last %u bytes were not consumed\n", |
|
||||||
(unsigned)bytes, (unsigned)parsed, (unsigned)(bytes - parsed)); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (!status_.ok()) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
if (parsed > bytes && skip_until_ >= 0) { |
|
||||||
skip_until_ = (int)(ofs_ + parsed); |
|
||||||
} |
|
||||||
|
|
||||||
ofs_ += UPB_MIN(parsed, bytes); |
|
||||||
|
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
void ResetBytesSink(upb::BytesSink sink) { |
|
||||||
sink_ = sink; |
|
||||||
} |
|
||||||
|
|
||||||
size_t ofs() { return ofs_; } |
|
||||||
|
|
||||||
bool SkippedWithNull() { return skipped_with_null_; } |
|
||||||
|
|
||||||
upb::Arena* arena() { return &arena_; } |
|
||||||
upb::Status* status() { return &status_; } |
|
||||||
|
|
||||||
private: |
|
||||||
upb::Arena arena_; |
|
||||||
upb::Status status_; |
|
||||||
upb::BytesSink sink_; |
|
||||||
const char* buf_; |
|
||||||
size_t len_; |
|
||||||
bool verbose_; |
|
||||||
size_t ofs_; |
|
||||||
void *subc_; |
|
||||||
bool expect_error_; |
|
||||||
bool end_ok_; |
|
||||||
bool end_ok_set_; |
|
||||||
|
|
||||||
/* When our parse call returns a value greater than the number of bytes
|
|
||||||
* we passed in, the decoder is indicating to us that the next N bytes |
|
||||||
* in the stream are not needed and can be skipped. The user is allowed |
|
||||||
* to pass a NULL buffer for those N bytes. |
|
||||||
* |
|
||||||
* skip_until_ is initially set to 0 if we should do this NULL-buffer |
|
||||||
* skipping or -1 if we should not. If we are open to doing NULL-buffer |
|
||||||
* skipping and we get an opportunity to do it, we set skip_until to the |
|
||||||
* stream offset where we can skip until. The user can then test whether |
|
||||||
* this happened by testing SkippedWithNull(). */ |
|
||||||
int skip_until_; |
|
||||||
bool skipped_with_null_; |
|
||||||
}; |
|
||||||
|
|
||||||
#endif /* __cplusplus */ |
|
||||||
|
|
||||||
UPB_INLINE char *upb_readfile(const char *filename, size_t *len) { |
|
||||||
long size; |
|
||||||
char *buf; |
|
||||||
FILE *f = fopen(filename, "rb"); |
|
||||||
if(!f) return NULL; |
|
||||||
if(fseek(f, 0, SEEK_END) != 0) goto error; |
|
||||||
size = ftell(f); |
|
||||||
if(size < 0) goto error; |
|
||||||
if(fseek(f, 0, SEEK_SET) != 0) goto error; |
|
||||||
buf = (char*)malloc(size + 1); |
|
||||||
if(size && fread(buf, size, 1, f) != 1) goto error; |
|
||||||
fclose(f); |
|
||||||
if (len) *len = size; |
|
||||||
buf[size] = '\0'; |
|
||||||
return buf; |
|
||||||
|
|
||||||
error: |
|
||||||
fclose(f); |
|
||||||
return NULL; |
|
||||||
} |
|
||||||
|
|
||||||
#include "upb/port_undef.inc" |
|
||||||
|
|
||||||
#endif /* UPB_TEST_UTIL_H_ */ |
|
Loading…
Reference in new issue