| Index: ppapi/tests/test_case.h
|
| diff --git a/ppapi/tests/test_case.h b/ppapi/tests/test_case.h
|
| index 297308489f58441da361e1dd3081ee4fb3c624c6..2cf2ddf42183e1388ba5ff12aca58d5b72f7f6b7 100644
|
| --- a/ppapi/tests/test_case.h
|
| +++ b/ppapi/tests/test_case.h
|
| @@ -12,9 +12,11 @@
|
|
|
| #include "ppapi/c/pp_resource.h"
|
| #include "ppapi/c/dev/ppb_testing_dev.h"
|
| +#include "ppapi/cpp/dev/message_loop_dev.h"
|
| #include "ppapi/cpp/dev/scrollbar_dev.h"
|
| #include "ppapi/cpp/view.h"
|
| #include "ppapi/tests/test_utils.h"
|
| +#include "ppapi/tests/testing_instance.h"
|
|
|
| #if (defined __native_client__)
|
| #include "ppapi/cpp/var.h"
|
| @@ -78,6 +80,8 @@ class TestCase {
|
|
|
| const PPB_Testing_Dev* testing_interface() { return testing_interface_; }
|
|
|
| + static void QuitMainMessageLoop(PP_Instance instance);
|
| +
|
| protected:
|
| #if !(defined __native_client__)
|
| // Overridden by each test to supply a ScriptableObject corresponding to the
|
| @@ -104,12 +108,37 @@ class TestCase {
|
| // Check for leaked resources and vars at the end of the test. If any exist,
|
| // return a string with some information about the error. Otherwise, return
|
| // an empty string.
|
| - std::string CheckResourcesAndVars();
|
| + //
|
| + // You should pass the error string from the test so far; if it is non-empty,
|
| + // CheckResourcesAndVars will do nothing and return the same string.
|
| + std::string CheckResourcesAndVars(std::string errors);
|
| +
|
| + // Run the given test method on a background thread and return the result.
|
| + template <class T>
|
| + std::string RunOnThread(std::string(T::*test_to_run)()) {
|
| +#ifdef ENABLE_PEPPER_THREADING
|
| + if (!testing_interface_) {
|
| + return "Testing blocking callbacks requires the testing interface. In "
|
| + "Chrome, use the --enable-pepper-testing flag.";
|
| + }
|
| + // These tests are only valid if running out-of-process (threading is not
|
| + // supported in-process). Just consider it a pass.
|
| + if (!testing_interface_->IsOutOfProcess())
|
| + return std::string();
|
| + ThreadedTestRunner<T> runner(instance_->pp_instance(),
|
| + static_cast<T*>(this), test_to_run);
|
| + RunOnThreadInternal(&ThreadedTestRunner<T>::ThreadFunction, &runner,
|
| + testing_interface_);
|
| + return runner.result();
|
| +#else
|
| + // If threading's not enabled, just treat it as success.
|
| + return std::string();
|
| +#endif
|
| + }
|
|
|
| // Pointer to the instance that owns us.
|
| TestingInstance* instance_;
|
|
|
| - protected:
|
| // NULL unless InitTestingInterface is called.
|
| const PPB_Testing_Dev* testing_interface_;
|
|
|
| @@ -127,6 +156,49 @@ class TestCase {
|
| }
|
|
|
| private:
|
| + template <class T>
|
| + class ThreadedTestRunner {
|
| + public:
|
| + typedef std::string(T::*TestMethodType)();
|
| + ThreadedTestRunner(PP_Instance instance,
|
| + T* test_case,
|
| + TestMethodType test_to_run)
|
| + : instance_(instance),
|
| + test_case_(test_case),
|
| + test_to_run_(test_to_run) {
|
| + }
|
| + const std::string& result() { return result_; }
|
| + static void ThreadFunction(void* runner) {
|
| + static_cast<ThreadedTestRunner<T>*>(runner)->Run();
|
| + }
|
| +
|
| + private:
|
| + void Run() {
|
| + // TODO(dmichael): Create and attach a pp::MessageLoop for this thread so
|
| + // nested loops work.
|
| + result_ = (test_case_->*test_to_run_)();
|
| + // Tell the main thread to quit its nested message loop, now that the test
|
| + // is complete.
|
| + TestCase::QuitMainMessageLoop(instance_);
|
| + }
|
| +
|
| + std::string result_;
|
| + PP_Instance instance_;
|
| + T* test_case_;
|
| + TestMethodType test_to_run_;
|
| + };
|
| +
|
| + // The internals for RunOnThread. This allows us to avoid including
|
| + // pp_thread.h in this header file, since it includes system headers like
|
| + // windows.h.
|
| + // RunOnThreadInternal launches a new thread to run |thread_func|, waits
|
| + // for it to complete using RunMessageLoop(), then joins.
|
| + void RunOnThreadInternal(void (*thread_func)(void*),
|
| + void* thread_param,
|
| + const PPB_Testing_Dev* testing_interface);
|
| +
|
| + static void DoQuitMainMessageLoop(void* pp_instance, int32_t result);
|
| +
|
| // Passed when creating completion callbacks in some tests. This determines
|
| // what kind of callback we use for the test.
|
| CallbackType callback_type_;
|
| @@ -184,12 +256,39 @@ class TestCaseFactory {
|
| #define RUN_TEST(name, test_filter) \
|
| if (MatchesFilter(#name, test_filter)) { \
|
| set_callback_type(PP_OPTIONAL); \
|
| - std::string error_message = Test##name(); \
|
| - if (error_message.empty()) \
|
| - error_message = CheckResourcesAndVars(); \
|
| - instance_->LogTest(#name, error_message); \
|
| + instance_->LogTest(#name, CheckResourcesAndVars(Test##name())); \
|
| + }
|
| +
|
| +// Like RUN_TEST above but forces functions taking callbacks to complete
|
| +// asynchronously on success or error.
|
| +#define RUN_TEST_FORCEASYNC(name, test_filter) \
|
| + if (MatchesFilter(#name, test_filter)) { \
|
| + set_callback_type(PP_REQUIRED); \
|
| + instance_->LogTest(#name"ForceAsync", \
|
| + CheckResourcesAndVars(Test##name())); \
|
| }
|
|
|
| +#define RUN_TEST_BLOCKING(test_case, name, test_filter) \
|
| + if (MatchesFilter(#name, test_filter)) { \
|
| + set_callback_type(PP_BLOCKING); \
|
| + instance_->LogTest(#name"Blocking", \
|
| + CheckResourcesAndVars(RunOnThread(&test_case::Test##name))); \
|
| + }
|
| +
|
| +#define RUN_TEST_FORCEASYNC_AND_NOT(name, test_filter) \
|
| + do { \
|
| + RUN_TEST_FORCEASYNC(name, test_filter); \
|
| + RUN_TEST(name, test_filter); \
|
| + } while (false)
|
| +
|
| +// Run a test with all possible callback types.
|
| +#define RUN_CALLBACK_TEST(test_case, name, test_filter) \
|
| + do { \
|
| + RUN_TEST_FORCEASYNC(name, test_filter); \
|
| + RUN_TEST(name, test_filter); \
|
| + RUN_TEST_BLOCKING(test_case, name, test_filter); \
|
| + } while (false)
|
| +
|
| #define RUN_TEST_WITH_REFERENCE_CHECK(name, test_filter) \
|
| if (MatchesFilter(#name, test_filter)) { \
|
| set_callback_type(PP_OPTIONAL); \
|
| @@ -204,21 +303,6 @@ class TestCaseFactory {
|
| instance_->LogTest(#name, error_message); \
|
| }
|
|
|
| -// Like RUN_TEST above but forces functions taking callbacks to complete
|
| -// asynchronously on success or error.
|
| -#define RUN_TEST_FORCEASYNC(name, test_filter) \
|
| - if (MatchesFilter(#name"ForceAsync", test_filter)) { \
|
| - set_callback_type(PP_REQUIRED); \
|
| - instance_->LogTest(#name"ForceAsync", Test##name()); \
|
| - }
|
| -
|
| -#define RUN_TEST_FORCEASYNC_AND_NOT(name, test_filter) \
|
| - do { \
|
| - RUN_TEST_FORCEASYNC(name, test_filter); \
|
| - RUN_TEST(name, test_filter); \
|
| - } while (false)
|
| -
|
| -
|
| // Helper macros for checking values in tests, and returning a location
|
| // description of the test fails.
|
| #define ASSERT_TRUE(cmd) \
|
|
|