diff options
Diffstat (limited to '')
-rw-r--r-- | third_party/libwebrtc/test/ios/Info.plist | 47 | ||||
-rw-r--r-- | third_party/libwebrtc/test/ios/coverage_util_ios.h | 24 | ||||
-rw-r--r-- | third_party/libwebrtc/test/ios/coverage_util_ios.mm | 42 | ||||
-rw-r--r-- | third_party/libwebrtc/test/ios/google_test_runner.mm | 40 | ||||
-rw-r--r-- | third_party/libwebrtc/test/ios/google_test_runner_delegate.h | 28 | ||||
-rw-r--r-- | third_party/libwebrtc/test/ios/test_support.h | 39 | ||||
-rw-r--r-- | third_party/libwebrtc/test/ios/test_support.mm | 217 |
7 files changed, 437 insertions, 0 deletions
diff --git a/third_party/libwebrtc/test/ios/Info.plist b/third_party/libwebrtc/test/ios/Info.plist new file mode 100644 index 0000000000..fe06a5e005 --- /dev/null +++ b/third_party/libwebrtc/test/ios/Info.plist @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +<dict> + <key>CFBundleDevelopmentRegion</key> + <string>English</string> + <key>CFBundleDisplayName</key> + <string>${PRODUCT_NAME}</string> + <key>CFBundleExecutable</key> + <string>${EXECUTABLE_NAME}</string> + <key>CFBundleIdentifier</key> + <string>${BUNDLE_IDENTIFIER}</string> + <key>CFBundleInfoDictionaryVersion</key> + <string>6.0</string> + <key>CFBundleName</key> + <string>${PRODUCT_NAME}</string> + <key>CFBundlePackageType</key> + <string>APPL</string> + <key>CFBundleShortVersionString</key> + <string>1.0</string> + <key>CFBundleSignature</key> + <string>????</string> + <key>CFBundleVersion</key> + <string>1.0</string> + <key>LSRequiresIPhoneOS</key> + <true/> + <key>NSAppTransportSecurity</key> + <dict> + <key>NSAllowsArbitraryLoads</key> + <true/> + </dict> + <key>UIFileSharingEnabled</key> + <true/> + <key>UISupportedInterfaceOrientation</key> + <array> + <string>UIInterfaceOrientationPortrait</string> + <string>UIInterfaceOrientationLandscapeLeft</string> + <string>UIInterfaceOrientationLandscapeRight</string> + </array> + <key>UIBackgroundModes</key> + <array> + <string>fetch</string> + </array> + <key>NSMicrophoneUsageDescription</key> + <string>For testing purposes</string> +</dict> +</plist> diff --git a/third_party/libwebrtc/test/ios/coverage_util_ios.h b/third_party/libwebrtc/test/ios/coverage_util_ios.h new file mode 100644 index 0000000000..a17b69dca8 --- /dev/null +++ b/third_party/libwebrtc/test/ios/coverage_util_ios.h @@ -0,0 +1,24 @@ +/* + * Copyright 2018 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_IOS_COVERAGE_UTIL_IOS_H_ +#define TEST_IOS_COVERAGE_UTIL_IOS_H_ + +namespace rtc { +namespace test { + +// In debug builds, if IOS_ENABLE_COVERAGE is defined, sets the filename of the +// coverage file. Otherwise, it does nothing. +void ConfigureCoverageReportPath(); + +} // namespace test +} // namespace rtc + +#endif // TEST_IOS_COVERAGE_UTIL_IOS_H_ diff --git a/third_party/libwebrtc/test/ios/coverage_util_ios.mm b/third_party/libwebrtc/test/ios/coverage_util_ios.mm new file mode 100644 index 0000000000..c21a16def2 --- /dev/null +++ b/third_party/libwebrtc/test/ios/coverage_util_ios.mm @@ -0,0 +1,42 @@ +/* + * Copyright 2018 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#import <Foundation/Foundation.h> + +#ifdef WEBRTC_IOS_ENABLE_COVERAGE +extern "C" void __llvm_profile_set_filename(const char* name); +#endif + +namespace rtc { +namespace test { + +void ConfigureCoverageReportPath() { +#ifdef WEBRTC_IOS_ENABLE_COVERAGE + static dispatch_once_t once_token; + dispatch_once(&once_token, ^{ + // Writes the profraw file to the Documents directory, where the app has + // write rights. + NSArray* paths = + NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString* documents_directory = [paths firstObject]; + NSString* file_name = [documents_directory stringByAppendingPathComponent:@"coverage.profraw"]; + + // For documentation, see: + // http://clang.llvm.org/docs/SourceBasedCodeCoverage.html + __llvm_profile_set_filename([file_name cStringUsingEncoding:NSUTF8StringEncoding]); + + // Print the path for easier retrieval. + NSLog(@"Coverage data at %@.", file_name); + }); +#endif // ifdef WEBRTC_IOS_ENABLE_COVERAGE +} + +} // namespace test +} // namespace rtc diff --git a/third_party/libwebrtc/test/ios/google_test_runner.mm b/third_party/libwebrtc/test/ios/google_test_runner.mm new file mode 100644 index 0000000000..87b7f7dfd7 --- /dev/null +++ b/third_party/libwebrtc/test/ios/google_test_runner.mm @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Copied from Chromium base/test/ios/google_test_runner.mm to avoid +// the //base dependency. The protocol is required to run iOS Unittest. + +#import <UIKit/UIKit.h> +#import <XCTest/XCTest.h> + +#import "test/ios/google_test_runner_delegate.h" + +#if !defined(__has_feature) || !__has_feature(objc_arc) +#error "This file requires ARC support." +#endif + +@interface GoogleTestRunner : XCTestCase +@end + +@implementation GoogleTestRunner + +- (void)testRunGoogleTests { + self.continueAfterFailure = false; + + id appDelegate = UIApplication.sharedApplication.delegate; + XCTAssertTrue([appDelegate conformsToProtocol:@protocol(GoogleTestRunnerDelegate)]); + + id<GoogleTestRunnerDelegate> runnerDelegate = + static_cast<id<GoogleTestRunnerDelegate>>(appDelegate); + XCTAssertTrue(runnerDelegate.supportsRunningGoogleTests); + XCTAssertTrue([runnerDelegate runGoogleTests] == 0); +} + +@end diff --git a/third_party/libwebrtc/test/ios/google_test_runner_delegate.h b/third_party/libwebrtc/test/ios/google_test_runner_delegate.h new file mode 100644 index 0000000000..78ee59e028 --- /dev/null +++ b/third_party/libwebrtc/test/ios/google_test_runner_delegate.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2021 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_IOS_GOOGLE_TEST_RUNNER_DELEGATE_H_ +#define TEST_IOS_GOOGLE_TEST_RUNNER_DELEGATE_H_ + +// Copied from Chromium base/test/ios/google_test_runner_delegate.h +// to avoid the //base dependency. This protocol is required +// to run iOS Unittest. +@protocol GoogleTestRunnerDelegate + +// Returns YES if this delegate supports running GoogleTests via a call to +// `runGoogleTests`. +@property(nonatomic, readonly, assign) BOOL supportsRunningGoogleTests; + +// Runs GoogleTests and returns the final exit code. +- (int)runGoogleTests; + +@end + +#endif // TEST_IOS_GOOGLE_TEST_RUNNER_DELEGATE_H_ diff --git a/third_party/libwebrtc/test/ios/test_support.h b/third_party/libwebrtc/test/ios/test_support.h new file mode 100644 index 0000000000..5ac731393f --- /dev/null +++ b/third_party/libwebrtc/test/ios/test_support.h @@ -0,0 +1,39 @@ +/* + * Copyright 2017 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef TEST_IOS_TEST_SUPPORT_H_ +#define TEST_IOS_TEST_SUPPORT_H_ + +#include <string> +#include <vector> + +#include "absl/types/optional.h" + +namespace rtc { +namespace test { +// Launches an iOS app that serves as a host for a test suite. +// This is necessary as iOS doesn't like processes without a gui +// running for longer than a few seconds. +void RunTestsFromIOSApp(); +void InitTestSuite(int (*test_suite)(void), + int argc, + char* argv[], + bool save_chartjson_result, + bool export_perf_results_new_api, + std::string webrtc_test_metrics_output_path, + absl::optional<std::vector<std::string>> metrics_to_plot); + +// Returns true if unittests should be run by the XCTest runnner. +bool ShouldRunIOSUnittestsWithXCTest(); + +} // namespace test +} // namespace rtc + +#endif // TEST_IOS_TEST_SUPPORT_H_ diff --git a/third_party/libwebrtc/test/ios/test_support.mm b/third_party/libwebrtc/test/ios/test_support.mm new file mode 100644 index 0000000000..d3c9ee0c74 --- /dev/null +++ b/third_party/libwebrtc/test/ios/test_support.mm @@ -0,0 +1,217 @@ +/* + * Copyright 2017 The WebRTC Project Authors. All rights reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#import <UIKit/UIKit.h> + +#include "api/test/metrics/chrome_perf_dashboard_metrics_exporter.h" +#include "api/test/metrics/global_metrics_logger_and_exporter.h" +#include "api/test/metrics/metrics_exporter.h" +#include "api/test/metrics/metrics_set_proto_file_exporter.h" +#include "api/test/metrics/print_result_proxy_metrics_exporter.h" +#include "api/test/metrics/stdout_metrics_exporter.h" +#include "test/ios/coverage_util_ios.h" +#include "test/ios/google_test_runner_delegate.h" +#include "test/ios/test_support.h" +#include "test/testsupport/perf_test.h" + +#import "sdk/objc/helpers/NSString+StdString.h" + +// Springboard will kill any iOS app that fails to check in after launch within +// a given time. Starting a UIApplication before invoking TestSuite::Run +// prevents this from happening. + +// InitIOSRunHook saves the TestSuite and argc/argv, then invoking +// RunTestsFromIOSApp calls UIApplicationMain(), providing an application +// delegate class: WebRtcUnitTestDelegate. The delegate implements +// application:didFinishLaunchingWithOptions: to invoke the TestSuite's Run +// method. + +// 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. + +// If enabled, runs unittests using the XCTest test runner. +const char kEnableRunIOSUnittestsWithXCTest[] = "enable-run-ios-unittests-with-xctest"; + +static int (*g_test_suite)(void) = NULL; +static int g_argc; +static char **g_argv; +static bool g_write_perf_output; +static bool g_export_perf_results_new_api; +static std::string g_webrtc_test_metrics_output_path; +static absl::optional<bool> g_is_xctest; +static absl::optional<std::vector<std::string>> g_metrics_to_plot; + +@interface UIApplication (Testing) +- (void)_terminateWithStatus:(int)status; +@end + +@interface WebRtcUnitTestDelegate : NSObject <GoogleTestRunnerDelegate> { + UIWindow *_window; +} +- (void)runTests; +@end + +@implementation WebRtcUnitTestDelegate + +- (BOOL)application:(UIApplication *)application + didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + CGRect bounds = [[UIScreen mainScreen] bounds]; + + _window = [[UIWindow alloc] initWithFrame:bounds]; + [_window setBackgroundColor:[UIColor whiteColor]]; + [_window makeKeyAndVisible]; + + // Add a label with the app name. + UILabel *label = [[UILabel alloc] initWithFrame:bounds]; + label.text = [[NSProcessInfo processInfo] processName]; + label.textAlignment = NSTextAlignmentCenter; + [_window addSubview:label]; + + // An NSInternalInconsistencyException is thrown if the app doesn't have a + // root view controller. Set an empty one here. + [_window setRootViewController:[[UIViewController alloc] init]]; + + if (!rtc::test::ShouldRunIOSUnittestsWithXCTest()) { + // When running in XCTest mode, XCTest will invoke `runGoogleTest` directly. + // Otherwise, schedule a call to `runTests`. + [self performSelector:@selector(runTests) withObject:nil afterDelay:0.1]; + } + + return YES; +} + +- (BOOL)supportsRunningGoogleTests { + return rtc::test::ShouldRunIOSUnittestsWithXCTest(); +} + +- (int)runGoogleTests { + rtc::test::ConfigureCoverageReportPath(); + + int exitStatus = g_test_suite(); + + NSArray<NSString *> *outputDirectories = + NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + std::vector<std::unique_ptr<webrtc::test::MetricsExporter>> exporters; + if (g_export_perf_results_new_api) { + exporters.push_back(std::make_unique<webrtc::test::StdoutMetricsExporter>()); + if (g_write_perf_output) { + // Stores data into a proto file under the app's document directory. + NSString *fileName = @"perftest-output.pb"; + if ([outputDirectories count] != 0) { + NSString *outputPath = [outputDirectories[0] stringByAppendingPathComponent:fileName]; + + exporters.push_back(std::make_unique<webrtc::test::ChromePerfDashboardMetricsExporter>( + [NSString stdStringForString:outputPath])); + } + } + if (!g_webrtc_test_metrics_output_path.empty()) { + RTC_CHECK_EQ(g_webrtc_test_metrics_output_path.find('/'), std::string::npos) + << "On iOS, --webrtc_test_metrics_output_path must only be a file name."; + if ([outputDirectories count] != 0) { + NSString *fileName = [NSString stringWithCString:g_webrtc_test_metrics_output_path.c_str() + encoding:[NSString defaultCStringEncoding]]; + NSString *outputPath = [outputDirectories[0] stringByAppendingPathComponent:fileName]; + exporters.push_back(std::make_unique<webrtc::test::MetricsSetProtoFileExporter>( + webrtc::test::MetricsSetProtoFileExporter::Options( + [NSString stdStringForString:outputPath]))); + } + } + } else { + exporters.push_back(std::make_unique<webrtc::test::PrintResultProxyMetricsExporter>()); + } + webrtc::test::ExportPerfMetric(*webrtc::test::GetGlobalMetricsLogger(), std::move(exporters)); + if (!g_export_perf_results_new_api) { + if (g_write_perf_output) { + // Stores data into a proto file under the app's document directory. + NSString *fileName = @"perftest-output.pb"; + if ([outputDirectories count] != 0) { + NSString *outputPath = [outputDirectories[0] stringByAppendingPathComponent:fileName]; + + if (!webrtc::test::WritePerfResults([NSString stdStringForString:outputPath])) { + return 1; + } + } + } + if (g_metrics_to_plot) { + webrtc::test::PrintPlottableResults(*g_metrics_to_plot); + } + } + + return exitStatus; +} + +- (void)runTests { + RTC_DCHECK(!rtc::test::ShouldRunIOSUnittestsWithXCTest()); + rtc::test::ConfigureCoverageReportPath(); + + int exitStatus = [self runGoogleTests]; + + // 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(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]]; + + // 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 +namespace rtc { +namespace test { + +// Note: This is not thread safe, and must be called from the same thread as +// runTests above. +void InitTestSuite(int (*test_suite)(void), + int argc, + char *argv[], + bool write_perf_output, + bool export_perf_results_new_api, + std::string webrtc_test_metrics_output_path, + absl::optional<std::vector<std::string>> metrics_to_plot) { + g_test_suite = test_suite; + g_argc = argc; + g_argv = argv; + g_write_perf_output = write_perf_output; + g_export_perf_results_new_api = export_perf_results_new_api; + g_webrtc_test_metrics_output_path = webrtc_test_metrics_output_path; + g_metrics_to_plot = std::move(metrics_to_plot); +} + +void RunTestsFromIOSApp() { + @autoreleasepool { + exit(UIApplicationMain(g_argc, g_argv, nil, @"WebRtcUnitTestDelegate")); + } +} + +bool ShouldRunIOSUnittestsWithXCTest() { + if (g_is_xctest.has_value()) { + return g_is_xctest.value(); + } + + char **argv = g_argv; + while (*argv != nullptr) { + if (strstr(*argv, kEnableRunIOSUnittestsWithXCTest) != nullptr) { + g_is_xctest = absl::optional<bool>(true); + return true; + } + argv++; + } + g_is_xctest = absl::optional<bool>(false); + return false; +} + +} // namespace test +} // namespace rtc |