Merge lp:~tangent-org/libmemcached/1.0-build/ Build: jenkins-Libmemcached-192
[awesomized/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 _WIN32
40 typedef int posix_spawn_file_actions_t;
41 #else
42 # include <spawn.h>
43 #endif
44
45 #include <pthread.h>
46
47 // http://www.gnu.org/software/automake/manual/automake.html#Using-the-TAP-test-protocol
48 #ifndef EXIT_SKIP
49 # define EXIT_SKIP 77
50 #endif
51
52 #ifndef EXIT_FATAL
53 # define EXIT_FATAL 99
54 #endif
55
56 #ifndef EX_NOEXEC
57 # define EX_NOEXEC 126
58 #endif
59
60 #ifndef EX_NOTFOUND
61 # define EX_NOTFOUND 127
62 #endif
63
64 namespace libtest {
65
66 class Application {
67 private:
68 typedef std::vector< std::pair<std::string, std::string> > Options;
69
70 public:
71
72 enum error_t {
73 SUCCESS= EXIT_SUCCESS,
74 FAILURE= EXIT_FAILURE,
75 UNINITIALIZED,
76 SIGTERM_KILLED,
77 UNKNOWN,
78 UNKNOWN_SIGNAL,
79 INVALID_POSIX_SPAWN= 127
80 };
81
82 static const char* toString(error_t arg)
83 {
84 switch (arg)
85 {
86 case Application::SUCCESS:
87 return "EXIT_SUCCESS";
88
89 case Application::UNINITIALIZED:
90 return "UNINITIALIZED";
91
92 case Application::SIGTERM_KILLED:
93 return "Exit happened via SIGTERM";
94
95 case Application::FAILURE:
96 return "EXIT_FAILURE";
97
98 case Application::UNKNOWN_SIGNAL:
99 return "Exit happened via a signal which was not SIGTERM";
100
101 case Application::INVALID_POSIX_SPAWN:
102 return "127: Invalid call to posix_spawn()";
103
104 case Application::UNKNOWN:
105 default:
106 break;
107 }
108
109 return "EXIT_UNKNOWN";
110 }
111
112 class Pipe {
113 public:
114 Pipe(int);
115 ~Pipe();
116
117 int fd();
118
119 enum close_t {
120 READ= 0,
121 WRITE= 1
122 };
123
124 void reset();
125 void close(const close_t& arg);
126 void dup_for_spawn(posix_spawn_file_actions_t& file_actions);
127
128 void nonblock();
129 void cloexec();
130 bool read(libtest::vchar_t&);
131
132 private:
133 const int _std_fd;
134 int _pipe_fd[2];
135 bool _open[2];
136 };
137
138 public:
139 Application(const std::string& arg, const bool _use_libtool_arg= false);
140
141 virtual ~Application();
142
143 void add_option(const std::string&);
144 void add_option(const std::string&, const std::string&);
145 void add_long_option(const std::string& option_name, const std::string& option_value);
146 error_t run(const char *args[]= NULL);
147 Application::error_t join();
148
149 libtest::vchar_t stdout_result() const
150 {
151 return _stdout_buffer;
152 }
153
154 size_t stdout_result_length() const
155 {
156 return _stdout_buffer.size();
157 }
158
159 libtest::vchar_t stderr_result() const
160 {
161 return _stderr_buffer;
162 }
163
164 const char* stderr_c_str() const
165 {
166 return &_stderr_buffer[0];
167 }
168
169 size_t stderr_result_length() const
170 {
171 return _stderr_buffer.size();
172 }
173
174 std::string print();
175
176 void use_valgrind(bool arg)
177 {
178 _use_valgrind= arg;
179 }
180
181 bool check() const;
182
183 bool slurp();
184 void murder();
185
186 void use_gdb(bool arg)
187 {
188 _use_gdb= arg;
189 }
190
191 void use_ptrcheck(bool arg)
192 {
193 _use_ptrcheck= arg;
194 }
195
196 std::string arguments();
197
198 std::string gdb_filename()
199 {
200 return _gdb_filename;
201 }
202
203 pid_t pid() const
204 {
205 return _pid;
206 }
207
208 void will_fail()
209 {
210 _will_fail= true;
211 }
212
213 private:
214 void create_argv(const char *args[]);
215 void delete_argv();
216 void add_to_build_argv(const char*);
217
218 private:
219 const bool _use_libtool;
220 bool _use_valgrind;
221 bool _use_gdb;
222 bool _use_ptrcheck;
223 bool _will_fail;
224 size_t _argc;
225 std::string _exectuble_name;
226 std::string _exectuble;
227 std::string _exectuble_with_path;
228 std::string _gdb_filename;
229 Options _options;
230 Pipe stdin_fd;
231 Pipe stdout_fd;
232 Pipe stderr_fd;
233 libtest::vchar_ptr_t built_argv;
234 pid_t _pid;
235 libtest::vchar_t _stdout_buffer;
236 libtest::vchar_t _stderr_buffer;
237 int _status;
238 pthread_t _thread;
239 error_t _app_exit_state;
240 };
241
242 static inline std::ostream& operator<<(std::ostream& output, const enum Application::error_t &arg)
243 {
244 return output << Application::toString(arg);
245 }
246
247 int exec_cmdline(const std::string& executable, const char *args[], bool use_libtool= false);
248
249 const char *gearmand_binary();
250 const char *drizzled_binary();
251
252 }