1// Copyright 2021-present 650 Industries. All rights reserved.
2
3#import <XCTest/XCTest.h>
4
5#import <objc/runtime.h>
6#import <EXDevLauncher/EXDevLauncher.h>
7#import <EXDevLauncher/EXDevLauncherController.h>
8
9@import EXManifests;
10
11@interface EXDevLauncherController (EXDevLauncherModuleTests)
12
13- (EXManifestsManifest * _Nullable)mockAppManifest;
14- (NSURL *)mockAppManifestURL;
15
16@end
17
18@implementation EXDevLauncherController (EXDevLauncherModuleTests)
19
20- (EXManifestsManifest * _Nullable)mockAppManifest
21{
22  return [EXManifestsManifestFactory manifestForManifestJSON:@{
23    @"name": @"testproject",
24    @"slug": @"testproject",
25    @"version": @"1.0.0",
26    @"sdkVersion": @"42.0.0",
27    @"bundleUrl": @"http://test.io/bundle.js"
28  }];
29}
30
31- (NSURL *)mockAppManifestURL
32{
33  return [NSURL URLWithString:@"https://exp.host/@test/test?query=param"];
34}
35
36@end
37
38@interface EXDevLauncherModuleTests : XCTestCase
39
40@end
41
42@implementation EXDevLauncherModuleTests
43
44// https://nshipster.com/method-swizzling/
45- (void)swizzleMethodForClass:(Class)class
46             originalSelector:(SEL)originalSelector
47             swizzledSelector:(SEL)swizzledSelector
48{
49  Method originalMethod = class_getInstanceMethod(class, originalSelector);
50  Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
51
52  BOOL didAddMethod =
53  class_addMethod(class,
54                  originalSelector,
55                  method_getImplementation(swizzledMethod),
56                  method_getTypeEncoding(swizzledMethod));
57
58  if (didAddMethod) {
59    class_replaceMethod(class,
60                        swizzledSelector,
61                        method_getImplementation(originalMethod),
62                        method_getTypeEncoding(originalMethod));
63  } else {
64    method_exchangeImplementations(originalMethod, swizzledMethod);
65  }
66}
67
68- (void)testConstantsToExportManifest
69{
70  [self swizzleMethodForClass:[EXDevLauncherController class]
71             originalSelector:@selector(appManifest)
72             swizzledSelector:@selector(mockAppManifest)];
73
74  EXDevLauncher *module = [EXDevLauncher new];
75  NSDictionary *constants = [module constantsToExport];
76
77  NSDictionary *expected = @{
78    @"name": @"testproject",
79    @"slug": @"testproject",
80    @"version": @"1.0.0",
81    @"sdkVersion": @"42.0.0",
82    @"bundleUrl": @"http://test.io/bundle.js"
83  };
84  NSDictionary *actual = [NSJSONSerialization JSONObjectWithData:[constants[@"manifestString"] dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:NULL];
85  XCTAssertEqualObjects(expected, actual);
86
87  // clean up
88  [self swizzleMethodForClass:[EXDevLauncherController class]
89             originalSelector:@selector(appManifest)
90             swizzledSelector:@selector(mockAppManifest)];
91}
92
93- (void)testConstantsToExportManifestURL
94{
95  // used by snack
96
97  [self swizzleMethodForClass:[EXDevLauncherController class]
98             originalSelector:@selector(appManifestURL)
99             swizzledSelector:@selector(mockAppManifestURL)];
100
101  EXDevLauncher *module = [EXDevLauncher new];
102  NSDictionary *constants = [module constantsToExport];
103  XCTAssertEqualObjects(@"https://exp.host/@test/test?query=param", constants[@"manifestURL"]);
104
105  // clean up
106  [self swizzleMethodForClass:[EXDevLauncherController class]
107             originalSelector:@selector(appManifestURL)
108             swizzledSelector:@selector(mockAppManifestURL)];
109}
110
111@end
112