Tanner Bennett лет назад: 6
Родитель
Сommit
c04e0b606d
2 измененных файлов с 108 добавлено и 0 удалено
  1. 4 0
      FLEX.xcodeproj/project.pbxproj
  2. 104 0
      FLEXTests/FLEXTests.m

+ 4 - 0
FLEX.xcodeproj/project.pbxproj

@@ -177,6 +177,7 @@
 		C32A19632317378C00EB02AC /* FLEXDefaultsContentSection.m in Sources */ = {isa = PBXBuildFile; fileRef = C32A19612317378C00EB02AC /* FLEXDefaultsContentSection.m */; };
 		C33C825E2316DC8600DD2451 /* FLEXObjectExplorer.h in Headers */ = {isa = PBXBuildFile; fileRef = C33C825C2316DC8600DD2451 /* FLEXObjectExplorer.h */; };
 		C33C825F2316DC8600DD2451 /* FLEXObjectExplorer.m in Sources */ = {isa = PBXBuildFile; fileRef = C33C825D2316DC8600DD2451 /* FLEXObjectExplorer.m */; };
+		C33C825B23159EAF00DD2451 /* FLEXTests.m in Sources */ = {isa = PBXBuildFile; fileRef = C33C825A23159EAF00DD2451 /* FLEXTests.m */; };
 		C33E46AF223B02CD004BD0E6 /* FLEXASLLogController.h in Headers */ = {isa = PBXBuildFile; fileRef = C33E46AD223B02CD004BD0E6 /* FLEXASLLogController.h */; };
 		C33E46B0223B02CD004BD0E6 /* FLEXASLLogController.m in Sources */ = {isa = PBXBuildFile; fileRef = C33E46AE223B02CD004BD0E6 /* FLEXASLLogController.m */; };
 		C3490E1F233BDD73002AE200 /* FLEXSingleRowSection.h in Headers */ = {isa = PBXBuildFile; fileRef = C3490E1D233BDD73002AE200 /* FLEXSingleRowSection.h */; };
@@ -456,6 +457,7 @@
 		C32A19612317378C00EB02AC /* FLEXDefaultsContentSection.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLEXDefaultsContentSection.m; sourceTree = "<group>"; };
 		C33C825C2316DC8600DD2451 /* FLEXObjectExplorer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FLEXObjectExplorer.h; path = Classes/ObjectExplorers/FLEXObjectExplorer.h; sourceTree = SOURCE_ROOT; };
 		C33C825D2316DC8600DD2451 /* FLEXObjectExplorer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = FLEXObjectExplorer.m; path = Classes/ObjectExplorers/FLEXObjectExplorer.m; sourceTree = SOURCE_ROOT; };
+		C33C825A23159EAF00DD2451 /* FLEXTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLEXTests.m; sourceTree = "<group>"; };
 		C33E46AD223B02CD004BD0E6 /* FLEXASLLogController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEXASLLogController.h; sourceTree = "<group>"; };
 		C33E46AE223B02CD004BD0E6 /* FLEXASLLogController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FLEXASLLogController.m; sourceTree = "<group>"; };
 		C3490E1D233BDD73002AE200 /* FLEXSingleRowSection.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FLEXSingleRowSection.h; sourceTree = "<group>"; };
@@ -577,6 +579,7 @@
 			children = (
 				1C27A8B81F0E5A0400F0D02D /* FLEXTestsMethodsList.m */,
 				1C27A8BA1F0E5A0400F0D02D /* Info.plist */,
+				C33C825A23159EAF00DD2451 /* FLEXTests.m */,
 			);
 			path = FLEXTests;
 			sourceTree = "<group>";
