blob: 86005974fb2216c6365cc50c167b3968a8244d06 [file] [log] [blame]
Kári Tristan Helgasone2baffb2017-06-09 08:31:581/*
2 * Copyright 2017 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#import <UIKit/UIKit.h>
12
Artem Titarenko34fc3462018-11-06 11:29:2913#include "test/ios/coverage_util_ios.h"
Mirko Bonadei92ea95e2017-09-15 04:47:3114#include "test/ios/test_support.h"
Edward Lemure66572b2018-01-05 14:34:0915#include "test/testsupport/perf_test.h"
Kári Tristan Helgasone2baffb2017-06-09 08:31:5816
Anders Carlsson7bca8ca2018-08-30 07:30:2917#import "sdk/objc/helpers/NSString+StdString.h"
denicijad207a392017-09-11 13:43:2818
Kári Tristan Helgasone2baffb2017-06-09 08:31:5819// Springboard will kill any iOS app that fails to check in after launch within
20// a given time. Starting a UIApplication before invoking TestSuite::Run
21// prevents this from happening.
22
23// InitIOSRunHook saves the TestSuite and argc/argv, then invoking
24// RunTestsFromIOSApp calls UIApplicationMain(), providing an application
25// delegate class: WebRtcUnitTestDelegate. The delegate implements
26// application:didFinishLaunchingWithOptions: to invoke the TestSuite's Run
27// method.
28
29// 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
31// run in a row, this provides an indication of which one is currently running.
32
33static int (*g_test_suite)(void) = NULL;
34static int g_argc;
35static char **g_argv;
Edward Lemure66572b2018-01-05 14:34:0936static bool g_save_chartjson_result;
Kári Tristan Helgasone2baffb2017-06-09 08:31:5837
38@interface UIApplication (Testing)
39- (void)_terminateWithStatus:(int)status;
40@end
41
42@interface WebRtcUnitTestDelegate : NSObject {
43 UIWindow *_window;
44}
45- (void)runTests;
46@end
47
48@implementation WebRtcUnitTestDelegate
49
50- (BOOL)application:(UIApplication *)application
51 didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
52 CGRect bounds = [[UIScreen mainScreen] bounds];
53
54 _window = [[UIWindow alloc] initWithFrame:bounds];
55 [_window setBackgroundColor:[UIColor whiteColor]];
56 [_window makeKeyAndVisible];
57
58 // Add a label with the app name.
59 UILabel *label = [[UILabel alloc] initWithFrame:bounds];
60 label.text = [[NSProcessInfo processInfo] processName];
61 label.textAlignment = NSTextAlignmentCenter;
62 [_window addSubview:label];
63
64 // An NSInternalInconsistencyException is thrown if the app doesn't have a
65 // root view controller. Set an empty one here.
66 [_window setRootViewController:[[UIViewController alloc] init]];
67
Kári Tristan Helgasone2baffb2017-06-09 08:31:5868 // Queue up the test run.
69 [self performSelector:@selector(runTests) withObject:nil afterDelay:0.1];
70 return YES;
71}
72
73- (void)runTests {
Artem Titarenko34fc3462018-11-06 11:29:2974 rtc::test::ConfigureCoverageReportPath();
75
Kári Tristan Helgasone2baffb2017-06-09 08:31:5876 int exitStatus = g_test_suite();
77
Edward Lemure66572b2018-01-05 14:34:0978 if (g_save_chartjson_result) {
79 // Stores data into a json file under the app's document directory.
80 NSString* fileName = @"perf_result.json";
81 NSArray<NSString*>* outputDirectories = NSSearchPathForDirectoriesInDomains(
82 NSDocumentDirectory, NSUserDomainMask, YES);
83 if ([outputDirectories count] != 0) {
84 NSString* outputPath =
85 [outputDirectories[0] stringByAppendingPathComponent:fileName];
86
87 webrtc::test::WritePerfResults(
Anders Carlsson7bca8ca2018-08-30 07:30:2988 [NSString stdStringForString:outputPath]);
Edward Lemure66572b2018-01-05 14:34:0989 }
90 }
91
Kári Tristan Helgasone2baffb2017-06-09 08:31:5892 // If a test app is too fast, it will exit before Instruments has has a
93 // a chance to initialize and no test results will be seen.
94 // TODO(crbug.com/137010): Figure out how much time is actually needed, and
95 // sleep only to make sure that much time has elapsed since launch.
96 [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];
97
98 // Use the hidden selector to try and cleanly take down the app (otherwise
99 // things can think the app crashed even on a zero exit status).
100 UIApplication *application = [UIApplication sharedApplication];
101 [application _terminateWithStatus:exitStatus];
102
103 exit(exitStatus);
104}
105
106@end
107namespace rtc {
108namespace test {
109
Edward Lemure66572b2018-01-05 14:34:09110// Note: This is not thread safe, and must be called from the same thread as
111// runTests above.
112void InitTestSuite(int (*test_suite)(void), int argc, char *argv[],
113 bool save_chartjson_result) {
Kári Tristan Helgasone2baffb2017-06-09 08:31:58114 g_test_suite = test_suite;
115 g_argc = argc;
116 g_argv = argv;
Edward Lemure66572b2018-01-05 14:34:09117 g_save_chartjson_result = save_chartjson_result;
Kári Tristan Helgasone2baffb2017-06-09 08:31:58118}
119
120void RunTestsFromIOSApp() {
121 @autoreleasepool {
122 exit(UIApplicationMain(g_argc, g_argv, nil, @"WebRtcUnitTestDelegate"));
123 }
124}
125} // namespace test
126} // namespace rtc