From b66cfb7414a3790826081049e14fc2ccf2b91b30 Mon Sep 17 00:00:00 2001 From: Byoungchan Lee Date: Mon, 26 Jul 2021 16:32:10 +0900 Subject: [PATCH] test: Make iOS Test Delegate Class conforms the proper protocol Currently, the WebRtcUnitTestDelegate does not conform to the GoogleTestRunnerDelegate protocol. So the GoogleTestRunner, designed to run googletest based tests using XCTest, fails like this: Test Case '-[GoogleTestRunner testRunGoogleTests]' started. /../../base/test/ios/google_test_runner.mm:24: error: -[GoogleTestRunner testRunGoogleTests] : (([appDelegate conformsToProtocol:@protocol(GoogleTestRunnerDelegate)]) is true) failed Test Case '-[GoogleTestRunner testRunGoogleTests]' failed (0.004 seconds). This CL fixes this issue by implementing the GoogleTestRunnerDelegate protocol, so googletest based tests run without error. No-Presubmit: True No-Try: True Bug: webrtc:12813 Change-Id: I6564b41c3aec88a9ddf078104753ceca5e6f0ba6 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/220260 Reviewed-by: Mirko Bonadei Reviewed-by: Artem Titov Commit-Queue: Mirko Bonadei Cr-Commit-Position: refs/heads/master@{#34593} --- test/BUILD.gn | 1 + test/ios/google_test_runner_delegate.h | 28 +++++++++++++ test/ios/test_support.h | 3 ++ test/ios/test_support.mm | 57 ++++++++++++++++++++++---- 4 files changed, 80 insertions(+), 9 deletions(-) create mode 100644 test/ios/google_test_runner_delegate.h diff --git a/test/BUILD.gn b/test/BUILD.gn index d645621e79..c89085d542 100644 --- a/test/BUILD.gn +++ b/test/BUILD.gn @@ -281,6 +281,7 @@ if (is_ios) { sources = [ "ios/coverage_util_ios.h", "ios/coverage_util_ios.mm", + "ios/google_test_runner_delegate.h", "ios/test_support.h", "ios/test_support.mm", ] diff --git a/test/ios/google_test_runner_delegate.h b/test/ios/google_test_runner_delegate.h new file mode 100644 index 0000000000..f0bcfe98d1 --- /dev/null +++ b/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 +// The WebRTC test cannot depend on //base, but this protocol is required +// to run iOS Unittest, so it is a workaround for the dependency. +@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/test/ios/test_support.h b/test/ios/test_support.h index 10958572cf..cd8d2a8103 100644 --- a/test/ios/test_support.h +++ b/test/ios/test_support.h @@ -28,6 +28,9 @@ void InitTestSuite(int (*test_suite)(void), bool save_chartjson_result, absl::optional> metrics_to_plot); +// Returns true if unittests should be run by the XCTest runnner. +bool ShouldRunIOSUnittestsWithXCTest(); + } // namespace test } // namespace rtc diff --git a/test/ios/test_support.mm b/test/ios/test_support.mm index 86d2e6ce17..3da896fa08 100644 --- a/test/ios/test_support.mm +++ b/test/ios/test_support.mm @@ -11,6 +11,7 @@ #import #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" @@ -30,17 +31,21 @@ // 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 absl::optional g_is_xctest; static absl::optional> g_metrics_to_plot; @interface UIApplication (Testing) - (void)_terminateWithStatus:(int)status; @end -@interface WebRtcUnitTestDelegate : NSObject { +@interface WebRtcUnitTestDelegate : NSObject { UIWindow *_window; } - (void)runTests; @@ -66,12 +71,20 @@ static absl::optional> g_metrics_to_plot; // root view controller. Set an empty one here. [_window setRootViewController:[[UIViewController alloc] init]]; - // Queue up the test run. - [self performSelector:@selector(runTests) withObject:nil afterDelay:0.1]; + 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; } -- (void)runTests { +- (BOOL)supportsRunningGoogleTests { + return rtc::test::ShouldRunIOSUnittestsWithXCTest(); +} + +- (int)runGoogleTests { rtc::test::ConfigureCoverageReportPath(); int exitStatus = g_test_suite(); @@ -79,14 +92,13 @@ static absl::optional> g_metrics_to_plot; if (g_write_perf_output) { // Stores data into a proto file under the app's document directory. NSString *fileName = @"perftest-output.pb"; - NSArray* outputDirectories = NSSearchPathForDirectoriesInDomains( - NSDocumentDirectory, NSUserDomainMask, YES); + NSArray *outputDirectories = + NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); if ([outputDirectories count] != 0) { - NSString* outputPath = - [outputDirectories[0] stringByAppendingPathComponent:fileName]; + NSString *outputPath = [outputDirectories[0] stringByAppendingPathComponent:fileName]; if (!webrtc::test::WritePerfResults([NSString stdStringForString:outputPath])) { - exit(1); + return 1; } } } @@ -94,6 +106,15 @@ static absl::optional> 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 @@ -131,5 +152,23 @@ void RunTestsFromIOSApp() { 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(true); + return true; + } + argv++; + } + g_is_xctest = absl::optional(false); + return false; +} + } // namespace test } // namespace rtc