OLD | NEW |
| (Empty) |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "mojo/public/cpp/application/application_test_base.h" | |
6 | |
7 #include <utility> | |
8 | |
9 #include "mojo/public/cpp/bindings/binding.h" | |
10 #include "mojo/public/cpp/environment/environment.h" | |
11 #include "mojo/public/cpp/system/message_pipe.h" | |
12 #include "mojo/public/interfaces/application/application.mojom.h" | |
13 | |
14 namespace mojo { | |
15 namespace test { | |
16 | |
17 namespace { | |
18 | |
19 // Share the application command-line arguments with multiple application tests. | |
20 Array<String> g_args; | |
21 | |
22 // Share the application URL with multiple application tests. | |
23 String g_url; | |
24 | |
25 // Application request handle passed from the shell in MojoMain, stored in | |
26 // between SetUp()/TearDown() so we can (re-)intialize new ApplicationImpls. | |
27 InterfaceRequest<Application> g_application_request; | |
28 | |
29 // Shell pointer passed in the initial mojo.Application.Initialize() call, | |
30 // stored in between initial setup and the first test and between SetUp/TearDown | |
31 // calls so we can (re-)initialize new ApplicationImpls. | |
32 ShellPtr g_shell; | |
33 | |
34 void InitializeArgs(int argc, const char** argv) { | |
35 MOJO_CHECK(g_args.is_null()); | |
36 for (int i = 0; i < argc; i++) { | |
37 MOJO_CHECK(argv[i]); | |
38 g_args.push_back(argv[i]); | |
39 } | |
40 } | |
41 | |
42 class ShellAndArgumentGrabber : public Application { | |
43 public: | |
44 ShellAndArgumentGrabber(Array<String>* args, | |
45 InterfaceRequest<Application> application_request) | |
46 : args_(args), binding_(this, application_request.Pass()) {} | |
47 | |
48 void WaitForInitialize() { | |
49 // Initialize is always the first call made on Application. | |
50 MOJO_CHECK(binding_.WaitForIncomingMethodCall()); | |
51 } | |
52 | |
53 private: | |
54 // Application implementation. | |
55 void Initialize(InterfaceHandle<Shell> shell, | |
56 Array<String> args, | |
57 const mojo::String& url) override { | |
58 *args_ = args.Pass(); | |
59 g_url = url; | |
60 g_application_request = binding_.Unbind(); | |
61 g_shell = ShellPtr::Create(std::move(shell)); | |
62 } | |
63 | |
64 void AcceptConnection(const String& requestor_url, | |
65 const String& url, | |
66 InterfaceRequest<ServiceProvider> services) override { | |
67 MOJO_CHECK(false); | |
68 } | |
69 | |
70 void RequestQuit() override { MOJO_CHECK(false); } | |
71 | |
72 Array<String>* args_; | |
73 Binding<Application> binding_; | |
74 }; | |
75 | |
76 } // namespace | |
77 | |
78 MojoResult RunAllTests(MojoHandle application_request_handle) { | |
79 { | |
80 // This loop is used for init, and then destroyed before running tests. | |
81 Environment::InstantiateDefaultRunLoop(); | |
82 | |
83 // Grab the shell handle and GTEST commandline arguments. | |
84 // GTEST command line arguments are supported amid application arguments: | |
85 // $ mojo_shell mojo:example_apptests | |
86 // --args-for='mojo:example_apptests arg1 --gtest_filter=foo arg2' | |
87 Array<String> args; | |
88 ShellAndArgumentGrabber grabber( | |
89 &args, InterfaceRequest<Application>(MakeScopedHandle( | |
90 MessagePipeHandle(application_request_handle)))); | |
91 grabber.WaitForInitialize(); | |
92 MOJO_CHECK(g_shell); | |
93 MOJO_CHECK(g_application_request.is_pending()); | |
94 | |
95 // InitGoogleTest expects (argc + 1) elements, including a terminating null. | |
96 // It also removes GTEST arguments from |argv| and updates the |argc| count. | |
97 MOJO_CHECK(args.size() < | |
98 static_cast<size_t>(std::numeric_limits<int>::max())); | |
99 // We'll put our URL in at |argv[0]| (|args| doesn't include a "command | |
100 // name"). | |
101 int argc = static_cast<int>(args.size()) + 1; | |
102 std::vector<const char*> argv(argc + 1); | |
103 argv[0] = g_url.get().c_str(); | |
104 for (size_t i = 0; i < args.size(); ++i) | |
105 argv[i + 1] = args[i].get().c_str(); | |
106 argv[argc] = nullptr; | |
107 | |
108 // Note: |InitGoogleTest()| will modify |argc| and |argv[...]|. | |
109 testing::InitGoogleTest(&argc, const_cast<char**>(&argv[0])); | |
110 InitializeArgs(argc, &argv[0]); | |
111 | |
112 Environment::DestroyDefaultRunLoop(); | |
113 } | |
114 | |
115 int result = RUN_ALL_TESTS(); | |
116 | |
117 // Shut down our message pipes before exiting. | |
118 (void)g_application_request.PassMessagePipe(); | |
119 (void)g_shell.PassInterfaceHandle(); | |
120 | |
121 return (result == 0) ? MOJO_RESULT_OK : MOJO_RESULT_UNKNOWN; | |
122 } | |
123 | |
124 ApplicationTestBase::ApplicationTestBase() {} | |
125 | |
126 ApplicationTestBase::~ApplicationTestBase() {} | |
127 | |
128 void ApplicationTestBase::SetUp() { | |
129 // A run loop is recommended for ApplicationImpl initialization and | |
130 // communication. | |
131 if (ShouldCreateDefaultRunLoop()) | |
132 Environment::InstantiateDefaultRunLoop(); | |
133 | |
134 MOJO_CHECK(g_application_request.is_pending()); | |
135 MOJO_CHECK(g_shell); | |
136 MOJO_CHECK(args_.empty()); | |
137 | |
138 shell_ = g_shell.Pass(); | |
139 for (size_t i = 0; i < g_args.size(); i++) | |
140 args_.push_back(g_args[i]); | |
141 } | |
142 | |
143 void ApplicationTestBase::TearDown() { | |
144 MOJO_CHECK(!g_shell); | |
145 | |
146 // TODO(vtl): The straightforward |g_shell = shell_.Pass();| causes tests to | |
147 // hang. Presumably, it's because there are still requests to the shell | |
148 // pending. :-( | |
149 g_shell.Bind(shell_.PassInterfaceHandle()); | |
150 args_.clear(); | |
151 | |
152 if (ShouldCreateDefaultRunLoop()) | |
153 Environment::DestroyDefaultRunLoop(); | |
154 } | |
155 | |
156 bool ApplicationTestBase::ShouldCreateDefaultRunLoop() { | |
157 return true; | |
158 } | |
159 | |
160 } // namespace test | |
161 } // namespace mojo | |
OLD | NEW |