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:
parent
ef374b8692
commit
1f1eeeade2
@ -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();
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user