Merge lp:~chasedouglas/xorg-gtest/fixes into lp:~oif-team/xorg-gtest/trunk
- fixes
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 3 |
Proposed branch: | lp:~chasedouglas/xorg-gtest/fixes |
Merge into: | lp:~oif-team/xorg-gtest/trunk |
Diff against target: |
595 lines (+377/-87) 8 files modified
Makefile.am (+10/-5) include/xorg/gtest/environment.h (+14/-5) include/xorg/gtest/process.h (+59/-0) include/xorg/gtest/test.h (+57/-0) src/environment.cpp (+53/-60) src/main.cpp (+37/-17) src/process.cpp (+98/-0) src/test.cpp (+49/-0) |
To merge this branch: | bzr merge lp:~chasedouglas/xorg-gtest/fixes |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Thomas Voß (community) | Approve | ||
Stephen M. Webb (community) | Approve | ||
Review via email: mp+84896@code.launchpad.net |
Commit message
Description of the change
A ton of fixes and changes. Highlights:
* Based on Thomas' process class branch
* Fix Process::Start() (variadic args weren't handled properly)
* Use exceptions instead of return codes where it makes sense
* Add server executable path option
* Add basic xorg::testing::Test fixture for opening a connection to the server
I have reworked my utouch-frame v2-tests branch on top of this API, and things seem to work well.
Chase Douglas (chasedouglas) wrote : | # |
> (1) "make install" doesn't install the headers.
It does here... Any ideas why it wasn't working on your system?
> (2) in xorg::testing:
> std::string, but std::string:
Fixed.
> (3) the error messages in xorg::testing:
> newlines.
Fixed.
> (4) xorg::testing:
> by using malloc() followed by a 'throw bad_alloc' on failure: argv at least
> should be a std::vector<char*>, eliminating all mallocs and reallocs.
Unfortunately, I can't find a version of exec* that takes an va_list. The two main versions are execl, which is variadic, and execv, which takes a typical argv list. There isn't a way to programatically call a variadic function, so that leaves us having to create an array.
While it would be nice if we could use std::vector, there's no method that provides a c-style array like std::string:
Any ideas on how to make this better?
> (5) can the pimpls be made std::unique_ptrs instead of using explicit deletes
> (this is not a big thing).
Fixed.
> (6) either a constructor should be added to
> xorg::testing:
> the initialization list in the xorg::testing:
> initializing Private members (it's bad form to initialize someone else's
> members). Same goes for xorg::testing:
The private members are POD structs. They don't have privacy, and they don't have methods. It seems overkill to make them full classes. And because these are just pimpls, it's not really the same as one normal class initializing another normal class' members.
Do you think we should make them full classes?
> (7) Why use the C-compatibility headers (eg. string.h, stdlib.h, errno.h)
> instead of the C++ headers (<cstring>, <cstdlib>, <cerrno>) if this is C++
> code? It's not broken, it's just a little inconsistent.
Fixed.
> But when all is said and done, this works well.
Great!
Chase Douglas (chasedouglas) wrote : | # |
> > (4) xorg::testing:
> operator
> > by using malloc() followed by a 'throw bad_alloc' on failure: argv at least
> > should be a std::vector<char*>, eliminating all mallocs and reallocs.
>
> Unfortunately, I can't find a version of exec* that takes an va_list. The two
> main versions are execl, which is variadic, and execv, which takes a typical
> argv list. There isn't a way to programatically call a variadic function, so
> that leaves us having to create an array.
>
> While it would be nice if we could use std::vector, there's no method that
> provides a c-style array like std::string:
> copy all the arrays into a std::vector, and then use the size of the
> std::vector to allocate the argv array. This seemed like a bunch of
> duplicitous effort, so I wrote a pure C version. I'm not sure which is better,
> but I don't think it makes sense to switch it from one annoying implementation
> to another.
>
> Any ideas on how to make this better?
I used something called Google and found someone stating that the the pointer to the first element in a vector should:
* Be stable until the array is reallocated
* Should act like an array (i.e. (&vector[0] + 1) == &vector[1])
Though I didn't double-check the C++ standard, these rules pass the sniff test. I rewrote the argument handling to take this into account. I also realized that the strings pointed to by the arguments should still be valid, so there's no real need for the strdup'ing I had in there. The code is much cleaner and compact now.
Stephen M. Webb (bregma) wrote : | # |
> The private members are POD structs. They don't have privacy, and they don't have methods. It seems overkill to make
> them full classes. And because these are just pimpls, it's not really the same as one normal class initializing
> another normal class' members.
xorg::testing:
I would still suggest adding an explicit constructor to that class just to initialize it members. It's not a sin to make it explicit.
xorg::testing:
The Process constructor would then become this.
xorg::testing:
}
Thomas Voß (thomas-voss) wrote : | # |
I do agree with Stephen's comments.
One minor remark: The file headers still hint to utouch-frame.
Thomas Voß (thomas-voss) wrote : | # |
> I do agree with Stephen's comments.
>
> One minor remark: The file headers still hint to utouch-frame.
Fixed in https:/
Chase Douglas (chasedouglas) wrote : | # |
> > The private members are POD structs. They don't have privacy, and they don't
> have methods. It seems overkill to make
> > them full classes. And because these are just pimpls, it's not really the
> same as one normal class initializing
> > another normal class' members.
>
> xorg::testing:
> (path_to_conf, path_to_server, and Process) that are not POD. The (default)
> constructor that's being used does not do the wrong thing, but you're almost
> always better off initializing members with the correct data on construction
> than to default-construct them and then immediately reset them with different
> data.
>
> I would still suggest adding an explicit constructor to that class just to
> initialize it members. It's not a sin to make it explicit.
Fixed.
> xorg::testing:
> be used so that it can be initialized in the Process initializer list.
> Uniform initialization syntax requires C++11 to be enabled in the compiler.
I don't want to make this depend on C++11 so that people wanting to test servers on old platforms are excluded. I've left it as is.
Stephen M. Webb (bregma) wrote : | # |
I think this is Good Enough.
Thomas Voß (thomas-voss) wrote : | # |
Looks good to me.
- 3. By Chase Douglas
-
Merge cleanup and fixes branch
Preview Diff
1 | === modified file 'Makefile.am' | |||
2 | --- Makefile.am 2011-12-06 00:25:36 +0000 | |||
3 | +++ Makefile.am 2011-12-09 21:07:24 +0000 | |||
4 | @@ -1,16 +1,21 @@ | |||
5 | 1 | lib_LTLIBRARIES = libxorg-gtest.la libxorg-gtest_main.la | 1 | lib_LTLIBRARIES = libxorg-gtest.la libxorg-gtest_main.la |
6 | 2 | 2 | ||
7 | 3 | libxorg_gtest_la_SOURCES = \ | 3 | libxorg_gtest_la_SOURCES = \ |
9 | 4 | src/environment.cpp | 4 | src/environment.cpp \ |
10 | 5 | src/process.cpp \ | ||
11 | 6 | src/test.cpp | ||
12 | 5 | 7 | ||
13 | 6 | libxorg_gtest_main_la_SOURCES = \ | 8 | libxorg_gtest_main_la_SOURCES = \ |
14 | 7 | src/main.cpp | 9 | src/main.cpp |
15 | 8 | 10 | ||
18 | 9 | library_includedir=$(includedir)/xorg/gtest | 11 | library_includedir = $(includedir)/xorg/gtest |
19 | 10 | library_include_HEADERS = include/xorg/gtest/environment.h | 12 | library_include_HEADERS = |
20 | 13 | include/xorg/gtest/environment.h \ | ||
21 | 14 | include/xorg/gtest/process.h \ | ||
22 | 15 | include/xorg/gtest/test.h | ||
23 | 11 | 16 | ||
26 | 12 | library_datadir=$(datadir)/xorg/gtest | 17 | library_datadir = $(datadir)/xorg/gtest |
27 | 13 | library_data_DATA=conf/dummy.conf | 18 | library_data_DATA = conf/dummy.conf |
28 | 14 | 19 | ||
29 | 15 | libxorg_gtest_main_la_CPPFLAGS = $(AM_CPPFLAGS) -DDUMMY_CONF_PATH="\"$(library_datadir)/dummy.conf\"" | 20 | libxorg_gtest_main_la_CPPFLAGS = $(AM_CPPFLAGS) -DDUMMY_CONF_PATH="\"$(library_datadir)/dummy.conf\"" |
30 | 16 | 21 | ||
31 | 17 | 22 | ||
32 | === modified file 'include/xorg/gtest/environment.h' | |||
33 | --- include/xorg/gtest/environment.h 2011-12-06 00:02:22 +0000 | |||
34 | +++ include/xorg/gtest/environment.h 2011-12-09 21:07:24 +0000 | |||
35 | @@ -18,7 +18,10 @@ | |||
36 | 18 | * with this program. If not, see <http://www.gnu.org/licenses/>. | 18 | * with this program. If not, see <http://www.gnu.org/licenses/>. |
37 | 19 | * | 19 | * |
38 | 20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
39 | 21 | #ifndef XORG_GTEST_ENVIRONMENT_H | ||
40 | 22 | #define XORG_GTEST_ENVIRONMENT_H | ||
41 | 21 | 23 | ||
42 | 24 | #include <memory> | ||
43 | 22 | #include <string> | 25 | #include <string> |
44 | 23 | 26 | ||
45 | 24 | #include <gtest/gtest.h> | 27 | #include <gtest/gtest.h> |
46 | @@ -31,19 +34,25 @@ | |||
47 | 31 | * | 34 | * |
48 | 32 | * Starts up a dummy Xorg server for testing purposes on | 35 | * Starts up a dummy Xorg server for testing purposes on |
49 | 33 | * display :133. Either associate the environment manually | 36 | * display :133. Either associate the environment manually |
51 | 34 | * with the overall testing framework or link to libxtestingenvironment_main.a. | 37 | * with the overall testing framework or link to libxorg-gtest_main. |
52 | 35 | */ | 38 | */ |
53 | 36 | class Environment : public ::testing::Environment { | 39 | class Environment : public ::testing::Environment { |
54 | 37 | public: | 40 | public: |
56 | 38 | Environment(const std::string& pathToConf, int display = 133); | 41 | Environment(const std::string& path_to_conf, |
57 | 42 | const std::string& path_to_server = "Xorg", int display = 133); | ||
58 | 39 | 43 | ||
59 | 40 | virtual void SetUp(); | 44 | virtual void SetUp(); |
60 | 41 | virtual void TearDown(); | 45 | virtual void TearDown(); |
61 | 42 | private: | 46 | private: |
65 | 43 | std::string path_to_conf_; | 47 | struct Private; |
66 | 44 | int display_; | 48 | std::auto_ptr<Private> d_; |
67 | 45 | pid_t child_pid_; | 49 | |
68 | 50 | /* Disable copy c'tor & assignment op. */ | ||
69 | 51 | Environment(const Environment&); | ||
70 | 52 | Environment& operator=(const Environment&); | ||
71 | 46 | }; | 53 | }; |
72 | 47 | 54 | ||
73 | 48 | } // namespace testing | 55 | } // namespace testing |
74 | 49 | } // namespace xorg | 56 | } // namespace xorg |
75 | 57 | |||
76 | 58 | #endif // XORG_GTEST_ENVIRONMENT_H | ||
77 | 50 | 59 | ||
78 | === added file 'include/xorg/gtest/process.h' | |||
79 | --- include/xorg/gtest/process.h 1970-01-01 00:00:00 +0000 | |||
80 | +++ include/xorg/gtest/process.h 2011-12-09 21:07:24 +0000 | |||
81 | @@ -0,0 +1,59 @@ | |||
82 | 1 | /***************************************************************************** | ||
83 | 2 | * | ||
84 | 3 | * utouch-frame - Touch Frame Library | ||
85 | 4 | * | ||
86 | 5 | * Copyright (C) 2011 Canonical Ltd. | ||
87 | 6 | * | ||
88 | 7 | * This program is free software: you can redistribute it and/or modify it | ||
89 | 8 | * under the terms of the GNU General Public License as published by the | ||
90 | 9 | * Free Software Foundation, either version 3 of the License, or (at your | ||
91 | 10 | * option) any later version. | ||
92 | 11 | * | ||
93 | 12 | * This program is distributed in the hope that it will be useful, but | ||
94 | 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
95 | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
96 | 15 | * General Public License for more details. | ||
97 | 16 | * | ||
98 | 17 | * You should have received a copy of the GNU General Public License along | ||
99 | 18 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
100 | 19 | * | ||
101 | 20 | ****************************************************************************/ | ||
102 | 21 | #ifndef XORG_GTEST_PROCESS_H | ||
103 | 22 | #define XORG_GTEST_PROCESS_H | ||
104 | 23 | |||
105 | 24 | #include <stdarg.h> | ||
106 | 25 | |||
107 | 26 | #include <memory> | ||
108 | 27 | #include <string> | ||
109 | 28 | |||
110 | 29 | namespace xorg { | ||
111 | 30 | namespace testing { | ||
112 | 31 | |||
113 | 32 | class Process { | ||
114 | 33 | public: | ||
115 | 34 | Process(); | ||
116 | 35 | |||
117 | 36 | void Start(const std::string& program, va_list args); | ||
118 | 37 | void Start(const std::string& program, ...); | ||
119 | 38 | |||
120 | 39 | bool Terminate(); | ||
121 | 40 | bool Kill(); | ||
122 | 41 | |||
123 | 42 | void SetEnv(const char* name, const char* value, bool overwrite); | ||
124 | 43 | const char * GetEnv(const char* name); | ||
125 | 44 | |||
126 | 45 | pid_t Pid() const; | ||
127 | 46 | |||
128 | 47 | private: | ||
129 | 48 | struct Private; | ||
130 | 49 | std::auto_ptr<Private> d_; | ||
131 | 50 | |||
132 | 51 | /* Disable copy c'tor, assignment operator */ | ||
133 | 52 | Process(const Process&); | ||
134 | 53 | Process& operator=(const Process&); | ||
135 | 54 | }; | ||
136 | 55 | |||
137 | 56 | } // xorg | ||
138 | 57 | } // testing | ||
139 | 58 | |||
140 | 59 | #endif // XORG_GTEST_PROCESS_H | ||
141 | 0 | 60 | ||
142 | === added file 'include/xorg/gtest/test.h' | |||
143 | --- include/xorg/gtest/test.h 1970-01-01 00:00:00 +0000 | |||
144 | +++ include/xorg/gtest/test.h 2011-12-09 21:07:24 +0000 | |||
145 | @@ -0,0 +1,57 @@ | |||
146 | 1 | /***************************************************************************** | ||
147 | 2 | * | ||
148 | 3 | * utouch-frame - Touch Frame Library | ||
149 | 4 | * | ||
150 | 5 | * Copyright (C) 2011 Canonical Ltd. | ||
151 | 6 | * | ||
152 | 7 | * This program is free software: you can redistribute it and/or modify it | ||
153 | 8 | * under the terms of the GNU General Public License as published by the | ||
154 | 9 | * Free Software Foundation, either version 3 of the License, or (at your | ||
155 | 10 | * option) any later version. | ||
156 | 11 | * | ||
157 | 12 | * This program is distributed in the hope that it will be useful, but | ||
158 | 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
159 | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
160 | 15 | * General Public License for more details. | ||
161 | 16 | * | ||
162 | 17 | * You should have received a copy of the GNU General Public License along | ||
163 | 18 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
164 | 19 | * | ||
165 | 20 | ****************************************************************************/ | ||
166 | 21 | |||
167 | 22 | #ifndef XORG_GTEST_TEST_H_ | ||
168 | 23 | #define XORG_GTEST_TEST_H_ | ||
169 | 24 | |||
170 | 25 | #include <memory> | ||
171 | 26 | |||
172 | 27 | #include <gtest/gtest.h> | ||
173 | 28 | #include <X11/Xlib.h> | ||
174 | 29 | |||
175 | 30 | #include "utouch/frame.h" | ||
176 | 31 | |||
177 | 32 | namespace xorg { | ||
178 | 33 | namespace testing { | ||
179 | 34 | |||
180 | 35 | class Test : public ::testing::Test { | ||
181 | 36 | public: | ||
182 | 37 | Test(); | ||
183 | 38 | |||
184 | 39 | virtual void SetUp(); | ||
185 | 40 | virtual void TearDown(); | ||
186 | 41 | |||
187 | 42 | protected: | ||
188 | 43 | ::Display* Display() const; | ||
189 | 44 | |||
190 | 45 | struct Private; | ||
191 | 46 | std::auto_ptr<Private> d_; | ||
192 | 47 | |||
193 | 48 | private: | ||
194 | 49 | /* Disable copy c'tor, assignment operator */ | ||
195 | 50 | Test(const Test&); | ||
196 | 51 | Test& operator=(const Test&); | ||
197 | 52 | }; | ||
198 | 53 | |||
199 | 54 | } // namespace testing | ||
200 | 55 | } // namespace xorg | ||
201 | 56 | |||
202 | 57 | #endif // XORG_GTEST_TEST_H_ | ||
203 | 0 | 58 | ||
204 | === modified file 'src/environment.cpp' | |||
205 | --- src/environment.cpp 2011-12-06 00:02:22 +0000 | |||
206 | +++ src/environment.cpp 2011-12-09 21:07:24 +0000 | |||
207 | @@ -20,84 +20,77 @@ | |||
208 | 20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
209 | 21 | 21 | ||
210 | 22 | #include "xorg/gtest/environment.h" | 22 | #include "xorg/gtest/environment.h" |
211 | 23 | #include "xorg/gtest/process.h" | ||
212 | 23 | 24 | ||
213 | 24 | #include <errno.h> | ||
214 | 25 | #include <signal.h> | ||
215 | 26 | #include <stdlib.h> | ||
216 | 27 | #include <sys/types.h> | 25 | #include <sys/types.h> |
217 | 28 | #include <unistd.h> | 26 | #include <unistd.h> |
218 | 29 | 27 | ||
219 | 28 | #include <cerrno> | ||
220 | 29 | #include <csignal> | ||
221 | 30 | #include <cstdlib> | ||
222 | 30 | #include <cstring> | 31 | #include <cstring> |
223 | 31 | #include <iostream> | 32 | #include <iostream> |
224 | 33 | #include <stdexcept> | ||
225 | 32 | 34 | ||
226 | 33 | #include <X11/Xlib.h> | 35 | #include <X11/Xlib.h> |
227 | 34 | 36 | ||
233 | 35 | xorg::testing::Environment::Environment(const std::string& path, int display) | 37 | struct xorg::testing::Environment::Private { |
234 | 36 | : path_to_conf_(path), | 38 | Private(const std::string& conf, const std::string& server, int display_num) |
235 | 37 | display_(display), | 39 | : path_to_conf(conf), path_to_server(server), display(display_num) { |
236 | 38 | child_pid_(-1) { | 40 | } |
237 | 39 | 41 | ||
238 | 42 | const std::string path_to_conf; | ||
239 | 43 | const std::string path_to_server; | ||
240 | 44 | const int display; | ||
241 | 45 | Process process; | ||
242 | 46 | }; | ||
243 | 47 | |||
244 | 48 | xorg::testing::Environment::Environment(const std::string& path_to_conf, | ||
245 | 49 | const std::string& path_to_server, | ||
246 | 50 | int display) | ||
247 | 51 | : d_(new Private(path_to_conf, path_to_server, display)) { | ||
248 | 40 | } | 52 | } |
249 | 41 | 53 | ||
250 | 42 | void xorg::testing::Environment::SetUp() { | 54 | void xorg::testing::Environment::SetUp() { |
251 | 43 | static char display_string[6]; | 55 | static char display_string[6]; |
295 | 44 | snprintf(display_string, 6, ":%d", display_); | 56 | snprintf(display_string, 6, ":%d", d_->display); |
296 | 45 | 57 | ||
297 | 46 | child_pid_ = vfork(); | 58 | d_->process.Start(d_->path_to_server, d_->path_to_server.c_str(), |
298 | 47 | if (child_pid_ == -1) { | 59 | display_string, "-config", d_->path_to_conf.c_str(), NULL); |
299 | 48 | FAIL() << "Failed to fork a process for dummy X server: " | 60 | |
300 | 49 | << std::strerror(errno); | 61 | setenv("DISPLAY", display_string, true); |
301 | 50 | } else if (!child_pid_) { /* Child */ | 62 | |
302 | 51 | close(0); | 63 | for (int i = 0; i < 10; ++i) { |
303 | 52 | close(1); | 64 | Display* display = XOpenDisplay(NULL); |
304 | 53 | close(2); | 65 | |
305 | 54 | 66 | if (display) { | |
306 | 55 | execlp("Xorg", "Xorg", display_string, "-config", path_to_conf_.c_str(), | 67 | XCloseDisplay(display); |
307 | 56 | NULL); | 68 | return; |
265 | 57 | perror("Failed to start dummy X server"); | ||
266 | 58 | exit(-1); | ||
267 | 59 | } else { /* Parent */ | ||
268 | 60 | setenv("DISPLAY", display_string, true); | ||
269 | 61 | |||
270 | 62 | for (int i = 0; i < 10; /*++i*/) { | ||
271 | 63 | Display* display = XOpenDisplay(NULL); | ||
272 | 64 | |||
273 | 65 | if (display) { | ||
274 | 66 | XCloseDisplay(display); | ||
275 | 67 | return; | ||
276 | 68 | } | ||
277 | 69 | |||
278 | 70 | int status; | ||
279 | 71 | int pid = waitpid(child_pid_, &status, WNOHANG); | ||
280 | 72 | if (pid == child_pid_) { | ||
281 | 73 | child_pid_ = -1; | ||
282 | 74 | FAIL() << "Dummy X server failed to start, did you run as root?"; | ||
283 | 75 | return; | ||
284 | 76 | } else if (pid == 0) { | ||
285 | 77 | sleep(1); /* Give the dummy X server some time to start */ | ||
286 | 78 | continue; | ||
287 | 79 | } else if (pid == -1) { | ||
288 | 80 | FAIL() << "Could not get status of dummy X server process: " | ||
289 | 81 | << std::strerror(errno); | ||
290 | 82 | return; | ||
291 | 83 | } else { | ||
292 | 84 | FAIL() << "Invalid child PID returned by waitpid()"; | ||
293 | 85 | return; | ||
294 | 86 | } | ||
308 | 87 | } | 69 | } |
309 | 88 | 70 | ||
311 | 89 | FAIL() << "Unable to open connection to dummy X server"; | 71 | int status; |
312 | 72 | int pid = waitpid(d_->process.Pid(), &status, WNOHANG); | ||
313 | 73 | if (pid == d_->process.Pid()) | ||
314 | 74 | throw std::runtime_error("Dummy X server failed to start, did you run as " | ||
315 | 75 | "root?"); | ||
316 | 76 | else if (pid == 0) | ||
317 | 77 | sleep(1); /* Give the dummy X server some time to start */ | ||
318 | 78 | else if (pid == -1) | ||
319 | 79 | throw std::runtime_error("Could not get status of dummy X server " | ||
320 | 80 | "process"); | ||
321 | 81 | else | ||
322 | 82 | throw std::runtime_error("Invalid child PID returned by Process::Wait()"); | ||
323 | 90 | } | 83 | } |
324 | 84 | |||
325 | 85 | throw std::runtime_error("Unable to open connection to dummy X server"); | ||
326 | 91 | } | 86 | } |
327 | 92 | 87 | ||
328 | 93 | void xorg::testing::Environment::TearDown() { | 88 | void xorg::testing::Environment::TearDown() { |
337 | 94 | if (child_pid_ && child_pid_ != -1) { | 89 | if (!d_->process.Terminate()) { |
338 | 95 | if (kill(child_pid_, SIGTERM) < 0) { | 90 | std::cerr << "Warning: Failed to terminate dummy Xorg server: " |
339 | 96 | FAIL() << "Warning: Failed to terminate dummy Xorg server: " | 91 | << std::strerror(errno) << "\n"; |
340 | 97 | << std::strerror(errno); | 92 | if (!d_->process.Kill()) |
341 | 98 | if (kill(child_pid_, SIGKILL)) | 93 | std::cerr << "Warning: Failed to kill dummy Xorg server: " |
342 | 99 | FAIL() << "Warning: Failed to kill dummy Xorg server: " | 94 | << std::strerror(errno) << "\n"; |
335 | 100 | << std::strerror(errno); | ||
336 | 101 | } | ||
343 | 102 | } | 95 | } |
344 | 103 | } | 96 | } |
345 | 104 | 97 | ||
346 | === modified file 'src/main.cpp' | |||
347 | --- src/main.cpp 2011-12-06 00:25:36 +0000 | |||
348 | +++ src/main.cpp 2011-12-09 21:07:24 +0000 | |||
349 | @@ -31,12 +31,14 @@ | |||
350 | 31 | int no_dummy_server = false; | 31 | int no_dummy_server = false; |
351 | 32 | int xorg_conf = false; | 32 | int xorg_conf = false; |
352 | 33 | int xorg_display_opt = false; | 33 | int xorg_display_opt = false; |
353 | 34 | int server = false; | ||
354 | 34 | 35 | ||
355 | 35 | const struct option longopts[] = { | 36 | const struct option longopts[] = { |
356 | 36 | { "help", no_argument, &help, true, }, | 37 | { "help", no_argument, &help, true, }, |
357 | 37 | { "no-dummy-server", no_argument, &no_dummy_server, true, }, | 38 | { "no-dummy-server", no_argument, &no_dummy_server, true, }, |
360 | 38 | { "xorg-conf", optional_argument, &xorg_conf, true, }, | 39 | { "xorg-conf", required_argument, &xorg_conf, true, }, |
361 | 39 | { "xorg-display", optional_argument, &xorg_display_opt, true, }, | 40 | { "xorg-display", required_argument, &xorg_display_opt, true, }, |
362 | 41 | { "server", required_argument, &server, true, }, | ||
363 | 40 | { NULL, 0, NULL, 0 } | 42 | { NULL, 0, NULL, 0 } |
364 | 41 | }; | 43 | }; |
365 | 42 | 44 | ||
366 | @@ -49,32 +51,49 @@ | |||
367 | 49 | /* Default X display */ | 51 | /* Default X display */ |
368 | 50 | int xorg_display = 133; | 52 | int xorg_display = 133; |
369 | 51 | 53 | ||
370 | 54 | /* Default Xorg executable */ | ||
371 | 55 | std::string server("Xorg"); | ||
372 | 56 | |||
373 | 52 | testing::InitGoogleTest(&argc, argv); | 57 | testing::InitGoogleTest(&argc, argv); |
374 | 53 | 58 | ||
375 | 54 | /* Reset getopt state */ | 59 | /* Reset getopt state */ |
376 | 55 | optind = 0; | 60 | optind = 0; |
377 | 56 | 61 | ||
393 | 57 | int ret; | 62 | while (true) { |
394 | 58 | do { | 63 | int ret; |
395 | 59 | ret = getopt_long(argc, argv, "", longopts, NULL); | 64 | int index; |
396 | 60 | 65 | ret = getopt_long(argc, argv, "", longopts, &index); | |
397 | 61 | if (xorg_conf) { | 66 | |
398 | 62 | xorg_conf_path = optarg; | 67 | if (ret == -1) |
399 | 63 | } | 68 | break; |
400 | 64 | 69 | ||
401 | 65 | if (xorg_display_opt) { | 70 | if (ret == '?') |
402 | 66 | xorg_display = atoi(optarg); | 71 | exit(-1); |
403 | 67 | } | 72 | |
404 | 68 | } while (ret == 0); | 73 | switch (index) { |
405 | 69 | 74 | case 2: | |
406 | 70 | if (ret != -1) | 75 | xorg_conf_path = optarg; |
407 | 71 | exit(-1); | 76 | break; |
408 | 77 | |||
409 | 78 | case 3: | ||
410 | 79 | xorg_display = atoi(optarg); | ||
411 | 80 | break; | ||
412 | 81 | |||
413 | 82 | case 4: | ||
414 | 83 | server = optarg; | ||
415 | 84 | break; | ||
416 | 85 | |||
417 | 86 | default: | ||
418 | 87 | break; | ||
419 | 88 | } | ||
420 | 89 | } | ||
421 | 72 | 90 | ||
422 | 73 | if (help) { | 91 | if (help) { |
423 | 74 | std::cout << "\nAdditional options:\n"; | 92 | std::cout << "\nAdditional options:\n"; |
424 | 75 | std::cout << " --no-dummy-server: Use the currently running X server " | 93 | std::cout << " --no-dummy-server: Use the currently running X server " |
425 | 76 | "for testing\n"; | 94 | "for testing\n"; |
426 | 77 | std::cout << " --xorg-conf: Path to xorg dummy configuration file\n"; | 95 | std::cout << " --xorg-conf: Path to xorg dummy configuration file\n"; |
427 | 96 | std::cout << " --server: Path to X server executable\n"; | ||
428 | 78 | std::cout << " --xorg-display: xorg dummy display port\n"; | 97 | std::cout << " --xorg-display: xorg dummy display port\n"; |
429 | 79 | exit(-1); | 98 | exit(-1); |
430 | 80 | } | 99 | } |
431 | @@ -82,6 +101,7 @@ | |||
432 | 82 | if (!no_dummy_server) { | 101 | if (!no_dummy_server) { |
433 | 83 | xorg::testing::Environment* environment = new xorg::testing::Environment( | 102 | xorg::testing::Environment* environment = new xorg::testing::Environment( |
434 | 84 | xorg_conf_path, | 103 | xorg_conf_path, |
435 | 104 | server, | ||
436 | 85 | xorg_display); | 105 | xorg_display); |
437 | 86 | testing::AddGlobalTestEnvironment(environment); | 106 | testing::AddGlobalTestEnvironment(environment); |
438 | 87 | } | 107 | } |
439 | 88 | 108 | ||
440 | === added file 'src/process.cpp' | |||
441 | --- src/process.cpp 1970-01-01 00:00:00 +0000 | |||
442 | +++ src/process.cpp 2011-12-09 21:07:24 +0000 | |||
443 | @@ -0,0 +1,98 @@ | |||
444 | 1 | #include "xorg/gtest/process.h" | ||
445 | 2 | |||
446 | 3 | #include <sys/types.h> | ||
447 | 4 | #include <sys/wait.h> | ||
448 | 5 | #include <unistd.h> | ||
449 | 6 | |||
450 | 7 | #include <algorithm> | ||
451 | 8 | #include <cerrno> | ||
452 | 9 | #include <csignal> | ||
453 | 10 | #include <cstdio> | ||
454 | 11 | #include <cstdlib> | ||
455 | 12 | #include <cstring> | ||
456 | 13 | #include <stdexcept> | ||
457 | 14 | #include <vector> | ||
458 | 15 | |||
459 | 16 | struct xorg::testing::Process::Private { | ||
460 | 17 | pid_t pid; | ||
461 | 18 | }; | ||
462 | 19 | |||
463 | 20 | xorg::testing::Process::Process() : d_(new Private) { | ||
464 | 21 | d_->pid = -1; | ||
465 | 22 | } | ||
466 | 23 | |||
467 | 24 | void xorg::testing::Process::Start(const std::string& program, va_list args) { | ||
468 | 25 | if (d_->pid != -1) | ||
469 | 26 | throw std::runtime_error("Attempting to start an already started process"); | ||
470 | 27 | |||
471 | 28 | d_->pid = vfork(); | ||
472 | 29 | |||
473 | 30 | if (d_->pid == -1) { | ||
474 | 31 | throw std::runtime_error("Failed to fork child process"); | ||
475 | 32 | } else if (d_->pid == 0) { /* Child */ | ||
476 | 33 | close(0); | ||
477 | 34 | close(1); | ||
478 | 35 | close(2); | ||
479 | 36 | |||
480 | 37 | std::vector<char*> argv; | ||
481 | 38 | |||
482 | 39 | do | ||
483 | 40 | argv.push_back(va_arg(args, char*)); | ||
484 | 41 | while (argv.back()); | ||
485 | 42 | |||
486 | 43 | execvp(program.c_str(), &argv[0]); | ||
487 | 44 | |||
488 | 45 | throw std::runtime_error("Failed to start process"); | ||
489 | 46 | } | ||
490 | 47 | } | ||
491 | 48 | |||
492 | 49 | void xorg::testing::Process::Start(const std::string& program, ...) { | ||
493 | 50 | va_list list; | ||
494 | 51 | va_start(list, program); | ||
495 | 52 | Start(program, list); | ||
496 | 53 | va_end(list); /* Shouldn't get here */ | ||
497 | 54 | } | ||
498 | 55 | |||
499 | 56 | bool xorg::testing::Process::Terminate() { | ||
500 | 57 | if (d_->pid == -1) { | ||
501 | 58 | return false; | ||
502 | 59 | } else if (d_->pid == 0) { | ||
503 | 60 | /* Child */ | ||
504 | 61 | throw std::runtime_error("Child process tried to terminate itself"); | ||
505 | 62 | } else { /* Parent */ | ||
506 | 63 | if (kill(d_->pid, SIGTERM) < 0) { | ||
507 | 64 | return false; | ||
508 | 65 | } | ||
509 | 66 | } | ||
510 | 67 | return true; | ||
511 | 68 | } | ||
512 | 69 | |||
513 | 70 | bool xorg::testing::Process::Kill() { | ||
514 | 71 | if (d_->pid == -1) { | ||
515 | 72 | return false; | ||
516 | 73 | } else if (d_->pid == 0) { | ||
517 | 74 | /* Child */ | ||
518 | 75 | throw std::runtime_error("Child process tried to kill itself"); | ||
519 | 76 | } else { /* Parent */ | ||
520 | 77 | if (kill(d_->pid, SIGKILL) < 0) { | ||
521 | 78 | return false; | ||
522 | 79 | } | ||
523 | 80 | } | ||
524 | 81 | return true; | ||
525 | 82 | } | ||
526 | 83 | |||
527 | 84 | void xorg::testing::Process::SetEnv(const char* name, const char* value, | ||
528 | 85 | bool overwrite) { | ||
529 | 86 | if (setenv(name, value, overwrite) != 0) | ||
530 | 87 | throw std::runtime_error("Failed to set environment variable in process"); | ||
531 | 88 | |||
532 | 89 | return; | ||
533 | 90 | } | ||
534 | 91 | |||
535 | 92 | const char* xorg::testing::Process::GetEnv(const char* name) { | ||
536 | 93 | return getenv(name); | ||
537 | 94 | } | ||
538 | 95 | |||
539 | 96 | pid_t xorg::testing::Process::Pid() const { | ||
540 | 97 | return d_->pid; | ||
541 | 98 | } | ||
542 | 0 | 99 | ||
543 | === added file 'src/test.cpp' | |||
544 | --- src/test.cpp 1970-01-01 00:00:00 +0000 | |||
545 | +++ src/test.cpp 2011-12-09 21:07:24 +0000 | |||
546 | @@ -0,0 +1,49 @@ | |||
547 | 1 | /***************************************************************************** | ||
548 | 2 | * | ||
549 | 3 | * utouch-frame - Touch Frame Library | ||
550 | 4 | * | ||
551 | 5 | * Copyright (C) 2011 Canonical Ltd. | ||
552 | 6 | * | ||
553 | 7 | * This program is free software: you can redistribute it and/or modify it | ||
554 | 8 | * under the terms of the GNU General Public License as published by the | ||
555 | 9 | * Free Software Foundation, either version 3 of the License, or (at your | ||
556 | 10 | * option) any later version. | ||
557 | 11 | * | ||
558 | 12 | * This program is distributed in the hope that it will be useful, but | ||
559 | 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
560 | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
561 | 15 | * General Public License for more details. | ||
562 | 16 | * | ||
563 | 17 | * You should have received a copy of the GNU General Public License along | ||
564 | 18 | * with this program. If not, see <http://www.gnu.org/licenses/>. | ||
565 | 19 | * | ||
566 | 20 | ****************************************************************************/ | ||
567 | 21 | |||
568 | 22 | #include "xorg/gtest/test.h" | ||
569 | 23 | |||
570 | 24 | #include <stdexcept> | ||
571 | 25 | |||
572 | 26 | #include <X11/Xlib.h> | ||
573 | 27 | |||
574 | 28 | struct xorg::testing::Test::Private { | ||
575 | 29 | ::Display* display; | ||
576 | 30 | }; | ||
577 | 31 | |||
578 | 32 | xorg::testing::Test::Test() : d_(new Private) { | ||
579 | 33 | d_->display = NULL; | ||
580 | 34 | } | ||
581 | 35 | |||
582 | 36 | void xorg::testing::Test::SetUp() { | ||
583 | 37 | d_->display = XOpenDisplay(NULL); | ||
584 | 38 | if (!d_->display) | ||
585 | 39 | throw std::runtime_error("Failed to open connection to display"); | ||
586 | 40 | } | ||
587 | 41 | |||
588 | 42 | void xorg::testing::Test::TearDown() { | ||
589 | 43 | XCloseDisplay(d_->display); | ||
590 | 44 | d_->display = NULL; | ||
591 | 45 | } | ||
592 | 46 | |||
593 | 47 | ::Display* xorg::testing::Test::Display() const { | ||
594 | 48 | return d_->display; | ||
595 | 49 | } |
(1) "make install" doesn't install the headers.
(2) in xorg::testing: :Environment: :SetUp( ), the first parameter is a std::string, but std::string: :c_str( ) is passed.
(3) the error messages in xorg::testing: :Environment: :TearDown( ) are missing newlines.
(4) xorg::testing: :Process: :Start( ) does a lot of simulating the new operator by using malloc() followed by a 'throw bad_alloc' on failure: argv at least should be a std::vector<char*>, eliminating all mallocs and reallocs.
(5) can the pimpls be made std::unique_ptrs instead of using explicit deletes (this is not a big thing).
(6) either a constructor should be added to xorg::testing: :Environment: :Private or a uniform initializer should be used in the initialization list in the xorg::testing: :Environment constructor when initializing Private members (it's bad form to initialize someone else's members). Same goes for xorg::testing: :Process: :Private.
(7) Why use the C-compatibility headers (eg. string.h, stdlib.h, errno.h) instead of the C++ headers (<cstring>, <cstdlib>, <cerrno>) if this is C++ code? It's not broken, it's just a little inconsistent.
But when all is said and done, this works well.