ca7098dd722343823e223cb932f6dbdead0615c5
[m6w6/libmemcached] / libtest / cmdline.h
1 /* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
2 *
3 * Data Differential YATL (i.e. libtest) library
4 *
5 * Copyright (C) 2012 Data Differential, http://datadifferential.com/
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are
9 * met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following disclaimer
16 * in the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * * The names of its contributors may not be used to endorse or
20 * promote products derived from this software without specific prior
21 * written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 *
35 */
36
37 #pragma once
38
39 #ifdef HAVE_SPAWN_H
40 # include <spawn.h>
41 #endif
42
43 /*
44 http://www.gnu.org/software/automake/manual/automake.html#Tests
45 When no test protocol is in use, an exit status of 0 from a test script will denote a success, an exit status of 77 a skipped test, an exit status of 99 an hard error, and any other exit status will denote a failure.
46 */
47
48 #define EXIT_SKIP 77
49 #define EXIT_FATAL 99
50
51 #ifndef EX_NOEXEC
52 # define EX_NOEXEC 126
53 #endif
54
55 #ifndef EX_NOTFOUND
56 # define EX_NOTFOUND 127
57 #endif
58
59 namespace libtest {
60
61 class Application {
62 private:
63 typedef std::vector< std::pair<std::string, std::string> > Options;
64
65 public:
66
67 enum error_t {
68 SUCCESS= EXIT_SUCCESS,
69 FAILURE= EXIT_FAILURE,
70 UNINITIALIZED,
71 SIGTERM_KILLED,
72 UNKNOWN,
73 UNKNOWN_SIGNAL,
74 INVALID_POSIX_SPAWN= 127
75 };
76
77 static const char* toString(error_t arg)
78 {
79 switch (arg)
80 {
81 case Application::SUCCESS:
82 return "EXIT_SUCCESS";
83
84 case Application::UNINITIALIZED:
85 return "UNINITIALIZED";
86
87 case Application::SIGTERM_KILLED:
88 return "Exit happened via SIGTERM";
89
90 case Application::FAILURE:
91 return "EXIT_FAILURE";
92
93 case Application::UNKNOWN_SIGNAL:
94 return "Exit happened via a signal which was not SIGTERM";
95
96 case Application::INVALID_POSIX_SPAWN:
97 return "127: Invalid call to posix_spawn()";
98
99 case Application::UNKNOWN:
100 default:
101 break;
102 }
103
104 return "EXIT_UNKNOWN";
105 }
106
107 class Pipe {
108 public:
109 Pipe(int);
110 ~Pipe();
111
112 int fd();
113
114 enum close_t {
115 READ= 0,
116 WRITE= 1
117 };
118
119 void reset();
120 void close(const close_t& arg);
121 void dup_for_spawn(posix_spawn_file_actions_t& file_actions);
122
123 void nonblock();
124 void cloexec();
125 bool read(libtest::vchar_t&);
126
127 private:
128 const int _std_fd;
129 int _pipe_fd[2];
130 bool _open[2];
131 };
132
133 public:
134 Application(const std::string& arg, const bool _use_libtool_arg= false);
135
136 virtual ~Application();
137
138 void add_option(const std::string&);
139 void add_option(const std::string&, const std::string&);
140 void add_long_option(const std::string& option_name, const std::string& option_value);
141 error_t run(const char *args[]= NULL);
142 Application::error_t join();
143
144 libtest::vchar_t stdout_result() const
145 {
146 return _stdout_buffer;
147 }
148
149 size_t stdout_result_length() const
150 {
151 return _stdout_buffer.size();
152 }
153
154 libtest::vchar_t stderr_result() const
155 {
156 return _stderr_buffer;
157 }
158
159 const char* stderr_c_str() const
160 {
161 return &_stderr_buffer[0];
162 }
163
164 size_t stderr_result_length() const
165 {
166 return _stderr_buffer.size();
167 }
168
169 std::string print();
170
171 void use_valgrind(bool arg= true)
172 {
173 _use_valgrind= arg;
174 }
175
176 bool check() const;
177
178 bool slurp();
179 void murder();
180
181 void use_gdb(bool arg= true)
182 {
183 _use_gdb= arg;
184 }
185
186 void use_ptrcheck(bool arg= true)
187 {
188 _use_ptrcheck= arg;
189 }
190
191 std::string arguments();
192
193 std::string gdb_filename()
194 {
195 return _gdb_filename;
196 }
197
198 pid_t pid() const
199 {
200 return _pid;
201 }
202
203 void will_fail()
204 {
205 _will_fail= true;
206 }
207
208 private:
209 void create_argv(const char *args[]);
210 void delete_argv();
211
212 private:
213 const bool _use_libtool;
214 bool _use_valgrind;
215 bool _use_gdb;
216 bool _use_ptrcheck;
217 bool _will_fail;
218 size_t _argc;
219 std::string _exectuble_name;
220 std::string _exectuble;
221 std::string _exectuble_with_path;
222 std::string _gdb_filename;
223 Options _options;
224 Pipe stdin_fd;
225 Pipe stdout_fd;
226 Pipe stderr_fd;
227 libtest::vchar_ptr_t built_argv;
228 pid_t _pid;
229 libtest::vchar_t _stdout_buffer;
230 libtest::vchar_t _stderr_buffer;
231 int _status;
232 pthread_t _thread;
233 error_t _app_exit_state;
234 };
235
236 static inline std::ostream& operator<<(std::ostream& output, const enum Application::error_t &arg)
237 {
238 return output << Application::toString(arg);
239 }
240
241 int exec_cmdline(const std::string& executable, const char *args[], bool use_libtool= false);
242
243 const char *gearmand_binary();
244 const char *drizzled_binary();
245
246 }