OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/test/main_hook.h" | 5 #include "base/test/run_hook_ios.h" |
6 | 6 |
7 #import <UIKit/UIKit.h> | 7 #import <UIKit/UIKit.h> |
8 | 8 |
9 #include "base/debug/debugger.h" | 9 #include "base/debug/debugger.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
11 #include "base/mac/scoped_nsautorelease_pool.h" | 11 #include "base/mac/scoped_nsautorelease_pool.h" |
12 #include "base/memory/scoped_nsobject.h" | 12 #include "base/memory/scoped_nsobject.h" |
13 | 13 |
14 // Springboard will kill any iOS app that fails to check in after launch within | 14 // Springboard will kill any iOS app that fails to check in after launch within |
15 // a given time. These two classes prevent this from happening. | 15 // a given time. These two classes prevent this from happening. |
16 | 16 |
17 // MainHook saves the chrome main() and calls UIApplicationMain(), | 17 // RunHook::Init saves the TestSuite and argc/argv, then invoking RunHook::Run |
18 // providing an application delegate class: ChromeUnitTestDelegate. The delegate | 18 // calls UIApplicationMain(), providing an application delegate class: |
19 // listens for UIApplicationDidFinishLaunchingNotification. When the | 19 // ChromeUnitTestDelegate. The delegate implements |
20 // notification is received, it fires main() again to have the real work done. | 20 // application:didFinishLaunchingWithOptions: to invoke the TestSuite's Run |
21 | 21 // method. |
22 // Example usage: | |
23 // int main(int argc, char** argv) { | |
24 // MainHook hook(main, argc, argv); | |
25 // // Testing code goes here. There should be no code above MainHook. If | |
26 // // there is, it will be run twice. | |
27 // } | |
28 | 22 |
29 // Since the executable isn't likely to be a real iOS UI, the delegate puts up a | 23 // Since the executable isn't likely to be a real iOS UI, the delegate puts up a |
30 // window displaying the app name. If a bunch of apps using MainHook are being | 24 // window displaying the app name. If a bunch of apps using MainHook are being |
31 // run in a row, this provides an indication of which one is currently running. | 25 // run in a row, this provides an indication of which one is currently running. |
32 | 26 |
33 static MainHook::MainType g_main_func = NULL; | 27 static base::TestSuite* g_test_suite = NULL; |
34 static int g_argc; | 28 static int g_argc; |
35 static char** g_argv; | 29 static char** g_argv; |
36 | 30 |
37 @interface UIApplication (Testing) | 31 @interface UIApplication (Testing) |
38 - (void) _terminateWithStatus:(int)status; | 32 - (void) _terminateWithStatus:(int)status; |
39 @end | 33 @end |
40 | 34 |
41 @interface ChromeUnitTestDelegate : NSObject { | 35 @interface ChromeUnitTestDelegate : NSObject { |
42 @private | 36 @private |
43 scoped_nsobject<UIWindow> window_; | 37 scoped_nsobject<UIWindow> window_; |
44 } | 38 } |
45 - (void)runTests; | 39 - (void)runTests; |
46 @end | 40 @end |
47 | 41 |
48 @implementation ChromeUnitTestDelegate | 42 @implementation ChromeUnitTestDelegate |
49 | 43 |
50 - (BOOL)application:(UIApplication *)application | 44 - (BOOL)application:(UIApplication *)application |
51 didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { | 45 didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { |
52 | 46 |
(...skipping 10 matching lines...) Expand all Loading... |
63 [window_ addSubview:label]; | 57 [window_ addSubview:label]; |
64 | 58 |
65 // Queue up the test run. | 59 // Queue up the test run. |
66 [self performSelector:@selector(runTests) | 60 [self performSelector:@selector(runTests) |
67 withObject:nil | 61 withObject:nil |
68 afterDelay:0.1]; | 62 afterDelay:0.1]; |
69 return YES; | 63 return YES; |
70 } | 64 } |
71 | 65 |
72 - (void)runTests { | 66 - (void)runTests { |
73 int exitStatus = g_main_func(g_argc, g_argv); | 67 int exitStatus = g_test_suite->Run(); |
74 | 68 |
75 // If a test app is too fast, it will exit before Instruments has has a | 69 // If a test app is too fast, it will exit before Instruments has has a |
76 // a chance to initialize and no test results will be seen. | 70 // a chance to initialize and no test results will be seen. |
77 // TODO(ios): crbug.com/137010 Figure out how much time is actually needed, | 71 // TODO(ios): crbug.com/137010 Figure out how much time is actually needed, |
78 // and sleep only to make sure that much time has elapsed since launch. | 72 // and sleep only to make sure that much time has elapsed since launch. |
79 [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]]; | 73 [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]]; |
80 window_.reset(); | 74 window_.reset(); |
81 | 75 |
82 // Use the hidden selector to try and cleanly take down the app (otherwise | 76 // Use the hidden selector to try and cleanly take down the app (otherwise |
83 // things can think the app crashed even on a zero exit status). | 77 // things can think the app crashed even on a zero exit status). |
84 UIApplication* application = [UIApplication sharedApplication]; | 78 UIApplication* application = [UIApplication sharedApplication]; |
85 [application _terminateWithStatus:exitStatus]; | 79 [application _terminateWithStatus:exitStatus]; |
86 | 80 |
87 exit(exitStatus); | 81 exit(exitStatus); |
88 } | 82 } |
89 | 83 |
90 @end | 84 @end |
91 | 85 |
92 #pragma mark - | 86 #pragma mark - |
93 | 87 |
94 MainHook::MainHook(MainType main_func, int argc, char* argv[]) { | 88 void RunHook::Init(base::TestSuite* suite, int argc, char* argv[]) { |
| 89 g_test_suite = suite; |
| 90 g_argc = argc; |
| 91 g_argv = argv; |
| 92 } |
| 93 |
| 94 void RunHook::RunTestsFromApp() { |
95 static bool ran_hook = false; | 95 static bool ran_hook = false; |
96 if (!ran_hook) { | 96 if (!ran_hook) { |
97 ran_hook = true; | 97 ran_hook = true; |
98 | |
99 g_main_func = main_func; | |
100 g_argc = argc; | |
101 g_argv = argv; | |
102 | |
103 base::mac::ScopedNSAutoreleasePool pool; | 98 base::mac::ScopedNSAutoreleasePool pool; |
104 int exit_status = UIApplicationMain(argc, argv, nil, | 99 int exit_status = UIApplicationMain(g_argc, g_argv, nil, |
105 @"ChromeUnitTestDelegate"); | 100 @"ChromeUnitTestDelegate"); |
106 exit(exit_status); | 101 exit(exit_status); |
107 } | 102 } |
108 } | 103 } |
OLD | NEW |