5 // Created by Chris Suter on 8/11/15.
9 #include <Foundation/Foundation.h>
10 #include <unordered_map>
20 #include <mach-o/dyld.h>
21 #include <sys/param.h>
23 #include "hfs-tests.h"
24 #include "test-utils.h"
25 #include "disk-image.h"
28 #define INSTALL_PATH "/AppleInternal/CoreOS/tests/hfs/hfs-tests"
30 typedef std::unordered_map<std::string, test_t *> tests_t;
31 static tests_t *tests;
33 static std::list<bool (^)(void)> cleanups;
35 int test_cleanup(bool (^ cleanup)(void))
37 cleanups.push_front(cleanup);
41 void do_cleanups(void)
45 while (progress || (attempts < 2)) {
46 size_t i, sz = cleanups.size();
49 for (i = 0; i < sz; i++) {
50 bool (^cleanup)(void) = cleanups.front();
52 if (cleanup() == false)
53 cleanups.push_back(cleanup);
61 attempts = 0; // reset
65 void register_test(test_t *test)
70 tests->insert({ test->name, test });
75 printf("hfs-tests [--test <test>|--plist] <list|run>\n");
79 static int run_test(test_t *test)
86 std::cout << "[TEST] " << test->name << std::endl
87 << "[BEGIN]" << std::endl;
89 std::flush(std::cout);
91 if (test->run_as_root && geteuid() != 0 && seteuid(0) != 0) {
92 std::cout << "error: " << test->name
93 << ": needs to run as root!" << std::endl;
96 if (!test->run_as_root && geteuid() == 0)
98 ret = test->test_fn(&ctx);
106 int main(int argc, char *argv[])
112 const char *test = NULL;
113 bool plist = false, nospawn = false;
116 static struct option longopts[] = {
117 { "test", required_argument, NULL, 't' },
118 { "plist", no_argument, NULL, 'p' },
119 { "no-spawn", no_argument, NULL, 'n' }, // private
123 while ((ch = getopt_long(argc, argv, "bf:", longopts, NULL)) != -1) {
139 char progname[MAXPATHLEN];
140 uint32_t sz = MAXPATHLEN;
141 assert(!_NSGetExecutablePath(progname, &sz));
151 if (!strcmp(argv[0], "list")) {
153 NSMutableArray *cases = [NSMutableArray new];
155 for (auto it = tests->begin(); it != tests->end(); ++it) {
156 NSMutableDictionary *test_case = [@{
157 @"TestName": @(it->first.c_str()),
158 @"Command": @[ @INSTALL_PATH, @"--test",
159 @(it->first.c_str()), @"run"]
162 test_case[@"AsRoot"] = (id)kCFBooleanTrue;
164 [cases addObject:test_case];
168 << (char *)[[NSPropertyListSerialization
169 dataWithPropertyList:@{
173 format:NSPropertyListXMLFormat_v1_0
175 error:NULL] bytes] << std::endl;
177 for (auto it = tests->begin(); it != tests->end(); ++it) {
178 std::cout << it->first << std::endl;
181 } else if (!strcmp(argv[0], "run")) {
182 disk_image_t *di = NULL;
185 // Set up the shared disk image
186 assert(!systemx("/bin/rm", SYSTEMX_QUIET, "-rf", SHARED_MOUNT, NULL));
187 di = disk_image_get();
192 for (auto it = tests->begin(); it != tests->end(); ++it) {
193 test_t *test = it->second;
195 int res = systemx(progname, "--test", test->name, "--no-spawn", "run", NULL);
198 std::cout << "[FAIL] " << test->name << std::endl;
200 std::cout << "[PASS] " << test->name << std::endl;
206 auto it = tests->find(test);
207 if (it == tests->end()) {
208 std::cout << "unknown test: " << test << std::endl;
215 ret = run_test(it->second);
218 test_t *test = it->second;
220 ret = systemx(progname, "--test", test->name, "--no-spawn", "run", NULL);
223 std::cout << "[FAIL] " << test->name << std::endl;
225 std::cout << "[PASS] " << test->name << std::endl;
231 // disk_image_cleanup(di) will free di.
232 disk_image_cleanup(di);
233 systemx("/bin/rm", SYSTEMX_QUIET, "-rf", "/tmp/mnt", NULL);