Merge lp:~chasedouglas/xorg-gtest/fixes into lp:~oif-team/xorg-gtest/trunk

Proposed by Chase Douglas
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
Reviewer Review Type Date Requested Status
Thomas Voß (community) Approve
Stephen M. Webb (community) Approve
Review via email: mp+84896@code.launchpad.net

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.

To post a comment you must log in.
Revision history for this message
Stephen M. Webb (bregma) wrote :

(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.

review: Needs Fixing
Revision history for this message
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::Environment::SetUp(), the first parameter is a
> std::string, but std::string::c_str() is passed.

Fixed.

> (3) the error messages in xorg::testing::Environment::TearDown() are missing
> newlines.

Fixed.

> (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.

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::data(). My first attempt was to 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?

> (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::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.

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!

Revision history for this message
Chase Douglas (chasedouglas) wrote :

> > (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.
>
> 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::data(). My first attempt was to
> 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.

Revision history for this message
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::Environment::Private is not a POD because it contains 3 members (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.

xorg::testing::Process::Private is a POD and uniform initialization syntax can 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.

The Process constructor would then become this.

xorg::testing::Process::Process() : d_(new Private{-1}) {
}

Revision history for this message
Thomas Voß (thomas-voss) wrote :

I do agree with Stephen's comments.

One minor remark: The file headers still hint to utouch-frame.

review: Needs Fixing
Revision history for this message
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://code.launchpad.net/~thomas-voss/xorg-gtest/Doxygen.

Revision history for this message
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::Environment::Private is not a POD because it contains 3 members
> (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::Process::Private is a POD and uniform initialization syntax can
> 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.

Revision history for this message
Stephen M. Webb (bregma) wrote :

I think this is Good Enough.

review: Approve
Revision history for this message
Thomas Voß (thomas-voss) wrote :

Looks good to me.

review: Approve
lp:~chasedouglas/xorg-gtest/fixes updated
3. By Chase Douglas

Merge cleanup and fixes branch

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'Makefile.am'
--- Makefile.am 2011-12-06 00:25:36 +0000
+++ Makefile.am 2011-12-09 21:07:24 +0000
@@ -1,16 +1,21 @@
1lib_LTLIBRARIES = libxorg-gtest.la libxorg-gtest_main.la1lib_LTLIBRARIES = libxorg-gtest.la libxorg-gtest_main.la
22
3libxorg_gtest_la_SOURCES = \3libxorg_gtest_la_SOURCES = \
4 src/environment.cpp4 src/environment.cpp \
5 src/process.cpp \
6 src/test.cpp
57
6libxorg_gtest_main_la_SOURCES = \8libxorg_gtest_main_la_SOURCES = \
7 src/main.cpp9 src/main.cpp
810
9library_includedir=$(includedir)/xorg/gtest11library_includedir = $(includedir)/xorg/gtest
10library_include_HEADERS = include/xorg/gtest/environment.h12library_include_HEADERS =
13 include/xorg/gtest/environment.h \
14 include/xorg/gtest/process.h \
15 include/xorg/gtest/test.h
1116
12library_datadir=$(datadir)/xorg/gtest17library_datadir = $(datadir)/xorg/gtest
13library_data_DATA=conf/dummy.conf18library_data_DATA = conf/dummy.conf
1419
15libxorg_gtest_main_la_CPPFLAGS = $(AM_CPPFLAGS) -DDUMMY_CONF_PATH="\"$(library_datadir)/dummy.conf\""20libxorg_gtest_main_la_CPPFLAGS = $(AM_CPPFLAGS) -DDUMMY_CONF_PATH="\"$(library_datadir)/dummy.conf\""
1621
1722
=== modified file 'include/xorg/gtest/environment.h'
--- include/xorg/gtest/environment.h 2011-12-06 00:02:22 +0000
+++ include/xorg/gtest/environment.h 2011-12-09 21:07:24 +0000
@@ -18,7 +18,10 @@
18 * with this program. If not, see <http://www.gnu.org/licenses/>.18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 *19 *
20 ****************************************************************************/20 ****************************************************************************/
21#ifndef XORG_GTEST_ENVIRONMENT_H
22#define XORG_GTEST_ENVIRONMENT_H
2123
24#include <memory>
22#include <string>25#include <string>
2326
24#include <gtest/gtest.h>27#include <gtest/gtest.h>
@@ -31,19 +34,25 @@
31 *34 *
32 * Starts up a dummy Xorg server for testing purposes on35 * Starts up a dummy Xorg server for testing purposes on
33 * display :133. Either associate the environment manually36 * display :133. Either associate the environment manually
34 * with the overall testing framework or link to libxtestingenvironment_main.a.37 * with the overall testing framework or link to libxorg-gtest_main.
35 */38 */
36class Environment : public ::testing::Environment {39class Environment : public ::testing::Environment {
37 public:40 public:
38 Environment(const std::string& pathToConf, int display = 133);41 Environment(const std::string& path_to_conf,
42 const std::string& path_to_server = "Xorg", int display = 133);
3943
40 virtual void SetUp();44 virtual void SetUp();
41 virtual void TearDown();45 virtual void TearDown();
42 private:46 private:
43 std::string path_to_conf_;47 struct Private;
44 int display_;48 std::auto_ptr<Private> d_;
45 pid_t child_pid_;49
50 /* Disable copy c'tor & assignment op. */
51 Environment(const Environment&);
52 Environment& operator=(const Environment&);
46};53};
4754
48} // namespace testing55} // namespace testing
49} // namespace xorg56} // namespace xorg
57
58#endif // XORG_GTEST_ENVIRONMENT_H
5059
=== added file 'include/xorg/gtest/process.h'
--- include/xorg/gtest/process.h 1970-01-01 00:00:00 +0000
+++ include/xorg/gtest/process.h 2011-12-09 21:07:24 +0000
@@ -0,0 +1,59 @@
1/*****************************************************************************
2 *
3 * utouch-frame - Touch Frame Library
4 *
5 * Copyright (C) 2011 Canonical Ltd.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 ****************************************************************************/
21#ifndef XORG_GTEST_PROCESS_H
22#define XORG_GTEST_PROCESS_H
23
24#include <stdarg.h>
25
26#include <memory>
27#include <string>
28
29namespace xorg {
30namespace testing {
31
32class Process {
33 public:
34 Process();
35
36 void Start(const std::string& program, va_list args);
37 void Start(const std::string& program, ...);
38
39 bool Terminate();
40 bool Kill();
41
42 void SetEnv(const char* name, const char* value, bool overwrite);
43 const char * GetEnv(const char* name);
44
45 pid_t Pid() const;
46
47 private:
48 struct Private;
49 std::auto_ptr<Private> d_;
50
51 /* Disable copy c'tor, assignment operator */
52 Process(const Process&);
53 Process& operator=(const Process&);
54};
55
56} // xorg
57} // testing
58
59#endif // XORG_GTEST_PROCESS_H
060
=== added file 'include/xorg/gtest/test.h'
--- include/xorg/gtest/test.h 1970-01-01 00:00:00 +0000
+++ include/xorg/gtest/test.h 2011-12-09 21:07:24 +0000
@@ -0,0 +1,57 @@
1/*****************************************************************************
2 *
3 * utouch-frame - Touch Frame Library
4 *
5 * Copyright (C) 2011 Canonical Ltd.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 ****************************************************************************/
21
22#ifndef XORG_GTEST_TEST_H_
23#define XORG_GTEST_TEST_H_
24
25#include <memory>
26
27#include <gtest/gtest.h>
28#include <X11/Xlib.h>
29
30#include "utouch/frame.h"
31
32namespace xorg {
33namespace testing {
34
35class Test : public ::testing::Test {
36 public:
37 Test();
38
39 virtual void SetUp();
40 virtual void TearDown();
41
42 protected:
43 ::Display* Display() const;
44
45 struct Private;
46 std::auto_ptr<Private> d_;
47
48 private:
49 /* Disable copy c'tor, assignment operator */
50 Test(const Test&);
51 Test& operator=(const Test&);
52};
53
54} // namespace testing
55} // namespace xorg
56
57#endif // XORG_GTEST_TEST_H_
058
=== modified file 'src/environment.cpp'
--- src/environment.cpp 2011-12-06 00:02:22 +0000
+++ src/environment.cpp 2011-12-09 21:07:24 +0000
@@ -20,84 +20,77 @@
20 ****************************************************************************/20 ****************************************************************************/
2121
22#include "xorg/gtest/environment.h"22#include "xorg/gtest/environment.h"
23#include "xorg/gtest/process.h"
2324
24#include <errno.h>
25#include <signal.h>
26#include <stdlib.h>
27#include <sys/types.h>25#include <sys/types.h>
28#include <unistd.h>26#include <unistd.h>
2927
28#include <cerrno>
29#include <csignal>
30#include <cstdlib>
30#include <cstring>31#include <cstring>
31#include <iostream>32#include <iostream>
33#include <stdexcept>
3234
33#include <X11/Xlib.h>35#include <X11/Xlib.h>
3436
35xorg::testing::Environment::Environment(const std::string& path, int display)37struct xorg::testing::Environment::Private {
36 : path_to_conf_(path),38 Private(const std::string& conf, const std::string& server, int display_num)
37 display_(display),39 : path_to_conf(conf), path_to_server(server), display(display_num) {
38 child_pid_(-1) {40 }
3941
42 const std::string path_to_conf;
43 const std::string path_to_server;
44 const int display;
45 Process process;
46};
47
48xorg::testing::Environment::Environment(const std::string& path_to_conf,
49 const std::string& path_to_server,
50 int display)
51 : d_(new Private(path_to_conf, path_to_server, display)) {
40}52}
4153
42void xorg::testing::Environment::SetUp() {54void xorg::testing::Environment::SetUp() {
43 static char display_string[6];55 static char display_string[6];
44 snprintf(display_string, 6, ":%d", display_);56 snprintf(display_string, 6, ":%d", d_->display);
4557
46 child_pid_ = vfork();58 d_->process.Start(d_->path_to_server, d_->path_to_server.c_str(),
47 if (child_pid_ == -1) {59 display_string, "-config", d_->path_to_conf.c_str(), NULL);
48 FAIL() << "Failed to fork a process for dummy X server: "60
49 << std::strerror(errno);61 setenv("DISPLAY", display_string, true);
50 } else if (!child_pid_) { /* Child */62
51 close(0);63 for (int i = 0; i < 10; ++i) {
52 close(1);64 Display* display = XOpenDisplay(NULL);
53 close(2);65
5466 if (display) {
55 execlp("Xorg", "Xorg", display_string, "-config", path_to_conf_.c_str(),67 XCloseDisplay(display);
56 NULL);68 return;
57 perror("Failed to start dummy X server");
58 exit(-1);
59 } else { /* Parent */
60 setenv("DISPLAY", display_string, true);
61
62 for (int i = 0; i < 10; /*++i*/) {
63 Display* display = XOpenDisplay(NULL);
64
65 if (display) {
66 XCloseDisplay(display);
67 return;
68 }
69
70 int status;
71 int pid = waitpid(child_pid_, &status, WNOHANG);
72 if (pid == child_pid_) {
73 child_pid_ = -1;
74 FAIL() << "Dummy X server failed to start, did you run as root?";
75 return;
76 } else if (pid == 0) {
77 sleep(1); /* Give the dummy X server some time to start */
78 continue;
79 } else if (pid == -1) {
80 FAIL() << "Could not get status of dummy X server process: "
81 << std::strerror(errno);
82 return;
83 } else {
84 FAIL() << "Invalid child PID returned by waitpid()";
85 return;
86 }
87 }69 }
8870
89 FAIL() << "Unable to open connection to dummy X server";71 int status;
72 int pid = waitpid(d_->process.Pid(), &status, WNOHANG);
73 if (pid == d_->process.Pid())
74 throw std::runtime_error("Dummy X server failed to start, did you run as "
75 "root?");
76 else if (pid == 0)
77 sleep(1); /* Give the dummy X server some time to start */
78 else if (pid == -1)
79 throw std::runtime_error("Could not get status of dummy X server "
80 "process");
81 else
82 throw std::runtime_error("Invalid child PID returned by Process::Wait()");
90 }83 }
84
85 throw std::runtime_error("Unable to open connection to dummy X server");
91}86}
9287
93void xorg::testing::Environment::TearDown() {88void xorg::testing::Environment::TearDown() {
94 if (child_pid_ && child_pid_ != -1) {89 if (!d_->process.Terminate()) {
95 if (kill(child_pid_, SIGTERM) < 0) {90 std::cerr << "Warning: Failed to terminate dummy Xorg server: "
96 FAIL() << "Warning: Failed to terminate dummy Xorg server: "91 << std::strerror(errno) << "\n";
97 << std::strerror(errno);92 if (!d_->process.Kill())
98 if (kill(child_pid_, SIGKILL))93 std::cerr << "Warning: Failed to kill dummy Xorg server: "
99 FAIL() << "Warning: Failed to kill dummy Xorg server: "94 << std::strerror(errno) << "\n";
100 << std::strerror(errno);
101 }
102 }95 }
103}96}
10497
=== modified file 'src/main.cpp'
--- src/main.cpp 2011-12-06 00:25:36 +0000
+++ src/main.cpp 2011-12-09 21:07:24 +0000
@@ -31,12 +31,14 @@
31int no_dummy_server = false;31int no_dummy_server = false;
32int xorg_conf = false;32int xorg_conf = false;
33int xorg_display_opt = false;33int xorg_display_opt = false;
34int server = false;
3435
35const struct option longopts[] = {36const struct option longopts[] = {
36 { "help", no_argument, &help, true, },37 { "help", no_argument, &help, true, },
37 { "no-dummy-server", no_argument, &no_dummy_server, true, },38 { "no-dummy-server", no_argument, &no_dummy_server, true, },
38 { "xorg-conf", optional_argument, &xorg_conf, true, },39 { "xorg-conf", required_argument, &xorg_conf, true, },
39 { "xorg-display", optional_argument, &xorg_display_opt, true, },40 { "xorg-display", required_argument, &xorg_display_opt, true, },
41 { "server", required_argument, &server, true, },
40 { NULL, 0, NULL, 0 }42 { NULL, 0, NULL, 0 }
41};43};
4244
@@ -49,32 +51,49 @@
49 /* Default X display */51 /* Default X display */
50 int xorg_display = 133;52 int xorg_display = 133;
5153
54 /* Default Xorg executable */
55 std::string server("Xorg");
56
52 testing::InitGoogleTest(&argc, argv);57 testing::InitGoogleTest(&argc, argv);
5358
54 /* Reset getopt state */59 /* Reset getopt state */
55 optind = 0;60 optind = 0;
5661
57 int ret;62 while (true) {
58 do {63 int ret;
59 ret = getopt_long(argc, argv, "", longopts, NULL);64 int index;
6065 ret = getopt_long(argc, argv, "", longopts, &index);
61 if (xorg_conf) {66
62 xorg_conf_path = optarg;67 if (ret == -1)
63 }68 break;
6469
65 if (xorg_display_opt) {70 if (ret == '?')
66 xorg_display = atoi(optarg);71 exit(-1);
67 }72
68 } while (ret == 0);73 switch (index) {
6974 case 2:
70 if (ret != -1)75 xorg_conf_path = optarg;
71 exit(-1);76 break;
77
78 case 3:
79 xorg_display = atoi(optarg);
80 break;
81
82 case 4:
83 server = optarg;
84 break;
85
86 default:
87 break;
88 }
89 }
7290
73 if (help) {91 if (help) {
74 std::cout << "\nAdditional options:\n";92 std::cout << "\nAdditional options:\n";
75 std::cout << " --no-dummy-server: Use the currently running X server "93 std::cout << " --no-dummy-server: Use the currently running X server "
76 "for testing\n";94 "for testing\n";
77 std::cout << " --xorg-conf: Path to xorg dummy configuration file\n";95 std::cout << " --xorg-conf: Path to xorg dummy configuration file\n";
96 std::cout << " --server: Path to X server executable\n";
78 std::cout << " --xorg-display: xorg dummy display port\n";97 std::cout << " --xorg-display: xorg dummy display port\n";
79 exit(-1);98 exit(-1);
80 }99 }
@@ -82,6 +101,7 @@
82 if (!no_dummy_server) {101 if (!no_dummy_server) {
83 xorg::testing::Environment* environment = new xorg::testing::Environment(102 xorg::testing::Environment* environment = new xorg::testing::Environment(
84 xorg_conf_path,103 xorg_conf_path,
104 server,
85 xorg_display);105 xorg_display);
86 testing::AddGlobalTestEnvironment(environment);106 testing::AddGlobalTestEnvironment(environment);
87 }107 }
88108
=== added file 'src/process.cpp'
--- src/process.cpp 1970-01-01 00:00:00 +0000
+++ src/process.cpp 2011-12-09 21:07:24 +0000
@@ -0,0 +1,98 @@
1#include "xorg/gtest/process.h"
2
3#include <sys/types.h>
4#include <sys/wait.h>
5#include <unistd.h>
6
7#include <algorithm>
8#include <cerrno>
9#include <csignal>
10#include <cstdio>
11#include <cstdlib>
12#include <cstring>
13#include <stdexcept>
14#include <vector>
15
16struct xorg::testing::Process::Private {
17 pid_t pid;
18};
19
20xorg::testing::Process::Process() : d_(new Private) {
21 d_->pid = -1;
22}
23
24void xorg::testing::Process::Start(const std::string& program, va_list args) {
25 if (d_->pid != -1)
26 throw std::runtime_error("Attempting to start an already started process");
27
28 d_->pid = vfork();
29
30 if (d_->pid == -1) {
31 throw std::runtime_error("Failed to fork child process");
32 } else if (d_->pid == 0) { /* Child */
33 close(0);
34 close(1);
35 close(2);
36
37 std::vector<char*> argv;
38
39 do
40 argv.push_back(va_arg(args, char*));
41 while (argv.back());
42
43 execvp(program.c_str(), &argv[0]);
44
45 throw std::runtime_error("Failed to start process");
46 }
47}
48
49void xorg::testing::Process::Start(const std::string& program, ...) {
50 va_list list;
51 va_start(list, program);
52 Start(program, list);
53 va_end(list); /* Shouldn't get here */
54}
55
56bool xorg::testing::Process::Terminate() {
57 if (d_->pid == -1) {
58 return false;
59 } else if (d_->pid == 0) {
60 /* Child */
61 throw std::runtime_error("Child process tried to terminate itself");
62 } else { /* Parent */
63 if (kill(d_->pid, SIGTERM) < 0) {
64 return false;
65 }
66 }
67 return true;
68}
69
70bool xorg::testing::Process::Kill() {
71 if (d_->pid == -1) {
72 return false;
73 } else if (d_->pid == 0) {
74 /* Child */
75 throw std::runtime_error("Child process tried to kill itself");
76 } else { /* Parent */
77 if (kill(d_->pid, SIGKILL) < 0) {
78 return false;
79 }
80 }
81 return true;
82}
83
84void xorg::testing::Process::SetEnv(const char* name, const char* value,
85 bool overwrite) {
86 if (setenv(name, value, overwrite) != 0)
87 throw std::runtime_error("Failed to set environment variable in process");
88
89 return;
90}
91
92const char* xorg::testing::Process::GetEnv(const char* name) {
93 return getenv(name);
94}
95
96pid_t xorg::testing::Process::Pid() const {
97 return d_->pid;
98}
099
=== added file 'src/test.cpp'
--- src/test.cpp 1970-01-01 00:00:00 +0000
+++ src/test.cpp 2011-12-09 21:07:24 +0000
@@ -0,0 +1,49 @@
1/*****************************************************************************
2 *
3 * utouch-frame - Touch Frame Library
4 *
5 * Copyright (C) 2011 Canonical Ltd.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 ****************************************************************************/
21
22#include "xorg/gtest/test.h"
23
24#include <stdexcept>
25
26#include <X11/Xlib.h>
27
28struct xorg::testing::Test::Private {
29 ::Display* display;
30};
31
32xorg::testing::Test::Test() : d_(new Private) {
33 d_->display = NULL;
34}
35
36void xorg::testing::Test::SetUp() {
37 d_->display = XOpenDisplay(NULL);
38 if (!d_->display)
39 throw std::runtime_error("Failed to open connection to display");
40}
41
42void xorg::testing::Test::TearDown() {
43 XCloseDisplay(d_->display);
44 d_->display = NULL;
45}
46
47::Display* xorg::testing::Test::Display() const {
48 return d_->display;
49}

Subscribers

People subscribed via source and target branches