blob: 4dcfe80401649b51b23a71f5166f7de4734a3b8d [file] [log] [blame]
Jorge Lucangeli Obes22388b92022-07-13 14:34:47 -04001/* unittest_util.h
Mike Frysinger4c331892022-09-13 05:17:08 -04002 * Copyright 2022 The ChromiumOS Authors
Jorge Lucangeli Obes22388b92022-07-13 14:34:47 -04003 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 *
6 * Utility functions for unit tests.
7 */
8
Christian Blichmann5fea38c2022-09-14 11:20:09 +02009#include <errno.h>
Jorge Lucangeli Obes22388b92022-07-13 14:34:47 -040010#include <ftw.h>
11#include <stdio.h>
12#include <stdlib.h>
13#include <unistd.h>
14
15#include "util.h"
16
17namespace {
18
19constexpr bool is_android_constexpr() {
20#if defined(__ANDROID__)
21 return true;
22#else
23 return false;
24#endif
25}
26
27// Returns a template path that can be used as an argument to mkstemp / mkdtemp.
28constexpr const char* temp_path_pattern() {
29 if (is_android_constexpr())
30 return "/data/local/tmp/minijail.tests.XXXXXX";
31 else
32 return "minijail.tests.XXXXXX";
33}
34
35// Recursively deletes the subtree rooted at |path|.
36bool rmdir_recursive(const std::string& path) {
37 auto callback = [](const char* child, const struct stat*, int file_type,
38 struct FTW*) -> int {
39 if (file_type == FTW_DP) {
40 if (rmdir(child) == -1) {
41 fprintf(stderr, "rmdir(%s): %s\n", child, strerror(errno));
42 return -1;
43 }
44 } else if (file_type == FTW_F) {
45 if (unlink(child) == -1) {
46 fprintf(stderr, "unlink(%s): %s\n", child, strerror(errno));
47 return -1;
48 }
49 }
50 return 0;
51 };
52
53 return nftw(path.c_str(), callback, 128, FTW_DEPTH) == 0;
54}
55
56} // namespace
57
58// Creates a temporary directory that will be cleaned up upon leaving scope.
59class TemporaryDir {
60 public:
61 TemporaryDir() : path(temp_path_pattern()) {
62 if (mkdtemp(const_cast<char*>(path.c_str())) == nullptr)
63 path.clear();
64 }
65 ~TemporaryDir() {
66 if (!is_valid())
67 return;
68 rmdir_recursive(path.c_str());
69 }
70
71 bool is_valid() const { return !path.empty(); }
72
73 std::string path;
74
75 private:
76 TemporaryDir(const TemporaryDir&) = delete;
77 TemporaryDir& operator=(const TemporaryDir&) = delete;
78};
79
80// Creates a named temporary file that will be cleaned up upon leaving scope.
81class TemporaryFile {
82 public:
83 TemporaryFile() : path(temp_path_pattern()) {
84 int fd = mkstemp(const_cast<char*>(path.c_str()));
85 if (fd == -1) {
86 path.clear();
87 return;
88 }
89 close(fd);
90 }
91 ~TemporaryFile() {
92 if (!is_valid())
93 return;
94 unlink(path.c_str());
95 }
96
97 bool is_valid() const { return !path.empty(); }
98
99 std::string path;
100
101 private:
102 TemporaryFile(const TemporaryFile&) = delete;
103 TemporaryFile& operator=(const TemporaryFile&) = delete;
104};