From 1a5f833a7150225448f9379e475b3c122dd922d0 Mon Sep 17 00:00:00 2001 From: Matt Stevens Date: Wed, 17 Jun 2015 22:41:56 -0600 Subject: [PATCH] Associate generated classes with the unit test bundle This is accomplished by implementing the undocumented +bundleForClass for the generated classes. This isn't necessary for proper operation, but it results in more expected output from XCTest reports. With this change Google Test classes appear to be part of the unit test bundle that GoogleTests.mm is compiled into, as they did under earlier implementations. Without it tests are still executed and filtered properly, but appear in the report as part of a separate bundle for the application running tests. When run within Xcode this is a command line app so the bundle is represented as the name of the directory where that app is located ("Agents"). --- Bundle/GoogleTests.mm | 51 +++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/Bundle/GoogleTests.mm b/Bundle/GoogleTests.mm index 33f802a..069a123 100644 --- a/Bundle/GoogleTests.mm +++ b/Bundle/GoogleTests.mm @@ -77,6 +77,37 @@ void OnTestPartResult(const TestPartResult& test_part_result) { XCTestCase *_testCase; }; +/** + * Registers an XCTestCase subclass for each Google Test case. + * + * Generating these classes allows Google Test cases to be represented as peers + * of standard XCTest suites and supports filtering of test runs to specific + * Google Test cases or individual tests via Xcode. + */ +@interface GoogleTestLoader : NSObject +@end + +/** + * Base class for the generated classes for Google Test cases. + */ +@interface GoogleTestCase : XCTestCase +@end + +@implementation GoogleTestCase + +/** + * Associates generated Google Test classes with the test bundle. + * + * This affects how the generated test cases are represented in reports. By + * associating the generated classes with a test bundle the Google Test cases + * appear to be part of the same test bundle that this source file is compiled + * into. Without this association they appear to be part of a bundle + * representing the directory of an internal Xcode tool that runs the tests. + */ ++ (NSBundle *)bundleForClass { + return [NSBundle bundleForClass:[GoogleTestLoader class]]; +} + /** * Implementation of +[XCTestCase testInvocations] that returns an array of test * invocations for each test method in the class. @@ -84,7 +115,7 @@ void OnTestPartResult(const TestPartResult& test_part_result) { * This differs from the standard implementation of testInvocations, which only * adds methods with a prefix of "test". */ -static NSArray *TestInvocations(id self, SEL _cmd) { ++ (NSArray *)testInvocations { NSMutableArray *invocations = [NSMutableArray array]; unsigned int methodCount = 0; @@ -103,6 +134,8 @@ void OnTestPartResult(const TestPartResult& test_part_result) { return invocations; } +@end + /** * Runs a single test. */ @@ -125,16 +158,6 @@ static void RunTest(id self, SEL _cmd) { XCTAssertEqual(totalTestsRun, 1, @"Expected to run a single test for filter \"%@\"", testFilter); } -/** - * Registers an XCTestCase subclass for each Google Test case. - * - * Generating these classes allows Google Test cases to be represented as peers - * of standard XCTest suites and supports filtering of test runs to specific - * Google Test cases or individual tests via Xcode. - */ -@interface GoogleTestLoader : NSObject -@end - @implementation GoogleTestLoader /** @@ -200,7 +223,7 @@ + (void)registerTestClasses { // a valid class name. NSString *className = [GeneratedClassPrefix stringByAppendingString:[testCaseNameComponents componentsJoinedByString:@"_"]]; - Class testClass = objc_allocateClassPair([XCTestCase class], [className UTF8String], 0); + Class testClass = objc_allocateClassPair([GoogleTestCase class], [className UTF8String], 0); NSAssert1(testClass, @"Failed to register Google Test class \"%@\", this class may already exist. The value of GeneratedClassPrefix can be changed to avoid this.", className); BOOL hasMethods = NO; @@ -229,10 +252,6 @@ + (void)registerTestClasses { } if (hasMethods) { - Class testMetaClass = object_getClass(testClass); - SEL invocationsSelector = @selector(testInvocations); - Method invocationsMethod = class_getClassMethod(testClass, invocationsSelector); - class_addMethod(testMetaClass, invocationsSelector, (IMP)TestInvocations, method_getTypeEncoding(invocationsMethod)); objc_registerClassPair(testClass); } else { objc_disposeClassPair(testClass);