| Index: base/test/main_hook_ios.mm
|
| diff --git a/base/test/main_hook_ios.mm b/base/test/main_hook_ios.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..6d7bc449e008aae10e4786cd1a6113889aea4f0b
|
| --- /dev/null
|
| +++ b/base/test/main_hook_ios.mm
|
| @@ -0,0 +1,108 @@
|
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "base/test/main_hook.h"
|
| +
|
| +#import <UIKit/UIKit.h>
|
| +
|
| +#include "base/debug/debugger.h"
|
| +#include "base/logging.h"
|
| +#include "base/mac/scoped_nsautorelease_pool.h"
|
| +#include "base/memory/scoped_nsobject.h"
|
| +
|
| +// Springboard will kill any iOS app that fails to check in after launch within
|
| +// a given time. These two classes prevent this from happening.
|
| +
|
| +// MainHook saves the chrome main() and calls UIApplicationMain(),
|
| +// providing an application delegate class: ChromeUnitTestDelegate. The delegate
|
| +// listens for UIApplicationDidFinishLaunchingNotification. When the
|
| +// notification is received, it fires main() again to have the real work done.
|
| +
|
| +// Example usage:
|
| +// int main(int argc, char** argv) {
|
| +// MainHook hook(main, argc, argv);
|
| +// // Testing code goes here. There should be no code above MainHook. If
|
| +// // there is, it will be run twice.
|
| +// }
|
| +
|
| +// Since the executable isn't likely to be a real iOS UI, the delegate puts up a
|
| +// window displaying the app name. If a bunch of apps using MainHook are being
|
| +// run in a row, this provides an indication of which one is currently running.
|
| +
|
| +static MainHook::MainType g_main_func = NULL;
|
| +static int g_argc;
|
| +static char** g_argv;
|
| +
|
| +@interface UIApplication (Testing)
|
| +- (void) _terminateWithStatus:(int)status;
|
| +@end
|
| +
|
| +@interface ChromeUnitTestDelegate : NSObject {
|
| +@private
|
| + scoped_nsobject<UIWindow> window_;
|
| +}
|
| +- (void)runTests;
|
| +@end
|
| +
|
| +@implementation ChromeUnitTestDelegate
|
| +
|
| +- (BOOL)application:(UIApplication *)application
|
| + didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
|
| +
|
| + CGRect bounds = [[UIScreen mainScreen] bounds];
|
| +
|
| + // Yes, this is leaked, it's just to make what's running visible.
|
| + window_.reset([[UIWindow alloc] initWithFrame:bounds]);
|
| + [window_ makeKeyAndVisible];
|
| +
|
| + // Add a label with the app name.
|
| + UILabel* label = [[[UILabel alloc] initWithFrame:bounds] autorelease];
|
| + label.text = [[NSProcessInfo processInfo] processName];
|
| + label.textAlignment = UITextAlignmentCenter;
|
| + [window_ addSubview:label];
|
| +
|
| + // Queue up the test run.
|
| + [self performSelector:@selector(runTests)
|
| + withObject:nil
|
| + afterDelay:0.1];
|
| + return YES;
|
| +}
|
| +
|
| +- (void)runTests {
|
| + int exitStatus = g_main_func(g_argc, g_argv);
|
| +
|
| + // If a test app is too fast, it will exit before Instruments has has a
|
| + // a chance to initialize and no test results will be seen.
|
| + // TODO(ios): crbug.com/137010 Figure out how much time is actually needed,
|
| + // and sleep only to make sure that much time has elapsed since launch.
|
| + [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];
|
| + window_.reset();
|
| +
|
| + // Use the hidden selector to try and cleanly take down the app (otherwise
|
| + // things can think the app crashed even on a zero exit status).
|
| + UIApplication* application = [UIApplication sharedApplication];
|
| + [application _terminateWithStatus:exitStatus];
|
| +
|
| + exit(exitStatus);
|
| +}
|
| +
|
| +@end
|
| +
|
| +#pragma mark -
|
| +
|
| +MainHook::MainHook(MainType main_func, int argc, char* argv[]) {
|
| + static bool ran_hook = false;
|
| + if (!ran_hook) {
|
| + ran_hook = true;
|
| +
|
| + g_main_func = main_func;
|
| + g_argc = argc;
|
| + g_argv = argv;
|
| +
|
| + base::mac::ScopedNSAutoreleasePool pool;
|
| + int exit_status = UIApplicationMain(argc, argv, nil,
|
| + @"ChromeUnitTestDelegate");
|
| + exit(exit_status);
|
| + }
|
| +}
|
|
|