├── .gitignore ├── .gitmodules ├── .hound.yml ├── .swift-version ├── .swiftlint.yml ├── .travis.yml ├── CHANGELOG.md ├── Cartfile.private ├── Cartfile.resolved ├── Configurations ├── Base.xcconfig ├── Base_XCTest.xcconfig ├── Framework.xcconfig ├── Framework_XCTest.xcconfig └── Test.xcconfig ├── Documentations └── Reference.md ├── Examples └── SampleApp │ ├── Cartfile │ ├── Cartfile.private │ ├── Cartfile.resolved │ ├── SampleApp.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata │ ├── SampleApp │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ ├── Info.plist │ ├── Main.storyboard │ └── TopVC.swift │ └── SampleAppTests │ ├── Info.plist │ ├── SampleAppTests.swift │ └── sample.json ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── Package.swift ├── README.md ├── Replacer.podspec ├── Replacer.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ ├── Replacer.xcscheme │ └── TestReplacer.xcscheme ├── Replacer.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── Sources ├── Replacer │ ├── Info.plist │ ├── Replacer.h │ ├── Replacer.swift │ ├── URLSessionConfiguration+.swift │ ├── URLStub.swift │ ├── URLStubManager.swift │ └── URLStubProtocol.swift └── TestReplacer │ ├── Info.plist │ ├── TestReplacer.h │ └── XCTest+.swift ├── TestReplacer.podspec ├── Tests ├── ReplacerTests │ ├── Info.plist │ └── ReplacerTests.swift └── TestReplacerTests │ ├── Info.plist │ ├── TestReplacerTests.swift │ └── sample.json └── codecov.yml /.gitignore: -------------------------------------------------------------------------------- 1 | ### https://raw.github.com/github/gitignore/e313e296c1e284d908adcb95bf4f2812617d4de1/Global/macOS.gitignore 2 | 3 | # General 4 | .DS_Store 5 | .AppleDouble 6 | .LSOverride 7 | 8 | # Icon must end with two \r 9 | Icon 10 | 11 | # Thumbnails 12 | ._* 13 | 14 | # Files that might appear in the root of a volume 15 | .DocumentRevisions-V100 16 | .fseventsd 17 | .Spotlight-V100 18 | .TemporaryItems 19 | .Trashes 20 | .VolumeIcon.icns 21 | .com.apple.timemachine.donotpresent 22 | 23 | # Directories potentially created on remote AFP share 24 | .AppleDB 25 | .AppleDesktop 26 | Network Trash Folder 27 | Temporary Items 28 | .apdisk 29 | 30 | 31 | ### https://raw.github.com/github/gitignore/e313e296c1e284d908adcb95bf4f2812617d4de1/Global/Xcode.gitignore 32 | 33 | # Xcode 34 | # 35 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 36 | 37 | ## User settings 38 | xcuserdata/ 39 | 40 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 41 | *.xcscmblueprint 42 | *.xccheckout 43 | 44 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 45 | build/ 46 | DerivedData/ 47 | *.moved-aside 48 | *.pbxuser 49 | !default.pbxuser 50 | *.mode1v3 51 | !default.mode1v3 52 | *.mode2v3 53 | !default.mode2v3 54 | *.perspectivev3 55 | !default.perspectivev3 56 | 57 | 58 | ### https://raw.github.com/github/gitignore/e313e296c1e284d908adcb95bf4f2812617d4de1/Swift.gitignore 59 | 60 | # Xcode 61 | # 62 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 63 | 64 | ## Build generated 65 | build/ 66 | DerivedData/ 67 | 68 | ## Various settings 69 | *.pbxuser 70 | !default.pbxuser 71 | *.mode1v3 72 | !default.mode1v3 73 | *.mode2v3 74 | !default.mode2v3 75 | *.perspectivev3 76 | !default.perspectivev3 77 | xcuserdata/ 78 | 79 | ## Other 80 | *.moved-aside 81 | *.xccheckout 82 | *.xcscmblueprint 83 | 84 | ## Obj-C/Swift specific 85 | *.hmap 86 | *.ipa 87 | *.dSYM.zip 88 | *.dSYM 89 | 90 | ## Playgrounds 91 | timeline.xctimeline 92 | playground.xcworkspace 93 | 94 | # Swift Package Manager 95 | # 96 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 97 | # Packages/ 98 | # Package.pins 99 | # Package.resolved 100 | .build/ 101 | 102 | # CocoaPods 103 | # 104 | # We recommend against adding the Pods directory to your .gitignore. However 105 | # you should judge for yourself, the pros and cons are mentioned at: 106 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 107 | # 108 | # Pods/ 109 | # 110 | # Add this line if you want to avoid checking in source code from the Xcode workspace 111 | # *.xcworkspace 112 | 113 | # Carthage 114 | # 115 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 116 | # Carthage/Checkouts 117 | 118 | Carthage/Build 119 | 120 | # fastlane 121 | # 122 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 123 | # screenshots whenever they are needed. 124 | # For more information about the recommended setup visit: 125 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 126 | 127 | fastlane/report.xml 128 | fastlane/Preview.html 129 | fastlane/screenshots/**/*.png 130 | fastlane/test_output 131 | 132 | # Code Injection 133 | # 134 | # After new code Injection tools there's a generated folder /iOSInjectionProject 135 | # https://github.com/johnno1962/injectionforxcode 136 | 137 | iOSInjectionProject/ 138 | 139 | 140 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Carthage/Checkouts/Alamofire"] 2 | url = https://github.com/Alamofire/Alamofire.git 3 | -------------------------------------------------------------------------------- /.hound.yml: -------------------------------------------------------------------------------- 1 | swift: 2 | enabled: true 3 | config_file: .swiftlint.yml 4 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 5.0 2 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - force_cast 3 | - line_length 4 | - trailing_whitespace 5 | - nesting 6 | - opening_brace 7 | - valid_docs 8 | - type_name 9 | - trailing_comma 10 | - mark 11 | - variable_name 12 | - vertical_whitespace 13 | - function_parameter_count 14 | 15 | excluded: 16 | - Carthage 17 | - Packages 18 | - Tests 19 | - Examples 20 | 21 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | osx_image: xcode10.2 3 | 4 | env: 5 | global: 6 | - LC_CTYPE=en_US.UTF-8 7 | - WORKSPACE=Replacer.xcworkspace 8 | - CONFIG=Release 9 | - ACTION="build-for-testing test-without-building" 10 | 11 | branches: 12 | only: 13 | - master 14 | 15 | cache: 16 | bundler: true 17 | directories: 18 | - Carthage 19 | 20 | matrix: 21 | include: 22 | - env: JOB=pod_lint 23 | script: 24 | - bundle 25 | - pod lib lint --quick 26 | 27 | - env: JOB=xcode SCHEME=Replacer XCODE_OPTION="" 28 | - env: JOB=xcode SCHEME=Replacer XCODE_OPTION="-sdk macosx" 29 | - env: JOB=xcode SCHEME=Replacer DESTINATION="OS=12.2,name=iPhone XS" XCODE_OPTION="-sdk iphonesimulator" 30 | - env: JOB=xcode SCHEME=Replacer DESTINATION="OS=12.2,name=Apple TV 4K" XCODE_OPTION="-sdk appletvsimulator" 31 | 32 | - env: JOB=xcode SCHEME=TestReplacer DESTINATION="OS=11.4,name=iPhone X" XCODE_OPTION="" 33 | - env: JOB=xcode SCHEME=TestReplacer XCODE_OPTION="-sdk macosx" 34 | - env: JOB=xcode SCHEME=TestReplacer DESTINATION="OS=11.4,name=iPhone X" XCODE_OPTION="-sdk iphonesimulator" 35 | - env: JOB=xcode SCHEME=TestReplacer DESTINATION="OS=12.2,name=Apple TV 4K" XCODE_OPTION="-sdk appletvsimulator" 36 | 37 | - env: JOB=swiftpm 38 | os: osx 39 | language: generic 40 | script: 41 | - swift build 42 | - swift test -Xswiftc -DSWIFTPM 43 | 44 | script: 45 | - set -o pipefail 46 | - if [ -v DESTINATION ]; then 47 | xcodebuild $ACTION -workspace "$WORKSPACE" -scheme "$SCHEME" $XCODE_OPTION -destination "$DESTINATION" -configuration "$CONFIG" ENABLE_TESTABILITY=YES | xcpretty; 48 | else 49 | xcodebuild $ACTION -workspace "$WORKSPACE" -scheme "$SCHEME" $XCODE_OPTION -configuration "$CONFIG" ENABLE_TESTABILITY=YES | xcpretty; 50 | fi 51 | 52 | before_script: 53 | - carthage bootstrap --cache-builds 54 | 55 | after_success: 56 | - | 57 | if [ "$JOB" == "xcode" ] && [ -z "$XCODE_OPTION" ]; then 58 | bash <(curl -s https://codecov.io/bash) 59 | fi 60 | sleep 10 61 | 62 | notifications: 63 | email: false 64 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Refer to [Release Notes](https://github.com/tattn/Replacer/releases). 2 | -------------------------------------------------------------------------------- /Cartfile.private: -------------------------------------------------------------------------------- 1 | github "Alamofire/Alamofire" 2 | -------------------------------------------------------------------------------- /Cartfile.resolved: -------------------------------------------------------------------------------- 1 | github "Alamofire/Alamofire" "4.9.0" 2 | -------------------------------------------------------------------------------- /Configurations/Base.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Base.xcconfig 3 | // Replacer 4 | // 5 | // Created by Tatsuya Tanaka on 2017/02/12. 6 | // Copyright © 2017年 tattn. All rights reserved. 7 | // 8 | 9 | SUPPORTED_PLATFORMS = macosx iphonesimulator iphoneos watchos watchsimulator appletvos appletvsimulator 10 | VALID_ARCHS[sdk=macosx*] = i386 x86_64 11 | VALID_ARCHS[sdk=iphoneos*] = arm64 armv7 armv7s 12 | VALID_ARCHS[sdk=iphonesimulator*] = i386 x86_64 13 | VALID_ARCHS[sdk=watchos*] = armv7k 14 | VALID_ARCHS[sdk=watchsimulator*] = i386 15 | VALID_ARCHS[sdk=appletv*] = arm64 16 | VALID_ARCHS[sdk=appletvsimulator*] = x86_64 17 | 18 | LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = $(inherited) '@executable_path/../Frameworks' '@loader_path/Frameworks' 19 | LD_RUNPATH_SEARCH_PATHS[sdk=iphoneos*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 20 | LD_RUNPATH_SEARCH_PATHS[sdk=iphonesimulator*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 21 | LD_RUNPATH_SEARCH_PATHS[sdk=watchos*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 22 | LD_RUNPATH_SEARCH_PATHS[sdk=watchsimulator*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 23 | LD_RUNPATH_SEARCH_PATHS[sdk=appletvos*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 24 | LD_RUNPATH_SEARCH_PATHS[sdk=appletvsimulator*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 25 | -------------------------------------------------------------------------------- /Configurations/Base_XCTest.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Base_XCTest.xcconfig 3 | // Replacer 4 | // 5 | // Created by Tatsuya Tanaka on 2017/02/12. 6 | // Copyright © 2017年 tattn. All rights reserved. 7 | // 8 | 9 | SUPPORTED_PLATFORMS = macosx iphonesimulator iphoneos appletvos appletvsimulator 10 | VALID_ARCHS[sdk=macosx*] = i386 x86_64 11 | VALID_ARCHS[sdk=iphoneos*] = arm64 armv7 armv7s 12 | VALID_ARCHS[sdk=iphonesimulator*] = i386 x86_64 13 | VALID_ARCHS[sdk=appletv*] = arm64 14 | VALID_ARCHS[sdk=appletvsimulator*] = x86_64 15 | 16 | LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = $(inherited) '@executable_path/../Frameworks' '@loader_path/Frameworks' 17 | LD_RUNPATH_SEARCH_PATHS[sdk=iphoneos*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 18 | LD_RUNPATH_SEARCH_PATHS[sdk=iphonesimulator*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 19 | LD_RUNPATH_SEARCH_PATHS[sdk=appletvos*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 20 | LD_RUNPATH_SEARCH_PATHS[sdk=appletvsimulator*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 21 | -------------------------------------------------------------------------------- /Configurations/Framework.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Framework.xcconfig 3 | // Replacer 4 | // 5 | // Created by Tatsuya Tanaka on 2017/02/12. 6 | // Copyright © 2017年 tattn. All rights reserved. 7 | // 8 | 9 | #include "Base.xcconfig" 10 | 11 | // OSX 12 | FRAMEWORK_VERSION[sdk=macosx*] = A 13 | COMBINE_HIDPI_IMAGES[sdk=macosx*] = YES 14 | 15 | // iOS 16 | CODE_SIGN_IDENTITY[sdk=iphoneos*] = iPhone Developer 17 | TARGETED_DEVICE_FAMILY[sdk=iphonesimulator*] = 1,2 18 | TARGETED_DEVICE_FAMILY[sdk=iphone*] = 1,2 19 | 20 | // TV 21 | TARGETED_DEVICE_FAMILY[sdk=appletvsimulator*] = 3 22 | TARGETED_DEVICE_FAMILY[sdk=appletv*] = 3 23 | 24 | // Watch 25 | TARGETED_DEVICE_FAMILY[sdk=watchsimulator*] = 4 26 | TARGETED_DEVICE_FAMILY[sdk=watch*] = 4 27 | 28 | ENABLE_BITCODE[sdk=macosx*] = NO 29 | ENABLE_BITCODE[sdk=watchsimulator*] = NO 30 | ENABLE_BITCODE[sdk=watch*] = NO 31 | ENABLE_BITCODE[sdk=iphonesimulator*] = NO 32 | ENABLE_BITCODE[sdk=iphone*] = NO 33 | ENABLE_BITCODE[sdk=appletvsimulator*] = NO 34 | ENABLE_BITCODE[sdk=appletv*] = NO 35 | -------------------------------------------------------------------------------- /Configurations/Framework_XCTest.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Framework_XCTest.xcconfig 3 | // Replacer 4 | // 5 | // Created by Tatsuya Tanaka on 2017/02/12. 6 | // Copyright © 2017年 tattn. All rights reserved. 7 | // 8 | 9 | #include "Base_XCTest.xcconfig" 10 | 11 | // OSX 12 | FRAMEWORK_VERSION[sdk=macosx*] = A 13 | COMBINE_HIDPI_IMAGES[sdk=macosx*] = YES 14 | 15 | // iOS 16 | CODE_SIGN_IDENTITY[sdk=iphoneos*] = iPhone Developer 17 | TARGETED_DEVICE_FAMILY[sdk=iphonesimulator*] = 1,2 18 | TARGETED_DEVICE_FAMILY[sdk=iphone*] = 1,2 19 | 20 | // TV 21 | TARGETED_DEVICE_FAMILY[sdk=appletvsimulator*] = 3 22 | TARGETED_DEVICE_FAMILY[sdk=appletv*] = 3 23 | 24 | ENABLE_BITCODE[sdk=macosx*] = NO 25 | ENABLE_BITCODE[sdk=iphonesimulator*] = NO 26 | ENABLE_BITCODE[sdk=iphone*] = NO 27 | ENABLE_BITCODE[sdk=appletvsimulator*] = NO 28 | ENABLE_BITCODE[sdk=appletv*] = NO 29 | -------------------------------------------------------------------------------- /Configurations/Test.xcconfig: -------------------------------------------------------------------------------- 1 | // 2 | // Test.xcconfig 3 | // Replacer 4 | // 5 | // Created by Tatsuya Tanaka on 2017/02/12. 6 | // Copyright © 2017年 tattn. All rights reserved. 7 | // 8 | 9 | #include "Base.xcconfig" 10 | 11 | FRAMEWORK_SEARCH_PATHS = $(inherited) '$(PLATFORM_DIR)/Developer/Library/Frameworks' 12 | 13 | LD_RUNPATH_SEARCH_PATHS[sdk=macosx*] = $(inherited) '@executable_path/../Frameworks' '@loader_path/../Frameworks' 14 | LD_RUNPATH_SEARCH_PATHS[sdk=iphoneos*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 15 | LD_RUNPATH_SEARCH_PATHS[sdk=iphonesimulator*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 16 | LD_RUNPATH_SEARCH_PATHS[sdk=appletvos*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 17 | LD_RUNPATH_SEARCH_PATHS[sdk=appletvsimulator*] = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 18 | -------------------------------------------------------------------------------- /Documentations/Reference.md: -------------------------------------------------------------------------------- 1 | # Stub Reference 2 | 3 | ## `stub` 4 | 5 | Register a stub. 6 | Registered stub at a previous takes precedence. 7 | 8 | Following option methods can chain them. 9 | 10 | ```swift 11 | self.urlStub.url("http://example.com") 12 | .httpMethod(.post) 13 | .delay(1.5) 14 | .json(["test": "data"]) 15 | ``` 16 | 17 | ## `urlStub.url(_)` 18 | 19 | Set an URL of the reuqest you want to stub. 20 | You can set a regular expression. 21 | 22 | ```swift 23 | self.urlStub.url("http://example.com") 24 | self.urlStub.url("http://example.com/[0-9]+/") 25 | 26 | self.urlStub.url("*") 27 | // equal to: self.urlStub.url("") 28 | // equal to: self.urlStub 29 | ``` 30 | 31 | ## `urlStub.json(_)` 32 | 33 | Set a JSON as response. 34 | 35 | ```swift 36 | self.urlStub.json(["test": "data"]) 37 | ``` 38 | 39 | ## `urlStub.json(filename: _)` 40 | 41 | Set a JSON as response from the file in bundle. 42 | 43 | ```swift 44 | self.urlStub.json(filename: "fixture") // load fixture.json 45 | ``` 46 | ## `urlStub.error(_)` 47 | 48 | Set an error as response. 49 | 50 | ```swift 51 | self.urlStub.error(NSError()) 52 | ``` 53 | 54 | ## `urlStub.delay(_)` 55 | 56 | Set a delay of response. 57 | The delay unit is second. 58 | 59 | ```swift 60 | self.urlStub.json(["test": "data"]).delay(0.5) // 500ms 61 | ``` 62 | 63 | ## `urlStub.response(block: _)` 64 | 65 | Set a closure which returns a custom response 66 | 67 | ```swift 68 | self.urlStub.response { result in 69 | if request.allHTTPHeaderFields["User-Agent"] == "😀" { 70 | let json = try! JSONSerialization.data(withJSONObject: ["face": "smile"], options: .prettyPrinted) 71 | return (json, nil) 72 | } 73 | return (nil, NSError(domain: "", code: 0)) 74 | } 75 | ``` 76 | 77 | ## `urlStub.statusCode(_)` 78 | 79 | Set a status code of response. 80 | 81 | ```swift 82 | self.urlStub.statusCode(400) 83 | ``` 84 | 85 | -------------------------------------------------------------------------------- /Examples/SampleApp/Cartfile: -------------------------------------------------------------------------------- 1 | # git "git@github.com:tattn/Replacer.git" 2 | git "~/work/iOS/Mokei/Replacer" 3 | github "Alamofire/Alamofire" 4 | -------------------------------------------------------------------------------- /Examples/SampleApp/Cartfile.private: -------------------------------------------------------------------------------- 1 | github "Quick/Quick" 2 | github "Quick/Nimble" 3 | -------------------------------------------------------------------------------- /Examples/SampleApp/Cartfile.resolved: -------------------------------------------------------------------------------- 1 | github "Alamofire/Alamofire" "4.3.0" 2 | github "Quick/Nimble" "v6.0.1" 3 | github "Quick/Quick" "v1.1.0" 4 | git "~/work/iOS/Mokei/Replacer" "0.0.7" 5 | -------------------------------------------------------------------------------- /Examples/SampleApp/SampleApp.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 244D70071E4FA4D1007AE072 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 244D70061E4FA4D1007AE072 /* AppDelegate.swift */; }; 11 | 244D70091E4FA4D1007AE072 /* TopVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 244D70081E4FA4D1007AE072 /* TopVC.swift */; }; 12 | 244D700E1E4FA4D1007AE072 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 244D700D1E4FA4D1007AE072 /* Assets.xcassets */; }; 13 | 244D70111E4FA4D1007AE072 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 244D700F1E4FA4D1007AE072 /* LaunchScreen.storyboard */; }; 14 | 244D701C1E4FA4D1007AE072 /* SampleAppTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 244D701B1E4FA4D1007AE072 /* SampleAppTests.swift */; }; 15 | 244D70271E4FA5BD007AE072 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 244D70261E4FA5BD007AE072 /* Main.storyboard */; }; 16 | 244D70381E5047F0007AE072 /* Replacer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 244D70361E5047F0007AE072 /* Replacer.framework */; }; 17 | 244D70391E5047F0007AE072 /* TestReplacer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 244D70371E5047F0007AE072 /* TestReplacer.framework */; }; 18 | 244D703B1E5049BF007AE072 /* Alamofire.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 244D703A1E5049BF007AE072 /* Alamofire.framework */; }; 19 | 244D703E1E5049D6007AE072 /* Nimble.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 244D703C1E5049D6007AE072 /* Nimble.framework */; }; 20 | 244D703F1E5049D6007AE072 /* Quick.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 244D703D1E5049D6007AE072 /* Quick.framework */; }; 21 | 244D70441E504BA9007AE072 /* Nimble.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 244D703C1E5049D6007AE072 /* Nimble.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 22 | 244D70451E504BA9007AE072 /* Quick.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 244D703D1E5049D6007AE072 /* Quick.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 23 | 244D70461E504BD6007AE072 /* TestReplacer.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 244D70371E5047F0007AE072 /* TestReplacer.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 24 | 244D70471E504BDC007AE072 /* Replacer.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 244D70361E5047F0007AE072 /* Replacer.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 25 | 244D70491E504C26007AE072 /* sample.json in Resources */ = {isa = PBXBuildFile; fileRef = 244D70481E504C26007AE072 /* sample.json */; }; 26 | 244D704F1E50654C007AE072 /* Replacer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 244D70361E5047F0007AE072 /* Replacer.framework */; }; 27 | /* End PBXBuildFile section */ 28 | 29 | /* Begin PBXContainerItemProxy section */ 30 | 244D70181E4FA4D1007AE072 /* PBXContainerItemProxy */ = { 31 | isa = PBXContainerItemProxy; 32 | containerPortal = 244D6FFB1E4FA4D1007AE072 /* Project object */; 33 | proxyType = 1; 34 | remoteGlobalIDString = 244D70021E4FA4D1007AE072; 35 | remoteInfo = SampleApp; 36 | }; 37 | /* End PBXContainerItemProxy section */ 38 | 39 | /* Begin PBXCopyFilesBuildPhase section */ 40 | 244D70431E504B9F007AE072 /* CopyFiles */ = { 41 | isa = PBXCopyFilesBuildPhase; 42 | buildActionMask = 2147483647; 43 | dstPath = ""; 44 | dstSubfolderSpec = 10; 45 | files = ( 46 | 244D70471E504BDC007AE072 /* Replacer.framework in CopyFiles */, 47 | 244D70461E504BD6007AE072 /* TestReplacer.framework in CopyFiles */, 48 | 244D70441E504BA9007AE072 /* Nimble.framework in CopyFiles */, 49 | 244D70451E504BA9007AE072 /* Quick.framework in CopyFiles */, 50 | ); 51 | runOnlyForDeploymentPostprocessing = 0; 52 | }; 53 | /* End PBXCopyFilesBuildPhase section */ 54 | 55 | /* Begin PBXFileReference section */ 56 | 244D70031E4FA4D1007AE072 /* SampleApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SampleApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 57 | 244D70061E4FA4D1007AE072 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 58 | 244D70081E4FA4D1007AE072 /* TopVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopVC.swift; sourceTree = ""; }; 59 | 244D700D1E4FA4D1007AE072 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 60 | 244D70101E4FA4D1007AE072 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 61 | 244D70121E4FA4D1007AE072 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 62 | 244D70171E4FA4D1007AE072 /* SampleAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SampleAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 63 | 244D701B1E4FA4D1007AE072 /* SampleAppTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SampleAppTests.swift; sourceTree = ""; }; 64 | 244D701D1E4FA4D1007AE072 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 65 | 244D70261E4FA5BD007AE072 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; 66 | 244D70361E5047F0007AE072 /* Replacer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Replacer.framework; path = Carthage/Build/iOS/Replacer.framework; sourceTree = ""; }; 67 | 244D70371E5047F0007AE072 /* TestReplacer.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TestReplacer.framework; path = Carthage/Build/iOS/TestReplacer.framework; sourceTree = ""; }; 68 | 244D703A1E5049BF007AE072 /* Alamofire.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Alamofire.framework; path = Carthage/Build/iOS/Alamofire.framework; sourceTree = ""; }; 69 | 244D703C1E5049D6007AE072 /* Nimble.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Nimble.framework; path = Carthage/Build/iOS/Nimble.framework; sourceTree = ""; }; 70 | 244D703D1E5049D6007AE072 /* Quick.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quick.framework; path = Carthage/Build/iOS/Quick.framework; sourceTree = ""; }; 71 | 244D70481E504C26007AE072 /* sample.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = sample.json; sourceTree = ""; }; 72 | /* End PBXFileReference section */ 73 | 74 | /* Begin PBXFrameworksBuildPhase section */ 75 | 244D70001E4FA4D1007AE072 /* Frameworks */ = { 76 | isa = PBXFrameworksBuildPhase; 77 | buildActionMask = 2147483647; 78 | files = ( 79 | 244D704F1E50654C007AE072 /* Replacer.framework in Frameworks */, 80 | 244D703B1E5049BF007AE072 /* Alamofire.framework in Frameworks */, 81 | ); 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | 244D70141E4FA4D1007AE072 /* Frameworks */ = { 85 | isa = PBXFrameworksBuildPhase; 86 | buildActionMask = 2147483647; 87 | files = ( 88 | 244D703E1E5049D6007AE072 /* Nimble.framework in Frameworks */, 89 | 244D703F1E5049D6007AE072 /* Quick.framework in Frameworks */, 90 | 244D70381E5047F0007AE072 /* Replacer.framework in Frameworks */, 91 | 244D70391E5047F0007AE072 /* TestReplacer.framework in Frameworks */, 92 | ); 93 | runOnlyForDeploymentPostprocessing = 0; 94 | }; 95 | /* End PBXFrameworksBuildPhase section */ 96 | 97 | /* Begin PBXGroup section */ 98 | 244D6FFA1E4FA4D1007AE072 = { 99 | isa = PBXGroup; 100 | children = ( 101 | 244D70051E4FA4D1007AE072 /* SampleApp */, 102 | 244D701A1E4FA4D1007AE072 /* SampleAppTests */, 103 | 244D70041E4FA4D1007AE072 /* Products */, 104 | 244D70351E5047F0007AE072 /* Frameworks */, 105 | ); 106 | sourceTree = ""; 107 | }; 108 | 244D70041E4FA4D1007AE072 /* Products */ = { 109 | isa = PBXGroup; 110 | children = ( 111 | 244D70031E4FA4D1007AE072 /* SampleApp.app */, 112 | 244D70171E4FA4D1007AE072 /* SampleAppTests.xctest */, 113 | ); 114 | name = Products; 115 | sourceTree = ""; 116 | }; 117 | 244D70051E4FA4D1007AE072 /* SampleApp */ = { 118 | isa = PBXGroup; 119 | children = ( 120 | 244D70061E4FA4D1007AE072 /* AppDelegate.swift */, 121 | 244D70081E4FA4D1007AE072 /* TopVC.swift */, 122 | 244D700D1E4FA4D1007AE072 /* Assets.xcassets */, 123 | 244D700F1E4FA4D1007AE072 /* LaunchScreen.storyboard */, 124 | 244D70121E4FA4D1007AE072 /* Info.plist */, 125 | 244D70261E4FA5BD007AE072 /* Main.storyboard */, 126 | ); 127 | path = SampleApp; 128 | sourceTree = ""; 129 | }; 130 | 244D701A1E4FA4D1007AE072 /* SampleAppTests */ = { 131 | isa = PBXGroup; 132 | children = ( 133 | 244D701B1E4FA4D1007AE072 /* SampleAppTests.swift */, 134 | 244D701D1E4FA4D1007AE072 /* Info.plist */, 135 | 244D70481E504C26007AE072 /* sample.json */, 136 | ); 137 | path = SampleAppTests; 138 | sourceTree = ""; 139 | }; 140 | 244D70351E5047F0007AE072 /* Frameworks */ = { 141 | isa = PBXGroup; 142 | children = ( 143 | 244D703C1E5049D6007AE072 /* Nimble.framework */, 144 | 244D703D1E5049D6007AE072 /* Quick.framework */, 145 | 244D703A1E5049BF007AE072 /* Alamofire.framework */, 146 | 244D70361E5047F0007AE072 /* Replacer.framework */, 147 | 244D70371E5047F0007AE072 /* TestReplacer.framework */, 148 | ); 149 | name = Frameworks; 150 | sourceTree = ""; 151 | }; 152 | /* End PBXGroup section */ 153 | 154 | /* Begin PBXNativeTarget section */ 155 | 244D70021E4FA4D1007AE072 /* SampleApp */ = { 156 | isa = PBXNativeTarget; 157 | buildConfigurationList = 244D70201E4FA4D1007AE072 /* Build configuration list for PBXNativeTarget "SampleApp" */; 158 | buildPhases = ( 159 | 244D6FFF1E4FA4D1007AE072 /* Sources */, 160 | 244D70001E4FA4D1007AE072 /* Frameworks */, 161 | 244D70011E4FA4D1007AE072 /* Resources */, 162 | 244D70401E504A36007AE072 /* Run Script - Carthage */, 163 | ); 164 | buildRules = ( 165 | ); 166 | dependencies = ( 167 | ); 168 | name = SampleApp; 169 | productName = SampleApp; 170 | productReference = 244D70031E4FA4D1007AE072 /* SampleApp.app */; 171 | productType = "com.apple.product-type.application"; 172 | }; 173 | 244D70161E4FA4D1007AE072 /* SampleAppTests */ = { 174 | isa = PBXNativeTarget; 175 | buildConfigurationList = 244D70231E4FA4D1007AE072 /* Build configuration list for PBXNativeTarget "SampleAppTests" */; 176 | buildPhases = ( 177 | 244D70131E4FA4D1007AE072 /* Sources */, 178 | 244D70141E4FA4D1007AE072 /* Frameworks */, 179 | 244D70151E4FA4D1007AE072 /* Resources */, 180 | 244D70431E504B9F007AE072 /* CopyFiles */, 181 | ); 182 | buildRules = ( 183 | ); 184 | dependencies = ( 185 | 244D70191E4FA4D1007AE072 /* PBXTargetDependency */, 186 | ); 187 | name = SampleAppTests; 188 | productName = SampleAppTests; 189 | productReference = 244D70171E4FA4D1007AE072 /* SampleAppTests.xctest */; 190 | productType = "com.apple.product-type.bundle.unit-test"; 191 | }; 192 | /* End PBXNativeTarget section */ 193 | 194 | /* Begin PBXProject section */ 195 | 244D6FFB1E4FA4D1007AE072 /* Project object */ = { 196 | isa = PBXProject; 197 | attributes = { 198 | LastSwiftUpdateCheck = 0820; 199 | LastUpgradeCheck = 0820; 200 | ORGANIZATIONNAME = tattn; 201 | TargetAttributes = { 202 | 244D70021E4FA4D1007AE072 = { 203 | CreatedOnToolsVersion = 8.2.1; 204 | ProvisioningStyle = Automatic; 205 | }; 206 | 244D70161E4FA4D1007AE072 = { 207 | CreatedOnToolsVersion = 8.2.1; 208 | ProvisioningStyle = Automatic; 209 | TestTargetID = 244D70021E4FA4D1007AE072; 210 | }; 211 | }; 212 | }; 213 | buildConfigurationList = 244D6FFE1E4FA4D1007AE072 /* Build configuration list for PBXProject "SampleApp" */; 214 | compatibilityVersion = "Xcode 3.2"; 215 | developmentRegion = English; 216 | hasScannedForEncodings = 0; 217 | knownRegions = ( 218 | en, 219 | Base, 220 | ); 221 | mainGroup = 244D6FFA1E4FA4D1007AE072; 222 | productRefGroup = 244D70041E4FA4D1007AE072 /* Products */; 223 | projectDirPath = ""; 224 | projectRoot = ""; 225 | targets = ( 226 | 244D70021E4FA4D1007AE072 /* SampleApp */, 227 | 244D70161E4FA4D1007AE072 /* SampleAppTests */, 228 | ); 229 | }; 230 | /* End PBXProject section */ 231 | 232 | /* Begin PBXResourcesBuildPhase section */ 233 | 244D70011E4FA4D1007AE072 /* Resources */ = { 234 | isa = PBXResourcesBuildPhase; 235 | buildActionMask = 2147483647; 236 | files = ( 237 | 244D70271E4FA5BD007AE072 /* Main.storyboard in Resources */, 238 | 244D70111E4FA4D1007AE072 /* LaunchScreen.storyboard in Resources */, 239 | 244D700E1E4FA4D1007AE072 /* Assets.xcassets in Resources */, 240 | ); 241 | runOnlyForDeploymentPostprocessing = 0; 242 | }; 243 | 244D70151E4FA4D1007AE072 /* Resources */ = { 244 | isa = PBXResourcesBuildPhase; 245 | buildActionMask = 2147483647; 246 | files = ( 247 | 244D70491E504C26007AE072 /* sample.json in Resources */, 248 | ); 249 | runOnlyForDeploymentPostprocessing = 0; 250 | }; 251 | /* End PBXResourcesBuildPhase section */ 252 | 253 | /* Begin PBXShellScriptBuildPhase section */ 254 | 244D70401E504A36007AE072 /* Run Script - Carthage */ = { 255 | isa = PBXShellScriptBuildPhase; 256 | buildActionMask = 2147483647; 257 | files = ( 258 | ); 259 | inputPaths = ( 260 | "$(SRCROOT)/Carthage/Build/iOS/Alamofire.framework", 261 | "$(SRCROOT)/Carthage/Build/iOS/Replacer.framework", 262 | ); 263 | name = "Run Script - Carthage"; 264 | outputPaths = ( 265 | ); 266 | runOnlyForDeploymentPostprocessing = 0; 267 | shellPath = /bin/sh; 268 | shellScript = "/usr/local/bin/carthage copy-frameworks"; 269 | }; 270 | /* End PBXShellScriptBuildPhase section */ 271 | 272 | /* Begin PBXSourcesBuildPhase section */ 273 | 244D6FFF1E4FA4D1007AE072 /* Sources */ = { 274 | isa = PBXSourcesBuildPhase; 275 | buildActionMask = 2147483647; 276 | files = ( 277 | 244D70091E4FA4D1007AE072 /* TopVC.swift in Sources */, 278 | 244D70071E4FA4D1007AE072 /* AppDelegate.swift in Sources */, 279 | ); 280 | runOnlyForDeploymentPostprocessing = 0; 281 | }; 282 | 244D70131E4FA4D1007AE072 /* Sources */ = { 283 | isa = PBXSourcesBuildPhase; 284 | buildActionMask = 2147483647; 285 | files = ( 286 | 244D701C1E4FA4D1007AE072 /* SampleAppTests.swift in Sources */, 287 | ); 288 | runOnlyForDeploymentPostprocessing = 0; 289 | }; 290 | /* End PBXSourcesBuildPhase section */ 291 | 292 | /* Begin PBXTargetDependency section */ 293 | 244D70191E4FA4D1007AE072 /* PBXTargetDependency */ = { 294 | isa = PBXTargetDependency; 295 | target = 244D70021E4FA4D1007AE072 /* SampleApp */; 296 | targetProxy = 244D70181E4FA4D1007AE072 /* PBXContainerItemProxy */; 297 | }; 298 | /* End PBXTargetDependency section */ 299 | 300 | /* Begin PBXVariantGroup section */ 301 | 244D700F1E4FA4D1007AE072 /* LaunchScreen.storyboard */ = { 302 | isa = PBXVariantGroup; 303 | children = ( 304 | 244D70101E4FA4D1007AE072 /* Base */, 305 | ); 306 | name = LaunchScreen.storyboard; 307 | sourceTree = ""; 308 | }; 309 | /* End PBXVariantGroup section */ 310 | 311 | /* Begin XCBuildConfiguration section */ 312 | 244D701E1E4FA4D1007AE072 /* Debug */ = { 313 | isa = XCBuildConfiguration; 314 | buildSettings = { 315 | ALWAYS_SEARCH_USER_PATHS = NO; 316 | CLANG_ANALYZER_NONNULL = YES; 317 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 318 | CLANG_CXX_LIBRARY = "libc++"; 319 | CLANG_ENABLE_MODULES = YES; 320 | CLANG_ENABLE_OBJC_ARC = YES; 321 | CLANG_WARN_BOOL_CONVERSION = YES; 322 | CLANG_WARN_CONSTANT_CONVERSION = YES; 323 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 324 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 325 | CLANG_WARN_EMPTY_BODY = YES; 326 | CLANG_WARN_ENUM_CONVERSION = YES; 327 | CLANG_WARN_INFINITE_RECURSION = YES; 328 | CLANG_WARN_INT_CONVERSION = YES; 329 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 330 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 331 | CLANG_WARN_UNREACHABLE_CODE = YES; 332 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 333 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 334 | COPY_PHASE_STRIP = NO; 335 | DEBUG_INFORMATION_FORMAT = dwarf; 336 | ENABLE_STRICT_OBJC_MSGSEND = YES; 337 | ENABLE_TESTABILITY = YES; 338 | GCC_C_LANGUAGE_STANDARD = gnu99; 339 | GCC_DYNAMIC_NO_PIC = NO; 340 | GCC_NO_COMMON_BLOCKS = YES; 341 | GCC_OPTIMIZATION_LEVEL = 0; 342 | GCC_PREPROCESSOR_DEFINITIONS = ( 343 | "DEBUG=1", 344 | "$(inherited)", 345 | ); 346 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 347 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 348 | GCC_WARN_UNDECLARED_SELECTOR = YES; 349 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 350 | GCC_WARN_UNUSED_FUNCTION = YES; 351 | GCC_WARN_UNUSED_VARIABLE = YES; 352 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 353 | MTL_ENABLE_DEBUG_INFO = YES; 354 | ONLY_ACTIVE_ARCH = YES; 355 | SDKROOT = iphoneos; 356 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 357 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 358 | TARGETED_DEVICE_FAMILY = "1,2"; 359 | }; 360 | name = Debug; 361 | }; 362 | 244D701F1E4FA4D1007AE072 /* Release */ = { 363 | isa = XCBuildConfiguration; 364 | buildSettings = { 365 | ALWAYS_SEARCH_USER_PATHS = NO; 366 | CLANG_ANALYZER_NONNULL = YES; 367 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 368 | CLANG_CXX_LIBRARY = "libc++"; 369 | CLANG_ENABLE_MODULES = YES; 370 | CLANG_ENABLE_OBJC_ARC = YES; 371 | CLANG_WARN_BOOL_CONVERSION = YES; 372 | CLANG_WARN_CONSTANT_CONVERSION = YES; 373 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 374 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 375 | CLANG_WARN_EMPTY_BODY = YES; 376 | CLANG_WARN_ENUM_CONVERSION = YES; 377 | CLANG_WARN_INFINITE_RECURSION = YES; 378 | CLANG_WARN_INT_CONVERSION = YES; 379 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 380 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 381 | CLANG_WARN_UNREACHABLE_CODE = YES; 382 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 383 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 384 | COPY_PHASE_STRIP = NO; 385 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 386 | ENABLE_NS_ASSERTIONS = NO; 387 | ENABLE_STRICT_OBJC_MSGSEND = YES; 388 | GCC_C_LANGUAGE_STANDARD = gnu99; 389 | GCC_NO_COMMON_BLOCKS = YES; 390 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 391 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 392 | GCC_WARN_UNDECLARED_SELECTOR = YES; 393 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 394 | GCC_WARN_UNUSED_FUNCTION = YES; 395 | GCC_WARN_UNUSED_VARIABLE = YES; 396 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 397 | MTL_ENABLE_DEBUG_INFO = NO; 398 | SDKROOT = iphoneos; 399 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 400 | TARGETED_DEVICE_FAMILY = "1,2"; 401 | VALIDATE_PRODUCT = YES; 402 | }; 403 | name = Release; 404 | }; 405 | 244D70211E4FA4D1007AE072 /* Debug */ = { 406 | isa = XCBuildConfiguration; 407 | buildSettings = { 408 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 409 | FRAMEWORK_SEARCH_PATHS = ( 410 | "$(inherited)", 411 | "$(PROJECT_DIR)/Carthage/Build/iOS", 412 | ); 413 | INFOPLIST_FILE = SampleApp/Info.plist; 414 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 415 | PRODUCT_BUNDLE_IDENTIFIER = com.github.tattn.SampleApp; 416 | PRODUCT_NAME = "$(TARGET_NAME)"; 417 | SWIFT_VERSION = 3.0; 418 | }; 419 | name = Debug; 420 | }; 421 | 244D70221E4FA4D1007AE072 /* Release */ = { 422 | isa = XCBuildConfiguration; 423 | buildSettings = { 424 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 425 | FRAMEWORK_SEARCH_PATHS = ( 426 | "$(inherited)", 427 | "$(PROJECT_DIR)/Carthage/Build/iOS", 428 | ); 429 | INFOPLIST_FILE = SampleApp/Info.plist; 430 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 431 | PRODUCT_BUNDLE_IDENTIFIER = com.github.tattn.SampleApp; 432 | PRODUCT_NAME = "$(TARGET_NAME)"; 433 | SWIFT_VERSION = 3.0; 434 | }; 435 | name = Release; 436 | }; 437 | 244D70241E4FA4D1007AE072 /* Debug */ = { 438 | isa = XCBuildConfiguration; 439 | buildSettings = { 440 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 441 | BUNDLE_LOADER = "$(TEST_HOST)"; 442 | FRAMEWORK_SEARCH_PATHS = ( 443 | "$(inherited)", 444 | "$(PROJECT_DIR)/Carthage/Build/iOS", 445 | ); 446 | INFOPLIST_FILE = SampleAppTests/Info.plist; 447 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 448 | PRODUCT_BUNDLE_IDENTIFIER = com.github.tattn.SampleAppTests; 449 | PRODUCT_NAME = "$(TARGET_NAME)"; 450 | SWIFT_VERSION = 3.0; 451 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SampleApp.app/SampleApp"; 452 | }; 453 | name = Debug; 454 | }; 455 | 244D70251E4FA4D1007AE072 /* Release */ = { 456 | isa = XCBuildConfiguration; 457 | buildSettings = { 458 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 459 | BUNDLE_LOADER = "$(TEST_HOST)"; 460 | FRAMEWORK_SEARCH_PATHS = ( 461 | "$(inherited)", 462 | "$(PROJECT_DIR)/Carthage/Build/iOS", 463 | ); 464 | INFOPLIST_FILE = SampleAppTests/Info.plist; 465 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 466 | PRODUCT_BUNDLE_IDENTIFIER = com.github.tattn.SampleAppTests; 467 | PRODUCT_NAME = "$(TARGET_NAME)"; 468 | SWIFT_VERSION = 3.0; 469 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SampleApp.app/SampleApp"; 470 | }; 471 | name = Release; 472 | }; 473 | /* End XCBuildConfiguration section */ 474 | 475 | /* Begin XCConfigurationList section */ 476 | 244D6FFE1E4FA4D1007AE072 /* Build configuration list for PBXProject "SampleApp" */ = { 477 | isa = XCConfigurationList; 478 | buildConfigurations = ( 479 | 244D701E1E4FA4D1007AE072 /* Debug */, 480 | 244D701F1E4FA4D1007AE072 /* Release */, 481 | ); 482 | defaultConfigurationIsVisible = 0; 483 | defaultConfigurationName = Release; 484 | }; 485 | 244D70201E4FA4D1007AE072 /* Build configuration list for PBXNativeTarget "SampleApp" */ = { 486 | isa = XCConfigurationList; 487 | buildConfigurations = ( 488 | 244D70211E4FA4D1007AE072 /* Debug */, 489 | 244D70221E4FA4D1007AE072 /* Release */, 490 | ); 491 | defaultConfigurationIsVisible = 0; 492 | }; 493 | 244D70231E4FA4D1007AE072 /* Build configuration list for PBXNativeTarget "SampleAppTests" */ = { 494 | isa = XCConfigurationList; 495 | buildConfigurations = ( 496 | 244D70241E4FA4D1007AE072 /* Debug */, 497 | 244D70251E4FA4D1007AE072 /* Release */, 498 | ); 499 | defaultConfigurationIsVisible = 0; 500 | }; 501 | /* End XCConfigurationList section */ 502 | }; 503 | rootObject = 244D6FFB1E4FA4D1007AE072 /* Project object */; 504 | } 505 | -------------------------------------------------------------------------------- /Examples/SampleApp/SampleApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Examples/SampleApp/SampleApp/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // SampleApp 4 | // 5 | // Created by Tatsuya Tanaka on 2017/02/12. 6 | // Copyright © 2017年 tattn. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Replacer 11 | 12 | @UIApplicationMain 13 | class AppDelegate: UIResponder, UIApplicationDelegate { 14 | 15 | var window: UIWindow? 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | 19 | replaceInstance(#selector(UIViewController.viewWillAppear(_:)), 20 | of: UIViewController.self, 21 | with: #selector(UIViewController.orig_viewWillAppear(_:)), 22 | of: UIViewController.self) 23 | 24 | return true 25 | } 26 | } 27 | 28 | extension UIViewController { 29 | func orig_viewWillAppear(_ animated: Bool) { 30 | orig_viewWillAppear(animated) 31 | 32 | print("swizzled") 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /Examples/SampleApp/SampleApp/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | } 88 | ], 89 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /Examples/SampleApp/SampleApp/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Examples/SampleApp/SampleApp/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /Examples/SampleApp/SampleApp/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Examples/SampleApp/SampleApp/TopVC.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TopVC.swift 3 | // SampleApp 4 | // 5 | // Created by Tatsuya Tanaka on 2017/02/12. 6 | // Copyright © 2017年 tattn. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import Alamofire 11 | import Replacer 12 | 13 | class TopVC: UIViewController { 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | Replacer.urlStub.url("stuburl").json(["key": "value"]) 19 | 20 | Alamofire.request("stuburl").responseJSON { response in 21 | if let json = response.result.value as? [String: String] { 22 | print("URLStub ============") 23 | print(json) 24 | } 25 | } 26 | 27 | class A: NSObject { 28 | @objc class func a() -> String { return "a" } 29 | } 30 | 31 | class B: NSObject { 32 | @objc class func b() -> String { return "b" } 33 | } 34 | 35 | 36 | replaceStatic(#selector(A.a), of: A.self, with: #selector(B.b), of: B.self) 37 | 38 | print(A.a()) 39 | 40 | replaceStatic(#selector(A.a), of: A.self, with: #selector(B.b), of: B.self) 41 | 42 | print(A.a()) 43 | } 44 | } 45 | 46 | -------------------------------------------------------------------------------- /Examples/SampleApp/SampleAppTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Examples/SampleApp/SampleAppTests/SampleAppTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SampleAppTests.swift 3 | // SampleAppTests 4 | // 5 | // Created by Tatsuya Tanaka on 2017/02/12. 6 | // Copyright © 2017年 tattn. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import Alamofire 11 | import Replacer 12 | import TestReplacer 13 | 14 | @testable import SampleApp 15 | 16 | class SampleAppTests: XCTestCase { 17 | 18 | var url = URL(string: "http://echo.jsontest.com/key/value/one/two")! 19 | 20 | func testJSONFile() { 21 | self.urlStub.url("echo.jsontest.com").json(filename: "sample") 22 | 23 | let expectation = self.expectation(description: "") 24 | 25 | URLSession.shared.dataTask(with: url) { data, _, _ in 26 | let json = try! JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [String: String] 27 | XCTAssert(json["test"] == "data") 28 | expectation.fulfill() 29 | }.resume() 30 | 31 | self.waitForExpectations(timeout: 0.02, handler: nil) 32 | } 33 | 34 | func testXmlString() { 35 | self.urlStub.url("echo.jsontest.com").xmlString() 36 | 37 | let expectation = self.expectation(description: "") 38 | 39 | URLSession.shared.dataTask(with: url) { data, _, _ in 40 | XCTAssert(String(data: data!, encoding: .utf8) == "") 41 | expectation.fulfill() 42 | }.resume() 43 | 44 | self.waitForExpectations(timeout: 0.02, handler: nil) 45 | } 46 | } 47 | 48 | extension Replacer.URLStub { 49 | @discardableResult 50 | func xmlString() -> Self { 51 | return response { request -> (Data?, Error?) in 52 | ("".data(using: .utf8), nil) 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Examples/SampleApp/SampleAppTests/sample.json: -------------------------------------------------------------------------------- 1 | {"test": "data"} 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | 5 | git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } 6 | 7 | gem "cocoapods" 8 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | CFPropertyList (3.0.1) 5 | activesupport (4.2.11.1) 6 | i18n (~> 0.7) 7 | minitest (~> 5.1) 8 | thread_safe (~> 0.3, >= 0.3.4) 9 | tzinfo (~> 1.1) 10 | atomos (0.1.3) 11 | claide (1.0.3) 12 | cocoapods (1.7.5) 13 | activesupport (>= 4.0.2, < 5) 14 | claide (>= 1.0.2, < 2.0) 15 | cocoapods-core (= 1.7.5) 16 | cocoapods-deintegrate (>= 1.0.3, < 2.0) 17 | cocoapods-downloader (>= 1.2.2, < 2.0) 18 | cocoapods-plugins (>= 1.0.0, < 2.0) 19 | cocoapods-search (>= 1.0.0, < 2.0) 20 | cocoapods-stats (>= 1.0.0, < 2.0) 21 | cocoapods-trunk (>= 1.3.1, < 2.0) 22 | cocoapods-try (>= 1.1.0, < 2.0) 23 | colored2 (~> 3.1) 24 | escape (~> 0.0.4) 25 | fourflusher (>= 2.3.0, < 3.0) 26 | gh_inspector (~> 1.0) 27 | molinillo (~> 0.6.6) 28 | nap (~> 1.0) 29 | ruby-macho (~> 1.4) 30 | xcodeproj (>= 1.10.0, < 2.0) 31 | cocoapods-core (1.7.5) 32 | activesupport (>= 4.0.2, < 6) 33 | fuzzy_match (~> 2.0.4) 34 | nap (~> 1.0) 35 | cocoapods-deintegrate (1.0.4) 36 | cocoapods-downloader (1.6.3) 37 | cocoapods-plugins (1.0.0) 38 | nap 39 | cocoapods-search (1.0.0) 40 | cocoapods-stats (1.1.0) 41 | cocoapods-trunk (1.4.0) 42 | nap (>= 0.8, < 2.0) 43 | netrc (~> 0.11) 44 | cocoapods-try (1.1.0) 45 | colored2 (3.1.2) 46 | concurrent-ruby (1.1.5) 47 | escape (0.0.4) 48 | fourflusher (2.3.1) 49 | fuzzy_match (2.0.4) 50 | gh_inspector (1.1.3) 51 | i18n (0.9.5) 52 | concurrent-ruby (~> 1.0) 53 | minitest (5.11.3) 54 | molinillo (0.6.6) 55 | nanaimo (0.2.6) 56 | nap (1.1.0) 57 | netrc (0.11.0) 58 | ruby-macho (1.4.0) 59 | thread_safe (0.3.6) 60 | tzinfo (1.2.10) 61 | thread_safe (~> 0.1) 62 | xcodeproj (1.12.0) 63 | CFPropertyList (>= 2.3.3, < 4.0) 64 | atomos (~> 0.1.3) 65 | claide (>= 1.0.2, < 2.0) 66 | colored2 (~> 3.1) 67 | nanaimo (~> 0.2.6) 68 | 69 | PLATFORMS 70 | ruby 71 | 72 | DEPENDENCIES 73 | cocoapods 74 | 75 | BUNDLED WITH 76 | 1.17.1 77 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Tatsuya Tanaka 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.0 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "Replacer", 7 | products: [ 8 | .library( 9 | name: "Replacer", 10 | targets: ["Replacer"]), 11 | .library( 12 | name: "TestReplacer", 13 | targets: ["TestReplacer"]), 14 | ], 15 | dependencies: [ 16 | .package(url: "https://github.com/Alamofire/Alamofire.git", from: "4.9.0"), 17 | ], 18 | targets: [ 19 | .target( 20 | name: "Replacer", 21 | dependencies: []), 22 | .testTarget( 23 | name: "ReplacerTests", 24 | dependencies: ["Replacer", "Alamofire"], 25 | path: "Tests/ReplacerTests"), 26 | .target( 27 | name: "TestReplacer", 28 | dependencies: ["Replacer"]), 29 | // .testTarget( 30 | // name: "TestReplacerTests", 31 | // dependencies: ["TestReplacer"], 32 | // path: "Tests/TestReplacerTests"), 33 | ] 34 | ) 35 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Replacer 2 | === 3 | 4 | [![Build Status](https://travis-ci.org/tattn/Replacer.svg?branch=master)](https://travis-ci.org/tattn/Replacer) 5 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 6 | [![Version](https://img.shields.io/cocoapods/v/Replacer.svg)](http://cocoapods.org/pods/Replacer) 7 | [![Platform](https://img.shields.io/cocoapods/p/Replacer.svg)](http://cocoapods.org/pods/Replacer) 8 | [![License](https://img.shields.io/cocoapods/l/Replacer.svg)](http://cocoapods.org/pods/Replacer) 9 | [![Swift Version](https://img.shields.io/badge/Swift-5-F16D39.svg)](https://developer.apple.com/swift) 10 | 11 | 12 | Replacer is an easy-to-use library to stub HTTP requests and to swizzle methods. 13 | 14 | Specifically, URLSession's response can be replaced with any JSON, Data, and so on.... 15 | It uses **method chaining** to set stubs up. 16 | 17 | # How to use 18 | 19 | ## Stub HTTP Request 20 | 21 | ### XCTest 22 | 23 | ```swift 24 | import Replacer 25 | import TestReplacer 26 | 27 | class SampleTests: XCTestCase { 28 | func testJSONFile() { 29 | // register a stub 30 | self.urlStub.url("echo.jsontest.com").json(["test": "data"]) 31 | 32 | // load sample.json & register a stub. 33 | self.urlStub.json(filename: "sample") 34 | 35 | let expectation = self.expectation(description: "") 36 | 37 | let url = URL(string: "http://echo.jsontest.com/key/value/one/two")! 38 | URLSession(configuration: .default).dataTask(with: url) { data, _, _ in 39 | let json = try! JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [String: String] 40 | XCTAssert(json["test"] == "data") 41 | expectation.fulfill() 42 | }.resume() 43 | 44 | self.waitForExpectations(timeout: 0.02, handler: nil) 45 | } 46 | } 47 | ``` 48 | 49 | ### Quick & Alamofire 50 | 51 | ```swift 52 | class SampleSpecs: QuickSpec { 53 | override func spec() { 54 | describe("Quick compatibility test") { 55 | context("using JSON file") { 56 | beforeEach() { 57 | // wait for 1.5s 58 | self.urlStub.url("echo.jsontest.com/[a-z]+/.*") 59 | .httpMethod(.post) 60 | .json(["test": "data"]) 61 | .delay(1.5) 62 | } 63 | 64 | it("returns mock data") { 65 | var json: [String: String]? 66 | 67 | Alamofire.request("http://echo.jsontest.com/key/value/one/two", method: .post).responseJSON { response in 68 | json = response.result.value as? [String: String] 69 | } 70 | 71 | // SessionManager is also OK. 72 | // SessionManager.default.request("http://echo.jsontest.com/key/value/one/two").responseJSON { _ in } 73 | 74 | expect(json?["test"]).toEventually(equal("data")) 75 | } 76 | } 77 | } 78 | } 79 | } 80 | ``` 81 | 82 | ## Method Swizzling 83 | 84 | ```swift 85 | import UIKit 86 | import Replacer 87 | 88 | @UIApplicationMain 89 | class AppDelegate: UIResponder, UIApplicationDelegate { 90 | 91 | var window: UIWindow? 92 | 93 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 94 | 95 | Replacer.replaceInstance(#selector(UIViewController.viewWillAppear(_:)), 96 | of: UIViewController.self, 97 | with: #selector(UIViewController.orig_viewWillAppear(_:)), 98 | of: UIViewController.self) 99 | 100 | return true 101 | } 102 | } 103 | 104 | extension UIViewController { 105 | func orig_viewWillAppear(_ animated: Bool) { 106 | orig_viewWillAppear(animated) 107 | 108 | print("swizzled") 109 | } 110 | } 111 | 112 | ``` 113 | 114 | # Installation 115 | 116 | ## Carthage 117 | 118 | ```ruby 119 | github "tattn/Replacer" 120 | ``` 121 | 122 | ## CocoaPods 123 | 124 | ```ruby 125 | pod 'Replacer' 126 | ``` 127 | 128 | # Documentation 129 | 130 | - [Stub Reference](https://github.com/tattn/Replacer/blob/master/Documentations/Reference.md) 131 | 132 | # Contributing 133 | 134 | 1. Fork it! 135 | 2. Create your feature branch: `git checkout -b my-new-feature` 136 | 3. Commit your changes: `git commit -am 'Add some feature'` 137 | 4. Push to the branch: `git push origin my-new-feature` 138 | 5. Submit a pull request :D 139 | 140 | # License 141 | 142 | Replacer is released under the MIT license. See LICENSE for details. 143 | -------------------------------------------------------------------------------- /Replacer.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'Replacer' 3 | s.version = '0.1.0' 4 | s.summary = 'An easy-to-use library to stub HTTP requests using URLSession and to swizzle methods' 5 | s.homepage = 'https://github.com/tattn/Replacer' 6 | s.social_media_url = 'https://github.com/tattn/Replacer' 7 | s.authors = { 'Tatsuya Tanaka (tattn)' => 'tanakasan2525@gmail.com' } 8 | s.source = { :git => 'https://github.com/tattn/Replacer.git', :tag => s.version } 9 | s.swift_versions = ['5.0'] 10 | s.ios.deployment_target = '8.0' 11 | s.osx.deployment_target = '10.10' 12 | if s.respond_to?(:watchos) 13 | s.watchos.deployment_target = '2.0' 14 | end 15 | if s.respond_to?(:tvos) 16 | s.tvos.deployment_target = '9.0' 17 | end 18 | s.source_files = 'Sources/Replacer/*.swift' 19 | s.license = { 20 | :type => "MIT", 21 | :text => <<-LICENSE 22 | Copyright (c) 2019 Tatsuya Tanaka 23 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 24 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 25 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 | LICENSE 27 | } 28 | end 29 | -------------------------------------------------------------------------------- /Replacer.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXAggregateTarget section */ 10 | 243C724A1E58D85400D8BBF5 /* SwiftLint */ = { 11 | isa = PBXAggregateTarget; 12 | buildConfigurationList = 243C724B1E58D85400D8BBF5 /* Build configuration list for PBXAggregateTarget "SwiftLint" */; 13 | buildPhases = ( 14 | 243C724E1E58D87600D8BBF5 /* Run Script - SwiftLint */, 15 | ); 16 | dependencies = ( 17 | ); 18 | name = SwiftLint; 19 | productName = SwiftLint; 20 | }; 21 | /* End PBXAggregateTarget section */ 22 | 23 | /* Begin PBXBuildFile section */ 24 | 243C72461E589EAC00D8BBF5 /* Alamofire.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 243C72451E589EAC00D8BBF5 /* Alamofire.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 25 | 244D6FCB1E4F9494007AE072 /* Replacer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 244D6FC81E4F9494007AE072 /* Replacer.swift */; }; 26 | 244D6FCC1E4F9494007AE072 /* URLStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 244D6FC91E4F9494007AE072 /* URLStub.swift */; }; 27 | 244D6FCF1E4F9531007AE072 /* URLStubProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 244D6FCE1E4F9531007AE072 /* URLStubProtocol.swift */; }; 28 | 244D6FE11E4F9D99007AE072 /* TestReplacer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 244D6FD81E4F9D99007AE072 /* TestReplacer.framework */; }; 29 | 244D6FE61E4F9D99007AE072 /* TestReplacerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 244D6FE51E4F9D99007AE072 /* TestReplacerTests.swift */; }; 30 | 244D6FE81E4F9D99007AE072 /* TestReplacer.h in Headers */ = {isa = PBXBuildFile; fileRef = 244D6FDA1E4F9D99007AE072 /* TestReplacer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 31 | 244D6FEF1E4F9E0A007AE072 /* XCTest+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 244D6FCA1E4F9494007AE072 /* XCTest+.swift */; }; 32 | 244D6FF61E4FA1A1007AE072 /* Replacer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 248E45451E4F93D4009135F0 /* Replacer.framework */; }; 33 | 244D704B1E50521C007AE072 /* URLStubManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 244D704A1E50521C007AE072 /* URLStubManager.swift */; }; 34 | 244D704D1E5055D5007AE072 /* URLSessionConfiguration+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 244D704C1E5055D5007AE072 /* URLSessionConfiguration+.swift */; }; 35 | 244D70571E50C6C3007AE072 /* Replacer.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 248E45451E4F93D4009135F0 /* Replacer.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 36 | 244D70591E50C6EE007AE072 /* sample.json in Resources */ = {isa = PBXBuildFile; fileRef = 244D70581E50C6EE007AE072 /* sample.json */; }; 37 | 248E454F1E4F93D4009135F0 /* Replacer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 248E45451E4F93D4009135F0 /* Replacer.framework */; }; 38 | 248E45541E4F93D4009135F0 /* ReplacerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 248E45531E4F93D4009135F0 /* ReplacerTests.swift */; }; 39 | 248E45561E4F93D4009135F0 /* Replacer.h in Headers */ = {isa = PBXBuildFile; fileRef = 248E45481E4F93D4009135F0 /* Replacer.h */; settings = {ATTRIBUTES = (Public, ); }; }; 40 | /* End PBXBuildFile section */ 41 | 42 | /* Begin PBXContainerItemProxy section */ 43 | 244D6FE21E4F9D99007AE072 /* PBXContainerItemProxy */ = { 44 | isa = PBXContainerItemProxy; 45 | containerPortal = 248E453C1E4F93D3009135F0 /* Project object */; 46 | proxyType = 1; 47 | remoteGlobalIDString = 244D6FD71E4F9D99007AE072; 48 | remoteInfo = TestReplacer; 49 | }; 50 | 248E45501E4F93D4009135F0 /* PBXContainerItemProxy */ = { 51 | isa = PBXContainerItemProxy; 52 | containerPortal = 248E453C1E4F93D3009135F0 /* Project object */; 53 | proxyType = 1; 54 | remoteGlobalIDString = 248E45441E4F93D3009135F0; 55 | remoteInfo = Replacer; 56 | }; 57 | /* End PBXContainerItemProxy section */ 58 | 59 | /* Begin PBXCopyFilesBuildPhase section */ 60 | 244D70511E50C40C007AE072 /* CopyFiles */ = { 61 | isa = PBXCopyFilesBuildPhase; 62 | buildActionMask = 2147483647; 63 | dstPath = ""; 64 | dstSubfolderSpec = 10; 65 | files = ( 66 | 244D70571E50C6C3007AE072 /* Replacer.framework in CopyFiles */, 67 | 243C72461E589EAC00D8BBF5 /* Alamofire.framework in CopyFiles */, 68 | ); 69 | runOnlyForDeploymentPostprocessing = 0; 70 | }; 71 | /* End PBXCopyFilesBuildPhase section */ 72 | 73 | /* Begin PBXFileReference section */ 74 | 243C72451E589EAC00D8BBF5 /* Alamofire.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Alamofire.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 75 | 244D6FC81E4F9494007AE072 /* Replacer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Replacer.swift; sourceTree = ""; }; 76 | 244D6FC91E4F9494007AE072 /* URLStub.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLStub.swift; sourceTree = ""; }; 77 | 244D6FCA1E4F9494007AE072 /* XCTest+.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "XCTest+.swift"; sourceTree = ""; }; 78 | 244D6FCE1E4F9531007AE072 /* URLStubProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLStubProtocol.swift; sourceTree = ""; }; 79 | 244D6FD81E4F9D99007AE072 /* TestReplacer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TestReplacer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 80 | 244D6FDA1E4F9D99007AE072 /* TestReplacer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestReplacer.h; sourceTree = ""; }; 81 | 244D6FDB1E4F9D99007AE072 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 82 | 244D6FE01E4F9D99007AE072 /* TestReplacerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TestReplacerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 83 | 244D6FE51E4F9D99007AE072 /* TestReplacerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestReplacerTests.swift; sourceTree = ""; }; 84 | 244D6FE71E4F9D99007AE072 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 85 | 244D702A1E4FAFEC007AE072 /* Base.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Base.xcconfig; sourceTree = ""; }; 86 | 244D702D1E4FB061007AE072 /* Framework.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Framework.xcconfig; sourceTree = ""; }; 87 | 244D70301E4FB133007AE072 /* Test.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Test.xcconfig; sourceTree = ""; }; 88 | 244D70331E5041F6007AE072 /* Framework_XCTest.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Framework_XCTest.xcconfig; sourceTree = ""; }; 89 | 244D70341E504286007AE072 /* Base_XCTest.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Base_XCTest.xcconfig; sourceTree = ""; }; 90 | 244D704A1E50521C007AE072 /* URLStubManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLStubManager.swift; sourceTree = ""; }; 91 | 244D704C1E5055D5007AE072 /* URLSessionConfiguration+.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "URLSessionConfiguration+.swift"; sourceTree = ""; }; 92 | 244D70581E50C6EE007AE072 /* sample.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = sample.json; sourceTree = ""; }; 93 | 248E45451E4F93D4009135F0 /* Replacer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Replacer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 94 | 248E45481E4F93D4009135F0 /* Replacer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Replacer.h; sourceTree = ""; }; 95 | 248E45491E4F93D4009135F0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 96 | 248E454E1E4F93D4009135F0 /* ReplacerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ReplacerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 97 | 248E45531E4F93D4009135F0 /* ReplacerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplacerTests.swift; sourceTree = ""; }; 98 | 248E45551E4F93D4009135F0 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 99 | /* End PBXFileReference section */ 100 | 101 | /* Begin PBXFrameworksBuildPhase section */ 102 | 244D6FD41E4F9D99007AE072 /* Frameworks */ = { 103 | isa = PBXFrameworksBuildPhase; 104 | buildActionMask = 2147483647; 105 | files = ( 106 | 244D6FF61E4FA1A1007AE072 /* Replacer.framework in Frameworks */, 107 | ); 108 | runOnlyForDeploymentPostprocessing = 0; 109 | }; 110 | 244D6FDD1E4F9D99007AE072 /* Frameworks */ = { 111 | isa = PBXFrameworksBuildPhase; 112 | buildActionMask = 2147483647; 113 | files = ( 114 | 244D6FE11E4F9D99007AE072 /* TestReplacer.framework in Frameworks */, 115 | ); 116 | runOnlyForDeploymentPostprocessing = 0; 117 | }; 118 | 248E45411E4F93D3009135F0 /* Frameworks */ = { 119 | isa = PBXFrameworksBuildPhase; 120 | buildActionMask = 2147483647; 121 | files = ( 122 | ); 123 | runOnlyForDeploymentPostprocessing = 0; 124 | }; 125 | 248E454B1E4F93D4009135F0 /* Frameworks */ = { 126 | isa = PBXFrameworksBuildPhase; 127 | buildActionMask = 2147483647; 128 | files = ( 129 | 248E454F1E4F93D4009135F0 /* Replacer.framework in Frameworks */, 130 | ); 131 | runOnlyForDeploymentPostprocessing = 0; 132 | }; 133 | /* End PBXFrameworksBuildPhase section */ 134 | 135 | /* Begin PBXGroup section */ 136 | 244D6FD01E4F95E0007AE072 /* Sources */ = { 137 | isa = PBXGroup; 138 | children = ( 139 | 244D6FD11E4F9604007AE072 /* Replacer */, 140 | 244D6FD91E4F9D99007AE072 /* TestReplacer */, 141 | ); 142 | path = Sources; 143 | sourceTree = ""; 144 | }; 145 | 244D6FD11E4F9604007AE072 /* Replacer */ = { 146 | isa = PBXGroup; 147 | children = ( 148 | 248E45491E4F93D4009135F0 /* Info.plist */, 149 | 244D6FC81E4F9494007AE072 /* Replacer.swift */, 150 | 248E45481E4F93D4009135F0 /* Replacer.h */, 151 | 244D6FC91E4F9494007AE072 /* URLStub.swift */, 152 | 244D704A1E50521C007AE072 /* URLStubManager.swift */, 153 | 244D704C1E5055D5007AE072 /* URLSessionConfiguration+.swift */, 154 | 244D6FCE1E4F9531007AE072 /* URLStubProtocol.swift */, 155 | ); 156 | path = Replacer; 157 | sourceTree = ""; 158 | }; 159 | 244D6FD21E4F9713007AE072 /* Tests */ = { 160 | isa = PBXGroup; 161 | children = ( 162 | 248E45521E4F93D4009135F0 /* ReplacerTests */, 163 | 244D6FE41E4F9D99007AE072 /* TestReplacerTests */, 164 | ); 165 | path = Tests; 166 | sourceTree = ""; 167 | }; 168 | 244D6FD91E4F9D99007AE072 /* TestReplacer */ = { 169 | isa = PBXGroup; 170 | children = ( 171 | 244D6FDB1E4F9D99007AE072 /* Info.plist */, 172 | 244D6FDA1E4F9D99007AE072 /* TestReplacer.h */, 173 | 244D6FCA1E4F9494007AE072 /* XCTest+.swift */, 174 | ); 175 | path = TestReplacer; 176 | sourceTree = ""; 177 | }; 178 | 244D6FE41E4F9D99007AE072 /* TestReplacerTests */ = { 179 | isa = PBXGroup; 180 | children = ( 181 | 244D6FE71E4F9D99007AE072 /* Info.plist */, 182 | 244D6FE51E4F9D99007AE072 /* TestReplacerTests.swift */, 183 | 244D70581E50C6EE007AE072 /* sample.json */, 184 | 243C72451E589EAC00D8BBF5 /* Alamofire.framework */, 185 | ); 186 | path = TestReplacerTests; 187 | sourceTree = ""; 188 | }; 189 | 244D70291E4FAFA6007AE072 /* Configurations */ = { 190 | isa = PBXGroup; 191 | children = ( 192 | 244D702A1E4FAFEC007AE072 /* Base.xcconfig */, 193 | 244D70341E504286007AE072 /* Base_XCTest.xcconfig */, 194 | 244D702D1E4FB061007AE072 /* Framework.xcconfig */, 195 | 244D70331E5041F6007AE072 /* Framework_XCTest.xcconfig */, 196 | 244D70301E4FB133007AE072 /* Test.xcconfig */, 197 | ); 198 | path = Configurations; 199 | sourceTree = ""; 200 | }; 201 | 248E453B1E4F93D3009135F0 = { 202 | isa = PBXGroup; 203 | children = ( 204 | 244D70291E4FAFA6007AE072 /* Configurations */, 205 | 248E45461E4F93D4009135F0 /* Products */, 206 | 244D6FD01E4F95E0007AE072 /* Sources */, 207 | 244D6FD21E4F9713007AE072 /* Tests */, 208 | ); 209 | sourceTree = ""; 210 | }; 211 | 248E45461E4F93D4009135F0 /* Products */ = { 212 | isa = PBXGroup; 213 | children = ( 214 | 248E45451E4F93D4009135F0 /* Replacer.framework */, 215 | 248E454E1E4F93D4009135F0 /* ReplacerTests.xctest */, 216 | 244D6FD81E4F9D99007AE072 /* TestReplacer.framework */, 217 | 244D6FE01E4F9D99007AE072 /* TestReplacerTests.xctest */, 218 | ); 219 | name = Products; 220 | sourceTree = ""; 221 | }; 222 | 248E45521E4F93D4009135F0 /* ReplacerTests */ = { 223 | isa = PBXGroup; 224 | children = ( 225 | 248E45551E4F93D4009135F0 /* Info.plist */, 226 | 248E45531E4F93D4009135F0 /* ReplacerTests.swift */, 227 | ); 228 | path = ReplacerTests; 229 | sourceTree = ""; 230 | }; 231 | /* End PBXGroup section */ 232 | 233 | /* Begin PBXHeadersBuildPhase section */ 234 | 244D6FD51E4F9D99007AE072 /* Headers */ = { 235 | isa = PBXHeadersBuildPhase; 236 | buildActionMask = 2147483647; 237 | files = ( 238 | 244D6FE81E4F9D99007AE072 /* TestReplacer.h in Headers */, 239 | ); 240 | runOnlyForDeploymentPostprocessing = 0; 241 | }; 242 | 248E45421E4F93D3009135F0 /* Headers */ = { 243 | isa = PBXHeadersBuildPhase; 244 | buildActionMask = 2147483647; 245 | files = ( 246 | 248E45561E4F93D4009135F0 /* Replacer.h in Headers */, 247 | ); 248 | runOnlyForDeploymentPostprocessing = 0; 249 | }; 250 | /* End PBXHeadersBuildPhase section */ 251 | 252 | /* Begin PBXNativeTarget section */ 253 | 244D6FD71E4F9D99007AE072 /* TestReplacer */ = { 254 | isa = PBXNativeTarget; 255 | buildConfigurationList = 244D6FE91E4F9D99007AE072 /* Build configuration list for PBXNativeTarget "TestReplacer" */; 256 | buildPhases = ( 257 | 244D6FD31E4F9D99007AE072 /* Sources */, 258 | 244D6FD41E4F9D99007AE072 /* Frameworks */, 259 | 244D6FD51E4F9D99007AE072 /* Headers */, 260 | 244D6FD61E4F9D99007AE072 /* Resources */, 261 | ); 262 | buildRules = ( 263 | ); 264 | dependencies = ( 265 | ); 266 | name = TestReplacer; 267 | productName = TestReplacer; 268 | productReference = 244D6FD81E4F9D99007AE072 /* TestReplacer.framework */; 269 | productType = "com.apple.product-type.framework"; 270 | }; 271 | 244D6FDF1E4F9D99007AE072 /* TestReplacerTests */ = { 272 | isa = PBXNativeTarget; 273 | buildConfigurationList = 244D6FEC1E4F9D99007AE072 /* Build configuration list for PBXNativeTarget "TestReplacerTests" */; 274 | buildPhases = ( 275 | 244D6FDC1E4F9D99007AE072 /* Sources */, 276 | 244D6FDD1E4F9D99007AE072 /* Frameworks */, 277 | 244D6FDE1E4F9D99007AE072 /* Resources */, 278 | 244D70511E50C40C007AE072 /* CopyFiles */, 279 | ); 280 | buildRules = ( 281 | ); 282 | dependencies = ( 283 | 244D6FE31E4F9D99007AE072 /* PBXTargetDependency */, 284 | ); 285 | name = TestReplacerTests; 286 | productName = TestReplacerTests; 287 | productReference = 244D6FE01E4F9D99007AE072 /* TestReplacerTests.xctest */; 288 | productType = "com.apple.product-type.bundle.unit-test"; 289 | }; 290 | 248E45441E4F93D3009135F0 /* Replacer */ = { 291 | isa = PBXNativeTarget; 292 | buildConfigurationList = 248E45591E4F93D4009135F0 /* Build configuration list for PBXNativeTarget "Replacer" */; 293 | buildPhases = ( 294 | 248E45401E4F93D3009135F0 /* Sources */, 295 | 248E45411E4F93D3009135F0 /* Frameworks */, 296 | 248E45421E4F93D3009135F0 /* Headers */, 297 | 248E45431E4F93D3009135F0 /* Resources */, 298 | ); 299 | buildRules = ( 300 | ); 301 | dependencies = ( 302 | ); 303 | name = Replacer; 304 | productName = Replacer; 305 | productReference = 248E45451E4F93D4009135F0 /* Replacer.framework */; 306 | productType = "com.apple.product-type.framework"; 307 | }; 308 | 248E454D1E4F93D4009135F0 /* ReplacerTests */ = { 309 | isa = PBXNativeTarget; 310 | buildConfigurationList = 248E455C1E4F93D4009135F0 /* Build configuration list for PBXNativeTarget "ReplacerTests" */; 311 | buildPhases = ( 312 | 248E454A1E4F93D4009135F0 /* Sources */, 313 | 248E454B1E4F93D4009135F0 /* Frameworks */, 314 | 248E454C1E4F93D4009135F0 /* Resources */, 315 | ); 316 | buildRules = ( 317 | ); 318 | dependencies = ( 319 | 248E45511E4F93D4009135F0 /* PBXTargetDependency */, 320 | ); 321 | name = ReplacerTests; 322 | productName = ReplacerTests; 323 | productReference = 248E454E1E4F93D4009135F0 /* ReplacerTests.xctest */; 324 | productType = "com.apple.product-type.bundle.unit-test"; 325 | }; 326 | /* End PBXNativeTarget section */ 327 | 328 | /* Begin PBXProject section */ 329 | 248E453C1E4F93D3009135F0 /* Project object */ = { 330 | isa = PBXProject; 331 | attributes = { 332 | LastSwiftUpdateCheck = 0820; 333 | LastUpgradeCheck = 1020; 334 | ORGANIZATIONNAME = tattn; 335 | TargetAttributes = { 336 | 243C724A1E58D85400D8BBF5 = { 337 | CreatedOnToolsVersion = 8.2.1; 338 | ProvisioningStyle = Automatic; 339 | }; 340 | 244D6FD71E4F9D99007AE072 = { 341 | CreatedOnToolsVersion = 8.2.1; 342 | LastSwiftMigration = 1020; 343 | ProvisioningStyle = Automatic; 344 | }; 345 | 244D6FDF1E4F9D99007AE072 = { 346 | CreatedOnToolsVersion = 8.2.1; 347 | LastSwiftMigration = 1020; 348 | ProvisioningStyle = Automatic; 349 | }; 350 | 248E45441E4F93D3009135F0 = { 351 | CreatedOnToolsVersion = 8.2.1; 352 | LastSwiftMigration = 1020; 353 | ProvisioningStyle = Automatic; 354 | }; 355 | 248E454D1E4F93D4009135F0 = { 356 | CreatedOnToolsVersion = 8.2.1; 357 | LastSwiftMigration = 1020; 358 | ProvisioningStyle = Automatic; 359 | }; 360 | }; 361 | }; 362 | buildConfigurationList = 248E453F1E4F93D3009135F0 /* Build configuration list for PBXProject "Replacer" */; 363 | compatibilityVersion = "Xcode 3.2"; 364 | developmentRegion = en; 365 | hasScannedForEncodings = 0; 366 | knownRegions = ( 367 | en, 368 | Base, 369 | ); 370 | mainGroup = 248E453B1E4F93D3009135F0; 371 | productRefGroup = 248E45461E4F93D4009135F0 /* Products */; 372 | projectDirPath = ""; 373 | projectRoot = ""; 374 | targets = ( 375 | 248E45441E4F93D3009135F0 /* Replacer */, 376 | 248E454D1E4F93D4009135F0 /* ReplacerTests */, 377 | 244D6FD71E4F9D99007AE072 /* TestReplacer */, 378 | 244D6FDF1E4F9D99007AE072 /* TestReplacerTests */, 379 | 243C724A1E58D85400D8BBF5 /* SwiftLint */, 380 | ); 381 | }; 382 | /* End PBXProject section */ 383 | 384 | /* Begin PBXResourcesBuildPhase section */ 385 | 244D6FD61E4F9D99007AE072 /* Resources */ = { 386 | isa = PBXResourcesBuildPhase; 387 | buildActionMask = 2147483647; 388 | files = ( 389 | ); 390 | runOnlyForDeploymentPostprocessing = 0; 391 | }; 392 | 244D6FDE1E4F9D99007AE072 /* Resources */ = { 393 | isa = PBXResourcesBuildPhase; 394 | buildActionMask = 2147483647; 395 | files = ( 396 | 244D70591E50C6EE007AE072 /* sample.json in Resources */, 397 | ); 398 | runOnlyForDeploymentPostprocessing = 0; 399 | }; 400 | 248E45431E4F93D3009135F0 /* Resources */ = { 401 | isa = PBXResourcesBuildPhase; 402 | buildActionMask = 2147483647; 403 | files = ( 404 | ); 405 | runOnlyForDeploymentPostprocessing = 0; 406 | }; 407 | 248E454C1E4F93D4009135F0 /* Resources */ = { 408 | isa = PBXResourcesBuildPhase; 409 | buildActionMask = 2147483647; 410 | files = ( 411 | ); 412 | runOnlyForDeploymentPostprocessing = 0; 413 | }; 414 | /* End PBXResourcesBuildPhase section */ 415 | 416 | /* Begin PBXShellScriptBuildPhase section */ 417 | 243C724E1E58D87600D8BBF5 /* Run Script - SwiftLint */ = { 418 | isa = PBXShellScriptBuildPhase; 419 | buildActionMask = 2147483647; 420 | files = ( 421 | ); 422 | inputPaths = ( 423 | ); 424 | name = "Run Script - SwiftLint"; 425 | outputPaths = ( 426 | ); 427 | runOnlyForDeploymentPostprocessing = 0; 428 | shellPath = /bin/sh; 429 | shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi"; 430 | }; 431 | /* End PBXShellScriptBuildPhase section */ 432 | 433 | /* Begin PBXSourcesBuildPhase section */ 434 | 244D6FD31E4F9D99007AE072 /* Sources */ = { 435 | isa = PBXSourcesBuildPhase; 436 | buildActionMask = 2147483647; 437 | files = ( 438 | 244D6FEF1E4F9E0A007AE072 /* XCTest+.swift in Sources */, 439 | ); 440 | runOnlyForDeploymentPostprocessing = 0; 441 | }; 442 | 244D6FDC1E4F9D99007AE072 /* Sources */ = { 443 | isa = PBXSourcesBuildPhase; 444 | buildActionMask = 2147483647; 445 | files = ( 446 | 244D6FE61E4F9D99007AE072 /* TestReplacerTests.swift in Sources */, 447 | ); 448 | runOnlyForDeploymentPostprocessing = 0; 449 | }; 450 | 248E45401E4F93D3009135F0 /* Sources */ = { 451 | isa = PBXSourcesBuildPhase; 452 | buildActionMask = 2147483647; 453 | files = ( 454 | 244D6FCB1E4F9494007AE072 /* Replacer.swift in Sources */, 455 | 244D704B1E50521C007AE072 /* URLStubManager.swift in Sources */, 456 | 244D704D1E5055D5007AE072 /* URLSessionConfiguration+.swift in Sources */, 457 | 244D6FCC1E4F9494007AE072 /* URLStub.swift in Sources */, 458 | 244D6FCF1E4F9531007AE072 /* URLStubProtocol.swift in Sources */, 459 | ); 460 | runOnlyForDeploymentPostprocessing = 0; 461 | }; 462 | 248E454A1E4F93D4009135F0 /* Sources */ = { 463 | isa = PBXSourcesBuildPhase; 464 | buildActionMask = 2147483647; 465 | files = ( 466 | 248E45541E4F93D4009135F0 /* ReplacerTests.swift in Sources */, 467 | ); 468 | runOnlyForDeploymentPostprocessing = 0; 469 | }; 470 | /* End PBXSourcesBuildPhase section */ 471 | 472 | /* Begin PBXTargetDependency section */ 473 | 244D6FE31E4F9D99007AE072 /* PBXTargetDependency */ = { 474 | isa = PBXTargetDependency; 475 | target = 244D6FD71E4F9D99007AE072 /* TestReplacer */; 476 | targetProxy = 244D6FE21E4F9D99007AE072 /* PBXContainerItemProxy */; 477 | }; 478 | 248E45511E4F93D4009135F0 /* PBXTargetDependency */ = { 479 | isa = PBXTargetDependency; 480 | target = 248E45441E4F93D3009135F0 /* Replacer */; 481 | targetProxy = 248E45501E4F93D4009135F0 /* PBXContainerItemProxy */; 482 | }; 483 | /* End PBXTargetDependency section */ 484 | 485 | /* Begin XCBuildConfiguration section */ 486 | 243C724C1E58D85400D8BBF5 /* Debug */ = { 487 | isa = XCBuildConfiguration; 488 | buildSettings = { 489 | PRODUCT_NAME = "$(TARGET_NAME)"; 490 | }; 491 | name = Debug; 492 | }; 493 | 243C724D1E58D85400D8BBF5 /* Release */ = { 494 | isa = XCBuildConfiguration; 495 | buildSettings = { 496 | PRODUCT_NAME = "$(TARGET_NAME)"; 497 | }; 498 | name = Release; 499 | }; 500 | 244D6FEA1E4F9D99007AE072 /* Debug */ = { 501 | isa = XCBuildConfiguration; 502 | baseConfigurationReference = 244D70331E5041F6007AE072 /* Framework_XCTest.xcconfig */; 503 | buildSettings = { 504 | CODE_SIGN_IDENTITY = ""; 505 | DEFINES_MODULE = YES; 506 | DYLIB_COMPATIBILITY_VERSION = 1; 507 | DYLIB_CURRENT_VERSION = 1; 508 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 509 | ENABLE_BITCODE = NO; 510 | FRAMEWORK_SEARCH_PATHS = ( 511 | "$(inherited)", 512 | "$(PLATFORM_DIR)/Developer/Library/Frameworks", 513 | ); 514 | INFOPLIST_FILE = Sources/TestReplacer/Info.plist; 515 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 516 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 517 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 518 | MACOSX_DEPLOYMENT_TARGET = 10.10; 519 | PRODUCT_BUNDLE_IDENTIFIER = com.github.tattn.TestReplacer; 520 | PRODUCT_NAME = TestReplacer; 521 | SKIP_INSTALL = YES; 522 | SWIFT_VERSION = 5.0; 523 | TVOS_DEPLOYMENT_TARGET = 9.0; 524 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 525 | }; 526 | name = Debug; 527 | }; 528 | 244D6FEB1E4F9D99007AE072 /* Release */ = { 529 | isa = XCBuildConfiguration; 530 | baseConfigurationReference = 244D70331E5041F6007AE072 /* Framework_XCTest.xcconfig */; 531 | buildSettings = { 532 | CODE_SIGN_IDENTITY = ""; 533 | DEFINES_MODULE = YES; 534 | DYLIB_COMPATIBILITY_VERSION = 1; 535 | DYLIB_CURRENT_VERSION = 1; 536 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 537 | ENABLE_BITCODE = NO; 538 | ENABLE_TESTABILITY = YES; 539 | FRAMEWORK_SEARCH_PATHS = ( 540 | "$(inherited)", 541 | "$(PLATFORM_DIR)/Developer/Library/Frameworks", 542 | ); 543 | INFOPLIST_FILE = Sources/TestReplacer/Info.plist; 544 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 545 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 546 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 547 | MACOSX_DEPLOYMENT_TARGET = 10.10; 548 | PRODUCT_BUNDLE_IDENTIFIER = com.github.tattn.TestReplacer; 549 | PRODUCT_NAME = TestReplacer; 550 | SKIP_INSTALL = YES; 551 | SWIFT_VERSION = 5.0; 552 | TVOS_DEPLOYMENT_TARGET = 9.0; 553 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 554 | }; 555 | name = Release; 556 | }; 557 | 244D6FED1E4F9D99007AE072 /* Debug */ = { 558 | isa = XCBuildConfiguration; 559 | baseConfigurationReference = 244D70301E4FB133007AE072 /* Test.xcconfig */; 560 | buildSettings = { 561 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 562 | FRAMEWORK_SEARCH_PATHS = ( 563 | "$(inherited)", 564 | "$(PROJECT_DIR)/Carthage/Build/iOS", 565 | ); 566 | INFOPLIST_FILE = Tests/TestReplacerTests/Info.plist; 567 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 568 | PRODUCT_BUNDLE_IDENTIFIER = com.github.tattn.TestReplacerTests; 569 | PRODUCT_NAME = "$(TARGET_NAME)"; 570 | SWIFT_VERSION = 5.0; 571 | }; 572 | name = Debug; 573 | }; 574 | 244D6FEE1E4F9D99007AE072 /* Release */ = { 575 | isa = XCBuildConfiguration; 576 | baseConfigurationReference = 244D70301E4FB133007AE072 /* Test.xcconfig */; 577 | buildSettings = { 578 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 579 | FRAMEWORK_SEARCH_PATHS = ( 580 | "$(inherited)", 581 | "$(PROJECT_DIR)/Carthage/Build/iOS", 582 | ); 583 | INFOPLIST_FILE = Tests/TestReplacerTests/Info.plist; 584 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 585 | PRODUCT_BUNDLE_IDENTIFIER = com.github.tattn.TestReplacerTests; 586 | PRODUCT_NAME = "$(TARGET_NAME)"; 587 | SWIFT_VERSION = 5.0; 588 | }; 589 | name = Release; 590 | }; 591 | 248E45571E4F93D4009135F0 /* Debug */ = { 592 | isa = XCBuildConfiguration; 593 | buildSettings = { 594 | ALWAYS_SEARCH_USER_PATHS = NO; 595 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 596 | CLANG_ANALYZER_NONNULL = YES; 597 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 598 | CLANG_CXX_LIBRARY = "libc++"; 599 | CLANG_ENABLE_MODULES = YES; 600 | CLANG_ENABLE_OBJC_ARC = YES; 601 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 602 | CLANG_WARN_BOOL_CONVERSION = YES; 603 | CLANG_WARN_COMMA = YES; 604 | CLANG_WARN_CONSTANT_CONVERSION = YES; 605 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 606 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 607 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 608 | CLANG_WARN_EMPTY_BODY = YES; 609 | CLANG_WARN_ENUM_CONVERSION = YES; 610 | CLANG_WARN_INFINITE_RECURSION = YES; 611 | CLANG_WARN_INT_CONVERSION = YES; 612 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 613 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 614 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 615 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 616 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 617 | CLANG_WARN_STRICT_PROTOTYPES = YES; 618 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 619 | CLANG_WARN_UNREACHABLE_CODE = YES; 620 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 621 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 622 | COPY_PHASE_STRIP = NO; 623 | CURRENT_PROJECT_VERSION = 1; 624 | DEBUG_INFORMATION_FORMAT = dwarf; 625 | ENABLE_STRICT_OBJC_MSGSEND = YES; 626 | ENABLE_TESTABILITY = YES; 627 | GCC_C_LANGUAGE_STANDARD = gnu99; 628 | GCC_DYNAMIC_NO_PIC = NO; 629 | GCC_NO_COMMON_BLOCKS = YES; 630 | GCC_OPTIMIZATION_LEVEL = 0; 631 | GCC_PREPROCESSOR_DEFINITIONS = ( 632 | "DEBUG=1", 633 | "$(inherited)", 634 | ); 635 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 636 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 637 | GCC_WARN_UNDECLARED_SELECTOR = YES; 638 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 639 | GCC_WARN_UNUSED_FUNCTION = YES; 640 | GCC_WARN_UNUSED_VARIABLE = YES; 641 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 642 | MTL_ENABLE_DEBUG_INFO = YES; 643 | ONLY_ACTIVE_ARCH = YES; 644 | SDKROOT = macosx; 645 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 646 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 647 | TARGETED_DEVICE_FAMILY = "1,2"; 648 | VERSIONING_SYSTEM = "apple-generic"; 649 | VERSION_INFO_PREFIX = ""; 650 | }; 651 | name = Debug; 652 | }; 653 | 248E45581E4F93D4009135F0 /* Release */ = { 654 | isa = XCBuildConfiguration; 655 | buildSettings = { 656 | ALWAYS_SEARCH_USER_PATHS = NO; 657 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 658 | CLANG_ANALYZER_NONNULL = YES; 659 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 660 | CLANG_CXX_LIBRARY = "libc++"; 661 | CLANG_ENABLE_MODULES = YES; 662 | CLANG_ENABLE_OBJC_ARC = YES; 663 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 664 | CLANG_WARN_BOOL_CONVERSION = YES; 665 | CLANG_WARN_COMMA = YES; 666 | CLANG_WARN_CONSTANT_CONVERSION = YES; 667 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 668 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 669 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 670 | CLANG_WARN_EMPTY_BODY = YES; 671 | CLANG_WARN_ENUM_CONVERSION = YES; 672 | CLANG_WARN_INFINITE_RECURSION = YES; 673 | CLANG_WARN_INT_CONVERSION = YES; 674 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 675 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 676 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 677 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 678 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 679 | CLANG_WARN_STRICT_PROTOTYPES = YES; 680 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 681 | CLANG_WARN_UNREACHABLE_CODE = YES; 682 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 683 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 684 | COPY_PHASE_STRIP = NO; 685 | CURRENT_PROJECT_VERSION = 1; 686 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 687 | ENABLE_NS_ASSERTIONS = NO; 688 | ENABLE_STRICT_OBJC_MSGSEND = YES; 689 | GCC_C_LANGUAGE_STANDARD = gnu99; 690 | GCC_NO_COMMON_BLOCKS = YES; 691 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 692 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 693 | GCC_WARN_UNDECLARED_SELECTOR = YES; 694 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 695 | GCC_WARN_UNUSED_FUNCTION = YES; 696 | GCC_WARN_UNUSED_VARIABLE = YES; 697 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 698 | MTL_ENABLE_DEBUG_INFO = NO; 699 | SDKROOT = macosx; 700 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 701 | TARGETED_DEVICE_FAMILY = "1,2"; 702 | VALIDATE_PRODUCT = YES; 703 | VERSIONING_SYSTEM = "apple-generic"; 704 | VERSION_INFO_PREFIX = ""; 705 | }; 706 | name = Release; 707 | }; 708 | 248E455A1E4F93D4009135F0 /* Debug */ = { 709 | isa = XCBuildConfiguration; 710 | baseConfigurationReference = 244D702D1E4FB061007AE072 /* Framework.xcconfig */; 711 | buildSettings = { 712 | CLANG_ENABLE_MODULES = YES; 713 | CODE_SIGN_IDENTITY = ""; 714 | DEFINES_MODULE = YES; 715 | DYLIB_COMPATIBILITY_VERSION = 1; 716 | DYLIB_CURRENT_VERSION = 1; 717 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 718 | ENABLE_BITCODE = NO; 719 | INFOPLIST_FILE = "$(SRCROOT)/Sources/Replacer/Info.plist"; 720 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 721 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 722 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 723 | MACOSX_DEPLOYMENT_TARGET = 10.10; 724 | PRODUCT_BUNDLE_IDENTIFIER = com.github.tattn.Replacer; 725 | PRODUCT_NAME = Replacer; 726 | SKIP_INSTALL = YES; 727 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 728 | SWIFT_VERSION = 5.0; 729 | TVOS_DEPLOYMENT_TARGET = 9.0; 730 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 731 | }; 732 | name = Debug; 733 | }; 734 | 248E455B1E4F93D4009135F0 /* Release */ = { 735 | isa = XCBuildConfiguration; 736 | baseConfigurationReference = 244D702D1E4FB061007AE072 /* Framework.xcconfig */; 737 | buildSettings = { 738 | CLANG_ENABLE_MODULES = YES; 739 | CODE_SIGN_IDENTITY = ""; 740 | DEFINES_MODULE = YES; 741 | DYLIB_COMPATIBILITY_VERSION = 1; 742 | DYLIB_CURRENT_VERSION = 1; 743 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 744 | ENABLE_BITCODE = NO; 745 | ENABLE_TESTABILITY = YES; 746 | INFOPLIST_FILE = "$(SRCROOT)/Sources/Replacer/Info.plist"; 747 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 748 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 749 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 750 | MACOSX_DEPLOYMENT_TARGET = 10.10; 751 | PRODUCT_BUNDLE_IDENTIFIER = com.github.tattn.Replacer; 752 | PRODUCT_NAME = Replacer; 753 | SKIP_INSTALL = YES; 754 | SWIFT_VERSION = 5.0; 755 | TVOS_DEPLOYMENT_TARGET = 9.0; 756 | WATCHOS_DEPLOYMENT_TARGET = 2.0; 757 | }; 758 | name = Release; 759 | }; 760 | 248E455D1E4F93D4009135F0 /* Debug */ = { 761 | isa = XCBuildConfiguration; 762 | baseConfigurationReference = 244D70301E4FB133007AE072 /* Test.xcconfig */; 763 | buildSettings = { 764 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 765 | INFOPLIST_FILE = Tests/ReplacerTests/Info.plist; 766 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 767 | PRODUCT_BUNDLE_IDENTIFIER = com.github.tattn.ReplacerTests; 768 | PRODUCT_NAME = "$(TARGET_NAME)"; 769 | SWIFT_VERSION = 5.0; 770 | }; 771 | name = Debug; 772 | }; 773 | 248E455E1E4F93D4009135F0 /* Release */ = { 774 | isa = XCBuildConfiguration; 775 | baseConfigurationReference = 244D70301E4FB133007AE072 /* Test.xcconfig */; 776 | buildSettings = { 777 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 778 | INFOPLIST_FILE = Tests/ReplacerTests/Info.plist; 779 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 780 | PRODUCT_BUNDLE_IDENTIFIER = com.github.tattn.ReplacerTests; 781 | PRODUCT_NAME = "$(TARGET_NAME)"; 782 | SWIFT_VERSION = 5.0; 783 | }; 784 | name = Release; 785 | }; 786 | /* End XCBuildConfiguration section */ 787 | 788 | /* Begin XCConfigurationList section */ 789 | 243C724B1E58D85400D8BBF5 /* Build configuration list for PBXAggregateTarget "SwiftLint" */ = { 790 | isa = XCConfigurationList; 791 | buildConfigurations = ( 792 | 243C724C1E58D85400D8BBF5 /* Debug */, 793 | 243C724D1E58D85400D8BBF5 /* Release */, 794 | ); 795 | defaultConfigurationIsVisible = 0; 796 | defaultConfigurationName = Release; 797 | }; 798 | 244D6FE91E4F9D99007AE072 /* Build configuration list for PBXNativeTarget "TestReplacer" */ = { 799 | isa = XCConfigurationList; 800 | buildConfigurations = ( 801 | 244D6FEA1E4F9D99007AE072 /* Debug */, 802 | 244D6FEB1E4F9D99007AE072 /* Release */, 803 | ); 804 | defaultConfigurationIsVisible = 0; 805 | defaultConfigurationName = Release; 806 | }; 807 | 244D6FEC1E4F9D99007AE072 /* Build configuration list for PBXNativeTarget "TestReplacerTests" */ = { 808 | isa = XCConfigurationList; 809 | buildConfigurations = ( 810 | 244D6FED1E4F9D99007AE072 /* Debug */, 811 | 244D6FEE1E4F9D99007AE072 /* Release */, 812 | ); 813 | defaultConfigurationIsVisible = 0; 814 | defaultConfigurationName = Release; 815 | }; 816 | 248E453F1E4F93D3009135F0 /* Build configuration list for PBXProject "Replacer" */ = { 817 | isa = XCConfigurationList; 818 | buildConfigurations = ( 819 | 248E45571E4F93D4009135F0 /* Debug */, 820 | 248E45581E4F93D4009135F0 /* Release */, 821 | ); 822 | defaultConfigurationIsVisible = 0; 823 | defaultConfigurationName = Release; 824 | }; 825 | 248E45591E4F93D4009135F0 /* Build configuration list for PBXNativeTarget "Replacer" */ = { 826 | isa = XCConfigurationList; 827 | buildConfigurations = ( 828 | 248E455A1E4F93D4009135F0 /* Debug */, 829 | 248E455B1E4F93D4009135F0 /* Release */, 830 | ); 831 | defaultConfigurationIsVisible = 0; 832 | defaultConfigurationName = Release; 833 | }; 834 | 248E455C1E4F93D4009135F0 /* Build configuration list for PBXNativeTarget "ReplacerTests" */ = { 835 | isa = XCConfigurationList; 836 | buildConfigurations = ( 837 | 248E455D1E4F93D4009135F0 /* Debug */, 838 | 248E455E1E4F93D4009135F0 /* Release */, 839 | ); 840 | defaultConfigurationIsVisible = 0; 841 | defaultConfigurationName = Release; 842 | }; 843 | /* End XCConfigurationList section */ 844 | }; 845 | rootObject = 248E453C1E4F93D3009135F0 /* Project object */; 846 | } 847 | -------------------------------------------------------------------------------- /Replacer.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Replacer.xcodeproj/xcshareddata/xcschemes/Replacer.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 45 | 46 | 48 | 54 | 55 | 56 | 57 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 79 | 80 | 86 | 87 | 88 | 89 | 90 | 91 | 97 | 98 | 104 | 105 | 106 | 107 | 109 | 110 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /Replacer.xcodeproj/xcshareddata/xcschemes/TestReplacer.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 45 | 46 | 48 | 54 | 55 | 56 | 57 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 79 | 80 | 86 | 87 | 88 | 89 | 90 | 91 | 97 | 98 | 104 | 105 | 106 | 107 | 109 | 110 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /Replacer.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Replacer.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Sources/Replacer/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Sources/Replacer/Replacer.h: -------------------------------------------------------------------------------- 1 | // 2 | // Replacer.h 3 | // Replacer 4 | // 5 | // Created by Tatsuya Tanaka on 2017/02/12. 6 | // Copyright © 2017年 tattn. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Replacer. 12 | FOUNDATION_EXPORT double ReplacerVersionNumber; 13 | 14 | //! Project version string for Replacer. 15 | FOUNDATION_EXPORT const unsigned char ReplacerVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Sources/Replacer/Replacer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Replacer.swift 3 | // Replacer 4 | // 5 | // Created by Tatsuya Tanaka (tattn) on 2017/01/01. 6 | // Copyright © 2017年 tattn. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | @discardableResult 12 | public func replaceStatic(_ fromSelector: Selector, 13 | of fromClass: AnyClass? = nil, 14 | with toSelector: Selector, 15 | of toClass: AnyClass) -> Bool { 16 | 17 | let fromClass: AnyClass = fromClass ?? toClass 18 | 19 | guard let from = class_getClassMethod(fromClass, fromSelector), 20 | let to = class_getClassMethod(toClass, toSelector) else { 21 | return false 22 | } 23 | 24 | method_exchangeImplementations(from, to) 25 | 26 | return true 27 | } 28 | 29 | @discardableResult 30 | public func replaceInstance(_ fromSelector: Selector, 31 | of fromClass: AnyClass? = nil, 32 | with toSelector: Selector, 33 | of toClass: AnyClass) -> Bool { 34 | 35 | let fromClass: AnyClass = fromClass ?? toClass 36 | 37 | guard let from = class_getInstanceMethod(fromClass, fromSelector), 38 | let to = class_getInstanceMethod(toClass, toSelector) else { 39 | return false 40 | } 41 | 42 | addOrExchangeMethod(fromSelector: fromSelector, 43 | fromMethod: from, 44 | of: fromClass, 45 | toSelector: toSelector, 46 | toMethod: to, 47 | of: toClass) 48 | return true 49 | } 50 | 51 | private func addOrExchangeMethod(fromSelector: Selector, 52 | fromMethod: Method, 53 | of fromClass: AnyClass, 54 | toSelector: Selector, 55 | toMethod: Method, 56 | of toClass: AnyClass) { 57 | // add if not exists 58 | if class_addMethod(fromClass, 59 | fromSelector, 60 | method_getImplementation(toMethod), 61 | method_getTypeEncoding(toMethod)) { 62 | 63 | // replace added method 64 | class_replaceMethod(fromClass, 65 | toSelector, 66 | method_getImplementation(fromMethod), 67 | method_getTypeEncoding(fromMethod)) 68 | } else { 69 | // exchange if exists 70 | method_exchangeImplementations(fromMethod, toMethod) 71 | } 72 | } 73 | 74 | /// Register a stub. 75 | public var urlStub: URLStub { 76 | URLStubManager.shared.isEnabled = true 77 | 78 | let stub = URLStub() 79 | URLStubManager.shared.register(stub) 80 | return stub 81 | } 82 | -------------------------------------------------------------------------------- /Sources/Replacer/URLSessionConfiguration+.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URLSessionConfiguration+.swift 3 | // Replacer 4 | // 5 | // Created by Tatsuya Tanaka on 2017/02/12. 6 | // Copyright © 2017年 tattn. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | extension URLSessionConfiguration { 12 | 13 | @objc dynamic class var mock: URLSessionConfiguration { 14 | let configuration = self.mock 15 | configuration.protocolClasses?.insert(URLStubProtocol.self, at: 0) 16 | return configuration 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sources/Replacer/URLStub.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URLStub.swift 3 | // Replacer 4 | // 5 | // Created by Tatsuya Tanaka (tattn) on 2017/01/01. 6 | // Copyright © 2017年 tattn. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public class URLStub { 12 | var _url: String = "" 13 | var _method: HTTPMethod = .get 14 | var _statusCode: Int? 15 | var _data: Data? 16 | var _error: Error? 17 | var _delay: Double = 0 18 | 19 | public typealias ResponseBlock = (URLRequest) -> (Data?, Error?) 20 | var _responseBlock: ResponseBlock? 21 | 22 | public var bundle: Bundle! 23 | 24 | 25 | init(bundle: Bundle = Bundle.main) { 26 | self.bundle = bundle 27 | } 28 | 29 | /// Set a URL you want to replace 30 | /// 31 | /// - Parameter url: URL you want to replace 32 | @discardableResult 33 | public func url(_ url: String) -> Self { 34 | _url = url 35 | return self 36 | } 37 | 38 | /// Set a HTTP Method 39 | /// 40 | /// - Parameter method: HTTP method 41 | @discardableResult 42 | public func httpMethod(_ method: HTTPMethod) -> Self { 43 | _method = method 44 | return self 45 | } 46 | 47 | /// Set a status code 48 | /// 49 | /// - Parameter statusCode: Status code 50 | @discardableResult 51 | public func statusCode(_ statusCode: Int) -> Self { 52 | _statusCode = statusCode 53 | return self 54 | } 55 | 56 | /// Set a JSON for response 57 | /// 58 | /// - Parameter json: json of response 59 | @discardableResult 60 | public func json(_ json: [String: Any]) -> Self { 61 | return self.json(json as Any) 62 | } 63 | 64 | /// Set a JSON for response 65 | /// 66 | /// - Parameter json: json of response 67 | @discardableResult 68 | public func json(_ json: [Any]) -> Self { 69 | return self.json(json as Any) 70 | } 71 | 72 | private func json(_ json: Any) -> Self { 73 | do { 74 | _data = try JSONSerialization.data(withJSONObject: json, options: .prettyPrinted) 75 | } catch { 76 | preconditionFailure("Failed to load a JSON: \(error.localizedDescription)") 77 | } 78 | return self 79 | } 80 | 81 | /// Set a filename of JSON for response 82 | /// 83 | /// - Parameter json: json of response 84 | @discardableResult 85 | public func json(filename: String, bundle: Bundle? = nil) -> Self { 86 | if let bundle = bundle { 87 | self.bundle = bundle 88 | } 89 | _data = loadJSON(filename: filename) 90 | return self 91 | } 92 | 93 | /// Set an error for response 94 | /// 95 | /// - Parameter error: error of response 96 | @discardableResult 97 | public func error(_ error: Error) -> Self { 98 | _error = error 99 | return self 100 | } 101 | 102 | /// Set a delay of response 103 | /// 104 | /// - Parameter seconds: wait time [s] 105 | @discardableResult 106 | public func delay(_ seconds: Double) -> Self { 107 | self._delay = seconds 108 | return self 109 | } 110 | 111 | @discardableResult 112 | public func response(block: @escaping ResponseBlock) -> Self { 113 | self._responseBlock = block 114 | return self 115 | } 116 | 117 | /// Load JSON from the bundle. 118 | /// 119 | /// - Parameter name: JSON file name (without the extension) 120 | /// - Returns: JSON data 121 | private func loadJSON(filename: String) -> Data { 122 | guard let path = bundle.url(forResource: filename, withExtension: "json"), 123 | let data = try? Data(contentsOf: path) else { 124 | preconditionFailure("Failed to load a JSON file[\(filename)]") 125 | } 126 | return data 127 | } 128 | } 129 | 130 | public extension URLStub { 131 | /// HTTP method definitions. 132 | enum HTTPMethod: String { 133 | case get = "GET" 134 | case post = "POST" 135 | case put = "PUT" 136 | case patch = "PATCH" 137 | case delete = "DELETE" 138 | case head = "HEAD" 139 | case options = "OPTIONS" 140 | case trace = "TRACE" 141 | case connect = "CONNECT" 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /Sources/Replacer/URLStubManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StubManager.swift 3 | // Replacer 4 | // 5 | // Created by Tatsuya Tanaka on 2017/02/12. 6 | // Copyright © 2017年 tattn. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public final class URLStubManager { 12 | 13 | public static let shared = URLStubManager() 14 | 15 | fileprivate var stubs: [URLStub] = [] 16 | 17 | public var isEnabled: Bool = false { 18 | didSet { 19 | guard isEnabled != oldValue else { return } 20 | swizzleDefaultSessionConfiguration() 21 | } 22 | } 23 | 24 | 25 | private init() {} 26 | 27 | private func swizzleDefaultSessionConfiguration() { 28 | let defaultSessionConfiguration = class_getClassMethod(URLSessionConfiguration.self, #selector(getter: URLSessionConfiguration.default))! 29 | let swizzledDefaultSessionConfiguration = class_getClassMethod(URLSessionConfiguration.self, #selector(getter: URLSessionConfiguration.mock))! 30 | method_exchangeImplementations(defaultSessionConfiguration, swizzledDefaultSessionConfiguration) 31 | } 32 | } 33 | 34 | public extension URLStubManager { 35 | 36 | func register(_ stub: URLStub) { 37 | stubs.append(stub) 38 | URLProtocol.registerClass(URLStubProtocol.self) 39 | } 40 | 41 | func unregisterAllStubs() { 42 | stubs = [] 43 | } 44 | 45 | func findStub(by request: URLRequest) -> URLStub? { 46 | if let url = request.url?.absoluteString { 47 | return stubs 48 | .filter { request.httpMethod == $0._method.rawValue } 49 | .filter { !".*\($0._url).*".matches(in: url).isEmpty } 50 | .first 51 | } 52 | return nil 53 | } 54 | } 55 | 56 | private extension String { 57 | func matches(in text: String) -> [String] { 58 | do { 59 | let regex = try NSRegularExpression(pattern: self) 60 | let nsString = text as NSString 61 | let results = regex.matches(in: text, range: NSRange(location: 0, length: nsString.length)) 62 | return results.map { nsString.substring(with: $0.range) } 63 | } catch let error { 64 | preconditionFailure("Invalid regex: \(error.localizedDescription)") 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Sources/Replacer/URLStubProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // URLStubProtocol.swift 3 | // Replacer 4 | // 5 | // Created by Tatsuya Tanaka (tattn) on 2017/02/12. 6 | // Copyright © 2017年 tattn. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public class URLStubProtocol: URLProtocol { 12 | 13 | override open class func canInit(with request: URLRequest) -> Bool { 14 | return URLStubManager.shared.findStub(by: request) != nil 15 | } 16 | 17 | override open class func canonicalRequest(for request: URLRequest) -> URLRequest { 18 | return request 19 | } 20 | 21 | override open func startLoading() { 22 | let stub = URLStubManager.shared.findStub(by: request)! 23 | DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + stub._delay) { 24 | if let responseBlock = stub._responseBlock { 25 | (stub._data, stub._error) = responseBlock(self.request) 26 | stub._responseBlock = nil 27 | } 28 | if let statusCode = stub._statusCode { 29 | let response = HTTPURLResponse(url: self.request.url!, statusCode: statusCode, httpVersion: nil, headerFields: nil) 30 | self.client?.urlProtocol(self, didReceive: response!, cacheStoragePolicy: .notAllowed) 31 | } 32 | if let error = stub._error { 33 | self.client?.urlProtocol(self, didFailWithError: error) 34 | } else if let data = stub._data { 35 | self.client?.urlProtocol(self, didLoad: data) 36 | } else { 37 | preconditionFailure("response is not set") 38 | } 39 | self.client?.urlProtocolDidFinishLoading(self) 40 | } 41 | } 42 | 43 | override open func stopLoading() { 44 | // noop 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Sources/TestReplacer/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Sources/TestReplacer/TestReplacer.h: -------------------------------------------------------------------------------- 1 | // 2 | // TestReplacer.h 3 | // TestReplacer 4 | // 5 | // Created by Tatsuya Tanaka on 2017/02/12. 6 | // Copyright © 2017年 tattn. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for TestReplacer. 12 | FOUNDATION_EXPORT double TestReplacerVersionNumber; 13 | 14 | //! Project version string for TestReplacer. 15 | FOUNDATION_EXPORT const unsigned char TestReplacerVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /Sources/TestReplacer/XCTest+.swift: -------------------------------------------------------------------------------- 1 | // 2 | // XCTest+.swift 3 | // Replacer 4 | // 5 | // Created by Tatsuya Tanaka (tattn) on 2017/01/01. 6 | // Copyright © 2017年 tattn. All rights reserved. 7 | // 8 | 9 | import Replacer 10 | import XCTest 11 | 12 | 13 | extension XCTest { 14 | 15 | private static let swizzleTearDown: Void = { 16 | let tearDown = class_getInstanceMethod(XCTest.self, #selector(XCTest.tearDown))! 17 | let replacerTearDown = class_getInstanceMethod(XCTest.self, #selector(XCTest.autoResetTearDown))! 18 | method_exchangeImplementations(tearDown, replacerTearDown) 19 | }() 20 | 21 | /// TearDown which resets all configurations automatically. 22 | @objc private dynamic func autoResetTearDown() { 23 | autoResetTearDown() 24 | 25 | URLStubManager.shared.unregisterAllStubs() 26 | } 27 | 28 | /// Register a stub. 29 | public var urlStub: URLStub { 30 | _ = XCTest.swizzleTearDown 31 | URLStubManager.shared.isEnabled = true 32 | 33 | let stub = Replacer.urlStub 34 | stub.bundle = Bundle(for: type(of: self)) 35 | return stub 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /TestReplacer.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'TestReplacer' 3 | s.version = '0.1.0' 4 | s.summary = 'An easy-to-use library to stub HTTP requests using URLSession and to swizzle methods' 5 | s.homepage = 'https://github.com/tattn/Replacer' 6 | s.social_media_url = 'https://github.com/tattn/Replacer' 7 | s.authors = { 'Tatsuya Tanaka (tattn)' => 'tanakasan2525@gmail.com' } 8 | s.source = { :git => 'https://github.com/tattn/Replacer.git', :tag => s.version } 9 | s.swift_versions = ['5.0'] 10 | s.ios.deployment_target = '8.0' 11 | s.osx.deployment_target = '10.10' 12 | if s.respond_to?(:tvos) 13 | s.tvos.deployment_target = '9.0' 14 | end 15 | s.framework = 'XCTest', 'Replacer' 16 | s.dependency 'Replacer', "= #{s.version}" 17 | s.source_files = 'Sources/TestReplacer/*.swift' 18 | s.license = { 19 | :type => "MIT", 20 | :text => <<-LICENSE 21 | Copyright (c) 2019 Tatsuya Tanaka 22 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 23 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | LICENSE 26 | } 27 | end 28 | -------------------------------------------------------------------------------- /Tests/ReplacerTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Tests/ReplacerTests/ReplacerTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ReplacerTests.swift 3 | // ReplacerTests 4 | // 5 | // Created by Tatsuya Tanaka on 2017/02/12. 6 | // Copyright © 2017年 tattn. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | @testable import Replacer 11 | 12 | 13 | class ReplacerTests: XCTestCase { 14 | 15 | override func setUp() { 16 | super.setUp() 17 | } 18 | 19 | override func tearDown() { 20 | super.tearDown() 21 | } 22 | 23 | func testReplaceStaticMethod() { 24 | 25 | class A { 26 | @objc dynamic class func a() -> String { return "a" } 27 | } 28 | 29 | class B { 30 | @objc dynamic class func b() -> String { return "b" } 31 | } 32 | 33 | XCTAssertEqual(A.a(), "a") 34 | 35 | replaceStatic(#selector(A.a), of: A.self, with: #selector(B.b), of: B.self) 36 | 37 | XCTAssertEqual(A.a(), "b") 38 | XCTAssertEqual(B.b(), "a") 39 | 40 | replaceStatic(#selector(A.a), of: A.self, with: #selector(B.b), of: B.self) 41 | 42 | XCTAssertEqual(A.a(), "a") 43 | XCTAssertEqual(B.b(), "b") 44 | } 45 | 46 | func testReplaceInstanceMethod() { 47 | 48 | class A { 49 | @objc dynamic func a() -> String { return "a" } 50 | } 51 | 52 | class B { 53 | @objc dynamic func b() -> String { return "b" } 54 | } 55 | 56 | replaceInstance(#selector(A.a), of: A.self, with: #selector(B.b), of: B.self) 57 | 58 | XCTAssertEqual(A().a(), "b") 59 | XCTAssertEqual(B().b(), "a") 60 | 61 | replaceInstance(#selector(A.a), of: A.self, with: #selector(B.b), of: B.self) 62 | 63 | XCTAssertEqual(A().a(), "a") 64 | XCTAssertEqual(B().b(), "b") 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /Tests/TestReplacerTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Tests/TestReplacerTests/TestReplacerTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestReplacerTests.swift 3 | // TestReplacerTests 4 | // 5 | // Created by Tatsuya Tanaka on 2017/02/12. 6 | // Copyright © 2017年 tattn. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | import Alamofire 11 | @testable import TestReplacer 12 | 13 | class TestReplacerTests: XCTestCase { 14 | 15 | var url = URL(string: "http://echo.jsontest.com/key/value/one/two")! 16 | 17 | #if !SWIFTPM // https://bugs.swift.org/browse/SR-2866 18 | func testJSONFile() { 19 | self.urlStub.url("echo.jsontest.com").json(filename: "sample", bundle: nil) 20 | 21 | let expectation = self.expectation(description: "") 22 | 23 | URLSession.shared.dataTask(with: url) { data, _, _ in 24 | let json = try! JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [String: String] 25 | XCTAssert(json["test"] == "data") 26 | expectation.fulfill() 27 | }.resume() 28 | 29 | self.waitForExpectations(timeout: 0.05, handler: nil) 30 | } 31 | #endif 32 | 33 | func testJSONObject() { 34 | self.urlStub.url("echo.jsontest.com/[a-z]+/.*").json(["test2": "data2"]) 35 | 36 | let expectation = self.expectation(description: "") 37 | 38 | URLSession(configuration: .default).dataTask(with: url) { data, _, _ in 39 | let json = try! JSONSerialization.jsonObject(with: data!, options: .allowFragments) as! [String: String] 40 | XCTAssert(json["test2"] == "data2") 41 | expectation.fulfill() 42 | }.resume() 43 | 44 | self.waitForExpectations(timeout: 0.05, handler: nil) 45 | } 46 | 47 | func testAlamofire() { 48 | self.urlStub.url("echo.jsontest.com").json(["test3": "data3"]) 49 | 50 | let expectation = self.expectation(description: "") 51 | 52 | Alamofire.request(url).responseJSON { response in 53 | let json = response.result.value as! [String: String] 54 | XCTAssert(json["test3"] == "data3") 55 | expectation.fulfill() 56 | } 57 | 58 | self.waitForExpectations(timeout: 0.05, handler: nil) 59 | } 60 | 61 | func testTimeout() { 62 | self.urlStub.url("echo.jsontest.com").json([:]).delay(2) 63 | 64 | let expectation = self.expectation(description: "") 65 | let expectation2 = self.expectation(description: "") 66 | 67 | let configuration = URLSessionConfiguration.default 68 | configuration.timeoutIntervalForRequest = 1 69 | 70 | URLSession(configuration: configuration).dataTask(with: url) { _, _, error in 71 | XCTAssert(error?._code == URLError.timedOut.rawValue) 72 | expectation.fulfill() 73 | }.resume() 74 | 75 | SessionManager(configuration: configuration).request(url).responseJSON { response in 76 | XCTAssert(response.result.error?._code == URLError.cancelled.rawValue) 77 | expectation2.fulfill() 78 | } 79 | 80 | self.waitForExpectations(timeout: 3, handler: nil) 81 | } 82 | 83 | func testError() { 84 | self.urlStub.url("echo.jsontest.com").error(NSError(domain: "", code: URLError.badServerResponse.rawValue)) 85 | 86 | let expectation = self.expectation(description: "") 87 | let expectation2 = self.expectation(description: "") 88 | 89 | URLSession.shared.dataTask(with: url) { _, _, error in 90 | XCTAssert(error?._code == URLError.badServerResponse.rawValue) 91 | expectation.fulfill() 92 | }.resume() 93 | 94 | SessionManager.default.request(url).responseJSON { response in 95 | XCTAssert(response.result.error?._code == URLError.badServerResponse.rawValue) 96 | expectation2.fulfill() 97 | } 98 | 99 | self.waitForExpectations(timeout: 0.05, handler: nil) 100 | } 101 | 102 | func testHTTPMethod() { 103 | self.urlStub.url("echo.jsontest.com").httpMethod(.get).json([:]) 104 | self.urlStub.url("echo.jsontest.com").httpMethod(.post).json(["test4": "data4"]) 105 | 106 | let expectation = self.expectation(description: "") 107 | let expectation2 = self.expectation(description: "") 108 | 109 | Alamofire.request(url).responseJSON { response in 110 | let json = response.result.value as? [String: String] 111 | XCTAssertNil(json?["test4"]) 112 | expectation.fulfill() 113 | } 114 | 115 | Alamofire.request(url, method: .post).responseJSON { response in 116 | let json = response.result.value as! [String: String] 117 | XCTAssert(json["test4"] == "data4") 118 | expectation2.fulfill() 119 | } 120 | 121 | self.waitForExpectations(timeout: 0.05, handler: nil) 122 | } 123 | 124 | func testRequestBlock() { 125 | self.urlStub.response { request in 126 | let json = try! JSONSerialization.data(withJSONObject: ["test5": "data5"], options: .prettyPrinted) 127 | return (json, nil) 128 | } 129 | 130 | let expectation = self.expectation(description: "") 131 | 132 | Alamofire.request(url).responseJSON { response in 133 | let json = response.result.value as! [String: String] 134 | XCTAssert(json["test5"] == "data5") 135 | expectation.fulfill() 136 | } 137 | 138 | self.waitForExpectations(timeout: 0.05, handler: nil) 139 | } 140 | 141 | func testStatusCode() { 142 | self.urlStub.statusCode(123).json([:]) 143 | 144 | let expectation = self.expectation(description: "") 145 | let expectation2 = self.expectation(description: "") 146 | 147 | URLSession.shared.dataTask(with: url) { _, response, _ in 148 | XCTAssert((response as? HTTPURLResponse)?.statusCode == 123) 149 | expectation.fulfill() 150 | }.resume() 151 | 152 | Alamofire.request(url).responseJSON { response in 153 | XCTAssert(response.response?.statusCode == 123) 154 | expectation2.fulfill() 155 | } 156 | 157 | self.waitForExpectations(timeout: 0.05, handler: nil) 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /Tests/TestReplacerTests/sample.json: -------------------------------------------------------------------------------- 1 | {"test": "data"} 2 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | ignore: Tests 3 | status: 4 | patch: false 5 | changes: false 6 | project: 7 | default: 8 | target: '80' 9 | 10 | comment: false 11 | --------------------------------------------------------------------------------