Allow FileTest to read from an abstracted line reader.

In GTest, we'll just burn the files into the binary and not worry about
this. Apparently test files is a one of computer science's great
unsolved problems and everyone has their own special-snowflake way of
doing it. Burning them into the executable is easier.

BUG=129

Change-Id: Ib39759ed4dba6eb9ba97f0282f000739ddf931fe
Reviewed-on: https://boringssl-review.googlesource.com/16506
Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
David Benjamin 2017-05-18 19:39:06 -04:00 committed by Adam Langley
parent ef374b8692
commit 1f1eeeade2
2 changed files with 65 additions and 33 deletions

View File

@ -15,11 +15,13 @@
#include "file_test.h" #include "file_test.h"
#include <algorithm> #include <algorithm>
#include <memory> #include <utility>
#include <assert.h>
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -28,18 +30,10 @@
#include "../internal.h" #include "../internal.h"
FileTest::FileTest(const char *path) { FileTest::FileTest(std::unique_ptr<FileTest::LineReader> reader)
file_ = fopen(path, "r"); : reader_(std::move(reader)) {}
if (file_ == nullptr) {
fprintf(stderr, "Could not open file %s: %s.\n", path, strerror(errno));
}
}
FileTest::~FileTest() { FileTest::~FileTest() {}
if (file_ != nullptr) {
fclose(file_);
}
}
// FindDelimiter returns a pointer to the first '=' or ':' in |str| or nullptr // FindDelimiter returns a pointer to the first '=' or ':' in |str| or nullptr
// if there is none. // if there is none.
@ -104,23 +98,19 @@ FileTest::ReadResult FileTest::ReadNext() {
while (true) { while (true) {
// Read the next line. // Read the next line.
if (fgets(buf.get(), kBufLen, file_) == nullptr) { switch (reader_->ReadLine(buf.get(), kBufLen)) {
if (feof(file_)) { case kReadError:
fprintf(stderr, "Error reading from input at line %u.\n", line_ + 1);
return kReadError;
case kReadEOF:
// EOF is a valid terminator for a test. // EOF is a valid terminator for a test.
return start_line_ > 0 ? kReadSuccess : kReadEOF; return start_line_ > 0 ? kReadSuccess : kReadEOF;
} case kReadSuccess:
fprintf(stderr, "Error reading from input.\n"); break;
return kReadError;
} }
line_++; line_++;
size_t len = strlen(buf.get()); size_t len = strlen(buf.get());
// Check for truncation.
if (len > 0 && buf[len - 1] != '\n' && !feof(file_)) {
fprintf(stderr, "Line %u too long.\n", line_);
return kReadError;
}
if (buf[0] == '\n' || buf[0] == '\r' || buf[0] == '\0') { if (buf[0] == '\n' || buf[0] == '\r' || buf[0] == '\0') {
// Empty lines delimit tests. // Empty lines delimit tests.
if (start_line_ > 0) { if (start_line_ > 0) {
@ -372,12 +362,51 @@ void FileTest::InjectInstruction(const std::string &key,
instructions_[key] = value; instructions_[key] = value;
} }
class FileLineReader : public FileTest::LineReader {
public:
explicit FileLineReader(const char *path) : file_(fopen(path, "r")) {}
~FileLineReader() override {
if (file_ != nullptr) {
fclose(file_);
}
}
// is_open returns true if the file was successfully opened.
bool is_open() const { return file_ != nullptr; }
FileTest::ReadResult ReadLine(char *out, size_t len) override {
assert(len > 0);
if (file_ == nullptr) {
return FileTest::kReadError;
}
if (fgets(out, len, file_) == nullptr) {
return feof(file_) ? FileTest::kReadEOF : FileTest::kReadError;
}
if (strlen(out) == len - 1 && out[len - 2] != '\n' && !feof(file_)) {
fprintf(stderr, "Line too long.\n");
return FileTest::kReadError;
}
return FileTest::kReadSuccess;
}
private:
FILE *file_;
FileLineReader(const FileLineReader &) = delete;
FileLineReader &operator=(const FileLineReader &) = delete;
};
int FileTestMainSilent(FileTestFunc run_test, void *arg, const char *path) { int FileTestMainSilent(FileTestFunc run_test, void *arg, const char *path) {
FileTest t(path); std::unique_ptr<FileLineReader> reader(new FileLineReader(path));
if (!t.is_open()) { if (!reader->is_open()) {
fprintf(stderr, "Could not open file %s: %s.\n", path, strerror(errno));
return 1; return 1;
} }
FileTest t(std::move(reader));
bool failed = false; bool failed = false;
while (true) { while (true) {
FileTest::ReadResult ret = t.ReadNext(); FileTest::ReadResult ret = t.ReadNext();

View File

@ -18,12 +18,12 @@
#include <openssl/base.h> #include <openssl/base.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
OPENSSL_MSVC_PRAGMA(warning(push)) OPENSSL_MSVC_PRAGMA(warning(push))
OPENSSL_MSVC_PRAGMA(warning(disable : 4702)) OPENSSL_MSVC_PRAGMA(warning(disable : 4702))
#include <map> #include <map>
#include <memory>
#include <set> #include <set>
#include <string> #include <string>
#include <vector> #include <vector>
@ -86,18 +86,21 @@ OPENSSL_MSVC_PRAGMA(warning(pop))
class FileTest { class FileTest {
public: public:
explicit FileTest(const char *path);
~FileTest();
// is_open returns true if the file was successfully opened.
bool is_open() const { return file_ != nullptr; }
enum ReadResult { enum ReadResult {
kReadSuccess, kReadSuccess,
kReadEOF, kReadEOF,
kReadError, kReadError,
}; };
class LineReader {
public:
virtual ~LineReader() {}
virtual ReadResult ReadLine(char *out, size_t len) = 0;
};
explicit FileTest(std::unique_ptr<LineReader> reader);
~FileTest();
// ReadNext reads the next test from the file. It returns |kReadSuccess| if // ReadNext reads the next test from the file. It returns |kReadSuccess| if
// successfully reading a test and |kReadEOF| at the end of the file. On // successfully reading a test and |kReadEOF| at the end of the file. On
// error or if the previous test had unconsumed attributes, it returns // error or if the previous test had unconsumed attributes, it returns
@ -168,7 +171,7 @@ class FileTest {
void OnKeyUsed(const std::string &key); void OnKeyUsed(const std::string &key);
void OnInstructionUsed(const std::string &key); void OnInstructionUsed(const std::string &key);
FILE *file_ = nullptr; std::unique_ptr<LineReader> reader_;
// line_ is the number of lines read. // line_ is the number of lines read.
unsigned line_ = 0; unsigned line_ = 0;