├── ResponseDetective
├── include
│ ├── ResponseDetective.h
│ ├── RDTBodyDeserializer.h
│ ├── RDTHTMLBodyDeserializer.h
│ └── RDTXMLBodyDeserializer.h
├── Configuration
│ ├── Tests-iOS.xcconfig
│ ├── Tests-macOS.xcconfig
│ ├── Tests-tvOS.xcconfig
│ ├── Framework-iOS.xcconfig
│ ├── Common-Debug.xcconfig
│ ├── Framework-tvOS.xcconfig
│ ├── Common-Release.xcconfig
│ ├── Framework-macOS.xcconfig
│ ├── Vendor
│ │ ├── Targets
│ │ │ ├── Tests.xcconfig
│ │ │ ├── Extension.xcconfig
│ │ │ ├── Application.xcconfig
│ │ │ └── Framework.xcconfig
│ │ ├── Common
│ │ │ ├── Carthage.xcconfig
│ │ │ ├── Variables.xcconfig
│ │ │ └── Common.xcconfig
│ │ ├── Platforms
│ │ │ ├── tvOS.xcconfig
│ │ │ ├── macOS.xcconfig
│ │ │ ├── watchOS.xcconfig
│ │ │ └── iOS.xcconfig
│ │ └── Configurations
│ │ │ ├── Release.xcconfig
│ │ │ └── Debug.xcconfig
│ ├── Tests-Base.xcconfig
│ ├── Common-Base.xcconfig
│ └── Framework-Base.xcconfig
├── Resources
│ ├── Framework.modulemap
│ ├── Framework-Info.plist
│ └── Tests-Info.plist
├── Sources
│ ├── RDTXMLBodyDeserializer.h
│ ├── RDTHTMLBodyDeserializer.h
│ ├── ResponseDetective.h
│ ├── PlaintextBodyDeserializer.swift
│ ├── Dictionary.swift
│ ├── JSONBodyDeserializer.swift
│ ├── ImageBodyDeserializer.swift
│ ├── RDTBodyDeserializer.h
│ ├── RDTHTMLBodyDeserializer.m
│ ├── RDTXMLBodyDeserializer.m
│ ├── OutputFacility.swift
│ ├── URLEncodedBodyDeserializer.swift
│ ├── BufferOutputFacility.swift
│ ├── ErrorRepresentation.swift
│ ├── RequestRepresentation.swift
│ ├── ResponseRepresentation.swift
│ ├── ConsoleOutputFacility.swift
│ ├── ResponseDetective.swift
│ └── URLProtocol.swift
└── Tests
│ ├── Specs
│ ├── PlaintextBodyDeserializerSpec.swift
│ ├── XMLBodyDeserializerSpec.swift
│ ├── HTMLBodyDeserializerSpec.swift
│ ├── JSONBodyDeserializerSpec.swift
│ ├── URLEncodedBodyDeserializerSpec.swift
│ ├── ResponseRepresentationSpec.swift
│ ├── BufferOutputFacilitySpec.swift
│ ├── RequestRepresentationSpec.swift
│ ├── ImageBodyDeserializerSpec.swift
│ ├── ErrorRepresentationSpec.swift
│ ├── ConsoleOutputFacilitySpec.swift
│ └── ResponseDetectiveSpec.swift
│ └── Additions
│ └── TestBodyDeserializer.swift
├── Images
└── Header.png
├── Cartfile.resolved
├── .gitattributes
├── ResponseDetective.playground
├── playground.xcworkspace
│ └── contents.xcworkspacedata
├── contents.xcplayground
└── Contents.swift
├── ResponseDetective.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcshareddata
│ └── xcschemes
│ │ ├── ResponseDetective-iOS.xcscheme
│ │ ├── ResponseDetective-tvOS.xcscheme
│ │ └── ResponseDetective-macOS.xcscheme
└── project.pbxproj
├── Cartfile.private
├── .gitignore
├── LICENSE.md
├── carthage.sh
├── ResponseDetective.podspec
├── Package.resolved
├── bitrise.yml
├── Package.swift
└── README.md
/ResponseDetective/include/ResponseDetective.h:
--------------------------------------------------------------------------------
1 | ../Sources/ResponseDetective.h
--------------------------------------------------------------------------------
/ResponseDetective/include/RDTBodyDeserializer.h:
--------------------------------------------------------------------------------
1 | ../Sources/RDTBodyDeserializer.h
--------------------------------------------------------------------------------
/ResponseDetective/include/RDTHTMLBodyDeserializer.h:
--------------------------------------------------------------------------------
1 | ../Sources/RDTHTMLBodyDeserializer.h
--------------------------------------------------------------------------------
/ResponseDetective/include/RDTXMLBodyDeserializer.h:
--------------------------------------------------------------------------------
1 | ../Sources/RDTXMLBodyDeserializer.h
--------------------------------------------------------------------------------
/Images/Header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netguru/ResponseDetective/HEAD/Images/Header.png
--------------------------------------------------------------------------------
/Cartfile.resolved:
--------------------------------------------------------------------------------
1 | github "AliSoftware/OHHTTPStubs" "9.1.0"
2 | github "Quick/Nimble" "v9.0.0"
3 | github "Quick/Quick" "v3.0.0"
4 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | #
2 | # .gitattributes
3 | #
4 | # Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | # Licensed under the MIT License.
6 | #
7 |
8 | .pbxproj merge=union
9 | *.strings text diff
10 |
--------------------------------------------------------------------------------
/ResponseDetective.playground/playground.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ResponseDetective.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ResponseDetective.playground/contents.xcplayground:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Tests-iOS.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Tests-iOS.xcconfig
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | // Imports
9 |
10 | #include "Tests-Base.xcconfig"
11 | #include "Vendor/Platforms/iOS.xcconfig"
12 |
--------------------------------------------------------------------------------
/ResponseDetective/Resources/Framework.modulemap:
--------------------------------------------------------------------------------
1 | //
2 | // Framework.modulemap
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | framework module ResponseDetective {
9 | umbrella header "ResponseDetective.h"
10 | export *
11 | }
12 |
--------------------------------------------------------------------------------
/Cartfile.private:
--------------------------------------------------------------------------------
1 | #
2 | # Cartfile.private
3 | #
4 | # Copyright © 2017-2020 Netguru S.A. All rights reserved.
5 | # Licensed under the MIT License.
6 | #
7 |
8 | # Test dependencies
9 |
10 | github "Quick/Quick" ~> 3.0.0
11 | github "Quick/Nimble" ~> 9.0.0
12 | github "AliSoftware/OHHTTPStubs" ~> 9.1.0
13 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Tests-macOS.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Tests-macOS.xcconfig
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | // Imports
9 |
10 | #include "Tests-Base.xcconfig"
11 | #include "Vendor/Platforms/macOS.xcconfig"
12 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Tests-tvOS.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Tests-tvOS.xcconfig
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | // Imports
9 |
10 | #include "Tests-Base.xcconfig"
11 | #include "Vendor/Platforms/tvOS.xcconfig"
12 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Framework-iOS.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Framework-iOS.xcconfig
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | // Imports
9 |
10 | #include "Framework-Base.xcconfig"
11 | #include "Vendor/Platforms/iOS.xcconfig"
12 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Common-Debug.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Common-Debug.xcconfig
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | // Imports
9 |
10 | #include "Common-Base.xcconfig"
11 | #include "Vendor/Configurations/Debug.xcconfig"
12 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Framework-tvOS.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Framework-tvOS.xcconfig
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | // Imports
9 |
10 | #include "Framework-Base.xcconfig"
11 | #include "Vendor/Platforms/tvOS.xcconfig"
12 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Common-Release.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Common-Release.xcconfig
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | // Imports
9 |
10 | #include "Common-Base.xcconfig"
11 | #include "Vendor/Configurations/Release.xcconfig"
12 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Framework-macOS.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Framework-macOS.xcconfig
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | // Imports
9 |
10 | #include "Framework-Base.xcconfig"
11 | #include "Vendor/Platforms/macOS.xcconfig"
12 |
--------------------------------------------------------------------------------
/ResponseDetective.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Vendor/Targets/Tests.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Targets/Tests.xcconfig
3 | //
4 | // Copyright © 2017 Netguru Sp. z o.o. All rights reserved.
5 | // Licensed under MIT License.
6 | //
7 | // This file contains build settings specific to test bundle targets.
8 | //
9 |
10 | // Inherit from Application target.
11 | #include "Application.xcconfig"
12 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Vendor/Targets/Extension.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Targets/Extension.xcconfig
3 | //
4 | // Copyright © 2017 Netguru Sp. z o.o. All rights reserved.
5 | // Licensed under MIT License.
6 | //
7 | // This file contains build settings specific to extension targets.
8 | //
9 |
10 | // Inherit from Application target.
11 | #include "Application.xcconfig"
12 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Vendor/Targets/Application.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Targets/Application.xcconfig
3 | //
4 | // Copyright © 2017 Netguru Sp. z o.o. All rights reserved.
5 | // Licensed under MIT License.
6 | //
7 | // This file contains build settings specific to application targets.
8 | //
9 |
10 | // MARK: Packaging
11 |
12 | // Define LLVM module.
13 | DEFINES_MODULE = YES
14 |
--------------------------------------------------------------------------------
/ResponseDetective/Sources/RDTXMLBodyDeserializer.h:
--------------------------------------------------------------------------------
1 | //
2 | // RDTXMLBodyDeserializer.h
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | @import Foundation;
9 | #import "RDTBodyDeserializer.h"
10 |
11 | /// Deserializes XML bodies.
12 | NS_SWIFT_NAME(XMLBodyDeserializer) @interface RDTXMLBodyDeserializer : NSObject
13 |
14 | // empty by design
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/ResponseDetective/Sources/RDTHTMLBodyDeserializer.h:
--------------------------------------------------------------------------------
1 | //
2 | // RDTHTMLBodyDeserializer.h
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | @import Foundation;
9 | #import "RDTBodyDeserializer.h"
10 |
11 | /// Deserializes HTML bodies.
12 | NS_SWIFT_NAME(HTMLBodyDeserializer) @interface RDTHTMLBodyDeserializer : NSObject
13 |
14 | // empty by design
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Tests-Base.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Tests-Base.xcconfig
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | // Imports
9 |
10 | #include "Vendor/Targets/Application.xcconfig"
11 |
12 | // Bundle
13 |
14 | _BUNDLE_NAME = ResponseDetectiveTests
15 | _BUNDLE_IDENTIFIER = co.netguru.lib.responsedetective.tests
16 | _BUNDLE_INFOPLIST_PATH = $(SRCROOT)/ResponseDetective/Resources/Tests-Info.plist
17 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #
2 | # .gitignore
3 | #
4 | # Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | # Licensed under the MIT License.
6 | #
7 |
8 | .DS_Store
9 | .localized
10 |
11 | xcuserdata
12 | profile
13 | build
14 | output
15 | DerivedData
16 | *.mode1v3
17 | *.mode2v3
18 | *.perspectivev3
19 | *.pbxuser
20 | *.xccheckout
21 | *.moved-aside
22 | *.hmap
23 | *.ipa
24 | *.o
25 | *.LinkFileList
26 | *.hmap
27 | *~.nib
28 | *.swp
29 | *.dat
30 | *.dep
31 |
32 | .idea
33 | *.iml
34 |
35 | Pods
36 | Carthage
37 | .build
38 | .swiftpm
39 |
--------------------------------------------------------------------------------
/ResponseDetective/Sources/ResponseDetective.h:
--------------------------------------------------------------------------------
1 | //
2 | // ResponseDetective.h
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | /// Project version number for ResponseDetective.
9 | extern double ResponseDetectiveVersionNumber;
10 |
11 | /// Project version string for ResponseDetective.
12 | extern const unsigned char ResponseDetectiveVersionString[];
13 |
14 | @import Foundation;
15 |
16 | #import "RDTBodyDeserializer.h"
17 | #import "RDTXMLBodyDeserializer.h"
18 | #import "RDTHTMLBodyDeserializer.h"
19 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Common-Base.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Common-Base.xcconfig
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | // Imports
9 |
10 | #include "Vendor/Common/Common.xcconfig"
11 | #include "Vendor/Common/Carthage.xcconfig"
12 |
13 | // MARK: Build
14 |
15 | _BUILD_VERSION = 1.5.0
16 |
17 | // MARK: Deployment
18 |
19 | _DEPLOYMENT_TARGET_IOS = 9.0
20 | _DEPLOYMENT_TARGET_MACOS = 10.10
21 | _DEPLOYMENT_TARGET_TVOS = 9.0
22 |
23 | // MARK: Compiler
24 |
25 | _COMPILER_SWIFT_VERSION = 5.2
26 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Framework-Base.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Framework-Base.xcconfig
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | // Imports
9 |
10 | #include "Vendor/Targets/Framework.xcconfig"
11 |
12 | // Bundle
13 |
14 | _BUNDLE_NAME = ResponseDetective
15 | _BUNDLE_IDENTIFIER = co.netguru.lib.responsedetective
16 | _BUNDLE_INFOPLIST_PATH = $(SRCROOT)/ResponseDetective/Resources/Framework-Info.plist
17 |
18 | // Compiler
19 |
20 | _COMPILER_OBJC_HEADER_SEARCH_PATHS = $(SDKROOT)/usr/include/libxml2
21 | _COMPILER_OBJC_LINKER_FLAGS = -lxml2
22 |
--------------------------------------------------------------------------------
/ResponseDetective/Sources/PlaintextBodyDeserializer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PlaintextBodyDeserializer.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 | #if SWIFT_PACKAGE
10 | import ResponseDetectiveObjC
11 | #endif
12 |
13 | /// Deserializes plaintext bodies.
14 | @objc(RDTPlaintextBodyDeserializer) public final class PlaintextBodyDeserializer: NSObject, BodyDeserializer {
15 |
16 | // MARK: BodyDeserializer
17 |
18 | /// Deserializes plaintext data into a string.
19 | public func deserialize(body: Data) -> String? {
20 | return NSString(data: body, encoding: String.Encoding.utf8.rawValue) as String?
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Vendor/Common/Carthage.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Common/Carthage.xcconfig
3 | //
4 | // Copyright © 2017 Netguru Sp. z o.o. All rights reserved.
5 | // Licensed under MIT License.
6 | //
7 | // This file contains base build settings for targets using Carthage.
8 | //
9 |
10 | // Path to top-level Carthage directory.
11 | _CARTHAGE_PATH = $(PROJECT_DIR)/Carthage
12 |
13 | // Path to platform-specific Carthage/Build directory.
14 | _CARTHAGE_BUILD_PATH[sdk=iphone*] = $(_CARTHAGE_PATH)/Build/iOS
15 | _CARTHAGE_BUILD_PATH[sdk=macosx*] = $(_CARTHAGE_PATH)/Build/Mac
16 | _CARTHAGE_BUILD_PATH[sdk=appletv*] = $(_CARTHAGE_PATH)/Build/tvOS
17 | _CARTHAGE_BUILD_PATH[sdk=watch*] = $(_CARTHAGE_PATH)/Build/watchOS
18 |
--------------------------------------------------------------------------------
/ResponseDetective/Tests/Specs/PlaintextBodyDeserializerSpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PlaintextBodyDeserializerSpec.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 | import Nimble
10 | import ResponseDetective
11 | import Quick
12 |
13 | internal final class PlaintextBodyDeserializerSpec: QuickSpec {
14 |
15 | override func spec() {
16 |
17 | describe("PlaintextBodyDeserializer") {
18 |
19 | let sut = PlaintextBodyDeserializer()
20 |
21 | it("should correctly deserialize plaintext data") {
22 | let source = "foo bar\nbaz qux"
23 | let data = source.data(using: .utf8)!
24 | let expected = source
25 | expect { sut.deserialize(body: data) }.to(equal(expected))
26 | }
27 |
28 | }
29 |
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/ResponseDetective/Sources/Dictionary.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Dictionary.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | extension Dictionary {
9 |
10 | /// Appends elements of other `dictionary` and returns a new one.
11 | ///
12 | /// - Parameters:
13 | /// - dictionary: The dictionary whose elements to append. Values
14 | /// under existing keys will replace values in `self`.
15 | ///
16 | /// - Returns: A `Dictionary` containing elements of `self` merged with
17 | /// elements of other `dictionary.
18 | internal func appending(elementsOf dictionary: [Key: Value]) -> [Key: Value] {
19 | var mutableSelf = self
20 | for (key, value) in dictionary {
21 | mutableSelf[key] = value
22 | }
23 | return mutableSelf
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Vendor/Platforms/tvOS.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Platforms/tvOS.xcconfig
3 | //
4 | // Copyright © 2017 Netguru Sp. z o.o. All rights reserved.
5 | // Licensed under MIT License.
6 | //
7 | // This file contains build settings specific to tvOS platform.
8 | //
9 |
10 | // MARK: Architecture
11 |
12 | // SDK root of tvOS.
13 | SDKROOT = appletvos
14 |
15 | // Supported platforms for tvOS.
16 | SUPPORTED_PLATFORMS = appletvos appletvsimulator
17 |
18 | // MARK: Deployment
19 |
20 | // Deployment target for tvOS.
21 | TVOS_DEPLOYMENT_TARGET = $(_DEPLOYMENT_TARGET_TVOS)
22 |
23 | // Supported device families for tvOS.
24 | TARGETED_DEVICE_FAMILY = $(_DEPLOYMENT_DEVICES_TVOS)
25 |
26 | // MARK: Linker
27 |
28 | // Where to find embedded frameworks for tvOS.
29 | LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks
30 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Vendor/Platforms/macOS.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Platforms/macOS.xcconfig
3 | //
4 | // Copyright © 2017 Netguru Sp. z o.o. All rights reserved.
5 | // Licensed under MIT License.
6 | //
7 | // This file contains build settings specific to macOS platform.
8 | //
9 |
10 | // MARK: Architecture
11 |
12 | // SDK root of macOS.
13 | SDKROOT = macosx
14 |
15 | // Supported platforms for macOS.
16 | SUPPORTED_PLATFORMS = macosx
17 |
18 | // MARK: Deployment
19 |
20 | // Deployment target for macOS.
21 | MACOSX_DEPLOYMENT_TARGET = $(_DEPLOYMENT_TARGET_MACOS)
22 |
23 | // MARK: Compiler
24 |
25 | // Whether to combine multiple image resolutions into a TIFF.
26 | COMBINE_HIDPI_IMAGES = YES
27 |
28 | // MARK: Linker
29 |
30 | // Where to find embedded frameworks for macOS.
31 | LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/../Frameworks @loader_path/../Frameworks
32 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Vendor/Platforms/watchOS.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Platforms/watchOS.xcconfig
3 | //
4 | // Copyright © 2017 Netguru Sp. z o.o. All rights reserved.
5 | // Licensed under MIT License.
6 | //
7 | // This file contains build settings specific to watchOS platform.
8 | //
9 |
10 | // MARK: Architecture
11 |
12 | // SDK root of tvOS.
13 | SDKROOT = watchos
14 |
15 | // Supported platforms for watchOS.
16 | SUPPORTED_PLATFORMS = watchos watchsimulator
17 |
18 | // MARK: Deployment
19 |
20 | // Deployment target for watchOS.
21 | WATCHOS_DEPLOYMENT_TARGET = $(_DEPLOYMENT_TARGET_WATCHOS)
22 |
23 | // Supported device families for watchOS.
24 | TARGETED_DEVICE_FAMILY = $(_DEPLOYMENT_DEVICES_WATCHOS)
25 |
26 | // MARK: Linker
27 |
28 | // Where to find embedded frameworks for watchOS.
29 | LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks
30 |
--------------------------------------------------------------------------------
/ResponseDetective/Sources/JSONBodyDeserializer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // JSONBodyDeserializer.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 | #if SWIFT_PACKAGE
10 | import ResponseDetectiveObjC
11 | #endif
12 |
13 | /// Deserializes JSON bodies.
14 | @objc(RDTJSONBodyDeserializer) public final class JSONBodyDeserializer: NSObject, BodyDeserializer {
15 |
16 | // MARK: BodyDeserializer
17 |
18 | /// Deserializes JSON data into a pretty-printed string.
19 | public func deserialize(body: Data) -> String? {
20 | do {
21 | let object = try JSONSerialization.jsonObject(with: body, options: [])
22 | let data = try JSONSerialization.data(withJSONObject: object, options: [.prettyPrinted])
23 | return String(data: data, encoding: .utf8)
24 | } catch {
25 | return nil
26 | }
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/ResponseDetective/Resources/Framework-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en_US
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 | $(PRODUCT_BUNDLE_VERSION_STRING)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(PRODUCT_BUNDLE_VERSION)
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ResponseDetective/Resources/Tests-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en_US
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 | $(PRODUCT_BUNDLE_VERSION_STRING)
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | $(PRODUCT_BUNDLE_VERSION)
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ResponseDetective/Tests/Specs/XMLBodyDeserializerSpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // XMLBodyDeserializerSpec.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 | import Nimble
10 | import ResponseDetective
11 | #if SWIFT_PACKAGE
12 | import ResponseDetectiveObjC
13 | #endif
14 | import Quick
15 |
16 | internal final class XMLBodyDeserializerSpec: QuickSpec {
17 |
18 | override func spec() {
19 |
20 | describe("XMLBodyDeserializer") {
21 |
22 | let sut = XMLBodyDeserializer()
23 |
24 | it("should correctly deserialize XML data") {
25 | let source = ""
26 | let data = source.data(using: .utf8)!
27 | let expected = "\n\n \n"
28 | expect { sut.deserialize(body: data) }.to(equal(expected))
29 | }
30 |
31 | }
32 |
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Vendor/Targets/Framework.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Targets/Framework.xcconfig
3 | //
4 | // Copyright © 2017 Netguru Sp. z o.o. All rights reserved.
5 | // Licensed under MIT License.
6 | //
7 | // This file contains build settings specific to framework targets.
8 | //
9 |
10 | // MARK: Build options
11 |
12 | // Disallow use of APIs that are not available to app extensions and linking to
13 | // frameworks that have not been built with this setting enabled.
14 | APPLICATION_EXTENSION_API_ONLY = YES
15 |
16 | // MARK: Deployment
17 |
18 | // Install in run path.
19 | INSTALL_PATH = @rpath
20 |
21 | // Skip installation.
22 | SKIP_INSTALL = YES
23 |
24 | // MARK: Linking
25 |
26 | // Enable framework to be included from any location as long as the run path
27 | // includes it.
28 | LD_DYLIB_INSTALL_NAME = @rpath/$(PRODUCT_NAME).$(WRAPPER_EXTENSION)/$(PRODUCT_NAME)
29 |
30 | // MARK: Packaging
31 |
32 | // Define LLVM module.
33 | DEFINES_MODULE = YES
34 |
--------------------------------------------------------------------------------
/ResponseDetective/Sources/ImageBodyDeserializer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageBodyDeserializer.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | #if os(iOS) || os(tvOS) || os(watchOS)
9 | import UIKit
10 | #elseif os(OSX)
11 | import AppKit
12 | #endif
13 | #if SWIFT_PACKAGE
14 | import ResponseDetectiveObjC
15 | #endif
16 |
17 | /// Deserializes image bodies.
18 | @objc(RDTImageBodyDeserializer) public final class ImageBodyDeserializer: NSObject, BodyDeserializer {
19 |
20 | // MARK: Nested types
21 |
22 | #if os(iOS) || os(tvOS) || os(watchOS)
23 | private typealias Image = UIImage
24 | #elseif os(OSX)
25 | private typealias Image = NSImage
26 | #endif
27 |
28 | // MARK: BodyDeserializer
29 |
30 | /// Deserializes image data into a pretty-printed string.
31 | public func deserialize(body: Data) -> String? {
32 | return Image(data: body).map { "\(Int($0.size.width))px × \(Int($0.size.height))px image" }
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/ResponseDetective/Sources/RDTBodyDeserializer.h:
--------------------------------------------------------------------------------
1 | //
2 | // RDTBodyDeserializer.h
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 | // This has been implemented as native Objective-C protocol instead of a Swift
8 | // protocol bridged to Objective-C because Swift protocol definition cannot be
9 | // imported in Objective-C header since it causes include cycle in the umbrella
10 | // header.
11 |
12 | @import Foundation;
13 |
14 | /// Represents a body deserializer which is able to deserialize raw body data
15 | /// into a human-readable string which will be logged as the request's or
16 | /// response's body.
17 | NS_SWIFT_NAME(BodyDeserializer) @protocol RDTBodyDeserializer
18 |
19 | @required
20 |
21 | /// Deserializes the body.
22 | ///
23 | /// @param body The HTTP body.
24 | ///
25 | /// @return A deserialized representation of the body.
26 | - (nullable NSString *)deserializeBody:(nonnull NSData *)body NS_SWIFT_NAME(deserialize(body:));
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/ResponseDetective/Tests/Specs/HTMLBodyDeserializerSpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // HTMLBodyDeserializerSpec.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 | import Nimble
10 | import ResponseDetective
11 | #if SWIFT_PACKAGE
12 | import ResponseDetectiveObjC
13 | #endif
14 | import Quick
15 |
16 | internal final class HTMLBodyDeserializerSpec: QuickSpec {
17 |
18 | override func spec() {
19 |
20 | describe("HTMLBodyDeserializer") {
21 |
22 | let sut = HTMLBodyDeserializer()
23 |
24 | it("should correctly deserialize HTML data") {
25 | let source = "lorem
ipsum
"
26 | let data = source.data(using: .utf8)!
27 | let expected = "\n\n\nlorem
ipsum
\n"
28 | expect { sut.deserialize(body: data) }.to(equal(expected))
29 | }
30 |
31 | }
32 |
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Vendor/Platforms/iOS.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Platforms/iOS.xcconfig
3 | //
4 | // Copyright © 2017 Netguru Sp. z o.o. All rights reserved.
5 | // Licensed under MIT License.
6 | //
7 | // This file contains build settings specific to iOS platform.
8 | //
9 |
10 | // MARK: Architecture
11 |
12 | // SDK root of iOS.
13 | SDKROOT = iphoneos
14 |
15 | // Supported platforms for iOS.
16 | SUPPORTED_PLATFORMS = iphoneos iphonesimulator
17 |
18 | // MARK: Deployment
19 |
20 | // Deployment target for iOS.
21 | IPHONEOS_DEPLOYMENT_TARGET = $(_DEPLOYMENT_TARGET_IOS)
22 |
23 | // Supported device families for iOS.
24 | TARGETED_DEVICE_FAMILY = $(_DEPLOYMENT_DEVICES_IOS)
25 |
26 | // MARK: Linking
27 |
28 | // Where to find embedded frameworks for iOS.
29 | LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks
30 |
31 | // MARK: Search paths
32 |
33 | // Xcode needs this to find archived headers if `SKIP_INSTALL` is set.
34 | HEADER_SEARCH_PATHS = $(inherited) $(OBJROOT)/UninstalledProducts/include
35 |
--------------------------------------------------------------------------------
/ResponseDetective/Sources/RDTHTMLBodyDeserializer.m:
--------------------------------------------------------------------------------
1 | //
2 | // RDTHTMLBodyDeserializer.m
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | #import
9 | #import "RDTHTMLBodyDeserializer.h"
10 |
11 | @implementation RDTHTMLBodyDeserializer
12 |
13 | // MARK: RDTBodyDeserializer
14 |
15 | - (nullable NSString *)deserializeBody:(nonnull NSData *)body {
16 | NSString *string = [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding];
17 | const char *memory = string.UTF8String;
18 | htmlDocPtr document = htmlReadMemory(memory, ((int)(strlen(memory))), NULL, NULL, HTML_PARSE_NOBLANKS);
19 | xmlChar *buffer = NULL;
20 | int bufferLength = 0;
21 | htmlDocDumpMemoryFormat(document, &buffer, &bufferLength, 1);
22 | NSString *result = [[NSString alloc] initWithBytes:buffer length:bufferLength encoding:NSUTF8StringEncoding];
23 | xmlFree(buffer);
24 | return [result stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
25 | }
26 |
27 | @end
28 |
--------------------------------------------------------------------------------
/ResponseDetective/Tests/Specs/JSONBodyDeserializerSpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // JSONBodyDeserializerSpec.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 | import Nimble
10 | import ResponseDetective
11 | import Quick
12 |
13 | internal final class JSONBodyDeserializerSpec: QuickSpec {
14 |
15 | override func spec() {
16 |
17 | describe("JSONBodyDeserializer") {
18 |
19 | let sut = JSONBodyDeserializer()
20 |
21 | it("should correctly deserialize JSON data") {
22 | let source: [String: Any] = ["foo": "", "bar": 0, "baz": false, "qux": [AnyObject](), "corge": [String: Any]()]
23 | let data = try! JSONSerialization.data(withJSONObject: source, options: [])
24 | let actualData = sut.deserialize(body: data)!.data(using: .utf8)!
25 | let actualJSON = try! JSONSerialization.jsonObject(with: actualData, options: []) as! [String: Any]
26 |
27 | expect { (actualJSON as NSDictionary) }.to(equal(source as NSDictionary))
28 | }
29 |
30 | }
31 |
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/ResponseDetective.playground/Contents.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResponseDetective.playground
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 | import PlaygroundSupport
10 | import ResponseDetective
11 |
12 | // Enable indefinite execution so that requests complete before the playground
13 | // is killed.
14 |
15 | PlaygroundPage.current.needsIndefiniteExecution = true
16 |
17 | //: ---
18 |
19 | // Start by creating a session configuration that includes ResponseDetective's
20 | // interception mechanisms.
21 |
22 | let configuration = URLSessionConfiguration.default
23 | ResponseDetective.enable(inConfiguration: configuration)
24 |
25 | // And use the above configuration to create your session instance.
26 |
27 | let session = URLSession(configuration: configuration)
28 |
29 | //: ---
30 |
31 | // Now, just create a request and resume its session data task.
32 |
33 | let request = URLRequest(url: URL(string: "https://httpbin.org/get")!)
34 | session.dataTask(with: request).resume()
35 |
36 | // Watch the console! 🎉
37 |
--------------------------------------------------------------------------------
/ResponseDetective/Sources/RDTXMLBodyDeserializer.m:
--------------------------------------------------------------------------------
1 | //
2 | // RDTXMLBodyDeserializer.m
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | #import
9 | #import
10 | #import "RDTXMLBodyDeserializer.h"
11 |
12 | @implementation RDTXMLBodyDeserializer
13 |
14 | // MARK: RDTBodyDeserializer
15 |
16 | - (nullable NSString *)deserializeBody:(nonnull NSData *)body {
17 | NSString *string = [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding];
18 | const char *memory = string.UTF8String;
19 | xmlDocPtr document = xmlReadMemory(memory, ((int)(strlen(memory))), NULL, NULL, XML_PARSE_NOCDATA | XML_PARSE_NOBLANKS);
20 | xmlChar *buffer = NULL;
21 | int bufferLength = 0;
22 | xmlDocDumpFormatMemory(document, &buffer, &bufferLength, 1);
23 | NSString *result = [[NSString alloc] initWithBytes:buffer length:bufferLength encoding:NSUTF8StringEncoding];
24 | xmlFree(buffer);
25 | return [result stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
26 | }
27 |
28 | @end
29 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright © 2017-2020 Netguru S.A.
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 |
--------------------------------------------------------------------------------
/ResponseDetective/Sources/OutputFacility.swift:
--------------------------------------------------------------------------------
1 | //
2 | // OutputFacility.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 |
10 | /// Represents an output facility which is capable of displaying requests,
11 | /// responses and errors.
12 | @objc(RDTOutputFacility) public protocol OutputFacility {
13 |
14 | /// Outputs a request representation.
15 | ///
16 | /// - Parameters:
17 | /// - request: The request representation to output.
18 | @objc(outputRequestRepresentation:) func output(requestRepresentation request: RequestRepresentation)
19 |
20 | /// Outputs a response representation.
21 | ///
22 | /// - Parameters:
23 | /// - response: The response representation to output.
24 | @objc(outputResponseRepresentation:) func output(responseRepresentation response: ResponseRepresentation)
25 |
26 | /// Outputs an error representation.
27 | ///
28 | /// - Parameters:
29 | /// - error: The error representation to output.
30 | @objc(outputErrorRepresentation:) func output(errorRepresentation error: ErrorRepresentation)
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/carthage.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Usage example: ./carthage.sh build --platform iOS
4 | #
5 | # This script fixes the issue with carthage being unable to produce fat
6 | # frameworks. This is needed until the following issue is fixed:
7 | # https://github.com/Carthage/Carthage/issues/3019
8 |
9 | # Forward inner failures.
10 | set -euo pipefail
11 |
12 | # Create a temporary xcconfig file for building the dependencies.
13 | xcconfig=$(mktemp /tmp/static.xcconfig.XXXXXX)
14 | trap 'rm -f "$xcconfig"' INT TERM HUP EXIT
15 |
16 | # For Xcode 12 make sure EXCLUDED_ARCHS is set to arm architectures otherwise
17 | # the build will fail on lipo due to duplicate architectures.
18 | echo 'EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1200 = arm64 arm64e armv7 armv7s armv6 armv8' >> $xcconfig
19 | echo 'EXCLUDED_ARCHS = $(inherited) $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_$(EFFECTIVE_PLATFORM_SUFFIX)__NATIVE_ARCH_64_BIT_$(NATIVE_ARCH_64_BIT)__XCODE_$(XCODE_VERSION_MAJOR))' >> $xcconfig
20 |
21 | # Run carthage with the temporary xcconfig file and forwarded arguments.
22 | export XCODE_XCCONFIG_FILE="$xcconfig"
23 | carthage "$@"
24 |
--------------------------------------------------------------------------------
/ResponseDetective/Sources/URLEncodedBodyDeserializer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URLEncodedBodyDeserializer.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 | #if SWIFT_PACKAGE
10 | import ResponseDetectiveObjC
11 | #endif
12 |
13 | /// Deserializes URL-encoded bodies.
14 | @objc(RDTURLEncodedBodyDeserializer) public final class URLEncodedBodyDeserializer: NSObject, BodyDeserializer {
15 |
16 | // MARK: BodyDeserializer
17 |
18 | /// Deserializes JSON data into a pretty-printed string.
19 | public func deserialize(body: Data) -> String? {
20 |
21 | guard let string = String(data: body, encoding: .utf8) else {
22 | return nil
23 | }
24 |
25 | if #available(macOS 10.10, *) {
26 |
27 | let stringFromQueryItems: ([URLQueryItem]) -> String = {
28 | $0.map { "\($0.name): \($0.value ?? "nil")" }.joined(separator: "\n")
29 | }
30 |
31 | if let items = URLComponents(string: string)?.queryItems {
32 | return stringFromQueryItems(items)
33 | }
34 |
35 | if let items = URLComponents(string: "?\(string)")?.queryItems {
36 | return stringFromQueryItems(items)
37 | }
38 |
39 | }
40 |
41 | return string
42 |
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Vendor/Configurations/Release.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Configurations/Release.xcconfig
3 | //
4 | // Copyright © 2017 Netguru Sp. z o.o. All rights reserved.
5 | // Licensed under MIT License.
6 | //
7 | // This file contains build settings specific to release configuration.
8 | //
9 |
10 | // MARK: Environment
11 |
12 | // Set release environments.
13 | _ENVIRONMENTS = ENV_RELEASE
14 |
15 | // MARK: Architecture
16 |
17 | // Build for all architectures.
18 | ONLY_ACTIVE_ARCH = NO
19 |
20 | // MARK: Build options
21 |
22 | // Disallow `@testable` imports.
23 | ENABLE_TESTABILITY = NO
24 |
25 | // MARK: Deployment
26 |
27 | // Strip debugging symbols when copying resources.
28 | COPY_PHASE_STRIP = YES
29 |
30 | // Strip debugging symbols when copying the built product to its final
31 | // installation location.
32 | STRIP_INSTALLED_PRODUCT = YES
33 |
34 | // MARK: LLVM compiler
35 |
36 | // Enable GCC optimization.
37 | GCC_OPTIMIZATION_LEVEL = s
38 |
39 | // MARK: Asset compiler
40 |
41 | // Optimize assets for space.
42 | ASSETCATALOG_COMPILER_OPTIMIZATION = space
43 |
44 | // MARK: Swift compiler
45 |
46 | // Enable whole-module compilation for Swift.
47 | SWIFT_COMPILATION_MODE = wholemodule
48 |
49 | // Enable whole-module optimization for Swift.
50 | SWIFT_OPTIMIZATION_LEVEL = -Owholemodule
51 |
--------------------------------------------------------------------------------
/ResponseDetective.podspec:
--------------------------------------------------------------------------------
1 | #
2 | # ResponseDetective.podspec
3 | #
4 | # Copyright © 2017-2020 Netguru S.A. All rights reserved.
5 | # Licensed under the MIT License.
6 | #
7 |
8 | Pod::Spec.new do |spec|
9 |
10 | # Description
11 |
12 | spec.name = 'ResponseDetective'
13 | spec.version = '1.5.0'
14 | spec.summary = 'Sherlock Holmes of the networking layer'
15 | spec.homepage = 'https://github.com/netguru/ResponseDetective'
16 |
17 | # License
18 |
19 | spec.license = {
20 | type: 'MIT',
21 | file: 'LICENSE.md'
22 | }
23 |
24 | spec.authors = {
25 | 'Adrian Kashivskyy' => 'adrian.kashivskyy@netguru.co',
26 | 'Aleksander Popko' => 'aleksander.popko@netguru.co'
27 | }
28 |
29 | # Source
30 |
31 | spec.source = {
32 | git: 'https://github.com/netguru/ResponseDetective.git',
33 | tag: spec.version.to_s
34 | }
35 |
36 | spec.source_files = 'ResponseDetective/Sources'
37 | spec.module_map = 'ResponseDetective/Resources/Framework.modulemap'
38 |
39 | # Linking
40 |
41 | spec.frameworks = 'Foundation'
42 | spec.libraries = 'xml2'
43 |
44 | spec.ios.frameworks = 'UIKit'
45 | spec.osx.frameworks = 'AppKit'
46 |
47 | # Settings
48 |
49 | spec.swift_version = '5.2'
50 |
51 | spec.requires_arc = true
52 |
53 | spec.ios.deployment_target = '8.0'
54 | spec.osx.deployment_target = '10.10'
55 | spec.tvos.deployment_target = '9.0'
56 |
57 | spec.pod_target_xcconfig = {
58 | 'HEADER_SEARCH_PATHS' => '$(SDKROOT)/usr/include/libxml2'
59 | }
60 |
61 | end
62 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Vendor/Configurations/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Configurations/Debug.xcconfig
3 | //
4 | // Copyright © 2017 Netguru Sp. z o.o. All rights reserved.
5 | // Licensed under MIT License.
6 | //
7 | // This file contains build settings specific to debug configuration.
8 | //
9 |
10 | // MARK: Environment
11 |
12 | // Set debug environments.
13 | _ENVIRONMENTS = ENV_DEBUG
14 |
15 | // MARK: Architecture
16 |
17 | // Build only the active architecture.
18 | ONLY_ACTIVE_ARCH = YES
19 |
20 | // MARK: Build options
21 |
22 | // Allow `@testable` imports.
23 | ENABLE_TESTABILITY = $(_BUNDLE_TESTABLE)
24 |
25 | // MARK: Deployment
26 |
27 | // Do not strip debugging symbols when copying resources.
28 | COPY_PHASE_STRIP = NO
29 |
30 | // Do not strip debugging symbols when copying the built product to its final
31 | // installation location.
32 | STRIP_INSTALLED_PRODUCT = NO
33 |
34 | // MARK: Signing
35 |
36 | // Disable Developer ID timestamping.
37 | OTHER_CODE_SIGN_FLAGS = --timestamp=none
38 |
39 | // MARK: LLVM compiler
40 |
41 | // Disable GCC optimization.
42 | GCC_OPTIMIZATION_LEVEL = 0
43 |
44 | // Catch errors in integer arithmetic.
45 | OTHER_CFLAGS = -ftrapv
46 |
47 | // MARK: Asset compiler
48 |
49 | // Optimize assets for time.
50 | ASSETCATALOG_COMPILER_OPTIMIZATION = time
51 |
52 | // MARK: Swift compiler
53 |
54 | // Disable whole-module compilation for Swift.
55 | SWIFT_COMPILATION_MODE = singlefile
56 |
57 | // Disable optimizations for Swift.
58 | SWIFT_OPTIMIZATION_LEVEL = -Onone
59 |
--------------------------------------------------------------------------------
/ResponseDetective/Tests/Additions/TestBodyDeserializer.swift:
--------------------------------------------------------------------------------
1 | //
2 | // TestBodyDeserializer.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import ResponseDetective
9 | #if SWIFT_PACKAGE
10 | import ResponseDetectiveObjC
11 | #endif
12 |
13 | /// A test body deserializer.
14 | internal final class TestBodyDeserializer: NSObject, BodyDeserializer {
15 |
16 | /// The closure for deserializing bodies.
17 | let deserializationClosure: @convention(block) (Data) -> String?
18 |
19 | /// Creates a general deserializer with given deserialization closure.
20 | ///
21 | /// - Parameter deserializationClosure: Implementation of `deserializeBody`.
22 | internal init(deserializationClosure: @escaping @convention(block) (Data) -> String?) {
23 | self.deserializationClosure = deserializationClosure
24 | }
25 |
26 | /// Creates a deserializer with fixed deserialized body.
27 | ///
28 | /// - Parameter fixedDeserializedBody: A fixed deserialized body.
29 | internal convenience init(fixedDeserializedBody: String?) {
30 | self.init { _ in fixedDeserializedBody }
31 | }
32 |
33 | /// Creates a deserializer which deserializes data into plaintext.
34 | internal convenience override init() {
35 | self.init { String(data: $0, encoding: .utf8) as String? }
36 | }
37 |
38 | // MARK: Implementation
39 |
40 | /// - SeeAlso: BodyDeserializer.deserializeBody(_:)
41 | internal func deserialize(body data: Data) -> String? {
42 | return deserializationClosure(data)
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/ResponseDetective/Tests/Specs/URLEncodedBodyDeserializerSpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URLEncodedBodyDeserializerSpec.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 | import Nimble
10 | import ResponseDetective
11 | import Quick
12 |
13 | internal final class URLEncodedBodyDeserializerSpec: QuickSpec {
14 |
15 | override func spec() {
16 |
17 | describe("URLEncodedBodyDeserializer") {
18 |
19 | let sut = URLEncodedBodyDeserializer()
20 |
21 | it("should correctly deserialize URL-encoded data") {
22 |
23 | if #available(macOS 10.10, *) {
24 |
25 | let items = [URLQueryItem(name: "foo", value: nil), URLQueryItem(name: "bar", value: "baz")]
26 | let components = URLComponents(queryItems: items)
27 | let data = components.url!.relativeString.data(using: .utf8)!
28 |
29 | let actualString = sut.deserialize(body: data)
30 | let expectedString = "foo: nil\nbar: baz"
31 |
32 | expect(actualString).to(equal(expectedString))
33 |
34 | } else {
35 |
36 | let expectedString = "foo&bar=baz"
37 | let actualString = sut.deserialize(body: expectedString.data(using: .utf8)!)
38 |
39 | expect(actualString).to(equal(expectedString))
40 |
41 | }
42 |
43 | }
44 |
45 | }
46 |
47 | }
48 |
49 | }
50 |
51 | // MARK: -
52 |
53 | @available(macOS 10.10, *) extension URLComponents {
54 |
55 | fileprivate init(queryItems: [URLQueryItem]) {
56 | self.init()
57 | self.queryItems = queryItems
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "object": {
3 | "pins": [
4 | {
5 | "package": "CwlCatchException",
6 | "repositoryURL": "https://github.com/mattgallagher/CwlCatchException.git",
7 | "state": {
8 | "branch": null,
9 | "revision": "682841464136f8c66e04afe5dbd01ab51a3a56f2",
10 | "version": "2.1.0"
11 | }
12 | },
13 | {
14 | "package": "CwlPreconditionTesting",
15 | "repositoryURL": "https://github.com/mattgallagher/CwlPreconditionTesting.git",
16 | "state": {
17 | "branch": null,
18 | "revision": "02b7a39a99c4da27abe03cab2053a9034379639f",
19 | "version": "2.0.0"
20 | }
21 | },
22 | {
23 | "package": "Nimble",
24 | "repositoryURL": "https://github.com/Quick/Nimble.git",
25 | "state": {
26 | "branch": null,
27 | "revision": "e491a6731307bb23783bf664d003be9b2fa59ab5",
28 | "version": "9.0.0"
29 | }
30 | },
31 | {
32 | "package": "OHHTTPStubs",
33 | "repositoryURL": "https://github.com/AliSoftware/OHHTTPStubs.git",
34 | "state": {
35 | "branch": null,
36 | "revision": "12f19662426d0434d6c330c6974d53e2eb10ecd9",
37 | "version": "9.1.0"
38 | }
39 | },
40 | {
41 | "package": "Quick",
42 | "repositoryURL": "https://github.com/Quick/Quick.git",
43 | "state": {
44 | "branch": null,
45 | "revision": "0038bcbab4292f3b028632556507c124e5ba69f3",
46 | "version": "3.0.0"
47 | }
48 | }
49 | ]
50 | },
51 | "version": 1
52 | }
53 |
--------------------------------------------------------------------------------
/ResponseDetective/Sources/BufferOutputFacility.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BufferOutputFacility.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 |
10 | /// An output facility that adds received representations to array buffers.
11 | @objc(RDTBufferOutputFacility) public final class BufferOutputFacility: NSObject, OutputFacility {
12 |
13 | // MARK: Properties
14 |
15 | /// A buffer of request representations.
16 | public private(set) var requestRepresentations: [RequestRepresentation] = []
17 |
18 | /// A buffer of request representations.
19 | public private(set) var responseRepresentations: [ResponseRepresentation] = []
20 |
21 | /// A buffer of request representations.
22 | public private(set) var errorRepresentations: [ErrorRepresentation] = []
23 |
24 | // MARK: OutputFacility
25 |
26 | /// Adds the request representation to the buffer.
27 | ///
28 | /// - SeeAlso: OutputFacility.output(requestRepresentation:)
29 | public func output(requestRepresentation request: RequestRepresentation) {
30 | requestRepresentations.append(request)
31 | }
32 |
33 | /// Adds the response representation to the buffer.
34 | ///
35 | /// - SeeAlso: OutputFacility.output(responseRepresentation:)
36 | public func output(responseRepresentation response: ResponseRepresentation) {
37 | responseRepresentations.append(response)
38 | }
39 |
40 | /// Adds the error representation to the buffer.
41 | ///
42 | /// - SeeAlso: OutputFacility.output(errorRepresentation:)
43 | public func output(errorRepresentation error: ErrorRepresentation) {
44 | errorRepresentations.append(error)
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/ResponseDetective/Tests/Specs/ResponseRepresentationSpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResponseRepresentationSpec.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 | import Nimble
10 | import ResponseDetective
11 | import Quick
12 |
13 | internal final class ResponseRepresentationSpec: QuickSpec {
14 |
15 | override func spec() {
16 |
17 | describe("ResponseRepresentation") {
18 |
19 | context("after initializing with a response") {
20 |
21 | let fixtureResponse = HTTPURLResponse(
22 | url: URL(string: "https://httpbin.org/post")!,
23 | statusCode: 200,
24 | httpVersion: nil,
25 | headerFields: [
26 | "Content-Type": "application/json",
27 | "X-Foo": "bar"
28 | ]
29 | )!
30 |
31 | let fixtureBody = try! JSONSerialization.data(withJSONObject: ["foo": "bar"], options: [])
32 | let fixtureIdentifier = "1"
33 |
34 | var sut: ResponseRepresentation!
35 |
36 | beforeEach {
37 | sut = ResponseRepresentation(requestIdentifier: fixtureIdentifier, response: fixtureResponse, body: fixtureBody, deserializedBody: nil)
38 | }
39 |
40 | it("should have a correct identifier") {
41 | expect(sut.requestIdentifier).to(equal(fixtureIdentifier))
42 | }
43 |
44 | it("should have a correct URLString") {
45 | expect(sut.urlString).to(equal(fixtureResponse.url!.absoluteString))
46 | }
47 |
48 | it("should have a correct method") {
49 | expect(sut.statusCode).to(equal(fixtureResponse.statusCode))
50 | }
51 |
52 | it("should have correct headers") {
53 | expect(sut.headers).to(equal(fixtureResponse.allHeaderFields as? [String: String]))
54 | }
55 |
56 | it("should have a correct body") {
57 | expect(sut.body).to(equal(fixtureBody))
58 | }
59 |
60 | }
61 |
62 | }
63 |
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/ResponseDetective/Tests/Specs/BufferOutputFacilitySpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // BufferOutputFacilitySpec.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 | import Nimble
10 | import ResponseDetective
11 | import Quick
12 |
13 | internal final class BufferOutputFacilitySpec: QuickSpec {
14 |
15 | override func spec() {
16 |
17 | describe("BufferOutputFacility") {
18 |
19 | let sut = BufferOutputFacility()
20 |
21 | it("should buffer request representations") {
22 | let request = RequestRepresentation(
23 | identifier: "0",
24 | method: "GET",
25 | urlString: "http://foo.bar",
26 | headers: [
27 | "X-Foo": "bar",
28 | "X-Baz": "qux",
29 | ],
30 | body: nil,
31 | deserializedBody: "lorem ipsum"
32 | )
33 | sut.output(requestRepresentation: request)
34 | expect(sut.requestRepresentations.count).to(beGreaterThanOrEqualTo(1))
35 | }
36 |
37 | it("should buffer response representation") {
38 | let response = ResponseRepresentation(
39 | requestIdentifier: "0",
40 | statusCode: 200,
41 | urlString: "http://foo.bar",
42 | headers: [
43 | "X-Bar": "foo",
44 | "X-Qux": "baz",
45 | ],
46 | body: nil,
47 | deserializedBody: "dolor sit amet"
48 | )
49 | sut.output(responseRepresentation: response)
50 | expect(sut.responseRepresentations.count).to(beGreaterThanOrEqualTo(1))
51 | }
52 |
53 | it("should buffer error representations") {
54 | let error = ErrorRepresentation(
55 | requestIdentifier: "0",
56 | response: nil,
57 | domain: "foo.bar.error",
58 | code: 1234,
59 | reason: "just because",
60 | userInfo: [
61 | "foo": "bar",
62 | "baz": "qux",
63 | ]
64 | )
65 | sut.output(errorRepresentation: error)
66 | expect(sut.errorRepresentations.count).to(beGreaterThanOrEqualTo(1))
67 | }
68 |
69 | }
70 |
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/ResponseDetective/Tests/Specs/RequestRepresentationSpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RequestRepresentationSpec.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 | import Nimble
10 | import ResponseDetective
11 | import Quick
12 |
13 | internal final class RequestRepresentationSpec: QuickSpec {
14 |
15 | override func spec() {
16 |
17 | describe("RequestRepresentation") {
18 |
19 | context("after initializing with a request") {
20 |
21 | let fixtureRequest = NSMutableURLRequest(
22 | URL: URL(string: "https://httpbin.org/post")!,
23 | HTTPMethod: "POST",
24 | headerFields: [
25 | "Content-Type": "application/json",
26 | "X-Foo": "bar",
27 | ],
28 | HTTPBody: try! JSONSerialization.data(withJSONObject: ["foo": "bar"], options: [])
29 | )
30 |
31 | let fixtureIdentifier = "1"
32 |
33 | var sut: RequestRepresentation!
34 |
35 | beforeEach {
36 | sut = RequestRepresentation(identifier: fixtureIdentifier, request: fixtureRequest as URLRequest, deserializedBody: nil)
37 | }
38 |
39 | it("should have a correct identifier") {
40 | expect(sut.identifier).to(equal(fixtureIdentifier))
41 | }
42 |
43 | it("should have a correct URLString") {
44 | expect(sut.urlString).to(equal(fixtureRequest.url!.absoluteString))
45 | }
46 |
47 | it("should have a correct method") {
48 | expect(sut.method).to(equal(fixtureRequest.httpMethod))
49 | }
50 |
51 | it("should have correct headers") {
52 | expect(sut.headers).to(equal(fixtureRequest.allHTTPHeaderFields))
53 | }
54 |
55 | it("should have a correct body") {
56 | expect(sut.body).to(equal(fixtureRequest.httpBody))
57 | }
58 |
59 | }
60 |
61 | }
62 |
63 | }
64 |
65 | }
66 |
67 | private extension NSMutableURLRequest {
68 |
69 | convenience init(URL: Foundation.URL, HTTPMethod: String, headerFields: [String: String], HTTPBody: Data?) {
70 | self.init(url: URL)
71 | self.httpMethod = HTTPMethod
72 | self.allHTTPHeaderFields = headerFields
73 | self.httpBody = HTTPBody
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/ResponseDetective/Tests/Specs/ImageBodyDeserializerSpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageBodyDeserializerSpec.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 | import Nimble
10 | import ResponseDetective
11 | import Quick
12 |
13 | internal final class ImageBodyDeserializerSpec: QuickSpec {
14 |
15 | override func spec() {
16 |
17 | describe("ImageBodyDeserializer") {
18 |
19 | let sut = ImageBodyDeserializer()
20 |
21 | it("should correctly deserialize image data") {
22 | let source = swatchImage(size: (width: 100, height: 200))
23 | let data = imageData(image: source)
24 | let expected = "100px × 200px image"
25 | expect { sut.deserialize(body: data) }.to(equal(expected))
26 | }
27 |
28 | }
29 |
30 | }
31 |
32 | }
33 |
34 | // MARK: -
35 |
36 | #if os(iOS) || os(tvOS) || os(watchOS)
37 | import UIKit
38 | private typealias Image = UIImage
39 | #elseif os(OSX)
40 | import AppKit
41 | private typealias Image = NSImage
42 | #endif
43 |
44 | private func swatchImage(size: (width: Int, height: Int)) -> Image {
45 | #if os(iOS) || os(tvOS) || os(watchOS)
46 | let rect = CGRect(x: 0, y: 0, width: CGFloat(size.width), height: CGFloat(size.height))
47 | UIGraphicsBeginImageContext(rect.size)
48 | let context = UIGraphicsGetCurrentContext()!
49 | context.setFillColor(UIColor.black.cgColor)
50 | context.fill(rect)
51 | let image = UIGraphicsGetImageFromCurrentImageContext()!
52 | UIGraphicsEndImageContext()
53 | return image.withRenderingMode(.alwaysOriginal)
54 | #elseif os(OSX)
55 | let rect = NSMakeRect(0, 0, CGFloat(size.width), CGFloat(size.height))
56 | let image = NSImage(size: rect.size)
57 | image.lockFocus()
58 | NSColor.black.drawSwatch(in: rect)
59 | image.unlockFocus()
60 | return image
61 | #endif
62 | }
63 |
64 | private func imageData(image: Image) -> Data {
65 | #if os(iOS) || os(tvOS) || os(watchOS)
66 | return image.jpegData(compressionQuality: 1)!
67 | #elseif os(OSX)
68 | return NSBitmapImageRep(data: image.tiffRepresentation!)!.representation(using: .jpeg, properties: [.compressionFactor: 1])!
69 | #endif
70 | }
71 |
--------------------------------------------------------------------------------
/ResponseDetective/Tests/Specs/ErrorRepresentationSpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ErrorRepresentationSpec.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 | import Nimble
10 | import ResponseDetective
11 | import Quick
12 |
13 | internal final class ErrorRepresentationSpec: QuickSpec {
14 |
15 | override func spec() {
16 |
17 | describe("ErrorRepresentation") {
18 |
19 | context("after initializing with an error") {
20 |
21 | let fixtureIdentifier = "1"
22 |
23 | let fixtureError = NSError(domain: NSURLErrorDomain, code: NSURLErrorNotConnectedToInternet, userInfo: [
24 | NSLocalizedDescriptionKey: "The connection failed because the device is not connected to the internet.",
25 | NSURLErrorKey: NSURL(string: "https://httpbin.org/post")!
26 | ])
27 |
28 | let fixtureResponse = ResponseRepresentation(
29 | requestIdentifier: fixtureIdentifier,
30 | response: HTTPURLResponse(
31 | url: URL(string: "https://httpbin.org/post")!,
32 | statusCode: 200,
33 | httpVersion: nil,
34 | headerFields: [
35 | "Content-Type": "application/json",
36 | "X-Foo": "bar"
37 | ]
38 | )!,
39 | body: nil,
40 | deserializedBody: nil
41 | )
42 |
43 | var sut: ErrorRepresentation!
44 |
45 | beforeEach {
46 | sut = ErrorRepresentation(requestIdentifier: fixtureIdentifier, error: fixtureError, response: fixtureResponse)
47 | }
48 |
49 | it("should have a correct identifier") {
50 | expect(sut.requestIdentifier).to(equal(fixtureIdentifier))
51 | }
52 |
53 | it("should have a correct response") {
54 | expect(sut.response).to(beIdenticalTo(fixtureResponse))
55 | }
56 |
57 | it("should have a correct domain") {
58 | expect(sut.domain).to(equal(fixtureError.domain))
59 | }
60 |
61 | it("should have a correct code") {
62 | expect(sut.code).to(equal(fixtureError.code))
63 | }
64 |
65 | it("should have a correct reason") {
66 | expect(sut.reason).to(equal(fixtureError.localizedDescription))
67 | }
68 |
69 | it("should have correct user info") {
70 | expect(sut.userInfo as? [String: NSObject]).to(equal(fixtureError.userInfo as? [String: NSObject]))
71 | }
72 |
73 | }
74 |
75 | }
76 |
77 | }
78 |
79 | }
80 |
--------------------------------------------------------------------------------
/ResponseDetective/Tests/Specs/ConsoleOutputFacilitySpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ConsoleOutputFacilitySpec.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 | import Nimble
10 | import ResponseDetective
11 | import Quick
12 |
13 | internal final class ConsoleOutputFacilitySpec: QuickSpec {
14 |
15 | override func spec() {
16 |
17 | describe("ConsoleOutputFacility") {
18 |
19 | var buffer = [String]()
20 | let sut = ConsoleOutputFacility(printClosure: { buffer.append($0) })
21 |
22 | it("should produce correct request output") {
23 | let request = RequestRepresentation(
24 | identifier: "0",
25 | method: "GET",
26 | urlString: "http://foo.bar",
27 | headers: ["X-Foo": "bar"],
28 | body: nil,
29 | deserializedBody: "lorem ipsum"
30 | )
31 | let expected = "<0> [REQUEST] GET http://foo.bar\n" +
32 | " ├─ Headers\n" +
33 | " │ X-Foo: bar\n" +
34 | " ├─ Body\n" +
35 | " │ lorem ipsum\n"
36 | sut.output(requestRepresentation: request)
37 | expect(buffer.last).to(equal(expected))
38 | }
39 |
40 | it("should produce correct response output") {
41 | let response = ResponseRepresentation(
42 | requestIdentifier: "0",
43 | statusCode: 200,
44 | urlString: "http://foo.bar",
45 | headers: ["X-Bar": "foo"],
46 | body: nil,
47 | deserializedBody: "dolor sit amet"
48 | )
49 | let expected = "<0> [RESPONSE] 200 (NO ERROR) http://foo.bar\n" +
50 | " ├─ Headers\n" +
51 | " │ X-Bar: foo\n" +
52 | " ├─ Body\n" +
53 | " │ dolor sit amet\n"
54 | sut.output(responseRepresentation: response)
55 | expect(buffer.last).to(equal(expected))
56 | }
57 |
58 | it("should produce correct error ourput") {
59 | let error = ErrorRepresentation(
60 | requestIdentifier: "0",
61 | response: nil,
62 | domain: "foo.bar.error",
63 | code: 1234,
64 | reason: "just because",
65 | userInfo: ["foo": "bar"]
66 | )
67 | let expected = "<0> [ERROR] foo.bar.error 1234\n" +
68 | " ├─ User Info\n" +
69 | " │ foo: bar\n"
70 | sut.output(errorRepresentation: error)
71 | expect(buffer.last).to(equal(expected))
72 | }
73 |
74 | }
75 |
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/ResponseDetective/Sources/ErrorRepresentation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ErrorRepresentation.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 |
10 | /// Represents an instance of `NSError`.
11 | @objc(RDTErrorRepresentation) public final class ErrorRepresentation: NSObject {
12 |
13 | // MARK: Initializers
14 |
15 | /// Initializes the receiver.
16 | ///
17 | /// - Parameters:
18 | /// - requestIdentifier: The request's unique identifier.
19 | /// - response: The HTTP URL response representation, if any.
20 | /// - domain: The error domain.
21 | /// - code: The error code.
22 | /// - reason: The error reason.
23 | /// - userInfo: The error user info.
24 | public init(requestIdentifier: String, response: ResponseRepresentation?, domain: String, code: Int, reason: String, userInfo: [String: Any]) {
25 | self.requestIdentifier = requestIdentifier
26 | self.response = response
27 | self.domain = domain
28 | self.code = code
29 | self.reason = reason
30 | self.userInfo = userInfo
31 | }
32 |
33 | /// Initializes the receiver.
34 | ///
35 | /// - Parameters:
36 | /// - requestIdentifier: The unique identifier of assocciated request.
37 | /// - error: The error that came with the response.
38 | /// - response: The HTTP URL response representation, if any.
39 | public convenience init(requestIdentifier: String, error: NSError, response: ResponseRepresentation?) {
40 | self.init(
41 | requestIdentifier: requestIdentifier,
42 | response: response,
43 | domain: error.domain,
44 | code: error.code,
45 | reason: error.localizedDescription,
46 | userInfo: error.userInfo
47 | )
48 | }
49 |
50 | // MARK: Properties
51 |
52 | /// The request's unique identifier.
53 | public let requestIdentifier: String
54 |
55 | /// The response representation that came along with the error.
56 | public let response: ResponseRepresentation?
57 |
58 | /// The error domain.
59 | public let domain: String
60 |
61 | /// The error code.
62 | public let code: Int
63 |
64 | /// The error reason.
65 | public let reason: String
66 |
67 | /// The error user info.
68 | public let userInfo: [String: Any]
69 |
70 | // MARK: Unavailable
71 |
72 | /// An unavailable initializer.
73 | @available(*, unavailable) public override init() {
74 | fatalError("\(#function) is not implemented.");
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/ResponseDetective/Sources/RequestRepresentation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // RequestRepresentation.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 |
10 | /// Represents an instance of `URLRequest`.
11 | @objc(RDTRequestRepresentation) public final class RequestRepresentation: NSObject {
12 |
13 | // MARK: Initializers
14 |
15 | /// Initializes the receiver.
16 | ///
17 | /// - Parameters:
18 | /// - identifier: A unique identifier of the request.
19 | /// - method: he HTTP method of the request.
20 | /// - urlString: The resolved URL string of the request.
21 | /// - headers: The HTTP headers of the request.
22 | /// - body: The raw body data of the request.
23 | /// - deserializedBody: The parsed body of the request.
24 | public init(identifier: String, method: String, urlString: String, headers: [String: String], body: Data?, deserializedBody: String?) {
25 | self.identifier = identifier
26 | self.method = method
27 | self.urlString = urlString
28 | self.headers = headers
29 | self.body = body
30 | self.deserializedBody = deserializedBody
31 | }
32 |
33 | /// Initializes the receiver.
34 | ///
35 | /// - Parameters:
36 | /// - identifier: A unique identifier of the request.
37 | /// - request: The URL request instance.
38 | /// - deserializedBody: The parsed body of the request.
39 | public convenience init(identifier: String, request: URLRequest, deserializedBody: String?) {
40 | self.init(
41 | identifier: identifier,
42 | method: request.httpMethod ?? "GET",
43 | urlString: request.url?.absoluteString ?? "",
44 | headers: request.allHTTPHeaderFields ?? [:],
45 | body: request.httpBody,
46 | deserializedBody: deserializedBody
47 | )
48 | }
49 |
50 | // MARK: Properties
51 |
52 | /// A unique identifier of the request.
53 | public let identifier: String
54 |
55 | /// The HTTP method of the request.
56 | public let method: String
57 |
58 | /// The resolved URL string of the request.
59 | public let urlString: String
60 |
61 | /// The HTTP headers of the request.
62 | public let headers: [String: String]
63 |
64 | /// The content type of the request.
65 | public var contentType: String {
66 | return headers["Content-Type"] ?? "application/octet-stream"
67 | }
68 |
69 | /// The raw body data of the request.
70 | public let body: Data?
71 |
72 | /// The parsed body of the request.
73 | public let deserializedBody: String?
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/ResponseDetective/Sources/ResponseRepresentation.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResponseRepresentation.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 |
10 | /// Represents a pair of `HTTPURLResponse` and `Data` instances.
11 | @objc(RDTResponseRepresentation) public final class ResponseRepresentation: NSObject {
12 |
13 | // MARK: Initializers
14 |
15 | /// Initializes the receiver.
16 | ///
17 | /// - Parameters:
18 | /// - requestIdentifier: The request's unique identifier.
19 | /// - statusCode: The status code of the response.
20 | /// - urlString: The URL string of the response.
21 | /// - headers: The HTTP headers of the response.
22 | /// - body: The raw body data of the response.
23 | /// - deserializedBody: The parsed body of the response.
24 | public init(requestIdentifier: String, statusCode: Int, urlString: String, headers: [String: String], body: Data?, deserializedBody: String?) {
25 | self.requestIdentifier = requestIdentifier
26 | self.statusCode = statusCode
27 | self.urlString = urlString
28 | self.headers = headers
29 | self.body = body
30 | self.deserializedBody = deserializedBody
31 | }
32 |
33 | /// Initializes the receiver.
34 | ///
35 | /// - Parameters:
36 | /// - requestIdentifier: The unique identifier of assocciated request.
37 | /// - response: The HTTP URL response instance.
38 | /// - body: The body that came with the response.
39 | /// - deserializedBody: The deserialized response body.
40 | public convenience init(requestIdentifier: String, response: HTTPURLResponse, body: Data?, deserializedBody: String?) {
41 | self.init(
42 | requestIdentifier: requestIdentifier,
43 | statusCode: response.statusCode,
44 | urlString: response.url?.absoluteString ?? "",
45 | headers: response.allHeaderFields as? [String: String] ?? [:],
46 | body: body,
47 | deserializedBody: deserializedBody
48 | )
49 | }
50 |
51 | // MARK: Properties
52 |
53 | /// The request's unique identifier.
54 | public let requestIdentifier: String
55 |
56 | /// The status code of the response.
57 | public let statusCode: Int
58 |
59 | /// A verbal representation of the status code.
60 | public var statusString: String {
61 | return HTTPURLResponse.localizedString(forStatusCode: statusCode)
62 | }
63 |
64 | /// The URL string of the response (which may be different than originally
65 | /// requested because of a redirect).
66 | public let urlString: String
67 |
68 | /// The HTTP headers of the response.
69 | public let headers: [String: String]
70 |
71 | /// The content type of the response.
72 | public var contentType: String {
73 | return headers["Content-Type"] ?? "application/octet-stream"
74 | }
75 |
76 | /// The raw body data of the response.
77 | public let body: Data?
78 |
79 | /// The parsed body of the response.
80 | public let deserializedBody: String?
81 |
82 | }
83 |
--------------------------------------------------------------------------------
/bitrise.yml:
--------------------------------------------------------------------------------
1 | #
2 | # bitrise.yml
3 | #
4 | # Copyright © 2017-2020 Netguru S.A. All rights reserved.
5 | # Licensed under the MIT License.
6 | #
7 |
8 | # CLI metadata
9 |
10 | format_version: 1.3.0
11 | default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
12 |
13 | # Workflow trigger map
14 |
15 | trigger_map:
16 |
17 | - pull_request_target_branch: develop
18 | workflow: build-and-test
19 |
20 | - push_branch: develop
21 | workflow: build-and-test
22 |
23 | # Environment configuration
24 |
25 | app:
26 | envs:
27 | - XCODEBUILD_PROJECT: ResponseDetective.xcodeproj
28 | - XCODEBUILD_OPTIONS: ''
29 |
30 | # Workflow declarations
31 |
32 | workflows:
33 |
34 | # Top level build workflows
35 |
36 | build-and-test:
37 | envs:
38 | - XCODEBUILD_SCHEME_IOS: ResponseDetective-iOS
39 | - XCODEBUILD_SCHEME_MACOS: ResponseDetective-macOS
40 | - XCODEBUILD_SCHEME_TVOS: ResponseDetective-tvOS
41 | before_run:
42 | - cache-pull
43 | - bootstrap-carthage
44 | - xcode-test
45 | - cocoapods-test
46 | after_run:
47 | - cache-push
48 | - deploy-artifacts
49 |
50 | # Cache workflows
51 |
52 | cache-pull:
53 | steps:
54 | - cache-pull: {}
55 |
56 | cache-push:
57 | steps:
58 | - cache-push:
59 | inputs:
60 | - cache_paths: "./Carthage -> ./Carthage/Cachefile"
61 |
62 | # Bootstrap workflows
63 |
64 | bootstrap-carthage:
65 | steps:
66 | - carthage:
67 | inputs:
68 | - carthage_command: bootstrap
69 |
70 | # Test workflows
71 |
72 | xcode-test:
73 | steps:
74 | - xcode-test:
75 | title: xcode-test-ios
76 | inputs:
77 | - project_path: $XCODEBUILD_PROJECT
78 | - scheme: $XCODEBUILD_SCHEME_IOS
79 | - xcodebuild_test_options: $XCODEBUILD_OPTIONS
80 | - generate_code_coverage_files: 'yes'
81 | - xcode-test-mac:
82 | title: xcode-test-macos
83 | inputs:
84 | - project_path: $XCODEBUILD_PROJECT
85 | - scheme: $XCODEBUILD_SCHEME_MACOS
86 | - xcodebuild_test_options: $XCODEBUILD_OPTIONS
87 | - generate_code_coverage_files: 'yes'
88 | - xcode-test:
89 | title: xcode-test-tvos
90 | inputs:
91 | - project_path: $XCODEBUILD_PROJECT
92 | - scheme: $XCODEBUILD_SCHEME_TVOS
93 | - xcodebuild_test_options: $XCODEBUILD_OPTIONS
94 | - generate_code_coverage_files: 'yes'
95 | - simulator_platform: tvOS Simulator
96 | - simulator_device: Apple TV 1080p
97 |
98 | cocoapods-test:
99 | steps:
100 | - script:
101 | title: cocoapods-lint
102 | inputs:
103 | - content: pod lib lint
104 |
105 | # Deploy workflows
106 |
107 | deploy-artifacts:
108 | steps:
109 | - deploy-to-bitrise-io:
110 | inputs:
111 | - notify_user_groups: none
112 | - is_enable_public_page: false
113 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Vendor/Common/Variables.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Common/Variables.xcconfig
3 | //
4 | // Copyright © 2017 Netguru Sp. z o.o. All rights reserved.
5 | // Licensed under MIT License.
6 | //
7 | // This file contains variables that are mapped to build settings.
8 | //
9 |
10 | // MARK: Environment
11 |
12 | // The environments build setting, typically overridden in environment-specific
13 | // `xcconfig` files.
14 | _ENVIRONMENTS = ENV_DEFAULT
15 |
16 | // MARK: Versioning
17 |
18 | // The build semantic version, mapped later to `CFBundleVersionString`.
19 | _BUILD_VERSION =
20 |
21 | // The build number, mapped later to `CFBundleVersion`.
22 | _BUILD_NUMBER = $(_BUILD_VERSION)
23 |
24 | // MARK: Bundle
25 |
26 | // Bundle name of the product, used by Xcode to create an `.app` bundle.
27 | _BUNDLE_NAME = $(TARGET_NAME)
28 |
29 | // Bundle identifier of the product.
30 | _BUNDLE_IDENTIFIER =
31 |
32 | /// Path to `Info.plist` file of the product.
33 | _BUNDLE_INFOPLIST_PATH =
34 |
35 | // Whether the bundle is `@testable`.
36 | _BUNDLE_TESTABLE = YES
37 |
38 | // MARK: Deployment
39 |
40 | // Minimum iOS deployment target.
41 | _DEPLOYMENT_TARGET_IOS =
42 |
43 | // Targeted device families on iOS.
44 | _DEPLOYMENT_DEVICES_IOS = 1,2
45 |
46 | // Minimum macOS deployment target.
47 | _DEPLOYMENT_TARGET_MACOS =
48 |
49 | // Minimum tvOS deployment target.
50 | _DEPLOYMENT_TARGET_TVOS =
51 |
52 | // Targeted device families on tvOS.
53 | _DEPLOYMENT_DEVICES_TVOS = 3
54 |
55 | // Minimum watchOS deployment target.
56 | _DEPLOYMENT_TARGET_WATCHOS =
57 |
58 | // Targeted device families on watchOS.
59 | _DEPLOYMENT_DEVICES_WATCHOS = 4
60 |
61 | // MARK: Signing
62 |
63 | // Code signign style.
64 | _CODESIGN_STYLE = Automatic
65 |
66 | // Development team to be used with `_CODESIGN_PROFILE_SPECIFIER` to manually
67 | // code sign the product.
68 | _CODESIGN_DEVELOPMENT_TEAM =
69 |
70 | // The identity to be used with `_CODESIGN_PROFILE_SPECIFIER` to manually code
71 | // sign the product.
72 | _CODESIGN_IDENTITY =
73 |
74 | // The provisioning profile specifier to be used with `_CODESIGN_IDENTITY` to
75 | // manually code sign the product.
76 | _CODESIGN_PROFILE_SPECIFIER =
77 |
78 | // Path to `.entitlements` file of the product.
79 | _CODESIGN_ENTITLEMENTS_PATH =
80 |
81 | // MARK: Assets
82 |
83 | // Name of the icon asset to be used.
84 | _ASSET_ICON =
85 |
86 | // Name of the launch image asset to be used.
87 | _ASSET_LAUNCHIMAGE =
88 |
89 | // MARK: Compiler
90 |
91 | // Whether to enable hard mode (a.k.a. treat warnings as errors).
92 | _COMPILER_HARD_MODE = YES
93 |
94 | // The version of Swift to be used by compiler.
95 | _COMPILER_SWIFT_VERSION =
96 |
97 | // Additional flags for the Swift compiler.
98 | _COMPILER_SWIFT_FLAGS =
99 |
100 | // Path to Swift bridging header to be used by compiler.
101 | _COMPILER_SWIFT_BRIDGING_HEADER_PATH =
102 |
103 | // Additional flags for Objective-C linker.
104 | _COMPILER_OBJC_LINKER_FLAGS =
105 |
106 | // Additional search paths when looking for headers.
107 | _COMPILER_OBJC_HEADER_SEARCH_PATHS =
108 |
109 | // Additional search paths when looking for frameworks.
110 | _COMPILER_FRAMEWORK_SEARCH_PATHS =
111 |
--------------------------------------------------------------------------------
/ResponseDetective.xcodeproj/xcshareddata/xcschemes/ResponseDetective-iOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
45 |
46 |
52 |
53 |
54 |
55 |
57 |
63 |
64 |
65 |
66 |
67 |
77 |
78 |
84 |
85 |
86 |
87 |
93 |
94 |
96 |
97 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/ResponseDetective.xcodeproj/xcshareddata/xcschemes/ResponseDetective-tvOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
45 |
46 |
52 |
53 |
54 |
55 |
57 |
63 |
64 |
65 |
66 |
67 |
77 |
78 |
84 |
85 |
86 |
87 |
93 |
94 |
96 |
97 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.3
2 | import PackageDescription
3 |
4 | let package = Package(
5 | name: "ResponseDetective",
6 | platforms: [
7 | .iOS(.v8),
8 | .macOS(.v10_10),
9 | .tvOS(.v9)
10 | ],
11 | products: [
12 | .library(
13 | name: "ResponseDetective",
14 | targets: [
15 | "ResponseDetective",
16 | "ResponseDetectiveObjC"
17 | ]
18 | )
19 | ],
20 | dependencies: [
21 | .package(
22 | url: "https://github.com/Quick/Quick.git",
23 | .exact("3.0.0")
24 | ),
25 | .package(
26 | url: "https://github.com/Quick/Nimble.git",
27 | .exact("9.0.0")
28 | ),
29 | .package(
30 | url: "https://github.com/AliSoftware/OHHTTPStubs.git",
31 | .exact("9.1.0")
32 | )
33 | ],
34 | targets: [
35 | .target(
36 | name: "ResponseDetective",
37 | dependencies: ["ResponseDetectiveObjC"],
38 | path: "ResponseDetective",
39 | exclude: [
40 | "Configuration",
41 | "Resources",
42 | "Tests",
43 | "include",
44 | "Sources/RDTHTMLBodyDeserializer.h",
45 | "Sources/RDTXMLBodyDeserializer.h",
46 | "Sources/ResponseDetective.h",
47 | "Sources/RDTHTMLBodyDeserializer.m",
48 | "Sources/RDTBodyDeserializer.h",
49 | "Sources/RDTXMLBodyDeserializer.m"
50 | ],
51 | sources: [
52 | "Sources/ResponseRepresentation.swift",
53 | "Sources/ErrorRepresentation.swift",
54 | "Sources/ResponseDetective.swift",
55 | "Sources/BufferOutputFacility.swift",
56 | "Sources/ConsoleOutputFacility.swift",
57 | "Sources/URLEncodedBodyDeserializer.swift",
58 | "Sources/PlaintextBodyDeserializer.swift",
59 | "Sources/ImageBodyDeserializer.swift",
60 | "Sources/JSONBodyDeserializer.swift",
61 | "Sources/Dictionary.swift",
62 | "Sources/URLProtocol.swift",
63 | "Sources/OutputFacility.swift",
64 | "Sources/RequestRepresentation.swift"
65 | ]
66 | ),
67 | .target(
68 | name: "ResponseDetectiveObjC",
69 | dependencies: [],
70 | path: "ResponseDetective",
71 | exclude: [
72 | "Configuration",
73 | "Resources",
74 | "Tests",
75 | "Sources/ResponseRepresentation.swift",
76 | "Sources/ErrorRepresentation.swift",
77 | "Sources/ResponseDetective.swift",
78 | "Sources/BufferOutputFacility.swift",
79 | "Sources/ConsoleOutputFacility.swift",
80 | "Sources/URLEncodedBodyDeserializer.swift",
81 | "Sources/PlaintextBodyDeserializer.swift",
82 | "Sources/ImageBodyDeserializer.swift",
83 | "Sources/JSONBodyDeserializer.swift",
84 | "Sources/Dictionary.swift",
85 | "Sources/URLProtocol.swift",
86 | "Sources/OutputFacility.swift",
87 | "Sources/RequestRepresentation.swift"
88 | ],
89 | sources: [
90 | "Sources/RDTHTMLBodyDeserializer.h",
91 | "Sources/RDTXMLBodyDeserializer.h",
92 | "Sources/ResponseDetective.h",
93 | "Sources/RDTHTMLBodyDeserializer.m",
94 | "Sources/RDTBodyDeserializer.h",
95 | "Sources/RDTXMLBodyDeserializer.m"
96 | ],
97 | cSettings: [
98 | .headerSearchPath("ResponseDetective/Sources"),
99 | .headerSearchPath("ResponseDetective")
100 | ]
101 | ),
102 | .testTarget(
103 | name: "ResponseDetectiveTests",
104 | dependencies: [
105 | "ResponseDetective",
106 | "ResponseDetectiveObjC",
107 | "Quick",
108 | "Nimble",
109 | "OHHTTPStubs"
110 | ],
111 | path: "ResponseDetective",
112 | exclude: [
113 | "Configuration",
114 | "Resources",
115 | "Sources",
116 | "include",
117 | ],
118 | sources: ["Tests"]
119 | ),
120 | ]
121 | )
122 |
--------------------------------------------------------------------------------
/ResponseDetective.xcodeproj/xcshareddata/xcschemes/ResponseDetective-macOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
45 |
46 |
52 |
53 |
54 |
55 |
57 |
63 |
64 |
65 |
66 |
67 |
77 |
78 |
84 |
85 |
86 |
87 |
93 |
94 |
100 |
101 |
102 |
103 |
105 |
106 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/ResponseDetective/Sources/ConsoleOutputFacility.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ConsoleOutputFacility.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 |
10 | /// An output facility which outputs requests, responses and errors to console.
11 | @objc(RDTConsoleOutputFacility) public final class ConsoleOutputFacility: NSObject, OutputFacility {
12 |
13 | // MARK: Initializers
14 |
15 | /// Initializes the receiver with default print closure.
16 | public convenience override init() {
17 | self.init(printClosure: { print($0) })
18 | }
19 |
20 | /// Initializes the receiver.
21 | ///
22 | /// - Parameters:
23 | /// - printClosure: The print closure used to output strings into the
24 | /// console.
25 | @objc(initWithPrintBlock:) public init(printClosure: @escaping @convention(block) (String) -> Void) {
26 | self.printClosure = printClosure
27 | }
28 |
29 | // MARK: Properties
30 |
31 | /// Print closure used to output strings into the console.
32 | private let printClosure: @convention(block) (String) -> Void
33 |
34 | // MARK: OutputFacility
35 |
36 | /// Prints the request in the following format:
37 | ///
38 | /// <0xbadf00d> [REQUEST] POST https://httpbin.org/post
39 | /// ├─ Headers
40 | /// │ Content-Type: application/json
41 | /// │ Content-Length: 14
42 | /// ├─ Body
43 | /// │ {
44 | /// │ "foo": "bar"
45 | /// │ }
46 | ///
47 | /// - SeeAlso: OutputFacility.output(requestRepresentation:)
48 | public func output(requestRepresentation request: RequestRepresentation) {
49 | let headers = request.headers.reduce([]) {
50 | $0 + ["\($1.0): \($1.1)"]
51 | }
52 | let body = request.deserializedBody.map {
53 | #if swift(>=3.2)
54 | return $0.split { $0 == "\n" }.map(String.init)
55 | #else
56 | return $0.characters.split { $0 == "\n" }.map(String.init)
57 | #endif
58 | } ?? [""]
59 | printBoxString(title: "<\(request.identifier)> [REQUEST] \(request.method) \(request.urlString)", sections: [
60 | ("Headers", headers),
61 | ("Body", body),
62 | ])
63 | }
64 |
65 | /// Prints the response in the following format:
66 | ///
67 | /// <0xbadf00d> [RESPONSE] 200 (NO ERROR) https://httpbin.org/post
68 | /// ├─ Headers
69 | /// │ Content-Type: application/json
70 | /// │ Content-Length: 24
71 | /// ├─ Body
72 | /// │ {
73 | /// │ "args": {},
74 | /// │ "headers": {}
75 | /// │ }
76 | ///
77 | /// - SeeAlso: OutputFacility.output(responseRepresentation:)
78 | public func output(responseRepresentation response: ResponseRepresentation) {
79 | let headers = response.headers.reduce([]) {
80 | $0 + ["\($1.0): \($1.1)"]
81 | }
82 | let body = response.deserializedBody.map {
83 | #if swift(>=3.2)
84 | return $0.split { $0 == "\n" }.map(String.init)
85 | #else
86 | return $0.characters.split { $0 == "\n" }.map(String.init)
87 | #endif
88 | } ?? [""]
89 | printBoxString(title: "<\(response.requestIdentifier)> [RESPONSE] \(response.statusCode) (\(response.statusString.uppercased())) \(response.urlString)", sections: [
90 | ("Headers", headers),
91 | ("Body", body),
92 | ])
93 | }
94 |
95 | /// Prints the error in the following format:
96 | ///
97 | /// <0xbadf00d> [ERROR] NSURLErrorDomain -1009
98 | /// ├─ User Info
99 | /// │ NSLocalizedDescriptionKey: The device is not connected to the internet.
100 | /// │ NSURLErrorKey: https://httpbin.org/post
101 | ///
102 | /// - SeeAlso: OutputFacility.output(errorRepresentation:)
103 | public func output(errorRepresentation error: ErrorRepresentation) {
104 | let userInfo = error.userInfo.reduce([]) {
105 | $0 + ["\($1.0): \($1.1)"]
106 | }
107 | printBoxString(title: "<\(error.requestIdentifier)> [ERROR] \(error.domain) \(error.code)", sections: [
108 | ("User Info", userInfo),
109 | ])
110 | }
111 |
112 | // MARK: Printing boxes
113 |
114 | /// Composes a box string in the following format:
115 | ///
116 | /// box title
117 | /// ├─ section title
118 | /// │ section
119 | /// │ contents
120 | ///
121 | /// - Parameters:
122 | /// - title: The title of the box
123 | /// - sections: A dictionary with section titles as keys and content
124 | /// lines as values.
125 | ///
126 | /// - Returns: A composed box string.
127 | private func composeBoxString(title: String, sections: [(String, [String])]) -> String {
128 | return "\(title)\n" + sections.reduce("") {
129 | "\($0) ├─ \($1.0)\n" + $1.1.reduce("") {
130 | "\($0) │ \($1)\n"
131 | }
132 | }
133 | }
134 |
135 | /// Composes and prints the box sting in the console.
136 | ///
137 | /// - Parameters:
138 | /// - title: The title of the box
139 | /// - sections: A dictionary with section titles as keys and content
140 | /// lines as values.
141 | private func printBoxString(title: String, sections: [(String, [String])]) {
142 | printClosure(composeBoxString(title: title, sections: sections))
143 | }
144 |
145 | }
146 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | 
4 | 
5 | 
6 | 
7 | 
8 | 
9 |
10 | **ResponseDetective** is a non-intrusive framework for intercepting any outgoing requests and incoming responses between your app and your server for debugging purposes.
11 |
12 | ## Requirements
13 |
14 | ResponseDetective is written in **Swift 5.3** and supports **iOS 9.0+**, **macOS 10.10+** and **tvOS 9.0+**.
15 |
16 | ## Usage
17 |
18 | Incorporating ResponseDetective in your project is very simple – it all comes down to just two steps:
19 |
20 | ### Step 1: Enable interception
21 |
22 | For ResponseDetective to work, it needs to be added as a middleman between your `(NS)URLSession` and the Internet. You can do this by registering the provided `URLProtocol` class in your session's `(NS)URLSessionConfiguration.protocolClasses`, or use a shortcut method:
23 |
24 | ```objc
25 | // Objective-C
26 |
27 | NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
28 | [RDTResponseDetective enableInConfiguration:configuration];
29 | ```
30 |
31 | ```swift
32 | // Swift
33 |
34 | let configuration = URLSessionConfiguration.default
35 | ResponseDetective.enable(inConfiguration: configuration)
36 | ```
37 |
38 | Then, you should use that configuration with your `(NS)URLSession`:
39 |
40 | ```objc
41 | // Objective-C
42 |
43 | NSURLSession *session = [[NSURLSession alloc] initWithConfiguration:configuration];
44 | ```
45 |
46 | ```swift
47 | // Swift
48 |
49 | let session = URLSession(configuration: configuration)
50 | ```
51 |
52 | Or, if you're using [AFNetworking](https://github.com/AFNetworking/AFNetworking)/[Alamofire](https://github.com/Alamofire/Alamofire) as your networking framework, integrating ResponseDetective comes down to just initializing your `AFURLSessionManager`/`Manager` with the above `(NS)URLSessionConfiguration`:
53 |
54 | ```objc
55 | // Objective-C (AFNetworking)
56 |
57 | AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
58 | ```
59 |
60 | ```swift
61 | // Swift (Alamofire)
62 |
63 | let manager = Alamofire.SessionManager(configuration: configuration)
64 | ```
65 |
66 | And that's all!
67 |
68 | ### Step 2: Profit
69 |
70 | Now it's time to perform the actual request:
71 |
72 | ```objc
73 | // Objective-C
74 |
75 | NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://httpbin.org/get"]];
76 | [[session dataTaskWithRequest:request] resume];
77 | ```
78 |
79 | ```swift
80 | // Swift
81 |
82 | let request = URLRequest(URL: URL(string: "http://httpbin.org/get")!)
83 | session.dataTask(with: request).resume()
84 | ```
85 |
86 | Voilà! 🎉 Check out your console output:
87 |
88 | ```none
89 | <0x000000000badf00d> [REQUEST] GET https://httpbin.org/get
90 | ├─ Headers
91 | ├─ Body
92 | │
93 |
94 | <0x000000000badf00d> [RESPONSE] 200 (NO ERROR) https://httpbin.org/get
95 | ├─ Headers
96 | │ Server: nginx
97 | │ Date: Thu, 01 Jan 1970 00:00:00 GMT
98 | │ Content-Type: application/json
99 | ├─ Body
100 | │ {
101 | │ "args" : {
102 | │ },
103 | │ "headers" : {
104 | │ "User-Agent" : "ResponseDetective\/1 CFNetwork\/758.3.15 Darwin\/15.4.0",
105 | │ "Accept-Encoding" : "gzip, deflate",
106 | │ "Host" : "httpbin.org",
107 | │ "Accept-Language" : "en-us",
108 | │ "Accept" : "*\/*"
109 | │ },
110 | │ "url" : "https:\/\/httpbin.org\/get"
111 | │ }
112 | ```
113 |
114 | ## Installation
115 |
116 | ### Carthage
117 |
118 | If you're using [Carthage](https://github.com/Carthage/Carthage), add the following dependency to your `Cartfile`:
119 |
120 | ```none
121 | github "netguru/ResponseDetective" ~> {version}
122 | ```
123 |
124 | ### CocoaPods
125 |
126 | If you're using [CocoaPods](http://cocoapods.org), add the following dependency to your `Podfile`:
127 |
128 | ```none
129 | use_frameworks!
130 | pod 'ResponseDetective', '~> {version}'
131 | ```
132 |
133 | ### Swift Package Manager
134 |
135 | If you're using [Swift Package Manager](https://github.com/apple/swift-package-manager), add this repository to the Swift Packages in your project settings.
136 |
137 | ### Local
138 |
139 | To install the test dependencies or to build ResponseDetective itself, do not run `carthage` directly. It can't handle the Apple Silicon architectures introduced in Xcode 12. Instead, run it through the `carthage.sh` script:
140 |
141 | ```bash
142 | $ ./carthage.sh bootstrap
143 | ```
144 |
145 | Alternatively, you can run the tests locally using Swift Package Manager with the following command:
146 |
147 | ```bash
148 | $ swift test
149 | ```
150 |
151 | ## About
152 |
153 | This project was made with ♡ by [Netguru](https://netguru.com).
154 |
155 | ### Release names
156 |
157 | Starting from version 1.0.0, ResponseDetective's releases are named after [Sherlock Holmes canon stories](http://www.sherlockian.net/investigating/canon/), in chronological order. **What happens if we reach 60 releases and there are no more stories?** We don't know, maybe we'll start naming them after cats or something.
158 |
159 | ### License
160 |
161 | This project is licensed under **MIT License**. See [LICENSE.md](LICENSE.md) for more info.
162 |
--------------------------------------------------------------------------------
/ResponseDetective/Sources/ResponseDetective.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResponseDetective.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 | #if SWIFT_PACKAGE
10 | import ResponseDetectiveObjC
11 | #endif
12 |
13 | /// ResponseDetective configuration cluster class that defines the behavior
14 | /// of request interception and logging.
15 | @objc(RDTResponseDetective) public final class ResponseDetective: NSObject {
16 |
17 | // MARK: Properties
18 |
19 | /// An output facility for reporting requests, responses and errors.
20 | public static var outputFacility: OutputFacility = ConsoleOutputFacility()
21 |
22 | /// A class of the URL protocol used to intercept requests.
23 | public static let URLProtocolClass: Foundation.URLProtocol.Type = URLProtocol.self
24 |
25 | /// A storage for request predicates.
26 | private static var requestPredicates: [NSPredicate] = []
27 |
28 | /// Body deserializers stored by a supported content type.
29 | private static var customBodyDeserializers: [String: BodyDeserializer] = [:]
30 |
31 | /// Default body deserializers provided by ResponseDetective.
32 | private static let defaultBodyDeserializers: [String: BodyDeserializer] = [
33 | "*/json": JSONBodyDeserializer(),
34 | "*/xml": XMLBodyDeserializer(),
35 | "*/html": HTMLBodyDeserializer(),
36 | "*/x-www-form-urlencoded": URLEncodedBodyDeserializer(),
37 | "image/*": ImageBodyDeserializer(),
38 | "text/*": PlaintextBodyDeserializer(),
39 | ]
40 |
41 | // MARK: Configuration
42 |
43 | /// Resets the ResponseDetective mutable state.
44 | public static func reset() {
45 | outputFacility = ConsoleOutputFacility()
46 | requestPredicates = []
47 | customBodyDeserializers = [:]
48 | }
49 |
50 | /// Enables ResponseDetective in an URL session configuration.
51 | ///
52 | /// - Parameters:
53 | /// - configuration: The URL session configuration to enable the
54 | /// session in.
55 | @objc(enableInConfiguration:) public static func enable(inConfiguration configuration: URLSessionConfiguration) {
56 | configuration.protocolClasses?.insert(URLProtocolClass, at: 0)
57 | }
58 |
59 | /// Ignores requests matching the given predicate. The predicate will be
60 | /// evaluated with an instance of NSURLRequest.
61 | ///
62 | /// - Parameters:
63 | /// - predicate: A predicate for matching a request. If the
64 | /// predicate evaluates to `false`, the request is not intercepted.
65 | @objc(ignoreRequestsMatchingPredicate:) public static func ignoreRequests(matchingPredicate predicate: NSPredicate) {
66 | requestPredicates.append(predicate)
67 | }
68 |
69 | /// Checks whether the given request can be incercepted.
70 | ///
71 | /// - Parameters:
72 | /// - request: The request to check.
73 | ///
74 | /// - Returns: `true` if request can be intercepted, `false` otherwise.
75 | @objc(canInterceptRequest:) public static func canIncercept(request: URLRequest) -> Bool {
76 | return requestPredicates.reduce(true) {
77 | return $0 && !$1.evaluate(with: request)
78 | }
79 | }
80 |
81 | // MARK: Deserialization
82 |
83 | /// Registers a body deserializer.
84 | ///
85 | /// - Parameters:
86 | /// - deserializer: The deserializer to register.
87 | /// - contentType: The supported content type.
88 | @objc(registerBodyDeserializer:forContentType:) public static func registerBodyDeserializer(_ deserializer: BodyDeserializer, forContentType contentType: String) {
89 | customBodyDeserializers[contentType] = deserializer
90 | }
91 |
92 | /// Registers a body deserializer.
93 | ///
94 | /// - Parameters:
95 | /// - deserializer: The deserializer to register.
96 | /// - contentTypes: The supported content types.
97 | @objc(registerBodyDeserializer:forContentTypes:) public static func registerBodyDeserializer(_ deserializer: BodyDeserializer, forContentTypes contentTypes: [String]) {
98 | for contentType in contentTypes {
99 | registerBodyDeserializer(deserializer, forContentType: contentType)
100 | }
101 | }
102 |
103 | /// Deserializes a HTTP body into a string.
104 | ///
105 | /// - Parameters:
106 | /// - body: The body to deserialize.
107 | /// - contentType: The content type of the body.
108 | ///
109 | /// - Returns: A deserialized body or `nil` if no serializer is capable of
110 | /// deserializing body with the given content type.
111 | @objc(deserializeBody:contentType:) public static func deserialize(body: Data, contentType: String) -> String? {
112 | if let deserializer = findBodyDeserializer(forContentType: contentType) {
113 | return deserializer.deserialize(body: body)
114 | } else {
115 | return nil
116 | }
117 | }
118 |
119 | /// Finds a body deserializer by pattern.
120 | ///
121 | /// - Parameters:
122 | /// - contentType: The content type to find a deserializer for.
123 | ///
124 | /// - Returns: A body deserializer for given `contentType` or `nil`.
125 | @objc(findBodyDeserializerForContentType:) private static func findBodyDeserializer(forContentType contentType: String) -> BodyDeserializer? {
126 | guard let trimmedContentType = contentType.components(separatedBy: ";").first?.trimmingCharacters(in: .whitespaces) else {
127 | return nil
128 | }
129 | for (pattern, deserializer) in defaultBodyDeserializers.appending(elementsOf: customBodyDeserializers) {
130 | let patternParts = pattern.components(separatedBy: "/")
131 | let actualParts = trimmedContentType.components(separatedBy: "/")
132 | guard patternParts.count == 2 && actualParts.count == 2 else {
133 | return nil
134 | }
135 | if ["*" , actualParts[0]].contains(patternParts[0]) && ["*" , actualParts[1]].contains(patternParts[1]) {
136 | return deserializer
137 | }
138 | }
139 | return nil
140 | }
141 |
142 | }
143 |
--------------------------------------------------------------------------------
/ResponseDetective/Sources/URLProtocol.swift:
--------------------------------------------------------------------------------
1 | //
2 | // URLProtocol.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 |
10 | /// The intercepting URL protocol.
11 | @objc(RDTURLProtocol) internal final class URLProtocol: Foundation.URLProtocol, URLSessionTaskDelegate, URLSessionDataDelegate {
12 |
13 | // MARK: Initialization
14 |
15 | /// - SeeAlso: Foundation.URLProtocol.canInit(with:)
16 | internal override static func canInit(with request: URLRequest) -> Bool {
17 | guard let URL = request.url, let scheme = URL.scheme else { return false }
18 | return ["http", "https"].contains(scheme) && ResponseDetective.canIncercept(request: request)
19 | }
20 |
21 | /// - SeeAlso: Foundation.URLProtocol.init(request:cachedResponse:client:)
22 | internal override init(request: URLRequest, cachedResponse: CachedURLResponse?, client: URLProtocolClient?) {
23 | super.init(request: request, cachedResponse: cachedResponse, client: client)
24 | internalSession = Foundation.URLSession(configuration: URLSessionConfiguration.default, delegate: self, delegateQueue: nil)
25 | internalTask = internalSession.dataTask(with: request)
26 | }
27 |
28 | // MARK: Properties
29 |
30 | /// Internal session object used to perform the request.
31 | private var internalSession: Foundation.URLSession!
32 |
33 | /// Internal session data dark responsible for request execution.
34 | private var internalTask: URLSessionDataTask!
35 |
36 | /// Internal task response storage.
37 | private var internalResponse: HTTPURLResponse?
38 |
39 | /// Internal response data storage.
40 | private lazy var internalResponseData = Data()
41 |
42 | /// A unique identifier of the request.
43 | private let requestIdentifier: String = UUID().uuidString.uppercased()
44 |
45 | // MARK: URLProtocol
46 |
47 | /// - SeeAlso: Foundation.URLProtocol.canonicalRequest(for:)
48 | internal override static func canonicalRequest(for request: URLRequest) -> URLRequest {
49 | return request
50 | }
51 |
52 | /// - SeeAlso: Foundation.URLProtocol.startLoading()
53 | internal override func startLoading() {
54 | intercept(request: request)
55 | internalTask.resume()
56 | }
57 |
58 | /// - SeeAlso: Foundation.URLProtocol.stopLoading()
59 | internal override func stopLoading() {
60 | internalSession.invalidateAndCancel()
61 | }
62 |
63 | // MARK: URLSessionTaskDelegate
64 |
65 | /// - SeeAlso: URLSessionTaskDelegate.urlSession(_:task:willPerformHTTPRedirection:newRequest:completionHandler:)
66 | internal func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: @escaping (URLRequest?) -> Void) {
67 | client?.urlProtocol(self, wasRedirectedTo: request, redirectResponse: response)
68 | completionHandler(request)
69 | }
70 |
71 | /// - SeeAlso: URLSessionTaskDelegate.urlSession(_:task:didCompleteWithError:)
72 | internal func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
73 | if let error = error {
74 | intercept(error: error as NSError, response: internalResponse, data: internalResponseData)
75 | client?.urlProtocol(self, didFailWithError: error)
76 | } else if let response = internalResponse {
77 | intercept(response: response, data: internalResponseData)
78 | client?.urlProtocolDidFinishLoading(self)
79 | }
80 | internalSession.finishTasksAndInvalidate()
81 | }
82 |
83 | // MARK: URLSessionDataDelegate
84 |
85 | /// - SeeAlso: URLSessionDataDelegate.urlSession(_:dataTask:didReceive:completionHandler:)
86 | internal func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {
87 | internalResponse = response as? HTTPURLResponse
88 | completionHandler(.allow)
89 | client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .allowed)
90 | }
91 |
92 | /// - SeeAlso: URLSessionDataDelegate.urlSession(_:dataTask:didReceive:)
93 | internal func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
94 | internalResponseData.append(data)
95 | client?.urlProtocol(self, didLoad: data)
96 | }
97 |
98 | // MARK: Interception
99 |
100 | /// Incercepts the given request and passes it to the ResponseDetective
101 | /// instance.
102 | ///
103 | /// - Parameter request: The intercepted request.
104 | private func intercept(request: URLRequest) {
105 | let deserializedBody = standardizedData(of: request).flatMap { data in
106 | ResponseDetective.deserialize(body: data, contentType: request.value(forHTTPHeaderField: "Content-Type") ?? "application/octet-stream")
107 | }
108 | let requestRepresentation = RequestRepresentation(identifier: requestIdentifier, request: request, deserializedBody: deserializedBody)
109 | ResponseDetective.outputFacility.output(requestRepresentation: requestRepresentation)
110 | }
111 |
112 | /// Incercepts the given response and passes it to the ResponseDetective
113 | /// instance.
114 | ///
115 | /// - Parameters:
116 | /// - response: The intercepted response.
117 | /// - data: The intercepted response data.
118 | private func intercept(response: HTTPURLResponse, data: Data?) {
119 | let deserializedBody = data.flatMap { data in
120 | ResponseDetective.deserialize(body: data, contentType: (response.allHeaderFields["Content-Type"] as? String) ?? "application/octet-stream")
121 | }
122 | let responseRepresentation = ResponseRepresentation(requestIdentifier: requestIdentifier, response: response, body: data, deserializedBody: deserializedBody)
123 | ResponseDetective.outputFacility.output(responseRepresentation: responseRepresentation)
124 | }
125 |
126 | /// Incercepts the given error and passes it to the ResponseDetective
127 | /// instance.
128 | ///
129 | /// - Parameters:
130 | /// - error: The intercepted request.
131 | /// - response: The intercepted response.
132 | /// - data: The intercepted response data.
133 | private func intercept(error: NSError, response: HTTPURLResponse?, data: Data?) {
134 | let deserializedBody = response.flatMap { response in
135 | return data.flatMap { data in
136 | ResponseDetective.deserialize(body: data, contentType: (response.allHeaderFields["Content-Type"] as? String) ?? "application/octet-stream")
137 | }
138 | }
139 | let responseRepresentation = response.flatMap { response in
140 | ResponseRepresentation(requestIdentifier: requestIdentifier, response: response, body: data, deserializedBody: deserializedBody)
141 | }
142 | let errorRepresentation = ErrorRepresentation(requestIdentifier: requestIdentifier, error: error, response: responseRepresentation)
143 | ResponseDetective.outputFacility.output(errorRepresentation: errorRepresentation)
144 | }
145 |
146 | // MARK: Private
147 |
148 | /// Extracts and standardizes data of a request.
149 | ///
150 | /// - Parameters:
151 | /// - request: The request which data should be standardized.
152 | ///
153 | /// - Returns: Data of the `request`.
154 | private func standardizedData(of request: URLRequest) -> Data? {
155 | return request.httpBody ?? request.httpBodyStream.flatMap { stream in
156 | let data = NSMutableData()
157 | stream.open()
158 | while stream.hasBytesAvailable {
159 | var buffer = [UInt8](repeating: 0, count: 1024)
160 | let length = stream.read(&buffer, maxLength: buffer.count)
161 | data.append(buffer, length: length)
162 | }
163 | stream.close()
164 | return data as Data
165 | }
166 | }
167 |
168 | }
169 |
--------------------------------------------------------------------------------
/ResponseDetective/Tests/Specs/ResponseDetectiveSpec.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ResponseDetectiveSpec.swift
3 | //
4 | // Copyright © 2016-2020 Netguru S.A. All rights reserved.
5 | // Licensed under the MIT License.
6 | //
7 |
8 | import Foundation
9 | import Nimble
10 | import OHHTTPStubs
11 | import ResponseDetective
12 | import Quick
13 |
14 | internal final class ResponseDetectiveSpec: QuickSpec {
15 |
16 | override func spec() {
17 |
18 | describe("ResponseDetective") {
19 |
20 | beforeSuite {
21 | HTTPStubs.stubRequests { request in
22 | return request.url?.host == "httpbin.org"
23 | } withStubResponse: { _ in
24 | return HTTPStubsResponse(data: Data(), statusCode: 200, headers: nil)
25 | }
26 | }
27 |
28 | beforeEach {
29 | ResponseDetective.reset()
30 | }
31 |
32 | afterSuite {
33 | HTTPStubs.removeAllStubs()
34 | }
35 |
36 | describe("initial state") {
37 |
38 | it("should use default output facility") {
39 | expect(type(of: ResponseDetective.outputFacility) == ConsoleOutputFacility.self).to(beTruthy())
40 | }
41 |
42 | it("should use default url protocol class") {
43 | expect(ResponseDetective.URLProtocolClass).to(beIdenticalTo(NSClassFromString("RDTURLProtocol")!))
44 | }
45 |
46 | }
47 |
48 | describe("enabling in url session configuration") {
49 |
50 | let configuration = URLSessionConfiguration.default
51 |
52 | beforeEach {
53 | ResponseDetective.enable(inConfiguration: configuration)
54 | }
55 |
56 | it("should add protocol class at the beginning of array") {
57 | expect(configuration.protocolClasses!.first == ResponseDetective.URLProtocolClass).to(beTrue())
58 | }
59 |
60 | }
61 |
62 | describe("ignoring requests") {
63 |
64 | let request = URLRequest(url: URL(string: "http://foo.bar")!)
65 |
66 | context("before adding predicate") {
67 |
68 | it("should not ignore the request") {
69 | expect {
70 | ResponseDetective.canIncercept(request: request)
71 | }.to(beTruthy())
72 | }
73 |
74 | }
75 |
76 | context("after adding predicate") {
77 |
78 | beforeEach {
79 | ResponseDetective.ignoreRequests(matchingPredicate: NSPredicate { subject, _ in
80 | guard let subject = subject as? URLRequest, let url = subject.url else {
81 | return true
82 | }
83 | let string = url.absoluteString
84 |
85 | return string.contains("foo")
86 | })
87 | }
88 |
89 | it("should ignore the request") {
90 | expect {
91 | ResponseDetective.canIncercept(request: request)
92 | }.to(beFalsy())
93 | }
94 |
95 | }
96 |
97 | }
98 |
99 | describe("body deserialization") {
100 |
101 | context("before registering a custom body deserializer") {
102 |
103 | it("should return no deserialized body") {
104 | expect {
105 | ResponseDetective.deserialize(body: Data(), contentType: "foo/bar")
106 | }.to(beNil())
107 | }
108 |
109 | }
110 |
111 | context("after registering an explicit body deserializer") {
112 |
113 | beforeEach {
114 | ResponseDetective.registerBodyDeserializer(
115 | TestBodyDeserializer(fixedDeserializedBody: "lorem ipsum"),
116 | forContentType: "foo/bar"
117 | )
118 | }
119 |
120 | it("should return a deserialized body") {
121 | expect {
122 | ResponseDetective.deserialize(body: Data(), contentType: "foo/bar")
123 | }.to(equal("lorem ipsum"))
124 | }
125 |
126 | it("should return a deserialized body for content type containing properties") {
127 | expect {
128 | ResponseDetective.deserialize(body: Data(), contentType: "foo/bar; charset=utf8")
129 | }.to(equal("lorem ipsum"))
130 | }
131 |
132 | }
133 |
134 | context("after registering a wildcard body deserializer") {
135 |
136 | beforeEach {
137 | ResponseDetective.registerBodyDeserializer(
138 | TestBodyDeserializer(fixedDeserializedBody: "dolor sit amet"),
139 | forContentType: "foo/*"
140 | )
141 | }
142 |
143 | it("should return a deserialized body") {
144 | expect {
145 | ResponseDetective.deserialize(body: Data(), contentType: "foo/baz")
146 | }.to(equal("dolor sit amet"))
147 | }
148 |
149 | }
150 |
151 | }
152 |
153 | describe("request interception") {
154 |
155 | var buffer: BufferOutputFacility!
156 | let configuration = URLSessionConfiguration.default
157 |
158 | beforeEach {
159 | buffer = BufferOutputFacility()
160 | ResponseDetective.outputFacility = buffer
161 | ResponseDetective.registerBodyDeserializer(TestBodyDeserializer(), forContentType: "*/*")
162 | ResponseDetective.enable(inConfiguration: configuration)
163 | }
164 |
165 | context("before request has been sent") {
166 |
167 | it("should intercept no requests") {
168 | expect(buffer.requestRepresentations).to(beEmpty())
169 | }
170 |
171 | }
172 |
173 | context("after request has been sent") {
174 |
175 | let request: URLRequest = {
176 | var request = URLRequest(url: URL(string: "https://httpbin.org/post")!)
177 | request.httpMethod = "POST"
178 | request.httpBody = Data(base64Encoded: "foo", options: [])
179 | return request
180 | }()
181 |
182 | beforeEach {
183 | let session = URLSession(configuration: configuration)
184 | session.dataTask(with: request).resume()
185 | }
186 |
187 | it("should eventually intercept it") {
188 | expect(buffer.requestRepresentations.count).toEventually(beGreaterThanOrEqualTo(1), timeout: .seconds(5))
189 | expect(buffer.responseRepresentations.last?.body).toEventuallyNot(beNil(), timeout: .seconds(5))
190 | }
191 |
192 | }
193 |
194 | }
195 |
196 | describe("response interception") {
197 |
198 | var buffer: BufferOutputFacility!
199 | let configuration = URLSessionConfiguration.default
200 |
201 | beforeEach {
202 | buffer = BufferOutputFacility()
203 | ResponseDetective.outputFacility = buffer
204 | ResponseDetective.registerBodyDeserializer(TestBodyDeserializer(), forContentType: "*/*")
205 | ResponseDetective.enable(inConfiguration: configuration)
206 | }
207 |
208 | context("before request has been sent") {
209 |
210 | it("should intercept no responses") {
211 | expect(buffer.responseRepresentations).to(beEmpty())
212 | }
213 |
214 | }
215 |
216 | context("after request has been sent") {
217 |
218 | let request = URLRequest(url: URL(string: "https://httpbin.org/get")!)
219 |
220 | beforeEach {
221 | let session = URLSession(configuration: configuration)
222 | session.dataTask(with: request).resume()
223 | }
224 |
225 | it("should eventually intercept its response") {
226 | expect(buffer.responseRepresentations.count).toEventually(beGreaterThanOrEqualTo(1), timeout: .seconds(5))
227 | }
228 |
229 | }
230 |
231 | }
232 |
233 | describe("error interception") {
234 |
235 | var buffer: BufferOutputFacility!
236 | let configuration = URLSessionConfiguration.default
237 |
238 | beforeEach {
239 | buffer = BufferOutputFacility()
240 | ResponseDetective.outputFacility = buffer
241 | ResponseDetective.registerBodyDeserializer(TestBodyDeserializer(), forContentType: "*/*")
242 | ResponseDetective.enable(inConfiguration: configuration)
243 | }
244 |
245 | context("before request has been sent") {
246 |
247 | it("should intercept no errors") {
248 | expect(buffer.responseRepresentations).to(beEmpty())
249 | }
250 |
251 | }
252 |
253 | context("after request has been sent") {
254 |
255 | let request = URLRequest(url: URL(string: "https://foobar")!)
256 |
257 | beforeEach {
258 | let session = URLSession(configuration: configuration)
259 | session.dataTask(with: request).resume()
260 | }
261 |
262 | it("should eventually intercept its error") {
263 | expect(buffer.errorRepresentations.count).toEventually(beGreaterThanOrEqualTo(1), timeout: .seconds(5))
264 | }
265 |
266 | }
267 |
268 | }
269 |
270 | }
271 |
272 | }
273 |
274 | }
275 |
--------------------------------------------------------------------------------
/ResponseDetective/Configuration/Vendor/Common/Common.xcconfig:
--------------------------------------------------------------------------------
1 | //
2 | // Common/Common.xcconfig
3 | //
4 | // Copyright © 2017 Netguru Sp. z o.o. All rights reserved.
5 | // Licensed under MIT License.
6 | //
7 | // This file contains base build settings for all targets.
8 | //
9 |
10 | // Include default values of variables.
11 | #include "Variables.xcconfig"
12 |
13 | // MARK: Build options
14 |
15 | // The format of debugging symbols.
16 | DEBUG_INFORMATION_FORMAT = dwarf-with-dsym
17 |
18 | // MARK: Search paths
19 |
20 | // Disable legacy-compatible header searching.
21 | ALWAYS_SEARCH_USER_PATHS = NO
22 |
23 | // Additional framework search paths.
24 | FRAMEWORK_SEARCH_PATHS = $(inherited) $(_CARTHAGE_BUILD_PATH) $(_COMPILER_FRAMEWORK_SEARCH_PATHS)
25 |
26 | // Additional header search paths.
27 | HEADER_SEARCH_PATHS = $(inherited) $(_COMPILER_OBJC_HEADER_SEARCH_PATHS)
28 |
29 | // MARK: Linking
30 |
31 | // Other linker flags.
32 | OTHER_LDFLAGS = $(inherited) $(_COMPILER_OBJC_LINKER_FLAGS)
33 |
34 | // MARK: Packaging
35 |
36 | // Path to `Info.plist` file.
37 | INFOPLIST_FILE = $(_BUNDLE_INFOPLIST_PATH)
38 |
39 | // `CFBundleVersionString`.
40 | PRODUCT_BUNDLE_VERSION_STRING = $(_BUILD_VERSION)
41 |
42 | // `CFBundleVersion`.
43 | PRODUCT_BUNDLE_VERSION = $(_BUILD_NUMBER)
44 |
45 | // `CFBundleIdentifier`.
46 | PRODUCT_BUNDLE_IDENTIFIER = $(_BUNDLE_IDENTIFIER)
47 |
48 | // Name of the product.
49 | PRODUCT_NAME = $(_BUNDLE_NAME)
50 |
51 | // MARK: Signing
52 |
53 | // Code signing style.
54 | CODE_SIGN_STYLE = $(_CODESIGN_STYLE)
55 |
56 | // Development team to use for code signing.
57 | DEVELOPMENT_TEAM = $(_CODESIGN_DEVELOPMENT_TEAM)
58 |
59 | // Identity to use for code signing.
60 | CODE_SIGN_IDENTITY = $(_CODESIGN_IDENTITY)
61 |
62 | // Provisioning profile specifier for code signing.
63 | PROVISIONING_PROFILE_SPECIFIER = $(_CODESIGN_PROFILE_SPECIFIER)
64 |
65 | // Path to `.entitlements` file for code signing.
66 | CODE_SIGN_ENTITLEMENTS = $(_CODESIGN_ENTITLEMENTS_PATH)
67 |
68 | // MARK: LLVM compiler
69 |
70 | // Disable link-time optimizations.
71 | LLVM_LTO = NO
72 |
73 | // Compile `NSAssert` assertions.
74 | ENABLE_NS_ASSERTIONS = YES
75 |
76 | // Require `objc_msgSend` to be cast before invocation.
77 | ENABLE_STRICT_OBJC_MSGSEND = YES
78 |
79 | // Preprocessor definitions, mapped from `_ENVIRONMENT`.
80 | GCC_PREPROCESSOR_DEFINITIONS = $(_ENVIRONMENTS) $(inherited)
81 |
82 | // Use GNU++11 C++ language standard.
83 | CLANG_CXX_LANGUAGE_STANDARD = gnu++11
84 |
85 | // Use LLVM C++ standard library.
86 | CLANG_CXX_LIBRARY = libc++
87 |
88 | // Enable module imports and definitions.
89 | CLANG_ENABLE_MODULES = YES
90 |
91 | // Enable Objective-C ARC.
92 | CLANG_ENABLE_OBJC_ARC = YES
93 |
94 | // Warn about block capture autoreleasing.
95 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES
96 |
97 | // Warn about suspucious commas.
98 | CLANG_WARN_COMMA = YES
99 |
100 | // Warn about suspicious empty loop bodies.
101 | CLANG_WARN_EMPTY_BODY = YES
102 |
103 | // Warn when a function will recursively call itself on every code path.
104 | CLANG_WARN_INFINITE_RECURSION = YES
105 |
106 | // Warn about non-literal null conversion.
107 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES
108 |
109 | // Whether to warn on suspicious implicit conversions.
110 | CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES
111 |
112 | // Warn about strict prototypes.
113 | CLANG_WARN_STRICT_PROTOTYPES = YES
114 |
115 | // Warn about unreachable code.
116 | CLANG_WARN_UNREACHABLE_CODE = YES
117 |
118 | // Warn about range-based `for` loops in C++.
119 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES
120 |
121 | // Warning about suspicious uses of `std::move`.
122 | CLANG_WARN_SUSPICIOUS_MOVE = YES
123 |
124 | // Warn when overriding deprecated Objective-C methods.
125 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES
126 |
127 | // Warn about implicit Objective-C literal conversions.
128 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES
129 |
130 | // Warn about direct accesses to the Objective-C `isa` pointer instead of using
131 | // the Objective-C runtime API.
132 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR
133 |
134 | // Warn about classes that unintentionally do not subclass a root class.
135 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR
136 |
137 | // Warn duplicate method declarations within the same `@interface`.
138 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
139 |
140 | // Warn about implicit capture of `self` (e.g. direct ivar access).
141 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES
142 |
143 | // Whether to run the static analyzer with every build.
144 | RUN_CLANG_STATIC_ANALYZER = YES
145 |
146 | // Warn for misused nullability attributes.
147 | CLANG_ANALYZER_NONNULL = YES
148 |
149 | // Warn when a non-localized string is passed to a user-interface method
150 | // expecting a localized string.
151 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES
152 |
153 | // Warn about suspicius conversions between `NSNumber` and `CFNumberRef`.
154 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE
155 |
156 | // Warn when a floating-point value is used as a loop counter.
157 | CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES
158 |
159 | // Warn when using `rand()` and `random()` instead of `arc4random()`.
160 | CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES
161 |
162 | // Warn when using `strcpy() and `strcat()`.
163 | CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES
164 |
165 | // Warn about incorrect uses of `nullable` values.
166 | CLANG_WARN_NULLABLE_TO_NONNULL_CONVERSION = YES
167 |
168 | // Function calls should not be position-dependent.
169 | GCC_DYNAMIC_NO_PIC = NO
170 |
171 | // Warn if the same variable is declared in two binaries that are linked
172 | // together.
173 | GCC_NO_COMMON_BLOCKS = YES
174 |
175 | // Use GNU99 C variant.
176 | GCC_C_LANGUAGE_STANDARD = gnu99
177 |
178 | // Whether to precompile the prefix header (if one is specified).
179 | GCC_PRECOMPILE_PREFIX_HEADER = YES
180 |
181 | // Treat warnings as errors (a.k.a. hard mode).
182 | GCC_TREAT_WARNINGS_AS_ERRORS = $(_COMPILER_HARD_MODE)
183 |
184 | // Warn about 64-bit values being implicitly shortened to 32 bits.
185 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES
186 |
187 | // Warn about fields missing from structure initializers (only if designated
188 | // initializers aren't used).
189 | GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES
190 |
191 | // Warn when the returned value does not match its return type.
192 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR
193 |
194 | // Warn about the use of four-character constants.
195 | GCC_WARN_FOUR_CHARACTER_CONSTANTS = YES
196 |
197 | // Warn about an aggregate data type's initializer not being fully bracketed.
198 | GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES
199 |
200 | // Whether to warn about unsafe comparisons between values of different
201 | // signedness.
202 | GCC_WARN_SIGN_COMPARE = YES
203 |
204 | // Warn if a variable might be clobbered by a setjmp call or if an automatic
205 | // variable is used without prior initialization.
206 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE
207 |
208 | // Warn about static functions that are unused.
209 | GCC_WARN_UNUSED_FUNCTION = YES
210 |
211 | // Whether to warn about labels that are unused.
212 | GCC_WARN_UNUSED_LABEL = YES
213 |
214 | // Warn about variables that are never used.
215 | GCC_WARN_UNUSED_VARIABLE = YES
216 |
217 | // Warn if a `@selector` expression refers to an undeclared selector.
218 | GCC_WARN_UNDECLARED_SELECTOR = YES
219 |
220 | // MARK: Asset catalog compiler
221 |
222 | // Asset to use as app icon.
223 | ASSETCATALOG_COMPILER_APPICON_NAME = $(_ASSET_ICON)
224 |
225 | // Asset to use as launch image.
226 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = $(_ASSET_LAUNCHIMAGE)
227 |
228 | // MARK: Swift compiler
229 |
230 | // Swift version to be used.
231 | SWIFT_VERSION = $(_COMPILER_SWIFT_VERSION)
232 |
233 | // Treat warning as errors (a.k.a. hard mode).
234 | SWIFT_TREAT_WARNINGS_AS_ERRORS = $(_COMPILER_HARD_MODE)
235 |
236 | // Compilation conditions for Swift, mapped from `_ENVIRONMENTS`.
237 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = $(_ENVIRONMENTS) $(inherited)
238 |
239 | // Additional flags passed to Swift compiler.
240 | OTHER_SWIFT_FLAGS = $(inherited) $(_COMPILER_SWIFT_FLAGS)
241 |
242 | // Path to bridging header between Swift and Objective-C.
243 | SWIFT_OBJC_BRIDGING_HEADER = $(_COMPILER_SWIFT_BRIDGING_HEADER_PATH)
244 |
--------------------------------------------------------------------------------
/ResponseDetective.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 3A2007E31B5501BC00769021 /* ResponseDetective.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A2007D81B5501BC00769021 /* ResponseDetective.framework */; };
11 | 3AB9E9801EBB64C8004E575E /* URLEncodedBodyDeserializerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AB9E97E1EBB64C0004E575E /* URLEncodedBodyDeserializerSpec.swift */; };
12 | 3AB9E9811EBB64C9004E575E /* URLEncodedBodyDeserializerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AB9E97E1EBB64C0004E575E /* URLEncodedBodyDeserializerSpec.swift */; };
13 | 3AB9E9821EBB64C9004E575E /* URLEncodedBodyDeserializerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AB9E97E1EBB64C0004E575E /* URLEncodedBodyDeserializerSpec.swift */; };
14 | 3AC631211EBB5CF8000F6353 /* URLEncodedBodyDeserializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AC631201EBB5CF8000F6353 /* URLEncodedBodyDeserializer.swift */; };
15 | 3AC631221EBB5CF8000F6353 /* URLEncodedBodyDeserializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AC631201EBB5CF8000F6353 /* URLEncodedBodyDeserializer.swift */; };
16 | 3AC631231EBB5CF8000F6353 /* URLEncodedBodyDeserializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AC631201EBB5CF8000F6353 /* URLEncodedBodyDeserializer.swift */; };
17 | 3AE546331E152DB600E74469 /* ResponseDetective.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AE5462A1E152DB500E74469 /* ResponseDetective.framework */; };
18 | 3AED3ED81B1DD7B400FA35FC /* ResponseDetective.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3AED3ECC1B1DD7B400FA35FC /* ResponseDetective.framework */; };
19 | 3AF56E841E5B37A500F1CEBC /* BufferOutputFacility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E721E5B37A500F1CEBC /* BufferOutputFacility.swift */; };
20 | 3AF56E851E5B37A500F1CEBC /* BufferOutputFacility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E721E5B37A500F1CEBC /* BufferOutputFacility.swift */; };
21 | 3AF56E861E5B37A500F1CEBC /* BufferOutputFacility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E721E5B37A500F1CEBC /* BufferOutputFacility.swift */; };
22 | 3AF56E871E5B37A500F1CEBC /* ConsoleOutputFacility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E731E5B37A500F1CEBC /* ConsoleOutputFacility.swift */; };
23 | 3AF56E881E5B37A500F1CEBC /* ConsoleOutputFacility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E731E5B37A500F1CEBC /* ConsoleOutputFacility.swift */; };
24 | 3AF56E891E5B37A500F1CEBC /* ConsoleOutputFacility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E731E5B37A500F1CEBC /* ConsoleOutputFacility.swift */; };
25 | 3AF56E8A1E5B37A500F1CEBC /* Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E741E5B37A500F1CEBC /* Dictionary.swift */; };
26 | 3AF56E8B1E5B37A500F1CEBC /* Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E741E5B37A500F1CEBC /* Dictionary.swift */; };
27 | 3AF56E8C1E5B37A500F1CEBC /* Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E741E5B37A500F1CEBC /* Dictionary.swift */; };
28 | 3AF56E8D1E5B37A500F1CEBC /* ErrorRepresentation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E751E5B37A500F1CEBC /* ErrorRepresentation.swift */; };
29 | 3AF56E8E1E5B37A500F1CEBC /* ErrorRepresentation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E751E5B37A500F1CEBC /* ErrorRepresentation.swift */; };
30 | 3AF56E8F1E5B37A500F1CEBC /* ErrorRepresentation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E751E5B37A500F1CEBC /* ErrorRepresentation.swift */; };
31 | 3AF56E901E5B37A500F1CEBC /* ImageBodyDeserializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E761E5B37A500F1CEBC /* ImageBodyDeserializer.swift */; };
32 | 3AF56E911E5B37A500F1CEBC /* ImageBodyDeserializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E761E5B37A500F1CEBC /* ImageBodyDeserializer.swift */; };
33 | 3AF56E921E5B37A500F1CEBC /* ImageBodyDeserializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E761E5B37A500F1CEBC /* ImageBodyDeserializer.swift */; };
34 | 3AF56E931E5B37A500F1CEBC /* JSONBodyDeserializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E771E5B37A500F1CEBC /* JSONBodyDeserializer.swift */; };
35 | 3AF56E941E5B37A500F1CEBC /* JSONBodyDeserializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E771E5B37A500F1CEBC /* JSONBodyDeserializer.swift */; };
36 | 3AF56E951E5B37A500F1CEBC /* JSONBodyDeserializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E771E5B37A500F1CEBC /* JSONBodyDeserializer.swift */; };
37 | 3AF56E961E5B37A500F1CEBC /* OutputFacility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E781E5B37A500F1CEBC /* OutputFacility.swift */; };
38 | 3AF56E971E5B37A500F1CEBC /* OutputFacility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E781E5B37A500F1CEBC /* OutputFacility.swift */; };
39 | 3AF56E981E5B37A500F1CEBC /* OutputFacility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E781E5B37A500F1CEBC /* OutputFacility.swift */; };
40 | 3AF56E991E5B37A500F1CEBC /* PlaintextBodyDeserializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E791E5B37A500F1CEBC /* PlaintextBodyDeserializer.swift */; };
41 | 3AF56E9A1E5B37A500F1CEBC /* PlaintextBodyDeserializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E791E5B37A500F1CEBC /* PlaintextBodyDeserializer.swift */; };
42 | 3AF56E9B1E5B37A500F1CEBC /* PlaintextBodyDeserializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E791E5B37A500F1CEBC /* PlaintextBodyDeserializer.swift */; };
43 | 3AF56E9C1E5B37A500F1CEBC /* RDTBodyDeserializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3AF56E7A1E5B37A500F1CEBC /* RDTBodyDeserializer.h */; settings = {ATTRIBUTES = (Public, ); }; };
44 | 3AF56E9D1E5B37A500F1CEBC /* RDTBodyDeserializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3AF56E7A1E5B37A500F1CEBC /* RDTBodyDeserializer.h */; settings = {ATTRIBUTES = (Public, ); }; };
45 | 3AF56E9E1E5B37A500F1CEBC /* RDTBodyDeserializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3AF56E7A1E5B37A500F1CEBC /* RDTBodyDeserializer.h */; settings = {ATTRIBUTES = (Public, ); }; };
46 | 3AF56E9F1E5B37A500F1CEBC /* RDTHTMLBodyDeserializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3AF56E7B1E5B37A500F1CEBC /* RDTHTMLBodyDeserializer.h */; settings = {ATTRIBUTES = (Public, ); }; };
47 | 3AF56EA01E5B37A500F1CEBC /* RDTHTMLBodyDeserializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3AF56E7B1E5B37A500F1CEBC /* RDTHTMLBodyDeserializer.h */; settings = {ATTRIBUTES = (Public, ); }; };
48 | 3AF56EA11E5B37A500F1CEBC /* RDTHTMLBodyDeserializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3AF56E7B1E5B37A500F1CEBC /* RDTHTMLBodyDeserializer.h */; settings = {ATTRIBUTES = (Public, ); }; };
49 | 3AF56EA21E5B37A500F1CEBC /* RDTHTMLBodyDeserializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E7C1E5B37A500F1CEBC /* RDTHTMLBodyDeserializer.m */; };
50 | 3AF56EA31E5B37A500F1CEBC /* RDTHTMLBodyDeserializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E7C1E5B37A500F1CEBC /* RDTHTMLBodyDeserializer.m */; };
51 | 3AF56EA41E5B37A500F1CEBC /* RDTHTMLBodyDeserializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E7C1E5B37A500F1CEBC /* RDTHTMLBodyDeserializer.m */; };
52 | 3AF56EA51E5B37A500F1CEBC /* RDTXMLBodyDeserializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3AF56E7D1E5B37A500F1CEBC /* RDTXMLBodyDeserializer.h */; settings = {ATTRIBUTES = (Public, ); }; };
53 | 3AF56EA61E5B37A500F1CEBC /* RDTXMLBodyDeserializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3AF56E7D1E5B37A500F1CEBC /* RDTXMLBodyDeserializer.h */; settings = {ATTRIBUTES = (Public, ); }; };
54 | 3AF56EA71E5B37A500F1CEBC /* RDTXMLBodyDeserializer.h in Headers */ = {isa = PBXBuildFile; fileRef = 3AF56E7D1E5B37A500F1CEBC /* RDTXMLBodyDeserializer.h */; settings = {ATTRIBUTES = (Public, ); }; };
55 | 3AF56EA81E5B37A500F1CEBC /* RDTXMLBodyDeserializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E7E1E5B37A500F1CEBC /* RDTXMLBodyDeserializer.m */; };
56 | 3AF56EA91E5B37A500F1CEBC /* RDTXMLBodyDeserializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E7E1E5B37A500F1CEBC /* RDTXMLBodyDeserializer.m */; };
57 | 3AF56EAA1E5B37A500F1CEBC /* RDTXMLBodyDeserializer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E7E1E5B37A500F1CEBC /* RDTXMLBodyDeserializer.m */; };
58 | 3AF56EAB1E5B37A500F1CEBC /* RequestRepresentation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E7F1E5B37A500F1CEBC /* RequestRepresentation.swift */; };
59 | 3AF56EAC1E5B37A500F1CEBC /* RequestRepresentation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E7F1E5B37A500F1CEBC /* RequestRepresentation.swift */; };
60 | 3AF56EAD1E5B37A500F1CEBC /* RequestRepresentation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E7F1E5B37A500F1CEBC /* RequestRepresentation.swift */; };
61 | 3AF56EAE1E5B37A500F1CEBC /* ResponseDetective.h in Headers */ = {isa = PBXBuildFile; fileRef = 3AF56E801E5B37A500F1CEBC /* ResponseDetective.h */; settings = {ATTRIBUTES = (Public, ); }; };
62 | 3AF56EAF1E5B37A500F1CEBC /* ResponseDetective.h in Headers */ = {isa = PBXBuildFile; fileRef = 3AF56E801E5B37A500F1CEBC /* ResponseDetective.h */; settings = {ATTRIBUTES = (Public, ); }; };
63 | 3AF56EB01E5B37A500F1CEBC /* ResponseDetective.h in Headers */ = {isa = PBXBuildFile; fileRef = 3AF56E801E5B37A500F1CEBC /* ResponseDetective.h */; settings = {ATTRIBUTES = (Public, ); }; };
64 | 3AF56EB11E5B37A500F1CEBC /* ResponseDetective.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E811E5B37A500F1CEBC /* ResponseDetective.swift */; };
65 | 3AF56EB21E5B37A500F1CEBC /* ResponseDetective.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E811E5B37A500F1CEBC /* ResponseDetective.swift */; };
66 | 3AF56EB31E5B37A500F1CEBC /* ResponseDetective.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E811E5B37A500F1CEBC /* ResponseDetective.swift */; };
67 | 3AF56EB41E5B37A500F1CEBC /* ResponseRepresentation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E821E5B37A500F1CEBC /* ResponseRepresentation.swift */; };
68 | 3AF56EB51E5B37A500F1CEBC /* ResponseRepresentation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E821E5B37A500F1CEBC /* ResponseRepresentation.swift */; };
69 | 3AF56EB61E5B37A500F1CEBC /* ResponseRepresentation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E821E5B37A500F1CEBC /* ResponseRepresentation.swift */; };
70 | 3AF56EB71E5B37A500F1CEBC /* URLProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E831E5B37A500F1CEBC /* URLProtocol.swift */; };
71 | 3AF56EB81E5B37A500F1CEBC /* URLProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E831E5B37A500F1CEBC /* URLProtocol.swift */; };
72 | 3AF56EB91E5B37A500F1CEBC /* URLProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56E831E5B37A500F1CEBC /* URLProtocol.swift */; };
73 | 3AF56ECF1E5B37B500F1CEBC /* BufferOutputFacilitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC01E5B37B500F1CEBC /* BufferOutputFacilitySpec.swift */; };
74 | 3AF56ED01E5B37B500F1CEBC /* BufferOutputFacilitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC01E5B37B500F1CEBC /* BufferOutputFacilitySpec.swift */; };
75 | 3AF56ED11E5B37B500F1CEBC /* BufferOutputFacilitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC01E5B37B500F1CEBC /* BufferOutputFacilitySpec.swift */; };
76 | 3AF56ED21E5B37B500F1CEBC /* ConsoleOutputFacilitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC11E5B37B500F1CEBC /* ConsoleOutputFacilitySpec.swift */; };
77 | 3AF56ED31E5B37B500F1CEBC /* ConsoleOutputFacilitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC11E5B37B500F1CEBC /* ConsoleOutputFacilitySpec.swift */; };
78 | 3AF56ED41E5B37B500F1CEBC /* ConsoleOutputFacilitySpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC11E5B37B500F1CEBC /* ConsoleOutputFacilitySpec.swift */; };
79 | 3AF56ED51E5B37B500F1CEBC /* ErrorRepresentationSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC21E5B37B500F1CEBC /* ErrorRepresentationSpec.swift */; };
80 | 3AF56ED61E5B37B500F1CEBC /* ErrorRepresentationSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC21E5B37B500F1CEBC /* ErrorRepresentationSpec.swift */; };
81 | 3AF56ED71E5B37B500F1CEBC /* ErrorRepresentationSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC21E5B37B500F1CEBC /* ErrorRepresentationSpec.swift */; };
82 | 3AF56ED81E5B37B500F1CEBC /* HTMLBodyDeserializerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC31E5B37B500F1CEBC /* HTMLBodyDeserializerSpec.swift */; };
83 | 3AF56ED91E5B37B500F1CEBC /* HTMLBodyDeserializerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC31E5B37B500F1CEBC /* HTMLBodyDeserializerSpec.swift */; };
84 | 3AF56EDA1E5B37B500F1CEBC /* HTMLBodyDeserializerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC31E5B37B500F1CEBC /* HTMLBodyDeserializerSpec.swift */; };
85 | 3AF56EDB1E5B37B500F1CEBC /* ImageBodyDeserializerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC41E5B37B500F1CEBC /* ImageBodyDeserializerSpec.swift */; };
86 | 3AF56EDC1E5B37B500F1CEBC /* ImageBodyDeserializerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC41E5B37B500F1CEBC /* ImageBodyDeserializerSpec.swift */; };
87 | 3AF56EDD1E5B37B500F1CEBC /* ImageBodyDeserializerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC41E5B37B500F1CEBC /* ImageBodyDeserializerSpec.swift */; };
88 | 3AF56EDE1E5B37B500F1CEBC /* JSONBodyDeserializerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC51E5B37B500F1CEBC /* JSONBodyDeserializerSpec.swift */; };
89 | 3AF56EDF1E5B37B500F1CEBC /* JSONBodyDeserializerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC51E5B37B500F1CEBC /* JSONBodyDeserializerSpec.swift */; };
90 | 3AF56EE01E5B37B500F1CEBC /* JSONBodyDeserializerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC51E5B37B500F1CEBC /* JSONBodyDeserializerSpec.swift */; };
91 | 3AF56EE11E5B37B500F1CEBC /* PlaintextBodyDeserializerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC61E5B37B500F1CEBC /* PlaintextBodyDeserializerSpec.swift */; };
92 | 3AF56EE21E5B37B500F1CEBC /* PlaintextBodyDeserializerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC61E5B37B500F1CEBC /* PlaintextBodyDeserializerSpec.swift */; };
93 | 3AF56EE31E5B37B500F1CEBC /* PlaintextBodyDeserializerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC61E5B37B500F1CEBC /* PlaintextBodyDeserializerSpec.swift */; };
94 | 3AF56EE41E5B37B500F1CEBC /* RequestRepresentationSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC71E5B37B500F1CEBC /* RequestRepresentationSpec.swift */; };
95 | 3AF56EE51E5B37B500F1CEBC /* RequestRepresentationSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC71E5B37B500F1CEBC /* RequestRepresentationSpec.swift */; };
96 | 3AF56EE61E5B37B500F1CEBC /* RequestRepresentationSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC71E5B37B500F1CEBC /* RequestRepresentationSpec.swift */; };
97 | 3AF56EE71E5B37B500F1CEBC /* ResponseDetectiveSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC81E5B37B500F1CEBC /* ResponseDetectiveSpec.swift */; };
98 | 3AF56EE81E5B37B500F1CEBC /* ResponseDetectiveSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC81E5B37B500F1CEBC /* ResponseDetectiveSpec.swift */; };
99 | 3AF56EE91E5B37B500F1CEBC /* ResponseDetectiveSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC81E5B37B500F1CEBC /* ResponseDetectiveSpec.swift */; };
100 | 3AF56EEA1E5B37B500F1CEBC /* ResponseRepresentationSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC91E5B37B500F1CEBC /* ResponseRepresentationSpec.swift */; };
101 | 3AF56EEB1E5B37B500F1CEBC /* ResponseRepresentationSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC91E5B37B500F1CEBC /* ResponseRepresentationSpec.swift */; };
102 | 3AF56EEC1E5B37B500F1CEBC /* ResponseRepresentationSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56EC91E5B37B500F1CEBC /* ResponseRepresentationSpec.swift */; };
103 | 3AF56EF01E5B37B500F1CEBC /* XMLBodyDeserializerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56ECB1E5B37B500F1CEBC /* XMLBodyDeserializerSpec.swift */; };
104 | 3AF56EF11E5B37B500F1CEBC /* XMLBodyDeserializerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56ECB1E5B37B500F1CEBC /* XMLBodyDeserializerSpec.swift */; };
105 | 3AF56EF21E5B37B500F1CEBC /* XMLBodyDeserializerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56ECB1E5B37B500F1CEBC /* XMLBodyDeserializerSpec.swift */; };
106 | 3AF56F0C1E5B4ED800F1CEBC /* TestBodyDeserializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56F0B1E5B4ED800F1CEBC /* TestBodyDeserializer.swift */; };
107 | 3AF56F0D1E5B4ED800F1CEBC /* TestBodyDeserializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56F0B1E5B4ED800F1CEBC /* TestBodyDeserializer.swift */; };
108 | 3AF56F0E1E5B4ED800F1CEBC /* TestBodyDeserializer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF56F0B1E5B4ED800F1CEBC /* TestBodyDeserializer.swift */; };
109 | /* End PBXBuildFile section */
110 |
111 | /* Begin PBXContainerItemProxy section */
112 | 3A2007E41B5501BC00769021 /* PBXContainerItemProxy */ = {
113 | isa = PBXContainerItemProxy;
114 | containerPortal = 3AED3EC31B1DD7B400FA35FC /* Project object */;
115 | proxyType = 1;
116 | remoteGlobalIDString = 3A2007D71B5501BC00769021;
117 | remoteInfo = "ResponseDetective (OS X)";
118 | };
119 | 3AE546341E152DB600E74469 /* PBXContainerItemProxy */ = {
120 | isa = PBXContainerItemProxy;
121 | containerPortal = 3AED3EC31B1DD7B400FA35FC /* Project object */;
122 | proxyType = 1;
123 | remoteGlobalIDString = 3AE546291E152DB500E74469;
124 | remoteInfo = "ResponseDetective (tvOS)";
125 | };
126 | 3AED3ED91B1DD7B400FA35FC /* PBXContainerItemProxy */ = {
127 | isa = PBXContainerItemProxy;
128 | containerPortal = 3AED3EC31B1DD7B400FA35FC /* Project object */;
129 | proxyType = 1;
130 | remoteGlobalIDString = 3AED3ECB1B1DD7B400FA35FC;
131 | remoteInfo = ResponseDetective;
132 | };
133 | /* End PBXContainerItemProxy section */
134 |
135 | /* Begin PBXFileReference section */
136 | 3A2007D81B5501BC00769021 /* ResponseDetective.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ResponseDetective.framework; sourceTree = BUILT_PRODUCTS_DIR; };
137 | 3A2007E21B5501BC00769021 /* ResponseDetectiveTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ResponseDetectiveTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
138 | 3A5A99CB1E604064002EFC39 /* bitrise.yml */ = {isa = PBXFileReference; lastKnownFileType = text; path = bitrise.yml; sourceTree = ""; };
139 | 3A5A99CC1E604064002EFC39 /* Cartfile.private */ = {isa = PBXFileReference; lastKnownFileType = text; path = Cartfile.private; sourceTree = ""; };
140 | 3A5A99CD1E604064002EFC39 /* ResponseDetective.podspec */ = {isa = PBXFileReference; lastKnownFileType = text; path = ResponseDetective.podspec; sourceTree = ""; };
141 | 3A7A4A831EC71336005E2E9D /* Common-Base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Common-Base.xcconfig"; sourceTree = ""; };
142 | 3A7A4A841EC71410005E2E9D /* Framework-Base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Framework-Base.xcconfig"; sourceTree = ""; };
143 | 3AB9E97E1EBB64C0004E575E /* URLEncodedBodyDeserializerSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLEncodedBodyDeserializerSpec.swift; sourceTree = ""; };
144 | 3AC631201EBB5CF8000F6353 /* URLEncodedBodyDeserializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLEncodedBodyDeserializer.swift; sourceTree = ""; };
145 | 3AE5462A1E152DB500E74469 /* ResponseDetective.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ResponseDetective.framework; sourceTree = BUILT_PRODUCTS_DIR; };
146 | 3AE546321E152DB600E74469 /* ResponseDetectiveTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ResponseDetectiveTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
147 | 3AED3ECC1B1DD7B400FA35FC /* ResponseDetective.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ResponseDetective.framework; sourceTree = BUILT_PRODUCTS_DIR; };
148 | 3AED3ED71B1DD7B400FA35FC /* ResponseDetectiveTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ResponseDetectiveTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
149 | 3AF56E6F1E5B379A00F1CEBC /* Framework-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Framework-Info.plist"; sourceTree = ""; };
150 | 3AF56E701E5B379A00F1CEBC /* Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Tests-Info.plist"; sourceTree = ""; };
151 | 3AF56E721E5B37A500F1CEBC /* BufferOutputFacility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BufferOutputFacility.swift; sourceTree = ""; };
152 | 3AF56E731E5B37A500F1CEBC /* ConsoleOutputFacility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConsoleOutputFacility.swift; sourceTree = ""; };
153 | 3AF56E741E5B37A500F1CEBC /* Dictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Dictionary.swift; sourceTree = ""; };
154 | 3AF56E751E5B37A500F1CEBC /* ErrorRepresentation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorRepresentation.swift; sourceTree = ""; };
155 | 3AF56E761E5B37A500F1CEBC /* ImageBodyDeserializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageBodyDeserializer.swift; sourceTree = ""; };
156 | 3AF56E771E5B37A500F1CEBC /* JSONBodyDeserializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONBodyDeserializer.swift; sourceTree = ""; };
157 | 3AF56E781E5B37A500F1CEBC /* OutputFacility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutputFacility.swift; sourceTree = ""; };
158 | 3AF56E791E5B37A500F1CEBC /* PlaintextBodyDeserializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlaintextBodyDeserializer.swift; sourceTree = ""; };
159 | 3AF56E7A1E5B37A500F1CEBC /* RDTBodyDeserializer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RDTBodyDeserializer.h; sourceTree = ""; };
160 | 3AF56E7B1E5B37A500F1CEBC /* RDTHTMLBodyDeserializer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RDTHTMLBodyDeserializer.h; sourceTree = ""; };
161 | 3AF56E7C1E5B37A500F1CEBC /* RDTHTMLBodyDeserializer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RDTHTMLBodyDeserializer.m; sourceTree = ""; };
162 | 3AF56E7D1E5B37A500F1CEBC /* RDTXMLBodyDeserializer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RDTXMLBodyDeserializer.h; sourceTree = ""; };
163 | 3AF56E7E1E5B37A500F1CEBC /* RDTXMLBodyDeserializer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RDTXMLBodyDeserializer.m; sourceTree = ""; };
164 | 3AF56E7F1E5B37A500F1CEBC /* RequestRepresentation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestRepresentation.swift; sourceTree = ""; };
165 | 3AF56E801E5B37A500F1CEBC /* ResponseDetective.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResponseDetective.h; sourceTree = ""; };
166 | 3AF56E811E5B37A500F1CEBC /* ResponseDetective.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResponseDetective.swift; sourceTree = ""; };
167 | 3AF56E821E5B37A500F1CEBC /* ResponseRepresentation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResponseRepresentation.swift; sourceTree = ""; };
168 | 3AF56E831E5B37A500F1CEBC /* URLProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLProtocol.swift; sourceTree = ""; };
169 | 3AF56EC01E5B37B500F1CEBC /* BufferOutputFacilitySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BufferOutputFacilitySpec.swift; sourceTree = ""; };
170 | 3AF56EC11E5B37B500F1CEBC /* ConsoleOutputFacilitySpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConsoleOutputFacilitySpec.swift; sourceTree = ""; };
171 | 3AF56EC21E5B37B500F1CEBC /* ErrorRepresentationSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ErrorRepresentationSpec.swift; sourceTree = ""; };
172 | 3AF56EC31E5B37B500F1CEBC /* HTMLBodyDeserializerSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HTMLBodyDeserializerSpec.swift; sourceTree = ""; };
173 | 3AF56EC41E5B37B500F1CEBC /* ImageBodyDeserializerSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageBodyDeserializerSpec.swift; sourceTree = ""; };
174 | 3AF56EC51E5B37B500F1CEBC /* JSONBodyDeserializerSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSONBodyDeserializerSpec.swift; sourceTree = ""; };
175 | 3AF56EC61E5B37B500F1CEBC /* PlaintextBodyDeserializerSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlaintextBodyDeserializerSpec.swift; sourceTree = ""; };
176 | 3AF56EC71E5B37B500F1CEBC /* RequestRepresentationSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RequestRepresentationSpec.swift; sourceTree = ""; };
177 | 3AF56EC81E5B37B500F1CEBC /* ResponseDetectiveSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResponseDetectiveSpec.swift; sourceTree = ""; };
178 | 3AF56EC91E5B37B500F1CEBC /* ResponseRepresentationSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ResponseRepresentationSpec.swift; sourceTree = ""; };
179 | 3AF56ECB1E5B37B500F1CEBC /* XMLBodyDeserializerSpec.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = XMLBodyDeserializerSpec.swift; sourceTree = ""; };
180 | 3AF56F0B1E5B4ED800F1CEBC /* TestBodyDeserializer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestBodyDeserializer.swift; sourceTree = ""; };
181 | 3AF695861ECB199700586DA7 /* Common-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Common-Debug.xcconfig"; sourceTree = ""; };
182 | 3AF695871ECB19CC00586DA7 /* Framework-iOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Framework-iOS.xcconfig"; sourceTree = ""; };
183 | 3AF695891ECB1A6A00586DA7 /* Tests-Base.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Tests-Base.xcconfig"; sourceTree = ""; };
184 | 3AF6958A1ECB1A7900586DA7 /* Common-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Common-Release.xcconfig"; sourceTree = ""; };
185 | 3AF6958B1ECB1B5100586DA7 /* Tests-iOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Tests-iOS.xcconfig"; sourceTree = ""; };
186 | 3AF6958C1ECB1D2B00586DA7 /* Framework-macOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Framework-macOS.xcconfig"; sourceTree = ""; };
187 | 3AF6958D1ECB1D4200586DA7 /* Framework-tvOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Framework-tvOS.xcconfig"; sourceTree = ""; };
188 | 3AF6958E1ECB1D5800586DA7 /* Tests-macOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Tests-macOS.xcconfig"; sourceTree = ""; };
189 | 3AF6958F1ECB1D6600586DA7 /* Tests-tvOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Tests-tvOS.xcconfig"; sourceTree = ""; };
190 | 3AF96F121E60647900A9831E /* Framework.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = Framework.modulemap; sourceTree = ""; };
191 | 3AF96F131E607C8F00A9831E /* ResponseDetective.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = ResponseDetective.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
192 | /* End PBXFileReference section */
193 |
194 | /* Begin PBXFrameworksBuildPhase section */
195 | 3A2007D41B5501BC00769021 /* Frameworks */ = {
196 | isa = PBXFrameworksBuildPhase;
197 | buildActionMask = 2147483647;
198 | files = (
199 | );
200 | runOnlyForDeploymentPostprocessing = 0;
201 | };
202 | 3A2007DF1B5501BC00769021 /* Frameworks */ = {
203 | isa = PBXFrameworksBuildPhase;
204 | buildActionMask = 2147483647;
205 | files = (
206 | 3A2007E31B5501BC00769021 /* ResponseDetective.framework in Frameworks */,
207 | );
208 | runOnlyForDeploymentPostprocessing = 0;
209 | };
210 | 3AE546261E152DB500E74469 /* Frameworks */ = {
211 | isa = PBXFrameworksBuildPhase;
212 | buildActionMask = 2147483647;
213 | files = (
214 | );
215 | runOnlyForDeploymentPostprocessing = 0;
216 | };
217 | 3AE5462F1E152DB600E74469 /* Frameworks */ = {
218 | isa = PBXFrameworksBuildPhase;
219 | buildActionMask = 2147483647;
220 | files = (
221 | 3AE546331E152DB600E74469 /* ResponseDetective.framework in Frameworks */,
222 | );
223 | runOnlyForDeploymentPostprocessing = 0;
224 | };
225 | 3AED3EC81B1DD7B400FA35FC /* Frameworks */ = {
226 | isa = PBXFrameworksBuildPhase;
227 | buildActionMask = 2147483647;
228 | files = (
229 | );
230 | runOnlyForDeploymentPostprocessing = 0;
231 | };
232 | 3AED3ED41B1DD7B400FA35FC /* Frameworks */ = {
233 | isa = PBXFrameworksBuildPhase;
234 | buildActionMask = 2147483647;
235 | files = (
236 | 3AED3ED81B1DD7B400FA35FC /* ResponseDetective.framework in Frameworks */,
237 | );
238 | runOnlyForDeploymentPostprocessing = 0;
239 | };
240 | /* End PBXFrameworksBuildPhase section */
241 |
242 | /* Begin PBXGroup section */
243 | 3A5A99CA1E60404E002EFC39 /* Other Files */ = {
244 | isa = PBXGroup;
245 | children = (
246 | 3A5A99CB1E604064002EFC39 /* bitrise.yml */,
247 | 3A5A99CC1E604064002EFC39 /* Cartfile.private */,
248 | 3A5A99CD1E604064002EFC39 /* ResponseDetective.podspec */,
249 | );
250 | name = "Other Files";
251 | sourceTree = "";
252 | };
253 | 3A7A4A821EC712FA005E2E9D /* Configuration */ = {
254 | isa = PBXGroup;
255 | children = (
256 | 3AF695831ECB192F00586DA7 /* Common */,
257 | 3AF695841ECB193800586DA7 /* Framework */,
258 | 3AF695881ECB1A5700586DA7 /* Tests */,
259 | );
260 | name = Configuration;
261 | path = ResponseDetective/Configuration;
262 | sourceTree = "";
263 | };
264 | 3AED3EC21B1DD7B400FA35FC = {
265 | isa = PBXGroup;
266 | children = (
267 | 3AF96F131E607C8F00A9831E /* ResponseDetective.playground */,
268 | 3AF56E711E5B37A500F1CEBC /* Sources */,
269 | 3AF56EBA1E5B37B500F1CEBC /* Tests */,
270 | 3AF56E6E1E5B379A00F1CEBC /* Resources */,
271 | 3A7A4A821EC712FA005E2E9D /* Configuration */,
272 | 3A5A99CA1E60404E002EFC39 /* Other Files */,
273 | 3AED3ECD1B1DD7B400FA35FC /* Products */,
274 | );
275 | sourceTree = "";
276 | };
277 | 3AED3ECD1B1DD7B400FA35FC /* Products */ = {
278 | isa = PBXGroup;
279 | children = (
280 | 3AED3ECC1B1DD7B400FA35FC /* ResponseDetective.framework */,
281 | 3AED3ED71B1DD7B400FA35FC /* ResponseDetectiveTests.xctest */,
282 | 3A2007D81B5501BC00769021 /* ResponseDetective.framework */,
283 | 3A2007E21B5501BC00769021 /* ResponseDetectiveTests.xctest */,
284 | 3AE5462A1E152DB500E74469 /* ResponseDetective.framework */,
285 | 3AE546321E152DB600E74469 /* ResponseDetectiveTests.xctest */,
286 | );
287 | name = Products;
288 | sourceTree = "";
289 | };
290 | 3AF56E6E1E5B379A00F1CEBC /* Resources */ = {
291 | isa = PBXGroup;
292 | children = (
293 | 3AF96F121E60647900A9831E /* Framework.modulemap */,
294 | 3AF56E6F1E5B379A00F1CEBC /* Framework-Info.plist */,
295 | 3AF56E701E5B379A00F1CEBC /* Tests-Info.plist */,
296 | );
297 | name = Resources;
298 | path = ResponseDetective/Resources;
299 | sourceTree = "";
300 | };
301 | 3AF56E711E5B37A500F1CEBC /* Sources */ = {
302 | isa = PBXGroup;
303 | children = (
304 | 3AF56E811E5B37A500F1CEBC /* ResponseDetective.swift */,
305 | 3AF56EFD1E5B3CE700F1CEBC /* Representations */,
306 | 3AF56EFE1E5B3CF900F1CEBC /* Body Deserializers */,
307 | 3AF56F011E5B3D3A00F1CEBC /* Output Facilities */,
308 | 3AF56F031E5B3D5C00F1CEBC /* Internal */,
309 | 3AF56F021E5B3D4900F1CEBC /* Extensions */,
310 | );
311 | name = Sources;
312 | path = ResponseDetective/Sources;
313 | sourceTree = "";
314 | };
315 | 3AF56EBA1E5B37B500F1CEBC /* Tests */ = {
316 | isa = PBXGroup;
317 | children = (
318 | 3AF56EBB1E5B37B500F1CEBC /* Additions */,
319 | 3AF56EBF1E5B37B500F1CEBC /* Specs */,
320 | );
321 | name = Tests;
322 | path = ResponseDetective/Tests;
323 | sourceTree = "";
324 | };
325 | 3AF56EBB1E5B37B500F1CEBC /* Additions */ = {
326 | isa = PBXGroup;
327 | children = (
328 | 3AF56F0B1E5B4ED800F1CEBC /* TestBodyDeserializer.swift */,
329 | );
330 | path = Additions;
331 | sourceTree = "";
332 | };
333 | 3AF56EBF1E5B37B500F1CEBC /* Specs */ = {
334 | isa = PBXGroup;
335 | children = (
336 | 3AF56EC81E5B37B500F1CEBC /* ResponseDetectiveSpec.swift */,
337 | 3AF56F081E5B4E7700F1CEBC /* Representations */,
338 | 3AF56F091E5B4E8800F1CEBC /* Body Deserializers */,
339 | 3AF56F0A1E5B4E9A00F1CEBC /* Output Facilities */,
340 | );
341 | path = Specs;
342 | sourceTree = "";
343 | };
344 | 3AF56EFD1E5B3CE700F1CEBC /* Representations */ = {
345 | isa = PBXGroup;
346 | children = (
347 | 3AF56E7F1E5B37A500F1CEBC /* RequestRepresentation.swift */,
348 | 3AF56E821E5B37A500F1CEBC /* ResponseRepresentation.swift */,
349 | 3AF56E751E5B37A500F1CEBC /* ErrorRepresentation.swift */,
350 | );
351 | name = Representations;
352 | sourceTree = "";
353 | };
354 | 3AF56EFE1E5B3CF900F1CEBC /* Body Deserializers */ = {
355 | isa = PBXGroup;
356 | children = (
357 | 3AF56E7A1E5B37A500F1CEBC /* RDTBodyDeserializer.h */,
358 | 3AF56E791E5B37A500F1CEBC /* PlaintextBodyDeserializer.swift */,
359 | 3AF56E761E5B37A500F1CEBC /* ImageBodyDeserializer.swift */,
360 | 3AF56E771E5B37A500F1CEBC /* JSONBodyDeserializer.swift */,
361 | 3AC631201EBB5CF8000F6353 /* URLEncodedBodyDeserializer.swift */,
362 | 3AF56EFF1E5B3D1200F1CEBC /* XMLBodyDeserializer */,
363 | 3AF56F001E5B3D2200F1CEBC /* HTMLBodyDeserializer */,
364 | );
365 | name = "Body Deserializers";
366 | sourceTree = "";
367 | };
368 | 3AF56EFF1E5B3D1200F1CEBC /* XMLBodyDeserializer */ = {
369 | isa = PBXGroup;
370 | children = (
371 | 3AF56E7D1E5B37A500F1CEBC /* RDTXMLBodyDeserializer.h */,
372 | 3AF56E7E1E5B37A500F1CEBC /* RDTXMLBodyDeserializer.m */,
373 | );
374 | name = XMLBodyDeserializer;
375 | sourceTree = "";
376 | };
377 | 3AF56F001E5B3D2200F1CEBC /* HTMLBodyDeserializer */ = {
378 | isa = PBXGroup;
379 | children = (
380 | 3AF56E7B1E5B37A500F1CEBC /* RDTHTMLBodyDeserializer.h */,
381 | 3AF56E7C1E5B37A500F1CEBC /* RDTHTMLBodyDeserializer.m */,
382 | );
383 | name = HTMLBodyDeserializer;
384 | sourceTree = "";
385 | };
386 | 3AF56F011E5B3D3A00F1CEBC /* Output Facilities */ = {
387 | isa = PBXGroup;
388 | children = (
389 | 3AF56E781E5B37A500F1CEBC /* OutputFacility.swift */,
390 | 3AF56E721E5B37A500F1CEBC /* BufferOutputFacility.swift */,
391 | 3AF56E731E5B37A500F1CEBC /* ConsoleOutputFacility.swift */,
392 | );
393 | name = "Output Facilities";
394 | sourceTree = "";
395 | };
396 | 3AF56F021E5B3D4900F1CEBC /* Extensions */ = {
397 | isa = PBXGroup;
398 | children = (
399 | 3AF56E741E5B37A500F1CEBC /* Dictionary.swift */,
400 | );
401 | name = Extensions;
402 | sourceTree = "";
403 | };
404 | 3AF56F031E5B3D5C00F1CEBC /* Internal */ = {
405 | isa = PBXGroup;
406 | children = (
407 | 3AF56E801E5B37A500F1CEBC /* ResponseDetective.h */,
408 | 3AF56E831E5B37A500F1CEBC /* URLProtocol.swift */,
409 | );
410 | name = Internal;
411 | sourceTree = "";
412 | };
413 | 3AF56F081E5B4E7700F1CEBC /* Representations */ = {
414 | isa = PBXGroup;
415 | children = (
416 | 3AF56EC71E5B37B500F1CEBC /* RequestRepresentationSpec.swift */,
417 | 3AF56EC91E5B37B500F1CEBC /* ResponseRepresentationSpec.swift */,
418 | 3AF56EC21E5B37B500F1CEBC /* ErrorRepresentationSpec.swift */,
419 | );
420 | name = Representations;
421 | sourceTree = "";
422 | };
423 | 3AF56F091E5B4E8800F1CEBC /* Body Deserializers */ = {
424 | isa = PBXGroup;
425 | children = (
426 | 3AF56EC41E5B37B500F1CEBC /* ImageBodyDeserializerSpec.swift */,
427 | 3AF56EC31E5B37B500F1CEBC /* HTMLBodyDeserializerSpec.swift */,
428 | 3AF56ECB1E5B37B500F1CEBC /* XMLBodyDeserializerSpec.swift */,
429 | 3AF56EC61E5B37B500F1CEBC /* PlaintextBodyDeserializerSpec.swift */,
430 | 3AF56EC51E5B37B500F1CEBC /* JSONBodyDeserializerSpec.swift */,
431 | 3AB9E97E1EBB64C0004E575E /* URLEncodedBodyDeserializerSpec.swift */,
432 | );
433 | name = "Body Deserializers";
434 | sourceTree = "";
435 | };
436 | 3AF56F0A1E5B4E9A00F1CEBC /* Output Facilities */ = {
437 | isa = PBXGroup;
438 | children = (
439 | 3AF56EC01E5B37B500F1CEBC /* BufferOutputFacilitySpec.swift */,
440 | 3AF56EC11E5B37B500F1CEBC /* ConsoleOutputFacilitySpec.swift */,
441 | );
442 | name = "Output Facilities";
443 | sourceTree = "";
444 | };
445 | 3AF695831ECB192F00586DA7 /* Common */ = {
446 | isa = PBXGroup;
447 | children = (
448 | 3A7A4A831EC71336005E2E9D /* Common-Base.xcconfig */,
449 | 3AF695861ECB199700586DA7 /* Common-Debug.xcconfig */,
450 | 3AF6958A1ECB1A7900586DA7 /* Common-Release.xcconfig */,
451 | );
452 | name = Common;
453 | sourceTree = "";
454 | };
455 | 3AF695841ECB193800586DA7 /* Framework */ = {
456 | isa = PBXGroup;
457 | children = (
458 | 3A7A4A841EC71410005E2E9D /* Framework-Base.xcconfig */,
459 | 3AF695871ECB19CC00586DA7 /* Framework-iOS.xcconfig */,
460 | 3AF6958C1ECB1D2B00586DA7 /* Framework-macOS.xcconfig */,
461 | 3AF6958D1ECB1D4200586DA7 /* Framework-tvOS.xcconfig */,
462 | );
463 | name = Framework;
464 | sourceTree = "";
465 | };
466 | 3AF695881ECB1A5700586DA7 /* Tests */ = {
467 | isa = PBXGroup;
468 | children = (
469 | 3AF695891ECB1A6A00586DA7 /* Tests-Base.xcconfig */,
470 | 3AF6958B1ECB1B5100586DA7 /* Tests-iOS.xcconfig */,
471 | 3AF6958E1ECB1D5800586DA7 /* Tests-macOS.xcconfig */,
472 | 3AF6958F1ECB1D6600586DA7 /* Tests-tvOS.xcconfig */,
473 | );
474 | name = Tests;
475 | sourceTree = "";
476 | };
477 | /* End PBXGroup section */
478 |
479 | /* Begin PBXHeadersBuildPhase section */
480 | 3A2007D51B5501BC00769021 /* Headers */ = {
481 | isa = PBXHeadersBuildPhase;
482 | buildActionMask = 2147483647;
483 | files = (
484 | 3AF56E9D1E5B37A500F1CEBC /* RDTBodyDeserializer.h in Headers */,
485 | 3AF56EAF1E5B37A500F1CEBC /* ResponseDetective.h in Headers */,
486 | 3AF56EA61E5B37A500F1CEBC /* RDTXMLBodyDeserializer.h in Headers */,
487 | 3AF56EA01E5B37A500F1CEBC /* RDTHTMLBodyDeserializer.h in Headers */,
488 | );
489 | runOnlyForDeploymentPostprocessing = 0;
490 | };
491 | 3AE546271E152DB500E74469 /* Headers */ = {
492 | isa = PBXHeadersBuildPhase;
493 | buildActionMask = 2147483647;
494 | files = (
495 | 3AF56E9E1E5B37A500F1CEBC /* RDTBodyDeserializer.h in Headers */,
496 | 3AF56EB01E5B37A500F1CEBC /* ResponseDetective.h in Headers */,
497 | 3AF56EA71E5B37A500F1CEBC /* RDTXMLBodyDeserializer.h in Headers */,
498 | 3AF56EA11E5B37A500F1CEBC /* RDTHTMLBodyDeserializer.h in Headers */,
499 | );
500 | runOnlyForDeploymentPostprocessing = 0;
501 | };
502 | 3AED3EC91B1DD7B400FA35FC /* Headers */ = {
503 | isa = PBXHeadersBuildPhase;
504 | buildActionMask = 2147483647;
505 | files = (
506 | 3AF56E9C1E5B37A500F1CEBC /* RDTBodyDeserializer.h in Headers */,
507 | 3AF56EAE1E5B37A500F1CEBC /* ResponseDetective.h in Headers */,
508 | 3AF56EA51E5B37A500F1CEBC /* RDTXMLBodyDeserializer.h in Headers */,
509 | 3AF56E9F1E5B37A500F1CEBC /* RDTHTMLBodyDeserializer.h in Headers */,
510 | );
511 | runOnlyForDeploymentPostprocessing = 0;
512 | };
513 | /* End PBXHeadersBuildPhase section */
514 |
515 | /* Begin PBXNativeTarget section */
516 | 3A2007D71B5501BC00769021 /* ResponseDetective-macOS */ = {
517 | isa = PBXNativeTarget;
518 | buildConfigurationList = 3A2007EB1B5501BC00769021 /* Build configuration list for PBXNativeTarget "ResponseDetective-macOS" */;
519 | buildPhases = (
520 | 3A2007D31B5501BC00769021 /* Sources */,
521 | 3A2007D41B5501BC00769021 /* Frameworks */,
522 | 3A2007D51B5501BC00769021 /* Headers */,
523 | 3A2007D61B5501BC00769021 /* Resources */,
524 | );
525 | buildRules = (
526 | );
527 | dependencies = (
528 | );
529 | name = "ResponseDetective-macOS";
530 | productName = "ResponseDetective (OS X)";
531 | productReference = 3A2007D81B5501BC00769021 /* ResponseDetective.framework */;
532 | productType = "com.apple.product-type.framework";
533 | };
534 | 3A2007E11B5501BC00769021 /* ResponseDetective-macOS-Tests */ = {
535 | isa = PBXNativeTarget;
536 | buildConfigurationList = 3A2007EE1B5501BC00769021 /* Build configuration list for PBXNativeTarget "ResponseDetective-macOS-Tests" */;
537 | buildPhases = (
538 | 3A2007DE1B5501BC00769021 /* Sources */,
539 | 3A2007DF1B5501BC00769021 /* Frameworks */,
540 | 3A2007E01B5501BC00769021 /* Resources */,
541 | 3A7D018A1CD3C09B00B7FBD7 /* Copy Carthage Frameworks */,
542 | );
543 | buildRules = (
544 | );
545 | dependencies = (
546 | 3A2007E51B5501BC00769021 /* PBXTargetDependency */,
547 | );
548 | name = "ResponseDetective-macOS-Tests";
549 | productName = "ResponseDetective (OS X)Tests";
550 | productReference = 3A2007E21B5501BC00769021 /* ResponseDetectiveTests.xctest */;
551 | productType = "com.apple.product-type.bundle.unit-test";
552 | };
553 | 3AE546291E152DB500E74469 /* ResponseDetective-tvOS */ = {
554 | isa = PBXNativeTarget;
555 | buildConfigurationList = 3AE5463B1E152DB600E74469 /* Build configuration list for PBXNativeTarget "ResponseDetective-tvOS" */;
556 | buildPhases = (
557 | 3AE546251E152DB500E74469 /* Sources */,
558 | 3AE546261E152DB500E74469 /* Frameworks */,
559 | 3AE546271E152DB500E74469 /* Headers */,
560 | 3AE546281E152DB500E74469 /* Resources */,
561 | );
562 | buildRules = (
563 | );
564 | dependencies = (
565 | );
566 | name = "ResponseDetective-tvOS";
567 | productName = "ResponseDetective (tvOS)";
568 | productReference = 3AE5462A1E152DB500E74469 /* ResponseDetective.framework */;
569 | productType = "com.apple.product-type.framework";
570 | };
571 | 3AE546311E152DB600E74469 /* ResponseDetective-tvOS-Tests */ = {
572 | isa = PBXNativeTarget;
573 | buildConfigurationList = 3AE5463E1E152DB600E74469 /* Build configuration list for PBXNativeTarget "ResponseDetective-tvOS-Tests" */;
574 | buildPhases = (
575 | 3AE5462E1E152DB600E74469 /* Sources */,
576 | 3AE5462F1E152DB600E74469 /* Frameworks */,
577 | 3AE546301E152DB600E74469 /* Resources */,
578 | 3AE546671E1531B300E74469 /* Copy Carthage Frameworks */,
579 | );
580 | buildRules = (
581 | );
582 | dependencies = (
583 | 3AE546351E152DB600E74469 /* PBXTargetDependency */,
584 | );
585 | name = "ResponseDetective-tvOS-Tests";
586 | productName = "ResponseDetective (tvOS)Tests";
587 | productReference = 3AE546321E152DB600E74469 /* ResponseDetectiveTests.xctest */;
588 | productType = "com.apple.product-type.bundle.unit-test";
589 | };
590 | 3AED3ECB1B1DD7B400FA35FC /* ResponseDetective-iOS */ = {
591 | isa = PBXNativeTarget;
592 | buildConfigurationList = 3AED3EE21B1DD7B400FA35FC /* Build configuration list for PBXNativeTarget "ResponseDetective-iOS" */;
593 | buildPhases = (
594 | 3AED3EC71B1DD7B400FA35FC /* Sources */,
595 | 3AED3EC81B1DD7B400FA35FC /* Frameworks */,
596 | 3AED3EC91B1DD7B400FA35FC /* Headers */,
597 | 3AED3ECA1B1DD7B400FA35FC /* Resources */,
598 | );
599 | buildRules = (
600 | );
601 | dependencies = (
602 | );
603 | name = "ResponseDetective-iOS";
604 | productName = ResponseDetective;
605 | productReference = 3AED3ECC1B1DD7B400FA35FC /* ResponseDetective.framework */;
606 | productType = "com.apple.product-type.framework";
607 | };
608 | 3AED3ED61B1DD7B400FA35FC /* ResponseDetective-iOS-Tests */ = {
609 | isa = PBXNativeTarget;
610 | buildConfigurationList = 3AED3EE51B1DD7B400FA35FC /* Build configuration list for PBXNativeTarget "ResponseDetective-iOS-Tests" */;
611 | buildPhases = (
612 | 3AED3ED31B1DD7B400FA35FC /* Sources */,
613 | 3AED3ED41B1DD7B400FA35FC /* Frameworks */,
614 | 3AED3ED51B1DD7B400FA35FC /* Resources */,
615 | 3ACCEBDB1B21D70D006C0FF4 /* Copy Carthage Frameworks */,
616 | );
617 | buildRules = (
618 | );
619 | dependencies = (
620 | 3AED3EDA1B1DD7B400FA35FC /* PBXTargetDependency */,
621 | );
622 | name = "ResponseDetective-iOS-Tests";
623 | productName = ResponseDetectiveTests;
624 | productReference = 3AED3ED71B1DD7B400FA35FC /* ResponseDetectiveTests.xctest */;
625 | productType = "com.apple.product-type.bundle.unit-test";
626 | };
627 | /* End PBXNativeTarget section */
628 |
629 | /* Begin PBXProject section */
630 | 3AED3EC31B1DD7B400FA35FC /* Project object */ = {
631 | isa = PBXProject;
632 | attributes = {
633 | CLASSPREFIX = RDT;
634 | LastSwiftMigration = 0700;
635 | LastSwiftUpdateCheck = 0820;
636 | LastUpgradeCheck = 1220;
637 | ORGANIZATIONNAME = "Netguru S.A.";
638 | TargetAttributes = {
639 | 3A2007D71B5501BC00769021 = {
640 | CreatedOnToolsVersion = 6.4;
641 | LastSwiftMigration = 0930;
642 | };
643 | 3A2007E11B5501BC00769021 = {
644 | CreatedOnToolsVersion = 6.4;
645 | LastSwiftMigration = 0930;
646 | };
647 | 3AE546291E152DB500E74469 = {
648 | CreatedOnToolsVersion = 8.2.1;
649 | ProvisioningStyle = Manual;
650 | };
651 | 3AE546311E152DB600E74469 = {
652 | CreatedOnToolsVersion = 8.2.1;
653 | ProvisioningStyle = Automatic;
654 | };
655 | 3AED3ECB1B1DD7B400FA35FC = {
656 | CreatedOnToolsVersion = 6.3.2;
657 | LastSwiftMigration = 0820;
658 | };
659 | 3AED3ED61B1DD7B400FA35FC = {
660 | CreatedOnToolsVersion = 6.3.2;
661 | LastSwiftMigration = 0820;
662 | };
663 | };
664 | };
665 | buildConfigurationList = 3AED3EC61B1DD7B400FA35FC /* Build configuration list for PBXProject "ResponseDetective" */;
666 | compatibilityVersion = "Xcode 3.2";
667 | developmentRegion = en;
668 | hasScannedForEncodings = 0;
669 | knownRegions = (
670 | en,
671 | Base,
672 | );
673 | mainGroup = 3AED3EC21B1DD7B400FA35FC;
674 | productRefGroup = 3AED3ECD1B1DD7B400FA35FC /* Products */;
675 | projectDirPath = "";
676 | projectRoot = "";
677 | targets = (
678 | 3AED3ECB1B1DD7B400FA35FC /* ResponseDetective-iOS */,
679 | 3AED3ED61B1DD7B400FA35FC /* ResponseDetective-iOS-Tests */,
680 | 3A2007D71B5501BC00769021 /* ResponseDetective-macOS */,
681 | 3A2007E11B5501BC00769021 /* ResponseDetective-macOS-Tests */,
682 | 3AE546291E152DB500E74469 /* ResponseDetective-tvOS */,
683 | 3AE546311E152DB600E74469 /* ResponseDetective-tvOS-Tests */,
684 | );
685 | };
686 | /* End PBXProject section */
687 |
688 | /* Begin PBXResourcesBuildPhase section */
689 | 3A2007D61B5501BC00769021 /* Resources */ = {
690 | isa = PBXResourcesBuildPhase;
691 | buildActionMask = 2147483647;
692 | files = (
693 | );
694 | runOnlyForDeploymentPostprocessing = 0;
695 | };
696 | 3A2007E01B5501BC00769021 /* Resources */ = {
697 | isa = PBXResourcesBuildPhase;
698 | buildActionMask = 2147483647;
699 | files = (
700 | );
701 | runOnlyForDeploymentPostprocessing = 0;
702 | };
703 | 3AE546281E152DB500E74469 /* Resources */ = {
704 | isa = PBXResourcesBuildPhase;
705 | buildActionMask = 2147483647;
706 | files = (
707 | );
708 | runOnlyForDeploymentPostprocessing = 0;
709 | };
710 | 3AE546301E152DB600E74469 /* Resources */ = {
711 | isa = PBXResourcesBuildPhase;
712 | buildActionMask = 2147483647;
713 | files = (
714 | );
715 | runOnlyForDeploymentPostprocessing = 0;
716 | };
717 | 3AED3ECA1B1DD7B400FA35FC /* Resources */ = {
718 | isa = PBXResourcesBuildPhase;
719 | buildActionMask = 2147483647;
720 | files = (
721 | );
722 | runOnlyForDeploymentPostprocessing = 0;
723 | };
724 | 3AED3ED51B1DD7B400FA35FC /* Resources */ = {
725 | isa = PBXResourcesBuildPhase;
726 | buildActionMask = 2147483647;
727 | files = (
728 | );
729 | runOnlyForDeploymentPostprocessing = 0;
730 | };
731 | /* End PBXResourcesBuildPhase section */
732 |
733 | /* Begin PBXShellScriptBuildPhase section */
734 | 3A7D018A1CD3C09B00B7FBD7 /* Copy Carthage Frameworks */ = {
735 | isa = PBXShellScriptBuildPhase;
736 | buildActionMask = 2147483647;
737 | files = (
738 | );
739 | inputPaths = (
740 | "$(_CARTHAGE_BUILD_PATH)/Quick.framework",
741 | "$(_CARTHAGE_BUILD_PATH)/Nimble.framework",
742 | "$(_CARTHAGE_BUILD_PATH)/OHHTTPStubs.framework",
743 | );
744 | name = "Copy Carthage Frameworks";
745 | outputPaths = (
746 | );
747 | runOnlyForDeploymentPostprocessing = 0;
748 | shellPath = /bin/sh;
749 | shellScript = "carthage copy-frameworks";
750 | showEnvVarsInLog = 0;
751 | };
752 | 3ACCEBDB1B21D70D006C0FF4 /* Copy Carthage Frameworks */ = {
753 | isa = PBXShellScriptBuildPhase;
754 | buildActionMask = 2147483647;
755 | files = (
756 | );
757 | inputPaths = (
758 | "$(_CARTHAGE_BUILD_PATH)/Nimble.framework",
759 | "$(_CARTHAGE_BUILD_PATH)/Quick.framework",
760 | "$(_CARTHAGE_BUILD_PATH)/OHHTTPStubs.framework",
761 | );
762 | name = "Copy Carthage Frameworks";
763 | outputPaths = (
764 | );
765 | runOnlyForDeploymentPostprocessing = 0;
766 | shellPath = /bin/sh;
767 | shellScript = "carthage copy-frameworks";
768 | showEnvVarsInLog = 0;
769 | };
770 | 3AE546671E1531B300E74469 /* Copy Carthage Frameworks */ = {
771 | isa = PBXShellScriptBuildPhase;
772 | buildActionMask = 2147483647;
773 | files = (
774 | );
775 | inputPaths = (
776 | "$(_CARTHAGE_BUILD_PATH)/Quick.framework",
777 | "$(_CARTHAGE_BUILD_PATH)/Nimble.framework",
778 | "$(_CARTHAGE_BUILD_PATH)/OHHTTPStubs.framework",
779 | );
780 | name = "Copy Carthage Frameworks";
781 | outputPaths = (
782 | );
783 | runOnlyForDeploymentPostprocessing = 0;
784 | shellPath = /bin/sh;
785 | shellScript = "carthage copy-frameworks";
786 | };
787 | /* End PBXShellScriptBuildPhase section */
788 |
789 | /* Begin PBXSourcesBuildPhase section */
790 | 3A2007D31B5501BC00769021 /* Sources */ = {
791 | isa = PBXSourcesBuildPhase;
792 | buildActionMask = 2147483647;
793 | files = (
794 | 3AF56E971E5B37A500F1CEBC /* OutputFacility.swift in Sources */,
795 | 3AF56E941E5B37A500F1CEBC /* JSONBodyDeserializer.swift in Sources */,
796 | 3AC631221EBB5CF8000F6353 /* URLEncodedBodyDeserializer.swift in Sources */,
797 | 3AF56E851E5B37A500F1CEBC /* BufferOutputFacility.swift in Sources */,
798 | 3AF56EA91E5B37A500F1CEBC /* RDTXMLBodyDeserializer.m in Sources */,
799 | 3AF56EAC1E5B37A500F1CEBC /* RequestRepresentation.swift in Sources */,
800 | 3AF56EB51E5B37A500F1CEBC /* ResponseRepresentation.swift in Sources */,
801 | 3AF56E911E5B37A500F1CEBC /* ImageBodyDeserializer.swift in Sources */,
802 | 3AF56EB21E5B37A500F1CEBC /* ResponseDetective.swift in Sources */,
803 | 3AF56E9A1E5B37A500F1CEBC /* PlaintextBodyDeserializer.swift in Sources */,
804 | 3AF56E8E1E5B37A500F1CEBC /* ErrorRepresentation.swift in Sources */,
805 | 3AF56E881E5B37A500F1CEBC /* ConsoleOutputFacility.swift in Sources */,
806 | 3AF56EB81E5B37A500F1CEBC /* URLProtocol.swift in Sources */,
807 | 3AF56E8B1E5B37A500F1CEBC /* Dictionary.swift in Sources */,
808 | 3AF56EA31E5B37A500F1CEBC /* RDTHTMLBodyDeserializer.m in Sources */,
809 | );
810 | runOnlyForDeploymentPostprocessing = 0;
811 | };
812 | 3A2007DE1B5501BC00769021 /* Sources */ = {
813 | isa = PBXSourcesBuildPhase;
814 | buildActionMask = 2147483647;
815 | files = (
816 | 3AF56EF11E5B37B500F1CEBC /* XMLBodyDeserializerSpec.swift in Sources */,
817 | 3AF56EEB1E5B37B500F1CEBC /* ResponseRepresentationSpec.swift in Sources */,
818 | 3AF56ED61E5B37B500F1CEBC /* ErrorRepresentationSpec.swift in Sources */,
819 | 3AF56EDC1E5B37B500F1CEBC /* ImageBodyDeserializerSpec.swift in Sources */,
820 | 3AF56ED01E5B37B500F1CEBC /* BufferOutputFacilitySpec.swift in Sources */,
821 | 3AF56EE81E5B37B500F1CEBC /* ResponseDetectiveSpec.swift in Sources */,
822 | 3AF56EE21E5B37B500F1CEBC /* PlaintextBodyDeserializerSpec.swift in Sources */,
823 | 3AB9E9811EBB64C9004E575E /* URLEncodedBodyDeserializerSpec.swift in Sources */,
824 | 3AF56ED31E5B37B500F1CEBC /* ConsoleOutputFacilitySpec.swift in Sources */,
825 | 3AF56ED91E5B37B500F1CEBC /* HTMLBodyDeserializerSpec.swift in Sources */,
826 | 3AF56EE51E5B37B500F1CEBC /* RequestRepresentationSpec.swift in Sources */,
827 | 3AF56F0D1E5B4ED800F1CEBC /* TestBodyDeserializer.swift in Sources */,
828 | 3AF56EDF1E5B37B500F1CEBC /* JSONBodyDeserializerSpec.swift in Sources */,
829 | );
830 | runOnlyForDeploymentPostprocessing = 0;
831 | };
832 | 3AE546251E152DB500E74469 /* Sources */ = {
833 | isa = PBXSourcesBuildPhase;
834 | buildActionMask = 2147483647;
835 | files = (
836 | 3AF56E981E5B37A500F1CEBC /* OutputFacility.swift in Sources */,
837 | 3AF56E951E5B37A500F1CEBC /* JSONBodyDeserializer.swift in Sources */,
838 | 3AC631231EBB5CF8000F6353 /* URLEncodedBodyDeserializer.swift in Sources */,
839 | 3AF56E861E5B37A500F1CEBC /* BufferOutputFacility.swift in Sources */,
840 | 3AF56EAA1E5B37A500F1CEBC /* RDTXMLBodyDeserializer.m in Sources */,
841 | 3AF56EAD1E5B37A500F1CEBC /* RequestRepresentation.swift in Sources */,
842 | 3AF56EB61E5B37A500F1CEBC /* ResponseRepresentation.swift in Sources */,
843 | 3AF56E921E5B37A500F1CEBC /* ImageBodyDeserializer.swift in Sources */,
844 | 3AF56EB31E5B37A500F1CEBC /* ResponseDetective.swift in Sources */,
845 | 3AF56E9B1E5B37A500F1CEBC /* PlaintextBodyDeserializer.swift in Sources */,
846 | 3AF56E8F1E5B37A500F1CEBC /* ErrorRepresentation.swift in Sources */,
847 | 3AF56E891E5B37A500F1CEBC /* ConsoleOutputFacility.swift in Sources */,
848 | 3AF56EB91E5B37A500F1CEBC /* URLProtocol.swift in Sources */,
849 | 3AF56E8C1E5B37A500F1CEBC /* Dictionary.swift in Sources */,
850 | 3AF56EA41E5B37A500F1CEBC /* RDTHTMLBodyDeserializer.m in Sources */,
851 | );
852 | runOnlyForDeploymentPostprocessing = 0;
853 | };
854 | 3AE5462E1E152DB600E74469 /* Sources */ = {
855 | isa = PBXSourcesBuildPhase;
856 | buildActionMask = 2147483647;
857 | files = (
858 | 3AF56EF21E5B37B500F1CEBC /* XMLBodyDeserializerSpec.swift in Sources */,
859 | 3AF56EEC1E5B37B500F1CEBC /* ResponseRepresentationSpec.swift in Sources */,
860 | 3AF56ED71E5B37B500F1CEBC /* ErrorRepresentationSpec.swift in Sources */,
861 | 3AF56EDD1E5B37B500F1CEBC /* ImageBodyDeserializerSpec.swift in Sources */,
862 | 3AF56ED11E5B37B500F1CEBC /* BufferOutputFacilitySpec.swift in Sources */,
863 | 3AF56EE91E5B37B500F1CEBC /* ResponseDetectiveSpec.swift in Sources */,
864 | 3AF56EE31E5B37B500F1CEBC /* PlaintextBodyDeserializerSpec.swift in Sources */,
865 | 3AB9E9821EBB64C9004E575E /* URLEncodedBodyDeserializerSpec.swift in Sources */,
866 | 3AF56ED41E5B37B500F1CEBC /* ConsoleOutputFacilitySpec.swift in Sources */,
867 | 3AF56EDA1E5B37B500F1CEBC /* HTMLBodyDeserializerSpec.swift in Sources */,
868 | 3AF56EE61E5B37B500F1CEBC /* RequestRepresentationSpec.swift in Sources */,
869 | 3AF56F0E1E5B4ED800F1CEBC /* TestBodyDeserializer.swift in Sources */,
870 | 3AF56EE01E5B37B500F1CEBC /* JSONBodyDeserializerSpec.swift in Sources */,
871 | );
872 | runOnlyForDeploymentPostprocessing = 0;
873 | };
874 | 3AED3EC71B1DD7B400FA35FC /* Sources */ = {
875 | isa = PBXSourcesBuildPhase;
876 | buildActionMask = 2147483647;
877 | files = (
878 | 3AF56E961E5B37A500F1CEBC /* OutputFacility.swift in Sources */,
879 | 3AF56E931E5B37A500F1CEBC /* JSONBodyDeserializer.swift in Sources */,
880 | 3AC631211EBB5CF8000F6353 /* URLEncodedBodyDeserializer.swift in Sources */,
881 | 3AF56E841E5B37A500F1CEBC /* BufferOutputFacility.swift in Sources */,
882 | 3AF56EA81E5B37A500F1CEBC /* RDTXMLBodyDeserializer.m in Sources */,
883 | 3AF56EAB1E5B37A500F1CEBC /* RequestRepresentation.swift in Sources */,
884 | 3AF56EB41E5B37A500F1CEBC /* ResponseRepresentation.swift in Sources */,
885 | 3AF56E901E5B37A500F1CEBC /* ImageBodyDeserializer.swift in Sources */,
886 | 3AF56EB11E5B37A500F1CEBC /* ResponseDetective.swift in Sources */,
887 | 3AF56E991E5B37A500F1CEBC /* PlaintextBodyDeserializer.swift in Sources */,
888 | 3AF56E8D1E5B37A500F1CEBC /* ErrorRepresentation.swift in Sources */,
889 | 3AF56E871E5B37A500F1CEBC /* ConsoleOutputFacility.swift in Sources */,
890 | 3AF56EB71E5B37A500F1CEBC /* URLProtocol.swift in Sources */,
891 | 3AF56E8A1E5B37A500F1CEBC /* Dictionary.swift in Sources */,
892 | 3AF56EA21E5B37A500F1CEBC /* RDTHTMLBodyDeserializer.m in Sources */,
893 | );
894 | runOnlyForDeploymentPostprocessing = 0;
895 | };
896 | 3AED3ED31B1DD7B400FA35FC /* Sources */ = {
897 | isa = PBXSourcesBuildPhase;
898 | buildActionMask = 2147483647;
899 | files = (
900 | 3AF56EF01E5B37B500F1CEBC /* XMLBodyDeserializerSpec.swift in Sources */,
901 | 3AF56EEA1E5B37B500F1CEBC /* ResponseRepresentationSpec.swift in Sources */,
902 | 3AF56ED51E5B37B500F1CEBC /* ErrorRepresentationSpec.swift in Sources */,
903 | 3AF56EDB1E5B37B500F1CEBC /* ImageBodyDeserializerSpec.swift in Sources */,
904 | 3AF56ECF1E5B37B500F1CEBC /* BufferOutputFacilitySpec.swift in Sources */,
905 | 3AF56EE71E5B37B500F1CEBC /* ResponseDetectiveSpec.swift in Sources */,
906 | 3AF56EE11E5B37B500F1CEBC /* PlaintextBodyDeserializerSpec.swift in Sources */,
907 | 3AB9E9801EBB64C8004E575E /* URLEncodedBodyDeserializerSpec.swift in Sources */,
908 | 3AF56ED21E5B37B500F1CEBC /* ConsoleOutputFacilitySpec.swift in Sources */,
909 | 3AF56ED81E5B37B500F1CEBC /* HTMLBodyDeserializerSpec.swift in Sources */,
910 | 3AF56EE41E5B37B500F1CEBC /* RequestRepresentationSpec.swift in Sources */,
911 | 3AF56F0C1E5B4ED800F1CEBC /* TestBodyDeserializer.swift in Sources */,
912 | 3AF56EDE1E5B37B500F1CEBC /* JSONBodyDeserializerSpec.swift in Sources */,
913 | );
914 | runOnlyForDeploymentPostprocessing = 0;
915 | };
916 | /* End PBXSourcesBuildPhase section */
917 |
918 | /* Begin PBXTargetDependency section */
919 | 3A2007E51B5501BC00769021 /* PBXTargetDependency */ = {
920 | isa = PBXTargetDependency;
921 | target = 3A2007D71B5501BC00769021 /* ResponseDetective-macOS */;
922 | targetProxy = 3A2007E41B5501BC00769021 /* PBXContainerItemProxy */;
923 | };
924 | 3AE546351E152DB600E74469 /* PBXTargetDependency */ = {
925 | isa = PBXTargetDependency;
926 | target = 3AE546291E152DB500E74469 /* ResponseDetective-tvOS */;
927 | targetProxy = 3AE546341E152DB600E74469 /* PBXContainerItemProxy */;
928 | };
929 | 3AED3EDA1B1DD7B400FA35FC /* PBXTargetDependency */ = {
930 | isa = PBXTargetDependency;
931 | target = 3AED3ECB1B1DD7B400FA35FC /* ResponseDetective-iOS */;
932 | targetProxy = 3AED3ED91B1DD7B400FA35FC /* PBXContainerItemProxy */;
933 | };
934 | /* End PBXTargetDependency section */
935 |
936 | /* Begin XCBuildConfiguration section */
937 | 3A2007EC1B5501BC00769021 /* Debug */ = {
938 | isa = XCBuildConfiguration;
939 | baseConfigurationReference = 3AF6958C1ECB1D2B00586DA7 /* Framework-macOS.xcconfig */;
940 | buildSettings = {
941 | };
942 | name = Debug;
943 | };
944 | 3A2007ED1B5501BC00769021 /* Release */ = {
945 | isa = XCBuildConfiguration;
946 | baseConfigurationReference = 3AF6958C1ECB1D2B00586DA7 /* Framework-macOS.xcconfig */;
947 | buildSettings = {
948 | };
949 | name = Release;
950 | };
951 | 3A2007EF1B5501BC00769021 /* Debug */ = {
952 | isa = XCBuildConfiguration;
953 | baseConfigurationReference = 3AF6958E1ECB1D5800586DA7 /* Tests-macOS.xcconfig */;
954 | buildSettings = {
955 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
956 | };
957 | name = Debug;
958 | };
959 | 3A2007F01B5501BC00769021 /* Release */ = {
960 | isa = XCBuildConfiguration;
961 | baseConfigurationReference = 3AF6958E1ECB1D5800586DA7 /* Tests-macOS.xcconfig */;
962 | buildSettings = {
963 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
964 | };
965 | name = Release;
966 | };
967 | 3AE5463C1E152DB600E74469 /* Debug */ = {
968 | isa = XCBuildConfiguration;
969 | baseConfigurationReference = 3AF6958D1ECB1D4200586DA7 /* Framework-tvOS.xcconfig */;
970 | buildSettings = {
971 | };
972 | name = Debug;
973 | };
974 | 3AE5463D1E152DB600E74469 /* Release */ = {
975 | isa = XCBuildConfiguration;
976 | baseConfigurationReference = 3AF6958D1ECB1D4200586DA7 /* Framework-tvOS.xcconfig */;
977 | buildSettings = {
978 | };
979 | name = Release;
980 | };
981 | 3AE5463F1E152DB600E74469 /* Debug */ = {
982 | isa = XCBuildConfiguration;
983 | baseConfigurationReference = 3AF6958F1ECB1D6600586DA7 /* Tests-tvOS.xcconfig */;
984 | buildSettings = {
985 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
986 | };
987 | name = Debug;
988 | };
989 | 3AE546401E152DB600E74469 /* Release */ = {
990 | isa = XCBuildConfiguration;
991 | baseConfigurationReference = 3AF6958F1ECB1D6600586DA7 /* Tests-tvOS.xcconfig */;
992 | buildSettings = {
993 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
994 | };
995 | name = Release;
996 | };
997 | 3AED3EE01B1DD7B400FA35FC /* Debug */ = {
998 | isa = XCBuildConfiguration;
999 | baseConfigurationReference = 3AF695861ECB199700586DA7 /* Common-Debug.xcconfig */;
1000 | buildSettings = {
1001 | };
1002 | name = Debug;
1003 | };
1004 | 3AED3EE11B1DD7B400FA35FC /* Release */ = {
1005 | isa = XCBuildConfiguration;
1006 | baseConfigurationReference = 3AF6958A1ECB1A7900586DA7 /* Common-Release.xcconfig */;
1007 | buildSettings = {
1008 | };
1009 | name = Release;
1010 | };
1011 | 3AED3EE31B1DD7B400FA35FC /* Debug */ = {
1012 | isa = XCBuildConfiguration;
1013 | baseConfigurationReference = 3AF695871ECB19CC00586DA7 /* Framework-iOS.xcconfig */;
1014 | buildSettings = {
1015 | };
1016 | name = Debug;
1017 | };
1018 | 3AED3EE41B1DD7B400FA35FC /* Release */ = {
1019 | isa = XCBuildConfiguration;
1020 | baseConfigurationReference = 3AF695871ECB19CC00586DA7 /* Framework-iOS.xcconfig */;
1021 | buildSettings = {
1022 | };
1023 | name = Release;
1024 | };
1025 | 3AED3EE61B1DD7B400FA35FC /* Debug */ = {
1026 | isa = XCBuildConfiguration;
1027 | baseConfigurationReference = 3AF6958B1ECB1B5100586DA7 /* Tests-iOS.xcconfig */;
1028 | buildSettings = {
1029 | };
1030 | name = Debug;
1031 | };
1032 | 3AED3EE71B1DD7B400FA35FC /* Release */ = {
1033 | isa = XCBuildConfiguration;
1034 | baseConfigurationReference = 3AF6958B1ECB1B5100586DA7 /* Tests-iOS.xcconfig */;
1035 | buildSettings = {
1036 | };
1037 | name = Release;
1038 | };
1039 | /* End XCBuildConfiguration section */
1040 |
1041 | /* Begin XCConfigurationList section */
1042 | 3A2007EB1B5501BC00769021 /* Build configuration list for PBXNativeTarget "ResponseDetective-macOS" */ = {
1043 | isa = XCConfigurationList;
1044 | buildConfigurations = (
1045 | 3A2007EC1B5501BC00769021 /* Debug */,
1046 | 3A2007ED1B5501BC00769021 /* Release */,
1047 | );
1048 | defaultConfigurationIsVisible = 0;
1049 | defaultConfigurationName = Release;
1050 | };
1051 | 3A2007EE1B5501BC00769021 /* Build configuration list for PBXNativeTarget "ResponseDetective-macOS-Tests" */ = {
1052 | isa = XCConfigurationList;
1053 | buildConfigurations = (
1054 | 3A2007EF1B5501BC00769021 /* Debug */,
1055 | 3A2007F01B5501BC00769021 /* Release */,
1056 | );
1057 | defaultConfigurationIsVisible = 0;
1058 | defaultConfigurationName = Release;
1059 | };
1060 | 3AE5463B1E152DB600E74469 /* Build configuration list for PBXNativeTarget "ResponseDetective-tvOS" */ = {
1061 | isa = XCConfigurationList;
1062 | buildConfigurations = (
1063 | 3AE5463C1E152DB600E74469 /* Debug */,
1064 | 3AE5463D1E152DB600E74469 /* Release */,
1065 | );
1066 | defaultConfigurationIsVisible = 0;
1067 | defaultConfigurationName = Release;
1068 | };
1069 | 3AE5463E1E152DB600E74469 /* Build configuration list for PBXNativeTarget "ResponseDetective-tvOS-Tests" */ = {
1070 | isa = XCConfigurationList;
1071 | buildConfigurations = (
1072 | 3AE5463F1E152DB600E74469 /* Debug */,
1073 | 3AE546401E152DB600E74469 /* Release */,
1074 | );
1075 | defaultConfigurationIsVisible = 0;
1076 | defaultConfigurationName = Release;
1077 | };
1078 | 3AED3EC61B1DD7B400FA35FC /* Build configuration list for PBXProject "ResponseDetective" */ = {
1079 | isa = XCConfigurationList;
1080 | buildConfigurations = (
1081 | 3AED3EE01B1DD7B400FA35FC /* Debug */,
1082 | 3AED3EE11B1DD7B400FA35FC /* Release */,
1083 | );
1084 | defaultConfigurationIsVisible = 0;
1085 | defaultConfigurationName = Release;
1086 | };
1087 | 3AED3EE21B1DD7B400FA35FC /* Build configuration list for PBXNativeTarget "ResponseDetective-iOS" */ = {
1088 | isa = XCConfigurationList;
1089 | buildConfigurations = (
1090 | 3AED3EE31B1DD7B400FA35FC /* Debug */,
1091 | 3AED3EE41B1DD7B400FA35FC /* Release */,
1092 | );
1093 | defaultConfigurationIsVisible = 0;
1094 | defaultConfigurationName = Release;
1095 | };
1096 | 3AED3EE51B1DD7B400FA35FC /* Build configuration list for PBXNativeTarget "ResponseDetective-iOS-Tests" */ = {
1097 | isa = XCConfigurationList;
1098 | buildConfigurations = (
1099 | 3AED3EE61B1DD7B400FA35FC /* Debug */,
1100 | 3AED3EE71B1DD7B400FA35FC /* Release */,
1101 | );
1102 | defaultConfigurationIsVisible = 0;
1103 | defaultConfigurationName = Release;
1104 | };
1105 | /* End XCConfigurationList section */
1106 | };
1107 | rootObject = 3AED3EC31B1DD7B400FA35FC /* Project object */;
1108 | }
1109 |
--------------------------------------------------------------------------------