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>
diff --git a/crypto/test/file_test.cc b/crypto/test/file_test.cc index 21ae3e4..87a6b96 100644 --- a/crypto/test/file_test.cc +++ b/crypto/test/file_test.cc
@@ -15,11 +15,13 @@ #include "file_test.h" #include <algorithm> -#include <memory> +#include <utility> +#include <assert.h> #include <ctype.h> #include <errno.h> #include <stdarg.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> @@ -28,18 +30,10 @@ #include "../internal.h" -FileTest::FileTest(const char *path) { - file_ = fopen(path, "r"); - if (file_ == nullptr) { - fprintf(stderr, "Could not open file %s: %s.\n", path, strerror(errno)); - } -} +FileTest::FileTest(std::unique_ptr<FileTest::LineReader> reader) + : reader_(std::move(reader)) {} -FileTest::~FileTest() { - if (file_ != nullptr) { - fclose(file_); - } -} +FileTest::~FileTest() {} // FindDelimiter returns a pointer to the first '=' or ':' in |str| or nullptr // if there is none. @@ -104,23 +98,19 @@ while (true) { // Read the next line. - if (fgets(buf.get(), kBufLen, file_) == nullptr) { - if (feof(file_)) { + switch (reader_->ReadLine(buf.get(), kBufLen)) { + 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. return start_line_ > 0 ? kReadSuccess : kReadEOF; - } - fprintf(stderr, "Error reading from input.\n"); - return kReadError; + case kReadSuccess: + break; } line_++; 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') { // Empty lines delimit tests. if (start_line_ > 0) { @@ -372,12 +362,51 @@ 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) { - FileTest t(path); - if (!t.is_open()) { + std::unique_ptr<FileLineReader> reader(new FileLineReader(path)); + if (!reader->is_open()) { + fprintf(stderr, "Could not open file %s: %s.\n", path, strerror(errno)); return 1; } + FileTest t(std::move(reader)); bool failed = false; while (true) { FileTest::ReadResult ret = t.ReadNext();
diff --git a/crypto/test/file_test.h b/crypto/test/file_test.h index 1a52e26..2c03f90 100644 --- a/crypto/test/file_test.h +++ b/crypto/test/file_test.h
@@ -18,12 +18,12 @@ #include <openssl/base.h> #include <stdint.h> -#include <stdio.h> OPENSSL_MSVC_PRAGMA(warning(push)) OPENSSL_MSVC_PRAGMA(warning(disable : 4702)) #include <map> +#include <memory> #include <set> #include <string> #include <vector> @@ -86,18 +86,21 @@ class FileTest { 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 { kReadSuccess, kReadEOF, 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 // successfully reading a test and |kReadEOF| at the end of the file. On // error or if the previous test had unconsumed attributes, it returns @@ -168,7 +171,7 @@ void OnKeyUsed(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. unsigned line_ = 0;