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