1 // Copyright 2019 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 #ifndef CHROME_BROWSER_VR_TEST_MULTI_CLASS_BROWSER_TEST_H_
6 #define CHROME_BROWSER_VR_TEST_MULTI_CLASS_BROWSER_TEST_H_
7 
8 #include "content/public/test/browser_test.h"
9 #include "device/vr/buildflags/buildflags.h"
10 #include "testing/gtest/include/gtest/gtest.h"
11 
12 // A collection of macros to automatically run a browser test multiple times
13 // with different test classes/test fixtures. These are used the same way as
14 // the standard IN_PROC_BROWSER_TEST_F and IN_PROC_BROWSER_TEST_P macros, except
15 // that multiple test classes/fixtures are specified instead of one and a common
16 // base class must be provided. The number suffix indicates how many classes the
17 // macro expects, e.g. IN_PROC_MULTI_CLASS_BROWSER_TEST_F2 takes two classes.
18 
19 // One important note is that while IN_PROC_BROWSER_TEST_F would normally
20 // provide the constructed test class as "this", the reference to the
21 // constructed class when using the multi class macros is instead provided as
22 // "t". t's type will also be the provided base class, so if you need behavior
23 // specific to one of the subclasses, you must first cast it. Although in such
24 // cases, you should probably reconsider whether use of these macros is really
25 // appropriate instead of having separate implementations.
26 
27 // In essence:
28 //
29 // IN_PROC_MULTI_CLASS_BROWSER_TEST_F2(sub1, sub2, base, name) { impl }
30 //
31 // Is shorthand for:
32 //
33 // void TestImpl(base* t) { impl }
34 // IN_PROC_BROWSER_TEST_F(sub1, name) { TestImpl(this); }
35 // IN_PROC_BROWSER_TEST_F(sub2, name) { TestImpl(this); }
36 
37 // We essentially create a dummy class for the test which contains a declaration
38 // for a static function that will have the actual test implementation. We then
39 // define as many IN_PROC_BROWSER_TEST_Fs as necesasry and have each call the
40 // static function with its "this" reference. Finally, we start the definition
41 // for the static function but leave it unfinished so that the definition
42 // provided by the caller is used (which is also what IN_PROC_BROWSER_TEST_F
43 // does under the hood).
44 
45 #define MULTI_CLASS_RUNNER_NAME_(test_name) RunMultiClassBrowserTest_##test_name
46 
47 #define DEFINE_RUN_TEST_IMPL_(test_name, base_class)        \
48   class MULTI_CLASS_RUNNER_NAME_(test_name) {               \
49    public:                                                  \
50     MULTI_CLASS_RUNNER_NAME_(test_name)() {}                \
51     static void ActuallyRunTestOnMainThread(base_class* t); \
52   };
53 
54 #define DEFINE_BROWSER_TEST_(test_class, test_name)                         \
55   IN_PROC_BROWSER_TEST_F(test_class, test_name) {                           \
56     MULTI_CLASS_RUNNER_NAME_(test_name)::ActuallyRunTestOnMainThread(this); \
57   }
58 
59 #define DEFINE_INCOGNITO_BROWSER_TEST_(test_class, test_name)               \
60   IN_PROC_BROWSER_TEST_F(test_class, test_name##Incognito) {                \
61     auto* browser = CreateIncognitoBrowser();                               \
62     SetBrowser(browser);                                                    \
63     MULTI_CLASS_RUNNER_NAME_(test_name)::ActuallyRunTestOnMainThread(this); \
64   }
65 
66 // In this case IN_PROC_BROWSER_TEST_F could realistically be used; however, in
67 // some cases, we're conditionally enabling runtimes. This method thus enables
68 // easily "switching" between having only one runtime enabled and having two or
69 // more runtimes enabled, and helps make the "ALL_RUNTIMES" macros possible.
70 #define IN_PROC_MULTI_CLASS_BROWSER_TEST_F1(test_class1, base_class,     \
71                                             test_name)                   \
72   DEFINE_RUN_TEST_IMPL_(test_name, base_class)                           \
73   DEFINE_BROWSER_TEST_(test_class1, test_name)                           \
74   void MULTI_CLASS_RUNNER_NAME_(test_name)::ActuallyRunTestOnMainThread( \
75       base_class* t)
76 
77 #define IN_PROC_MULTI_CLASS_BROWSER_TEST_F2(test_class1, test_class2,    \
78                                             base_class, test_name)       \
79   DEFINE_RUN_TEST_IMPL_(test_name, base_class)                           \
80   DEFINE_BROWSER_TEST_(test_class1, test_name)                           \
81   DEFINE_BROWSER_TEST_(test_class2, test_name)                           \
82   void MULTI_CLASS_RUNNER_NAME_(test_name)::ActuallyRunTestOnMainThread( \
83       base_class* t)
84 
85 #define IN_PROC_MULTI_CLASS_PLUS_INCOGNITO_BROWSER_TEST_F2(              \
86     test_class1, test_class2, base_class, test_name)                     \
87   DEFINE_RUN_TEST_IMPL_(test_name, base_class)                           \
88   DEFINE_BROWSER_TEST_(test_class1, test_name)                           \
89   DEFINE_BROWSER_TEST_(test_class2, test_name)                           \
90   DEFINE_INCOGNITO_BROWSER_TEST_(test_class1, test_name)                 \
91   DEFINE_INCOGNITO_BROWSER_TEST_(test_class2, test_name)                 \
92   void MULTI_CLASS_RUNNER_NAME_(test_name)::ActuallyRunTestOnMainThread( \
93       base_class* t)
94 
95 // In this case IN_PROC_BROWSER_TEST_F could realistically be used; however, in
96 // some cases, we're conditionally enabling runtimes. This method thus enables
97 // easily "switching" between having only one runtime enabled and having two or
98 // more runtimes enabled, and helps make the "ALL_RUNTIMES" macros possible.
99 #define IN_PROC_MULTI_CLASS_PLUS_INCOGNITO_BROWSER_TEST_F1(              \
100     test_class1, base_class, test_name)                                  \
101   DEFINE_RUN_TEST_IMPL_(test_name, base_class)                           \
102   DEFINE_BROWSER_TEST_(test_class1, test_name)                           \
103   DEFINE_INCOGNITO_BROWSER_TEST_(test_class1, test_name)                 \
104   void MULTI_CLASS_RUNNER_NAME_(test_name)::ActuallyRunTestOnMainThread( \
105       base_class* t)
106 
107 // Helper macro to cut down on duplicate code since most uses of
108 // IN_PROC_MULTI_CLASS_BROWSER_TEST_F2 are passed the same WMR, and OpenXR
109 // classes and the same base class
110 #if BUILDFLAG(ENABLE_OPENXR)
111 #define WEBXR_VR_ALL_RUNTIMES_BROWSER_TEST_F(test_name)         \
112   IN_PROC_MULTI_CLASS_BROWSER_TEST_F2(WebXrVrWmrBrowserTest,    \
113                                       WebXrVrOpenXrBrowserTest, \
114                                       WebXrVrBrowserTestBase, test_name)
115 #else
116 #define WEBXR_VR_ALL_RUNTIMES_BROWSER_TEST_F(test_name)      \
117   IN_PROC_MULTI_CLASS_BROWSER_TEST_F1(WebXrVrWmrBrowserTest, \
118                                       WebXrVrBrowserTestBase, test_name)
119 #endif  // BUILDFLAG(ENABLE_OPENXR)
120 
121 // The same as WEBXR_VR_ALL_RUNTIMES_BROWSER_TEST_F, but runs the tests in
122 // incognito mode as well.
123 #if BUILDFLAG(ENABLE_OPENXR)
124 #define WEBXR_VR_ALL_RUNTIMES_PLUS_INCOGNITO_BROWSER_TEST_F(test_name)         \
125   IN_PROC_MULTI_CLASS_PLUS_INCOGNITO_BROWSER_TEST_F2(                          \
126       WebXrVrOpenXrBrowserTest, WebXrVrWmrBrowserTest, WebXrVrBrowserTestBase, \
127       test_name)
128 #else
129 #define WEBXR_VR_ALL_RUNTIMES_PLUS_INCOGNITO_BROWSER_TEST_F(test_name) \
130   IN_PROC_MULTI_CLASS_PLUS_INCOGNITO_BROWSER_TEST_F1(                  \
131       WebXrVrWmrBrowserTest, WebXrVrBrowserTestBase, test_name)
132 #endif  // ENABLE_OPENXR
133 
134 // Helper class to disable a specific runtime of the above
135 #define WEBXR_VR_DISABLE_TEST_ON(runtime) \
136   if (t->GetRuntimeType() == runtime)     \
137   return
138 
139 #endif  // CHROME_BROWSER_VR_TEST_MULTI_CLASS_BROWSER_TEST_H_
140