Clean up fuzz test source
[oweals/dinit.git] / src / tests / test-bpsys.cc
1 #include <vector>
2 #include <utility>
3 #include <algorithm>
4 #include <map>
5
6 #include <cstdlib>
7 #include <cerrno>
8
9 #include "baseproc-sys.h"
10
11 namespace {
12
13 std::vector<bool> usedfds = {true, true, true};
14
15 struct read_result
16 {
17         read_result(int errcode_p) : errcode(errcode_p) {}
18
19         read_result(std::vector<char> &data_p) : errcode(0), data(data_p) {}
20         read_result(std::vector<char> &&data_p) : errcode(0), data(std::move(data_p)) {}
21
22         int errcode; // errno return
23         std::vector<char> data;  // data (if errcode == 0)
24 };
25
26 class read_cond : public std::vector<read_result>
27 {
28     public:
29     using vector<read_result>::vector;
30
31     // if blocking, return EAGAIN rather than end-of-file:
32     bool is_blocking = false;
33 };
34
35 // map of fd to read results to supply for reads of that fd
36 std::map<int,read_cond> read_data;
37
38 // map of data written to each fd
39 std::map<int,std::vector<char>> written_data;
40
41 } // anon namespace
42
43 namespace bp_sys {
44
45 int last_sig_sent = -1; // last signal number sent, accessible for tests.
46 pid_t last_forked_pid = 1;  // last forked process id (incremented each 'fork')
47
48 // Test helper methods:
49
50 // Allocate a file descriptor
51 int allocfd()
52 {
53     auto f = std::find(usedfds.begin(), usedfds.end(), false);
54     if (f == usedfds.end()) {
55         int r = usedfds.size();
56         usedfds.push_back(true);
57         return r;
58     }
59
60     *f = true;
61     return f - usedfds.begin();
62 }
63
64 // Supply data to be returned by read()
65 void supply_read_data(int fd, std::vector<char> &data)
66 {
67         read_data[fd].emplace_back(data);
68 }
69
70 void supply_read_data(int fd, std::vector<char> &&data)
71 {
72         read_data[fd].emplace_back(std::move(data));
73 }
74
75 void set_blocking(int fd)
76 {
77     read_data[fd].is_blocking = true;
78 }
79
80 // retrieve data written via write()
81 void extract_written_data(int fd, std::vector<char> &data)
82 {
83         data = std::move(written_data[fd]);
84 }
85
86
87 // Mock implementations of system calls:
88
89 int pipe2(int fds[2], int flags)
90 {
91     fds[0] = allocfd();
92     fds[1] = allocfd();
93     return 0;
94 }
95
96 int close(int fd)
97 {
98     if (size_t(fd) >= usedfds.size()) abort();
99
100     usedfds[fd] = false;
101     return 0;
102 }
103
104 int kill(pid_t pid, int sig)
105 {
106     last_sig_sent = sig;
107     return 0;
108 }
109
110 ssize_t read(int fd, void *buf, size_t count)
111 {
112         read_cond & rrs = read_data[fd];
113         if (rrs.empty()) {
114             if (rrs.is_blocking) {
115                 errno = EAGAIN;
116                 return -1;
117             }
118                 return 0;
119         }
120
121         read_result &rr = rrs.front();
122         if (rr.errcode != 0) {
123                 errno = rr.errcode;
124                 // Remove the result record:
125                 auto i = rrs.begin();
126                 i++;
127                 rrs.erase(rrs.begin(), i);
128                 return -1;
129         }
130
131         auto dsize = rr.data.size();
132         if (dsize <= count) {
133                 // Consume entire result:
134                 std::copy_n(rr.data.begin(), dsize, (char *)buf);
135                 // Remove the result record:
136                 rrs.erase(rrs.begin());
137                 return dsize;
138         }
139
140         // Consume partial result:
141         std::copy_n(rr.data.begin(), count, (char *)buf);
142         rr.data.erase(rr.data.begin(), rr.data.begin() + count);
143         return count;
144 }
145
146 ssize_t write(int fd, const void *buf, size_t count)
147 {
148         std::vector<char> &wd = written_data[fd];
149         wd.insert(wd.end(), (char *)buf, (char *)buf + count);
150         return count;
151 }
152
153 }