FLEXTests.m 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. //
  2. // FLEXTests.m
  3. // FLEXTests
  4. //
  5. // Created by Tanner Bennett on 8/27/19.
  6. // Copyright © 2019 Flipboard. All rights reserved.
  7. //
  8. #import <XCTest/XCTest.h>
  9. #import <objc/runtime.h>
  10. #import "NSObject+Reflection.h"
  11. #import "NSArray+Functional.h"
  12. #import "FLEXPropertyAttributes.h"
  13. #import "FLEXProperty.h"
  14. #import "FLEXUtility.h"
  15. #import "FLEXMethod.h"
  16. @interface Subclass : NSObject @end
  17. @implementation Subclass @end
  18. @interface FLEXTests : XCTestCase
  19. @property (nonatomic, setter=setMyFoo:) id foo;
  20. @end
  21. @implementation FLEXTests
  22. - (void)testRuntimeAdditions {
  23. XCTAssertEqual(1, [NSObject flex_classHierarchy].count);
  24. XCTAssertEqual(4, [FLEXTests flex_classHierarchy].count);
  25. XCTAssertEqual([FLEXTests flex_classHierarchy].firstObject, [self class]);
  26. XCTAssertEqual([FLEXTests flex_classHierarchy].lastObject, [NSObject class]);
  27. }
  28. - (void)testAssumptionsAboutClasses {
  29. Class cls = [self class];
  30. Class meta = objc_getMetaClass(NSStringFromClass(cls).UTF8String);
  31. // Subsequent `class` calls yield self
  32. XCTAssertEqual(cls, [cls class]);
  33. XCTAssertEqual(meta, [meta class]);
  34. // A class's superclass is NOT a metaclass
  35. XCTAssertFalse(class_isMetaClass([cls superclass]));
  36. // A metaclass's superclass IS a metaclass
  37. XCTAssertTrue(class_isMetaClass([meta superclass]));
  38. // Subsequent object_getClass calls yield metaclass
  39. XCTAssertEqual(object_getClass(cls), meta);
  40. XCTAssertEqual(object_getClass(meta), meta);
  41. // Superclass of a root class is nil
  42. XCTAssertNil([NSObject superclass]);
  43. }
  44. - (void)testAssumptionsAboutMessageSending {
  45. // "instances respond to selector" works with metaclasses targeting class objects
  46. Class meta = object_getClass(NSBundle.class);
  47. XCTAssertTrue([meta instancesRespondToSelector:@selector(mainBundle)]);
  48. XCTAssertFalse([meta respondsToSelector:@selector(mainBundle)]);
  49. }
  50. - (void)testAssumptionsAboutRuntimeMethodFunctions {
  51. Class cls = [NSBundle class];
  52. Class meta = object_getClass(cls);
  53. Method bundleID = class_getInstanceMethod(cls, @selector(bundleIdentifier));
  54. Method mainBundle = class_getClassMethod(cls, @selector(mainBundle));
  55. // Preconditions...
  56. XCTAssert(class_isMetaClass(meta));
  57. XCTAssert(bundleID != nil);
  58. XCTAssert(mainBundle != nil);
  59. // Metaclasses cannot find instance methods
  60. XCTAssertEqual(nil, class_getInstanceMethod(meta, @selector(bundleIdentifier)));
  61. // Metaclasses can find class methods as both class methods and instance methods,
  62. // and the methods found by metaclasses are equal regardless of which function is used
  63. XCTAssertEqual(mainBundle, class_getClassMethod(meta, @selector(mainBundle)));
  64. // Metaclasses can find class methods as instance methods
  65. XCTAssertEqual(mainBundle, class_getInstanceMethod(meta, @selector(mainBundle)));
  66. }
  67. - (void)testAbilitiesOfKVC {
  68. [self setValue:@5 forKey:@"foo"];
  69. XCTAssertEqualObjects(self.foo, @5);
  70. }
  71. - (void)testCPPTypeEncoding {
  72. const char *type = "{basic_string<char, std::__1::char_traits<char>, "
  73. "std::__1::allocator<char> >={__compressed_pair<std::__1::basic_string<char, "
  74. "std::__1::char_traits<char>, std::__1::allocator<char> >::__rep, "
  75. "std::__1::allocator<char> >={__rep}}}";
  76. XCTAssertThrows(NSGetSizeAndAlignment(type, nil, nil));
  77. }
  78. - (void)testGetClassProperties {
  79. NSArray *props = [NSBundle flex_allClassProperties];
  80. props = [props flex_filtered:^BOOL(FLEXProperty *obj, NSUInteger idx) {
  81. return [obj.name isEqualToString:@"mainBundle"];
  82. }];
  83. XCTAssert(props.count == 1);
  84. }
  85. @end