@@ -1310,6 +1313,7 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				C33C825B23159EAF00DD2451 /* FLEXTests.m in Sources */,
 				1C27A8B91F0E5A0400F0D02D /* FLEXTestsMethodsList.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;

+ 104 - 0
FLEXTests/FLEXTests.m

@@ -0,0 +1,104 @@
+//
+//  FLEXTests.m
+//  FLEXTests
+//
+//  Created by Tanner Bennett on 8/27/19.
+//  Copyright © 2019 Flipboard. All rights reserved.
+//
+
+#import <XCTest/XCTest.h>
+#import <objc/runtime.h>
+#import "NSObject+Reflection.h"
+#import "NSArray+Functional.h"
+#import "FLEXPropertyAttributes.h"
+#import "FLEXProperty.h"
+#import "FLEXUtility.h"
+#import "FLEXMethod.h"
+
+@interface Subclass : NSObject @end
+@implementation Subclass @end
+
+@interface FLEXTests : XCTestCase
+@property (nonatomic, setter=setMyFoo:) id foo;
+@end
+
+@implementation FLEXTests
+
+- (void)testRuntimeAdditions {
+    XCTAssertEqual(1, [NSObject flex_classHierarchy].count);
+    XCTAssertEqual(4, [FLEXTests flex_classHierarchy].count);
+    XCTAssertEqual([FLEXTests flex_classHierarchy].firstObject, [self class]);
+    XCTAssertEqual([FLEXTests flex_classHierarchy].lastObject, [NSObject class]);
+}
+
+- (void)testAssumptionsAboutClasses {
+    Class cls = [self class];
+    Class meta = objc_getMetaClass(NSStringFromClass(cls).UTF8String);
+
+    // Subsequent `class` calls yield self
+    XCTAssertEqual(cls, [cls class]);
+    XCTAssertEqual(meta, [meta class]);
+    // A class's superclass is NOT a metaclass
+    XCTAssertFalse(class_isMetaClass([cls superclass]));
+    // A metaclass's superclass IS a metaclass
+    XCTAssertTrue(class_isMetaClass([meta superclass]));
+
+    // Subsequent object_getClass calls yield metaclass
+    XCTAssertEqual(object_getClass(cls), meta);
+    XCTAssertEqual(object_getClass(meta), meta);
+
+    // Superclass of a root class is nil
+    XCTAssertNil([NSObject superclass]);
+}
+
+- (void)testAssumptionsAboutMessageSending {
+    // "instances respond to selector" works with metaclasses targeting class objects
+    Class meta = object_getClass(NSBundle.class);
+    XCTAssertTrue([meta instancesRespondToSelector:@selector(mainBundle)]);
+    XCTAssertFalse([meta respondsToSelector:@selector(mainBundle)]);
+}
+
+- (void)testAssumptionsAboutRuntimeMethodFunctions {
+    Class cls = [NSBundle class];
+    Class meta = object_getClass(cls);
+
+    Method bundleID = class_getInstanceMethod(cls, @selector(bundleIdentifier));
+    Method mainBundle = class_getClassMethod(cls, @selector(mainBundle));
+
+    // Preconditions...
+    XCTAssert(class_isMetaClass(meta));
+    XCTAssert(bundleID != nil);
+    XCTAssert(mainBundle != nil);
+
+    // Metaclasses cannot find instance methods
+    XCTAssertEqual(nil, class_getInstanceMethod(meta, @selector(bundleIdentifier)));
+    // Metaclasses can find class methods as both class methods and instance methods,
+    // and the methods found by metaclasses are equal regardless of which function is used
+    XCTAssertEqual(mainBundle, class_getClassMethod(meta, @selector(mainBundle)));
+    // Metaclasses can find class methods as instance methods
+    XCTAssertEqual(mainBundle, class_getInstanceMethod(meta, @selector(mainBundle)));
+}
+
+- (void)testAbilitiesOfKVC {
+    [self setValue:@5 forKey:@"foo"];
+    XCTAssertEqualObjects(self.foo, @5);
+}
+
+- (void)testCPPTypeEncoding {
+    const char *type = "{basic_string<char, std::__1::char_traits<char>, "
+    "std::__1::allocator<char> >={__compressed_pair<std::__1::basic_string<char, "
+    "std::__1::char_traits<char>, std::__1::allocator<char> >::__rep, "
+    "std::__1::allocator<char> >={__rep}}}";
+
+    XCTAssertThrows(NSGetSizeAndAlignment(type, nil, nil));
+}
+
+- (void)testGetClassProperties {
+    NSArray *props = [NSBundle flex_allClassProperties];
+    props = [props flex_filtered:^BOOL(FLEXProperty *obj, NSUInteger idx) {
+        return [obj.name isEqualToString:@"mainBundle"];
+    }];
+    XCTAssert(props.count == 1);
+}
+
+@end