1 // Copyright 2018 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #pragma once 6 7 #include <dirent.h> 8 #include <errno.h> 9 #include <fcntl.h> 10 #include <limits.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <sys/stat.h> 14 #include <unistd.h> 15 16 #include <fbl/auto_call.h> 17 #include <fbl/string.h> 18 #include <fbl/string_buffer.h> 19 #include <fbl/unique_fd.h> 20 #include <fbl/unique_ptr.h> 21 #include <fbl/vector.h> 22 #include <runtests-utils/runtests-utils.h> 23 #include <unittest/unittest.h> 24 25 #include "runtests-utils-test-globals.h" 26 27 28 namespace runtests { 29 30 static constexpr char kExpectedJSONOutputPrefix[] = "{\n \"tests\": [\n"; 31 // We don't want to count the null terminator. 32 static constexpr size_t kExpectedJSONOutputPrefixSize = 33 sizeof(kExpectedJSONOutputPrefix) - 1; 34 35 // Creates a script file with given contents in its constructor and deletes it 36 // in its destructor. 37 class ScopedScriptFile { 38 39 public: 40 // |path| is the path of the file to be created. Should start with 41 // kMemFsPath. |contents| are the script contents. Shebang line will be 42 // added automatically. 43 ScopedScriptFile(const fbl::StringPiece path, 44 const fbl::StringPiece contents); 45 ~ScopedScriptFile(); 46 fbl::StringPiece path() const; 47 48 private: 49 const fbl::StringPiece path_; 50 }; 51 52 53 // Creates a script file with given contents in its constructor and deletes it 54 // in its destructor. 55 class ScopedTestFile { 56 57 public: 58 // |path| is the path of the file to be created. Should start with kMemFsPath. 59 // |contents| are the script contents. Shebang line will be added automatically. 60 ScopedTestFile(const fbl::StringPiece path, const fbl::StringPiece file); 61 ~ScopedTestFile(); 62 fbl::StringPiece path() const; 63 64 private: 65 const fbl::StringPiece path_; 66 }; 67 68 69 // Creates a subdirectory of TestFsRoot() in its constructor and deletes it in 70 // its destructor. 71 class ScopedTestDir { 72 73 public: ScopedTestDir()74 ScopedTestDir() 75 : basename_(NextBasename()), path_(JoinPath(TestFsRoot(), basename_)) { 76 if (mkdir(path_.c_str(), 0755)) { 77 printf("FAILURE: mkdir failed to open %s: %s\n", path_.c_str(), 78 strerror(errno)); 79 exit(1); 80 } 81 } ~ScopedTestDir()82 ~ScopedTestDir() { CleanUpDir(path_.c_str()); } basename()83 const char* basename() { return basename_.c_str(); } path()84 const char* path() { return path_.c_str(); } 85 86 private: NextBasename()87 fbl::String NextBasename() { 88 // More than big enough to print INT_MAX. 89 char buf[64]; 90 sprintf(buf, "%d", num_test_dirs_created_++); 91 return fbl::String(buf); 92 } 93 94 // Recursively removes the directory at |dir_path| and its contents. CleanUpDir(const char * dir_path)95 static void CleanUpDir(const char* dir_path) { 96 struct dirent* entry; 97 DIR* dp; 98 99 dp = opendir(dir_path); 100 if (dp == nullptr) { 101 // File found; remove it. 102 remove(dir_path); 103 return; 104 } 105 106 while ((entry = readdir(dp))) { 107 // Skip "." and "..". 108 if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) { 109 continue; 110 } 111 fbl::String sub_dir_name = JoinPath(dir_path, entry->d_name); 112 CleanUpDir(sub_dir_name.c_str()); 113 } 114 closedir(dp); 115 116 // Directory is now empty: remove it. 117 rmdir(dir_path); 118 } 119 120 const fbl::String basename_; 121 const fbl::String path_; 122 123 // Used to generate unique subdirectories of TestFsRoot(). 124 static int num_test_dirs_created_; 125 }; 126 127 128 class TestStopwatch : public Stopwatch { 129 public: Start()130 void Start() override { start_called_ = true; } DurationInMsecs()131 int64_t DurationInMsecs() override { 132 BEGIN_HELPER; 133 EXPECT_TRUE(start_called_); 134 END_HELPER; 135 return 14u; 136 } 137 138 private: 139 bool start_called_ = false; 140 }; 141 142 143 // Returns the number of files or subdirectories in a given directory. 144 int NumEntriesInDir(const char* dir_path); 145 146 // Returns true if and only if the contents of |file| match |expected|. 147 bool CompareFileContents(FILE* file, const char* expected); 148 149 // Computes the relative path within |output_dir| of the output file of the 150 // test at |test_path|, setting |output_file_rel_path| as its value if 151 // successful. 152 // Returns true iff successful. 153 bool GetOutputFileRelPath(const fbl::StringPiece& output_dir, 154 const fbl::StringPiece& test_path, 155 fbl::String* output_file_rel_path); 156 157 } // namespace runtests 158