diff --git a/crypto/test/file_test.cc b/crypto/test/file_test.cc index 21ae3e4e..87a6b96b 100644 --- a/crypto/test/file_test.cc +++ b/crypto/test/file_test.cc @@ -15,11 +15,13 @@ #include "file_test.h" #include -#include +#include +#include #include #include #include +#include #include #include @@ -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 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 @@ FileTest::ReadResult FileTest::ReadNext() { 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 @@ void FileTest::InjectInstruction(const std::string &key, 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 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 1a52e26e..2c03f903 100644 --- a/crypto/test/file_test.h +++ b/crypto/test/file_test.h @@ -18,12 +18,12 @@ #include #include -#include OPENSSL_MSVC_PRAGMA(warning(push)) OPENSSL_MSVC_PRAGMA(warning(disable : 4702)) #include +#include #include #include #include @@ -86,18 +86,21 @@ OPENSSL_MSVC_PRAGMA(warning(pop)) 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 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 @@ class FileTest { void OnKeyUsed(const std::string &key); void OnInstructionUsed(const std::string &key); - FILE *file_ = nullptr; + std::unique_ptr reader_; // line_ is the number of lines read. unsigned line_ = 0;