├── .github ├── ISSUE_TEMPLATE │ ├── bug.md │ ├── feature.md │ ├── question.md │ └── task.md ├── PULL_REQUEST_TEMPLATE.md ├── codecov.yml ├── config.yml ├── semantic.yml └── workflows │ ├── build.yml │ └── build_pr.yml ├── .gitignore ├── .hound.yml ├── .swiftlint.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Configurations ├── Info-iOS-Tests.plist ├── Info-iOS.plist ├── Info-macOS-Tests.plist ├── Info-macOS.plist ├── Project-Debug.xcconfig ├── Project-Release.xcconfig ├── Project-Shared.xcconfig ├── Target-iOS-Debug.xcconfig ├── Target-iOS-Release.xcconfig ├── Target-iOS-Shared.xcconfig ├── Target-iOS-Tests-Debug.xcconfig ├── Target-iOS-Tests-Release.xcconfig ├── Target-iOS-Tests-Shared.xcconfig ├── Target-macOS-Debug.xcconfig ├── Target-macOS-Release.xcconfig ├── Target-macOS-Shared.xcconfig ├── Target-macOS-Tests-Debug.xcconfig ├── Target-macOS-Tests-Release.xcconfig └── Target-macOS-Tests-Shared.xcconfig ├── Documentation ├── ADRs │ ├── ADR-001-Language_choice.md │ ├── ADR-002-Coding_standard.md │ ├── ADR-003-Organization_of_type_members.md │ ├── ADR-004-Dependencies-management.md │ └── ADR-005-Project-Structure.md ├── CORE_CONTRIBUTOR.md ├── VISION.md └── images │ ├── 04_destination_dir.png │ ├── 08_xcode_spm_search.png │ ├── 09_xcode_spm_options.png │ ├── 10_xcode_spm_add_package.png │ ├── 11_xcode_carthage_xcframework.png │ ├── 12_xcode_scheme_env_setup.png │ └── pact-swift.png ├── LICENSE.md ├── Package.resolved ├── Package.swift ├── PactSwift.xcfilelist ├── PactSwift.xcodeproj ├── project.pbxproj └── xcshareddata │ ├── IDETemplateMacros.plist │ └── xcschemes │ ├── PactSwift-iOS.xcscheme │ └── PactSwift-macOS.xcscheme ├── README.md ├── SECURITY.md ├── Scripts ├── BuildPhases │ ├── lint-project │ ├── lint-target │ ├── validate-build-settings │ └── validate-project-config ├── build_file_list_and_swiftlint ├── carthage ├── check_build_tools ├── prepare_build_tools ├── release └── run_tests ├── Sources ├── ExampleGenerators │ ├── DateTime.swift │ ├── DateTimeExpression.swift │ ├── ExampleGenerator.swift │ ├── ProviderStateGenerator.swift │ ├── RandomBool.swift │ ├── RandomDate.swift │ ├── RandomDateTime.swift │ ├── RandomDecimal.swift │ ├── RandomHexadecimal.swift │ ├── RandomInt.swift │ ├── RandomString.swift │ ├── RandomTime.swift │ └── RandomUUID.swift ├── Extensions │ ├── Bundle+PactSwift.swift │ ├── Date+PactSwift.swift │ ├── Dictionary+PactSwift.swift │ ├── MockServer+Async.swift │ ├── Sequence+PactSwift.swift │ ├── String+PactSwift.swift │ ├── Task+Timeout.swift │ └── UUID+PactSwift.swift ├── Headers │ └── PactSwift.h ├── Matchers │ ├── DecimalLike.swift │ ├── EachKeyLike.swift │ ├── EachLike.swift │ ├── EqualTo.swift │ ├── FromProviderState.swift │ ├── IncludesLike.swift │ ├── IntegerLike.swift │ ├── MatchNull.swift │ ├── Matcher.swift │ ├── OneOf.swift │ ├── RegexLike.swift │ └── SomethingLike.swift ├── MockService+Concurrency.swift ├── MockService+Extension.swift ├── MockService.swift ├── Model │ ├── AnyEncodable.swift │ ├── Constants.swift │ ├── EncodingError.swift │ ├── ErrorReportable.swift │ ├── ErrorReporter.swift │ ├── ExampleGeneratorExpressible.swift │ ├── Interaction.swift │ ├── MatchingRuleExpressible.swift │ ├── Metadata.swift │ ├── Pact.swift │ ├── PactBroker.swift │ ├── PactHTTPMethod.swift │ ├── PactInteractionElement.swift │ ├── PactInteractionNode.swift │ ├── PactPathParameter.swift │ ├── PactSwiftVersion.swift │ ├── Pacticipant.swift │ ├── ProviderState.swift │ ├── ProviderVerifier+Error.swift │ ├── ProviderVerifier+Options.swift │ ├── ProviderVerifier+Provider.swift │ ├── Request.swift │ ├── Response.swift │ ├── Toolbox.swift │ ├── TransferProtocol.swift │ ├── VersionSelector.swift │ └── WIPPacts.swift ├── PFMockService.swift ├── PactBuilder.swift ├── ProviderVerifier.swift └── Toolbox │ ├── Logger.swift │ └── PactFileManager.swift ├── Tests ├── ExampleGenerators │ ├── DateTimeExpressionTests.swift │ ├── DateTimeTests.swift │ ├── ObjCExampleGeneratorTests.swift │ ├── ProviderStateGeneratorTests.swift │ ├── RandomBooleanTests.swift │ ├── RandomDateTests.swift │ ├── RandomDateTimeTests.swift │ ├── RandomDecimalTests.swift │ ├── RandomHexadecimalTests.swift │ ├── RandomIntTests.swift │ ├── RandomStringTests.swift │ ├── RandomTimeTests.swift │ └── RandomUuidTests.swift ├── Extensions │ └── String+PactSwiftTests.swift ├── Matchers │ ├── DecimalLikeTests.swift │ ├── EachKeyLikeTests.swift │ ├── EachLikeTests.swift │ ├── EqualToTests.swift │ ├── FromProviderStateTests.swift │ ├── IncludesLikeTests.swift │ ├── IntegerLikeTests.swift │ ├── MatchNullTests.swift │ ├── ObjCMatcherTests.swift │ ├── OneOfTests.swift │ ├── RegexLikeTests.swift │ └── SomethingLikeTests.swift ├── Model │ ├── AnyEncodableTests.swift │ ├── InteractionTests.swift │ ├── MetadataTests.swift │ ├── PactBrokerTests.swift │ ├── PactBuilderTests.swift │ ├── PactHTTPMethodTests.swift │ ├── PactTests.swift │ ├── PacticipantTests.swift │ ├── ProviderVerifier+OptionsTests.swift │ ├── ToolboxTests.swift │ ├── TransferProtocolTests.swift │ ├── VersionSelectorTests.swift │ └── WIPPactsTests.swift ├── Services │ ├── AsyncMockServiceTests.swift │ ├── MockServiceTests.swift │ ├── MockServiceWithDirectoryPathTests.swift │ ├── PFMockServiceTests.swift │ ├── PactContractTests.swift │ └── ProviderVerifierTests.swift └── TestHelpers │ ├── DateHelper.swift │ ├── ErrorCapture.swift │ ├── ExampleGeneratorTestHelpers.swift │ └── MatcherTestHelpers.swift └── codecov.yml /.github/ISSUE_TEMPLATE/bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a bug report to help us improve. 4 | title: 'Bug: ...' 5 | labels: "bug" 6 | assignees: '' 7 | --- 8 | # 🌎 Environment 9 | 10 | - Xcode: [e.g. 11.4] 11 | - Platform: [e.g. iOS] 12 | - Version/Release: [e.g. 1.0.2] 13 | - Dependency manager: [e.g. Carthage 0.38] 14 | 15 | # 💬 Description 16 | 17 | 18 | 19 | # 🦶 Reproduction Steps 20 | 21 | 22 | 23 | Steps to reproduce the behavior: 24 | 1. Do this... 25 | 2. Run this `xcrun ...` 26 | 3. Etc. 27 | 28 | # 🤔 Expected Results 29 | 30 | 31 | 32 | # 😲 Actual Results 33 | 34 | 35 | 36 | ## 🌳 Logs 37 | 38 | ``` 39 | Include any logs or command output if applicable... 40 | ``` 41 | 42 | ## 📄 Stack Traces 43 | 44 | ``` 45 | Include a stack trace if applicable... 46 | ``` 47 | 48 | # 🤝 Relationships 49 | 50 | - Related PRs or Issues: #xxx, #yyy 51 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: Create a feature request to enhance the project. 4 | title: '' 5 | labels: 'enhancement' 6 | assignees: '' 7 | 8 | --- 9 | 10 | # 🗣 Context 11 | 12 | 13 | 14 | # 💬 Narrative 15 | 16 | When ... 17 | I want ... 18 | So that ... 19 | 20 | # 📝 Notes 21 | 22 | 23 | 24 | # 🏗 Design 25 | 26 | 27 | 28 | # ✅ Acceptance Criteria 29 | 30 | **GIVEN** ... 31 | **WHEN** ... 32 | **THEN** ... 33 | 34 | # 🚫 Out of Scope 35 | 36 | 37 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Just looking for some information about a thing 4 | title: 'Question: ...' 5 | labels: "question" 6 | assignees: '' 7 | --- 8 | # ❔ Question 9 | 10 | 11 | 12 | # 💬 Context 13 | 14 | 15 | 16 | 17 | # 🤝 Relationships 18 | 19 | - Other Related Issues: #xxx, #yyy 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/task.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Task 3 | about: Create a technical task that needs doing. 4 | title: 'Task: ...' 5 | labels: "task" 6 | assignees: '' 7 | --- 8 | # ❕ Problem Statement 9 | 10 | 11 | 12 | # 💬 Task Description 13 | 14 | 15 | 16 | # 👩‍🔧 Technical Design Notes 17 | 18 | 19 | 20 | # 🤝 Relationships 21 | 22 | - Other Related Issues: #xxx, #yyy 23 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | - ☝️ Provide a short but descriptive title for this PR. 2 | - 🏷 Remember to label your pull request appropriately and select appropriate code reviewers. 3 | 4 | _Provide a more descriptive summary of the changes in this PR here._ 5 | 6 | # 📝 Summary of Changes 7 | 8 | Changes proposed in this pull request: 9 | 10 | - Resolves issue #99999 by doing the thing with another thing 11 | - Add more details here... 12 | - ... 13 | 14 | # ⚠️ Items of Note 15 | 16 | _Document anything here that you think the reviewer(s) of this PR may need to know, or would be of specific interest._ 17 | 18 | # 🧐🗒 Reviewer Notes 19 | 20 | ## 💁 Example 21 | 22 | _Add an example of using the changes you've implemented (eg, a screenshot or text dump of the output)._ 23 | 24 | ## 🔨 How To Test 25 | 26 | _Provide instructions on how to test your changes._ -------------------------------------------------------------------------------- /.github/codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | notify: 3 | require_ci_to_pass: yes 4 | 5 | coverage: 6 | precision: 2 7 | round: down 8 | range: "70...90" 9 | 10 | status: 11 | project: yes 12 | patch: yes 13 | changes: no 14 | 15 | ignore: 16 | - "Tests/**" 17 | 18 | parsers: 19 | gcov: 20 | branch_detection: 21 | conditional: yes 22 | loop: yes 23 | method: no 24 | macro: no 25 | 26 | comment: 27 | layout: "header, diff" 28 | behavior: default 29 | require_changes: no 30 | -------------------------------------------------------------------------------- /.github/config.yml: -------------------------------------------------------------------------------- 1 | updateDocsWhiteList: 2 | - BUG 3 | - Chore 4 | - minor 5 | 6 | updateDocsComment: > 7 | Thanks for opening this pull request! The maintainers of this repository would appreciate it if you would update some of our documentation based on your changes. 8 | requestInfoReplyComment: > 9 | We would appreciate it if you could provide us with more info about this issue/pr! 10 | requestInfoLabelToAdd: request-more-info 11 | 12 | newPRWelcomeComment: > 13 | :tada: Thanks so much for opening your first PR in this project! We really do appreciate your help! :heart: 14 | firstPRMergeComment: > 15 | Congrats on merging your first pull request in this project! :tada: You're awesome! :metal: 16 | newIssueWelcomeComment: > 17 | Thanks for opening this issue, a maintainer will get back to you shortly! cc/ @surpher 18 | sentimentBotToxicityThreshold: .7 19 | 20 | sentimentBotReplyComment: > 21 | Please be sure to review the code of conduct and be respectful of other users. cc/ @surpher 22 | lockThreads: 23 | toxicityThreshold: .7 24 | numComments: 2 25 | setTimeInHours: 72 26 | replyComment: > 27 | This thread is being locked due to exceeding the toxicity minimums. cc/ @surpher 28 | -------------------------------------------------------------------------------- /.github/semantic.yml: -------------------------------------------------------------------------------- 1 | # Always validate the PR title and commits (this is important because release notes are automated and we rely on semantic commit titles) 2 | titleAndCommits: true 3 | 4 | # By default types specified in commitizen/conventional-commit-types is used. 5 | # See: https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json 6 | # You can override the valid types 7 | types: 8 | - feat 9 | - feature 10 | - fix 11 | - docs 12 | - style 13 | - refactor 14 | - perf 15 | - test 16 | - build 17 | - ci 18 | - chore 19 | - revert 20 | - tech 21 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | pull_request: 5 | types: 6 | - opened 7 | - synchronize 8 | - reopened 9 | - ready_for_review 10 | workflow_dispatch: 11 | 12 | env: 13 | RUST_TARGET_PATH: pact-reference 14 | 15 | jobs: 16 | test_ios: 17 | name: "🤖 Test iOS" 18 | runs-on: ${{ matrix.host }} 19 | 20 | strategy: 21 | fail-fast: true 22 | matrix: 23 | host: [macos-13, macos-14] 24 | platform: [ios, macos] 25 | include: 26 | - platform: ios 27 | scheme: "PactSwift-iOS" 28 | destination: "platform=iOS Simulator,name=iPhone 15 Pro" 29 | - platform: macos 30 | scheme: "PactSwift-macOS" 31 | destination: "arch=x86_64" 32 | - host: macos-13 33 | xcode: 14.3.1 34 | - host: macos-14 35 | xcode: 15.3 36 | 37 | env: 38 | SCHEME: "PactSwift-iOS" 39 | DESTINATION: ${{ matrix.destination }} 40 | 41 | concurrency: 42 | group: test_${{ matrix.host }}_${{ matrix.xcode }}_iOS_${{ github.ref }} 43 | cancel-in-progress: true 44 | 45 | steps: 46 | - name: "🧑‍💻 Checkout repository" 47 | uses: actions/checkout@v3 48 | 49 | - name: "🏭 Use Xcode ${{ matrix.xcode }}" 50 | run: sudo xcode-select -switch /Applications/Xcode_${{ matrix.xcode }}.app 51 | 52 | - name: "🧪 Run tests (xcodebuild)" 53 | run: | 54 | set -o pipefail && \ 55 | xcodebuild -resolvePackageDependencies && \ 56 | xcodebuild test \ 57 | -project PactSwift.xcodeproj \ 58 | -scheme "$SCHEME"\ 59 | -destination "$DESTINATION" \ 60 | | xcbeautify 61 | 62 | # - name: "⚗️ Run tests (swift)" 63 | # run: | 64 | # swift build 65 | # swift test -c release 66 | -------------------------------------------------------------------------------- /.github/workflows/build_pr.yml: -------------------------------------------------------------------------------- 1 | name: Build Pull Request 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - '!main' 7 | 8 | jobs: 9 | test_macos: 10 | name: "🤖 Test macOS" 11 | runs-on: macos-13 12 | 13 | env: 14 | XCODE_VERSION: 14.3.1 15 | 16 | concurrency: 17 | group: test_macos13_darwin_$SCHEME_${{ github.ref }} 18 | cancel-in-progress: true 19 | 20 | steps: 21 | - name: "🧑‍💻 Checkout repository" 22 | uses: actions/checkout@v3 23 | 24 | - name: "⚙️ Use Xcode ${{ env.XCODE_VERSION }}" 25 | run: sudo xcode-select -switch /Applications/Xcode_${{ env.XCODE_VERSION }}.app 26 | 27 | - name: "🧰 Prepare tools" 28 | run: | 29 | Scripts/prepare_build_tools 30 | 31 | - name: "🧪 xcodebuild clean test" 32 | run: | 33 | set -o pipefail && xcodebuild -resolvePackageDependencies | xcbeautify && xcodebuild clean test -project PactSwift.xcodeproj -scheme "PactSwift-macOS" -destination "arch=x86_64" | xcbeautify 34 | 35 | - name: "⚗️ swift test" 36 | run: | 37 | set -o pipefail && swift test -c release 38 | 39 | test_ios: 40 | name: "🤖 Test iOS" 41 | runs-on: macos-13 42 | needs: [test_macos] 43 | 44 | env: 45 | SCHEME: "PactSwift-iOS" 46 | DESTINATION: "platform=iOS Simulator,name=iPhone 14 Pro" 47 | XCODE_VERSION: 14.3.1 48 | 49 | concurrency: 50 | group: test_macos13_ios_$SCHEME_${{ github.ref }} 51 | cancel-in-progress: true 52 | 53 | steps: 54 | - name: "🧑‍💻 Checkout repository" 55 | uses: actions/checkout@v3 56 | 57 | - name: "⚙️ Use Xcode ${{ env.XCODE_VERSION }}" 58 | run: sudo xcode-select -switch /Applications/Xcode_${{ env.XCODE_VERSION }}.app 59 | 60 | - name: "🧰 Prepare tools" 61 | run: | 62 | Scripts/prepare_build_tools 63 | 64 | - name: "♘ Test for Carthage" 65 | run: | 66 | set -o pipefail && carthage build --no-skip-current --use-xcframeworks 67 | 68 | - name: "🧪 xcodebuild clean test" 69 | run: | 70 | set -o pipefail && xcodebuild -resolvePackageDependencies | xcbeautify && xcodebuild clean test -project PactSwift.xcodeproj -scheme "PactSwift-iOS" -destination "platform=iOS Simulator,name=iPhone 14 Pro" | xcbeautify 71 | 72 | - name: "⚗️ swift test" 73 | run: | 74 | swift test -c release 75 | 76 | after_success: 77 | needs: [test_ios] 78 | name: "🚚 Build demo projects" 79 | if: github.ref == 'refs/heads/main' 80 | runs-on: ubuntu-latest 81 | 82 | steps: 83 | - name: "🚚 Build demo projects" 84 | run: | 85 | curl -X POST https://api.github.com/repos/surpher/pact-swift-examples/dispatches -H 'Accept: application/vnd.github.everest-preview+json' -u ${{ secrets.PACT_SWIFT_TOKEN }} --data '{"event_type":"PactSwift - ${{ github.event.head_commit.message }}"}' 86 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### macOS ### 2 | # General 3 | .DS_Store 4 | .AppleDouble 5 | .LSOverride 6 | 7 | # Icon must end with two \r 8 | Icon 9 | 10 | # Thumbnails 11 | ._* 12 | 13 | # Files that might appear in the root of a volume 14 | .DocumentRevisions-V100 15 | .fseventsd 16 | .Spotlight-V100 17 | .TemporaryItems 18 | .Trashes 19 | .VolumeIcon.icns 20 | .com.apple.timemachine.donotpresent 21 | 22 | # Directories potentially created on remote AFP share 23 | .AppleDB 24 | .AppleDesktop 25 | Network Trash Folder 26 | Temporary Items 27 | .apdisk 28 | 29 | ### Xcode ### 30 | # Xcode 31 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 32 | 33 | ## User settings 34 | 35 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 36 | 37 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 38 | 39 | ## Xcode Patch 40 | *.xcodeproj/* 41 | !*.xcodeproj/project.pbxproj 42 | !*.xcodeproj/xcshareddata/ 43 | !*.xcworkspace/contents.xcworkspacedata 44 | /*.gcno 45 | 46 | ### Xcode Patch ### 47 | **/xcshareddata/WorkspaceSettings.xcsettings 48 | 49 | ### Swift ### 50 | # Xcode 51 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 52 | 53 | ## Build generated 54 | build/ 55 | DerivedData/ 56 | tmp/ 57 | 58 | ## Various settings 59 | *.pbxuser 60 | !default.pbxuser 61 | *.mode1v3 62 | !default.mode1v3 63 | *.mode2v3 64 | !default.mode2v3 65 | *.perspectivev3 66 | !default.perspectivev3 67 | xcuserdata/ 68 | 69 | ## Other 70 | *.moved-aside 71 | *.xccheckout 72 | *.xcscmblueprint 73 | 74 | ## Obj-C/Swift specific 75 | *.hmap 76 | *.ipa 77 | *.dSYM.zip 78 | *.dSYM 79 | 80 | ## Playgrounds 81 | timeline.xctimeline 82 | playground.xcworkspace 83 | 84 | ###################### 85 | ## Package managers ## 86 | ###################### 87 | 88 | ### SwiftPackageManager ### 89 | 90 | Packages/ 91 | .build/ 92 | 93 | # Add this line if you want to avoid checking in Xcode SPM integration. 94 | # .swiftpm/xcode 95 | 96 | ### Carthage ### 97 | # Carthage 98 | # 99 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 100 | # Carthage/Checkouts 101 | 102 | Carthage/ 103 | .swiftpm* 104 | 105 | ################### 106 | ## Binaries ## 107 | ################### 108 | *.a 109 | -------------------------------------------------------------------------------- /.hound.yml: -------------------------------------------------------------------------------- 1 | swiftlint: 2 | config_file: .swiftlint.yml 3 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | disabled_rules: 2 | - force_cast 3 | - identifier_name 4 | - large_tuple 5 | - operator_whitespace 6 | - unused_declaration 7 | - unused_import 8 | 9 | opt_in_rules: 10 | - closure_body_length 11 | - closure_end_indentation 12 | - closure_parameter_position 13 | - closure_spacing 14 | - collection_alignment 15 | - contains_over_filter_count 16 | - contains_over_filter_is_empty 17 | - contains_over_first_not_nil 18 | - contains_over_range_nil_comparison 19 | - convenience_type 20 | - discouraged_object_literal 21 | - empty_collection_literal 22 | - empty_count 23 | - empty_string 24 | - empty_xctest_method 25 | - explicit_init 26 | - first_where 27 | - flatmap_over_map_reduce 28 | - identical_operands 29 | - implicit_return 30 | - joined_default_parameter 31 | - last_where 32 | - legacy_multiple 33 | - legacy_random 34 | - literal_expression_end_indentation 35 | - lower_acl_than_parent 36 | - modifier_order 37 | - number_separator 38 | - operator_usage_whitespace 39 | - overridden_super_call 40 | - override_in_extension 41 | - private_action 42 | - prohibited_super_call 43 | - reduce_into 44 | - redundant_nil_coalescing 45 | - redundant_type_annotation 46 | - sorted_first_last 47 | - sorted_imports 48 | - static_operator 49 | - toggle_bool 50 | - trailing_whitespace 51 | - unneeded_parentheses_in_closure_argument 52 | - yoda_condition 53 | - xct_specific_matcher 54 | 55 | analyzer_rules: 56 | - unused_declaration 57 | - unused_import 58 | 59 | line_length: 60 | warning: 180 61 | ignores_function_declarations: true 62 | ignores_comments: false 63 | 64 | modifier_order: 65 | preferred_modifier_order: [acl, override] 66 | 67 | nesting: 68 | type_level: 2 69 | 70 | included: 71 | - Sources 72 | 73 | excluded: 74 | - Carthage 75 | - Tests 76 | 77 | trailing_comma: 78 | mandatory_comma: true 79 | -------------------------------------------------------------------------------- /Configurations/Info-iOS-Tests.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Configurations/Info-iOS.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSHumanReadableCopyright 22 | Copyright © 2020-2021 Marko Justinek. All rights reserved. 23 | 24 | 25 | -------------------------------------------------------------------------------- /Configurations/Info-macOS-Tests.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Configurations/Info-macOS.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | NSHumanReadableCopyright 22 | Copyright © 2020-2021 Marko Justinek. All rights reserved. 23 | 24 | 25 | -------------------------------------------------------------------------------- /Configurations/Project-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Configurations/Project-Shared.xcconfig" 2 | 3 | ONLY_ACTIVE_ARCH = YES 4 | DEBUG_INFORMATION_FORMAT = dwarf 5 | ENABLE_TESTABILITY = YES 6 | 7 | GCC_DYNAMIC_NO_PIC = NO 8 | GCC_OPTIMIZATION_LEVEL = 0 9 | GCC_PREPROCESSOR_DEFINITIONS = DEBUG=1 $(inherited) 10 | 11 | SWIFT_OPTIMIZATION_LEVEL = -Onone 12 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG 13 | 14 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE 15 | -------------------------------------------------------------------------------- /Configurations/Project-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Configurations/Project-Shared.xcconfig" 2 | 3 | DEBUG_INFORMATION_FORMAT = dwarf-with-dsym 4 | VALIDATE_PRODUCT = YES 5 | 6 | ENABLE_NS_ASSERTIONS = NO 7 | 8 | MTL_ENABLE_DEBUG_INFO = NO 9 | 10 | SWIFT_OPTIMIZATION_LEVEL = -O 11 | SWIFT_COMPILATION_MODE = wholemodule 12 | -------------------------------------------------------------------------------- /Configurations/Project-Shared.xcconfig: -------------------------------------------------------------------------------- 1 | // !!! WARNING: NEXT LINE IS AUTOMATED - DO NOT CHANGE OR MOVE !!! 2 | MARKETING_VERSION = 1.1.0 3 | 4 | CURRENT_PROJECT_VERSION = 1 5 | VERSIONING_SYSTEM = apple-generic 6 | 7 | SWIFT_VERSION = 5.0 8 | 9 | COPY_PHASE_STRIP = NO 10 | 11 | ALWAYS_SEARCH_USER_PATHS = NO 12 | ENABLE_STRICT_OBJC_MSGSEND = YES 13 | 14 | BUILD_LIBRARY_FOR_DISTRIBUTION = YES 15 | 16 | // GCC 17 | 18 | GCC_NO_COMMON_BLOCKS = YES 19 | GCC_C_LANGUAGE_STANDARD = gnu11 20 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES 21 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR 22 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE 23 | GCC_WARN_UNUSED_FUNCTION = YES 24 | GCC_WARN_UNUSED_VARIABLE = YES 25 | GCC_WARN_UNDECLARED_SELECTOR = YES 26 | 27 | MTL_FAST_MATH = YES 28 | 29 | CLANG_CXX_LANGUAGE_STANDARD = gnu++14 30 | CLANG_CXX_LIBRARY = libc++ 31 | CLANG_ENABLE_MODULES = YES 32 | CLANG_ENABLE_OBJC_ARC = YES 33 | CLANG_ENABLE_OBJC_WEAK = YES 34 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES 35 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES 36 | CLANG_WARN_EMPTY_BODY = YES 37 | CLANG_WARN_BOOL_CONVERSION = YES 38 | CLANG_WARN_CONSTANT_CONVERSION = YES 39 | CLANG_WARN_ENUM_CONVERSION = YES 40 | CLANG_WARN_INT_CONVERSION = YES 41 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES 42 | CLANG_WARN_INFINITE_RECURSION = YES 43 | CLANG_WARN_STRICT_PROTOTYPES = YES 44 | CLANG_WARN_COMMA = YES 45 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE 46 | CLANG_WARN_UNREACHABLE_CODE = YES 47 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES 48 | CLANG_WARN_SUSPICIOUS_MOVE = YES 49 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR 50 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES 51 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES 52 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES 53 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR 54 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES 55 | CLANG_ANALYZER_NONNULL = YES 56 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE 57 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES 58 | 59 | // Xcode 14 60 | 61 | DEAD_CODE_STRIPPING = YES 62 | -------------------------------------------------------------------------------- /Configurations/Target-iOS-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Configurations/Target-iOS-Shared.xcconfig" 2 | 3 | SWIFT_OPTIMIZATION_LEVEL = -Onone 4 | -------------------------------------------------------------------------------- /Configurations/Target-iOS-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Configurations/Target-iOS-Shared.xcconfig" 2 | -------------------------------------------------------------------------------- /Configurations/Target-iOS-Shared.xcconfig: -------------------------------------------------------------------------------- 1 | PRODUCT_NAME = PactSwift 2 | 3 | IPHONEOS_DEPLOYMENT_TARGET = 12.0 4 | SDKROOT = iphoneos 5 | INSTALL_PATH = $(LOCAL_LIBRARY_DIR)/Frameworks 6 | SKIP_INSTALL = YES 7 | TARGETED_DEVICE_FAMILY = 1,2 8 | SUPPORTS_MACCATALYST = NO 9 | BUNDLE_VERSION_STRING_SHORT = $(MARKETING_VERSION) 10 | 11 | DYLIB_COMPATIBILITY_VERSION = 1 12 | DYLIB_CURRENT_VERSION = 1 13 | DYLIB_INSTALL_NAME_BASE = @rpath 14 | 15 | INFOPLIST_FILE = Configurations/Info-iOS.plist 16 | PRODUCT_BUNDLE_IDENTIFIER = au.com.pact-foundation.iOS.PactSwift 17 | LIBRARY_SEARCH_PATHS = $(inherited) $(PLATFORM_DIR)/Developer/usr/lib 18 | LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks 19 | FRAMEWORK_SEARCH_PATHS = $(inherited) 20 | HEADER_SEARCH_PATHS = $(PROJECT_DIR)/Sources/Headers 21 | 22 | OTHER_LDFLAGS = -weak_framework XCTEST -weak-lXCTestSwiftSupport 23 | 24 | DEFINES_MODULE = YES 25 | CODE_SIGN_STYLE = Automatic 26 | CLANG_ENABLE_MODULES = YES 27 | ENABLE_BITCODE = NO 28 | ENABLE_TESTING_SEARCH_PATHS = YES 29 | 30 | CODE_SIGN_IDENTITY = 31 | ENABLE_MODULE_VERIFIER = YES 32 | MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = gnu11 gnu++14 33 | MODULE_VERIFIER_SUPPORTED_LANGUAGES = objective-c objective-c++ 34 | -------------------------------------------------------------------------------- /Configurations/Target-iOS-Tests-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Configurations/Target-iOS-Tests-Shared.xcconfig" 2 | -------------------------------------------------------------------------------- /Configurations/Target-iOS-Tests-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Configurations/Target-iOS-Tests-Shared.xcconfig" 2 | -------------------------------------------------------------------------------- /Configurations/Target-iOS-Tests-Shared.xcconfig: -------------------------------------------------------------------------------- 1 | SDKROOT = iphoneos 2 | PRODUCT_NAME = $(TARGET_NAME) 3 | TARGETED_DEVICE_FAMILY = 1,2 4 | IPHONEOS_DEPLOYMENT_TARGET = 12.0 5 | 6 | INFOPLIST_FILE = Configurations/Info-iOS-Tests.plist 7 | PRODUCT_BUNDLE_IDENTIFIER = au.com.pact-foundation.PactSwiftTests 8 | CODE_SIGN_IDENTITY[sdk=macosx*] = - 9 | 10 | LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks 11 | -------------------------------------------------------------------------------- /Configurations/Target-macOS-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Configurations/Target-macOS-Shared.xcconfig" 2 | ONLY_ACTIVE_ARCH = YES 3 | 4 | DEBUG_INFORMATION_FORMAT = dwarf 5 | ENABLE_TESTABILITY = YES 6 | 7 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE 8 | -------------------------------------------------------------------------------- /Configurations/Target-macOS-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Configurations/Target-macOS-Shared.xcconfig" 2 | 3 | DEBUG_INFORMATION_FORMAT = dwarf-with-dsym 4 | ENABLE_NS_ASSERTIONS = NO 5 | 6 | SWIFT_COMPILATION_MODE = wholemodule 7 | SWIFT_OPTIMIZATION_LEVEL = -O 8 | MTL_ENABLE_DEBUG_INFO = NO 9 | -------------------------------------------------------------------------------- /Configurations/Target-macOS-Shared.xcconfig: -------------------------------------------------------------------------------- 1 | PRODUCT_NAME = PactSwift 2 | 3 | ONLY_ACTIVE_ARCH = NO 4 | 5 | SDKROOT = macosx 6 | MACOSX_DEPLOYMENT_TARGET = 10.15 7 | CODE_SIGN_STYLE = Automatic 8 | 9 | DEFINES_MODULE = YES 10 | COMBINE_HIDPI_IMAGES = YES 11 | INSTALL_PATH = $(LOCAL_LIBRARY_DIR)/Frameworks 12 | SKIP_INSTALL = YES 13 | 14 | INFOPLIST_FILE = Configurations/Info-macOS.plist 15 | PRODUCT_BUNDLE_IDENTIFIER = au.com.pact-foundation.macOS.PactSwift 16 | DYLIB_INSTALL_NAME_BASE = @rpath 17 | LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks 18 | LIBRARY_SEARCH_PATHS = $(inherited) $(PLATFORM_DIR)/Developer/usr/lib 19 | FRAMEWORK_SEARCH_PATHS = $(inherited) 20 | 21 | OTHER_LDFLAGS = -weak_framework XCTEST -weak-lXCTestSwiftSupport 22 | 23 | DYLIB_COMPATIBILITY_VERSION = 1 24 | DYLIB_CURRENT_VERSION = 1 25 | ALWAYS_SEARCH_USER_PATHS = NO 26 | VERSION_INFO_PREFIX = 27 | COPY_PHASE_STRIP = NO 28 | 29 | GCC_DYNAMIC_NO_PIC = NO 30 | GCC_OPTIMIZATION_LEVEL = 0 31 | GCC_PREPROCESSOR_DEFINITIONS = DEBUG=1 $(inherited) 32 | 33 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG 34 | SWIFT_OPTIMIZATION_LEVEL = -Onone 35 | 36 | ENABLE_TESTING_SEARCH_PATHS = YES 37 | 38 | DEAD_CODE_STRIPPING = YES 39 | 40 | ENABLE_MODULE_VERIFIER = YES 41 | MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = gnu11 gnu++14 42 | MODULE_VERIFIER_SUPPORTED_LANGUAGES = objective-c objective-c++ 43 | -------------------------------------------------------------------------------- /Configurations/Target-macOS-Tests-Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Configurations/Target-macOS-Tests-Shared.xcconfig" 2 | 3 | ONLY_ACTIVE_ARCH = YES 4 | ENABLE_TESTABILITY = YES 5 | GCC_OPTIMIZATION_LEVEL = 0 6 | GCC_DYNAMIC_NO_PIC = NO 7 | GCC_PREPROCESSOR_DEFINITIONS = DEBUG=1 $(inherited) 8 | SWIFT_OPTIMIZATION_LEVEL = -Onone 9 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG 10 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE 11 | DEBUG_INFORMATION_FORMAT = dwarf-with-dsym 12 | -------------------------------------------------------------------------------- /Configurations/Target-macOS-Tests-Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Configurations/Target-macOS-Tests-Shared.xcconfig" 2 | SWIFT_OPTIMIZATION_LEVEL = -O 3 | ENABLE_NS_ASSERTIONS = NO 4 | MTL_ENABLE_DEBUG_INFO = NO 5 | SWIFT_COMPILATION_MODE = wholemodule 6 | -------------------------------------------------------------------------------- /Configurations/Target-macOS-Tests-Shared.xcconfig: -------------------------------------------------------------------------------- 1 | //:configuration = Debug 2 | SDKROOT = macosx 3 | MACOSX_DEPLOYMENT_TARGET = 11.0 4 | 5 | CODE_SIGN_STYLE = Automatic 6 | COMBINE_HIDPI_IMAGES = YES 7 | 8 | INFOPLIST_FILE = Configurations/Info-macOS-Tests.plist 9 | LD_RUNPATH_SEARCH_PATHS = $(inherited) @executable_path/Frameworks @loader_path/Frameworks 10 | 11 | PRODUCT_BUNDLE_IDENTIFIER = au.com.pact-foundation.macOS.PactSwift-Tests 12 | PRODUCT_NAME = $(TARGET_NAME) 13 | 14 | MTL_FAST_MATH = YES 15 | 16 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES 17 | 18 | DEAD_CODE_STRIPPING = YES 19 | -------------------------------------------------------------------------------- /Documentation/ADRs/ADR-001-Language_choice.md: -------------------------------------------------------------------------------- 1 | # Context 2 | 3 | iOS applications can be written in Objective-C or Swift. Objective-C offers greater interaction with C++ code but is considered a legacy language choice in the iOS developer community. The `pact-consumer-swift` framework was built to support Objective-C as well, but it's proven to become a bigger challenge supporting both with newer Xcode and Swift versions. 4 | 5 | # Decision 6 | 7 | The framework is written in Swift. 8 | 9 | # Consequences 10 | -------------------------------------------------------------------------------- /Documentation/ADRs/ADR-003-Organization_of_type_members.md: -------------------------------------------------------------------------------- 1 | # Context 2 | 3 | For legibility and discoverability, it is helpful to have a clear ordering of members within each type. Criteria which factor into this include: 4 | 5 | 1. Member kind (property, method, subtype) 6 | 2. Access (public/internal/private) 7 | 3. Nature of member (stored or computed property, override or unique method) 8 | 9 | There are different approaches to how these should be prioritized in C++/Objective-C, whether you're focussing on the needs of the type's consumer or implementer and which slices of behavior you most want to separate. 10 | 11 | # Decision 12 | 13 | Where possible, members should be organized as follows: 14 | 15 | ``` 16 | class MyClass: BaseClass { 17 | 18 | // MARK: - Constants 19 | 20 | public static let valueA = 1 21 | private static let valueB = 2 22 | 23 | // MARK: - Types 24 | 25 | public struct SubTypeA {} 26 | private struct SubTypeB {} 27 | 28 | // MARK: - Stored Properties 29 | 30 | public var propertyA = 1 31 | private var propertyB = 2 32 | 33 | // MARK: - Computed Properties 34 | 35 | public var propertyC: Int { return propertyA * 3 } 36 | private var propertyD: Int { return propertyB * 4 } 37 | 38 | // MARK: - Constructors 39 | 40 | public init() {} 41 | private init(param: Int) {} 42 | 43 | // MARK: - Methods 44 | 45 | public static func k() {} 46 | 47 | public func f() {} 48 | private func g() {} 49 | 50 | private static func h() {} 51 | 52 | // MARK: - BaseClass overrides 53 | 54 | public override var propertyL: Int { return propertyA * 3 } 55 | public override func base() {} 56 | 57 | } 58 | 59 | extension MyClass: SomeComformance { 60 | 61 | public var i: Int { return 0 } 62 | 63 | public func j() {} 64 | 65 | } 66 | ``` 67 | 68 | Important points to note: 69 | 70 | 1. public before private 71 | 2. static lifetimes before properties before methods 72 | 3. stored properties before computed properties 73 | 4. constructors before other methods 74 | 5. overrides grouped based on the class they override 75 | 6. protocol conformances in separate extensions (unless auto-synthesis is involved) 76 | 77 | In most cases, these sections will not all be present... don't use a heading for a section not included 78 | 79 | # Consequences 80 | 81 | There are a couple points that aren't totally decided. 82 | 83 | They do not *need* to have "mark" headings and when they do, provided the contents themselves are organized, a simple "Properties" or "Methods" is sufficient to cover all methods or properties (e.g. doesn't need to be broken into "Stored" and "Computed"). 84 | 85 | However, overrides sections should have a heading indicating which class' methods they override, otherwise its purpose is difficult to understand. 86 | 87 | Static methods are all in one section with the other methods, with public static first and private static last (after all non-static methods). However: 88 | 89 | 1. Most public static functions are constructors and should go in the constructor section (probably ahead of init functions) 90 | 2. Many private static functions are called from just one location, lifted out for purely syntactic reasons. Sometimes these might appear alongside the function they're lifted out-of, sometimes they might appear at the end of the file since they're mostly an implementation detail that can be ignored. 91 | 92 | There's a little flexibility here and when reviewing PR's suggestions and requests for improvement may be made prior to approving a PR. 93 | -------------------------------------------------------------------------------- /Documentation/ADRs/ADR-004-Dependencies-management.md: -------------------------------------------------------------------------------- 1 | # Context 2 | 3 | Almost all software we write depends on some other code, library or development tool which allows us to build what we want faster. Although this project attempts to avoid bringing in 3rd party dependencies, there are is functionality already written that is critical to this projects success. 4 | 5 | # Decision 6 | 7 | The main dependency is the programmable in-process mock server that can receive network requests and respond with the response we define. This dependency is written in rust and is available at [pact-foundation/pact-reference/rust](https://github.com/pact-foundation/pact-reference/tree/main/rust/pact_mock_server_ffi). 8 | 9 | The binary framework(s) that are built using `cargo lipo --release` command are added into the Xcode project. 10 | 11 | Unfortunately SPM doesn't handle the binary dependencies well at the time of this writing. Therefore a SPM package is required 12 | 13 | There will be a separation of responsibilities between PactSwift framework and PactSwiftServices in a separate (yet embedded) project which will provide extra functionality by reaching out to and/or interact with different services (interacting with Pact Mock Server, etc.). 14 | 15 | Matt's [CwlPreconditionTesting](https://github.com/mattgallagher/CwlPreconditionTesting) is a dependency this project can't really exist without. To support distributon of PactSwift using both Carthage and SPM, the dependency CwlPreconditionTesting is brougt into the PactSwiftServices project (files `./Carthage/Checkouts/CwlPreconditionTesting/*` added into the project itself). For SPM it is defined as a dependency in `./PactSwiftServices/Package.swift`. 16 | 17 | # Consequences 18 | 19 | Due to SPM not handling binary dependencies well. When linking and embedding a binary framework while building and running in Xcode everything works fine, `xcodebuild` command in command line builds the project and dependencies just fine. 20 | 21 | Yet, when running `swift build` in terminal, SPM doesn't know where to find it. That's why a separate SPM package to provide the binary framework as a dependency is required and unfortunately the binary framework is duplicated in the codebase - once in `PactSwiftServices` project and once in `PactMockServer` swift package. 22 | 23 | # Follow-up (September 30, 2020) 24 | 25 | All 3rd party dependencies have been successfully removed from this project/framework. 26 | -------------------------------------------------------------------------------- /Documentation/CORE_CONTRIBUTOR.md: -------------------------------------------------------------------------------- 1 | # _PactSwift_ Core Contributor Expectations 2 | 3 | We are always looking for active, enthusiastic members of the developer community to become core contributors. 4 | 5 | We hope to harness the diversity of the iOS/macOS Developer community to build the _PactSwift_ into an essential tool for developers. 6 | 7 | ## How does one become a Core Contributor? 8 | 9 | Contributors who have displayed lasting commitment to the evolution and maintenance of this project will be invited to become Core Contributors. For instance, contributors who: 10 | 11 | - Love to help out other users with issues on GitHub 12 | - Continue to make _PactSwift_ a stable product and encourage features aligned with our [vision][vision]. 13 | 14 | ## Core Contributors 15 | 16 | - Review pull requests using the "Review Changes" feature in GitHub. 17 | - Merge pull requests we review, except for PRs where the author has push access. 18 | - Respond to issues and help others. 19 | - Own regressions caused by our own contributions and PR approvals. 20 | - Maintain consistent coding standards. 21 | - Inform other Core Contributors when critical fixes are merged so a release can be prepared. 22 | - Identify other community members who would be effective Core Contributors. 23 | - Ensure that new contributions fit into the [Vision][vision]. 24 | - Adhere to the [Code of Conduct][code-of-conduct]. 25 | - Keep external dependencies to a minimum. 26 | - Keep test coverage high and ensure up-to-date documentation. 27 | - Are polite, friendly and having fun contributing. 28 | 29 | ## Pull Request Ownership 30 | 31 | We work in a high-trust environment which implies that anyone and everyone is able to merge pull requests from the community. If the PR reviewer feels strongly about seeing a PR to completion, they should assign it to themselves and request necessary changes. 32 | 33 | ## Adding Dependencies 34 | 35 | We want to keep _PactSwift_ focused and robust. Avoid adding new dependencies to the code base unless absolutely necessary. 36 | 37 | [vision]: VISION.md 38 | [code-of-conduct]: ../CODE_OF_CONDUCT.md -------------------------------------------------------------------------------- /Documentation/VISION.md: -------------------------------------------------------------------------------- 1 | # Our Vision 2 | 3 | _PactSwift_ automates the process of generating Pact contracts. 4 | 5 | _PactSwift_ provides a simple and easy to use framework in one's Swift or Objective-C project that creates workflows where Pact contracts are generated. 6 | 7 | _PactSwift_ will continue to evolve, in a measured way that extends its functionality to make it an indespensable tool for developers writing [Consumer Driven contracts][consumer-driven-contracts]. 8 | 9 | [consumer-driven-contracts]: https://martinfowler.com/articles/consumerDrivenContracts.html 10 | -------------------------------------------------------------------------------- /Documentation/images/04_destination_dir.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/surpher/PactSwift/0746420a5ea9198294916e86db3c305cb5c0f169/Documentation/images/04_destination_dir.png -------------------------------------------------------------------------------- /Documentation/images/08_xcode_spm_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/surpher/PactSwift/0746420a5ea9198294916e86db3c305cb5c0f169/Documentation/images/08_xcode_spm_search.png -------------------------------------------------------------------------------- /Documentation/images/09_xcode_spm_options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/surpher/PactSwift/0746420a5ea9198294916e86db3c305cb5c0f169/Documentation/images/09_xcode_spm_options.png -------------------------------------------------------------------------------- /Documentation/images/10_xcode_spm_add_package.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/surpher/PactSwift/0746420a5ea9198294916e86db3c305cb5c0f169/Documentation/images/10_xcode_spm_add_package.png -------------------------------------------------------------------------------- /Documentation/images/11_xcode_carthage_xcframework.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/surpher/PactSwift/0746420a5ea9198294916e86db3c305cb5c0f169/Documentation/images/11_xcode_carthage_xcframework.png -------------------------------------------------------------------------------- /Documentation/images/12_xcode_scheme_env_setup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/surpher/PactSwift/0746420a5ea9198294916e86db3c305cb5c0f169/Documentation/images/12_xcode_scheme_env_setup.png -------------------------------------------------------------------------------- /Documentation/images/pact-swift.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/surpher/PactSwift/0746420a5ea9198294916e86db3c305cb5c0f169/Documentation/images/pact-swift.png -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Marko Justinek 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. -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "PactSwiftMockServer", 6 | "repositoryURL": "https://github.com/surpher/PactSwiftServer.git", 7 | "state": { 8 | "branch": null, 9 | "revision": "12ecc92092ecd3640dcc2dcb98ce6b3d1f2d76f7", 10 | "version": "0.4.7" 11 | } 12 | } 13 | ] 14 | }, 15 | "version": 1 16 | } 17 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "PactSwift", 7 | 8 | platforms: [ 9 | .macOS(.v10_13), 10 | .iOS(.v12), 11 | .tvOS(.v12) 12 | ], 13 | 14 | products: [ 15 | .library( 16 | name: "PactSwift", 17 | targets: ["PactSwift"] 18 | ) 19 | ], 20 | 21 | dependencies: [ 22 | .package(url: "https://github.com/surpher/PactSwiftServer.git", .exact("0.4.7")) 23 | ], 24 | 25 | targets: [ 26 | 27 | // PactSwift 28 | .target( 29 | name: "PactSwift", 30 | dependencies: [ 31 | .product(name: "PactSwiftMockServer", package: "PactSwiftServer"), 32 | ], 33 | path: "./Sources" 34 | ), 35 | 36 | // Tests 37 | .testTarget( 38 | name: "PactSwiftTests", 39 | dependencies: [ 40 | "PactSwift" 41 | ], 42 | path: "./Tests" 43 | ), 44 | 45 | ], 46 | 47 | swiftLanguageVersions: [.v5] 48 | 49 | ) 50 | -------------------------------------------------------------------------------- /PactSwift.xcodeproj/xcshareddata/IDETemplateMacros.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | FILEHEADER 6 | 7 | // Created by ___FULLUSERNAME___ on ___DATE___. 8 | // Copyright © ___YEAR___ ___FULLUSERNAME___. All rights reserved. 9 | // 10 | // Permission to use, copy, modify, and/or distribute this software for any 11 | // purpose with or without fee is hereby granted, provided that the above 12 | // copyright notice and this permission notice appear in all copies. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 15 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 16 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 17 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 19 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 20 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21 | // 22 | 23 | 24 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 5.1.x | :white_check_mark: | 11 | | 5.0.x | :x: | 12 | | 4.0.x | :white_check_mark: | 13 | | < 4.0 | :x: | 14 | 15 | ## Reporting a Vulnerability 16 | 17 | Use this section to tell people how to report a vulnerability. 18 | 19 | Tell them where to go, how often they can expect to get an update on a 20 | reported vulnerability, what to expect if the vulnerability is accepted or 21 | declined, etc. 22 | -------------------------------------------------------------------------------- /Scripts/BuildPhases/lint-project: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # PactSwift 4 | # 5 | # Created by Marko Justinek on 26/3/20. 6 | # Copyright © 2020 Marko Justinek. All rights reserved. 7 | # Permission to use, copy, modify, and/or distribute this software for any 8 | # purpose with or without fee is hereby granted, provided that the above 9 | # copyright notice and this permission notice appear in all copies. 10 | # 11 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 14 | # SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 17 | # IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | # 19 | 20 | set -eu 21 | 22 | echo "--- 🤖 Linting ${PROJECT_NAME} Project..." 23 | 24 | SCRIPT_DIR="${BASH_SOURCE[0]%/*}" 25 | 26 | echo "Setting the scripts dir to ${SCRIPT_DIR}" 27 | 28 | "${SCRIPT_DIR}"/validate-build-settings 29 | "${SCRIPT_DIR}"/validate-project-config 30 | 31 | echo "--- 👍 ${PROJECT_NAME} project successfully validated and linted." 32 | -------------------------------------------------------------------------------- /Scripts/BuildPhases/lint-target: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # PactSwift 4 | # 5 | # Created by Marko Justinek on 26/3/20. 6 | # Copyright © 2020 Marko Justinek. All rights reserved. 7 | # Permission to use, copy, modify, and/or distribute this software for any 8 | # purpose with or without fee is hereby granted, provided that the above 9 | # copyright notice and this permission notice appear in all copies. 10 | # 11 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 14 | # SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 17 | # IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | # 19 | 20 | set -eu 21 | 22 | echo "--- 🤖 Linting ${TARGET_NAME} Target Structure..." 23 | 24 | #### Variables 25 | 26 | #### Expecting for source files to be in ./Sources file (SPM file structure) 27 | TARGET_SRCROOT="${SRCROOT}/Sources" 28 | 29 | errors=() 30 | 31 | #### Script steps 32 | 33 | if [[ ! -z "${INFOPLIST_FILE}" && ! -f "${INFOPLIST_FILE}" ]]; then 34 | errors+=("error: Could not find Info.plist file "${INFOPLIST_FILE}" for target '${TARGET_NAME}'.") 35 | fi 36 | 37 | if [[ ! -d "${TARGET_SRCROOT}" ]]; then 38 | errors+=("error: Could not find root folder '${TARGET_SRCROOT}' for target '${TARGET_NAME}'.") 39 | fi 40 | 41 | if [ ${#errors[@]} -ne 0 ]; then 42 | for i in "${errors[@]}"; do 43 | echo $i 44 | done 45 | exit 1 46 | fi 47 | 48 | echo "--- 👍 Linting ${TARGET_NAME} successful!" 49 | -------------------------------------------------------------------------------- /Scripts/BuildPhases/validate-build-settings: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # PactSwift 4 | # 5 | # Created by Marko Justinek on 26/3/20. 6 | # Copyright © 2020 Marko Justinek. All rights reserved. 7 | # Permission to use, copy, modify, and/or distribute this software for any 8 | # purpose with or without fee is hereby granted, provided that the above 9 | # copyright notice and this permission notice appear in all copies. 10 | # 11 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 14 | # SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 17 | # IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | # 19 | 20 | set -eu 21 | 22 | echo "--- 🤖 Ensuring there are no build settings in Xcode project file." 23 | 24 | PBXPROJ_FILE_PATH="${PROJECT_FILE_PATH}/project.pbxproj" 25 | NUMBER_OF_BUILD_SETTINGS=`grep "buildSettings" "$PBXPROJ_FILE_PATH" | wc -l` 26 | NUMBER_OF_EMPTY_BUILD_SETTINGS=`grep -B 0 -A 1 "buildSettings" "$PBXPROJ_FILE_PATH" | grep "};" | wc -l` 27 | 28 | if [ $NUMBER_OF_BUILD_SETTINGS != $NUMBER_OF_EMPTY_BUILD_SETTINGS ]; then 29 | NUMBER_WITH_SETTINGS=`expr $NUMBER_OF_BUILD_SETTINGS - $NUMBER_OF_EMPTY_BUILD_SETTINGS` 30 | 31 | echo "error: Found ${NUMBER_WITH_SETTINGS} build settings in Xcode project file! Build settings should only be defined in ./Configurations/*.xcconfig files." 32 | exit 1 33 | fi 34 | 35 | echo "--- 👍 There are no build settings in Xcode project file." 36 | -------------------------------------------------------------------------------- /Scripts/BuildPhases/validate-project-config: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # PactSwift 4 | # 5 | # Created by Marko Justinek on 26/3/20. 6 | # Copyright © 2020 Marko Justinek. All rights reserved. 7 | # Permission to use, copy, modify, and/or distribute this software for any 8 | # purpose with or without fee is hereby granted, provided that the above 9 | # copyright notice and this permission notice appear in all copies. 10 | # 11 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 14 | # SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 17 | # IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | # 19 | 20 | set -eu 21 | 22 | echo "--- 🤖 Validating project config..." 23 | 24 | PROJECT_CONFIG_DIR="${SRCROOT}/Configurations" 25 | 26 | ### Validate top level project configuration 27 | if [[ ! -d "${PROJECT_CONFIG_DIR}" ]]; then 28 | echo "error: Could not find 'Configurations' folder for project '${PROJECT_NAME}'." 29 | exit 1 30 | fi 31 | 32 | echo "--- 👍 Project config validated." 33 | -------------------------------------------------------------------------------- /Scripts/build_file_list_and_swiftlint: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # PactSwift 4 | # 5 | # Created by Marko Justinek on 26/3/20. 6 | # Copyright © 2020 Marko Justinek. All rights reserved. 7 | # Permission to use, copy, modify, and/or distribute this software for any 8 | # purpose with or without fee is hereby granted, provided that the above 9 | # copyright notice and this permission notice appear in all copies. 10 | # 11 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 14 | # SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 17 | # IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 | # 19 | 20 | set -eu 21 | 22 | # Adds support for Apple Silicon brew directory 23 | export PATH="$PATH:/opt/homebrew/bin" 24 | 25 | SRCROOT=${SRCROOT:-"."} 26 | DERIVED_FILE_DIR=${DERIVED_FILE_DIR:-"."} 27 | 28 | if [ $# -ne 2 ]; then 29 | echo "usage: build_file_list_and_swiftlint project_name swiftlint_yml" 30 | exit 1 31 | fi 32 | 33 | echo "--- 🤖 Linting $SRCROOT/Sources/*.swift" 34 | 35 | if which swiftlint >/dev/null; then 36 | # Build a list of Swift files in the Sources directory 37 | find Sources -name \*.swift -exec echo "\$(SRCROOT)/"{} \; > $DERIVED_FILE_DIR/$1.xcfilelist 38 | 39 | # Update the xcfilelist if the list of Swift files has changed 40 | cmp --silent $SRCROOT/$1.xcfilelist $DERIVED_FILE_DIR/$1.xcfilelist || cp -f $DERIVED_FILE_DIR/$1.xcfilelist $SRCROOT/$1.xcfilelist 41 | 42 | # Run swiftlint (TODO: - swiftlint by iterating through the $1.xcfilelist) 43 | # swiftlint --config $2 -- #filename0 #filename1 #filename2 ... 44 | swiftlint --config $2 45 | 46 | # Output an empty derived file 47 | touch $DERIVED_FILE_DIR/swiftlint.txt 48 | 49 | # All hunky dory 50 | echo "--- 👍 .swift files linted" 51 | else 52 | echo "--- ⚠️ Swiftlint" 53 | echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint" 54 | fi 55 | -------------------------------------------------------------------------------- /Scripts/carthage: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # carthage workaround 4 | # Usage example: ./carthage build --platform iOS 5 | # 6 | # Source(s): 7 | # - https://github.com/Carthage/Carthage/issues/3201 8 | # - https://github.com/Carthage/Carthage/issues/3019#issuecomment-665136323 9 | # - https://github.com/Carthage/Carthage/issues/3019#issuecomment-734415287 10 | # 11 | 12 | set -euo pipefail 13 | 14 | # Determine architecture of current machine 15 | ACTIVE_ARCH=$(uname -m) 16 | 17 | if [[ $ACTIVE_ARCH == "x86_64" ]]; then 18 | 19 | # If running on Intel machine, do the excluded architectures dance 💃🕺 20 | 21 | xcconfig=$(mktemp /tmp/static.xcconfig.XXXXXX) 22 | trap 'rm -f "$xcconfig"' INT TERM HUP EXIT 23 | 24 | echo "⚠️ NOTE: Using Carthage workaround script..." 25 | 26 | # For Xcode 12 and 13 make sure EXCLUDED_ARCHS is set to arm architectures otherwise 27 | # the build will fail on lipo due to duplicate architectures. 28 | 29 | CURRENT_XCODE_VERSION="$(xcodebuild -version | grep "Xcode" | cut -d' ' -f2 | cut -d'.' -f1)00" 30 | CURRENT_XCODE_BUILD=$(xcodebuild -version | grep "Build version" | cut -d' ' -f3) 31 | 32 | echo "EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_${CURRENT_XCODE_VERSION}__BUILD_${CURRENT_XCODE_BUILD} = arm64 arm64e armv7 armv7s armv6 armv8" >> $xcconfig 33 | 34 | echo 'EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_'${CURRENT_XCODE_VERSION}' = $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_$(XCODE_VERSION_MAJOR)__BUILD_$(XCODE_PRODUCT_BUILD_VERSION))' >> $xcconfig 35 | 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 36 | 37 | export XCODE_XCCONFIG_FILE="$xcconfig" 38 | carthage "$@" 39 | 40 | else 41 | 42 | # Running on arm64 machine so just use the plain carthage 43 | echo "⚠️ NOTE: Using plain vanilla Carthage..." 44 | carthage "$@" 45 | 46 | fi 47 | 48 | -------------------------------------------------------------------------------- /Scripts/check_build_tools: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu 4 | set -o pipefail 5 | 6 | # Checking for SwiftLint 7 | if which swiftlint >/dev/null; then 8 | echo "👍 swiftLint installed" 9 | else 10 | echo "⚠️ Swiftlint" 11 | echo "warning: SwiftLint not installed, use 'brew install swiftlint' to install it." 12 | fi 13 | 14 | # Checking for xcbeautify 15 | if which xcbeautify >/dev/null; then 16 | echo "👍 xcbeautify installed" 17 | else 18 | echo "⚠️ xcbeautify" 19 | echo "warning: xcbeautify not installed, use 'brew install xcbeautify' to install it." 20 | fi -------------------------------------------------------------------------------- /Scripts/prepare_build_tools: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | brew tap thii/xcbeautify https://github.com/thii/xcbeautify.git 4 | brew install xcbeautify 5 | 6 | if [[ "$CI" == false ]]; then 7 | brew install swiftlint 8 | fi -------------------------------------------------------------------------------- /Scripts/run_tests: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -eu 4 | set -o pipefail 5 | 6 | # Overridable Environment 7 | SIMULATOR_NAME=${SIMULATOR_NAME:-'iPhone 14 Pro'} 8 | SCRIPTS_DIR="${BASH_SOURCE[0]%/*}" 9 | 10 | # Determine architecture of current machine 11 | ACTIVE_ARCH=$(uname -m) 12 | 13 | # Check for dependencies 14 | $SCRIPTS_DIR/check_build_tools 15 | 16 | # Carthage build 17 | echo "📦 Building as a Carthage dependency" 18 | if [[ $ACTIVE_ARCH == "x86_64" ]]; then 19 | ${SCRIPTS_DIR}/carthage build --no-skip-current --use-xcframeworks 20 | else 21 | carthage build --no-skip-current --use-xcframeworks 22 | fi 23 | 24 | # Build and test for SPM 25 | echo "📦 Verifying it works using Swift Package Manager" 26 | 27 | echo "ℹ️ Resolving package dependencies" 28 | xcodebuild -resolvePackageDependencies 29 | 30 | echo "🏗 Building" 31 | swift build | xcbeautify 32 | 33 | echo "🤖 Running tests" 34 | swift test | xcbeautify 35 | 36 | # Run iOS tests 37 | echo "📱 Running iOS tests" 38 | set -o pipefail && xcodebuild clean test -project PactSwift.xcodeproj -scheme PactSwift-iOS -destination "platform=iOS Simulator,name=${SIMULATOR_NAME}" GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES | xcbeautify 39 | 40 | # Run macOS tests 41 | echo "🖥 Running macOS tests" 42 | set -o pipefail && xcodebuild clean test -project PactSwift.xcodeproj -scheme PactSwift-macOS -destination "platform=macOS,arch=${ACTIVE_ARCH}" GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES GCC_GENERATE_TEST_COVERAGE_FILES=YES| xcbeautify 43 | 44 | # A-OK? 45 | 46 | echo "👍 All hunky dory!" 47 | -------------------------------------------------------------------------------- /Sources/ExampleGenerators/DateTime.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DateTime.swift 3 | // PactSwift 4 | // 5 | // Created by Marko Justinek on 13/2/22. 6 | // Copyright © 2022 Marko Justinek. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension ExampleGenerator { 12 | 13 | /// Generates an example for DateTime using a specific `Date` 14 | struct DateTime: ExampleGeneratorExpressible { 15 | internal let value: Any 16 | internal let generator: ExampleGenerator.Generator = .dateTime 17 | internal var rules: [String: AnyEncodable]? 18 | 19 | /// Generates an example value for DateTime using a specific `Date` for consumer tests 20 | /// 21 | /// - Parameters: 22 | /// - format: The format used for datetime 23 | /// - use: The `Date` object used in consumer tests 24 | /// 25 | public init(format: String, use date: Date) { 26 | self.value = date.formatted(format) 27 | self.rules = [ 28 | "format": AnyEncodable(format), 29 | ] 30 | } 31 | } 32 | 33 | } 34 | 35 | // MARK: - Objective-C 36 | 37 | @objc(PFGeneratorDateTime) 38 | public class ObjcDateTime: NSObject, ObjcGenerator { 39 | 40 | let type: ExampleGeneratorExpressible 41 | 42 | /// Generates an example value for DateTime using a specific `Date` for consumer tests 43 | /// 44 | /// - Parameters: 45 | /// - format: The format used for datetime 46 | /// - use: The `Date` object used in consumer tests 47 | /// 48 | @objc(date: format:) 49 | public init(format: String, use date: Date) { 50 | type = ExampleGenerator.DateTime(format: format, use: date) 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /Sources/ExampleGenerators/DateTimeExpression.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DateTimeExpression.swift 3 | // PactSwift 4 | // 5 | // Created by Marko Justinek on 5/3/22. 6 | // Copyright © 2022 Marko Justinek. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public extension ExampleGenerator { 12 | 13 | /// Generates a generator for DateTime using an expression 14 | /// 15 | /// Warning: 16 | /// Not all Pact impelmentations support this type of example generator! 17 | /// 18 | struct DateTimeExpression: ExampleGeneratorExpressible { 19 | internal let value: Any 20 | internal let generator: ExampleGenerator.Generator = .dateTime 21 | internal var rules: [String: AnyEncodable]? 22 | 23 | /// Generates an example generator for DateTime using an expression 24 | /// 25 | /// - Parameters: 26 | /// - expression: The expression provider should use when verifying 27 | /// - format: The date time format 28 | /// 29 | /// - Warning: Not all Pact implementations support this type of example generator! 30 | /// 31 | public init(expression: String, format: String) { 32 | self.value = Date().formatted(format) 33 | self.rules = [ 34 | "format": AnyEncodable(format), 35 | "expression": AnyEncodable(expression), 36 | ] 37 | } 38 | } 39 | 40 | } 41 | 42 | // MARK: - Objective-C 43 | 44 | @objc(PFGeneratorDateTimeExpression) 45 | public class OjbcDateTimeExpression: NSObject, ObjcGenerator { 46 | 47 | let type: ExampleGeneratorExpressible 48 | 49 | /// Generates an example generator for DateTime using an expression 50 | /// 51 | /// - Parameters: 52 | /// - expression: The expression provider should use when verifying 53 | /// - format: The date time format 54 | /// 55 | /// - Warning: Not all Pact implementations support this type of example generator! 56 | /// 57 | @objc(expression: format:) 58 | public init(expression: String, format: String) { 59 | type = ExampleGenerator.DateTimeExpression(expression: expression, format: format) 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /Sources/ExampleGenerators/ProviderStateGenerator.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 15/8/21. 3 | // Copyright © 2021 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | extension ExampleGenerator { 21 | 22 | // Works with Matcher.FromProviderState(references: value:) 23 | struct ProviderStateGenerator: ExampleGeneratorExpressible { 24 | let value: Any 25 | let generator: ExampleGenerator.Generator = .providerState 26 | var rules: [String: AnyEncodable]? 27 | 28 | init(parameter: String, value: Any) { 29 | self.value = value 30 | self.rules = [ 31 | "expression": AnyEncodable(parameter), 32 | "type": AnyEncodable(generator.rawValue), 33 | ] 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Sources/ExampleGenerators/RandomBool.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 11/9/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | public extension ExampleGenerator { 21 | 22 | /// Generates a random boolean value 23 | struct RandomBool: ExampleGeneratorExpressible { 24 | internal let value: Any = Bool.random() 25 | internal let generator: ExampleGenerator.Generator = .bool 26 | internal let rules: [String: AnyEncodable]? = nil 27 | 28 | /// Generates a random boolean value 29 | public init() { } 30 | } 31 | 32 | } 33 | 34 | // MARK: - Objective-C 35 | 36 | @objc(PFGeneratorRandomBool) 37 | public class ObjcRandomBool: NSObject, ObjcGenerator { 38 | 39 | let type: ExampleGeneratorExpressible = ExampleGenerator.RandomBool() 40 | 41 | /// Generates a random boolean value 42 | @objc public override init() { 43 | super.init() 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /Sources/ExampleGenerators/RandomDate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 17/9/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | public extension ExampleGenerator { 21 | 22 | /// Generates a Date value from the current date either in ISO format or using the provided format string 23 | struct RandomDate: ExampleGeneratorExpressible { 24 | internal let value: Any 25 | internal let generator: ExampleGenerator.Generator = .date 26 | internal var rules: [String: AnyEncodable]? 27 | 28 | /// Generates a `Date` value from the current date either in ISO format or using the provided format string 29 | /// 30 | /// - Parameters: 31 | /// - format: The format of generated date 32 | /// 33 | public init(format: String? = nil) { 34 | self.value = Date.formattedDate(format: format, isoFormat: .date) 35 | 36 | if let format = format { 37 | self.rules = [ 38 | "format": AnyEncodable(format), 39 | ] 40 | } 41 | } 42 | } 43 | 44 | } 45 | 46 | // MARK: - Objective-C 47 | 48 | @objc(PFGeneratorRandomDate) 49 | public class ObjcRandomDate: NSObject, ObjcGenerator { 50 | 51 | let type: ExampleGeneratorExpressible 52 | 53 | /// Generates a `Date` value from the current date either in ISO format or using the provided format string 54 | /// 55 | /// - Parameters: 56 | /// - format: The format of generated date 57 | /// 58 | @objc(format:) 59 | public init(format: String? = nil) { 60 | type = ExampleGenerator.RandomDate(format: format) 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /Sources/ExampleGenerators/RandomDateTime.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 17/9/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | public extension ExampleGenerator { 21 | 22 | /// Generates a Date and Time (timestamp) value from the current date and time either in ISO format or using the provided format string 23 | struct RandomDateTime: ExampleGeneratorExpressible { 24 | internal let value: Any 25 | internal let generator: ExampleGenerator.Generator = .dateTime 26 | internal var rules: [String: AnyEncodable]? 27 | 28 | /// Generates a Date and Time (timestamp) value from the current date and time either in ISO format or using the provided format string 29 | /// 30 | /// - Parameters: 31 | /// - format: The format of generated timestamp 32 | /// 33 | public init(format: String? = nil) { 34 | self.value = Date.formattedDate(format: format, isoFormat: .dateTime) 35 | 36 | if let format = format { 37 | self.rules = [ 38 | "format": AnyEncodable(format), 39 | ] 40 | } 41 | } 42 | } 43 | 44 | } 45 | 46 | // MARK: - Objective-C 47 | 48 | @objc(PFGeneratorRandomDateTime) 49 | public class ObjcRandomDateTime: NSObject, ObjcGenerator { 50 | 51 | let type: ExampleGeneratorExpressible 52 | 53 | /// Generates a Date and Time (timestamp) value from the current date and time either in ISO format or using the provided format string 54 | /// 55 | /// - Parameters: 56 | /// - format: The format of generated timestamp 57 | /// 58 | @objc(format:) 59 | public init(format: String? = nil) { 60 | type = ExampleGenerator.RandomDateTime(format: format) 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /Sources/ExampleGenerators/RandomDecimal.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 17/9/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | public extension ExampleGenerator { 21 | 22 | /// Generates a random decimal value (BigDecimal) with the provided number of digits 23 | struct RandomDecimal: ExampleGeneratorExpressible { 24 | internal let value: Any 25 | internal let generator: ExampleGenerator.Generator = .decimal 26 | internal var rules: [String: AnyEncodable]? 27 | 28 | /// Generates a random decimal value (BigDecimal) with the provided number of digits 29 | /// 30 | /// - Parameters: 31 | /// - digits: Number of digits of the generated `Decimal` value (max 9) 32 | /// 33 | /// - Precondition: `digits` is a positive value 34 | /// 35 | public init(digits: Int = 6) { 36 | let digits = digits < 9 ? digits : 9 37 | self.value = NumberHelper.randomDecimal(digits: digits) 38 | self.rules = [ 39 | "digits": AnyEncodable(digits < 9 ? digits : 9), 40 | ] 41 | } 42 | } 43 | 44 | } 45 | 46 | private enum NumberHelper { 47 | 48 | static func randomDecimal(digits: Int) -> Decimal { 49 | var randomDecimal: String = "" 50 | (0.. String { 42 | let formatter = DateFormatter() 43 | formatter.dateFormat = format 44 | return formatter.string(from: self) 45 | } 46 | 47 | // MARK: - Static interface 48 | 49 | static func formattedDate(format: String?, isoFormat: ISOFormat) -> String { 50 | if let format = format { 51 | return Date().formatted(format) 52 | } 53 | 54 | let formatter = ISO8601DateFormatter() 55 | formatter.formatOptions = isoFormat.formatOptions 56 | return formatter.string(from: Date()) 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /Sources/Extensions/Dictionary+PactSwift.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 31/3/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | /// Merges two `Dictionary` objects and returns a `Dictionary` 19 | func merge(_ lhs: [Key: Value], with rhs: [Key: Value]) -> [Key: Value] { 20 | var result = lhs 21 | rhs.forEach { result[$0] = $1 } 22 | return result 23 | } 24 | -------------------------------------------------------------------------------- /Sources/Extensions/MockServer+Async.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Oliver Jones on 30/11/2022. 3 | // Copyright © 2022 Oliver Jones. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | #if canImport(_Concurrency) && compiler(>=5.7) 19 | 20 | import Foundation 21 | @_implementationOnly import PactSwiftMockServer 22 | 23 | extension MockServer { 24 | 25 | /// Spins up a mock server with expected interactions defined in the provided Pact 26 | /// 27 | /// - Parameters: 28 | /// - pact: The pact contract 29 | /// - protocol: HTTP protocol 30 | /// 31 | @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) 32 | @discardableResult 33 | func setup(pact: Data, protocol: PactSwiftMockServer.TransferProtocol = .standard) async throws -> Int { 34 | try await withCheckedThrowingContinuation { continuation in 35 | self.setup(pact: pact, protocol: `protocol`) { result in 36 | continuation.resume(with: result) 37 | } 38 | } 39 | } 40 | 41 | /// Verifies all interactions passed to mock server 42 | /// 43 | /// By default pact files are written to `/tmp/pacts`. 44 | /// Use `PACT_OUTPUT_DIR` environment variable with absolute path to your custom path in schema `run` configuration. 45 | /// 46 | @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) 47 | func verify() async throws -> Bool { 48 | try await withCheckedThrowingContinuation { continuation in 49 | self.verify { result in 50 | continuation.resume(with: result) 51 | } 52 | } 53 | } 54 | 55 | /// Finalises Pact tests by writing the pact contract file to disk 56 | /// 57 | /// - Parameters: 58 | /// - pact: The Pact contract to write 59 | /// - completion: A completion block called when setup completes 60 | /// 61 | @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) 62 | func finalize(pact: Data) async throws -> String { 63 | try await withCheckedThrowingContinuation { continuation in 64 | self.finalize(pact: pact) { result in 65 | continuation.resume(with: result) 66 | } 67 | } 68 | } 69 | 70 | } 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /Sources/Extensions/Sequence+PactSwift.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 9/7/21. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | extension Sequence where Iterator.Element: Hashable { 21 | 22 | var unique: [Iterator.Element] { 23 | var seen: Set = [] 24 | return filter { seen.insert($0).inserted } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Sources/Extensions/String+PactSwift.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 27/10/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | extension String: PactPathParameter { } 21 | 22 | extension String { 23 | 24 | /// Returns the `UUID` given the `String` itself represents a valid UUID 25 | var uuid: UUID? { 26 | UUID(uuidString: self) 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /Sources/Extensions/Task+Timeout.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Oliver Jones on 1/12/2022. 3 | // Copyright © 2022 Oliver Jones. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | #if canImport(_Concurrency) && compiler(>=5.7) 19 | 20 | import Foundation 21 | 22 | @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) 23 | extension Task where Failure == Error { 24 | 25 | // Start a new Task with a timeout. If the timeout expires before the operation is 26 | // completed then the task is cancelled and an error is thrown. 27 | @available(macOS 12.0, iOS 15.0, watchOS 8.0, tvOS 15.0, *) 28 | init(priority: TaskPriority? = nil, timeout: TimeInterval, operation: @escaping @Sendable () async throws -> Success) { 29 | self = Task(priority: priority) { 30 | try await withThrowingTaskGroup(of: Success.self) { group -> Success in 31 | group.addTask(operation: operation) 32 | group.addTask { 33 | try await _Concurrency.Task.sleep(nanoseconds: UInt64(timeout * Double(NSEC_PER_SEC))) 34 | throw TimeoutError(interval: timeout) 35 | } 36 | guard let success = try await group.next() else { 37 | throw _Concurrency.CancellationError() 38 | } 39 | group.cancelAll() 40 | return success 41 | } 42 | } 43 | } 44 | } 45 | 46 | struct TimeoutError: LocalizedError { 47 | var interval: TimeInterval 48 | var errorDescription: String? { "Task timed out after \(interval) seconds" } 49 | } 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /Sources/Extensions/UUID+PactSwift.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 16/9/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | extension UUID { 21 | 22 | /// Returns `UUID` as String with no hyphens, lowercased 23 | var uuidStringSimple: String { 24 | self.uuidString.replacingOccurrences(of: "-", with: "").lowercased() 25 | } 26 | 27 | /// Returns an RFC4122-compliant string created from the UUID, such as "385336e1-d647-44a8-8b1b-3dbf4a073416" 28 | var rfc4122String: String { 29 | uuidString.lowercased() 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /Sources/Headers/PactSwift.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 26/3/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | #import 19 | 20 | //! Project version number for PactSwift. 21 | FOUNDATION_EXPORT double PactSwiftVersionNumber; 22 | 23 | //! Project version string for PactSwift. 24 | FOUNDATION_EXPORT const unsigned char PactSwiftVersionString[]; 25 | 26 | // In this header, you should import all the public headers of your framework using statements like #import 27 | -------------------------------------------------------------------------------- /Sources/Matchers/DecimalLike.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 11/4/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | public extension Matcher { 21 | 22 | /// Mathes a `Decimal` value. 23 | /// 24 | /// - Parameters: 25 | /// - value: The value MockService should expect or respond with in your tests 26 | /// 27 | /// Use this matcher when you expect the type being returned by the API provider is a `Decimal`. 28 | /// 29 | /// ``` 30 | /// [ 31 | /// "foo": Matcher.DecimalLike(1234) 32 | /// ] 33 | /// ``` 34 | /// 35 | struct DecimalLike: MatchingRuleExpressible { 36 | internal let value: Any 37 | internal let rules: [[String: AnyEncodable]] = [["match": AnyEncodable("decimal")]] 38 | 39 | // MARK: - Initializer 40 | 41 | /// Mathes a `Decimal` value. 42 | /// 43 | /// - parameter value: The value MockService should expect or respond with in your tests 44 | /// 45 | public init(_ value: Decimal) { 46 | self.value = value 47 | } 48 | } 49 | 50 | } 51 | 52 | // MARK: - Objective-C 53 | 54 | /// Mathes a `Decimal` value. 55 | /// 56 | /// Use this matcher when you expect the type being returned by the API provider is a `Decimal`. 57 | /// 58 | /// ``` 59 | /// @{@"foo": [Matcher DecimalLike(1234)] } 60 | /// ``` 61 | /// 62 | /// - Parameters: 63 | /// - value: The value MockService should expect or respond with 64 | /// 65 | @objc(PFMatcherDecimalLike) 66 | public class ObjcDecimalLike: NSObject, ObjcMatcher { 67 | 68 | let type: MatchingRuleExpressible 69 | 70 | /// Mathes a `Decimal` value. 71 | /// 72 | /// - Parameters: 73 | /// - value: The value MockService should expect or respond with 74 | /// 75 | @objc(value:) 76 | public init(value: Decimal) { 77 | self.type = Matcher.DecimalLike(value) 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /Sources/Matchers/EqualTo.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 11/4/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | public extension Matcher { 21 | 22 | /// Matches the API provided value varbatim. 23 | /// 24 | /// Use this matcher where you expect the exact type and value 25 | /// in the interaction between your consumer and your provider. 26 | /// 27 | /// ``` 28 | /// // DSL 29 | /// [ 30 | /// "foo": Matcher.EqualTo("bar"), 31 | /// "bar": Matcher.EqualTo(847) 32 | /// ] 33 | /// ``` 34 | /// 35 | struct EqualTo: MatchingRuleExpressible { 36 | 37 | internal let value: Any 38 | internal let rules: [[String: AnyEncodable]] = [["match": AnyEncodable("equality")]] 39 | 40 | // MARK: - Initializers 41 | 42 | /// Matches the API provided value varbatim. 43 | /// 44 | /// - parameter value: The exact value that is expected 45 | /// 46 | public init(_ value: Any) { 47 | self.value = value 48 | } 49 | } 50 | 51 | } 52 | 53 | // MARK: - Objective-C 54 | 55 | @objc(PFMatcherEqualTo) 56 | public class ObjcEqualTo: NSObject, ObjcMatcher { 57 | 58 | let type: MatchingRuleExpressible 59 | 60 | /// Matches the API provided value varbatim. 61 | /// 62 | /// - parameter value: The exact value that is expected 63 | /// 64 | @objc(value:) 65 | public init(value: Any) { 66 | type = Matcher.EqualTo(value) 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /Sources/Matchers/IntegerLike.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 11/4/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | public extension Matcher { 21 | 22 | /// Matches an `Int` type. 23 | /// 24 | /// Use this matcher where you expect an `Int` to be returned 25 | /// by your API provider. 26 | /// 27 | struct IntegerLike: MatchingRuleExpressible { 28 | 29 | internal let value: Any 30 | internal let rules: [[String: AnyEncodable]] = [["match": AnyEncodable("integer")]] 31 | 32 | // MARK: - Initializer 33 | 34 | /// Matches an `Int` type. 35 | /// 36 | /// - Parameters: 37 | /// - value: Value to use in tests 38 | /// 39 | public init(_ value: Int) { 40 | self.value = value 41 | } 42 | } 43 | 44 | } 45 | 46 | // MARK: - Objective-C 47 | 48 | @objc(PFMatcherIntegerLike) 49 | public class ObjcIntegerLike: NSObject, ObjcMatcher { 50 | 51 | let type: MatchingRuleExpressible 52 | 53 | /// Matches an `Int` type. 54 | /// 55 | /// - Parameters: 56 | /// - value: Value to use in tests 57 | /// 58 | @objc(value:) 59 | public init(value: Int) { 60 | type = Matcher.IntegerLike(value) 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /Sources/Matchers/MatchNull.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 9/10/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | public extension Matcher { 21 | 22 | /// Matches a `null` value. 23 | struct MatchNull: MatchingRuleExpressible { 24 | 25 | internal let value: Any 26 | internal let rules: [[String: AnyEncodable]] = [["match": AnyEncodable("null")]] 27 | 28 | // MARK: - Initializer 29 | 30 | /// The value returned by API provider matches `null`. 31 | public init() { 32 | value = "pact_matcher_null" 33 | } 34 | } 35 | 36 | } 37 | 38 | // MARK: - Objective-C 39 | 40 | @objc(PFMatcherNull) 41 | public class ObjcMatchNull: NSObject, ObjcMatcher { 42 | 43 | let type: MatchingRuleExpressible = Matcher.MatchNull() 44 | 45 | /// The value returned by API provider matches `null`. 46 | @objc public override init() { 47 | super.init() 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /Sources/Matchers/OneOf.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 9/7/21. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | public extension Matcher { 21 | 22 | /// Defines a Pact matcher that validates against one of the provided values 23 | /// 24 | /// Case sensitive. Uses the first provided value in consumer tests. Removes duplicate values. 25 | /// Use this matcher when you're expecting API response values to fit an `enum` type. 26 | /// 27 | struct OneOf: MatchingRuleExpressible { 28 | internal let value: Any 29 | internal let pattern: String 30 | 31 | internal var rules: [[String: AnyEncodable]] { 32 | [ 33 | [ 34 | "match": AnyEncodable("regex"), 35 | "regex": AnyEncodable(pattern), 36 | ], 37 | ] 38 | } 39 | 40 | // MARK: - Initializer 41 | 42 | /// Matches one of the provided values 43 | /// 44 | /// - Parameters: 45 | /// - values: List of possible values 46 | /// 47 | /// Case sensitive. Uses the first provided value in the consumer test. Removes duplicated values. 48 | /// 49 | init(_ values: AnyHashable...) { 50 | self.init(values: values) 51 | } 52 | 53 | /// Matches one of the provided values 54 | /// 55 | /// - Parameters: 56 | /// - values: The array of possible values 57 | /// 58 | /// Case sensitive. Uses the first provided value in the consumer test. Removes duplicated values. 59 | /// 60 | public init(values: [AnyHashable]) { 61 | self.value = values.first as Any 62 | self.pattern = Self.regexed(values) 63 | } 64 | 65 | // MARK: - Private 66 | 67 | private static func regexed(_ values: [AnyHashable]) -> String { 68 | "^(\(values.unique.map { "\($0)" }.joined(separator: "|")))$" 69 | } 70 | } 71 | 72 | } 73 | 74 | // MARK: - Objective-C 75 | 76 | @objc(PFMatcherOneOf) 77 | public class ObjcOneOf: NSObject, ObjcMatcher { 78 | 79 | let type: MatchingRuleExpressible 80 | 81 | /// Matches one of the provided values 82 | /// 83 | /// - Parameters: 84 | /// - values: The array of possible values 85 | /// 86 | /// Case sensitive. Uses the first provided value in the consumer test. Removes duplicated values. 87 | /// 88 | @objc(oneOfFloat:) 89 | public init(values: [AnyHashable]) { 90 | type = Matcher.OneOf(values: values) 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /Sources/Matchers/SomethingLike.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 9/4/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | public extension Matcher { 21 | 22 | /// Matches a `Type`. 23 | /// 24 | /// Use this matcher where you expect a specific `Type` to be 25 | /// returned by the API provider. 26 | /// 27 | /// ``` 28 | /// [ 29 | /// "foo": Matcher.SomethingLike("bar"), // Matches a `String` 30 | /// "bar": Matcher.SomethingLike(1) // Matches an `Int` 31 | /// ] 32 | /// ``` 33 | /// 34 | struct SomethingLike: MatchingRuleExpressible { 35 | internal let value: Any 36 | internal let rules: [[String: AnyEncodable]] = [["match": AnyEncodable("type")]] 37 | 38 | // MARK: - Initializers 39 | 40 | /// Matches the provided `Type`. 41 | /// 42 | /// - Parameters: 43 | /// - value: Value to use in tests 44 | /// 45 | public init(_ value: Any) { 46 | self.value = value 47 | } 48 | } 49 | 50 | } 51 | 52 | // MARK: - Objective-C 53 | 54 | @objc(PFMatcherSomethingLike) 55 | public class ObjcSomethingLike: NSObject, ObjcMatcher { 56 | 57 | let type: MatchingRuleExpressible 58 | 59 | /// Matches the provided `Type`. 60 | /// 61 | /// - Parameters: 62 | /// - value: Value to use in tests 63 | /// 64 | @objc(value:) 65 | public init(value: Any) { 66 | type = Matcher.SomethingLike(value) 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /Sources/Model/AnyEncodable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 6/4/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | struct AnyEncodable: Encodable { 21 | 22 | private let _encode: (Encoder) throws -> Void 23 | 24 | init(_ value: T) { 25 | self._encode = { encoder in 26 | var container = encoder.singleValueContainer() 27 | try container.encode(value) 28 | } 29 | } 30 | 31 | // Passing a `nil` as a generic type is not allowed so we are piggy-backing off of String type. 32 | init(_ value: String?) { 33 | self._encode = { encoder in 34 | var container = encoder.singleValueContainer() 35 | (value != nil) ? try container.encode(value) : try container.encodeNil() 36 | } 37 | } 38 | 39 | func encode(to encoder: Encoder) throws { 40 | try _encode(encoder) 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /Sources/Model/Constants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 31/7/21. 3 | // Copyright © 2021 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | /// Contains constant values used across `PactSwift` 21 | enum Constants { 22 | 23 | /// The default value for timeout when running Pact tests 24 | static let kTimeout: TimeInterval = 10 25 | 26 | } 27 | -------------------------------------------------------------------------------- /Sources/Model/EncodingError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 27/10/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | enum EncodingError: Error { 21 | case encodingFailure(Any?) 22 | case unknown 23 | 24 | var localizedDescription: String { 25 | switch self { 26 | case .encodingFailure(let message): 27 | var errorMessage = ["Error preparing pact!"] 28 | message.map { errorMessage.append(String(describing: $0)) } 29 | return errorMessage.joined(separator: " ") 30 | 31 | default: 32 | return "Error casting unknown type into an Encodable type!" 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Sources/Model/ErrorReportable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 20/4/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | public typealias FileString = StaticString 21 | 22 | public protocol ErrorReportable { 23 | 24 | func reportFailure(_ message: String) 25 | func reportFailure(_ message: String, file: FileString, line: UInt) 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Sources/Model/ErrorReporter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 20/4/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | import XCTest 20 | 21 | class ErrorReporter: ErrorReportable { 22 | 23 | /// Reports test failure in file and on line where this method is called 24 | func reportFailure(_ message: String) { 25 | XCTFail(message, file: #file, line: #line) 26 | } 27 | 28 | /// Reports test failure in provided file and on provided line 29 | func reportFailure(_ message: String, file: FileString, line: UInt) { 30 | XCTFail(message, file: file, line: line) 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /Sources/Model/ExampleGeneratorExpressible.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 11/9/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | protocol ExampleGeneratorExpressible { 21 | 22 | var value: Any { get } 23 | var generator: ExampleGenerator.Generator { get } 24 | var rules: [String: AnyEncodable]? { get } 25 | 26 | } 27 | 28 | extension ExampleGeneratorExpressible { 29 | 30 | var attributes: [String: AnyEncodable] { 31 | var generatorAttributes: [String: AnyEncodable] = rules ?? [:] 32 | generatorAttributes["type"] = AnyEncodable(generator.rawValue) 33 | 34 | return generatorAttributes 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Sources/Model/MatchingRuleExpressible.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 9/4/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | protocol MatchingRuleExpressible { 21 | 22 | var value: Any { get } 23 | var rules: [[String: AnyEncodable]] { get } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Model/Metadata.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 1/4/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | struct Metadata { 21 | 22 | let pactSpec = PactVersion("3.0.0") 23 | let pactSwift = PactVersion(pactSwiftVersion) 24 | 25 | struct PactVersion: Encodable { 26 | let version: String 27 | 28 | init(_ version: String) { 29 | self.version = version 30 | } 31 | } 32 | 33 | } 34 | 35 | extension Metadata: Encodable { 36 | 37 | enum CodingKeys: String, CodingKey { 38 | case pactSpec = "pactSpecification" 39 | case pactSwift 40 | } 41 | 42 | public func encode(to encoder: Encoder) throws { 43 | var container = encoder.container(keyedBy: CodingKeys.self) 44 | try container.encode(pactSpec, forKey: .pactSpec) 45 | try container.encode(pactSwift, forKey: .pactSwift) 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /Sources/Model/Pact.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 1/4/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | struct Pact: Encodable { 21 | 22 | private let metadata = Metadata() 23 | 24 | // MARK: - Properties 25 | 26 | let consumer: Pacticipant 27 | let provider: Pacticipant 28 | 29 | var interactions: [Interaction] = [] 30 | 31 | // These are the top level required nodes of a Pact contract file 32 | var payload: [String: Any] { 33 | [ 34 | "consumer": consumer.name, 35 | "provider": provider.name, 36 | "interactions": interactions, 37 | "metadata": metadata, 38 | ] 39 | } 40 | 41 | var data: Data? { 42 | do { 43 | let encoder = JSONEncoder() 44 | return try encoder.encode(self) 45 | } catch { 46 | Logger.log(message: error.localizedDescription) 47 | } 48 | return nil 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /Sources/Model/PactHTTPMethod.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 31/3/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | /// The HTTP method expected in the interaction 21 | @objc public enum PactHTTPMethod: Int { 22 | case GET 23 | case HEAD 24 | case POST 25 | case PUT 26 | case PATCH 27 | case DELETE 28 | case TRACE 29 | case CONNECT 30 | case OPTIONS 31 | } 32 | 33 | extension PactHTTPMethod { 34 | 35 | var method: String { 36 | switch self { 37 | case .GET: return "get" 38 | case .HEAD: return "head" 39 | case .POST: return "post" 40 | case .PUT: return "put" 41 | case .PATCH: return "patch" 42 | case .DELETE: return "delete" 43 | case .TRACE: return "trace" 44 | case .CONNECT: return "connect" 45 | case .OPTIONS: return "options" 46 | } 47 | } 48 | 49 | } 50 | 51 | extension PactHTTPMethod: Encodable { 52 | 53 | enum CodingKeys: CodingKey { 54 | case method 55 | } 56 | 57 | public func encode(to encoder: Encoder) throws { 58 | var container = encoder.singleValueContainer() 59 | try container.encode(method) 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /Sources/Model/PactInteractionElement.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 9/4/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | enum PactInteractionNode: String { 21 | 22 | case body 23 | case header 24 | case path 25 | case query 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Sources/Model/PactInteractionNode.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 9/4/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | enum PactInteractionElement: String { 21 | 22 | case body 23 | case headers 24 | case path 25 | case query 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Sources/Model/PactPathParameter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 27/10/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | /// A protocol defining a Type that can be used as a request's path parameter (eg: a RegexLike matcher) 21 | public protocol PactPathParameter { } 22 | -------------------------------------------------------------------------------- /Sources/Model/PactSwiftVersion.swift: -------------------------------------------------------------------------------- 1 | // !!! WARNING: THIS FILE IS AUTOMATED - DO NOT CHANGE OR MOVE !!! 2 | let pactSwiftVersion = "1.1.0" 3 | -------------------------------------------------------------------------------- /Sources/Model/Pacticipant.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 1/4/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | /// An object representing a participant in the Pact contract. 21 | enum Pacticipant { 22 | 23 | case consumer(String) 24 | case provider(String) 25 | 26 | var name: String { 27 | switch self { 28 | case .consumer(let name), 29 | .provider(let name): 30 | return name 31 | } 32 | } 33 | 34 | } 35 | 36 | extension Pacticipant: Encodable { 37 | 38 | enum CodingKeys: CodingKey { 39 | case name 40 | } 41 | 42 | public func encode(to encoder: Encoder) throws { 43 | var container = encoder.container(keyedBy: CodingKeys.self) 44 | try container.encode(name, forKey: .name) 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /Sources/Model/ProviderState.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 2/4/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | /// Object describing expected provider state for an interaction 21 | public struct ProviderState: Encodable { 22 | 23 | let name: String 24 | let params: [String: String] 25 | 26 | /// Object describing expected provider state for an interaction 27 | /// 28 | /// - parameter description: The description of the state 29 | /// - parameter params: The `Key` `Value` pair of the expected state (eg: `"user_id": "1"`) 30 | /// 31 | public init(description: String, params: [String: String]) { 32 | self.name = description 33 | self.params = params 34 | } 35 | 36 | } 37 | 38 | extension ProviderState: Equatable { 39 | 40 | static public func ==(lhs: ProviderState, rhs: ProviderState) -> Bool { 41 | lhs.name == rhs.name && lhs.params == rhs.params 42 | } 43 | 44 | } 45 | 46 | // MARK: - Objective-C 47 | /*! 48 | @brief Object describing expected provider state for an interaction 49 | 50 | @discussion This object holds information about the provider state and specific parameters that are required for the specific provider state. 51 | 52 | To use it, simply call @c[[ProviderState alloc] description:@"user exists" params:@{@"id": @"abc123"}]; 53 | 54 | @param description Description of the provider state 55 | 56 | @param params A dictionary of parameters describing data for the given state 57 | */ 58 | @objc(ProviderState) 59 | public final class ObjCProviderState: NSObject { 60 | 61 | let state: ProviderState 62 | 63 | @objc(initWithDescription:params:) 64 | public init(description: String, params: [String: String]) { 65 | state = ProviderState(description: description, params: params) 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /Sources/Model/ProviderVerifier+Error.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 23/8/21. 3 | // Copyright © 2021 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | public extension ProviderVerifier { 21 | 22 | // A bridge to PactSwiftMockServer provider verification errors 23 | enum VerificationError: Error { 24 | case error(String) 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /Sources/Model/ProviderVerifier+Provider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 21/8/21. 3 | // Copyright © 2021 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | public extension ProviderVerifier { 21 | 22 | /// The provider being verified 23 | struct Provider { 24 | 25 | /// The port of provider being verified 26 | let port: Int 27 | 28 | /// URL of the provider being verified 29 | let url: URL? 30 | 31 | /// The provider being verified 32 | public init(url: URL? = nil, port: Int) { 33 | self.url = url 34 | self.port = port 35 | } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /Sources/Model/Response.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 31/3/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | /// An object representing an API response in Pact Specification Version 3.0 19 | public struct Response { 20 | 21 | var statusCode: Int 22 | var headers: [String: Any]? 23 | 24 | private let bodyEncoder: (Encoder) throws -> Void 25 | 26 | } 27 | 28 | extension Response: Encodable { 29 | 30 | enum CodingKeys: String, CodingKey { 31 | case statusCode = "status" 32 | case headers 33 | case body 34 | case matchingRules 35 | case generators 36 | } 37 | 38 | /// Creates an object representing a network `Response` 39 | /// - Parameters: 40 | /// - statusCode: The status code of the API response 41 | /// - headers: Headers of the API response 42 | /// - body: Optional body in the API response 43 | /// 44 | init(statusCode: Int, headers: [String: Any]? = nil, body: Any? = nil) throws { 45 | self.statusCode = statusCode 46 | self.headers = headers 47 | 48 | let bodyValues = try Toolbox.process(element: body, for: .body) 49 | let headerValues = try Toolbox.process(element: headers, for: .header) 50 | 51 | self.bodyEncoder = { 52 | var container = $0.container(keyedBy: CodingKeys.self) 53 | try container.encode(statusCode, forKey: .statusCode) 54 | if let header = headerValues?.node { try container.encode(header, forKey: .headers) } 55 | if let encodableBody = bodyValues?.node { try container.encode(encodableBody, forKey: .body) } 56 | if let matchingRules = Toolbox.merge(body: bodyValues?.rules, header: headerValues?.rules) { 57 | try container.encode(matchingRules, forKey: .matchingRules) 58 | } 59 | if let generators = Toolbox.merge(body: bodyValues?.generators, header: headerValues?.generators) { 60 | try container.encode(generators, forKey: .generators) 61 | } 62 | } 63 | } 64 | 65 | public func encode(to encoder: Encoder) throws { 66 | try bodyEncoder(encoder) 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /Sources/Model/Toolbox.swift: -------------------------------------------------------------------------------- 1 | // Created by Marko Justinek on 20/10/20. 2 | // Copyright © 2020 Marko Justinek. All rights reserved. 3 | // 4 | // Permission to use, copy, modify, and/or distribute this software for any 5 | // purpose with or without fee is hereby granted, provided that the above 6 | // copyright notice and this permission notice appear in all copies. 7 | // 8 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 14 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 | // 16 | 17 | import Foundation 18 | 19 | enum Toolbox { 20 | 21 | /// Merges the Pact top level elements into one dictionary thac can be Encoded 22 | /// - Parameters: 23 | /// - body: The PactBuilder processed object representing interaction's body 24 | /// - query: The PactBuilder processed object representing interaction's query 25 | /// - header: The PactBuilder processed object representing interaction's header 26 | /// - path: The PactBuilder processed object representing request path 27 | /// 28 | static func merge(body: AnyEncodable?, query: AnyEncodable? = nil, header: AnyEncodable? = nil, path: AnyEncodable? = nil) -> [String: AnyEncodable]? { 29 | var merged: [String: AnyEncodable] = [:] 30 | 31 | if let header = header { 32 | merged["header"] = header 33 | } 34 | 35 | if let body = body { 36 | merged["body"] = body 37 | } 38 | 39 | if let query = query { 40 | merged["query"] = query 41 | } 42 | 43 | if let path = path { 44 | merged["path"] = path 45 | } 46 | 47 | return merged.isEmpty ? nil : merged 48 | } 49 | 50 | /// Runs the `Any` type through PactBuilder and returns a Pact tuple 51 | /// - Parameters: 52 | /// - element: The object to process through PactBuilder 53 | /// - interactionElement: The network interaction element the object relates to 54 | /// 55 | static func process(element: Any?, for interactionElement: PactInteractionNode) throws -> (node: AnyEncodable?, rules: AnyEncodable?, generators: AnyEncodable?)? { 56 | if let element = element { 57 | do { 58 | let encodedElement = try PactBuilder(with: element, for: interactionElement).encoded() 59 | return (node: encodedElement.node, rules: encodedElement.rules, generators: encodedElement.generators) 60 | } catch { 61 | throw error 62 | } 63 | } 64 | 65 | return nil 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /Sources/Model/TransferProtocol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 31/7/21. 3 | // Copyright © 2021 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | #if compiler(>=5.5) 21 | // This is ridiculous! This works when building on macOS 11+. 22 | @_implementationOnly import PactSwiftMockServer 23 | #else 24 | import PactSwiftMockServer 25 | #endif 26 | 27 | /// Defines the transfer protocol on which `MockService` runs. 28 | @objc public enum TransferProtocol: Int { 29 | case standard 30 | case secure 31 | 32 | var bridge: PactSwiftMockServer.TransferProtocol { 33 | switch self { 34 | case .standard: return .standard 35 | case .secure: return .secure 36 | } 37 | } 38 | } 39 | 40 | extension TransferProtocol { 41 | 42 | /// HTTP Transfer protocol 43 | var `protocol`: String { 44 | switch self { 45 | case .standard: return "http" 46 | case .secure: return "https" 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /Sources/Model/VersionSelector.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 19/8/21. 3 | // Copyright © 2021 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | /// Provides a way to configure which pacts the provider verifies. 21 | public struct VersionSelector: Codable, Equatable { 22 | 23 | // MARK: - Properties 24 | 25 | /// The name of the tag which applies to the pacticipant versions of the pacts to verify 26 | let tag: String 27 | 28 | /// Whether or not to verify only the pact that belongs to the latest application version 29 | let latest: Bool 30 | 31 | /// A fallback tag if a pact for the specified `tag` does not exist 32 | let fallbackTag: String? 33 | 34 | /// Filter pacts by the specified consumer 35 | /// 36 | /// When omitted, all consumers are included. 37 | let consumer: String? 38 | 39 | // MARK: - Initialization 40 | 41 | /// Defines a version configuration for which pacts the provider verifies 42 | /// 43 | /// - Parameters: 44 | /// - tag: The version `tag` name of the consumer to verify 45 | /// - fallbackTag: The version `tag` to use if the initial `tag` does not exist 46 | /// - latest: Whether to verify only the pact belonging to the latest application version 47 | /// - consumer: Filter pacts by the specified consumer 48 | /// 49 | /// See [https://docs.pact.io/selectors](https://docs.pact.io/selectors) for more context. 50 | /// 51 | public init(tag: String, fallbackTag: String? = nil, latest: Bool = true, consumer: String? = nil) { 52 | self.tag = tag 53 | self.fallbackTag = fallbackTag 54 | self.latest = latest 55 | self.consumer = consumer 56 | } 57 | 58 | } 59 | 60 | // MARK: - Internal 61 | 62 | extension VersionSelector { 63 | 64 | /// Converts to JSON string 65 | /// 66 | /// - Returns: A `String` representing `ProviderVerifier` in JSON format 67 | /// 68 | func toJSONString() throws -> String { 69 | let jsonEncoder = JSONEncoder() 70 | let jsonData = try jsonEncoder.encode(self) 71 | guard let jsonString = String(data: jsonData, encoding: .utf8) else { 72 | throw ProviderVerifier.VerificationError.error("Invalid consumer version selector specified: \(self)") 73 | } 74 | 75 | return jsonString 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /Sources/Model/WIPPacts.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 24/8/21. 3 | // Copyright © 2021 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | /// The configuration used when verifying WIP pacts 21 | public struct WIPPacts { 22 | 23 | /// The date from which the changed pacts are to be included 24 | let sinceDate: Date 25 | 26 | /// The provider 27 | let providerVersion: String 28 | 29 | /// Configuration for verifying WIP pacts 30 | /// 31 | /// - Parameters: 32 | /// - since: The date from which the WIP pacts are to be included in verification 33 | /// - providerVersion: The provider version being verified 34 | /// 35 | /// See [Work in Progress pacts](https://docs.pact.io/pact_broker/advanced_topics/wip_pacts/) for more 36 | 37 | /// - Warning: The `providerVersion` value set in the `VerificationResult` object is used if provided 38 | /// 39 | public init(since date: Date, providerVersion: String) { 40 | self.sinceDate = date 41 | self.providerVersion = providerVersion 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /Sources/ProviderVerifier.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 20/8/21. 3 | // Copyright © 2021 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | import XCTest 20 | 21 | #if compiler(>=5.5) 22 | @_implementationOnly import PactSwiftMockServer 23 | #else 24 | import PactSwiftMockServer 25 | #endif 26 | 27 | /// Entry point for provider verification 28 | public final class ProviderVerifier { 29 | 30 | let verifier: ProviderVerifying 31 | private let errorReporter: ErrorReportable 32 | 33 | /// Initializes a `Verifier` object for provider verification 34 | public convenience init() { 35 | self.init(verifier: Verifier(), errorReporter: ErrorReporter()) 36 | } 37 | 38 | /// Initializes a `Verifier` object 39 | /// 40 | /// - Parameters: 41 | /// - verifier: The verifier object handling provider verification 42 | /// - errorReporter: Error reporting or intercepting object 43 | /// 44 | /// This initializer is marked `internal` for testing purposes! 45 | /// 46 | internal init(verifier: ProviderVerifying, errorReporter: ErrorReportable? = nil) { 47 | self.verifier = verifier 48 | self.errorReporter = errorReporter ?? ErrorReporter() 49 | } 50 | 51 | /// Executes provider verification test 52 | /// 53 | /// - Parameters: 54 | /// - options: Flags and args to use when verifying a provider 55 | /// - file: The file in which to report the error in 56 | /// - line: The line on which to report the error on 57 | /// - completionBlock: Completion block executed at the end of verification 58 | /// 59 | /// - Returns: A `Result` where error describes the failure 60 | /// 61 | @discardableResult 62 | public func verify(options: Options, file: FileString? = #file, line: UInt? = #line, completionBlock: (() -> Void)? = nil) -> Result { 63 | switch verifier.verifyProvider(options: options.args) { 64 | case .success(let value): 65 | completionBlock?() 66 | return .success(value) 67 | case .failure(let error): 68 | failWith(error.description, file: file, line: line) 69 | completionBlock?() 70 | return .failure(VerificationError.error(error.description)) 71 | } 72 | } 73 | 74 | } 75 | 76 | // MARK: - Private 77 | 78 | private extension ProviderVerifier { 79 | 80 | /// Fail the test and raise the failure in `file` at `line` 81 | func failWith(_ message: String, file: FileString? = nil, line: UInt? = nil) { 82 | if let file = file, let line = line { 83 | errorReporter.reportFailure(message, file: file, line: line) 84 | } else { 85 | errorReporter.reportFailure(message) 86 | } 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /Sources/Toolbox/Logger.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 9/8/2022. 3 | // Copyright © 2022 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | import os.log 20 | 21 | enum Logger { 22 | 23 | /// Logs Pact related messages. 24 | /// 25 | /// Looks for environment variable `PACT_ENABLE_LOGGING = "all"`. Can be set in project's scheme. Uses `os_log` on Apple platforms. 26 | /// 27 | /// - Parameters: 28 | /// - message: The message to log 29 | /// - data: Data to log 30 | /// 31 | static func log(message: String, data: Data? = nil) { 32 | guard case .all = PactLoggingLevel(value: ProcessInfo.processInfo.environment["PACT_ENABLE_LOGGING"]) else { 33 | return 34 | } 35 | 36 | let stringData = data.flatMap { String(data: $0, encoding: .utf8) } ?? "" 37 | 38 | if #available(iOS 10, OSX 10.14, *) { 39 | os_log( 40 | "PactSwift: %{private}s", 41 | log: .default, 42 | type: .default, 43 | "\(message): \(stringData)" 44 | ) 45 | } else { 46 | print(message: "PactSwift: \(message)\n\(stringData)") 47 | } 48 | } 49 | 50 | } 51 | 52 | // MARK: - Private 53 | 54 | private extension Logger { 55 | 56 | static func print(message: String) { 57 | debugPrint(message) 58 | } 59 | 60 | enum PactLoggingLevel: String { 61 | case all 62 | case disabled 63 | 64 | init(value: String?) { 65 | switch value { 66 | case "all": self = .all 67 | default: self = .disabled 68 | } 69 | } 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /Sources/Toolbox/PactFileManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 9/8/2022. 3 | // Copyright © 2022 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | enum PactFileManager { 21 | 22 | /// Where Pact contracts are written to. 23 | /// 24 | /// macOS: 25 | /// 26 | /// Running tests for macOS it will default to app's Documents folder: 27 | /// 28 | /// (eg: `~/Library/Containers/au.com.pact-foundation.Pact-macOS-Example/Data/Documents`) 29 | /// 30 | /// If testing a sandboxed macOS app, this is the default location and it can not be overwritten. 31 | /// If testing a macOS app that is not sandboxed, define a `PACT_OUTPUT_DIR` Environment Variable (in the scheme) 32 | /// with the path to where you want Pact contracts to be written to. 33 | /// 34 | /// iOS/tvOS or non-Xcode project: 35 | /// 36 | /// Default location where Pact contracts are written is `/tmp/pacts` and can be overwritten 37 | /// with a `PACT_OUTPUT_DIR` environment variable set to an absolute path (eg: `$(PROJECT_DIR)/tmp/pacts`). 38 | /// 39 | static var pactDirectoryPath: String { 40 | #if os(macOS) || os(OSX) 41 | let defaultPath = NSHomeDirectory() + "/Documents" 42 | if isSandboxed { 43 | return defaultPath 44 | } 45 | return ProcessInfo.processInfo.environment["PACT_OUTPUT_DIR"] ?? defaultPath 46 | #else 47 | return ProcessInfo.processInfo.environment["PACT_OUTPUT_DIR"] ?? "/tmp/pacts" 48 | #endif 49 | } 50 | 51 | /// Returns true if the directory where Pact contracts are set to be written to exists. 52 | /// If it does not exists, it attempts to create it and if successful, returns true. 53 | /// 54 | static func isPactDirectoryAvailable() -> Bool { 55 | if FileManager.default.fileExists(atPath: pactDirectoryPath) == false { 56 | do { 57 | try FileManager.default.createDirectory(at: pactDirectoryURL, withIntermediateDirectories: true, attributes: nil) 58 | } catch let error as NSError { 59 | debugPrint("Directory \(pactDirectoryURL) could not be created! \(error.localizedDescription)") 60 | return false 61 | } 62 | } 63 | return true 64 | } 65 | 66 | } 67 | 68 | // MARK: - Private 69 | 70 | private extension PactFileManager { 71 | 72 | static var pactDirectoryURL: URL { 73 | URL(fileURLWithPath: pactDirectoryPath, isDirectory: true) 74 | } 75 | 76 | /// Returns true if app is sandboxed 77 | static var isSandboxed: Bool { 78 | let environment = ProcessInfo.processInfo.environment 79 | return environment["APP_SANDBOX_CONTAINER_ID"] != nil 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /Tests/ExampleGenerators/DateTimeExpressionTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DateTimeExpressionTests.swift 3 | // PactSwift 4 | // 5 | // Created by Marko Justinek on 5/3/22. 6 | // Copyright © 2022 Marko Justinek. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | @testable import PactSwift 12 | 13 | class DateTimeExpressionTests: XCTestCase { 14 | 15 | func testDateTimeExpressionExampleGenerator() throws { 16 | let testFormat = "dd.MM.yyyy HH:mm:ss" 17 | let testExpression = "tomorrow 5pm" 18 | let sut = ExampleGenerator.DateTimeExpression(expression: testExpression, format: testFormat) 19 | 20 | XCTAssertEqual(sut.generator, .dateTime) 21 | 22 | let attributes = try XCTUnwrap(sut.rules) 23 | XCTAssertTrue( 24 | ["format", "expression"].allSatisfy { keyValue in 25 | attributes.contains { key, _ in 26 | key == keyValue 27 | } 28 | } 29 | ) 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /Tests/ExampleGenerators/DateTimeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DateTimeTests.swift 3 | // PactSwift 4 | // 5 | // Created by Marko Justinek on 13/2/22. 6 | // Copyright © 2022 Marko Justinek. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | @testable import PactSwift 12 | 13 | class DateTimeTests: XCTestCase { 14 | 15 | func testDateTimeExampleGenerator() throws { 16 | let testDate = Date() 17 | let testFormat = "YYYY-MM-DD HH:mm" 18 | let sut = ExampleGenerator.DateTime(format: testFormat, use: testDate) 19 | 20 | XCTAssertEqual(sut.generator, .dateTime) 21 | 22 | let resultValue = try XCTUnwrap(sut.value as? String) 23 | let resultDate = try XCTUnwrap(DateHelper.dateFrom(string: resultValue, format: testFormat)) 24 | // Assert using the same format due to loss of accuracy using a limited datetime format 25 | XCTAssertEqual(testDate.formatted(testFormat), resultDate.formatted(testFormat)) 26 | 27 | let attributes = try XCTUnwrap(sut.rules) 28 | XCTAssertTrue(attributes.contains { key, _ in 29 | key == "format" 30 | }) 31 | 32 | let resultFormat = try ExampleGeneratorTestHelpers.encodeDecode(sut.rules!) 33 | XCTAssertEqual(resultFormat.format, testFormat) 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Tests/ExampleGenerators/ProviderStateGeneratorTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 15/8/21. 3 | // Copyright © 2021 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | class ProviderStateGeneratorTests: XCTestCase { 23 | 24 | let sut = ExampleGenerator.ProviderStateGenerator(parameter: "test-parameter", value: "test-value") 25 | 26 | func testProviderGenerator() throws { 27 | XCTAssertEqual(sut.generator, .providerState) 28 | } 29 | 30 | func testProviderGenerator_WithExpression() throws { 31 | let valueResult = try XCTUnwrap((sut.value as Any) as? String) 32 | XCTAssertEqual(valueResult, "test-value") 33 | 34 | let attributes = try XCTUnwrap(sut.rules) 35 | XCTAssertTrue(attributes.contains { key, _ in 36 | key == "expression" 37 | }) 38 | } 39 | 40 | func testProviderGenerator_WithType() throws { 41 | let attributes = try XCTUnwrap(sut.rules) 42 | XCTAssertTrue(attributes.contains { key, value in 43 | key == "type" 44 | }) 45 | } 46 | 47 | func testProviderGenerator_SetsRules() throws { 48 | let result = try ExampleGeneratorTestHelpers.encodeDecode(sut.rules!) 49 | 50 | XCTAssertEqual(result.type, "ProviderState") 51 | XCTAssertEqual(result.expression, "test-parameter") 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /Tests/ExampleGenerators/RandomBooleanTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 16/9/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | class RandomBooleanTests: XCTestCase { 23 | 24 | func testBooleanExampleGenerator() { 25 | let sut = ExampleGenerator.RandomBool() 26 | XCTAssertTrue(sut.value is Bool) 27 | XCTAssertEqual(sut.generator, .bool) 28 | XCTAssertNil(sut.rules) 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /Tests/ExampleGenerators/RandomDateTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 17/9/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | class RandomDateTests: XCTestCase { 23 | 24 | func testRandomDate() { 25 | let sut = ExampleGenerator.RandomDate() 26 | 27 | XCTAssertEqual(sut.generator, .date) 28 | XCTAssertNil(sut.rules) 29 | XCTAssertNotNil(DateHelper.dateFrom(isoString: try XCTUnwrap(sut.value as? String), isoFormat: [.withFullDate, .withDashSeparatorInDate])) 30 | } 31 | 32 | func testRandomDate_WithFormat() throws { 33 | let testFormat = "dd-MM-yyyy" 34 | let sut = ExampleGenerator.RandomDate(format: testFormat) 35 | 36 | let attributes = try XCTUnwrap(sut.rules) 37 | XCTAssertTrue(attributes.contains { key, _ in 38 | key == "format" 39 | }) 40 | XCTAssertEqual(sut.generator, .date) 41 | XCTAssertNotNil(DateHelper.dateFrom(string: try XCTUnwrap(sut.value as? String), format: testFormat)) 42 | } 43 | 44 | func testRandomDate_SetsRules() throws { 45 | let testFormat = "dd-MM-yyyy" 46 | let sut = ExampleGenerator.RandomDate(format: testFormat) 47 | let result = try ExampleGeneratorTestHelpers.encodeDecode(sut.rules!) 48 | 49 | XCTAssertEqual(result.format, testFormat) 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /Tests/ExampleGenerators/RandomDateTimeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 17/9/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | class RandomDateTimeTests: XCTestCase { 23 | 24 | func testRandomDateTime() { 25 | let sut = ExampleGenerator.RandomDateTime() 26 | 27 | XCTAssertEqual(sut.generator, .dateTime) 28 | XCTAssertNil(sut.rules) 29 | XCTAssertNotNil(DateHelper.dateFrom(isoString: try XCTUnwrap(sut.value as? String), isoFormat: [.withFullDate, .withFullTime])) 30 | } 31 | 32 | func testRandomDateTime_WithFormat() throws { 33 | let testFormat = "yyyy/MM/dd - HH:mm:ss.S" 34 | let sut = ExampleGenerator.RandomDateTime(format: testFormat) 35 | 36 | let attributes = try XCTUnwrap(sut.rules) 37 | XCTAssertTrue(attributes.contains { key, _ in 38 | key == "format" 39 | }) 40 | XCTAssertEqual(sut.generator, .dateTime) 41 | XCTAssertNotNil(DateHelper.dateFrom(string: try XCTUnwrap(sut.value as? String), format: testFormat)) 42 | } 43 | 44 | func testRandomDateTime_SetsRules() throws { 45 | let testFormat = "yyyy/MM/dd - HH:mm:ss.S" 46 | let sut = ExampleGenerator.RandomDateTime(format: testFormat) 47 | let result = try ExampleGeneratorTestHelpers.encodeDecode(sut.rules!) 48 | 49 | XCTAssertEqual(result.format, testFormat) 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /Tests/ExampleGenerators/RandomDecimalTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 17/9/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | class RandomDecimalTests: XCTestCase { 23 | 24 | func testRandomDecimal() throws { 25 | let sut = ExampleGenerator.RandomDecimal() 26 | 27 | let attributes = try XCTUnwrap(sut.rules) 28 | XCTAssertTrue(attributes.contains { key, _ in 29 | key == "digits" 30 | }) 31 | XCTAssertEqual(sut.generator, .decimal) 32 | let decimalValue = try XCTUnwrap(sut.value as? Decimal) 33 | XCTAssertEqual(String(describing: decimalValue).count, 6) 34 | } 35 | 36 | func testRandomDecimal_WithDigits() throws { 37 | let sut = ExampleGenerator.RandomDecimal(digits: 12) 38 | 39 | let attributes = try XCTUnwrap(sut.rules) 40 | XCTAssertTrue(attributes.contains { key, _ in 41 | key == "digits" 42 | }) 43 | XCTAssertEqual(sut.generator, .decimal) 44 | let decimalValue = try XCTUnwrap(sut.value as? Decimal) 45 | 46 | // Expecting 9 digits as it's the set as the cap in ExampleGenerator.Decimal 47 | XCTAssertEqual(String(describing: decimalValue).count, 9) 48 | } 49 | 50 | func testRandomDecimal_SetsRules() throws { 51 | let sut = ExampleGenerator.RandomDecimal(digits: 12) 52 | let result = try ExampleGeneratorTestHelpers.encodeDecode(sut.rules!) 53 | 54 | // Expecting a key `digits` with value 9 55 | XCTAssertEqual(result.digits, 9) 56 | } 57 | 58 | } 59 | 60 | -------------------------------------------------------------------------------- /Tests/ExampleGenerators/RandomHexadecimalTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 17/9/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | class RandomHexadecimalTests: XCTestCase { 23 | 24 | func testRandomHexadecimal() throws { 25 | let sut = ExampleGenerator.RandomHexadecimal() 26 | 27 | XCTAssertEqual(sut.generator, .hexadecimal) 28 | 29 | let attributes = try XCTUnwrap(sut.rules) 30 | XCTAssertTrue(attributes.contains { key, _ in 31 | key == "digits" 32 | }) 33 | 34 | let hexValue = try XCTUnwrap(sut.value as? String) 35 | XCTAssertEqual(hexValue.count, 8) 36 | } 37 | 38 | func testRandomHexadecimal_WithDigits() throws { 39 | let sut = ExampleGenerator.RandomHexadecimal(digits: 16) 40 | 41 | XCTAssertEqual(sut.generator, .hexadecimal) 42 | 43 | let attributes = try XCTUnwrap(sut.rules) 44 | XCTAssertTrue(attributes.contains { key, _ in 45 | key == "digits" 46 | }) 47 | 48 | let hexValue = try XCTUnwrap(sut.value as? String) 49 | XCTAssertEqual(hexValue.count, 16) 50 | } 51 | 52 | func testRandomHexadecimal_SetsRules() throws { 53 | let sut = ExampleGenerator.RandomHexadecimal(digits: 16) 54 | let result = try ExampleGeneratorTestHelpers.encodeDecode(sut.rules!) 55 | 56 | // Expecting a key `digits` with value 16 57 | XCTAssertEqual(result.digits, 16) 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /Tests/ExampleGenerators/RandomIntTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 16/9/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | class RandomIntTests: XCTestCase { 23 | 24 | func testRandomIntExampleGenerator() throws { 25 | let expectedKeys = ["min", "max"] 26 | let sut = ExampleGenerator.RandomInt(min: -4231, max: 64210) 27 | 28 | let attributes = try XCTUnwrap(sut.rules) 29 | XCTAssertTrue((sut.value as Any) is Int) 30 | XCTAssertEqual(sut.generator, .int) 31 | XCTAssertTrue(attributes.allSatisfy { key, value in expectedKeys.contains(key) }) 32 | XCTAssertTrue((-4231...64210).contains(sut.value as! Int)) 33 | } 34 | 35 | func testRandomInt_SetsRules() throws { 36 | let sut = ExampleGenerator.RandomInt(min: -4231, max: 2147483647) 37 | let result = try ExampleGeneratorTestHelpers.encodeDecode(sut.rules!) 38 | 39 | XCTAssertEqual(result.min, -4231) 40 | XCTAssertEqual(result.max, 2147483647) 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /Tests/ExampleGenerators/RandomStringTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 18/9/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | class RandomStringTests: XCTestCase { 23 | 24 | func testRandomString() throws { 25 | let sut = ExampleGenerator.RandomString() 26 | 27 | let attributes = try XCTUnwrap(sut.rules) 28 | XCTAssertTrue(attributes.contains { key, _ in 29 | key == "size" 30 | }) 31 | XCTAssertEqual(sut.generator, .string) 32 | let stringValue = try XCTUnwrap(sut.value as? String) 33 | XCTAssertEqual(stringValue.count, 20) 34 | } 35 | 36 | func testRandomString_WithSize() throws { 37 | let sut = ExampleGenerator.RandomString(size: 1145) 38 | 39 | let attributes = try XCTUnwrap(sut.rules) 40 | XCTAssertTrue(attributes.contains { key, _ in 41 | key == "size" 42 | }) 43 | XCTAssertEqual(sut.generator, .string) 44 | let stringValue = try XCTUnwrap(sut.value as? String) 45 | XCTAssertEqual(stringValue.count, 1145) 46 | } 47 | 48 | func testRandomRegex() throws { 49 | let sut = ExampleGenerator.RandomString(regex: #"\d{1,2}/\d{1,2}"#) 50 | 51 | let attributes = try XCTUnwrap(sut.rules) 52 | XCTAssertTrue(attributes.contains { key, _ in 53 | key == "regex" 54 | }) 55 | 56 | XCTAssertEqual(sut.generator, .regex) 57 | } 58 | 59 | func testRandomString_SetsSizeRules() throws { 60 | let sut = ExampleGenerator.RandomString(size: 20) 61 | let result = try ExampleGeneratorTestHelpers.encodeDecode(sut.rules!) 62 | 63 | XCTAssertEqual(result.size, 20) 64 | } 65 | 66 | func testRandomString_SetsRegexRules() throws { 67 | let regex = #"\d{1,2}/\d{1,2}"# 68 | let sut = ExampleGenerator.RandomString(regex: regex) 69 | let result = try ExampleGeneratorTestHelpers.encodeDecode(sut.rules!) 70 | 71 | XCTAssertEqual(result.regex, regex) 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /Tests/ExampleGenerators/RandomTimeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 17/9/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | class RandomTimeTests: XCTestCase { 23 | 24 | func testRandomTime() throws { 25 | let sut = ExampleGenerator.RandomTime() 26 | 27 | XCTAssertEqual(sut.generator, .time) 28 | XCTAssertNil(sut.rules) 29 | let isoTime = try XCTUnwrap(sut.value as? String) 30 | XCTAssertNotNil(DateHelper.dateFrom(isoString: isoTime, isoFormat: [.withFullTime])) 31 | } 32 | 33 | func testRandomTime_WithFormat() throws { 34 | let testFormat = "HH:mm" 35 | let sut = ExampleGenerator.RandomTime(format: testFormat) 36 | 37 | let attributes = try XCTUnwrap(sut.rules) 38 | XCTAssertTrue(attributes.contains { key, _ in 39 | key == "format" 40 | }) 41 | XCTAssertEqual(sut.generator, .time) 42 | XCTAssertNotNil(DateHelper.dateFrom(string: try XCTUnwrap(sut.value as? String), format: testFormat)) 43 | } 44 | 45 | func testRandomTime_SetsRules() throws { 46 | let testFormat = "HH:mm" 47 | let sut = ExampleGenerator.RandomTime(format: testFormat) 48 | let result = try ExampleGeneratorTestHelpers.encodeDecode(sut.rules!) 49 | 50 | XCTAssertEqual(result.format, testFormat) 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /Tests/ExampleGenerators/RandomUuidTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 16/9/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | class RandomUUIDTests: XCTestCase { 23 | 24 | func testRandomUUIDExampleGenerator() throws { 25 | let sut = ExampleGenerator.RandomUUID() 26 | 27 | XCTAssertNotNil(UUID(uuidString: try XCTUnwrap(sut.value as? String))) 28 | XCTAssertEqual(sut.generator, .uuid) 29 | XCTAssertNotNil(sut.rules) 30 | } 31 | 32 | func testRandomUUIDDefaultFormat() throws { 33 | let sut = ExampleGenerator.RandomUUID() 34 | 35 | let uuid = try XCTUnwrap(sut.value as? String) 36 | XCTAssertEqual(uuid.count, 36) 37 | 38 | let result = try ExampleGeneratorTestHelpers.encodeDecode(sut.rules!) 39 | XCTAssertEqual(result.format, "upper-case-hyphenated") 40 | } 41 | 42 | func testRandomUUIDUpperCaseHyphenatedFormat() throws { 43 | let sut = ExampleGenerator.RandomUUID(format: .uppercaseHyphenated) 44 | 45 | let uuid = try XCTUnwrap(sut.value as? String) 46 | XCTAssertEqual(uuid.count, 36) 47 | 48 | let result = try ExampleGeneratorTestHelpers.encodeDecode(sut.rules!) 49 | XCTAssertEqual(result.format, "upper-case-hyphenated") 50 | } 51 | 52 | func testRandomUUIDSimpleFormat() throws { 53 | let sut = ExampleGenerator.RandomUUID(format: .simple) 54 | 55 | let uuid = try XCTUnwrap(sut.value as? String) 56 | XCTAssertEqual(uuid.count, 32) 57 | 58 | let result = try ExampleGeneratorTestHelpers.encodeDecode(sut.rules!) 59 | XCTAssertEqual(result.format, "simple") 60 | } 61 | 62 | func testRandomUUIDLowerCaseHyphenatedFormat() throws { 63 | let sut = ExampleGenerator.RandomUUID(format: .lowercaseHyphenated) 64 | 65 | let uuid = try XCTUnwrap(sut.value as? String) 66 | XCTAssertEqual(uuid.count, 36) 67 | 68 | let result = try ExampleGeneratorTestHelpers.encodeDecode(sut.rules!) 69 | XCTAssertEqual(result.format, "lower-case-hyphenated") 70 | } 71 | 72 | func testRandomUUIDURNFormat() throws { 73 | let sut = ExampleGenerator.RandomUUID(format: .urn) 74 | 75 | let uuid = try XCTUnwrap(sut.value as? String) 76 | XCTAssertEqual(uuid.prefix(9), "urn:uuid:") 77 | 78 | let result = try ExampleGeneratorTestHelpers.encodeDecode(sut.rules!) 79 | XCTAssertEqual(result.format, "URN") 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /Tests/Extensions/String+PactSwiftTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 7/8/21. 3 | // Copyright © 2021 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | class StringExtensionTests: XCTestCase { 23 | 24 | func testConvertsSimpleUUID() { 25 | XCTAssertEqual("1234abcd1234abcf12ababcdef1234567".uuid, UUID(uuidString: "1234abcd-1234-abcf-12ab-abcdef1234567")) 26 | } 27 | 28 | func testInvalidStringUUIDIsNil() { 29 | XCTAssertNil("a".uuid) 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /Tests/Matchers/DecimalLikeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 11/4/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | class DecimalLikeTests: XCTestCase { 23 | 24 | func testMatcher_DecimalLike_InitsWithValue() throws { 25 | let testResult = try XCTUnwrap((Matcher.DecimalLike(1234).value as Any) as? Decimal) 26 | XCTAssertEqual(testResult, 1234) 27 | 28 | let testDecimalResult = try XCTUnwrap((Matcher.DecimalLike(1234.56).value as Any) as? Decimal) 29 | XCTAssertEqual(testDecimalResult, 1234.56) 30 | } 31 | 32 | func testMatcher_DecimalLike_SetsRules() throws { 33 | let sut = Matcher.DecimalLike(Decimal(1234)) 34 | let result = try MatcherTestHelpers.encodeDecode(sut.rules) 35 | 36 | XCTAssertEqual(result.first?.match, "decimal") 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /Tests/Matchers/EachKeyLikeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 3/4/2022. 3 | // Copyright © 2022 PACT Foundation. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | class EachKeyLikeTests: XCTestCase { 23 | 24 | func testMatcher_EachKeyLike_InitsWithStringValue() throws { 25 | let sut = try XCTUnwrap(Matcher.EachKeyLike("bar").value as? String) 26 | XCTAssertEqual(sut, "bar") 27 | } 28 | 29 | func testMatcher_EachKeyLike_InitsWithIntValue() throws { 30 | let sut = try XCTUnwrap(Matcher.EachKeyLike(123).value as? Int) 31 | XCTAssertEqual(sut, 123) 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /Tests/Matchers/EqualToTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 10/9/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | class EqualToTests: XCTestCase { 23 | 24 | func testMatcher_Equal_InitsWithToString() throws { 25 | XCTAssertEqual(try XCTUnwrap(Matcher.EqualTo("TestValue").value as? String), "TestValue") 26 | } 27 | 28 | func testMatcher_Equal_InitsWithToInt() throws { 29 | XCTAssertEqual(try XCTUnwrap(Matcher.EqualTo(32).value as? Int), Int(32)) 30 | } 31 | 32 | func testMatcher_EqualTo_InitsWithDouble() throws { 33 | XCTAssertEqual(try XCTUnwrap(Matcher.EqualTo(128.32).value as? Double), Double(128.32)) 34 | } 35 | 36 | func testMatcher_EqualTo_InitsWithArrayOfStrings() throws { 37 | XCTAssertEqual(try XCTUnwrap(Matcher.EqualTo(["TestValue", "Teapot"]).value as? [String]), ["TestValue", "Teapot"]) 38 | } 39 | 40 | func testMatcher_EqualTo_InitsWithDecimal() throws { 41 | XCTAssertEqual(try XCTUnwrap(Matcher.EqualTo(Decimal(123.45)).value as? Decimal), Decimal(123.45)) 42 | } 43 | 44 | func testMatcher_EqualTo_SetsRules() throws { 45 | let sut = Matcher.EqualTo("test") 46 | let result = try MatcherTestHelpers.encodeDecode(sut.rules) 47 | 48 | XCTAssertEqual(result.first?.match, "equality") 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /Tests/Matchers/FromProviderStateTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 15/8/21. 3 | // Copyright © 2021 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | class FromProviderStateTests: XCTestCase { 23 | 24 | func testMatcher_FromProviderState_InitsWithValue() throws { 25 | let testStringResult = try XCTUnwrap((Matcher.FromProviderState(parameter: "testParameter", value: .string("some-string")).value as Any) as? String) 26 | XCTAssertEqual(testStringResult, "some-string") 27 | 28 | let testIntResult = try XCTUnwrap((Matcher.FromProviderState(parameter: "testParameter", value: .int(100)).value as Any) as? Int) 29 | XCTAssertEqual(testIntResult, 100) 30 | 31 | let testDecimalResult = try XCTUnwrap((Matcher.FromProviderState(parameter: "testParameter", value: .decimal(Decimal(123.45))).value as Any) as? Decimal) 32 | XCTAssertEqual(testDecimalResult, Decimal(123.45)) 33 | 34 | let testBoolResult = try XCTUnwrap((Matcher.FromProviderState(parameter: "testParameter", value: .bool(true)).value as Any) as? Bool) 35 | XCTAssertEqual(testBoolResult, true) 36 | } 37 | 38 | func testMatcher_FromProviderState_InitsWithparameter() { 39 | let testParameterResult = Matcher.FromProviderState(parameter: "testParameter", value: .int(100)).parameter 40 | XCTAssertEqual(testParameterResult, "testParameter") 41 | } 42 | 43 | func testMatcher_FromProviderState_SetsRules() throws { 44 | let sut = Matcher.FromProviderState(parameter: "test", value: .string("value")) 45 | let result = try MatcherTestHelpers.encodeDecode(sut.rules) 46 | 47 | XCTAssertEqual(result.first?.match, "type") 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /Tests/Matchers/IncludesLikeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 26/5/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | class IncludesLikeTests: XCTestCase { 23 | 24 | func testInitsWith_ArrayArgument() throws { 25 | let testResult = Matcher.IncludesLike(["Foo", "Bar"], combine: .AND) 26 | 27 | XCTAssertEqual(testResult.rules.count, 2) 28 | XCTAssertEqual(try XCTUnwrap((testResult.value as Any) as? String), "Foo Bar") 29 | } 30 | 31 | func testInitsWith_VariadicArgument() throws { 32 | let testResult = Matcher.IncludesLike("Foo", "Bar", "Baz", combine: .OR) 33 | 34 | XCTAssertEqual(testResult.rules.count, 3) 35 | XCTAssertEqual(testResult.combine, .OR) 36 | XCTAssertEqual(try XCTUnwrap((testResult.value as Any) as? String), "Foo Bar Baz") 37 | } 38 | 39 | func testInitsWith_ArrayArgument_AndGeneratedValue() throws { 40 | let testResult = Matcher.IncludesLike(["I'm", "Teapot"], combine: .AND, generate: "I'm a little Teapot") 41 | 42 | XCTAssertEqual(testResult.rules.count, 2) 43 | XCTAssertEqual(testResult.combine, .AND) 44 | XCTAssertEqual(try XCTUnwrap((testResult.value as Any) as? String), "I'm a little Teapot") 45 | } 46 | 47 | func testInitsWith_VariadicArgument_AndGeneratedValue() throws { 48 | let testResult = Matcher.IncludesLike("Teapot", "I'm", combine: .AND, generate: "I'm a big Teapot") 49 | 50 | XCTAssertEqual(testResult.rules.count, 2) 51 | XCTAssertEqual(testResult.combine, .AND) 52 | XCTAssertEqual(try XCTUnwrap((testResult.value as Any) as? String), "I'm a big Teapot") 53 | } 54 | 55 | func testMatcher_IncludesLike_SetsRules() throws { 56 | let sut = Matcher.IncludesLike("Teapot", "I'm", combine: .AND, generate: "I'm a big Teapot") 57 | let result = try MatcherTestHelpers.encodeDecode(sut.rules) 58 | 59 | XCTAssertTrue(result.allSatisfy { $0.match == "include" }) 60 | XCTAssertTrue(result.allSatisfy { encodedModel in 61 | ["Teapot", "I'm"].contains(encodedModel.value) 62 | }) 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /Tests/Matchers/IntegerLikeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 11/4/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | class IntegerLikeTests: XCTestCase { 23 | 24 | func testMatcher_IntegerLike_InitsWithValue() throws { 25 | let testResult = try XCTUnwrap((Matcher.IntegerLike(1234).value as Any) as? Int) 26 | XCTAssertEqual(testResult, 1234) 27 | } 28 | 29 | func testMatcher_IntegerLike_SetsRules() throws { 30 | let sut = Matcher.IntegerLike(123) 31 | let result = try MatcherTestHelpers.encodeDecode(sut.rules) 32 | 33 | XCTAssertEqual(result.first?.match, "integer") 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Tests/Matchers/MatchNullTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MatchNullTests.swift 3 | // PactSwift 4 | // 5 | // Created by Marko Justinek on 9/10/20. 6 | // Copyright © 2020 Marko Justinek. All rights reserved. 7 | // 8 | 9 | import XCTest 10 | 11 | @testable import PactSwift 12 | 13 | class MatchNullTests: XCTestCase { 14 | 15 | func testMatcher_MatchNull() throws { 16 | let matcherValue = try XCTUnwrap((Matcher.MatchNull().value as Any) as? String) 17 | XCTAssertEqual(matcherValue, "pact_matcher_null") 18 | 19 | let matcherRules = try XCTUnwrap(Matcher.MatchNull().rules.first) 20 | XCTAssertTrue(matcherRules.contains { key, value in 21 | key == "match" 22 | }) 23 | } 24 | 25 | func testMatcher_MatchNull_SetsRules() throws { 26 | let sut = Matcher.MatchNull() 27 | let result = try MatcherTestHelpers.encodeDecode(sut.rules) 28 | 29 | XCTAssertEqual(result.first?.match, "null") 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /Tests/Matchers/RegexLikeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 11/4/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | class RegexLikeTests: XCTestCase { 23 | 24 | func testMatcher_RegexLike_InitsWithValue() throws { 25 | let testResult = try XCTUnwrap(( Matcher.RegexLike(value: "2020-11-04", pattern: "\\d{4}-\\d{2}-\\d{2}").value as Any) as? String) 26 | XCTAssertEqual(testResult, "2020-11-04") 27 | } 28 | 29 | func testMatcher_RegexLike_SetsRules() throws { 30 | let sut = Matcher.RegexLike(value: "2020-11-04", pattern: "\\d{4}-\\d{2}-\\d{2}") 31 | let result = try MatcherTestHelpers.encodeDecode(sut.rules) 32 | 33 | XCTAssertEqual(result.first?.match, "regex") 34 | XCTAssertEqual(result.first?.regex, #"\d{4}-\d{2}-\d{2}"#) 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /Tests/Matchers/SomethingLikeTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 11/4/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | class SomethingLikeTests: XCTestCase { 23 | 24 | func testMatcher_SomethingLike_InitsWithValue() throws { 25 | XCTAssertEqual(try XCTUnwrap((Matcher.SomethingLike("TestString").value as Any) as? String), "TestString") 26 | XCTAssertEqual(try XCTUnwrap((Matcher.SomethingLike(200).value as Any) as? Int), 200) 27 | XCTAssertEqual(try XCTUnwrap((Matcher.SomethingLike(123.45).value as Any) as? Double), 123.45) 28 | 29 | let dictResult = try XCTUnwrap((Matcher.SomethingLike(["foo": "bar"]).value as Any) as? [String: String]) 30 | XCTAssertEqual(dictResult["foo"], "bar") 31 | 32 | let testArray = [1, 3, 2] 33 | let arrayResult = try XCTUnwrap((Matcher.SomethingLike([1, 2, 3]).value as Any) as? [Int]) 34 | XCTAssertEqual(arrayResult.count, 3) 35 | XCTAssertTrue(arrayResult.allSatisfy { testArray.contains($0) }) 36 | } 37 | 38 | func testMatcher_SomethingLike_SetsRules() throws { 39 | let sut = Matcher.SomethingLike("test") 40 | let result = try MatcherTestHelpers.encodeDecode(sut.rules) 41 | 42 | XCTAssertEqual(result.first?.match, "type") 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /Tests/Model/InteractionTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 26/5/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | class InteractionTests: XCTestCase { 23 | 24 | var sut: Interaction! 25 | 26 | func testConvenienceInit_WithDescription() { 27 | sut = Interaction(description: "A test request") 28 | XCTAssertEqual(sut.interactionDescription, "A test request") 29 | } 30 | 31 | func testGivenState_WithArray() { 32 | sut = Interaction(description: "A test request with array of states") 33 | let providerState = ProviderState(description: "array exists", params: ["foo": "bar"]) 34 | let sutWithInteraction = sut.given([providerState]) 35 | 36 | XCTAssertEqual(sutWithInteraction.providerStates, [providerState]) 37 | XCTAssertEqual(sutWithInteraction.providerStates?.count, 1) 38 | } 39 | 40 | func testGivenState_WithVariadicParameter() throws { 41 | sut = Interaction(description: "A test request with states as variadic param") 42 | let oneProviderState = ProviderState(description: "array exists", params: ["foo": "bar"]) 43 | let twoProviderState = ProviderState(description: "variadic exists", params: ["bar": "baz"]) 44 | let sutWithInteraction = sut.given(oneProviderState, twoProviderState) 45 | 46 | let providerStates = try XCTUnwrap(sutWithInteraction.providerStates) 47 | XCTAssertEqual(providerStates.count, 2) 48 | XCTAssertTrue(providerStates.contains(oneProviderState)) 49 | XCTAssertTrue(providerStates.contains(twoProviderState)) 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /Tests/Model/MetadataTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 1/4/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | class MetadataTests: XCTestCase { 23 | 24 | func testMetadata_SetsPactSpecificationVersion() { 25 | XCTAssertEqual(Metadata().pactSpec.version, "3.0.0") 26 | } 27 | 28 | #if !SWIFT_PACKAGE 29 | func testMetadata_SetsPactSwiftVersion() throws { 30 | guard let expectedResult = bundleVersion() else { 31 | XCTFail("Expected version number") 32 | return 33 | } 34 | XCTAssertEqual(try XCTUnwrap(Metadata().pactSwift.version), expectedResult) 35 | } 36 | #endif 37 | 38 | } 39 | 40 | private extension MetadataTests { 41 | 42 | func bundleVersion() -> String? { 43 | #if os(iOS) 44 | return Bundle(identifier: "au.com.pact-foundation.iOS.PactSwift")?.infoDictionary?["CFBundleShortVersionString"] as? String 45 | #elseif os(macOS) 46 | return Bundle(identifier: "au.com.pact-foundation.macOS.PactSwift")?.infoDictionary?["CFBundleShortVersionString"] as? String ?? pactSwiftVersion 47 | #else 48 | return nil 49 | #endif 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /Tests/Model/PactHTTPMethodTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 29/8/21. 3 | // Copyright © 2021 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | @testable import PactSwift 20 | 21 | final class PactHTTPMehtodTests: XCTestCase { 22 | 23 | func testPactHTTPMethods() { 24 | XCTAssertEqual(PactHTTPMethod.GET.method, "get") 25 | XCTAssertEqual(PactHTTPMethod.HEAD.method, "head") 26 | XCTAssertEqual(PactHTTPMethod.POST.method, "post") 27 | XCTAssertEqual(PactHTTPMethod.PUT.method, "put") 28 | XCTAssertEqual(PactHTTPMethod.PATCH.method, "patch") 29 | XCTAssertEqual(PactHTTPMethod.DELETE.method, "delete") 30 | XCTAssertEqual(PactHTTPMethod.TRACE.method, "trace") 31 | XCTAssertEqual(PactHTTPMethod.CONNECT.method, "connect") 32 | XCTAssertEqual(PactHTTPMethod.OPTIONS.method, "options") 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /Tests/Model/PacticipantTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 1/4/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | class PacticipantTests: XCTestCase { 23 | 24 | func testPacticipant_ReturnsConsumerName() { 25 | XCTAssertEqual(Pacticipant.consumer("test_consumer").name, "test_consumer") 26 | } 27 | 28 | func testPacticipant_ReturnsProviderName() { 29 | XCTAssertEqual(Pacticipant.provider("test_provider").name, "test_provider") 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /Tests/Model/ToolboxTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ToolboxTests.swift 3 | // PactSwift 4 | // 5 | // Created by Marko Justinek on 27/10/20. 6 | // Copyright © 2020 Marko Justinek. All rights reserved. 7 | // 8 | // Permission to use, copy, modify, and/or distribute this software for any 9 | // purpose with or without fee is hereby granted, provided that the above 10 | // copyright notice and this permission notice appear in all copies. 11 | // 12 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 13 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 14 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 15 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 16 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 17 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 18 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 19 | // 20 | 21 | import XCTest 22 | 23 | @testable import PactSwift 24 | 25 | class ToolboxTests: XCTestCase { 26 | 27 | func testMerge_ReturnsNil() { 28 | let testSubject = Toolbox.merge(body: nil, query: nil, header: nil, path: nil) 29 | 30 | XCTAssertNil(testSubject) 31 | } 32 | 33 | func testMerge_HandlesArguments() throws { 34 | let testBody = AnyEncodable("foo:body") 35 | let testQuery = AnyEncodable("foo:query") 36 | let testHeader = AnyEncodable("foo:header") 37 | 38 | let testSubject = Toolbox.merge(body: testBody, query: testQuery, header: testHeader, path: nil) 39 | let mergedObjectKeys = try XCTUnwrap(processAnyEncodable(object: testSubject as Any)) 40 | 41 | let expectedObjectKeys = ["body", "query", "header"] 42 | XCTAssertTrue( 43 | expectedObjectKeys.allSatisfy { value in 44 | mergedObjectKeys.contains(value) 45 | } 46 | ) 47 | } 48 | 49 | func testProcess_Throws_NonEncodable() { 50 | struct NonSupportedType { 51 | let some = "Uh oh!" 52 | } 53 | let nonSupportedType = NonSupportedType() 54 | 55 | do { 56 | _ = try Toolbox.process(element: nonSupportedType, for: .body) 57 | XCTFail("Should fail with EncodingError") 58 | } catch { 59 | XCTAssertTrue((error as Any) is EncodingError) 60 | } 61 | } 62 | 63 | } 64 | 65 | private extension ToolboxTests { 66 | 67 | func processAnyEncodable(object: Any) -> [String]? { 68 | switch object { 69 | case let dict as [String: Any]: 70 | var mergedKeys: [String] = [] 71 | for key in dict.keys { 72 | mergedKeys.append(key) 73 | } 74 | return mergedKeys 75 | default: 76 | XCTFail("Should only expect a Dictionary here as Toolbox.merge() should return it") 77 | return nil 78 | } 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /Tests/Model/TransferProtocolTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 7/8/21. 3 | // Copyright © 2021 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | #if compiler(>=5.5) 23 | @_implementationOnly import PactSwiftMockServer 24 | #else 25 | import PactSwiftMockServer 26 | #endif 27 | 28 | class TransferProtocolTests: XCTestCase { 29 | 30 | func testTransferProtocol() { 31 | XCTAssertEqual(TransferProtocol.standard.protocol, "http") 32 | XCTAssertEqual(TransferProtocol.secure.protocol, "https") 33 | } 34 | 35 | func testTransferProtocolBridge() { 36 | XCTAssertEqual(TransferProtocol.standard.bridge, PactSwiftMockServer.TransferProtocol.standard) 37 | XCTAssertEqual(TransferProtocol.secure.bridge, PactSwiftMockServer.TransferProtocol.secure) 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /Tests/Model/VersionSelectorTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 28/8/21. 3 | // Copyright © 2021 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import XCTest 19 | 20 | @testable import PactSwift 21 | 22 | final class VersionSelectorTests: XCTestCase { 23 | 24 | func testVersionSelectorInitializes() { 25 | let testSubject = VersionSelector(tag: "test-tag") 26 | 27 | XCTAssertEqual(testSubject.tag, "test-tag") 28 | XCTAssertNil(testSubject.fallbackTag) 29 | XCTAssertTrue(testSubject.latest) 30 | XCTAssertNil(testSubject.consumer) 31 | } 32 | 33 | func testVersionSelectorSetsFallbackTag() { 34 | let testSubject = VersionSelector(tag: "test-tag", fallbackTag: "fallback-tag") 35 | 36 | XCTAssertEqual(testSubject.tag, "test-tag") 37 | XCTAssertEqual(testSubject.fallbackTag, "fallback-tag") 38 | } 39 | 40 | func testVersionSelectorSetsLatest() { 41 | let testSubject = VersionSelector(tag: "test-tag", latest: false) 42 | 43 | XCTAssertFalse(testSubject.latest) 44 | } 45 | 46 | func testVersionSelectorSetsConsumer() { 47 | let testSubject = VersionSelector(tag: "test-tag", consumer: "api-consumer") 48 | 49 | XCTAssertEqual(testSubject.consumer, "api-consumer") 50 | } 51 | 52 | func testVersionSelectorJSONString() throws { 53 | let testSubject = try VersionSelector(tag: "test", fallbackTag: "main", latest: true, consumer: "api-consumer").toJSONString() 54 | 55 | XCTAssertTrue(testSubject.contains("\"tag\":\"test\"")) 56 | XCTAssertTrue(testSubject.contains("\"fallbackTag\":\"main\"")) 57 | XCTAssertTrue(testSubject.contains("\"latest\":true")) 58 | XCTAssertTrue(testSubject.contains("\"consumer\":\"api-consumer\"")) 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /Tests/Model/WIPPactsTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 28/8/21. 3 | // Copyright © 2021 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | import XCTest 18 | 19 | @testable import PactSwift 20 | 21 | final class WIPPactsTests: XCTestCase { 22 | 23 | func testWIPPactsInitializesWithDate() { 24 | let testDate = Date() 25 | let testSubject = WIPPacts(since: testDate, providerVersion: "test") 26 | 27 | XCTAssertEqual(testSubject.sinceDate, testDate) 28 | } 29 | 30 | func testWIPPactsInitializesWithProviderVersion() { 31 | let testSubject = WIPPacts(since: Date(), providerVersion: "test") 32 | 33 | XCTAssertEqual(testSubject.providerVersion, "test") 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Tests/TestHelpers/DateHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 17/9/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | enum DateHelper { 21 | 22 | static func dateFrom(isoString: String, isoFormat: ISO8601DateFormatter.Options) -> Date? { 23 | let formatter = ISO8601DateFormatter() 24 | formatter.formatOptions = isoFormat 25 | return formatter.date(from: isoString) 26 | } 27 | 28 | static func dateFrom(string: String, format: String) -> Date? { 29 | let formatter = DateFormatter() 30 | formatter.dateFormat = format 31 | return formatter.date(from: string) 32 | } 33 | 34 | static func stringFrom(date: Date, format: String) -> String { 35 | let formatter = DateFormatter() 36 | formatter.dateFormat = format 37 | return formatter.string(from: date) 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /Tests/TestHelpers/ErrorCapture.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 20/4/20. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | 20 | @testable import PactSwift 21 | 22 | struct ErrorReceived { 23 | 24 | var message: String 25 | var file: FileString? 26 | var line: UInt? 27 | 28 | } 29 | 30 | class ErrorCapture: ErrorReportable { 31 | 32 | public var error: ErrorReceived? 33 | 34 | func reportFailure(_ message: String) { 35 | self.error = ErrorReceived(message: message, file: nil, line: nil) 36 | } 37 | 38 | func reportFailure(_ message: String, file: FileString, line: UInt) { 39 | self.error = ErrorReceived(message: message, file: file, line: line) 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /Tests/TestHelpers/ExampleGeneratorTestHelpers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 25/10/21. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | @testable import PactSwift 20 | 21 | enum ExampleGeneratorTestHelpers { 22 | 23 | /// Encodes a model containing `AnyEncodable` type and decodes the value into String? or Int? type 24 | static func encodeDecode(_ model: [String: AnyEncodable]) throws -> DecodableTypeModel { 25 | let data = try JSONEncoder().encode(EncodableModel(params: model).params) 26 | return try JSONDecoder().decode(DecodableTypeModel.self, from: data) 27 | } 28 | 29 | struct EncodableModel: Encodable { 30 | let params: [String: AnyEncodable] 31 | } 32 | 33 | struct DecodableTypeModel: Decodable { 34 | let expression: String? 35 | let digits: Int? 36 | let format: String? 37 | let max: Int? 38 | let min: Int? 39 | let regex: String? 40 | let size: Int? 41 | let type: String? 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /Tests/TestHelpers/MatcherTestHelpers.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Marko Justinek on 25/10/21. 3 | // Copyright © 2020 Marko Justinek. All rights reserved. 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 12 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR 15 | // IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | 18 | import Foundation 19 | @testable import PactSwift 20 | 21 | enum MatcherTestHelpers { 22 | 23 | /// Encodes a model containing `AnyEncodable` type and decodes the value into String type 24 | static func encodeDecode(_ model: [[String: AnyEncodable]]) throws -> [DecodableModel] { 25 | let data = try JSONEncoder().encode(EncodableModel(params: model).params) 26 | return try JSONDecoder().decode([DecodableModel].self, from: data) 27 | } 28 | 29 | struct EncodableModel: Encodable { 30 | let params: [[String: AnyEncodable]] 31 | } 32 | 33 | struct DecodableModel: Decodable { 34 | let match: String 35 | let min: Int? 36 | let max: Int? 37 | let regex: String? 38 | let value: String? 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | codecov: 2 | notify: 3 | require_ci_to_pass: yes 4 | 5 | coverage: 6 | precision: 2 7 | round: down 8 | range: "75...100" 9 | 10 | status: 11 | project: yes 12 | patch: yes 13 | changes: no 14 | 15 | ignore: 16 | - "Tests/**/*" 17 | - "Tests" 18 | 19 | parsers: 20 | gcov: 21 | branch_detection: 22 | conditional: yes 23 | loop: yes 24 | method: no 25 | macro: no 26 | 27 | comment: 28 | layout: "header, diff" 29 | behavior: default 30 | require_changes: no 31 | --------------------------------------------------------------------------------