// Copyright 2018 The Fuchsia Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "runtests-utils-test-globals.h" namespace runtests { static constexpr char kExpectedJSONOutputPrefix[] = "{\n \"tests\": [\n"; // We don't want to count the null terminator. static constexpr size_t kExpectedJSONOutputPrefixSize = sizeof(kExpectedJSONOutputPrefix) - 1; // Creates a script file with given contents in its constructor and deletes it // in its destructor. class ScopedScriptFile { public: // |path| is the path of the file to be created. Should start with // kMemFsPath. |contents| are the script contents. Shebang line will be // added automatically. ScopedScriptFile(const fbl::StringPiece path, const fbl::StringPiece contents); ~ScopedScriptFile(); fbl::StringPiece path() const; private: const fbl::StringPiece path_; }; // Creates a script file with given contents in its constructor and deletes it // in its destructor. class ScopedTestFile { public: // |path| is the path of the file to be created. Should start with kMemFsPath. // |contents| are the script contents. Shebang line will be added automatically. ScopedTestFile(const fbl::StringPiece path, const fbl::StringPiece file); ~ScopedTestFile(); fbl::StringPiece path() const; private: const fbl::StringPiece path_; }; // Creates a subdirectory of TestFsRoot() in its constructor and deletes it in // its destructor. class ScopedTestDir { public: ScopedTestDir() : basename_(NextBasename()), path_(JoinPath(TestFsRoot(), basename_)) { if (mkdir(path_.c_str(), 0755)) { printf("FAILURE: mkdir failed to open %s: %s\n", path_.c_str(), strerror(errno)); exit(1); } } ~ScopedTestDir() { CleanUpDir(path_.c_str()); } const char* basename() { return basename_.c_str(); } const char* path() { return path_.c_str(); } private: fbl::String NextBasename() { // More than big enough to print INT_MAX. char buf[64]; sprintf(buf, "%d", num_test_dirs_created_++); return fbl::String(buf); } // Recursively removes the directory at |dir_path| and its contents. static void CleanUpDir(const char* dir_path) { struct dirent* entry; DIR* dp; dp = opendir(dir_path); if (dp == nullptr) { // File found; remove it. remove(dir_path); return; } while ((entry = readdir(dp))) { // Skip "." and "..". if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) { continue; } fbl::String sub_dir_name = JoinPath(dir_path, entry->d_name); CleanUpDir(sub_dir_name.c_str()); } closedir(dp); // Directory is now empty: remove it. rmdir(dir_path); } const fbl::String basename_; const fbl::String path_; // Used to generate unique subdirectories of TestFsRoot(). static int num_test_dirs_created_; }; class TestStopwatch : public Stopwatch { public: void Start() override { start_called_ = true; } int64_t DurationInMsecs() override { BEGIN_HELPER; EXPECT_TRUE(start_called_); END_HELPER; return 14u; } private: bool start_called_ = false; }; // Returns the number of files or subdirectories in a given directory. int NumEntriesInDir(const char* dir_path); // Returns true if and only if the contents of |file| match |expected|. bool CompareFileContents(FILE* file, const char* expected); // Computes the relative path within |output_dir| of the output file of the // test at |test_path|, setting |output_file_rel_path| as its value if // successful. // Returns true iff successful. bool GetOutputFileRelPath(const fbl::StringPiece& output_dir, const fbl::StringPiece& test_path, fbl::String* output_file_rel_path); } // namespace runtests