Index: mojo/examples/apptest/example_apptest.cc |
diff --git a/mojo/examples/apptest/example_apptest.cc b/mojo/examples/apptest/example_apptest.cc |
index 7288608edb3692bad0325e6beaf1a8bf5689fdab..dba00e0f539d380ef916cf35767c46e9c1cf1113 100644 |
--- a/mojo/examples/apptest/example_apptest.cc |
+++ b/mojo/examples/apptest/example_apptest.cc |
@@ -18,32 +18,83 @@ |
#include "mojo/public/cpp/utility/run_loop.h" |
#include "testing/gtest/include/gtest/gtest.h" |
+namespace mojo { |
+ |
namespace { |
-// TODO(msw): Remove this once we can get ApplicationImpl from TLS. |
-mojo::ApplicationImpl* g_application_impl_hack = NULL; |
+// This global shell handle is needed for repeated use by test applications. |
+MessagePipeHandle g_shell_message_pipe_handle_hack; |
-} // namespace |
+// Apptest is a GTEST base class for application testing executed in mojo_shell. |
+class Apptest : public testing::Test { |
+ public: |
+ explicit Apptest(Array<String> args) |
+ : args_(args.Pass()), |
+ application_impl_(nullptr) { |
+ } |
+ virtual ~Apptest() override {} |
-namespace mojo { |
+ protected: |
+ ApplicationImpl* application_impl() { return application_impl_; } |
-namespace { |
+ // Get the ApplicationDelegate for the application to be tested. |
+ virtual ApplicationDelegate* GetApplicationDelegate() = 0; |
-class ExampleApptest : public testing::Test { |
- public: |
- ExampleApptest() { |
- g_application_impl_hack->ConnectToService("mojo:mojo_example_service", |
- &example_service_); |
- example_service_.set_client(&example_client_); |
+ // testing::Test: |
+ virtual void SetUp() override { |
+ // New applications are constructed for each test to avoid persisting state. |
+ MOJO_CHECK(g_shell_message_pipe_handle_hack.is_valid()); |
+ application_impl_ = new ApplicationImpl( |
+ GetApplicationDelegate(), |
+ MakeScopedHandle(g_shell_message_pipe_handle_hack)); |
+ |
+ // Fake application initialization with the given command line arguments. |
+ application_impl_->Initialize(args_.Clone()); |
} |
+ virtual void TearDown() override { |
+ g_shell_message_pipe_handle_hack = |
+ application_impl_->UnbindShell().release(); |
+ delete application_impl_; |
+ } |
+ |
+ private: |
+ // The command line arguments supplied to each test application instance. |
+ Array<String> args_; |
+ // The application implementation instance, reconstructed for each test. |
+ ApplicationImpl* application_impl_; |
+ |
+ // A run loop is needed for ApplicationImpl initialization and communication. |
+ RunLoop run_loop_; |
+ |
+ MOJO_DISALLOW_COPY_AND_ASSIGN(Apptest); |
+}; |
+ |
+// ExampleApptest exemplifies Apptest's application testing pattern. |
+class ExampleApptest : public Apptest { |
+ public: |
+ // TODO(msw): Exemplify the use of actual command line arguments. |
+ ExampleApptest() : Apptest(Array<String>()) {} |
virtual ~ExampleApptest() override {} |
protected: |
+ // Apptest: |
+ virtual ApplicationDelegate* GetApplicationDelegate() override { |
+ return &example_client_application_; |
+ } |
+ virtual void SetUp() override { |
+ Apptest::SetUp(); |
+ application_impl()->ConnectToService("mojo:mojo_example_service", |
+ &example_service_); |
+ example_service_.set_client(&example_client_); |
+ } |
+ |
ExampleServicePtr example_service_; |
ExampleClientImpl example_client_; |
private: |
+ ExampleClientApplication example_client_application_; |
+ |
MOJO_DISALLOW_COPY_AND_ASSIGN(ExampleApptest); |
}; |
@@ -64,9 +115,9 @@ TEST_F(ExampleApptest, PingServiceToPongClient) { |
} |
template <typename T> |
-struct SetAndQuit : public Callback<void()>::Runnable { |
- SetAndQuit(T* val, T result) : val_(val), result_(result) {} |
- virtual ~SetAndQuit() {} |
+struct SetCallback : public Callback<void()>::Runnable { |
+ SetCallback(T* val, T result) : val_(val), result_(result) {} |
+ virtual ~SetCallback() {} |
virtual void Run() const override { *val_ = result_; } |
T* val_; |
T result_; |
@@ -75,7 +126,7 @@ struct SetAndQuit : public Callback<void()>::Runnable { |
TEST_F(ExampleApptest, RunCallbackViaService) { |
// Test ExampleService callback functionality. |
bool was_run = false; |
- example_service_->RunCallback(SetAndQuit<bool>(&was_run, true)); |
+ example_service_->RunCallback(SetCallback<bool>(&was_run, true)); |
EXPECT_TRUE(example_service_.WaitForIncomingMethodCall()); |
EXPECT_TRUE(was_run); |
} |
@@ -85,18 +136,22 @@ TEST_F(ExampleApptest, RunCallbackViaService) { |
} // namespace mojo |
MojoResult MojoMain(MojoHandle shell_handle) { |
- mojo::Environment env; |
- // TODO(msw): Destroy this ambient RunLoop before running tests. |
- // Need to CancelWait() / PassMessagePipe() from the ShellPtr? |
- mojo::RunLoop loop; |
- mojo::ApplicationDelegate* delegate = new mojo::ExampleClientApplication(); |
- mojo::ApplicationImpl app(delegate, shell_handle); |
- g_application_impl_hack = &app; |
- MOJO_CHECK(app.WaitForInitialize()); |
+ mojo::Environment environment; |
{ |
+ // This RunLoop is used for init, and then destroyed before running tests. |
+ mojo::RunLoop run_loop; |
+ |
+ // Construct an ApplicationImpl just for the GTEST commandline arguments. |
+ // GTEST command line arguments are supported amid application arguments: |
+ // mojo_shell 'mojo:mojo_example_apptest arg1 --gtest_filter=foo arg2' |
+ mojo::ApplicationDelegate dummy_application_delegate; |
+ mojo::ApplicationImpl app(&dummy_application_delegate, shell_handle); |
+ MOJO_CHECK(app.WaitForInitialize()); |
+ |
// InitGoogleTest expects (argc + 1) elements, including a terminating NULL. |
// It also removes GTEST arguments from |argv| and updates the |argc| count. |
+ // TODO(msw): Provide tests access to these actual command line arguments. |
const std::vector<std::string>& args = app.args(); |
MOJO_CHECK(args.size() < INT_MAX); |
int argc = static_cast<int>(args.size()); |
@@ -105,10 +160,14 @@ MojoResult MojoMain(MojoHandle shell_handle) { |
argv[i] = const_cast<char*>(args[i].data()); |
argv[argc] = NULL; |
testing::InitGoogleTest(&argc, &argv[0]); |
+ mojo::g_shell_message_pipe_handle_hack = app.UnbindShell().release(); |
} |
mojo_ignore_result(RUN_ALL_TESTS()); |
- delete delegate; |
+ MojoResult result = MojoClose(mojo::g_shell_message_pipe_handle_hack.value()); |
+ MOJO_ALLOW_UNUSED_LOCAL(result); |
+ assert(result == MOJO_RESULT_OK); |
+ |
return MOJO_RESULT_OK; |
} |