[
  {
    "path": ".codecov.yml",
    "content": "coverage:\n  ignore:\n    - Tests/ParseSwiftTests/.*\n    - TestHost/*\n    - TestHostTV/*\n  status:\n    patch:\n      default:\n        target: auto\n    changes: false\n    project:\n      default:\n        target: 89\ncomment:\n  require_changes: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/---1-report-an-issue.md",
    "content": "---\nname: \"\\U0001F41B Report an issue\"\nabout: A feature is not working as expected.\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n### New Issue Checklist\n<!--\n    Check every following box [x] before submitting your issue.\n    Click the \"Preview\" tab for better readability.\n    Thanks for contributing to Parse Platform!\n-->\n\n- [ ] I am not disclosing a [vulnerability](https://github.com/parse-community/Parse-Swift/security/policy).\n- [ ] I am not just asking a [question](https://github.com/parse-community/.github/blob/main/SUPPORT.md).\n- [ ] I have searched through [existing issues](https://github.com/parse-community/Parse-Swift/issues?q=is%3Aissue).\n- [ ] I can reproduce the issue with the latest versions of [Parse Server](https://github.com/parse-community/parse-server/releases) and the [Parse Swift SDK](https://github.com/parse-community/Parse-Swift/releases). <!-- We don't investigate issues for outdated releases. -->\n\n### Issue Description\n<!-- What is the specific issue? -->\n\n### Steps to reproduce\n<!-- How can someone else reproduce the issue? -->\n\n### Actual Outcome\n<!-- What outcome did you get? -->\n\n### Expected Outcome\n<!-- What outcome did you expect? -->\n\n### Environment\n<!-- Be specific with versions, don't use \"latest\" or semver ranges like \"~x.y.z\" or \"^x.y.z\". -->\n\nClient\n- Parse Swift SDK version: `FILL_THIS_OUT`\n- Xcode version: `FILL_THIS_OUT`\n- Operating system (iOS, macOS, watchOS, etc.): `FILL_THIS_OUT`\n- Operating system version: `FILL_THIS_OUT`\n\nServer\n- Parse Server version: `FILL_THIS_OUT`\n- Operating system: `FILL_THIS_OUT`\n- Local or remote host (AWS, Azure, Google Cloud, Heroku, Digital Ocean, etc): `FILL_THIS_OUT`\n\nDatabase\n- System (MongoDB or Postgres): `FILL_THIS_OUT`\n- Database version: `FILL_THIS_OUT`\n- Local or remote host (MongoDB Atlas, mLab, AWS, Azure, Google Cloud, etc): `FILL_THIS_OUT`\n\n### Logs\n<!-- Include relevant logs here. -->\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/---2-feature-request.md",
    "content": "---\nname: \"\\U0001F4A1 Request a feature\"\nabout: Suggest new functionality or an enhancement of existing functionality.\ntitle: ''\nlabels: ''\nassignees: ''\n\n---\n\n### New Feature / Enhancement Checklist\n<!--\n    Check all of the following boxes [x] before submitting your issue.\n    Click the \"Preview\" tab for better readability.\n    Thanks for contributing to Parse Swift!\n-->\n\n- [ ] I am not disclosing a [vulnerability](https://github.com/parse-community/Parse-Swift/security/policy).\n- [ ] I am not just asking a [question](https://github.com/parse-community/.github/blob/main/SUPPORT.md).\n- [ ] I have searched through [existing issues](https://github.com/parse-community/Parse-Swift/issues?q=is%3Aissue).\n\n### Current Limitation\n<!-- Which current limitation is the feature or enhancement addressing? -->\n\n### Feature / Enhancement Description\n<!-- What is the concept of the functionality and how should it be implemented? -->\n\n### Example Use Case\n<!-- What is an example use case in steps (1. / 2. / 3. / etc.) that describes the functionality? -->\n\n### Alternatives / Workarounds\n<!-- Which alternatives or workarounds exist currently? -->\n\n### 3rd Party References\n<!-- Have you seen a similar functionality provided somewhere else? -->\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: 🙋🏽‍♀️ Getting help with code\n    url: https://stackoverflow.com/questions/tagged/parse-platform\n    about: Get help with code-level questions on Stack Overflow.\n  - name: 🙋 Getting general help\n    url: https://community.parseplatform.org\n    about: Get help with other questions on our Community Forum.\n"
  },
  {
    "path": ".github/pull_request_template.md",
    "content": "### New Pull Request Checklist\n<!--\n    Please check the following boxes [x] before submitting your issue.\n    Click the \"Preview\" tab for better readability.\n    Thanks for contributing to Parse Platform!\n-->\n\n- [ ] I am not disclosing a [vulnerability](https://github.com/parse-community/Parse-Swift/security/policy).\n- [ ] I am creating this PR in reference to an [issue](https://github.com/parse-community/Parse-Swift/issues?q=is%3Aissue).\n\n### Issue Description\n<!-- Add a brief description of the issue this PR solves. -->\n\nCloses: FILL_THIS_OUT\n\n### Approach\n<!-- Add a description of the approach in this PR. -->\n\n### TODOs before merging\n<!--\n    Add TODOs that need to be completed before merging this PR.\n    Delete TODOs that do not apply to this PR.\n-->\n\n- [ ] Add tests\n- [ ] Add entry to changelog\n- [ ] Add changes to documentation (guides, repository pages, in-code descriptions)\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: ci\non:\n  push:\n    branches: [ main ]\n  pull_request:\n    branches: '*'\nenv:\n  CI_XCODE_OLDEST: '/Applications/Xcode_12.5.1.app/Contents/Developer'\n  CI_XCODE_13: '/Applications/Xcode_13.4.1.app/Contents/Developer'\n  CI_XCODE_LATEST: '/Applications/Xcode_14.0.1.app/Contents/Developer'\n\njobs:\n  xcode-test-ios:\n    runs-on: macos-12\n    steps:\n    - uses: actions/checkout@v3\n    - name: Use multiple cores\n      run: defaults write com.apple.dt.XCBuild EnableSwiftBuildSystemIntegration 1\n    - name: Build-Test\n      run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -workspace Parse.xcworkspace -scheme ParseSwift\\ \\(iOS\\) -destination platform\\=iOS\\ Simulator,name\\=iPhone\\ 12\\ Pro\\ Max -derivedDataPath DerivedData -test-iterations 10 -retry-tests-on-failure clean test | xcpretty\n      env:\n          DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}\n    - name: Export code coverage\n      run: |\n        PROFDATA=$(find ./DerivedData -name 'Coverage.profdata' -type f | head -1)\n        XCTEST=$(find ./DerivedData -name '*.xctest' -type d | head -1)\n        EXEC=\"$XCTEST/Contents/MacOS/$(basename \"$XCTEST\" .xctest)\"\n        xcrun llvm-cov export -format=\"lcov\" \"$EXEC\" -instr-profile \"$PROFDATA\" > coverage.lcov\n      env:\n          DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}\n    - name: Upload coverage to Codecov\n      uses: codecov/codecov-action@v3\n      with:\n        files: coverage.lcov\n        env_vars: IOS\n        fail_ci_if_error: true\n      env:\n          DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}\n\n  xcode-test-macos:\n    runs-on: macos-12\n    steps:\n    - uses: actions/checkout@v3\n    - name: Create and set the default keychain\n      run: |\n        security create-keychain -p \"\" temporary\n        security default-keychain -s temporary\n        security unlock-keychain -p \"\" temporary\n        security set-keychain-settings -lut 7200 temporary\n    - name: Use multiple cores\n      run: defaults write com.apple.dt.XCBuild EnableSwiftBuildSystemIntegration 1\n    - name: Build-Test\n      run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -workspace Parse.xcworkspace -scheme ParseSwift\\ \\(macOS\\) -destination platform\\=macOS -derivedDataPath DerivedData -test-iterations 10 -retry-tests-on-failure clean test | xcpretty\n      env:\n          DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}\n    - name: Export code coverage\n      run: |\n        PROFDATA=$(find ./DerivedData -name 'Coverage.profdata' -type f | head -1)\n        XCTEST=$(find ./DerivedData -name '*.xctest' -type d | head -1)\n        EXEC=\"$XCTEST/Contents/MacOS/$(basename \"$XCTEST\" .xctest)\"\n        xcrun llvm-cov export -format=\"lcov\" \"$EXEC\" -instr-profile \"$PROFDATA\" > coverage.lcov\n      env:\n          DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}\n    - name: Upload coverage to Codecov\n      uses: codecov/codecov-action@v3\n      with:\n        files: coverage.lcov\n        env_vars: MACOS\n        fail_ci_if_error: true\n      env:\n          DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}\n\n  xcode-test-tvos:\n    runs-on: macos-12\n    steps:\n    - uses: actions/checkout@v3\n    - name: Use multiple cores\n      run: defaults write com.apple.dt.XCBuild EnableSwiftBuildSystemIntegration 1\n    - name: Build\n      run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -workspace Parse.xcworkspace -scheme ParseSwift\\ \\(tvOS\\) -destination platform\\=tvOS\\ Simulator,name\\=Apple\\ TV -derivedDataPath DerivedData -test-iterations 10 -retry-tests-on-failure clean test | xcpretty\n      env:\n          DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}\n    - name: Export code coverage\n      run: |\n        PROFDATA=$(find ./DerivedData -name 'Coverage.profdata' -type f | head -1)\n        XCTEST=$(find ./DerivedData -name '*.xctest' -type d | head -1)\n        EXEC=\"$XCTEST/Contents/MacOS/$(basename \"$XCTEST\" .xctest)\"\n        xcrun llvm-cov export -format=\"lcov\" \"$EXEC\" -instr-profile \"$PROFDATA\" > coverage.lcov\n      env:\n          DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}\n    - name: Upload coverage to Codecov\n      uses: codecov/codecov-action@v3\n      with:\n        files: coverage.lcov\n        env_vars: TVOS\n        fail_ci_if_error: true\n      env:\n          DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}\n\n  xcode-build-watchos:\n    runs-on: macos-12\n    steps:\n    - uses: actions/checkout@v3\n    - name: Use multiple cores\n      run: defaults write com.apple.dt.XCBuild EnableSwiftBuildSystemIntegration 1\n    - name: Build\n      run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -target ParseSwift\\ \\(watchOS\\) | xcpretty\n      env:\n          DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}\n    - name: Upload coverage to Codecov\n      uses: codecov/codecov-action@v3\n      with:\n        env_vars: WATCHOS\n      env:\n          DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}\n\n  spm-test:\n    runs-on: macos-12\n    steps:\n    - uses: actions/checkout@v3\n    - name: Create and set the default keychain\n      run: |\n        security create-keychain -p \"\" temporary\n        security default-keychain -s temporary\n        security unlock-keychain -p \"\" temporary\n        security set-keychain-settings -lut 7200 temporary\n    - name: Use multiple cores\n      run: defaults write com.apple.dt.XCBuild EnableSwiftBuildSystemIntegration 1\n    - name: Build and Test\n      run: swift test --enable-code-coverage -v\n      env:\n          DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}\n    - name: Export code coverage\n      run: |\n        BIN_PATH=$(swift build --show-bin-path)\n        XCTEST=$(find \"$BIN_PATH\" -name '*.xctest' -type d | head -1)\n        PROFDATA=$(find .build -name 'default.profdata' -type f)\n        xcrun llvm-cov export -format=\"lcov\" \"$XCTEST\" -instr-profile \"$PROFDATA\" > coverage.lcov\n      env:\n          DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}\n    - name: Upload coverage to Codecov\n      uses: codecov/codecov-action@v3\n      with:\n        files: coverage.lcov\n        env_vars: SPM\n        fail_ci_if_error: true\n      env:\n          DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}\n\n  spm-test-5_2:\n    needs: xcode-build-watchos\n    runs-on: macos-latest\n    steps:\n    - uses: actions/checkout@v3\n    - name: Build-Test\n      run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -workspace Parse.xcworkspace -scheme ParseSwift\\ \\(iOS\\) -destination platform\\=iOS\\ Simulator,name\\=iPhone\\ 11 -derivedDataPath DerivedData clean test | xcpretty\n      env:\n          DEVELOPER_DIR: ${{ env.CI_XCODE_OLDEST }}\n    - name: Export code coverage\n      run: |\n        PROFDATA=$(find ./DerivedData -name 'Coverage.profdata' -type f | head -1)\n        XCTEST=$(find ./DerivedData -name '*.xctest' -type d | head -1)\n        EXEC=\"$XCTEST/Contents/MacOS/$(basename \"$XCTEST\" .xctest)\"\n        xcrun llvm-cov export -format=\"lcov\" \"$EXEC\" -instr-profile \"$PROFDATA\" > coverage.lcov\n    - name: Upload coverage to Codecov\n      uses: codecov/codecov-action@v3\n      with:\n        files: coverage.lcov\n        env_vars: IOS_Earliest\n        fail_ci_if_error: true\n      env:\n          DEVELOPER_DIR: ${{ env.CI_XCODE_OLDEST }}\n\n  linux:\n    runs-on: ubuntu-18.04\n    steps:\n      - uses: actions/checkout@v3\n      - uses: swift-actions/setup-swift@v2\n        with:\n          swift-version: \"5\"\n      - name: Build and Test\n        run: swift test --enable-test-discovery --enable-code-coverage -v\n      - name: Prepare codecov\n        run: |\n          llvm-cov export -format=\"lcov\" .build/x86_64-unknown-linux-gnu/debug/ParseSwiftPackageTests.xctest -instr-profile .build/x86_64-unknown-linux-gnu/debug/codecov/default.profdata > info_linux.lcov\n      - name: Upload coverage to Codecov\n        uses: codecov/codecov-action@v3\n        with:\n          env_vars: LINUX\n          fail_ci_if_error: true\n          \n  windows:\n    runs-on: windows-2019\n    steps:\n      - uses: actions/checkout@v3\n      - uses: swift-actions/setup-swift@v2\n        with:\n          swift-version: \"5.5.1\"\n      - name: Build and Test\n        run: |\n          swift test --enable-test-discovery --enable-code-coverage -v\n      - name: Upload coverage to Codecov\n        uses: codecov/codecov-action@v3\n        with:\n          env_vars: WINDOWS\n          fail_ci_if_error: false\n\n  windows-latest:\n    runs-on: windows-latest\n    steps:\n      - uses: actions/checkout@v3\n      - uses: swift-actions/setup-swift@v2\n        with:\n          swift-version: \"5.6.3\"\n      - name: Build\n        run: |\n          swift build -v\n      - name: Upload coverage to Codecov\n        uses: codecov/codecov-action@v3\n        with:\n          env_vars: WINDOWSLATEST\n          fail_ci_if_error: false\n  \n  docs:\n    needs: xcode-build-watchos\n    runs-on: macos-12\n    steps:\n      - uses: actions/checkout@v3\n      - name: Use multiple cores\n        run: defaults write com.apple.dt.XCBuild EnableSwiftBuildSystemIntegration 1\n      - name: Generate Docs\n        run: set -o pipefail && env NSUnbufferedIO=YES Scripts/generate-documentation\n        env:\n          DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}\n    \n  cocoapods:\n    needs: xcode-build-watchos\n    runs-on: macos-12\n    steps:\n      - uses: actions/checkout@v3\n      - name: Use multiple cores\n        run: defaults write com.apple.dt.XCBuild EnableSwiftBuildSystemIntegration 1\n      - name: Update Framework Version\n        run: ./Scripts/update_build\n        env:\n          BUILD_VERSION: '1.8.3'\n      - name: CocoaPods\n        run: pod lib lint --allow-warnings\n        env:\n          DEVELOPER_DIR: ${{ env.CI_XCODE_13 }}\n\n  carthage:\n   needs: xcode-build-watchos\n   runs-on: macos-12\n   steps:\n     - uses: actions/checkout@v3\n     - name: Use multiple cores\n       run: defaults write com.apple.dt.XCBuild EnableSwiftBuildSystemIntegration 1\n     - name: Carthage \n       run: ./Scripts/carthage.sh build --no-skip-current --use-xcframeworks\n       env:\n          DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: release\non:\n  release:\n    types: [published]\nenv:\n  CI_XCODE_13: '/Applications/Xcode_13.4.1.app/Contents/Developer'\n  CI_XCODE_LATEST: '/Applications/Xcode_14.0.1.app/Contents/Developer'\n\njobs:\n  cocoapods:\n    runs-on: macos-12\n    steps:\n      - uses: actions/checkout@v3\n      - name: Get release version\n        run: echo \"TAG=${GITHUB_REF/refs\\/tags\\//}\" >> $GITHUB_ENV\n      - name: Use multiple cores\n        run: defaults write com.apple.dt.XCBuild EnableSwiftBuildSystemIntegration 1\n      - name: Update Framework Version\n        run: ./Scripts/update_build\n        env:\n          BUILD_VERSION: ${{ env.TAG }}\n      - name: Deploy CocoaPods\n        run: set -o pipefail && env NSUnbufferedIO=YES pod trunk push ParseSwift.podspec --allow-warnings --verbose\n        env:\n          COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}\n          DEVELOPER_DIR: ${{ env.CI_XCODE_13 }}\n\n  docs:\n    runs-on: macos-12\n    steps:\n      - uses: actions/checkout@v3\n      - name: Get release version\n        run: echo \"TAG=${GITHUB_REF/refs\\/tags\\//}\" >> $GITHUB_ENV\n      - name: Use multiple cores\n        run: defaults write com.apple.dt.XCBuild EnableSwiftBuildSystemIntegration 1\n      - name: Build and Deploy Docs\n        run: set -o pipefail && env NSUnbufferedIO=YES Scripts/update-gh-pages-documentation-site\n        env:\n          CURRENT_BRANCH_NAME: release\n          DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}\n"
  },
  {
    "path": ".gitignore",
    "content": "# Xcode\n#\n# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore\n\n## Build generated\nbuild/\nDerivedData/\n.swiftpm\ndocs/\n\n## Various settings\n*.pbxuser\n!default.pbxuser\n*.mode1v3\n!default.mode1v3\n*.mode2v3\n!default.mode2v3\n*.perspectivev3\n!default.perspectivev3\nxcuserdata/\n\n## Other\n.DS_Store\n*.moved-aside\n*.xccheckout\n*.xcscmblueprint\n\n## Obj-C/Swift specific\n*.hmap\n*.ipa\n*.dSYM.zip\n*.dSYM\n\n## Playgrounds\ntimeline.xctimeline\nplayground.xcworkspace\n\n# Swift Package Manager\n#\n# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.\n# Packages/\n# Package.pins\n.build/\n\n# CocoaPods\n#\n# We recommend against adding the Pods directory to your .gitignore. However\n# you should judge for yourself, the pros and cons are mentioned at:\n# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control\n#\n# Pods/\n\n# Carthage\n#\n# Add this line if you want to avoid checking in source code from Carthage dependencies.\n# Carthage/Checkouts\n\nCarthage/Build\n\n# fastlane\n#\n# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the\n# screenshots whenever they are needed.\n# For more information about the recommended setup visit:\n# https://docs.fastlane.tools/best-practices/source-control/#source-control\n\nfastlane/report.xml\nfastlane/Preview.html\nfastlane/screenshots\nfastlane/test_output\n"
  },
  {
    "path": ".spi.yml",
    "content": "version: 1\nbuilder:\n  configs:\n  - platform: ios\n    scheme: \"ParseSwift (iOS)\"\n  - platform: macos-spm\n    documentation_targets: [ParseSwift]\n  - platform: macos-xcodebuild\n    scheme: \"ParseSwift (macOS)\"\n  - platform: macos-xcodebuild-arm\n    scheme: \"ParseSwift (macOS)\"\n  - platform: tvos\n    scheme: \"ParseSwift (tvOS)\"\n  - platform: watchos\n    scheme: \"ParseSwift (watchOS)\"\n"
  },
  {
    "path": ".swiftlint.yml",
    "content": "disabled_rules:\n  - file_length\n  - cyclomatic_complexity\n  - function_body_length\n  - type_body_length\n  - inclusive_language\n  - comment_spacing\n  - identifier_name\nexcluded: # paths to ignore during linting. Takes precedence over `included`.\n  - Tests/ParseSwiftTests/ParseEncoderTests\n  - DerivedData\n  - .build\n  - .dependencies\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Parse-Swift Changelog\n\n### main\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.14.2...main), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/main/documentation/parseswift)\n* _Contributing to this repo? Add info about your change here to be included in the next release_\n\n### 4.14.2\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.14.1...4.14.2), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.14.2/documentation/parseswift)\n\n__Fixes__\n- Addressed an issue that prevented updating ParseObjects with saveAll ([#423](https://github.com/parse-community/Parse-Swift/pull/423)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 4.14.1\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.14.0...4.14.1), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.14.1/documentation/parseswift)\n\n__Fixes__\n- For Swift 5.5.2+ all asynchronous methods that attempt to save, create, update, or replace use the async/await version of deep saving ParseObjects. This fixes any purple warnings caused by the SDK in Xcode. Older Swift versions use the synchronous version of deep saving ([#418](https://github.com/parse-community/Parse-Swift/pull/418)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Can catch when the Parse Server throws an improper ParseError that only contains \"error\" or \"message\", but does not contain a \"code\" ([#418](https://github.com/parse-community/Parse-Swift/pull/418)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 4.14.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.13.1...4.14.0), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.14.0/documentation/parseswift)\n\n__New features__\n- Add file caching using the Parse download folder ([#416](https://github.com/parse-community/Parse-Swift/pull/416)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 4.13.1\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.13.0...4.13.1), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.13.1/documentation/parseswift)\n\n__Fixes__\n- Remove ParseFile caching due to OS not having a natural way to cache files. Instead, if developers want to access a saved ParseFile, they should check the download directory for the respective file name ([#414](https://github.com/parse-community/Parse-Swift/pull/414)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 4.13.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.12.0...4.13.0), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.13.0/documentation/parseswift)\n\n__New features__\n- Add helper methods to ParseFileTransferable protocol to assist with creating propper responses to file uploads ([#411](https://github.com/parse-community/Parse-Swift/pull/411)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Fixes__\n- Remove cached error responses when decoding errors occur ([#411](https://github.com/parse-community/Parse-Swift/pull/411)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 4.12.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.11.0...4.12.0), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.12.0/documentation/parseswift)\n\n__New features__\n- Add the ParseFileTransferable protocol for overriding the default transfer behavior for ParseFile's. Allows for direct uploads to other file storage providers ([#410](https://github.com/parse-community/Parse-Swift/pull/410)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Add the become method to ParseInstallation which allows any ParseInstallation to be copied to the current installation. This method can be used to migrate any ParseInstallation to the current installation in the Swift SDK  ([#407](https://github.com/parse-community/Parse-Swift/pull/407)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Fixes__\n- Properly get the session token from the Parse Objective-C Keychain when using ParseUser.loginUsingObjCKeychain  ([#407](https://github.com/parse-community/Parse-Swift/pull/407)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 4.11.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.10.0...4.11.0), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.11.0/documentation/parseswift)\n\n__New features__\n- Add a set method that developers can call on their ParseObjects which automatically sends updated properties to a Parse Server and merges those updates with the original ParseObject locally. The feature removes the requirement to call mergeable and implement merge(), but comes at additional computational overhead ([#406](https://github.com/parse-community/Parse-Swift/pull/406)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 4.10.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.9.3...4.10.0), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.10.0/documentation/parseswift)\n\n__New features__\n- Add a new operation method that allows developers to set a new value to a KeyPath without needing the string version of the key. Also adds the get() method to allow developers to get the unwrapped property of any ParseObject based on its KeyPath ([#403](https://github.com/parse-community/Parse-Swift/pull/403)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Add revertKeyPath() and revertObject() methods to ParseObject which allow developers to revert to original values of key paths or objects after mutating ParseObjects that already have an objectId  ([#402](https://github.com/parse-community/Parse-Swift/pull/402)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 4.9.3\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.9.2...4.9.3), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.9.3/documentation/parseswift)\n\n__Fixes__\n- When saving ParseFiles locally, files that have a directory in their filename save correctly instead of throwing an error on the client ([#399](https://github.com/parse-community/Parse-Swift/pull/399)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Default to not setting kSecUseDataProtectionKeychain to true as this can cause issues with querying the Keychain in Swift Playgrounds or other apps that cannot setup the Keychain on macOS. This behavior can be changed by setting usingDataProtectionKeychain to true when initializing the SDK ([#398](https://github.com/parse-community/Parse-Swift/pull/398)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 4.9.2\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.9.1...4.9.2), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.9.2/documentation/parseswift)\n\n__Fixes__\n- Allow fully qualified ParseSwift types to be used externally by fixing clash with module name ([#397](https://github.com/parse-community/Parse-Swift/pull/397)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 4.9.1\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.9.0...4.9.1), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.9.1/documentation/parseswift)\n\n__Fixes__\n- Corrects a memory leak where multiple Parse URLSessions can get created. Use an actor for the url session delegates to ensure thread safety when making async calls in parallel ([#394](https://github.com/parse-community/Parse-Swift/pull/394)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 4.9.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.8.0...4.9.0), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.9.0/documentation/parseswift)\n\n__New features__\n- Add methods for migrating users and installations from the Parse Objective-C SDK to the Swift SDK ([#391](https://github.com/parse-community/Parse-Swift/pull/391)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Enable query caching by using GET instead of POST. GET is now used by default. To switch back to POST, set usingPostForQuery = true when initializing the SDK which will automatically disable all query caching ([#386](https://github.com/parse-community/Parse-Swift/pull/386)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Add setAccessGroup method which allows the Parse Keychain to be shared with app extensions and iCloud accounts ([#378](https://github.com/parse-community/Parse-Swift/pull/378)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Improvements__\n- Add more details to error messages related when decoding errors occur ([#388](https://github.com/parse-community/Parse-Swift/pull/388)), thanks to [Daniel Blyth](https://github.com/dblythy).\n- Added discardableResult to allow developers to choose whether or not certain functions should return a result ([#385](https://github.com/parse-community/Parse-Swift/pull/385)), thanks to [Damian Van de Kauter](https://github.com/vdkdamian).\n\n__Fixes__\n- Ensure properties that are already saved ParseObject's are converted to Parse pointers when using saveAll ([#390](https://github.com/parse-community/Parse-Swift/pull/390)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 4.8.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.7.0...4.8.0)\n\n__New features__\n- Add ParseSpotify authentication ([#375](https://github.com/parse-community/Parse-Swift/pull/375)), thanks to [Ulaş Sancak](https://github.com/rocxteady).\n\n__Fixes__\n- Encode withinPolygon Queryconstraint correctly ([#381](https://github.com/parse-community/Parse-Swift/pull/381)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Use select for ParseLiveQuery when fields are not present ([#376](https://github.com/parse-community/Parse-Swift/pull/376)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 4.7.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.6.0...4.7.0)\n\n__New features__\n- Add support for ParseFile and beforeConnect triggers ([#376](https://github.com/parse-community/Parse-Swift/pull/376)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 4.6.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.5.0...4.6.0)\n\n__New features__\n- Add the ability to use Parse Hooks and Triggers ([#373](https://github.com/parse-community/Parse-Swift/pull/373)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Add ParseInstagram authentication ([#372](https://github.com/parse-community/Parse-Swift/pull/372)), thanks to [Ulaş Sancak](https://github.com/rocxteady).\n- Add the ability to send APN and FCM push notifications. Also adds the ability to query _PushStatus ([#371](https://github.com/parse-community/Parse-Swift/pull/371)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Add ParseSchema, ParseCLP, and ParseFieldOptions. Should only be used when using the Swift SDK on a secured server ([#370](https://github.com/parse-community/Parse-Swift/pull/370)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 4.5.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.4.0...4.5.0)\n\n__New features__\n- Add toCLLocation and toCLLocationCoordinate2D computed properties to ParseGeoPoint, deprecate toCLLocation() and toCLLocationCoordinate2D() ([#366](https://github.com/parse-community/Parse-Swift/pull/366)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Add query computed property to ParseObject ([#365](https://github.com/parse-community/Parse-Swift/pull/365)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Add macCatalyst to SPM ([#363](https://github.com/parse-community/Parse-Swift/pull/363)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Add an order() method to Query that excepts a variadic list as input ([#362](https://github.com/parse-community/Parse-Swift/pull/362)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Improvements__\n- Allow includeAll key to be sent with additional include keys. When fetching, if the include argument is specified, convert it to a Set to prevent duplicate keys from being sent to the server ([#367](https://github.com/parse-community/Parse-Swift/pull/367)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Allow LiveQuery client to be set using ParseLiveQuery.defaultClient and deprecate ParseLiveQuery.setDefault(). Show usage of deprecated code as warnings during compile time and suggest changes ([#360](https://github.com/parse-community/Parse-Swift/pull/360)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 4.4.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.3.1...4.4.0)\n\n__Improvements__\n- Drop support for Swift 5.2 as App Store requires apps to be built in Xcode 12 ([#356](https://github.com/parse-community/Parse-Swift/pull/356)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 4.3.1\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.3.0...4.3.1)\n\n__Fixes__\n- Fix links to API documentation ([#354](https://github.com/parse-community/Parse-Swift/pull/354)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 4.3.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.2.0...4.3.0)\n\n__Improvements__\n- Use DocC for documentation instead of jazzy. Improved documentation ([#350](https://github.com/parse-community/Parse-Swift/pull/350)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 4.2.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.1.0...4.2.0)\n\n__New features__\n- Add variadic QueryConstraint methods for or, nor, and ([#345](https://github.com/parse-community/Parse-Swift/pull/345)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Improvements__\n- Add clientDefault static property to ParseLiveQuery which replaces the getDefault() method. getDefault() is still avaiable, but will be deprecated in ParseSwift 5.0.0 so it is recommended to switch to defaultClient ([#342](https://github.com/parse-community/Parse-Swift/pull/342)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 4.1.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.0.1...4.1.0)\n\n__Improvements__\n- Let the OS and developer decide if app tracking authorization is required when using ParseAnalytics. ParseAnalytics can now take any Codable value in its' dimensions instead of just strings. Added a new property \"date\" to ParseAnalytics. The \"at\" property will be deprecated in ParseSwift 5.0.0, so developers should switch to \"date\". ParseAnalytics can now be properly decoded after encoding with a JSONEncoder. This is useful if ParseAnalytics need to be stored locally and sent to the server later ([#341](https://github.com/parse-community/Parse-Swift/pull/341)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 4.0.1\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.0.0...4.0.1)\n\n__Fixes__\n- Allow ParseRole's to be updated when the SDK is allowing custom objectId's ([#338](https://github.com/parse-community/Parse-Swift/pull/338)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 4.0.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/3.1.2...4.0.0)\n\n__New features__\n- Add the verifyPassword to ParseUser. This method defaults to using POST though POST is not available on the current Parse Server. Change userPost == false to use GET on older Parse Servers ([#333](https://github.com/parse-community/Parse-Swift/pull/333)), thanks to [Corey Baker](https://github.com/cbaker6).\n- (Breaking Change) Bump the SPM toolchain from 5.1 to 5.5. This is done to take advantage of features in the latest toolchain. For developers using < Xcode 13 and depending on the Swift SDK through SPM, this will cause a break. You can either upgrade your Xcode or use Cocoapods or Carthage to depend on ParseSwift ([#326](https://github.com/parse-community/Parse-Swift/pull/326)), thanks to [Corey Baker](https://github.com/cbaker6).\n- (Breaking Change) Add the ability to merge updated ParseObject's with original objects when using the .mergeable property. To do this, developers need to add an implementation of merge() to respective ParseObject's. The compiler will recommend the new originalData property be added to every ParseObject. If you used ParseObjectMutable in the past, you should remove it as it is now part of ParseObject. In addition, all ParseObject properties should be optional and every object needs to have a default initializer of init(). See the Playgrounds for recommendations on how to define a ParseObject. Look at the PR for details on why this is important when using the SDK ([#315](https://github.com/parse-community/Parse-Swift/pull/315)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Add DocC for SDK documentation ([#209](https://github.com/parse-community/Parse-Swift/pull/214)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Improvements__\n- (Breaking Change) Make ParseRelation conform to Codable and add methods to make decoded stored ParseRelations \"usable\". ParseObjects can now contain properties of ParseRelation<Self>. In addition, ParseRelations can now be made from ParseObject pointers. For ParseRole, the computed properties: users and roles, are now optional. The queryRoles property has been changed to queryRoles() to improve the handling of thrown errors ([#328](https://github.com/parse-community/Parse-Swift/pull/328)), thanks to [Corey Baker](https://github.com/cbaker6).\n- (Breaking Change) Change the following method parameter names: isUsingMongoDB -> usingMongoDB, isIgnoreCustomObjectIdConfig -> ignoringCustomObjectIdConfig, isUsingEQ -> usingEqComparator ([#321](https://github.com/parse-community/Parse-Swift/pull/321)), thanks to [Corey Baker](https://github.com/cbaker6).\n- (Breaking Change) Change the following method parameter names: isUsingMongoDB -> usingMongoDB, isIgnoreCustomObjectIdConfig -> ignoringCustomObjectIdConfig, isUsingEQ -> usingEqComparator ([#321](https://github.com/parse-community/Parse-Swift/pull/321)), thanks to [Corey Baker](https://github.com/cbaker6).\n- (Breaking Change) Change the following method parameter names: isUsingTransactions -> usingTransactions, isAllowingCustomObjectIds -> allowingCustomObjectIds, isUsingEqualQueryConstraint -> usingEqualQueryConstraint, isMigratingFromObjcSDK -> migratingFromObjcSDK, isDeletingKeychainIfNeeded -> deletingKeychainIfNeeded ([#323](https://github.com/parse-community/Parse-Swift/pull/323)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Fixes__\n- Async/await methods that return void would no throw errors received from server ([#334](https://github.com/parse-community/Parse-Swift/pull/334)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Always check for ParseError first when decoding responses from the server. Before this fix, this could cause issues depending on how calls are made from the Swift SDK ([#332](https://github.com/parse-community/Parse-Swift/pull/332)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 3.1.2\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/3.1.1...3.1.2)\n\n__Fixes__\n- Allowing building of the Swift SDK for Swift 5.5.0 and 5.5.1 re-enabling builds for Xcode 13.0 and 13.1. Note that async/await functionality is only available for Swift 5.5.2+ and Xcode 13.2+ ([#320](https://github.com/parse-community/Parse-Swift/pull/320)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Move the var score: Double? to a protocol named ParseQueryScorable. When developers want to sort by score using a matchesText QueryConstraint, they just conform their ParseObject's to ParseQueryScorable ([#319](https://github.com/parse-community/Parse-Swift/pull/319)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 3.1.1\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/3.1.0...3.1.1)\n\n__Fixes__\n- Always sort keys when using the ParseEncoder as it can cause issues when trying to save ParseObject's that have children ([#318](https://github.com/parse-community/Parse-Swift/pull/318)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 3.1.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/3.0.0...3.1.0)\n\n__New features__\n- Add the ability to explain MongoDB queries by setting usingMongoDB = true for the respective explain query ([#314](https://github.com/parse-community/Parse-Swift/pull/314)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 3.0.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.5.1...3.0.0)\n\n__New features__\n- Adds equalTo QueryConstraint along with ability to change the SDK default behavior of using $eq QueryConstraint parameter or not ([#310](https://github.com/parse-community/Parse-Swift/pull/310)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Adds isNull and isNotNull QueryConstraint along with the ability set/forceSet null using ParseOperation ([#308](https://github.com/parse-community/Parse-Swift/pull/308)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Adds auth support for GitHub, Google, and LinkedIn ([#307](https://github.com/parse-community/Parse-Swift/pull/307)), thanks to [Corey Baker](https://github.com/cbaker6).\n- (Breaking Change) Adds options to matchesText QueryConstraint along with the ability to see matching score. The compiler will recommend the new score property be added to all ParseObjects ([#306](https://github.com/parse-community/Parse-Swift/pull/306)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Adds withCount query ([#306](https://github.com/parse-community/Parse-Swift/pull/306)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Improvements__\n- (Breaking Change) Change boolean configuration parameters to match Swift conventions. The compilor should help with name changes ([#311](https://github.com/parse-community/Parse-Swift/pull/311)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Improve QueryWhere by making at a set of QueryConstraint's instead of any array. This dedupes the same constraint when encoding the query; improving the encoding speed when the same constraints are added ([#308](https://github.com/parse-community/Parse-Swift/pull/308)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 2.5.1\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.5.0...2.5.1)\n\n__Improvements__\n- Reduce call sites by having all methods with variadic arguments call their array counterparts ([#301](https://github.com/parse-community/Parse-Swift/pull/301)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Fixes__\n- Let additional headers accept [AnyHashable: Any] ([#302](https://github.com/parse-community/Parse-Swift/pull/302)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Throw .missingObjectId when missing the client detects a missing objectId instead of throwing an .unknown error ([#300](https://github.com/parse-community/Parse-Swift/pull/300)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 2.5.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.4.0...2.5.0)\n\n__New features__\n- Added create(), replace(), update(), createAll(), replaceAll(), and updateAll() to ParseObjects. Currently, update() and updateAll() are unavaivalble due to limitations of PATCH on the Parse Server ([#299](https://github.com/parse-community/Parse-Swift/pull/299)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Added convenience methods to convert ParseObject's to Pointer<ParseObject>'s for QueryConstraint's: !=, containedIn, notContainedIn, containedBy, containsAll ([#298](https://github.com/parse-community/Parse-Swift/pull/298)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 2.4.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.3.1...2.4.0)\n\n__New features__\n- Added additional methods to ParseRelation to make it easier to create and query relations ([#294](https://github.com/parse-community/Parse-Swift/pull/294)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Enable async/await for iOS13, tvOS13, watchOS6, and macOS10_15. All async/await methods are MainActor's. Requires Xcode 13.2 or above to use async/await. Not compatible with Xcode 13.0/1, will need to upgrade to 13.2+. Still works with Xcode 11/12 ([#278](https://github.com/parse-community/Parse-Swift/pull/278)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Fixes__\n- When transactions are enabled errors are now thrown from the client if the amount of objects in a transaction exceeds the batch size. An error will also be thrown if a developer attempts to save objects in a transation that has unsaved children ([#295](https://github.com/parse-community/Parse-Swift/pull/294)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 2.3.1\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.3.0...2.3.1)\n\n__Fixes__\n- Fixed an issue where querying an object did not dispatch to the proper queue which can cause app crashes ([#293](https://github.com/parse-community/Parse-Swift/pull/293)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 2.3.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.2.6...2.3.0)\n\n__New features__\n- Add a retry mechanism to the SDK that randomly (up to 3 seconds each) tries to reconnect up to 5 times. The developer can increase or reduce the amount of retries when configuring the SDK ([#291](https://github.com/parse-community/Parse-Swift/pull/291)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Add toCLLocation and toCLLocationCoordinate2D methods for easy conversion from a ParseGeoPoint object ([#287](https://github.com/parse-community/Parse-Swift/pull/287)), thanks to [Jayson Ng](https://github.com/jaysonng).\n\n__Fixes__\n- Fixed an issue where an annonymous could not be turned into a regular user using signup ([#291](https://github.com/parse-community/Parse-Swift/pull/291)), thanks to [Corey Baker](https://github.com/cbaker6).\n- The default ACL is now deleted from the keychain when a user is logged out. This previously caused an issue when logging out a user and logging in as a different user caused all objects to only have ACL permisions for the logged in user ([#291](https://github.com/parse-community/Parse-Swift/pull/291)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 2.2.6\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.2.5...2.2.6)\n\n__Fixes__\n- Use default ACL automatically on newley created ParseObject's if a default ACL is available ([#284](https://github.com/parse-community/Parse-Swift/pull/284)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 2.2.5\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.2.4...2.2.5)\n\n__Fixes__\n- Overload QueryConstraint to accept Pointer<ParseObject> ([#281](https://github.com/parse-community/Parse-Swift/pull/281)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Add checks to build for Windows ([#281](https://github.com/parse-community/Parse-Swift/pull/281)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 2.2.4\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.2.3...2.2.4)\n\n__Fixes__\n- Delete all stored Parse data and cache when isDeletingKeychainIfNeeded is true ([#280](https://github.com/parse-community/Parse-Swift/pull/280)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 2.2.3\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.2.2...2.2.3)\n\n__Fixes__\n- Improve dpcumentation ([#276](https://github.com/parse-community/Parse-Swift/pull/276)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 2.2.2\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.2.1...2.2.2)\n\n__Fixes__\n- Improve equatable comparison of QueryConstraint ([#275](https://github.com/parse-community/Parse-Swift/pull/275)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 2.2.1\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.2.0...2.2.1)\n\n__Fixes__\n- Set the default cache policy for ParseFile to the default policy set when initializing the SDK ([#274](https://github.com/parse-community/Parse-Swift/pull/274)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 2.2.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.1.0...2.2.0)\n\n__Improvements__\n- Added ability to fetch ParsePointer using async/await ([#271](https://github.com/parse-community/Parse-Swift/pull/271)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Fixes__\n- By default, do not use cache when fetching ParseObject's and ParseFile's. Developers can choose to fetch from cache if desired by passing the necessary option while fetching. Fixed a bug when the incorrect file location for a dowloaded ParseFile was being cached ([#272](https://github.com/parse-community/Parse-Swift/pull/272)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 2.1.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.0.3...2.1.0)\n\n__Improvements__\n- Make ParseUser.current, ParseInstallation.current, ParseConfig.current immutable. This prevents accidently setting to nil. When developers want to make changes, they should make mutable copies, mutate, then save ([#266](https://github.com/parse-community/Parse-Swift/pull/266)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Added the ParseObjectMutable protocol to make emptyObject more developer friendly ([#270](https://github.com/parse-community/Parse-Swift/pull/270)), thanks to [Damian Van de Kauter](https://github.com/novemTeam).\n\n\n### 2.0.3\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.0.2...2.0.3)\n\n__Fixes__\n- Async/await methods should be available for watchOS 8+ ([#265](https://github.com/parse-community/Parse-Swift/pull/265)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 2.0.2\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.0.1...2.0.2)\n\n__Improvements__\n- Add static methods for accessing encoders/decoder so developers do not have to create instances to access ([#259](https://github.com/parse-community/Parse-Swift/pull/259)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Fixes__\n- Parse ViewModels always dispatch to the main queue when updating published properties. This prevents possible issues when background async calls update properties used for views ([#260](https://github.com/parse-community/Parse-Swift/pull/260)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 2.0.1\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.0.0...2.0.1)\n\n__Fixes__\n- ParseUser should only encode email when User.current?.email is different from current user email ([#256](https://github.com/parse-community/Parse-Swift/pull/256)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 2.0.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.11.0...2.0.0)\n\n__New features__\n- Added option to delete Parse items from Keychain when the app is running for the first time  ([#254](https://github.com/parse-community/Parse-Swift/pull/254)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Improvements__\n- (Breaking Change) ParseObject's now conform to Identifiable and can be used directly with SwiftUI without additonal properties needed. Drops support for iOS 12, tvOS 12, watchOS 5, and macOS 10.13/14 ([#254](https://github.com/parse-community/Parse-Swift/pull/254)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.11.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.10.4...1.11.0)\n\n__Improvements__\n- Added `operation` for `set` and `forceSet`, used for single key updates ([#248](https://github.com/parse-community/Parse-Swift/pull/248)), thanks to [Daniel Blyth](https://github.com/dblythy) and [Corey Baker](https://github.com/cbaker6).\n- Add more detail to invalid struct errors ([#238](https://github.com/parse-community/Parse-Swift/pull/238)), thanks to [Daniel Blyth](https://github.com/dblythy).\n\n### 1.10.4\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.10.3...1.10.4)\n\n__Improvements__\n- Improve documentation for ParseObject ([#253](https://github.com/parse-community/Parse-Swift/pull/253)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.10.3\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.10.2...1.10.3)\n\n__Improvements__\n- Update documents to show new Swift 5.5 async/await methods ([#252](https://github.com/parse-community/Parse-Swift/pull/252)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.10.2\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.10.1...1.10.2)\n\n__New features__\n- Supports Swift 5.5 async/await ([#212](https://github.com/parse-community/Parse-Swift/pull/212)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Improvements__\n- Added an extension to compare a Swift Error with a single ParseError or multiple ParseErrors ([#250](https://github.com/parse-community/Parse-Swift/pull/250)), thanks to [Damian Van de Kauter](https://github.com/novemTeam).\n\n### 1.10.1\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.10.0...1.10.1)\n\n__Improvements__\n- Removes emptyObject requirement that was added in #243. Instead, has a recommendation in playgrounds on how to use emptyObject to only send select modified keys to the server ([#249](https://github.com/parse-community/Parse-Swift/pull/249)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.10.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.10...1.10.0)\n\n__Improvements__\n- (Breaking Change) Provide ParseObject property, emptyObject, that makes it easy to send only modified keys to the server. This change \"might\" be breaking depending on your implementation as it requires ParseObjects to now have an empty initializer, init() ([#243](https://github.com/parse-community/Parse-Swift/pull/243)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Fixes__\n- ParseUser should not send email if it has not been modified or else email verification is resent ([#241](https://github.com/parse-community/Parse-Swift/pull/241)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.9.10\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.9...1.9.10)\n\n__Fixes__\n- ParseInstallation cannot be retreived from Keychain after the first fun ([#236](https://github.com/parse-community/Parse-Swift/pull/236)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.9.9\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.8...1.9.9)\n\n__Fixes__\n- Saving ParseObjects with ParseFile properties now saves files on background queue ([#230](https://github.com/parse-community/Parse-Swift/pull/230)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.9.8\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.7...1.9.8)\n\n__Fixes__\n- Use a seperate Keychain for each app bundleId. This only effects macOS apps as their Keychain is handled by the OS differently. For macOS app developers only, the user who logged in last to your app will have their Keychain upgraded to the patched version. Other users/apps will either need to login again or logout then login again ([#224](https://github.com/parse-community/Parse-Swift/pull/224)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.9.7\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.6...1.9.7)\n\n__Improvements__\n- Properly allow a mixed custom objectId environment without compromising safety checks using .save(). If a developer wants to ignore the objectId checks, they need to specify ignoringCustomObjectIdConfig = true each time ([#222](https://github.com/parse-community/Parse-Swift/pull/222)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.9.6\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.5...1.9.6)\n\n__Fixes__\n- Query withinMiles and withinKilometers was not returning unsorted results when sort=false ([#219](https://github.com/parse-community/Parse-Swift/pull/219)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.9.5\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.4...1.9.5)\n\n__Improvements__\n- LiveQuery web socket connections handle URL error codes -1001 \"The request timed out\" and -1011 \"There was a bad response from the server.\" ([#217](https://github.com/parse-community/Parse-Swift/pull/217)), thanks to [Lukas Smilek](https://github.com/lsmilek1).\n\n### 1.9.4\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.3...1.9.4)\n\n__Fixes__\n- Fix LiveQuery reconnections when server disconnects. Always receive and pass connection errors to ParseLiveQuery delegate ([#211](https://github.com/parse-community/Parse-Swift/pull/211)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.9.3\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.2...1.9.3)\n\n__Improvements__\n- Ensure delegate set before resuming a ParseLiveQuery task ([#209](https://github.com/parse-community/Parse-Swift/pull/209)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.9.2\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.1...1.9.2)\n\n__Improvements__\n- ParseLiveQuery checks all states of a websocket and reacts as needed after an error ([#207](https://github.com/parse-community/Parse-Swift/pull/207)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.9.1\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.0...1.9.1)\n\n__Improvements__\n- Clear caching when a user logs out ([#198](https://github.com/parse-community/Parse-Swift/pull/198)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Close all LiveQuery connections when a user logs out ([#199](https://github.com/parse-community/Parse-Swift/pull/199)), thanks to [Corey Baker](https://github.com/cbaker6).\n- ParseLiveQuery attempts to reconnect upon disconnection error ([#204](https://github.com/parse-community/Parse-Swift/pull/204)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Make ParseFileManager public so developers can easily find the location of ParseFiles ([#205](https://github.com/parse-community/Parse-Swift/pull/205)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Fixes__\n- Fix Facebook and Twitter login setting incorrect keys ([#202](https://github.com/parse-community/Parse-Swift/pull/202)), thanks to [Daniel Blyth](https://github.com/dblythy).\n\n### 1.9.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.8.6...1.9.0)\n\n__New features__\n- (Breaking Change) Added a new type, QueryViewModel which conforms to ObservableObject. The new type serves as a view model property for any Parse Query. Simply call query.viewModel to use the view model with any SwiftUI view. QueryViewModel can be subclassed for customization. In addition, developers can create their own view models for queries by conforming to QueryObservable. LiveQuery Subscription's inherrit from QueryViewModel meaning instances of Subscription provides a single view model that publishes updates from LiveQuery events and traditional find, first, count, and aggregate queries. A breaking change is introduced for those use custom subscriptions as ParseSubscription has been renamed to QuerySubscribable ([#183](https://github.com/parse-community/Parse-Swift/pull/183)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Added a new type, CloudViewModel which conforms to ObservableObject. The new type serves as a view model property for any Cloud Code. Simply call cloud.viewModel to use the view model with any SwiftUI view. CloudViewModel can be subclassed for customization. In addition, developers can create their own view models for queries by conforming to CloudObservable ([#183](https://github.com/parse-community/Parse-Swift/pull/183)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Added two missing Parse types, ParseBytes and ParsePolygon ([#190](https://github.com/parse-community/Parse-Swift/pull/190)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Added caching of http requests along with adding additional headers. Caching and additional headers can be set when initializing the SDK. Caching can also be set per request using API.Options ([#196](https://github.com/parse-community/Parse-Swift/pull/196)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Improvements__\n- Removed CommonCrypto and now uses encoded string as a hash for child ParseObjects across all OS's ([#184](https://github.com/parse-community/Parse-Swift/pull/184)), thanks to [Corey Baker](https://github.com/cbaker6).\n- All types now conform to CustomStringConvertible ([#185](https://github.com/parse-community/Parse-Swift/pull/185)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Setting limit = 0 of a query does not query the server and instead just returns empty or no results depending on the query ([#189](https://github.com/parse-community/Parse-Swift/pull/189)), thanks to [Corey Baker](https://github.com/cbaker6).\n- ParseGeoPoint initializer now throws if geopoints are out-of-bounds instead of asserting ([#190](https://github.com/parse-community/Parse-Swift/pull/190)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Persist all properties of ParseUser and ParseInstallation to keychain so they can be accessed via current. Developers do not have to fetch the ParseUser or ParseInstlation after app restart anymore ([#191](https://github.com/parse-community/Parse-Swift/pull/191)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Fixes__\n- Fixed a bug when signing up from a ParseUser instance resulted in custom keys not being persisted to the keychain ([#187](https://github.com/parse-community/Parse-Swift/pull/187)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Fixed a bug where countExplain query result was not returned as an array  ([#189](https://github.com/parse-community/Parse-Swift/pull/189)), thanks to [Corey Baker](https://github.com/cbaker6).\n- The query withinPolygon(key: String, points: [ParseGeoPoint]) now works correctly and sends an array of doubles instead of an array of GeoPoint's ([#190](https://github.com/parse-community/Parse-Swift/pull/190)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Fixed a bug where the ParseEncoder incorrectly detects a circular dependency when two child objects are the same ([#194](https://github.com/parse-community/Parse-Swift/pull/194)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Make sure all LiveQuery socket changes are received on the correct queue to prevent threading issues ([#195](https://github.com/parse-community/Parse-Swift/pull/195)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.8.6\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.8.5...1.8.6)\n\n__Improvements__\n- Added SwiftUI query combine example to playgrounds. Skip id when encoding ParseObjects ([#181](https://github.com/parse-community/Parse-Swift/pull/181)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Persist current SDK version for migrating between versions ([#182](https://github.com/parse-community/Parse-Swift/pull/182)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.8.5\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.8.4...1.8.5)\n\n__Fixes__\n- Fixed a bug in LiveQuery when a close frame is sent from the server that resulted in closing\nall running websocket tasks instead of the particular task the request was intended for. The fix\nincludes a new delegate method named `closedSocket()` which provides the close code\nand reason the server closed the connection ([#176](https://github.com/parse-community/Parse-Swift/pull/176)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.8.4\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.8.3...1.8.4)\n\n__Fixes__\n- Switched context header X-Parse-Context to X-Parse-Cloud-Context to match server ([#170](https://github.com/parse-community/Parse-Swift/pull/170)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Fixed a bug in LiveQuery that prevented reconnecting after a connection was closed. Also added a sendPing method to LiveQuery ([#172](https://github.com/parse-community/Parse-Swift/pull/172)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.8.3\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.8.2...1.8.3)\n\n__Fixes__\n- Fixed a bug that prevented saving ParseObjects that had Pointers as properties ([#169](https://github.com/parse-community/Parse-Swift/pull/169)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.8.2\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.8.1...1.8.2)\n\n__Improvements__\n- Ensure pipeline and fields are checked when comparing queries ([#163](https://github.com/parse-community/Parse-Swift/pull/163)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Allow custom error codes to be thrown from Cloud Functions ([#165](https://github.com/parse-community/Parse-Swift/pull/165)), thanks to [Daniel Blyth](https://github.com/dblythy).\n\n### 1.8.1\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.8.0...1.8.1)\n\n__Improvements__\n- Append instead of replace when using query select, exclude, include, and fields ([#155](https://github.com/parse-community/Parse-Swift/pull/155)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Fixes__\n- Transactions currently do not work when using MongoDB(postgres does work) on the parse-server. Internal use of transactions are disabled by default. If you want the Swift SDK to use transactions internally, you need to set isUsingTransactionsInternally=true when configuring the client. It is recommended not to use transactions if you are using MongoDB until it is fixed on the server ([#158](https://github.com/parse-community/Parse-Swift/pull/158)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.8.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.7.2...1.8.0)\n\n__New features__\n- Add ParseAnalytics. Requires app tracking authorization in latest OS's ([#147](https://github.com/parse-community/Parse-Swift/pull/147)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Improvements__\n- Adds the ability to directly use == as a QueryConstraint on a field that's a ParseObject ([#147](https://github.com/parse-community/Parse-Swift/pull/147)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Future proof SDK by always sending client version header. Also added http method PATCH to API for future use ([#146](https://github.com/parse-community/Parse-Swift/pull/146)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Fixes__\n- Fixed an error that occured when deleting a ParseFile which resulted in the file being downloaded locally ([#147](https://github.com/parse-community/Parse-Swift/pull/147)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.7.2\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.7.1...1.7.2)\n\n__New features__\n- Added ability to send context with object by specifying it within options ([#140](https://github.com/parse-community/Parse-Swift/pull/140)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Fixes__\n- ParseFiles cannot be updated from the client and will now throw an error if attempted. Instead another file should be created and the older file should be deleted by the developer. ([#144](https://github.com/parse-community/Parse-Swift/pull/144)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Fixed issue where Swift SDK prevented fetching of Parse objects when custom objectId was enabled ([#139](https://github.com/parse-community/Parse-Swift/pull/139)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Improvements__\n- Add playground example of saving Parse objects with a custom objectId ([#137](https://github.com/parse-community/Parse-Swift/pull/137)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Improved comparison of query constraints by comparing value ([#140](https://github.com/parse-community/Parse-Swift/pull/140)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.7.1\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.7.0...1.7.1)\n\n__New features__\n- Can now check the health of a Parse Server using ParseHealth. ([#134](https://github.com/parse-community/Parse-Swift/pull/134)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.7.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.6.0...1.7.0)\n\n__Improvements__\n- Add emailVerified to ParseUser. Make relative query take a QueryConstraint as an argument. Add more documentation ([#129](https://github.com/parse-community/Parse-Swift/pull/129)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.6.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.5.1...1.6.0)\n\n__Improvements__\n- Make AnyCodable internal. If developers want to use AnyCodable, AnyEncodable, or AnyDecodable for `explain` or `ParseCloud`, they should add the [AnyCodable](https://github.com/Flight-School/AnyCodable) package to their app. In addition developers can create their own type-erased wrappers or use whatever they desire ([#127](https://github.com/parse-community/Parse-Swift/pull/127)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.5.1\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.5.0...1.5.1)\n\n__Improvements__\n- Update ParseError to match server and make ParseError and ParseObject Pointer documentation public ([#125](https://github.com/parse-community/Parse-Swift/pull/125)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.5.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.4.0...1.5.0)\n\n__Improvements__\n- (Breaking Change) Aggregrate takes any Encodable type. Query planning methods are now: findExlpain, firstEplain, countExplain, etc. The distinct query now works. The client will also not throw an error anymore when attempting to delete a File and the masterKey is not available. The developer will still need to configure the server to delete the file properly ([#122](https://github.com/parse-community/Parse-Swift/pull/122)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.4.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.3.1...1.4.0)\n\n__Improvements__\n- (Breaking Change) A query hint can now be set using a method and its return type is automatically inferred. In addition, a hint can now be any Encodable type instead of just a String ([#119](https://github.com/parse-community/Parse-Swift/pull/119)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.3.1\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.3.0...1.3.1)\n\n__New features__\n- Add findAll query to find all objects ([#118](https://github.com/parse-community/Parse-Swift/pull/118)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Can now delete the iOS Objective-C SDK Keychain from app ([#118](https://github.com/parse-community/Parse-Swift/pull/118)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Migrate installationId from obj-c SDK ([#117](https://github.com/parse-community/Parse-Swift/pull/117)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Improvements__\n- Added ability to initialize SDK with ParseConfiguration. Can now update certificate pinning authorization after SDK is initializated ([#117](https://github.com/parse-community/Parse-Swift/pull/117)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.3.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.2.6...1.3.0)\n\n__Improvements__\n- (Breaking Change) No longer require dispatch to main queue when using ParseInstallation. The side effect of this is badge is no longer retrieved by the SDK. The developer should retrieve the badge count on their own and save it to `ParseInstallation` if they require badge ([#114](https://github.com/parse-community/Parse-Swift/pull/114)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Fixes__\n- (Breaking Change) Correctly saves objectId of ParseInstallation to Keychain when saving to server. Also fixes issue when using deleteAll with current ParseUser and ParseInstallation. Old installations will automatically be migrated to the new one. If you end up having issues you can delete all of the installations in your ParseDashboard that were created with Parse-Swift < 1.30. If you are not able to do this, you can all log out of devices using Parse-Swift < 1.30 and then log back in ([#116](https://github.com/parse-community/Parse-Swift/pull/116)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.2.6\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.2.5...1.2.6)\n\n__Fixes__\n- Recreate installation automatically after deletion from Keychain ([#112](https://github.com/parse-community/Parse-Swift/pull/112)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Error when linking auth types due to server not sending sessionToken ([#109](https://github.com/parse-community/Parse-Swift/pull/109)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.2.5\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.2.4...1.2.5)\n\n__Fixes__\n- Let ParseFacebook accept expiresIn parameter instead of converting to date ([#104](https://github.com/parse-community/Parse-Swift/pull/104)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.2.4\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.2.3...1.2.4)\n\n__Fixes__\n- Ensure all dates are encoded/decoded to the proper UTC time ([#103](https://github.com/parse-community/Parse-Swift/pull/103)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.2.3\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.2.2...1.2.3)\n\n__Fixes__\n- Fixed a bug that prevented custom objectIds from working ([#101](https://github.com/parse-community/Parse-Swift/pull/101)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.2.2\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.2.1...1.2.2)\n\n__New features__\n- Allow custom objectIds ([#100](https://github.com/parse-community/Parse-Swift/pull/100)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Add ParseTwitter and ParseFacebook authentication ([#97](https://github.com/parse-community/Parse-Swift/pull/97)), thanks to [Abdulaziz Alhomaidhi](https://github.com/abs8090).\n- Add build support for Android ([#90](https://github.com/parse-community/Parse-Swift/pull/90)), thanks to [jt9897253](https://github.com/jt9897253).\n\n__Fixes__\n- There was another bug after a user first logs in anonymously and then becomes a real user. The authData sent to the server was not stripped, keep the user anonymous instead of making them a real user ([#100](https://github.com/parse-community/Parse-Swift/pull/100)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.2.1\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.2.0...1.2.1)\n\n__Improvements__\n- Child objects are now automatically saved in batches using transactions. This will result in less network overhead and prevent uneccessary clean up of data on the server if a child objects throws an error while saving ([#94](https://github.com/parse-community/Parse-Swift/pull/94)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Fixes__\n- There was a bug after a user first logs in anonymously and then becomes a real user as the server sends a new sessionToken when this occurs, but the SDK used the old sessionToken, resulting in an invalid sessionToken error ([#94](https://github.com/parse-community/Parse-Swift/pull/94)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.2.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.6...1.2.0)\n\n__New features__\n- Add transaction support to batch saveAll and deleteAll ([#89](https://github.com/parse-community/Parse-Swift/pull/89)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Add modifiers to containsString, hasPrefix, hasSuffix ([#85](https://github.com/parse-community/Parse-Swift/pull/85)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Improvements__\n- (Breaking Change) Allows return types to be specified for `ParseCloud`, query `hint`, and `explain` (see playgrounds for examples). Changed functionality of synchronous `query.first()`. It use to return nil if no values are found. Now it will throw an error if none are found. ([#92](https://github.com/parse-community/Parse-Swift/pull/92)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Better error reporting when decode errors occur ([#92](https://github.com/parse-community/Parse-Swift/pull/92)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Can use a variadic version of exclude. Added examples of select and exclude query in playgrounds ([#88](https://github.com/parse-community/Parse-Swift/pull/88)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.1.6\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.5...1.1.6)\n\n__Fixes__\n- Send correct SDK version number to Parse Server ([#84](https://github.com/parse-community/Parse-Swift/pull/84)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.1.5\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.4...1.1.5)\n\n__Improvements__\n- Make it easier to use `ParseApple` ([#81](https://github.com/parse-community/Parse-Swift/pull/81)), thanks to [Corey Baker](https://github.com/cbaker6).\n- `ParseACL` improvements. Only call `ParseUser.current` when necessary ([#80](https://github.com/parse-community/Parse-Swift/pull/80)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.1.4\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.3...1.1.4)\n\n__New features__\n- LDAP authentication support ([#79](https://github.com/parse-community/Parse-Swift/pull/79)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Support for push notifications through `ParseInstallation` ([#78](https://github.com/parse-community/Parse-Swift/pull/78)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Fetch with include ([#74](https://github.com/parse-community/Parse-Swift/pull/74)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Improvements__\n- Added `ParseLiveQuery` SwiftUI example to Playgrounds ([#77](https://github.com/parse-community/Parse-Swift/pull/77)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.1.3\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.2...1.1.3)\n\n__New features__\n- SwiftUI ready! ([#73](https://github.com/parse-community/Parse-Swift/pull/73)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n__Fixes__\n- Fixes some issues with `ParseUser.logout` ([#73](https://github.com/parse-community/Parse-Swift/pull/73)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.1.2\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.1...1.1.2)\n\n__Fixes__\nInstalling via SPM crashes ([#69](https://github.com/parse-community/Parse-Swift/pull/69)), thanks to [pmmlo](https://github.com/pmmlo).\n\n### 1.1.1\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.0...1.1.1)\n\n__Fixes__\n- Expose `ParseLiveQuery` subscription properties ([#66](https://github.com/parse-community/Parse-Swift/pull/66)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.1.0\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.0.2...1.1.0)\n\n__New features__\n- Enable `ParseFile` for Linux ([#64](https://github.com/parse-community/Parse-Swift/pull/64)), thanks to [jt9897253](https://github.com/jt9897253).\n- Use a `ParseLiveQuery` subscription as a SwiftUI view model ([#65](https://github.com/parse-community/Parse-Swift/pull/65)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Idempotency support ([#62](https://github.com/parse-community/Parse-Swift/pull/62)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.0.2\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.0.0...1.0.2)\n\n__New features__\n- Linux support. See the PR for limitations ([#59](https://github.com/parse-community/Parse-Swift/pull/59)), thanks to [Corey Baker](https://github.com/cbaker6).\n\n### 1.0.0\n\n__New features__\n- Config support ([#56](https://github.com/parse-community/Parse-Swift/pull/56)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).\n- Role and Relation support. Also improved Parse operations and added examples in Playgrounds ([#54](https://github.com/parse-community/Parse-Swift/pull/54)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).\n- Added more `Query` support for distinct, aggregate, nor, containedBy, and relative time ([#54](https://github.com/parse-community/Parse-Swift/pull/54)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).\n- Annonymous and Apple login along with `ParseAuthentication` protocol for support of any adapter ([#53](https://github.com/parse-community/Parse-Swift/pull/53)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).\n- Developer side network authentication for certificate pinning. Parse-Swift can share authentication with `ParseLiveQuery` or they can use seperate ([#45](https://github.com/parse-community/Parse-Swift/pull/45)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).\n- Full LiveQuery support (min requirement: macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0) ([#45](https://github.com/parse-community/Parse-Swift/pull/45)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).\n- Support of Cloud and Job functions along with password reset and verification email request ([#43](https://github.com/parse-community/Parse-Swift/pull/43)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).\n- Add `ParseFile` support ([#40](https://github.com/parse-community/Parse-Swift/pull/40)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Add `deleteAll` to Parse objects ([#34](https://github.com/parse-community/Parse-Swift/pull/34)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Save child pointers and deep saving of objects ([#21](https://github.com/parse-community/Parse-Swift/pull/21)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Persist `ParseUser`, `ParseInstallation`, and default `ParseACL` to Keychain ([#19](https://github.com/parse-community/Parse-Swift/pull/19)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Add PrimitiveObectStore protocol that extends Keychain Store ([#13](https://github.com/parse-community/Parse-Swift/pull/13)), thanks to [Pranjal Satija](https://github.com/pranjalsatija).\n- Add `AnyCodable` support ([#12](https://github.com/parse-community/Parse-Swift/pull/12)), thanks to [Corey Baker](https://github.com/cbaker6) and [Shawn Baek](https://github.com/ShawnBaek).\n- Add Keychain storage ([#7](https://github.com/parse-community/Parse-Swift/pull/7)), thanks to [Florent Vilmart](https://github.com/flovilmart).\n- Add `ParseError`, SwiftLint, saveAll, SPM, synchronous support ([#6](https://github.com/parse-community/Parse-Swift/pull/6)), thanks to [Florent Vilmart](https://github.com/flovilmart).\n- Create Parse-Swift project, project Playground, and add Travis CI ([#1](https://github.com/parse-community/Parse-Swift/pull/1)), thanks to [Florent Vilmart](https://github.com/flovilmart).\n\n__Improvements__\n- Naming conventions and structure ([#54](https://github.com/parse-community/Parse-Swift/pull/54)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).\n- Improve network progress updates and threading ([#51](https://github.com/parse-community/Parse-Swift/pull/51)), thanks to [Corey Baker](https://github.com/cbaker6).\n- User login now uses `POST` instead of `GET` ([#45](https://github.com/parse-community/Parse-Swift/pull/45)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).\n- Dedicated Parse URLSession for more control and delegation ([#45](https://github.com/parse-community/Parse-Swift/pull/45)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).\n- Objects are batched in groups of 50 ([#43](https://github.com/parse-community/Parse-Swift/pull/43)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).\n- Add default queues to async calls ([#38](https://github.com/parse-community/Parse-Swift/pull/38)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Persist queried and fetch objects to Keychain if they match a `current` object already stored ([#34](https://github.com/parse-community/Parse-Swift/pull/34)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Improve ParseEncoder to support arrays ([#33](https://github.com/parse-community/Parse-Swift/pull/33)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Add a new ParseEncoder from Swift 5.3 open-source JSON encoder ([#21](https://github.com/parse-community/Parse-Swift/pull/21)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Full support of `ParseGeopoint` and improve querying ([#21](https://github.com/parse-community/Parse-Swift/pull/21)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).\n- Improved async networking calls ([#15](https://github.com/parse-community/Parse-Swift/pull/15)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Rename and restructure project ([#13](https://github.com/parse-community/Parse-Swift/pull/13)), thanks to [Pranjal Satija](https://github.com/pranjalsatija).\n- Update to Swift 5.0 ([#12](https://github.com/parse-community/Parse-Swift/pull/12)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Remove RESTCommand and add API.Command ([#6](https://github.com/parse-community/Parse-Swift/pull/6)), thanks to [Florent Vilmart](https://github.com/flovilmart).\n\n__Fixes__\n- Delete current installation during logout ([#52](https://github.com/parse-community/Parse-Swift/pull/52)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Parse server supports `$eq`, but this is not supported by LiveQueryServer, switched to supported ([#49](https://github.com/parse-community/Parse-Swift/pull/49)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Bug when updating a ParseObject bug where objects was accidently converted to pointers ([#48](https://github.com/parse-community/Parse-Swift/pull/48)), thanks to [Corey Baker](https://github.com/cbaker6).\n- User logout was calling the wrong endpoint ([#43](https://github.com/parse-community/Parse-Swift/pull/43)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).\n- Fix an issue where ACL was overwritten with nil ([#40](https://github.com/parse-community/Parse-Swift/pull/40)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Update Keychain during fetch. Fix synchronous bug that occured with `ParseError` was thrown ([#38](https://github.com/parse-community/Parse-Swift/pull/38)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Fix ParseEncoder bugs ([#27](https://github.com/parse-community/Parse-Swift/pull/27)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Fix async callback queue bug ([#27](https://github.com/parse-community/Parse-Swift/pull/27)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Fix bugs in ParseACL and bump minimum OS support to `.iOS(.v11), .macOS(.v10_13), .tvOS(.v11), .watchOS(.v4)` ([#19](https://github.com/parse-community/Parse-Swift/pull/19)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Fix bugs in batch and save responses ([#15](https://github.com/parse-community/Parse-Swift/pull/15)), thanks to [Corey Baker](https://github.com/cbaker6).\n- Fix Keychain tests ([#12](https://github.com/parse-community/Parse-Swift/pull/12)), thanks to [Corey Baker](https://github.com/cbaker6).\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# Contributing to the ParseSwift SDK <!-- omit in toc -->\n\n## Table of Contents <!-- omit in toc -->\n- [Contributing](#contributing)\n- [Why Contributing?](#why-contributing)\n- [Environment Setup](#environment-setup)\n  - [Setting up your local machine](#setting-up-your-local-machine)\n  - [Swift Playgrounds](#swift-playgrounds)\n  - [Please Do's](#please-dos)\n- [Pull Request](#pull-request)\n- [Evolution](#evolution)\n- [Code of Conduct](#code-of-conduct)\n\nWe really want the ParseSwift SDK to be yours, to see it grow and thrive in the open source community.\n\nIf you are not familiar with Pull Requests and want to know more about them, you can visit the [Creating a pull request](https://help.github.com/articles/creating-a-pull-request/) article. It contains detailed information about the process.\n\n## Contributing\n\nBefore you start to code, please open a [new issue](https://github.com/parse-community/Parse-Swift/issues/new/choose) to describe your idea, or search for and continue the discussion in an [existing issue](https://github.com/parse-community/Parse-Swift/issues).\n\n> ⚠️ Please do not post a security vulnerability on GitHub or in the Parse Community Forum. Instead, follow the [Parse Community Security Policy](https://github.com/parse-community/parse-server/security/policy).\n\nPlease completely fill out any templates to provide essential information about your new feature or the bug you discovered.\n\nTogether we will plan out the best conceptual approach for your contribution, so that your and our time is invested in the best possible approach. The discussion often reveals how to leverage existing features of ParseSwift SDK to reach your goal with even less effort and in a more sustainable way.\n\nWhen you are ready to code, you can find more information about opening a pull request in the [GitHub docs](https://help.github.com/articles/creating-a-pull-request/).\n\nWhether this is your first contribution or you are already an experienced contributor, the Parse Community has your back – do not hesitate to ask for help!\n\n## Why Contributing?\n\nBuy cheap, buy twice. What? No, this is not the Economics 101 class, but the same is true for contributing.\n\nThere are two ways of writing a feature or fixing a bug. Sometimes the quick solution is to just write a Cloud Code function that does what you want. Contributing by making the change directly in ParseSwift may take a bit longer, but it actually saves you much more time in the long run.\n\nConsider the benefits you get:\n\n- #### 🚀 Higher efficiency\n  Your code is examined for efficiency and interoperability with existing features by the community.\n- #### 🛡 Stronger security\n  Your code is scrutinized for bugs and vulnerabilities and automated checks help to identify security issues that may arise in the future.\n- #### 🧬 Continuous improvement\n  If your feature is used by others it is likely to be continuously improved and extended by the community.\n- #### 💝 Giving back\n  You give back to the community that contributed to make the Parse Platform become what it is today and for future developers to come.\n- #### 🧑‍🎓 Improving yourself\n  You learn to better understand the inner workings of ParseSwift, which will help you to write more efficient and resilient code for your own application.\n\nMost importantly, with every contribution you improve your skills so that future contributions take even less time and you get all the benefits above for free — easy choice, right?\n\n## Environment Setup\n\n### Setting up your local machine\n\n* [Fork](https://github.com/parse-community/Parse-Swift) this project and clone the fork on to your local machine:\n\n```sh\n$ git clone https://github.com/parse-community/Parse-Swift\n$ cd Parse-Swift # go into the clone directory\n```\n\n* Please install [SwiftLint](https://github.com/realm/SwiftLint) to ensure that your PR conforms to our coding standards:\n\n```sh\n$ brew install swiftlint\n```\n\n### Swift Playgrounds\n\nAny feature additions should work with a real Parse Server. You can experiment with features in the ParseSwift SDK by modifying the [ParseSwift Playground files](https://github.com/parse-community/Parse-Swift/tree/main/ParseSwift.playground/Pages). It is recommended to make sure your ParseSwift workspace in Xcode is set to build for `ParseSwift (macOS)` framework when using Swift Playgrounds. To configure the playgounds, you can do one of the following:\n\n* Use the pre-configured parse-server in [this repo](https://github.com/netreconlab/parse-hipaa/tree/parse-swift) which comes with docker compose files (`docker-compose up` gives you a working server) configured to connect with the ParseSwift Playgrounds. The docker comes with [Parse Dashboard](https://github.com/parse-community/parse-dashboard) and can be used with MongoDB or PostgreSQL.\n* Configure the ParseSwift Playgrounds to work with your own Parse Server by editing the configuation in [Common.swift](https://github.com/parse-community/Parse-Swift/blob/e9ba846c399257100b285d25d2bd055628b13b4b/ParseSwift.playground/Sources/Common.swift#L4-L19).\n\n### Please Do's\n\n* Take testing seriously! Aim to increase the test coverage with every pull request\n* Add/modify test files for the code you are working on in [ParseSwiftTests](https://github.com/parse-community/Parse-Swift/tree/main/Tests/ParseSwiftTests)\n* Run the tests for the file you are working on using Xcode\n* Run the tests for the whole project to make sure the code passes all tests. This can be done by running the tests in Xcode\n* Address all errors and warnings your fixes introduce as the ParseSwift SDK should have zero warnings\n* Test your additions in Swift Playgrounds and add to the Playgrounds if applicable\n* Please consider if any changes to the [docs](http://docs.parseplatform.org) are needed or add additional sections in the case of an enhancement or feature.\n\n## Pull Request\n\nFor release automation, the title of pull requests needs to be written in a defined syntax. We loosely follow the [Conventional Commits](https://www.conventionalcommits.org) specification, which defines this syntax:\n\n```\n<type>: <summary>\n```\n\nThe _type_ is the category of change that is made, possible types are:\n- `feat` - add a new feature\n- `fix` - fix a bug\n- `refactor` - refactor code without impact on features or performance\n- `docs` - add or edit code comments, documentation, GitHub pages\n- `style` - edit code style\n- `build` - retry failing build and anything build process related\n- `perf` - performance optimization\n- `ci` - continuous integration\n- `test` - tests\n\nThe _summary_ is a short change description in present tense, not capitalized, without period at the end. This summary will also be used as the changelog entry.\n- It must be short and self-explanatory for a reader who does not see the details of the full pull request description\n- It must not contain abbreviations, e.g. instead of `LQ` write `LiveQuery`\n- It must use the correct product and feature names as referenced in the documentation, e.g. instead of `Cloud Validator` use `Cloud Function validation`\n- In case of a breaking change, the summary must not contain duplicate information that is also in the [BREAKING CHANGE](#breaking-change) chapter of the pull request description. It must not contain a note that it is a breaking change, as this will be automatically flagged as such if the pull request description contains the BREAKING CHANGE chapter.\n\nFor example:\n\n```\nfeat: add handle to door for easy opening\n```\n\nCurrently, we are not making use of the commit _scope_, which would be written as `<type>(<scope>): <summary>`, that attributes a change to a specific part of the product.\n\n## Evolution\n\nThe ParseSwift SDK is not a port of the [Parse-SDK-iOS-OSX SDK](https://github.com/parse-community/Parse-SDK-iOS-OSX) and though some of it may feel familiar, it is not backwards compatible and is designed using [protocol oriented programming (POP) and value types](https://www.pluralsight.com/guides/protocol-oriented-programming-in-swift) instead of OOP and reference types. You can learn more about POP by watching [this](https://developer.apple.com/videos/play/wwdc2015/408/) or [that](https://developer.apple.com/videos/play/wwdc2016/419/) videos from previous WWDC's. Please see [this thread](https://github.com/parse-community/Parse-Swift/issues/3) for a detailed discussion about the intended evolution of this SDK.\n\n## Code of Conduct\n\nThis project adheres to the [Contributor Covenant Code of Conduct](https://github.com/parse-community/.github/blob/main/CODE_OF_CONDUCT.md). By participating, you are expected to honor this code.\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 Parse Community\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "MIGRATION.md",
    "content": "# Migration from Parse ObjC SDK <!-- omit in toc -->\n\nThis document describes how to migrate from the [Parse ObjC SDK](https://github.com/parse-community/Parse-SDK-iOS-OSX) to the Parse Swift SDK.\n\nℹ️ *This document is a work-in-progress. If you find information missing, please submit a pull request to help us updating this document for the benefit of others.*\n\n- [Behavioral Differences](#behavioral-differences)\n- [Known Issues](#known-issues)\n  - [Installation](#installation)\n- [Feature Comparison](#feature-comparison)\n\n# Behavioral Differences\n\n- ⚠️ Partially updating an object sends the complete object (including unchanged properties) to the server if you follow the familiar syntax from the Parse ObjC SDK or any other Parse SDK. This can have a significant impact on data transfer costs depending on your use case and architecture. All other Parse SDKs, including the Parse ObjC SDK, only send the changed properties to the server. The Parse Swift SDK requires a different syntax with additional overhead to achieve the same behavior. See [#401](https://github.com/parse-community/Parse-Swift/issues/401), [#242](https://github.com/parse-community/Parse-Swift/issues/242).\n\n  <details>\n    <summary>Code Examples</summary>\n  \n    ```swift\n    // The following examples compare how to update a saved object in the Parse ObjC SDK vs. the\n    // Parse Swift SDK. For simplicity, the examples show how to migrate synchonrous methods. If\n    // you are migrating asynchronous methods your code looks slightly differently, but the same\n    // approach applies.\n\n    // Parse ObjC SDK\n    PFObject *obj = [PFObject objectWithClassName:@\"Example\"];\n    obj[@\"key\"] = @\"value1\";\n    [obj save];\n    obj[@\"key\"] = @\"value2\";\n    [obj save];\n\n    // Parse Swift SDK - Variant 1\n    // This sends the complete object to the server when partially updating the object. This approach\n    // is not recommended as sending unchanged properties is unnecessary and therefore wastes resources.\n    struct Example: ParseObject {\n      var objectId: String?\n      var createdAt: Date?\n      var updatedAt: Date?\n      var ACL: ParseACL?\n      var originalData: Data? \n      var key: String?\n    }\n\n    let obj = Example()\n    obj.key = \"value1\"\n    obj.save()\n    obj.key = \"value2\"\n    obj.save()\n\n    // Parse Swift SDK - Variant 2\n    // This sends only the changed properties to the server. Note that `objMergable` only contains the\n    // modified properties and is missing the unchanged properties. To also contain the unchanged\n    // properties in addition to the changed properties, an additional `fetch` call on the respective\n    // object would be necessary. This aproach is not recommended as it adds an additional server\n    // request to get data that is already present locally. This is unrelated to the limitation that\n    // any Parse SDK is unaware of any object modification that is done via Cloud Code triggers.\n    struct Example: ParseObject {\n      var objectId: String?\n      var createdAt: Date?\n      var updatedAt: Date?\n      var ACL: ParseACL?\n      var originalData: Data? \n      var key: String?\n    }\n\n    let obj = Example()\n    obj.key = \"value1\"\n    obj.save()\n    var objMergable = obj.mergeable\n    objMergable.key = \"value2\"\n    objMergable.save()\n\n    // Parse Swift SDK - Variant 3\n    // This sends only the changed properties to the server. By overriding the `merge` method the\n    // `objMergable` also contains the unchanged properties of the original `obj`. This means no\n    // additional `fetch` call is needed. This is the recommned approach which corresponds the most\n    // with the behavior of the Parse ObjC SDK. Note that any change of custom properies will need\n    // to reflect in the `merge` method, otherwise `objMergable` may only partially contain the\n    // original data which leads to data inconsistencies that may be difficult to track down.\n    struct Example: ParseObject {\n      var objectId: String?\n      var createdAt: Date?\n      var updatedAt: Date?\n      var ACL: ParseACL?\n      var originalData: Data? \n      var key: String?\n\n      func merge(with object: Self) throws -> Self { \n        var updated = try mergeParse(with: object) \n        if updated.shouldRestoreKey(\\.key, original: object) { \n          updated.key = object.key \n        }\n        return updated\n      }\n    }\n\n    let obj = Example()\n    obj.key = \"value1\"\n    obj.save()\n    var objMergable = obj.mergeable\n    objMergable.key = \"value2\"\n    objMergable.save()\n    ```\n  </details>\n\n# Known Issues\n\nThe following issues are important to consider before migrating.\n\n## Installation\n\nAfter migrating an app to the Parse Swift SDK, launching the app will create a new `_Installation` object with a new `installationId`. It will appear as if the app had been uninstalled and then reinstalled, even though it was only updated with the new Parse Swift SDK.\n\nThis may be problematic if the installation object is directly referenced in your app or if it contains fields that should be maintained, like the `badge` number field for example. To address this, here are two options:\n\n  - a) Use the Parse Swift SDK *together with* the Parse ObjC SDK in your project. This way you can migrate the installation by referencing the installation's `objectId`:\n\n    ```swift\n    import Parse      // Parse ObjC SDK\n    import ParseSwift // Parse Swift SDK\n\n    let objcInstallation = PFInstallation.current()!\n    let swiftInstallation = try await Installation.become(objcInstallation.objectId!)\n    ```\n  - b) Release an update for your app which stores the installation's `objectId` somewhere. Once the app has seen a sufficient adoption, you could release an app update with only the Parse Swift SDK and use the stored `objectId` to migrate to the installation.\n\nBoth options may require a long-term migration if your existing app has many installations and until the adoption rate with either approach is high enough.\n\n# Feature Comparison\n\nThis table only lists features that are known to be available in the Parse ObjC SDK but still missing in the Swift SDK. *This table is a work-in-progress.*\n\n| Feature                     | Parse ObjC SDK                       | Parse Swift SDK                                             |\n|-----------------------------|--------------------------------------|-------------------------------------------------------------|\n| [Saving objects offline][1] | `saveEventually`, `deleteEventually` | unsupported; requires implementing a custom offline storage |\n\n[1]: https://docs.parseplatform.org/ios/guide/#saving-objects-offline\n"
  },
  {
    "path": "Package.swift",
    "content": "// swift-tools-version:5.5\n\nimport PackageDescription\n\nlet package = Package(\n    name: \"ParseSwift\",\n    platforms: [.iOS(.v13),\n                .macCatalyst(.v13),\n                .macOS(.v10_15),\n                .tvOS(.v13),\n                .watchOS(.v6)],\n    products: [\n        .library(\n            name: \"ParseSwift\",\n            targets: [\"ParseSwift\"])\n    ],\n    targets: [\n        .target(\n            name: \"ParseSwift\",\n            dependencies: []),\n        .testTarget(\n            name: \"ParseSwiftTests\",\n            dependencies: [\"ParseSwift\"],\n            exclude: [\"Info.plist\"])\n    ]\n)\n"
  },
  {
    "path": "Package@5.1.swift",
    "content": "// swift-tools-version:5.1\n\nimport PackageDescription\n\nlet package = Package(\n    name: \"ParseSwift\",\n    platforms: [.iOS(.v13),\n                .macCatalyst(.v13),\n                .macOS(.v10_15),\n                .tvOS(.v13),\n                .watchOS(.v6)],\n    products: [\n        .library(\n            name: \"ParseSwift\",\n            targets: [\"ParseSwift\"])\n    ],\n    targets: [\n        .target(\n            name: \"ParseSwift\",\n            dependencies: []),\n        .testTarget(\n            name: \"ParseSwiftTests\",\n            dependencies: [\"ParseSwift\"],\n            exclude: [\"Info.plist\"])\n    ]\n)\n"
  },
  {
    "path": "Parse.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"container:ParseSwift.xcodeproj\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "Parse.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "ParseSwift-iOS/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleDisplayName</key>\n\t<string>ParseSwift</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>FMWK</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>$(MARKETING_VERSION)</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>NSPrincipalClass</key>\n\t<string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "ParseSwift-macOS/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>FMWK</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>$(MARKETING_VERSION)</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n\t<key>NSHumanReadableCopyright</key>\n\t<string>Copyright © 2020 Parse Community. All rights reserved.</string>\n\t<key>NSPrincipalClass</key>\n\t<string></string>\n</dict>\n</plist>\n"
  },
  {
    "path": "ParseSwift-tvOS/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>$(MARKETING_VERSION)</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "ParseSwift-tvOS/ParseSwift_tvOS.h",
    "content": "//\n//  ParseSwift_tvOS.h\n//  ParseSwift-tvOS\n//\n//  Created by Corey Baker on 7/30/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n//! Project version number for ParseSwift_tvOS.\nFOUNDATION_EXPORT double ParseSwift_tvOSVersionNumber;\n\n//! Project version string for ParseSwift_tvOS.\nFOUNDATION_EXPORT const unsigned char ParseSwift_tvOSVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <ParseSwift_tvOS/PublicHeader.h>\n\n\n"
  },
  {
    "path": "ParseSwift-watchOS/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>$(MARKETING_VERSION)</string>\n\t<key>CFBundleVersion</key>\n\t<string>$(CURRENT_PROJECT_VERSION)</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "ParseSwift-watchOS/ParseSwift_watchOS.h",
    "content": "//\n//  ParseSwift_watchOS.h\n//  ParseSwift-watchOS\n//\n//  Created by Corey Baker on 7/30/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n//! Project version number for ParseSwift_watchOS.\nFOUNDATION_EXPORT double ParseSwift_watchOSVersionNumber;\n\n//! Project version string for ParseSwift_watchOS.\nFOUNDATION_EXPORT const unsigned char ParseSwift_watchOSVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <ParseSwift_watchOS/PublicHeader.h>\n\n\n"
  },
  {
    "path": "ParseSwift.playground/Pages/1 - Your first Object.xcplaygroundpage/Contents.swift",
    "content": "//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//: `My Mac` or whatever the name of your mac is. Also be sure your `Playground Settings`\n//: in the `File Inspector` is `Platform = macOS`. This is because\n//: Keychain in iOS Playgrounds behaves differently. Every page in Playgrounds should\n//: be set to build for `macOS` unless specified.\n\nimport PlaygroundSupport\nimport Foundation\nimport ParseSwift\nPlaygroundPage.current.needsIndefiniteExecution = true\n\n/*: start parse-server with\nnpm start -- --appId applicationId --clientKey clientKey --masterKey masterKey --mountPath /1\n*/\n\n//: In Xcode, make sure you are building the \"ParseSwift (macOS)\" framework.\n\ninitializeParse()\n\n//: Get current SDK version\nif let version = ParseVersion.current {\n    print(\"Current Swift SDK version is \\\"\\(version)\\\"\")\n}\n\n//: Check the health of your Parse Server.\ndo {\n    print(\"Server health is: \\(try ParseHealth.check())\")\n} catch {\n    print(error)\n}\n\n//: Create your own value typed `ParseObject`.\nstruct GameScore: ParseObject {\n    //: These are required by ParseObject\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: Your own properties.\n    var points: Int?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.points,\n                                     original: object) {\n            updated.points = object.points\n        }\n        return updated\n    }\n}\n\n//: It's recommended to place custom initializers in an extension\n//: to preserve the memberwise initializer.\nextension GameScore {\n\n    init(points: Int) {\n        self.points = points\n    }\n\n    init(objectId: String?) {\n        self.objectId = objectId\n    }\n}\n\nstruct GameData: ParseObject {\n    //: These are required by ParseObject\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: Your own properties.\n    var polygon: ParsePolygon?\n    //: `ParseBytes` needs to be a part of the original schema\n    //: or else you will need your masterKey to force an upgrade.\n    var bytes: ParseBytes?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if shouldRestoreKey(\\.polygon,\n                             original: object) {\n            updated.polygon = object.polygon\n        }\n        if shouldRestoreKey(\\.bytes,\n                             original: object) {\n            updated.bytes = object.bytes\n        }\n        return updated\n    }\n}\n\n//: It's recommended to place custom initializers in an extension\n//: to preserve the memberwise initializer.\nextension GameData {\n\n    init (bytes: ParseBytes?, polygon: ParsePolygon) {\n        self.bytes = bytes\n        self.polygon = polygon\n    }\n}\n\n//: Define initial GameScores.\nlet score = GameScore(points: 10)\nlet score2 = GameScore(points: 3)\n\n/*: Save asynchronously (preferred way) - Performs work on background\n    queue and returns to specified callbackQueue.\n    If no callbackQueue is specified it returns to main queue.\n*/\nscore.save { result in\n    switch result {\n    case .success(let savedScore):\n        assert(savedScore.objectId != nil)\n        assert(savedScore.createdAt != nil)\n        assert(savedScore.updatedAt != nil)\n        assert(savedScore.points == 10)\n\n        /*:\n         To modify, you need to make it a var as the value type\n         was initialized as immutable. Using `mergeable`\n         allows you to only send the updated keys to the\n         parse server as opposed to the whole object. Make sure\n         to call `mergeable` before you begin\n         your first mutation of your `ParseObject`.\n        */\n        var changedScore = savedScore.mergeable\n        changedScore.points = 200\n        changedScore.save { result in\n            switch result {\n            case .success(let savedChangedScore):\n                assert(savedChangedScore.points == 200)\n                assert(savedScore.objectId == savedChangedScore.objectId)\n\n            case .failure(let error):\n                assertionFailure(\"Error saving: \\(error)\")\n            }\n        }\n    case .failure(let error):\n        assertionFailure(\"Error saving: \\(error)\")\n    }\n}\n\n//: This will store the second batch score to be used later.\nvar score2ForFetchedLater: GameScore?\n\n//: Saving multiple GameScores at once.\n[score, score2].saveAll { results in\n    switch results {\n    case .success(let otherResults):\n        var index = 0\n        otherResults.forEach { otherResult in\n            switch otherResult {\n            case .success(let savedScore):\n                print(\"\"\"\n                    Saved \\\"\\(savedScore.className)\\\" with\n                    points \\(String(describing: savedScore.points)) successfully\n                \"\"\")\n                if index == 1 {\n                    score2ForFetchedLater = savedScore\n                }\n                index += 1\n            case .failure(let error):\n                assertionFailure(\"Error saving: \\(error)\")\n            }\n        }\n\n    case .failure(let error):\n        assertionFailure(\"Error saving: \\(error)\")\n    }\n}\n\n//: Saving multiple GameScores at once using a transaction.\n//: May not work on MongoDB depending on your configuration.\n/*[score, score2].saveAll(transaction: true) { results in\n    switch results {\n    case .success(let otherResults):\n        var index = 0\n        otherResults.forEach { otherResult in\n            switch otherResult {\n            case .success(let savedScore):\n                print(\"Saved \\\"\\(savedScore.className)\\\" with points \\(savedScore.points) successfully\")\n                if index == 1 {\n                    score2ForFetchedLater = savedScore\n                }\n                index += 1\n            case .failure(let error):\n                assertionFailure(\"Error saving: \\(error)\")\n            }\n        }\n\n    case .failure(let error):\n        assertionFailure(\"Error saving: \\(error)\")\n    }\n}*/\n\n//: Save synchronously (not preferred - all operations on current queue).\nlet savedScore: GameScore?\ndo {\n    savedScore = try score.save()\n} catch {\n    savedScore = nil\n    fatalError(\"Error saving: \\(error)\")\n}\n\nassert(savedScore != nil)\nassert(savedScore?.objectId != nil)\nassert(savedScore?.createdAt != nil)\nassert(savedScore?.updatedAt != nil)\nassert(savedScore?.points == 10)\n\n/*:\n To modify, you need to make a mutable copy of `savedScore`.\n Instead of using `mergeable` this time, we will use the `set()`\n method which allows us to accomplish the same thing\n as `mergeable`. You can choose to use `set()` or\n `mergeable` as long as you use either before you begin\n your first mutation of your `ParseObject`.\n*/\nguard var changedScore = savedScore else {\n    fatalError(\"Should have produced mutable changedScore\")\n}\nchangedScore = changedScore.set(\\.points, to: 200)\n\nlet savedChangedScore: GameScore?\ndo {\n    savedChangedScore = try changedScore.save()\n    print(\"Updated score: \\(String(describing: savedChangedScore))\")\n} catch {\n    savedChangedScore = nil\n    fatalError(\"Error saving: \\(error)\")\n}\n\nassert(savedChangedScore != nil)\nassert(savedChangedScore!.points == 200)\nassert(savedScore!.objectId == savedChangedScore!.objectId)\n\nlet otherResults: [(Result<GameScore, ParseError>)]?\ndo {\n    otherResults = try [score, score2].saveAll()\n} catch {\n    otherResults = nil\n    fatalError(\"Error saving: \\(error)\")\n}\nassert(otherResults != nil)\n\notherResults!.forEach { result in\n    switch result {\n    case .success(let savedScore):\n        print(\"Saved \\\"\\(savedScore.className)\\\" with points \\(String(describing: savedScore.points)) successfully\")\n    case .failure(let error):\n        assertionFailure(\"Error saving: \\(error)\")\n    }\n}\n\n//: Now we will create another object and delete it.\nlet score3 = GameScore(points: 30)\n\n//: Save the score and store it in \"scoreToDelete\".\nvar scoreToDelete: GameScore!\ndo {\n    scoreToDelete = try score3.save()\n    print(\"Successfully saved: \\(scoreToDelete!)\")\n} catch {\n    assertionFailure(\"Error deleting: \\(error)\")\n}\n\n//: Delete the score from parse-server synchronously.\ndo {\n    try scoreToDelete.delete()\n    print(\"Successfully deleted: \\(scoreToDelete!)\")\n} catch {\n    assertionFailure(\"Error deleting: \\(error)\")\n}\n\n//: Now we will fetch a ParseObject that has already been saved based on its' objectId.\nlet scoreToFetch = GameScore(objectId: savedScore?.objectId)\n\n//: Asynchronously (preferred way) fetch this GameScore based on it is objectId alone.\nscoreToFetch.fetch { result in\n    switch result {\n    case .success(let fetchedScore):\n        print(\"Successfully fetched: \\(fetchedScore)\")\n    case .failure(let error):\n        assertionFailure(\"Error fetching: \\(error)\")\n    }\n}\n\n//: Synchronously fetch this GameScore based on it is objectId alone.\ndo {\n    let fetchedScore = try scoreToFetch.fetch()\n    print(\"Successfully fetched: \\(fetchedScore)\")\n} catch {\n    assertionFailure(\"Error fetching: \\(error)\")\n}\n\n//: Now we will fetch `ParseObject`'s in batch that have already been saved based on its' objectId.\nlet score2ToFetch = GameScore(objectId: score2ForFetchedLater?.objectId)\n\n//: Asynchronously (preferred way) fetch GameScores based on it is objectId alone.\n[scoreToFetch, score2ToFetch].fetchAll { result in\n    switch result {\n    case .success(let fetchedScores):\n\n        fetchedScores.forEach { result in\n            switch result {\n            case .success(let fetched):\n                print(\"Successfully fetched: \\(fetched)\")\n            case .failure(let error):\n                print(\"Error fetching: \\(error)\")\n            }\n        }\n    case .failure(let error):\n        assertionFailure(\"Error fetching: \\(error)\")\n    }\n}\n\nvar fetchedScore: GameScore!\n\n//: Synchronously fetchAll GameScore's based on it is objectId's alone.\ndo {\n    let fetchedScores = try [scoreToFetch, score2ToFetch].fetchAll()\n    fetchedScores.forEach { result in\n        switch result {\n        case .success(let fetched):\n            fetchedScore = fetched\n            print(\"Successfully fetched: \\(fetched)\")\n        case .failure(let error):\n            print(\"Error fetching: \\(error)\")\n        }\n    }\n} catch {\n    assertionFailure(\"Error fetching: \\(error)\")\n}\n\n//: Asynchronously (preferred way) deleteAll GameScores based on it is objectId alone.\n[scoreToFetch, score2ToFetch].deleteAll { result in\n    switch result {\n    case .success(let deletedScores):\n        deletedScores.forEach { result in\n            switch result {\n            case .success:\n                print(\"Successfully deleted score\")\n            case .failure(let error):\n                print(\"Error deleting: \\(error)\")\n            }\n        }\n    case .failure(let error):\n        assertionFailure(\"Error deleting: \\(error)\")\n    }\n}\n\n//: Synchronously deleteAll GameScore's based on it is objectId's alone.\n//: Commented out because the async above deletes the items already.\n/* do {\n    let fetchedScores = try [scoreToFetch, score2ToFetch].deleteAll()\n    fetchedScores.forEach { result in\n        switch result {\n        case .success(let fetched):\n            print(\"Successfully deleted: \\(fetched)\")\n        case .failure(let error):\n            print(\"Error deleted: \\(error)\")\n        }\n    }\n} catch {\n    assertionFailure(\"Error deleting: \\(error)\")\n}*/\n\n//: How to add `ParseBytes` and `ParsePolygon` to objects.\nlet points = [\n    try ParseGeoPoint(latitude: 0, longitude: 0),\n    try ParseGeoPoint(latitude: 0, longitude: 1),\n    try ParseGeoPoint(latitude: 1, longitude: 1),\n    try ParseGeoPoint(latitude: 1, longitude: 0),\n    try ParseGeoPoint(latitude: 0, longitude: 0)\n]\n\ndo {\n    let polygon = try ParsePolygon(points)\n    let bytes = ParseBytes(data: \"hello world\".data(using: .utf8)!)\n    var gameData = GameData(bytes: bytes, polygon: polygon)\n    gameData = try gameData.save()\n    print(\"Successfully saved: \\(gameData)\")\n} catch {\n    print(\"Error saving: \\(error.localizedDescription)\")\n}\n\nPlaygroundPage.current.finishExecution()\n//: [Next](@next)\n"
  },
  {
    "path": "ParseSwift.playground/Pages/10 - Cloud Code.xcplaygroundpage/Contents.swift",
    "content": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//: `My Mac` or whatever the name of your mac is. Also be sure your `Playground Settings`\n//: in the `File Inspector` is `Platform = macOS`. This is because\n//: Keychain in iOS Playgrounds behaves differently. Every page in Playgrounds should\n//: be set to build for `macOS` unless specified.\n\nimport PlaygroundSupport\nimport Foundation\nimport ParseSwift\n\nPlaygroundPage.current.needsIndefiniteExecution = true\ninitializeParse()\n\n//: Create your own value typed `ParseCloudable` type.\nstruct Hello: ParseCloudable {\n\n    //: Return type of your Cloud Function\n    typealias ReturnType = String\n\n    //: These are required by `ParseCloudable`, you can set the default value to make it easier\n    //: to use.\n    var functionJobName: String = \"hello\"\n}\n\n//: Create another `ParseCloudable` type.\nstruct TestCloudCode: ParseCloudable {\n\n    //: Return type of your Cloud Function\n    typealias ReturnType = [String: Int]\n\n    //: These are required by `ParseCloudable`, you can set the default value to make it easier\n    //: to use.\n    var functionJobName: String = \"testCloudCode\"\n\n    //: If your cloud function takes arguments, they can be passed by creating properties:\n    var argument1: [String: Int]\n}\n\n//: Create another `ParseCloudable` type.\nstruct TestCloudCodeError: ParseCloudable {\n\n    //: Return type of your Cloud Function\n    typealias ReturnType = String\n\n    //: These are required by `ParseCloudable`, you can set the default value to make it easier\n    //: to use.\n    var functionJobName: String = \"testCloudCodeError\"\n}\n\n/*: Assuming you have the Cloud Function named \"hello\" on your parse-server:\n     // main.js\n     Parse.Cloud.define('hello', async (request) => {\n       console.log('From client: ' + JSON.stringify(request));\n       return 'Hello world!';\n     });\n */\nlet hello = Hello()\n\nhello.runFunction { result in\n    switch result {\n    case .success(let response):\n        print(\"Response from cloud function: \\(response)\")\n    case .failure(let error):\n        assertionFailure(\"Error calling cloud function: \\(error)\")\n    }\n}\n\n/*: Assuming you have the Cloud Function named \"testCloudCode\" on your parse-server.\n You can catch custom errors created in Cloud Code:\n     // main.js\n     Parse.Cloud.define(\"testCloudCode\", async(request) => {\n       console.log('From client: ' + JSON.stringify(request));\n       return request.params.argument1;\n     });\n */\nlet testCloudCode = TestCloudCode(argument1: [\"test\": 5])\n\ntestCloudCode.runFunction { result in\n    switch result {\n    case .success(let response):\n        print(\"Response from cloud function: \\(response)\")\n    case .failure(let error):\n        assertionFailure(\"Error: \\(error.localizedDescription)\")\n    }\n}\n\n/*: Assuming you have the Cloud Function named \"testCloudCode\" on your parse-server.\n You can catch custom errors created in Cloud Code:\n     // main.js\n     Parse.Cloud.define(\"testCloudCodeError\", async(request) => {\n       console.log('From client: ' + JSON.stringify(request));\n       throw new Parse.Error(3000, \"cloud has an error on purpose.\");\n     });\n */\nlet testCloudCodeError = TestCloudCodeError()\n\ntestCloudCodeError.runFunction { result in\n    switch result {\n    case .success:\n        assertionFailure(\"Should have thrown a custom error\")\n    case .failure(let error):\n        switch error.code {\n        case .other:\n            guard let otherCode = error.otherCode else {\n                assertionFailure(\"Should have unwrapped otherCode\")\n                return\n            }\n            switch otherCode {\n            case 3000:\n                print(\"Received Cloud Code error: \\(error)\")\n            default:\n                assertionFailure(\"\"\"\n                    Should have received code \\\"3000\\\"\n                    Instead received \\(error)\n                \"\"\")\n            }\n        default:\n            assertionFailure(\"\"\"\n                Should have received code \\\"other\\\"\n                Instead received \\(error)\n            \"\"\")\n        }\n    }\n}\n\n//: Jobs can be run the same way by using the method `startJob()`.\n\n/*: Saving objects with context for beforeSave, afterSave, etc.\n Parse.Cloud.beforeSave(\"GameScore\", async(request) => {\n   console.log('From client context: ' + JSON.stringify(request.context));\n });\n */\n//: Create your own value typed `ParseObject`.\nstruct GameScore: ParseObject {\n    //: These are required by ParseObject\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: Your own properties.\n    var points: Int?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.points,\n                                     original: object) {\n            updated.points = object.points\n        }\n        return updated\n    }\n}\n\n//: It's recommended to place custom initializers in an extension\n//: to preserve the memberwise initializer.\nextension GameScore {\n    //: Custom initializer.\n    init(points: Int) {\n        self.points = points\n    }\n\n    init(objectId: String?) {\n        self.objectId = objectId\n    }\n}\n\n//: Define a GameScore.\nlet score = GameScore(points: 10)\n\n//: Save asynchronously (preferred way) with the context option.\nscore.save(options: [.context([\"hello\": \"world\"])]) { result in\n    switch result {\n    case .success(let savedScore):\n        print(\"Successfully saved \\(savedScore)\")\n    case .failure(let error):\n        assertionFailure(\"Error saving: \\(error)\")\n    }\n}\n\nPlaygroundPage.current.finishExecution()\n//: [Next](@next)\n"
  },
  {
    "path": "ParseSwift.playground/Pages/11 - LiveQuery.xcplaygroundpage/Contents.swift",
    "content": "//: [Previous](@previous)\n\nimport PlaygroundSupport\nimport Foundation\nimport ParseSwift\nimport SwiftUI\n\nPlaygroundPage.current.needsIndefiniteExecution = true\n\ninitializeParse()\n\n//: Create your own value typed ParseObject.\nstruct GameScore: ParseObject {\n    //: These are required by `ParseObject`.\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: Your own properties.\n    var points: Int?\n    var location: ParseGeoPoint?\n    var name: String?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.points,\n                                     original: object) {\n            updated.points = object.points\n        }\n        if updated.shouldRestoreKey(\\.location,\n                                     original: object) {\n            updated.location = object.location\n        }\n        if updated.shouldRestoreKey(\\.name,\n                                     original: object) {\n            updated.name = object.name\n        }\n        return updated\n    }\n}\n\n//: It's recommended to place custom initializers in an extension\n//: to preserve the memberwise initializer.\nextension GameScore {\n    //: Custom initializer.\n    init(name: String, points: Int) {\n        self.name = name\n        self.points = points\n    }\n}\n\n//: Create a delegate for LiveQuery errors\nclass LiveQueryDelegate: ParseLiveQueryDelegate {\n\n    func received(_ error: Error) {\n        print(error)\n    }\n\n    func closedSocket(_ code: URLSessionWebSocketTask.CloseCode?, reason: Data?) {\n        print(\"Socket closed with \\(String(describing: code)) and \\(String(describing: reason))\")\n    }\n}\n\n//: Be sure you have LiveQuery enabled on your server.\n\n//: Set the delegate.\nlet delegate = LiveQueryDelegate()\nif let socket = ParseLiveQuery.defaultClient {\n    socket.receiveDelegate = delegate\n}\n\n//: Create a query just as you normally would.\nvar query = GameScore.query(\"points\" < 11)\n\n//: This is how you subscribe to your created query using callbacks.\nlet subscription = query.subscribeCallback!\n\n//: This is how you receive notifications about the success\n//: of your subscription.\nsubscription.handleSubscribe { subscribedQuery, isNew in\n\n    //: You can check this subscription is for this query\n    if isNew {\n        print(\"Successfully subscribed to new query \\(subscribedQuery)\")\n    } else {\n        print(\"Successfully updated subscription to new query \\(subscribedQuery)\")\n    }\n}\n\n//: This is how you register to receive notifications of events related to your LiveQuery.\nsubscription.handleEvent { _, event in\n    switch event {\n\n    case .entered(let object):\n        print(\"Entered: \\(object)\")\n    case .left(let object):\n        print(\"Left: \\(object)\")\n    case .created(let object):\n        print(\"Created: \\(object)\")\n    case .updated(let object):\n        print(\"Updated: \\(object)\")\n    case .deleted(let object):\n        print(\"Deleted: \\(object)\")\n    }\n}\n\n//: Ping the LiveQuery server\nParseLiveQuery.client?.sendPing { error in\n    if let error = error {\n        print(\"Error pinging LiveQuery server: \\(error)\")\n    } else {\n        print(\"Successfully pinged server!\")\n    }\n}\n\n//: Now go to your dashboard, go to the GameScore table and add, update or remove rows.\n//: You should receive notifications for each.\n\n//: This is how you register to receive notifications about being unsubscribed.\nsubscription.handleUnsubscribe { query in\n    print(\"Unsubscribed from \\(query)\")\n}\n\n//: To unsubscribe from your query.\ndo {\n    try query.unsubscribe()\n} catch {\n    print(error)\n}\n\n//: If you look at your server log, you will notice the client and server disconnnected.\n//: This is because there is no more LiveQuery subscriptions.\n\n//: Ping the LiveQuery server. This should produce an error\n//: because LiveQuery is disconnected.\nParseLiveQuery.client?.sendPing { error in\n    if let error = error {\n        print(\"Error pinging LiveQuery server: \\(error)\")\n    } else {\n        print(\"Successfully pinged server!\")\n    }\n}\n\n//: Create a new query.\nvar query2 = GameScore.query(\"points\" > 50)\n\n//: Select the fields you are interested in receiving.\nquery2.select(\"points\")\n\n//: Subscribe to your new query.\nlet subscription2 = query2.subscribeCallback!\n\n//: As before, setup your subscription, event, and unsubscribe handlers.\nsubscription2.handleSubscribe { subscribedQuery, isNew in\n\n    //: You can check this subscription is for this query.\n    if isNew {\n        print(\"Successfully subscribed to new query \\(subscribedQuery)\")\n    } else {\n        print(\"Successfully updated subscription to new query \\(subscribedQuery)\")\n    }\n}\n\nsubscription2.handleEvent { _, event in\n    switch event {\n\n    case .entered(let object):\n        print(\"Entered: \\(object)\")\n    case .left(let object):\n        print(\"Left: \\(object)\")\n    case .created(let object):\n        print(\"Created: \\(object)\")\n    case .updated(let object):\n        print(\"Updated: \\(object)\")\n    case .deleted(let object):\n        print(\"Deleted: \\(object)\")\n    }\n}\n\nsubscription2.handleUnsubscribe { query in\n    print(\"Unsubscribed from \\(query)\")\n}\n\n//: To close the current LiveQuery connection.\nParseLiveQuery.client?.close()\n\n//: To close all LiveQuery connections use:\n//ParseLiveQuery.client?.closeAll()\n\n//: Ping the LiveQuery server. This should produce an error\n//: because LiveQuery is disconnected.\nParseLiveQuery.client?.sendPing { error in\n    if let error = error {\n        print(\"Error pinging LiveQuery server: \\(error)\")\n    } else {\n        print(\"Successfully pinged server!\")\n    }\n}\n\n//: Resubscribe to your previous query.\n//: Since we never unsubscribed you can use your previous handlers.\nlet subscription3 = query2.subscribeCallback!\n\n//: Resubscribe to another previous query.\n//: This one needs new handlers.\nlet subscription4 = query.subscribeCallback!\n\n//: Need a new handler because we previously unsubscribed.\nsubscription4.handleSubscribe { subscribedQuery, isNew in\n\n    //: You can check this subscription is for this query\n    if isNew {\n        print(\"Successfully subscribed to new query \\(subscribedQuery)\")\n    } else {\n        print(\"Successfully updated subscription to new query \\(subscribedQuery)\")\n    }\n}\n\n//: Need a new event handler because we previously unsubscribed.\nsubscription4.handleEvent { _, event in\n    switch event {\n\n    case .entered(let object):\n        print(\"Entered: \\(object)\")\n    case .left(let object):\n        print(\"Left: \\(object)\")\n    case .created(let object):\n        print(\"Created: \\(object)\")\n    case .updated(let object):\n        print(\"Updated: \\(object)\")\n    case .deleted(let object):\n        print(\"Deleted: \\(object)\")\n    }\n}\n\n//: Need a new unsubscribe handler because we previously unsubscribed.\nsubscription4.handleUnsubscribe { query in\n    print(\"Unsubscribed from \\(query)\")\n}\n\n//: To unsubscribe from your query.\ndo {\n    try query2.unsubscribe()\n} catch {\n    print(error)\n}\n\n//: Ping the LiveQuery server\nParseLiveQuery.client?.sendPing { error in\n    if let error = error {\n        print(\"Error pinging LiveQuery server: \\(error)\")\n    } else {\n        print(\"Successfully pinged server!\")\n    }\n}\n\n//: To unsubscribe from your your last query.\ndo {\n    try query.unsubscribe()\n} catch {\n    print(error)\n}\n\n//: If you look at your server log, you will notice the client and server disconnnected.\n//: This is because there is no more LiveQuery subscriptions.\n\nPlaygroundPage.current.finishExecution()\n//: [Next](@next)\n"
  },
  {
    "path": "ParseSwift.playground/Pages/12 - Roles and Relations.xcplaygroundpage/Contents.swift",
    "content": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//: `My Mac` or whatever the name of your mac is. Also be sure your `Playground Settings`\n//: in the `File Inspector` is `Platform = macOS`. This is because\n//: Keychain in iOS Playgrounds behaves differently. Every page in Playgrounds should\n//: be set to build for `macOS` unless specified.\n\nimport PlaygroundSupport\nimport Foundation\nimport ParseSwift\n\nPlaygroundPage.current.needsIndefiniteExecution = true\ninitializeParse()\n\nstruct User: ParseUser {\n    //: These are required by `ParseObject`.\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: These are required by `ParseUser`.\n    var username: String?\n    var email: String?\n    var emailVerified: Bool?\n    var password: String?\n    var authData: [String: [String: String]?]?\n\n    //: Your custom keys.\n    var customKey: String?\n    var scores: ParseRelation<Self>?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.customKey,\n                                     original: object) {\n            updated.customKey = object.customKey\n        }\n        return updated\n    }\n}\n\nstruct Role<RoleUser: ParseUser>: ParseRole {\n\n    //: Required by `ParseObject`.\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: Provided by Role.\n    var name: String?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.name,\n                                     original: object) {\n            updated.name = object.name\n        }\n        return updated\n    }\n}\n\n//: Create your own value typed `ParseObject`.\nstruct GameScore: ParseObject {\n    //: These are required by ParseObject\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: Your own properties.\n    var points: Int?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.points,\n                                     original: object) {\n            updated.points = object.points\n        }\n        return updated\n    }\n}\n\n//: It's recommended to place custom initializers in an extension\n//: to preserve the memberwise initializer.\nextension GameScore {\n\n    init(points: Int) {\n        self.points = points\n    }\n\n    init(objectId: String?) {\n        self.objectId = objectId\n    }\n}\n\n//: Roles can provide additional access/security to your apps.\n\n//: This variable will store the saved role.\nvar savedRole: Role<User>?\n\n//: Now we will create the Role.\nguard let currentUser = User.current else {\n    fatalError(\"User currently is not signed in\")\n}\n\n//: Every Role requires an ACL that cannot be changed after saving.\nvar acl = ParseACL()\nacl.setReadAccess(user: currentUser, value: true)\nacl.setWriteAccess(user: currentUser, value: true)\n\ndo {\n    //: Create the actual Role with a name and ACL.\n    let adminRole = try Role<User>(name: \"Administrator\", acl: acl)\n    adminRole.save { result in\n        switch result {\n        case .success(let saved):\n            print(\"The role saved successfully: \\(saved)\")\n            print(\"Check your \\\"Role\\\" class in Parse Dashboard.\")\n\n            //: Store the saved role so we can use it later...\n            savedRole = saved\n\n        case .failure(let error):\n            print(\"Error saving role: \\(error)\")\n        }\n    }\n} catch {\n    print(\"Error: \\(error)\")\n}\n\n//: Lets check to see if our Role has saved.\nif savedRole != nil {\n    print(\"We have a saved Role\")\n}\n\n//: Users can be added to our previously saved Role.\ndo {\n    //: `ParseRoles` have `ParseRelations` that relate them either `ParseUser` and `ParseRole` objects.\n    //: The `ParseUser` relations can be accessed using `users`. We can then add `ParseUser`'s to the relation.\n    try savedRole!.users?.add([User.current!]).save { result in\n        switch result {\n        case .success(let saved):\n            print(\"The role saved successfully: \\(saved)\")\n            print(\"Check \\\"users\\\" field in your \\\"Role\\\" class in Parse Dashboard.\")\n\n        case .failure(let error):\n            print(\"Error saving role: \\(error)\")\n        }\n    }\n\n} catch {\n    print(\"Error: \\(error)\")\n}\n\n//: To retrieve the users who are all Administrators, we need to query the relation.\ndo {\n    let query: Query<User>? = try savedRole!.users?.query()\n    query?.find { result in\n        switch result {\n        case .success(let relatedUsers):\n            print(\"\"\"\n                The following users are part of the\n                \\\"\\(String(describing: savedRole!.name)) role: \\(relatedUsers)\n            \"\"\")\n\n        case .failure(let error):\n            print(\"Error querying role: \\(error)\")\n        }\n    }\n} catch {\n    print(error)\n}\n\n//: Of course, you can remove users from the roles as well.\ndo {\n    try savedRole!.users?.remove([User.current!]).save { result in\n        switch result {\n        case .success(let saved):\n            print(\"The role removed successfully: \\(saved)\")\n            print(\"Check \\\"users\\\" field in your \\\"Role\\\" class in Parse Dashboard.\")\n\n        case .failure(let error):\n            print(\"Error saving role: \\(error)\")\n        }\n    }\n} catch {\n    print(error)\n}\n\n//: Additional roles can be created and tied to already created roles. Lets create a \"Member\" role.\n\n//: This variable will store the saved role.\nvar savedRoleModerator: Role<User>?\n\ndo {\n    //: Create the actual Role with a name and ACL.\n    let memberRole = try Role<User>(name: \"Member\", acl: acl)\n    memberRole.save { result in\n        switch result {\n        case .success(let saved):\n            print(\"The role saved successfully: \\(saved)\")\n            print(\"Check your \\\"Role\\\" class in Parse Dashboard.\")\n\n            //: Store the saved role so we can use it later...\n            savedRoleModerator = saved\n\n        case .failure(let error):\n            print(\"Error saving role: \\(error)\")\n        }\n    }\n} catch {\n    print(\"Error: \\(error)\")\n}\n\n//: Lets check to see if our Role has saved\nif savedRoleModerator != nil {\n    print(\"We have a saved Role\")\n}\n\n//: Roles can be added to our previously saved Role.\ndo {\n    //: `ParseRoles` have `ParseRelations` that relate them either `ParseUser` and `ParseRole` objects.\n    //: The `ParseUser` relations can be accessed using `users`. We can then add `ParseUser`'s to the relation.\n    try savedRole!.roles?.add([savedRoleModerator!]).save { result in\n        switch result {\n        case .success(let saved):\n            print(\"The role saved successfully: \\(saved)\")\n            print(\"Check \\\"roles\\\" field in your \\\"Role\\\" class in Parse Dashboard.\")\n\n        case .failure(let error):\n            print(\"Error saving role: \\(error)\")\n        }\n    }\n} catch {\n    print(\"Error: \\(error)\")\n}\n\n//: To retrieve the users who are all Administrators, we need to query the relation.\n//: This time we will use a helper query from `ParseRole`.\ndo {\n    try savedRole!.queryRoles().find { result in\n        switch result {\n        case .success(let relatedRoles):\n            print(\"\"\"\n                The following roles are part of the\n                \\\"\\(String(describing: savedRole!.name)) role: \\(relatedRoles)\n            \"\"\")\n\n        case .failure(let error):\n            print(\"Error querying role: \\(error)\")\n        }\n    }\n} catch {\n    print(\"Error: \\(error)\")\n}\n\n//: Of course, you can remove users from the roles as well.\ndo {\n    try savedRole!.roles?.remove([savedRoleModerator!]).save { result in\n        switch result {\n        case .success(let saved):\n            print(\"The role removed successfully: \\(saved)\")\n            print(\"Check the \\\"roles\\\" field in your \\\"Role\\\" class in Parse Dashboard.\")\n\n        case .failure(let error):\n            print(\"Error saving role: \\(error)\")\n        }\n    }\n} catch {\n    print(error)\n}\n\n//: Using this relation, you can create one-to-many relationships with other `ParseObjecs`,\n//: similar to `users` and `roles`.\n//: All `ParseObject`s have a `ParseRelation` attribute that be used on instances.\n//: For example, the User has:\nvar relation = User.current!.relation\nlet score1 = GameScore(points: 53)\nlet score2 = GameScore(points: 57)\n\n//: Add new child relationships.\n[score1, score2].saveAll { result in\n    switch result {\n    case .success(let savedScores):\n        //: Make an array of all scores that were properly saved.\n        let scores = savedScores.compactMap { try? $0.get() }\n        do {\n            guard let newRelations = try relation?.add(\"scores\", objects: scores) else {\n                print(\"Error: should have unwrapped relation\")\n                return\n            }\n            newRelations.save { result in\n                switch result {\n                case .success(let saved):\n                    print(\"The relation saved successfully: \\(saved)\")\n                    print(\"Check \\\"points\\\" field in your \\\"_User\\\" class in Parse Dashboard.\")\n\n                case .failure(let error):\n                    print(\"Error saving role: \\(error)\")\n                }\n            }\n        } catch {\n            print(error)\n        }\n    case .failure(let error):\n        print(\"Could not save scores. \\(error)\")\n    }\n}\n\n//: You can also do\n// let specificRelation = User.current!.relation(\"scores\", className: \"GameScore\")\ndo {\n    let specificRelation = try User.current!.relation(\"scores\", child: score1)\n    try (specificRelation.query() as Query<GameScore>).find { result in\n        switch result {\n        case .success(let scores):\n            print(\"Found related scores: \\(scores)\")\n        case .failure(let error):\n            print(\"Error querying scores: \\(error)\")\n        }\n    }\n} catch {\n    print(error)\n}\n\n//: In addition, you can leverage the child to find scores related to the parent.\ndo {\n    try GameScore.queryRelations(\"scores\", parent: User.current!).find { result in\n        switch result {\n        case .success(let scores):\n            print(\"Found related scores from child: \\(scores)\")\n        case .failure(let error):\n            print(\"Error querying scores from child: \\(error)\")\n        }\n    }\n} catch {\n    print(error)\n}\n\n//: Now we will see how to use the stored `ParseRelation on` property in User to create query\n//: all of the relations to `scores`.\nvar updatedCurrentUser: User\ndo {\n    //: Fetch the updated user since the previous relations were created on the server.\n    updatedCurrentUser = try User.current!.fetch()\n    print(\"Updated current user with relation: \\(updatedCurrentUser)\")\n} catch {\n    updatedCurrentUser = User.current!\n    print(\"\\(error.localizedDescription)\")\n}\n\ndo {\n    let usableStoredRelation = try updatedCurrentUser.relation(updatedCurrentUser.scores, key: \"scores\")\n    try (usableStoredRelation.query() as Query<GameScore>).find { result in\n        switch result {\n        case .success(let scores):\n            print(\"Found related scores from stored ParseRelation: \\(scores)\")\n        case .failure(let error):\n            print(\"Error querying scores from stored ParseRelation: \\(error)\")\n        }\n    }\n} catch {\n    print(\"\\(error.localizedDescription)\")\n}\n\nPlaygroundPage.current.finishExecution()\n//: [Next](@next)\n"
  },
  {
    "path": "ParseSwift.playground/Pages/13 - Operations.xcplaygroundpage/Contents.swift",
    "content": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//: `My Mac` or whatever the name of your mac is. Also be sure your `Playground Settings`\n//: in the `File Inspector` is `Platform = macOS`. This is because\n//: Keychain in iOS Playgrounds behaves differently. Every page in Playgrounds should\n//: be set to build for `macOS` unless specified.\n\nimport PlaygroundSupport\nimport Foundation\nimport ParseSwift\n\nPlaygroundPage.current.needsIndefiniteExecution = true\ninitializeParse()\n\nstruct GameScore: ParseObject {\n    //: These are required by ParseObject.\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: Your own properties.\n    var points: Int?\n    var name: String?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.points,\n                                     original: object) {\n            updated.points = object.points\n        }\n        if updated.shouldRestoreKey(\\.name,\n                                     original: object) {\n            updated.name = object.name\n        }\n        return updated\n    }\n}\n\n//: It's recommended to place custom initializers in an extension\n//: to preserve the memberwise initializer.\nextension GameScore {\n    //: Custom initializer.\n    init(points: Int) {\n        self.points = points\n    }\n\n    init(objectId: String?) {\n        self.objectId = objectId\n    }\n}\n\n//: You can have the server do operations on your `ParseObject`'s for you.\n\n//: First lets create another GameScore.\nlet savedScore: GameScore!\ndo {\n    let score = GameScore(points: 102, name: \"player1\")\n    savedScore = try score.save()\n} catch {\n    savedScore = nil\n    assertionFailure(\"Error saving: \\(error)\")\n}\n\n//: Then we will increment the points.\nlet incrementOperation = savedScore\n    .operation.increment(\"points\", by: 1)\n\nincrementOperation.save { result in\n    switch result {\n    case .success:\n        print(\"Original score: \\(String(describing: savedScore)). Check the new score on Parse Dashboard.\")\n    case .failure(let error):\n        assertionFailure(\"Error saving: \\(error)\")\n    }\n}\n\n//: You can increment the score again syncronously.\ndo {\n    _ = try incrementOperation.save()\n    print(\"Original score: \\(String(describing: savedScore)). Check the new score on Parse Dashboard.\")\n} catch {\n    print(error)\n}\n\n//: Query all scores whose name is null or undefined.\nlet query1 = GameScore.query(isNotNull(key: \"name\"))\nlet results1 = try query1.find()\nprint(\"Total found: \\(results1.count)\")\nresults1.forEach { score in\n    print(\"Found score with a name: \\(score)\")\n}\n\n//: Query all scores whose name is undefined.\nlet query2 = GameScore.query(exists(key: \"name\"))\nlet results2 = try query2.find()\nprint(\"Total found: \\(results2.count)\")\nresults2.forEach { score in\n    print(\"Found score with a name: \\(score)\")\n}\n\n//: You can also remove a value for a property using unset.\nlet unsetOperation = savedScore\n    .operation.unset((\"points\", \\.points))\ndo {\n    let updatedScore = try unsetOperation.save()\n    print(\"Updated score: \\(updatedScore). Check the new score on Parse Dashboard.\")\n} catch {\n    print(error)\n}\n\n//: There may be cases where you want to set/forceSet a value to null\n//: instead of unsetting\nlet setToNullOperation = savedScore\n    .operation.set((\"name\", \\.name), to: nil)\ndo {\n    let updatedScore = try setToNullOperation.save()\n    print(\"Updated score: \\(updatedScore). Check the new score on Parse Dashboard.\")\n} catch {\n    print(error)\n}\n\n//: Query all scores whose name is null or undefined.\nlet query3 = GameScore.query(isNull(key: \"name\"))\nlet results3 = try query3.find()\nprint(\"Total found: \\(results3.count)\")\nresults3.forEach { score in\n    print(\"Found score with name is null: \\(score)\")\n}\n\n//: Query all scores whose name is undefined.\nlet query4 = GameScore.query(doesNotExist(key: \"name\"))\nlet results4 = try query4.find()\nprint(\"Total found: \\(results4.count)\")\nresults4.forEach { score in\n    print(\"Found score with name does not exist: \\(score)\")\n}\n\n//: There are other operations: set/forceSet/unset/add/remove, etc. objects from `ParseObject`s.\n//: In fact, the `users` and `roles` relations from `ParseRoles` used the add/remove operations.\n//: Multiple operations can be chained together. See:\n//: https://github.com/parse-community/Parse-Swift/pull/268#issuecomment-955714414\nlet operations = savedScore.operation\n\n//: Example: operations.add(\"hello\", objects: [\"test\"]).\n\nPlaygroundPage.current.finishExecution()\n//: [Next](@next)\n"
  },
  {
    "path": "ParseSwift.playground/Pages/14 - Config.xcplaygroundpage/Contents.swift",
    "content": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//: `My Mac` or whatever the name of your mac is. Also be sure your `Playground Settings`\n//: in the `File Inspector` is `Platform = macOS`. This is because\n//: Keychain in iOS Playgrounds behaves differently. Every page in Playgrounds should\n//: be set to build for `macOS` unless specified.\n\nimport PlaygroundSupport\nimport Foundation\nimport ParseSwift\n\nPlaygroundPage.current.needsIndefiniteExecution = true\ninitializeParse()\n\n//: Create a value typed `ParseConfig` that matches your server config.\nstruct Config: ParseConfig {\n\n    //: If your server Config has any parameters their names and types should\n    //: match your ParseCondig properties:\n    var welcomeMessage: String?\n    var winningNumber: Int?\n}\n\n/*: Go to your Parse Dashboard and click `Config->Create a parameter`:\n    Now add the following parameters:\n - Parameter Name: \"welcomeMessage\", Type: \"String\", Value: \"Hello\".\n - Parameter Name: \"winningNumber\", Type: \"Number\", Value: \"42\".\n */\nvar config = Config()\n\nconfig.fetch { result in\n    switch result {\n    case .success(let currentConfig):\n        print(\"The current config on the server: \\(currentConfig)\")\n    case .failure(let error):\n        assertionFailure(\"Error fetching the config: \\(error)\")\n    }\n}\n\n//: We can also update the config.\nconfig.winningNumber = 50\n\n//: Save the update.\nconfig.save { result in\n    switch result {\n    case .success(let isUpdated):\n        if isUpdated {\n            print(\"The current config on the server has been updated.\")\n        } else {\n            print(\"The current config on the server failed to update.\")\n        }\n    case .failure(let error):\n        assertionFailure(\"Error updating the config: \\(error)\")\n    }\n}\n\n//: Fetch the updated config to make sure it is saved.\nconfig.fetch { result in\n    switch result {\n    case .success(let currentConfig):\n        print(\"The current config on the server: \\(currentConfig)\")\n    case .failure(let error):\n        assertionFailure(\"Error fetching the config: \\(error)\")\n    }\n}\n\n//: Anytime you fetch or update your Config successfully, it is automatically saved to your Keychain.\nprint(Config.current ?? \"No config\")\n\nPlaygroundPage.current.finishExecution()\n//: [Next](@next)\n"
  },
  {
    "path": "ParseSwift.playground/Pages/15 - Custom ObjectId.xcplaygroundpage/Contents.swift",
    "content": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//: `My Mac` or whatever the name of your mac is. Also be sure your `Playground Settings`\n//: in the `File Inspector` is `Platform = macOS`. This is because\n//: Keychain in iOS Playgrounds behaves differently. Every page in Playgrounds should\n//: be set to build for `macOS` unless specified.\n\nimport PlaygroundSupport\nimport Foundation\nimport ParseSwift\nPlaygroundPage.current.needsIndefiniteExecution = true\n\n/*:\n start parse-server with\n npm start -- --appId applicationId --clientKey clientKey --masterKey masterKey --mountPath /1\n*/\n\n/*:\n In Xcode, make sure you are building the \"ParseSwift (macOS)\" framework.\n */\n\ninitializeParse(customObjectId: true)\n\n//: Create your own value typed `ParseObject`.\nstruct GameScore: ParseObject {\n    //: These are required by ParseObject\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: Your own properties.\n    var points: Int?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.points,\n                                     original: object) {\n            updated.points = object.points\n        }\n        return updated\n    }\n}\n\n//: It's recommended to place custom initializers in an extension\n//: to preserve the memberwise initializer.\nextension GameScore {\n    //: Custom initializer.\n    init(objectId: String, points: Int) {\n        self.objectId = objectId\n        self.points = points\n    }\n\n    init(objectId: String) {\n        self.objectId = objectId\n    }\n}\n\n//: Define initial GameScore this time with custom `objectId`.\n//: customObjectId has to be enabled on the server for this to work.\nvar score = GameScore(objectId: \"myObjectId\", points: 10)\n\n/*: Save asynchronously (preferred way) - Performs work on background\n    queue and returns to specified callbackQueue.\n    If no callbackQueue is specified it returns to main queue.\n*/\nscore.save { result in\n    switch result {\n    case .success(let savedScore):\n        assert(savedScore.objectId != nil)\n        assert(savedScore.createdAt != nil)\n        assert(savedScore.updatedAt != nil)\n        assert(savedScore.points == 10)\n\n        //: Now that this object has a `createdAt`, it is properly saved to the server.\n        //: Any changes to `createdAt` and `objectId` will not be saved to the server.\n        print(\"Saved score: \\(savedScore)\")\n\n        /*:\n         To modify, need to make it a var as the value type\n         was initialized as immutable. Using `.mergeable` or `set()`\n         allows you to only send the updated keys to the\n         parse server as opposed to the whole object.\n        */\n        var changedScore = savedScore.mergeable\n        changedScore.points = 200\n        changedScore.save { result in\n            switch result {\n            case .success(let savedChangedScore):\n                assert(savedChangedScore.points == 200)\n                assert(savedScore.objectId == savedChangedScore.objectId)\n                print(\"Updated score: \\(savedChangedScore)\")\n\n            case .failure(let error):\n                assertionFailure(\"Error saving: \\(error)\")\n            }\n        }\n    case .failure(let error):\n        assertionFailure(\"Error saving: \\(error)\")\n    }\n}\n\n//: Fetch object\nscore.fetch { result in\n    switch result {\n    case .success(let fetchedScore):\n        print(\"Successfully fetched: \\(fetchedScore)\")\n    case .failure(let error):\n        assertionFailure(\"Error fetching: \\(error)\")\n    }\n}\n\n//: Query object\nlet query = GameScore.query(\"objectId\" == \"myObjectId\")\nquery.first { result in\n    switch result {\n    case .success(let found):\n        print(found)\n    case .failure(let error):\n        print(error)\n    }\n}\n\n//: Now we will attempt to fetch a ParseObject that is not saved.\nlet scoreToFetch = GameScore(objectId: \"hello\")\n\n//: Asynchronously (preferred way) fetch this GameScore based on it is objectId alone.\nscoreToFetch.fetch { result in\n    switch result {\n    case .success(let fetchedScore):\n        print(\"Successfully fetched: \\(fetchedScore)\")\n    case .failure(let error):\n        assertionFailure(\"Error fetching on purpose: \\(error)\")\n    }\n}\n\nPlaygroundPage.current.finishExecution()\n//: [Next](@next)\n"
  },
  {
    "path": "ParseSwift.playground/Pages/16 - Analytics.xcplaygroundpage/Contents.swift",
    "content": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//: `My Mac` or whatever the name of your mac is. Also be sure your `Playground Settings`\n//: in the `File Inspector` is `Platform = macOS`. This is because\n//: Keychain in iOS Playgrounds behaves differently. Every page in Playgrounds should\n//: be set to build for `macOS` unless specified.\n\nimport PlaygroundSupport\nimport Foundation\nimport ParseSwift\n\nPlaygroundPage.current.needsIndefiniteExecution = true\ninitializeParse()\n\n//: To track when the app has been opened, do the following.\nParseAnalytics.trackAppOpened { result in\n    switch result {\n    case .success:\n        print(\"Saved analytics for app opened.\")\n    case .failure(let error):\n        print(error)\n    }\n}\n\n//: To track any event, do the following.\nvar friendEvent = ParseAnalytics(name: \"openedFriendList\")\nfriendEvent.track { result in\n    switch result {\n    case .success:\n        print(\"Saved analytics for custom event.\")\n    case .failure(let error):\n        print(error)\n    }\n}\n\n//: You can also add dimensions to your analytics.\nfriendEvent.track(dimensions: [\"more\": \"info\"]) { result in\n    switch result {\n    case .success:\n        print(\"Saved analytics for custom event with dimensions.\")\n    case .failure(let error):\n        print(error)\n    }\n}\n\nPlaygroundPage.current.finishExecution()\n//: [Next](@next)\n"
  },
  {
    "path": "ParseSwift.playground/Pages/17 - SwiftUI - Finding Objects.xcplaygroundpage/Contents.swift",
    "content": "//: [Previous](@previous)\n\n//: If you are using Xcode 13+, ignore the comments below:\n//: For this page, make sure your build target is set to ParseSwift (iOS) and targeting\n//: an iPhone, iPod, or iPad. Also be sure your `Playground Settings`\n//: in the `File Inspector` is `Platform = iOS`. This is because\n//: SwiftUI in macOS Playgrounds does not seem to build correctly\n//: Be sure to switch your target and `Playground Settings` back to\n//: macOS after leaving this page.\n\nimport PlaygroundSupport\nimport Foundation\nimport ParseSwift\nimport SwiftUI\n\nPlaygroundPage.current.needsIndefiniteExecution = true\n\ninitializeParse()\n\n//: Create your own value typed ParseObject.\nstruct GameScore: ParseObject {\n\n    //: These are required by `ParseObject`.\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: Your own properties.\n    var points: Int?\n    var location: ParseGeoPoint?\n    var name: String?\n    var myFiles: [ParseFile]?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.points,\n                                     original: object) {\n            updated.points = object.points\n        }\n        if updated.shouldRestoreKey(\\.name,\n                                     original: object) {\n            updated.name = object.name\n        }\n        if updated.shouldRestoreKey(\\.myFiles,\n                                     original: object) {\n            updated.myFiles = object.myFiles\n        }\n        if updated.shouldRestoreKey(\\.location,\n                                     original: object) {\n            updated.location = object.location\n        }\n        return updated\n    }\n}\n\n//: It's recommended to place custom initializers in an extension\n//: to preserve the memberwise initializer.\nextension GameScore {\n    //: Custom initializer.\n    init(name: String, points: Int) {\n        self.name = name\n        self.points = points\n    }\n}\n\n//: To use queries with SwiftUI\n\n//: Create a SwiftUI view.\nstruct ContentView: View {\n\n    //: A view model in SwiftUI\n    @StateObject var viewModel = GameScore.query(\"points\" > 2)\n        .order([.descending(\"points\")])\n        .viewModel\n    @State var name = \"\"\n    @State var points = \"\"\n    @State var isShowingAction = false\n    @State var savedLabel = \"\"\n\n    var body: some View {\n        NavigationView {\n            VStack {\n                TextField(\"Name\", text: $name)\n                TextField(\"Points\", text: $points)\n                Button(action: {\n                    guard let pointsValue = Int(points),\n                          let linkToFile = URL(string: \"https://parseplatform.org/img/logo.svg\") else {\n                        return\n                    }\n                    var score = GameScore(name: name,\n                                          points: pointsValue)\n                    //: Create new `ParseFile` for saving.\n                    let file1 = ParseFile(name: \"file1.svg\",\n                                          cloudURL: linkToFile)\n                    let file2 = ParseFile(name: \"file2.svg\",\n                                          cloudURL: linkToFile)\n                    score.myFiles = [file1, file2]\n                    score.save { result in\n                        switch result {\n                        case .success:\n                            savedLabel = \"Saved score\"\n                            self.viewModel.find()\n                        case .failure(let error):\n                            savedLabel = \"Error: \\(error.message)\"\n                        }\n                        isShowingAction = true\n                    }\n                }, label: {\n                    Text(\"Save score\")\n                })\n            }\n            if let error = viewModel.error {\n                Text(error.description)\n            } else {\n                //: Warning - List seems to only work in Playgrounds Xcode 13+.\n                List(viewModel.results, id: \\.id) { result in\n                    VStack(alignment: .leading) {\n                        Text(\"Points: \\(String(describing: result.points))\")\n                            .font(.headline)\n                        if let createdAt = result.createdAt {\n                            Text(\"\\(createdAt.description)\")\n                        }\n                    }\n                }\n            }\n            Spacer()\n        }.onAppear(perform: {\n            viewModel.find()\n        }).alert(isPresented: $isShowingAction, content: {\n            Alert(title: Text(\"GameScore\"),\n                  message: Text(savedLabel),\n                  dismissButton: .default(Text(\"Ok\"), action: {\n            }))\n        })\n    }\n}\n\nPlaygroundPage.current.setLiveView(ContentView())\n\nPlaygroundPage.current.finishExecution()\n//: [Next](@next)\n"
  },
  {
    "path": "ParseSwift.playground/Pages/18 - SwiftUI - Finding Objects With Custom ViewModel.xcplaygroundpage/Contents.swift",
    "content": "//: [Previous](@previous)\n\n//: If you are using Xcode 13+, ignore the comments below:\n//: For this page, make sure your build target is set to ParseSwift (iOS) and targeting\n//: an iPhone, iPod, or iPad. Also be sure your `Playground Settings`\n//: in the `File Inspector` is `Platform = iOS`. This is because\n//: SwiftUI in macOS Playgrounds does not seem to build correctly\n//: Be sure to switch your target and `Playground Settings` back to\n//: macOS after leaving this page.\n\nimport PlaygroundSupport\nimport Foundation\nimport ParseSwift\nimport SwiftUI\nimport Combine\n\nPlaygroundPage.current.needsIndefiniteExecution = true\n\ninitializeParse()\n\n//: Create your own value typed ParseObject.\nstruct GameScore: ParseObject {\n\n    //: These are required by `ParseObject`.\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: Your own properties.\n    var points: Int?\n    var location: ParseGeoPoint?\n    var name: String?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.points,\n                                     original: object) {\n            updated.points = object.points\n        }\n        if updated.shouldRestoreKey(\\.name,\n                                     original: object) {\n            updated.name = object.name\n        }\n        if updated.shouldRestoreKey(\\.location,\n                                     original: object) {\n            updated.location = object.location\n        }\n        return updated\n    }\n}\n\n//: It's recommended to place custom initializers in an extension\n//: to preserve the memberwise initializer.\nextension GameScore {\n    //: Custom initializer.\n    init(name: String, points: Int) {\n        self.name = name\n        self.points = points\n    }\n}\n\n//: To use queries with SwiftUI\n\n//: To create a custom view model that queries GameScore's.\nclass ViewModel: ObservableObject {\n    @Published var objects = [GameScore]()\n    @Published var error: ParseError?\n\n    private var subscriptions = Set<AnyCancellable>()\n\n    init() {\n        fetchScores()\n    }\n\n    func fetchScores() {\n        let query = GameScore.query(\"points\" > 2)\n            .order([.descending(\"points\")])\n        let publisher = query\n            .findPublisher()\n            .sink(receiveCompletion: { result in\n                switch result {\n                case .failure(let error):\n                    //: Publish error.\n                    self.error = error\n                case .finished:\n                    print(\"Successfully queried data\")\n                }\n            },\n            receiveValue: {\n                //: Publish found objects\n                self.objects = $0\n                print(\"Found \\(self.objects.count), objects: \\(self.objects)\")\n            })\n        publisher.store(in: &subscriptions)\n    }\n}\n\n//: Create a SwiftUI view.\nstruct ContentView: View {\n\n    //: A view model in SwiftUI\n    @StateObject var viewModel = ViewModel()\n\n    var body: some View {\n        NavigationView {\n            if let error = viewModel.error {\n                Text(error.description)\n            } else {\n                //: Warning - List seems to only work in Playgrounds Xcode 13+.\n                List(viewModel.objects, id: \\.id) { object in\n                    VStack(alignment: .leading) {\n                        Text(\"Points: \\(String(describing: object.points))\")\n                            .font(.headline)\n                        if let createdAt = object.createdAt {\n                            Text(\"\\(createdAt.description)\")\n                        }\n                    }\n                }\n            }\n            Spacer()\n        }\n    }\n}\n\nPlaygroundPage.current.setLiveView(ContentView())\n\nPlaygroundPage.current.finishExecution()\n//: [Next](@next)\n"
  },
  {
    "path": "ParseSwift.playground/Pages/19 - SwiftUI - LiveQuery.xcplaygroundpage/Contents.swift",
    "content": "//: [Previous](@previous)\n\n//: If you are using Xcode 13+, ignore the comments below:\n//: For this page, make sure your build target is set to ParseSwift (iOS) and targeting\n//: an iPhone, iPod, or iPad. Also be sure your `Playground Settings`\n//: in the `File Inspector` is `Platform = iOS`. This is because\n//: SwiftUI in macOS Playgrounds does not seem to build correctly\n//: Be sure to switch your target and `Playground Settings` back to\n//: macOS after leaving this page.\n\nimport PlaygroundSupport\nimport Foundation\nimport ParseSwift\nimport SwiftUI\n\nPlaygroundPage.current.needsIndefiniteExecution = true\n\ninitializeParse()\n\n//: Create your own value typed ParseObject.\nstruct GameScore: ParseObject {\n    //: These are required by `ParseObject`.\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: Your own properties.\n    var points: Int? = 0\n    var location: ParseGeoPoint?\n    var name: String?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.points,\n                                     original: object) {\n            updated.points = object.points\n        }\n        if updated.shouldRestoreKey(\\.name,\n                                     original: object) {\n            updated.name = object.name\n        }\n        if updated.shouldRestoreKey(\\.location,\n                                     original: object) {\n            updated.location = object.location\n        }\n        return updated\n    }\n}\n\n//: It's recommended to place custom initializers in an extension\n//: to preserve the memberwise initializer.\nextension GameScore {\n    //: Custom initializer.\n    init(name: String, points: Int) {\n        self.name = name\n        self.points = points\n    }\n}\n\n//: Be sure you have LiveQuery enabled on your server.\n\n//: Create a query just as you normally would.\nvar query = GameScore.query(\"points\" < 11)\n\n//: To use subscriptions inside of SwiftUI\nstruct ContentView: View {\n\n    //: A LiveQuery subscription can be used as a view model in SwiftUI\n    @StateObject var subscription = query.subscribe!\n\n    var body: some View {\n        VStack {\n\n            if subscription.subscribed != nil {\n                Text(\"Subscribed to query!\")\n            } else if subscription.unsubscribed != nil {\n                Text(\"Unsubscribed from query!\")\n            } else if let event = subscription.event {\n\n                //: This is how you register to receive notifications of events related to your LiveQuery.\n                switch event.event {\n\n                case .entered(let object):\n                    Text(\"Entered with points: \\(String(describing: object.points))\")\n                case .left(let object):\n                    Text(\"Left with points: \\(String(describing: object.points))\")\n                case .created(let object):\n                    Text(\"Created with points: \\(String(describing: object.points))\")\n                case .updated(let object):\n                    Text(\"Updated with points: \\(String(describing: object.points))\")\n                case .deleted(let object):\n                    Text(\"Deleted with points: \\(String(describing: object.points))\")\n                }\n            } else {\n                Text(\"Not subscribed to a query\")\n            }\n\n            Text(\"Update GameScore in Parse Dashboard to see changes here:\")\n\n            Button(action: {\n                try? query.unsubscribe()\n            }, label: {\n                Text(\"Unsubscribe\")\n                    .font(.headline)\n                    .background(Color.red)\n                    .foregroundColor(.white)\n                    .padding()\n                    .cornerRadius(20.0)\n            })\n            Spacer()\n        }\n    }\n}\n\nPlaygroundPage.current.setLiveView(ContentView())\n\nPlaygroundPage.current.finishExecution()\n//: [Next](@next)\n"
  },
  {
    "path": "ParseSwift.playground/Pages/2 - Finding Objects.xcplaygroundpage/Contents.swift",
    "content": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//: `My Mac` or whatever the name of your mac is. Also be sure your `Playground Settings`\n//: in the `File Inspector` is `Platform = macOS`. This is because\n//: Keychain in iOS Playgrounds behaves differently. Every page in Playgrounds should\n//: be set to build for `macOS` unless specified.\n\nimport PlaygroundSupport\nimport Foundation\nimport ParseSwift\nPlaygroundPage.current.needsIndefiniteExecution = true\n\ninitializeParse()\n\nstruct GameScore: ParseObject {\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: Your own properties.\n    var points: Int?\n    var timeStamp: Date? = Date()\n    var oldScore: Int?\n    var isHighest: Bool?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.points,\n                                     original: object) {\n            updated.points = object.points\n        }\n        if updated.shouldRestoreKey(\\.timeStamp,\n                                     original: object) {\n            updated.timeStamp = object.timeStamp\n        }\n        if updated.shouldRestoreKey(\\.oldScore,\n                                     original: object) {\n            updated.oldScore = object.oldScore\n        }\n        if updated.shouldRestoreKey(\\.isHighest,\n                                     original: object) {\n            updated.isHighest = object.isHighest\n        }\n        return updated\n    }\n}\n\nvar score = GameScore()\nscore.points = 200\nscore.oldScore = 10\nscore.isHighest = true\ndo {\n    try score.save()\n} catch {\n    print(error)\n}\n\nlet afterDate = Date().addingTimeInterval(-300)\nvar query = GameScore.query(\"points\" > 50,\n                            \"createdAt\" > afterDate)\n    .order([.descending(\"points\")])\n\n//: Query asynchronously (preferred way) - Performs work on background\n//: queue and returns to specified callbackQueue.\n//: If no callbackQueue is specified it returns to main queue.\nquery.limit(2)\n    .order([.descending(\"points\")])\n    .find(callbackQueue: .main) { results in\n    switch results {\n    case .success(let scores):\n\n        assert(scores.count >= 1)\n        scores.forEach { score in\n            guard let createdAt = score.createdAt else { fatalError() }\n            assert(createdAt.timeIntervalSince1970 > afterDate.timeIntervalSince1970, \"date should be ok\")\n            print(\"Found score: \\(score)\")\n        }\n\n    case .failure(let error):\n        if error.equalsTo(.objectNotFound) {\n            assertionFailure(\"Object not found for this query\")\n        } else {\n            assertionFailure(\"Error querying: \\(error)\")\n        }\n    }\n}\n\n//: Query synchronously (not preferred - all operations on current queue).\nlet results = try query.find()\nassert(results.count >= 1)\nresults.forEach { score in\n    guard let createdAt = score.createdAt else { fatalError() }\n    assert(createdAt.timeIntervalSince1970 > afterDate.timeIntervalSince1970, \"date should be ok\")\n    print(\"Found score: \\(score)\")\n}\n\n//: Query first asynchronously (preferred way) - Performs work on background\n//: queue and returns to specified callbackQueue.\n//: If no callbackQueue is specified it returns to main queue.\nquery.first { results in\n    switch results {\n    case .success(let score):\n\n        guard score.objectId != nil,\n            let createdAt = score.createdAt else { fatalError() }\n        assert(createdAt.timeIntervalSince1970 > afterDate.timeIntervalSince1970, \"date should be ok\")\n        print(\"Found score: \\(score)\")\n\n    case .failure(let error):\n        if error.containedIn([.objectNotFound, .invalidQuery]) {\n            assertionFailure(\"The query is invalid or the object is not found.\")\n        } else {\n            assertionFailure(\"Error querying: \\(error)\")\n        }\n    }\n}\n\n//: Query first asynchronously (preferred way) - Performs work on background\n//: queue and returns to specified callbackQueue.\n//: If no callbackQueue is specified it returns to main queue.\nquery.withCount { results in\n    switch results {\n    case .success(let (score, count)):\n        print(\"Found scores: \\(score) total amount: \\(count)\")\n\n    case .failure(let error):\n        if error.containedIn([.objectNotFound, .invalidQuery]) {\n            assertionFailure(\"The query is invalid or the object is not found.\")\n        } else {\n            assertionFailure(\"Error querying: \\(error)\")\n        }\n    }\n}\n\n//: Query based on relative time.\nlet queryRelative = GameScore.query(relative(\"createdAt\" < \"in 10 minutes\"))\nqueryRelative.find { results in\n    switch results {\n    case .success(let scores):\n\n        print(\"Found scores using relative time: \\(scores)\")\n\n    case .failure(let error):\n        print(\"Error querying: \\(error)\")\n    }\n}\n\nlet querySelect = query.select(\"points\")\nquerySelect.first { results in\n    switch results {\n    case .success(let score):\n\n        guard score.objectId != nil,\n            let createdAt = score.createdAt else { fatalError() }\n        assert(createdAt.timeIntervalSince1970 > afterDate.timeIntervalSince1970, \"date should be ok\")\n        print(\"Found score using select: \\(score)\")\n\n    case .failure(let error):\n        if let parseError = error.equalsTo(.objectNotFound) {\n            assertionFailure(\"Object not found: \\(parseError)\")\n        } else {\n            assertionFailure(\"Error querying: \\(error)\")\n        }\n    }\n}\n\nlet queryExclude = query.exclude(\"points\")\nqueryExclude.first { results in\n    switch results {\n    case .success(let score):\n\n        guard score.objectId != nil,\n            let createdAt = score.createdAt else { fatalError() }\n        assert(createdAt.timeIntervalSince1970 > afterDate.timeIntervalSince1970, \"date should be ok\")\n        print(\"Found score using exclude: \\(score)\")\n\n    case .failure(let error):\n        if let parseError = error.containedIn(.objectNotFound, .invalidQuery) {\n            assertionFailure(\"Matching error found: \\(parseError)\")\n        } else {\n            assertionFailure(\"Error querying: \\(error)\")\n        }\n    }\n}\n\nPlaygroundPage.current.finishExecution()\n//: [Next](@next)\n"
  },
  {
    "path": "ParseSwift.playground/Pages/20 - Cloud Schemas.xcplaygroundpage/Contents.swift",
    "content": "//: [Previous](@previous)\n\n/*:\n The code in this Playground is intended to run at the\n server level only. It is not intended to be run in client\n applications as it requires the use of the master key.\n */\n\nimport PlaygroundSupport\nimport Foundation\nimport ParseSwift\n\nPlaygroundPage.current.needsIndefiniteExecution = true\ninitializeParse()\n\n//: Youe specific _User value type.\nstruct User: ParseUser {\n    //: These are required by `ParseObject`.\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: These are required by `ParseUser`.\n    var username: String?\n    var email: String?\n    var emailVerified: Bool?\n    var password: String?\n    var authData: [String: [String: String]?]?\n\n    //: Your custom keys.\n    var customKey: String?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.customKey,\n                                     original: object) {\n            updated.customKey = object.customKey\n        }\n        return updated\n    }\n}\n\n//: Create your own value typed `ParseObject`.\nstruct GameScore2: ParseObject {\n    //: These are required by ParseObject\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: Your own properties.\n    var points: Int?\n    var level: Int?\n    var data: ParseBytes?\n    var owner: User?\n    var rivals: [User]?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.points,\n                                     original: object) {\n            updated.points = object.points\n        }\n        if updated.shouldRestoreKey(\\.level,\n                                     original: object) {\n            updated.level = object.level\n        }\n        if updated.shouldRestoreKey(\\.data,\n                                     original: object) {\n            updated.data = object.data\n        }\n        if updated.shouldRestoreKey(\\.owner,\n                                     original: object) {\n            updated.owner = object.owner\n        }\n        if updated.shouldRestoreKey(\\.rivals,\n                                     original: object) {\n            updated.rivals = object.rivals\n        }\n        return updated\n    }\n}\n\n/*:\n It's recommended to place custom initializers in an extension\n to preserve the memberwise initializer.\n */\nextension GameScore2 {\n\n    init(points: Int) {\n        self.points = points\n    }\n\n    init(objectId: String?) {\n        self.objectId = objectId\n    }\n}\n\n//: First lets create a new CLP for the new schema.\nlet clp = ParseCLP(requiresAuthentication: true, publicAccess: false)\n    .setAccessPublic(true, on: .get)\n    .setAccessPublic(true, on: .find)\n\n//: Next we use the CLP to create the new schema and add fields to it.\nvar gameScoreSchema = ParseSchema<GameScore2>(classLevelPermissions: clp)\n    .addField(\"points\",\n              type: .number,\n              options: ParseFieldOptions<Int>(required: false, defauleValue: nil))\n    .addField(\"level\",\n              type: .number,\n              options: ParseFieldOptions<Int>(required: false, defauleValue: nil))\n    .addField(\"data\",\n              type: .bytes,\n              options: ParseFieldOptions<String>(required: false, defauleValue: nil))\n\ndo {\n    gameScoreSchema = try gameScoreSchema\n        .addField(\"owner\",\n                  type: .pointer,\n                  options: ParseFieldOptions<User>(required: false, defauleValue: nil))\n        .addField(\"rivals\",\n                  type: .array,\n                  options: ParseFieldOptions<[User]>(required: false, defauleValue: nil))\n} catch {\n    print(\"Cannot add field: \\(gameScoreSchema)\")\n}\n\n//: Now lets create the schema on the server.\ngameScoreSchema.create { result in\n    switch result {\n    case .success(let savedSchema):\n        print(\"Check GameScore2 in Dashboard. \\nThe created schema:  \\(savedSchema)\")\n    case .failure(let error):\n        print(\"Could not save schema: \\(error)\")\n    }\n}\n\n//: We can update the CLP to only allow access to users specified in the \"owner\" field.\nlet clp2 = clp.setPointerFields(Set([\"owner\"]), on: .get)\ngameScoreSchema.classLevelPermissions = clp2\n\n//: In addition, we can add an index.\ngameScoreSchema = gameScoreSchema.addIndex(\"myIndex\", field: \"level\", index: 1)\n\n//: Next, we need to update the schema on the server with the changes.\ngameScoreSchema.update { result in\n    switch result {\n    case .success(let updatedSchema):\n        print(\"Check GameScore2 in Dashboard. \\nThe updated schema: \\(updatedSchema)\")\n        /*:\n         Updated the current gameScoreSchema with the newest.\n         */\n        gameScoreSchema = updatedSchema\n    case .failure(let error):\n        print(\"Could not update schema: \\(error)\")\n    }\n}\n\n//: Indexes can also be deleted.\ngameScoreSchema = gameScoreSchema.deleteIndex(\"myIndex\")\n\n//: Next, we need to update the schema on the server with the changes.\ngameScoreSchema.update { result in\n    switch result {\n    case .success(let updatedSchema):\n        print(\"Check GameScore2 in Dashboard. \\nThe updated schema: \\(updatedSchema)\")\n        /*:\n         Updated the current gameScoreSchema with the newest.\n         */\n        gameScoreSchema = updatedSchema\n    case .failure(let error):\n        print(\"Could not update schema: \\(error)\")\n    }\n}\n\n//: We can also fetch the schema.\ngameScoreSchema.fetch { result in\n    switch result {\n    case .success(let fetchedGameScore):\n        print(\"The fetched GameScore2 schema is: \\(fetchedGameScore)\")\n    case .failure(let error):\n        print(\"Could not fetch schema: \\(error)\")\n    }\n}\n\n/*:\n Fields can also be deleted on a schema. Lets remove\n the **data** field since it is not going being used.\n*/\ngameScoreSchema = gameScoreSchema.deleteField(\"data\")\n\n//: Next, we need to update the schema on the server with the changes.\ngameScoreSchema.update { result in\n    switch result {\n    case .success(let updatedSchema):\n        print(\"Check GameScore2 in Dashboard. \\nThe updated schema: \\(updatedSchema)\")\n        /*:\n         Updated the current gameScoreSchema with the newest.\n         */\n        gameScoreSchema = updatedSchema\n    case .failure(let error):\n        print(\"Could not update schema: \\(error)\")\n    }\n}\n\n/*:\n Sets of fields can also be protected from access. Lets protect\n some fields from access.\n*/\nvar clp3 = gameScoreSchema.classLevelPermissions\nclp3 = clp3?\n    .setProtectedFieldsPublic([\"owner\"])\n    .setProtectedFields([\"level\"], userField: \"rivals\")\ngameScoreSchema.classLevelPermissions = clp3\n\n//: Next, we need to update the schema on the server with the changes.\ngameScoreSchema.update { result in\n    switch result {\n    case .success(let updatedSchema):\n        print(\"Check GameScore2 in Dashboard. \\nThe updated schema: \\(updatedSchema)\")\n        /*:\n         Updated the current gameScoreSchema with the newest.\n         */\n        gameScoreSchema = updatedSchema\n    case .failure(let error):\n        print(\"Could not update schema: \\(error)\")\n    }\n}\n\n//: Now lets save a new object to the new schema.\nvar gameScore = GameScore2()\ngameScore.points = 120\ngameScore.owner = User.current\n\ngameScore.save { result in\n    switch result {\n    case .success(let savedGameScore):\n        print(\"The saved GameScore is: \\(savedGameScore)\")\n    case .failure(let error):\n        print(\"Could not save schema: \\(error)\")\n    }\n}\n\n//: You can delete all objects your schema by purging them.\ngameScoreSchema.purge { result in\n    switch result {\n    case .success:\n        print(\"All objects have been purged from this schema.\")\n    case .failure(let error):\n        print(\"Could not purge schema: \\(error)\")\n    }\n}\n\n/*:\n As long as there is no data in your `ParseSchema` you can\n delete the schema.\n*/\n gameScoreSchema.delete { result in\n    switch result {\n    case .success:\n        print(\"The schema has been deleted.\")\n    case .failure(let error):\n        print(\"Could not delete the schema: \\(error)\")\n    }\n}\n\nPlaygroundPage.current.finishExecution()\n//: [Next](@next)\n"
  },
  {
    "path": "ParseSwift.playground/Pages/21 - Cloud Push Notifications.xcplaygroundpage/Contents.swift",
    "content": "//: [Previous](@previous)\n\n/*:\n The code in this Playground is intended to run at the\n server level only. It is not intended to be run in client\n applications as it requires the use of the master key.\n */\n\nimport PlaygroundSupport\nimport Foundation\nimport ParseSwift\n\nPlaygroundPage.current.needsIndefiniteExecution = true\ninitializeParse()\n\nstruct Installation: ParseInstallation {\n    //: These are required by `ParseObject`.\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: These are required by `ParseInstallation`.\n    var installationId: String?\n    var deviceType: String?\n    var deviceToken: String?\n    var badge: Int?\n    var timeZone: String?\n    var channels: [String]?\n    var appName: String?\n    var appIdentifier: String?\n    var appVersion: String?\n    var parseVersion: String?\n    var localeIdentifier: String?\n\n    //: Your custom keys\n    var customKey: String?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.customKey,\n                                     original: object) {\n            updated.customKey = object.customKey\n        }\n        return updated\n    }\n}\n\n/*:\n We will begin by creating the payload information we want to\n send in the push notification.\n */\nlet helloAlert = ParsePushAppleAlert(body: \"Hello from ParseSwift!\")\nlet applePayload = ParsePushPayloadApple(alert: helloAlert)\n    .setBadge(1)\n\n/*:\n We now crate a query where the `objectId`\n is not null or undefined.\n*/\nlet installationQuery = Installation.query(isNotNull(key: \"objectId\"))\n\n//: Now create a new push notification using the payload and query.\nlet push = ParsePush(payload: applePayload, query: installationQuery)\n\n//: Creating this property to use later in the playground.\nvar pushStatusId = \"\"\n\n//: You can send the push notification whenever you are ready.\npush.send { result in\n    switch result {\n    case .success(let statusId):\n        print(\"The push was created with id: \\\"\\(statusId)\\\"\")\n        //: Update the stored property with the lastest status id.\n        pushStatusId = statusId\n    case .failure(let error):\n        print(\"Could not create push: \\(error)\")\n    }\n}\n\n//: You can fetch the status of notificaiton if you know it is id.\npush.fetchStatus(pushStatusId) { result in\n    switch result {\n    case .success(let pushStatus):\n        print(\"The push status is: \\\"\\(pushStatus)\\\"\")\n    case .failure(let error):\n        print(\"Could not fetch push status: \\(error)\")\n    }\n}\n\n/*:\n Lets create another Push, this time by incrementing the badge\n and using channels instead of a query.\n */\nlet helloAgainAlert = ParsePushAppleAlert(body: \"Hello from ParseSwift again!\")\nlet applePayload2 = ParsePushPayloadApple(alert: helloAgainAlert)\n    .incrementBadge()\n\nvar push2 = ParsePush(payload: applePayload2)\n//: Set all channels the notificatioin should be published to.\npush2.channels = Set([\"newDevices\"])\n\n//: You can send the push notification whenever you are ready.\npush2.send { result in\n    switch result {\n    case .success(let statusId):\n        print(\"The push was created with id: \\\"\\(statusId)\\\"\")\n        //: Update the stored property with the lastest status id.\n        pushStatusId = statusId\n    case .failure(let error):\n        print(\"Could not create push: \\(error)\")\n    }\n}\n\n/*:\n Similar to before, you can fetch the status of notificaiton\n if you know the id.\n */\npush2.fetchStatus(pushStatusId) { result in\n    switch result {\n    case .success(let pushStatus):\n        print(\"The push status is: \\\"\\(pushStatus)\\\"\")\n    case .failure(let error):\n        print(\"Could not fetch push status: \\(error)\")\n    }\n}\n\n/*:\n You can also send push notifications using Firebase Cloud Messanger.\n */\nlet helloNotification = ParsePushFirebaseNotification(body: \"Hello from ParseSwift using FCM!\")\nlet firebasePayload = ParsePushPayloadFirebase(notification: helloNotification)\n\nlet push3 = ParsePush(payload: firebasePayload, query: installationQuery)\n\n//: You can send the push notification whenever you are ready.\npush3.send { result in\n    switch result {\n    case .success(let statusId):\n        print(\"The Firebase push was created with id: \\\"\\(statusId)\\\"\")\n        //: Update the stored property with the lastest status id.\n        pushStatusId = statusId\n    case .failure(let error):\n        print(\"Could not create push: \\(error)\")\n    }\n}\n\n/*:\n Similar to before, you can fetch the status of notificaiton\n if you know the id.\n */\npush3.fetchStatus(pushStatusId) { result in\n    switch result {\n    case .success(let pushStatus):\n        print(\"The Firebase push status is: \\\"\\(pushStatus)\\\"\")\n    case .failure(let error):\n        print(\"Could not fetch push status: \\(error)\")\n    }\n}\n\n/*:\n If you have a mixed push environment and are querying\n multiple ParsePushStatus's you will can use the any\n payload, `ParsePushPayloadAny`.\n */\nlet query = ParsePushStatus<ParsePushPayloadAny>\n    .query(isNotNull(key: \"objectId\"))\n\n/*:\n Be sure to add the `.userMasterKey option when doing\n anything with `ParsePushStatus` directly.\n*/\nquery.findAll(options: [.useMasterKey]) { result in\n    switch result {\n    case .success(let pushStatus):\n        print(\"All matching statuses: \\\"\\(pushStatus)\\\"\")\n    case .failure(let error):\n        print(\"Could not perform query: \\(error)\")\n    }\n}\n\nPlaygroundPage.current.finishExecution()\n//: [Next](@next)\n"
  },
  {
    "path": "ParseSwift.playground/Pages/22 - Cloud Hook Functions.xcplaygroundpage/Contents.swift",
    "content": "//: [Previous](@previous)\n\n/*:\n The code in this Playground is intended to run at the\n server level only. It is not intended to be run in client\n applications as it requires the use of the master key.\n */\n\nimport PlaygroundSupport\nimport Foundation\nimport ParseSwift\n\nPlaygroundPage.current.needsIndefiniteExecution = true\ninitializeParse()\n\n/*:\n Parse Hook Functions can be created by conforming to\n `ParseHookFunctionable`.\n */\nstruct HookFunction: ParseHookFunctionable {\n    var functionName: String?\n    var url: URL?\n}\n\n/*:\n Lets create our first Hook function by first creating an instance\n with the name of the function and url for the hook.\n */\nvar myFunction = HookFunction(name: \"foo\",\n                              url: URL(string: \"https://api.example.com/foo\"))\n\n//: Then, create the function on the server.\nmyFunction.create { result in\n    switch result {\n    case .success(let newFunction):\n        print(\"Created: \\\"\\(newFunction)\\\"\")\n    case .failure(let error):\n        print(\"Could not create: \\(error)\")\n    }\n}\n\n/*:\n The function can be fetched at any time.\n */\nmyFunction.fetch { result in\n    switch result {\n    case .success(let fetchedFunction):\n        print(\"Fetched: \\\"\\(fetchedFunction)\\\"\")\n    case .failure(let error):\n        print(\"Could not fetch: \\(error)\")\n    }\n}\n\n/*:\n There will be times you need to update a Hook function.\n You can update your hook at anytime.\n */\nmyFunction.url = URL(string: \"https://api.example.com/bar\")\nmyFunction.update { result in\n    switch result {\n    case .success(let updated):\n        print(\"Updated: \\\"\\(updated)\\\"\")\n    case .failure(let error):\n        print(\"Could not update: \\(error)\")\n    }\n}\n\n/*:\n Lets fetchAll using the instance method to see all of the\n available hook functions.\n */\nmyFunction.fetchAll { result in\n    switch result {\n    case .success(let functions):\n        print(\"Current: \\\"\\(functions)\\\"\")\n    case .failure(let error):\n        print(\"Could not fetch: \\(error)\")\n    }\n}\n\n/*:\n Hook functions can also be deleted.\n */\nmyFunction.delete { result in\n    switch result {\n    case .success:\n        print(\"The Parse Cloud function was deleted successfully\")\n    case .failure(let error):\n        print(\"Could not delete: \\(error)\")\n    }\n}\n\n/*:\n You can also use the fetchAll type method to fetch all of\n the current Hook functions.\n */\nHookFunction.fetchAll { result in\n    switch result {\n    case .success(let functions):\n        print(\"Current: \\\"\\(functions)\\\"\")\n    case .failure(let error):\n        print(\"Could not fetch: \\(error)\")\n    }\n}\n\nPlaygroundPage.current.finishExecution()\n//: [Next](@next)\n"
  },
  {
    "path": "ParseSwift.playground/Pages/23 - Cloud Hook Triggers.xcplaygroundpage/Contents.swift",
    "content": "//: [Previous](@previous)\n\n/*:\n The code in this Playground is intended to run at the\n server level only. It is not intended to be run in client\n applications as it requires the use of the master key.\n */\n\nimport PlaygroundSupport\nimport Foundation\nimport ParseSwift\n\nPlaygroundPage.current.needsIndefiniteExecution = true\ninitializeParse()\n\n//: Create your own value typed `ParseObject`.\nstruct GameScore: ParseObject {\n    //: These are required by ParseObject\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: Your own properties.\n    var points: Int?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.points,\n                                     original: object) {\n            updated.points = object.points\n        }\n        return updated\n    }\n}\n\n//: It's recommended to place custom initializers in an extension\n//: to preserve the memberwise initializer.\nextension GameScore {\n\n    init(points: Int) {\n        self.points = points\n    }\n\n    init(objectId: String?) {\n        self.objectId = objectId\n    }\n}\n\n/*:\n Parse Hook Triggers can be created by conforming to\n `ParseHookFunctionable`.\n */\nstruct HookTrigger: ParseHookTriggerable {\n    var className: String?\n    var triggerName: ParseHookTriggerType?\n    var url: URL?\n}\n\n/*:\n Lets create our first Hook trigger by first creating an instance\n with the name of the trigger and url for the hook.\n */\nlet gameScore = GameScore()\nvar myTrigger = HookTrigger(object: gameScore,\n                            triggerName: .afterSave,\n                            url: URL(string: \"https://api.example.com/bar\")!)\n\n//: Then, create the trigger on the server.\nmyTrigger.create { result in\n    switch result {\n    case .success(let newFunction):\n        print(\"Created: \\\"\\(newFunction)\\\"\")\n    case .failure(let error):\n        print(\"Could not create: \\(error)\")\n    }\n}\n\n/*:\n The trigger can be fetched at any time.\n */\nmyTrigger.fetch { result in\n    switch result {\n    case .success(let fetchedFunction):\n        print(\"Fetched: \\\"\\(fetchedFunction)\\\"\")\n    case .failure(let error):\n        print(\"Could not fetch: \\(error)\")\n    }\n}\n\n/*:\n There will be times you need to update a Hook trigger.\n You can update your hook at anytime.\n */\nmyTrigger.url = URL(string: \"https://api.example.com/car\")\nmyTrigger.update { result in\n    switch result {\n    case .success(let updated):\n        print(\"Updated: \\\"\\(updated)\\\"\")\n    case .failure(let error):\n        print(\"Could not update: \\(error)\")\n    }\n}\n\n/*:\n Lets fetchAll using the instance method to see all of the\n available hook triggers.\n */\nmyTrigger.fetchAll { result in\n    switch result {\n    case .success(let triggers):\n        print(\"Current: \\\"\\(triggers)\\\"\")\n    case .failure(let error):\n        print(\"Could not fetch: \\(error)\")\n    }\n}\n\n/*:\n Hook triggers can also be deleted.\n */\nmyTrigger.delete { result in\n    switch result {\n    case .success:\n        print(\"The Parse Cloud trigger was deleted successfully\")\n    case .failure(let error):\n        print(\"Could not delete: \\(error)\")\n    }\n}\n\n/*:\n You can also use the fetchAll type method to fetch all of\n the current Hook triggers.\n */\nHookTrigger.fetchAll { result in\n    switch result {\n    case .success(let triggers):\n        print(\"Current: \\\"\\(triggers)\\\"\")\n    case .failure(let error):\n        print(\"Could not fetch: \\(error)\")\n    }\n}\n\nPlaygroundPage.current.finishExecution()\n\n//: [Next](@next)\n"
  },
  {
    "path": "ParseSwift.playground/Pages/3 - User - Sign Up.xcplaygroundpage/Contents.swift",
    "content": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//: `My Mac` or whatever the name of your mac is. Also be sure your `Playground Settings`\n//: in the `File Inspector` is `Platform = macOS`. This is because\n//: Keychain in iOS Playgrounds behaves differently. Every page in Playgrounds should\n//: be set to build for `macOS` unless specified.\n\nimport PlaygroundSupport\nimport Foundation\nPlaygroundPage.current.needsIndefiniteExecution = true\n\nimport ParseSwift\ninitializeParse()\n\nstruct User: ParseUser {\n    //: These are required by `ParseObject`.\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: These are required by `ParseUser`.\n    var username: String?\n    var email: String?\n    var emailVerified: Bool?\n    var password: String?\n    var authData: [String: [String: String]?]?\n\n    //: Your custom keys.\n    var customKey: String?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.customKey,\n                                     original: object) {\n            updated.customKey = object.customKey\n        }\n        return updated\n    }\n}\n\n/*: Sign up user asynchronously - Performs work on background\n    queue and returns to specified callbackQueue.\n    If no callbackQueue is specified it returns to main queue.\n*/\nUser.signup(username: \"hello\", password: \"world\") { results in\n\n    switch results {\n    case .success(let user):\n\n        guard let currentUser = User.current else {\n            assertionFailure(\"Error: current user currently not stored locally\")\n            return\n        }\n\n        if !currentUser.hasSameObjectId(as: user) {\n            assertionFailure(\"Error: these two objects should match\")\n        } else {\n            print(\"Successfully signed up user \\(user)\")\n        }\n\n    case .failure(let error):\n        assertionFailure(\"Error signing up \\(error)\")\n    }\n}\n\n//: You can verify the password of the user.\n//: Note that usingPost should be set to **true** on newer servers.\nUser.verifyPassword(password: \"world\", usingPost: false) { results in\n\n    switch results {\n    case .success(let user):\n        print(user)\n\n    case .failure(let error):\n        print(\"Error verifying password \\(error)\")\n    }\n}\n\n//: Check a bad password\nUser.verifyPassword(password: \"bad\", usingPost: false) { results in\n\n    switch results {\n    case .success(let user):\n        print(user)\n\n    case .failure(let error):\n        print(\"Error verifying password \\(error)\")\n    }\n}\n\nPlaygroundPage.current.finishExecution()\n//: [Next](@next)\n"
  },
  {
    "path": "ParseSwift.playground/Pages/4 - User - Continued.xcplaygroundpage/Contents.swift",
    "content": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//: `My Mac` or whatever the name of your mac is. Also be sure your `Playground Settings`\n//: in the `File Inspector` is `Platform = macOS`. This is because\n//: Keychain in iOS Playgrounds behaves differently. Every page in Playgrounds should\n//: be set to build for `macOS` unless specified.\n\nimport PlaygroundSupport\nimport Foundation\nimport ParseSwift\n\nPlaygroundPage.current.needsIndefiniteExecution = true\ninitializeParse()\n\nstruct User: ParseUser {\n    //: These are required by `ParseObject`.\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: These are required by `ParseUser`.\n    var username: String?\n    var email: String?\n    var emailVerified: Bool?\n    var password: String?\n    var authData: [String: [String: String]?]?\n\n    //: Your custom keys.\n    var customKey: String?\n    var gameScore: GameScore?\n    var targetScore: GameScore?\n    var allScores: [GameScore]?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.customKey,\n                                     original: object) {\n            updated.customKey = object.customKey\n        }\n        if updated.shouldRestoreKey(\\.gameScore,\n                                     original: object) {\n            updated.gameScore = object.gameScore\n        }\n        if updated.shouldRestoreKey(\\.targetScore,\n                                     original: object) {\n            updated.targetScore = object.targetScore\n        }\n        if updated.shouldRestoreKey(\\.allScores,\n                                     original: object) {\n            updated.allScores = object.allScores\n        }\n        return updated\n    }\n}\n\n//: It's recommended to place custom initializers in an extension\n//: to preserve the memberwise initializer.\nextension User {\n    //: Custom init for signup.\n    init(username: String, password: String, email: String) {\n        self.username = username\n        self.password = password\n        self.email = email\n    }\n}\n\n//: Create your own value typed `ParseObject`.\nstruct GameScore: ParseObject {\n    //: These are required by ParseObject\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: Your own properties.\n    var points: Int? = 0\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.points,\n                                         original: object) {\n            updated.points = object.points\n        }\n        return updated\n    }\n}\n\n//: It's recommended to place custom initializers in an extension\n//: to preserve the memberwise initializer.\nextension GameScore {\n    //: Custom initializer.\n    init(points: Int) {\n        self.points = points\n    }\n\n    init(objectId: String?) {\n        self.objectId = objectId\n    }\n}\n\n//: Logging out - synchronously\ndo {\n    try User.logout()\n    print(\"Successfully logged out\")\n} catch let error {\n    print(\"Error logging out: \\(error)\")\n}\n\n/*:\n Login - asynchronously - Performs work on background\n queue and returns to specified callbackQueue.\n If no callbackQueue is specified it returns to main queue.\n*/\nUser.login(username: \"hello\", password: \"world\") { result in\n\n    switch result {\n    case .success(let user):\n\n        guard let currentUser = User.current else {\n            assertionFailure(\"Error: current user not stored locally\")\n            return\n        }\n        assert(currentUser.hasSameObjectId(as: user))\n        print(\"Successfully logged in as user: \\(user)\")\n\n    case .failure(let error):\n        print(\"Error logging in: \\(error)\")\n    }\n}\n\n/*:\n Save your first `customKey` value to your `ParseUser`\n Asynchrounously - Performs work on background\n queue and returns to specified callbackQueue.\n If no callbackQueue is specified it returns to main queue.\n Using `.mergeable` or `set()` allows you to only send\n the updated keys to the parse server as opposed to the\n whole object. You can chain set calls or even use\n `set()` in combination with mutating the `ParseObject`\n directly.\n*/\nvar currentUser = User.current?\n    .set(\\.customKey, to: \"myCustom\")\n    .set(\\.gameScore, to: GameScore(points: 12))\n    .set(\\.targetScore, to: GameScore(points: 100))\ncurrentUser?.allScores = [GameScore(points: 5), GameScore(points: 8)]\ncurrentUser?.save { result in\n\n    switch result {\n    case .success(let updatedUser):\n        print(\"Successfully saved custom fields of User to ParseServer: \\(updatedUser)\")\n    case .failure(let error):\n        print(\"Failed to update user: \\(error)\")\n    }\n}\n\n//: Looking at the output of user from the previous login, it only has\n//: a pointer to the `gameScore` and `targetScore` fields. You can\n//: fetch using `include` to get the gameScore.\nUser.current?.fetch(includeKeys: [\"gameScore\"]) { result in\n    switch result {\n    case .success:\n        print(\"Successfully fetched user with gameScore key: \\(String(describing: User.current))\")\n    case .failure(let error):\n        print(\"Error fetching User: \\(error)\")\n    }\n}\n\n//: The `target` gameScore is still missing. You can get all pointer fields at\n//: once by including `[\"*\"]`.\nUser.current?.fetch(includeKeys: [\"*\"]) { result in\n    switch result {\n    case .success:\n        print(\"Successfully fetched user with all keys: \\(String(describing: User.current))\")\n    case .failure(let error):\n        print(\"Error fetching User: \\(error)\")\n    }\n}\n\n//: Logging out - synchronously.\ndo {\n    try User.logout()\n    print(\"Successfully logged out\")\n} catch let error {\n    print(\"Error logging out: \\(error)\")\n}\n\n//: To add additional information when signing up a user,\n//: you should create an instance of your user first.\nvar newUser = User(username: \"parse\", password: \"aPassword*\", email: \"parse@parse.com\")\n//: Add any other additional information.\nnewUser.customKey = \"mind\"\nnewUser.signup { result in\n\n    switch result {\n    case .success(let user):\n\n        guard let currentUser = User.current else {\n            assertionFailure(\"Error: current user not stored locally\")\n            return\n        }\n        assert(currentUser.hasSameObjectId(as: user))\n        print(\"Successfully signed up as user: \\(user)\")\n\n    case .failure(let error):\n        print(\"Error logging in: \\(error)\")\n    }\n}\n\n//: Logging out - synchronously.\ndo {\n    try User.logout()\n    print(\"Successfully logged out\")\n} catch let error {\n    print(\"Error logging out: \\(error)\")\n}\n\n//: Verification Email - synchronously.\ndo {\n    try User.verificationEmail(email: \"hello@parse.org\")\n    print(\"Successfully requested verification email be sent\")\n} catch let error {\n    print(\"Error requesting verification email be sent: \\(error)\")\n}\n\n//: Password Reset Request - synchronously.\ndo {\n    try User.passwordReset(email: \"hello@parse.org\")\n    print(\"Successfully requested password reset\")\n} catch let error {\n    print(\"Error requesting password reset: \\(error)\")\n}\n\n//: Logging in anonymously.\nUser.anonymous.login { result in\n    switch result {\n    case .success:\n        print(\"Successfully logged in \\(String(describing: User.current))\")\n        print(\"Session token: \\(String(describing: User.current?.sessionToken))\")\n    case .failure(let error):\n        print(\"Error logging in: \\(error)\")\n    }\n}\n\n//: Convert the anonymous user to a real new user.\nvar currentUser2 = User.current\ncurrentUser2?.username = \"bye\"\ncurrentUser2?.password = \"world\"\ncurrentUser2?.signup { result in\n    switch result {\n\n    case .success(let user):\n        print(\"Parse signup successful: \\(user)\")\n        print(\"Session token: \\(String(describing: User.current?.sessionToken))\")\n    case .failure(let error):\n        print(\"Error logging in: \\(error)\")\n    }\n}\n\nPlaygroundPage.current.finishExecution()\n//: [Next](@next)\n"
  },
  {
    "path": "ParseSwift.playground/Pages/5 - ACL.xcplaygroundpage/Contents.swift",
    "content": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//: `My Mac` or whatever the name of your mac is. Also be sure your `Playground Settings`\n//: in the `File Inspector` is `Platform = macOS`. This is because\n//: Keychain in iOS Playgrounds behaves differently. Every page in Playgrounds should\n//: be set to build for `macOS` unless specified.\n\nimport PlaygroundSupport\nimport Foundation\nimport ParseSwift\n\nPlaygroundPage.current.needsIndefiniteExecution = true\ninitializeParse()\n\ndo {\n    var acl = ParseACL()\n    acl.publicRead = true\n    acl.publicWrite = false\n    try ParseACL.setDefaultACL(acl, withAccessForCurrentUser: true)\n} catch {\n    assertionFailure(\"Error storing default ACL to Keychain: \\(error)\")\n}\n\n//: Create your own value typed ParseObject.\nstruct GameScore: ParseObject {\n    //: These are required by ParseObject\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: Your own properties\n    var points: Int?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.points,\n                                     original: object) {\n            updated.points = object.points\n        }\n        return updated\n    }\n}\n\n//: It's recommended to place custom initializers in an extension\n//: to preserve the memberwise initializer.\nextension GameScore {\n    //: Custom initializer.\n    init(points: Int) {\n        self.points = points\n    }\n}\n\n//: Define initial GameScores.\nvar score = GameScore(points: 40)\n\n/*: Save asynchronously (preferred way) - Performs work on background\n    queue and returns to specified callbackQueue.\n    If no callbackQueue is specified it returns to main queue.\n*/\nscore.save { result in\n    switch result {\n    case .success(let savedScore):\n        assert(savedScore.objectId != nil)\n        assert(savedScore.createdAt != nil)\n        assert(savedScore.updatedAt != nil)\n        assert(savedScore.points == 40)\n        assert(savedScore.ACL != nil)\n\n        print(\"Saved score with ACL: \\(savedScore)\")\n\n    case .failure(let error):\n        assertionFailure(\"Error saving: \\(error)\")\n    }\n}\n\nPlaygroundPage.current.finishExecution()\n//: [Next](@next)\n"
  },
  {
    "path": "ParseSwift.playground/Pages/6 - Installation.xcplaygroundpage/Contents.swift",
    "content": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//: `My Mac` or whatever the name of your mac is. Also be sure your `Playground Settings`\n//: in the `File Inspector` is `Platform = macOS`. This is because\n//: Keychain in iOS Playgrounds behaves differently. Every page in Playgrounds should\n//: be set to build for `macOS` unless specified.\n\nimport PlaygroundSupport\nimport Foundation\nimport ParseSwift\n\nPlaygroundPage.current.needsIndefiniteExecution = true\ninitializeParse()\n\nstruct Installation: ParseInstallation {\n    //: These are required by `ParseObject`.\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: These are required by `ParseInstallation`.\n    var installationId: String?\n    var deviceType: String?\n    var deviceToken: String?\n    var badge: Int?\n    var timeZone: String?\n    var channels: [String]?\n    var appName: String?\n    var appIdentifier: String?\n    var appVersion: String?\n    var parseVersion: String?\n    var localeIdentifier: String?\n\n    //: Your custom keys\n    var customKey: String?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.customKey,\n                                     original: object) {\n            updated.customKey = object.customKey\n        }\n        return updated\n    }\n}\n\n/*: Save your first `customKey` value to your `ParseInstallation`.\n    Performs work on background queue and returns to designated on\n    designated callbackQueue. If no callbackQueue is specified it\n    returns to main queue. Note that this may be the first time you\n    are saving your Installation.\n */\nlet currentInstallation = Installation.current\ncurrentInstallation?.save { results in\n\n    switch results {\n    case .success(let updatedInstallation):\n        print(\"Successfully saved Installation to ParseServer: \\(updatedInstallation)\")\n    case .failure(let error):\n        print(\"Failed to update installation: \\(error)\")\n    }\n}\n\n/*:\n Update your `ParseInstallation` `customKey` and `channels` values.\n Performs work on background queue and returns to designated on\n designated callbackQueue. If no callbackQueue is specified it\n returns to main queue. Using `.mergeable` or `set()`\n allows you to only send the updated keys to the\n parse server as opposed to the whole object.\n */\nvar installationToUpdate = Installation.current?.mergeable\ninstallationToUpdate?.customKey = \"myCustomInstallationKey2\"\ninstallationToUpdate?.channels = [\"newDevices\"]\ninstallationToUpdate?.save { results in\n\n    switch results {\n    case .success(let updatedInstallation):\n        print(\"Successfully saved myCustomInstallationKey to ParseServer: \\(updatedInstallation)\")\n    case .failure(let error):\n        print(\"Failed to update installation: \\(error)\")\n    }\n}\n\n//: You can fetch your installation at anytime.\nInstallation.current?.fetch { results in\n\n    switch results {\n    case .success(let fetchedInstallation):\n        print(\"Successfully fetched installation from ParseServer: \\(fetchedInstallation)\")\n    case .failure(let error):\n        print(\"Failed to fetch installation: \\(error)\")\n    }\n\n}\n\nPlaygroundPage.current.finishExecution()\n//: [Next](@next)\n"
  },
  {
    "path": "ParseSwift.playground/Pages/7 - GeoPoint.xcplaygroundpage/Contents.swift",
    "content": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//: `My Mac` or whatever the name of your mac is. Also be sure your `Playground Settings`\n//: in the `File Inspector` is `Platform = macOS`. This is because\n//: Keychain in iOS Playgrounds behaves differently. Every page in Playgrounds should\n//: be set to build for `macOS` unless specified.\n\nimport PlaygroundSupport\nimport Foundation\nimport ParseSwift\n\nPlaygroundPage.current.needsIndefiniteExecution = true\ninitializeParse()\n\n//: Create your own value typed `ParseObject`.\nstruct GameScore: ParseObject {\n    //: These are required by ParseObject.\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var location: ParseGeoPoint?\n    var originalData: Data?\n\n    //: Your own properties\n    var points: Int?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.points,\n                                     original: object) {\n            updated.points = object.points\n        }\n        return updated\n    }\n}\n\n//: It's recommended to place custom initializers in an extension\n//: to preserve the memberwise initializer.\nextension GameScore {\n    //: Custom initializer.\n    init(points: Int) {\n        self.points = points\n    }\n}\n\n//: Define initial GameScore.\nvar score = GameScore(points: 10)\ndo {\n    try score.location = ParseGeoPoint(latitude: 40.0, longitude: -30.0)\n}\n\n/*:\n Save asynchronously (preferred way) - performs work on background\n queue and returns to specified callbackQueue.\n If no callbackQueue is specified it returns to main queue.\n*/\nscore.save { result in\n    switch result {\n    case .success(let savedScore):\n        assert(savedScore.objectId != nil)\n        assert(savedScore.createdAt != nil)\n        assert(savedScore.updatedAt != nil)\n        assert(savedScore.points == 10)\n        assert(savedScore.location != nil)\n\n        guard let location = savedScore.location else {\n            print(\"Something went wrong\")\n            return\n        }\n\n        print(location)\n\n    case .failure(let error):\n        assertionFailure(\"Error saving: \\(error)\")\n    }\n}\n\n//: Now we will show how to query based on the `ParseGeoPoint`.\nvar query: Query<GameScore> //: Store query for later user\nvar constraints = [QueryConstraint]()\n\ndo {\n    let pointToFind = try ParseGeoPoint(latitude: 40.0, longitude: -30.0)\n    constraints.append(near(key: \"location\", geoPoint: pointToFind))\n\n    query = GameScore.query(constraints)\n    query.find { results in\n        switch results {\n        case .success(let scores):\n\n            assert(scores.count >= 1)\n            scores.forEach { (score) in\n                print(\"\"\"\n                    Someone with objectId \\\"\\(score.objectId!)\\\"\n                    has a points value of \\\"\\(String(describing: score.points))\\\" near me\n                \"\"\")\n            }\n\n        case .failure(let error):\n            assertionFailure(\"Error querying: \\(error)\")\n        }\n    }\n}\n\n/*:\n If you only want to query for points in descending order, use the order enum.\n Notice the \"var\", the query has to be mutable since it is a value type.\n*/\nvar querySorted = query\nquerySorted.order([.descending(\"points\")])\nquerySorted.find { results in\n    switch results {\n    case .success(let scores):\n\n        assert(scores.count >= 1)\n        scores.forEach { (score) in\n            print(\"\"\"\n                Someone with objectId \\\"\\(score.objectId!)\\\"\n                has a points value of \\\"\\(String(describing: score.points))\\\" near me\n            \"\"\")\n        }\n\n    case .failure(let error):\n        assertionFailure(\"Error querying: \\(error)\")\n    }\n}\n\n//: If you only want to query for points > 50, you can add more constraints.\nconstraints.append(\"points\" > 9)\nvar query2 = GameScore.query(constraints)\nquery2.find { results in\n    switch results {\n    case .success(let scores):\n\n        assert(scores.count >= 1)\n        scores.forEach { (score) in\n            print(\"\"\"\n                Someone with objectId \\\"\\(score.objectId!)\\\" has a\n                points value of \\\"\\(String(describing: score.points))\\\" near me which is greater than 9\n            \"\"\")\n        }\n\n    case .failure(let error):\n        assertionFailure(\"Error querying: \\(error)\")\n    }\n}\n\n//: If you want to query for points > 50 and whose location is undefined.\nvar query3 = GameScore.query(\"points\" > 50, doesNotExist(key: \"location\"))\nquery3.find { results in\n    switch results {\n    case .success(let scores):\n\n        scores.forEach { (score) in\n            print(\"\"\"\n                Someone has a points value of \\\"\\(String(describing: score.points))\\\"\n                with no geopoint \\(String(describing: score.location))\n            \"\"\")\n        }\n\n    case .failure(let error):\n        assertionFailure(\"Error querying: \\(error)\")\n    }\n}\n\n//: If you want to query for points > 50 and whose location is null or undefined.\nvar anotherQuery3 = GameScore.query(\"points\" > 50, isNull(key: \"location\"))\nanotherQuery3.find { results in\n    switch results {\n    case .success(let scores):\n\n        scores.forEach { (score) in\n            print(\"\"\"\n                Someone has a points value of \\\"\\(String(describing: score.points))\\\"\n                with no geopoint \\(String(describing: score.location))\n            \"\"\")\n        }\n\n    case .failure(let error):\n        assertionFailure(\"Error querying: \\(error)\")\n    }\n}\n\n//: If you want to query for points > 9 and whose location is not undefined.\nvar query4 = GameScore.query(\"points\" > 9, exists(key: \"location\"))\nquery4.find { results in\n    switch results {\n    case .success(let scores):\n\n        assert(scores.count >= 1)\n        scores.forEach { (score) in\n            print(\"\"\"\n                Someone has a points of \\\"\\(String(describing: score.points))\\\"\n                with geopoint \\(String(describing: score.location))\n            \"\"\")\n        }\n\n    case .failure(let error):\n        assertionFailure(\"Error querying: \\(error)\")\n    }\n}\n\n//: If you want to query for points > 9 and whose location is not null or undefined.\nvar anotherQuery4 = GameScore.query(\"points\" > 9, isNotNull(key: \"location\"))\nanotherQuery4.find { results in\n    switch results {\n    case .success(let scores):\n\n        assert(scores.count >= 1)\n        scores.forEach { (score) in\n            print(\"\"\"\n                Someone has a points of \\\"\\(String(describing: score.points))\\\"\n                with geopoint \\(String(describing: score.location))\n            \"\"\")\n        }\n\n    case .failure(let error):\n        assertionFailure(\"Error querying: \\(error)\")\n    }\n}\n\nlet query5 = GameScore.query(\"points\" == 50)\nlet query6 = GameScore.query(\"points\" == 200)\n\nvar query7 = GameScore.query(or(queries: [query5, query6]))\nquery7.find { results in\n    switch results {\n    case .success(let scores):\n\n        scores.forEach { (score) in\n            print(\"\"\"\n                Someone has a points value of \\\"\\(String(describing: score.points))\\\"\n                with geopoint using OR \\(String(describing: score.location))\n            \"\"\")\n        }\n\n    case .failure(let error):\n        assertionFailure(\"Error querying: \\(error)\")\n    }\n}\n\n//: Find all GameScores.\nlet query8 = GameScore.query\nquery8.findAll { result in\n    switch result {\n    case .success(let scores):\n        print(scores)\n    case .failure(let error):\n        print(error.localizedDescription)\n    }\n}\n\ndo {\n    let points: [ParseGeoPoint] = [\n        try .init(latitude: 35.0, longitude: -28.0),\n        try .init(latitude: 45.0, longitude: -28.0),\n        try .init(latitude: 39.0, longitude: -35.0)\n    ]\n    let query9 = GameScore.query(withinPolygon(key: \"location\", points: points))\n    query9.find { results in\n        switch results {\n        case .success(let scores):\n\n            scores.forEach { (score) in\n                print(\"\"\"\n                    Someone has a points value of \\\"\\(String(describing: score.points))\\\"\n                    with a geolocation \\(String(describing: score.location)) within the\n                    polygon using points: \\(points)\n                \"\"\")\n            }\n        case .failure(let error):\n            assertionFailure(\"Error querying: \\(error)\")\n        }\n    }\n} catch {\n    print(\"Could not create geopoints: \\(error)\")\n}\n\ndo {\n    let points: [ParseGeoPoint] = [\n        try .init(latitude: 35.0, longitude: -28.0),\n        try .init(latitude: 45.0, longitude: -28.0),\n        try .init(latitude: 39.0, longitude: -35.0)\n    ]\n    let polygon = try ParsePolygon(points)\n    let query10 = GameScore.query(withinPolygon(key: \"location\", polygon: polygon))\n    query10.find { results in\n        switch results {\n        case .success(let scores):\n            scores.forEach { (score) in\n                print(\"\"\"\n                    Someone has a points value of \\\"\\(String(describing: score.points))\\\"\n                    with a geolocation \\(String(describing: score.location)) within the\n                    polygon: \\(polygon)\n                \"\"\")\n            }\n        case .failure(let error):\n            assertionFailure(\"Error querying: \\(error)\")\n        }\n    }\n} catch {\n    print(\"Could not create geopoints: \\(error)\")\n}\n\n//: Hint of the previous query (asynchronous)\nquery2 = query2.hint(\"_id_\")\nquery2.find { result in\n    switch result {\n    case .success(let scores):\n        print(scores)\n    case .failure(let error):\n        print(error.localizedDescription)\n    }\n}\n\n/*: Explain the previous query. Read the documentation note on `explain`\n queries and use a type-erased wrapper such as AnyCodable.\n */\n//let explain: AnyDecodable = try query8.firstExplain()\n//print(explain)\n\nPlaygroundPage.current.finishExecution()\n//: [Next](@next)\n"
  },
  {
    "path": "ParseSwift.playground/Pages/8 - Pointers.xcplaygroundpage/Contents.swift",
    "content": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//: `My Mac` or whatever the name of your mac is. Also be sure your `Playground Settings`\n//: in the `File Inspector` is `Platform = macOS`. This is because\n//: Keychain in iOS Playgrounds behaves differently. Every page in Playgrounds should\n//: be set to build for `macOS` unless specified.\n\nimport PlaygroundSupport\nimport Foundation\nimport ParseSwift\n\nPlaygroundPage.current.needsIndefiniteExecution = true\ninitializeParse()\n\n//: Create your own value typed `ParseObject`.\nstruct Book: ParseObject, ParseQueryScorable {\n    //: These are required by ParseObject\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var score: Double?\n    var originalData: Data?\n\n    //: Your own properties.\n    var title: String?\n    var relatedBook: Pointer<Book>?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.title,\n                                     original: object) {\n            updated.title = object.title\n        }\n        if updated.shouldRestoreKey(\\.relatedBook,\n                                     original: object) {\n            updated.relatedBook = object.relatedBook\n        }\n        return updated\n    }\n}\n\n//: It's recommended to place custom initializers in an extension\n//: to preserve the memberwise initializer.\nextension Book {\n\n    init(title: String) {\n        self.title = title\n    }\n}\n\nstruct Author: ParseObject {\n    //: These are required by ParseObject.\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: Your own properties.\n    var name: String?\n    var book: Book?\n    var otherBooks: [Book]?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.name,\n                                     original: object) {\n            updated.name = object.name\n        }\n        if updated.shouldRestoreKey(\\.book,\n                                     original: object) {\n            updated.book = object.book\n        }\n        if updated.shouldRestoreKey(\\.otherBooks,\n                                     original: object) {\n            updated.otherBooks = object.otherBooks\n        }\n        return updated\n    }\n}\n\n//: It's recommended to place custom initializers in an extension\n//: to preserve the memberwise initializer.\nextension Author {\n    init(name: String, book: Book) {\n        self.name = name\n        self.book = book\n    }\n}\n\nvar newBook = Book(title: \"hello\")\nlet author = Author(name: \"Alice\", book: newBook)\n\nauthor.save { result in\n    switch result {\n    case .success(let savedAuthorAndBook):\n        assert(savedAuthorAndBook.objectId != nil)\n        assert(savedAuthorAndBook.createdAt != nil)\n        assert(savedAuthorAndBook.updatedAt != nil)\n\n        print(\"Saved: \\(savedAuthorAndBook)\")\n    case .failure(let error):\n        assertionFailure(\"Error saving: \\(error)\")\n    }\n}\n\n//: Pointer array.\nlet otherBook1 = Book(title: \"I like this book\")\nlet otherBook2 = Book(title: \"I like this book also\")\nvar author2 = Author(name: \"Bruce\", book: newBook)\nauthor2.otherBooks = [otherBook1, otherBook2]\n\nauthor2.save { result in\n    switch result {\n    case .success(let savedAuthorAndBook):\n        assert(savedAuthorAndBook.objectId != nil)\n        assert(savedAuthorAndBook.createdAt != nil)\n        assert(savedAuthorAndBook.updatedAt != nil)\n        assert(savedAuthorAndBook.otherBooks?.count == 2)\n\n        /*:\n         Notice the pointer objects have not been updated on the\n         client.If you want the latest pointer objects, fetch and include them.\n         */\n        print(\"Saved: \\(savedAuthorAndBook)\")\n\n    case .failure(let error):\n        assertionFailure(\"Error saving: \\(error)\")\n    }\n}\n\n//: Query for your new saved author\nlet query1 = Author.query(\"name\" == \"Bruce\")\n\nquery1.first { results in\n    switch results {\n    case .success(let author):\n        print(\"Found author: \\(author)\")\n\n    case .failure(let error):\n        assertionFailure(\"Error querying: \\(error)\")\n    }\n}\n\n/*: You will notice in the query above, the fields `book` and `otherBooks` only contain\n arrays consisting of key/value pairs of `objectId`. These are called Pointers\n in `Parse`.\n \n If you want to retrieve the complete object pointed to in `book`, you need to add\n the field names containing the objects specifically in `include` in your query.\n*/\n\n/*: Here, we include `book`. If you wanted `book` and `otherBook`, you\n could have used: `.include([\"book\", \"otherBook\"])`.\n*/\nlet query2 = Author.query(\"name\" == \"Bruce\")\n    .include(\"book\")\n\nquery2.first { results in\n    switch results {\n    case .success(let author):\n        //: Save the book to use later\n        if let book = author.book {\n            newBook = book\n        }\n\n        print(\"Found author and included \\\"book\\\": \\(author)\")\n\n    case .failure(let error):\n        assertionFailure(\"Error querying: \\(error)\")\n    }\n}\n\n/*: When you have many fields that are pointing to objects, it may become tedious\n to add all of them to the list. You can quickly retreive all pointer objects by\n using `includeAll`. You can also use `include(\"*\")` to retrieve all pointer\n objects.\n*/\nlet query3 = Author.query(\"name\" == \"Bruce\")\n    .includeAll()\n\nquery3.first { results in\n    switch results {\n    case .success(let author):\n        print(\"Found author and included all: \\(author)\")\n\n    case .failure(let error):\n        assertionFailure(\"Error querying: \\(error)\")\n    }\n}\n\n//: You can also check if a field is equal to a ParseObject.\ndo {\n    let query4 = try Author.query(\"book\" == newBook)\n        .includeAll()\n\n    query4.first { results in\n        switch results {\n        case .success(let author):\n            print(\"Found author and included all: \\(author)\")\n\n        case .failure(let error):\n            assertionFailure(\"Error querying: \\(error)\")\n        }\n    }\n} catch {\n    print(\"\\(error)\")\n}\n\n//: Here's an example of saving Pointers as properties.\ndo {\n    //: First we query\n    let query5 = try Author.query(\"book\" == newBook)\n        .include(\"book\")\n\n    query5.first { results in\n        switch results {\n        case .success(let author):\n            print(\"Found author and included \\\"book\\\": \\(author)\")\n            /*:\n             Setup related books. Using `.mergeable` or `set()`\n             allows you to only send the updated keys to the\n             parse server as opposed to the whole object.\n            */\n            var modifiedNewBook = newBook.mergeable\n            modifiedNewBook.relatedBook = try? author.otherBooks?.first?.toPointer()\n\n            modifiedNewBook.save { result in\n                switch result {\n                case .success(let updatedBook):\n                    assert(updatedBook.objectId != nil)\n                    assert(updatedBook.createdAt != nil)\n                    assert(updatedBook.updatedAt != nil)\n                    assert(updatedBook.relatedBook != nil)\n\n                    print(\"Saved: \\(updatedBook)\")\n                case .failure(let error):\n                    assertionFailure(\"Error saving: \\(error)\")\n                }\n            }\n        case .failure(let error):\n            assertionFailure(\"Error querying: \\(error)\")\n        }\n    }\n} catch {\n    print(\"\\(error)\")\n}\n\n//: Here's an example of querying using matchesText.\ndo {\n    let query6 = try Book.query(matchesText(key: \"title\",\n                                            text: \"like\",\n                                            options: [:]))\n        .include([\"*\"])\n        .sortByTextScore()\n\n    query6.find { results in\n        switch results {\n        case .success(let books):\n            print(\"Found books and included all: \\(books)\")\n        case .failure(let error):\n            assertionFailure(\"Error querying: \\(error)\")\n        }\n    }\n} catch {\n    print(\"\\(error)\")\n}\n\n//: Batching saves with saved and unsaved pointer items.\nvar author3 = Author(name: \"Logan\", book: newBook)\nlet otherBook3 = Book(title: \"I like this book\")\nlet otherBook4 = Book(title: \"I like this book also\")\nauthor3.otherBooks = [otherBook3, otherBook4]\n\n[author3].saveAll { result in\n    switch result {\n    case .success(let savedAuthorsAndBook):\n        savedAuthorsAndBook.forEach { eachResult in\n            switch eachResult {\n            case .success(let savedAuthorAndBook):\n                assert(savedAuthorAndBook.objectId != nil)\n                assert(savedAuthorAndBook.createdAt != nil)\n                assert(savedAuthorAndBook.updatedAt != nil)\n                assert(savedAuthorAndBook.otherBooks?.count == 2)\n\n                /*:\n                 Notice the pointer objects have not been updated on the\n                 client.If you want the latest pointer objects, fetch and include them.\n                 */\n                print(\"Saved \\(savedAuthorAndBook)\")\n            case .failure(let error):\n                assertionFailure(\"Error saving: \\(error)\")\n            }\n        }\n\n    case .failure(let error):\n        assertionFailure(\"Error saving: \\(error)\")\n    }\n}\n\n//: Batching saves with unsaved pointer items.\nvar newBook2 = Book(title: \"world\")\nvar author4 = Author(name: \"Scott\", book: newBook2)\nauthor4.otherBooks = [otherBook3, otherBook4]\n\n[author4].saveAll { result in\n    switch result {\n    case .success(let savedAuthorsAndBook):\n        savedAuthorsAndBook.forEach { eachResult in\n            switch eachResult {\n            case .success(let savedAuthorAndBook):\n                assert(savedAuthorAndBook.objectId != nil)\n                assert(savedAuthorAndBook.createdAt != nil)\n                assert(savedAuthorAndBook.updatedAt != nil)\n                assert(savedAuthorAndBook.otherBooks?.count == 2)\n                author4 = savedAuthorAndBook\n                /*:\n                 Notice the pointer objects have not been updated on the\n                 client.If you want the latest pointer objects, fetch and include them.\n                 */\n                print(\"Saved: \\(savedAuthorAndBook)\")\n            case .failure(let error):\n                assertionFailure(\"Error saving: \\(error)\")\n            }\n        }\n\n    case .failure(let error):\n        assertionFailure(\"Error saving: \\(error)\")\n    }\n}\n\n//: Batching saves by updating an already saved object.\nauthor4.fetch { result in\n    switch result {\n    case .success(var fetchedAuthor):\n        print(\"The latest author: \\(fetchedAuthor)\")\n        fetchedAuthor.name = \"R.L. Stine\"\n        [fetchedAuthor].saveAll { result in\n            switch result {\n            case .success(let savedAuthorsAndBook):\n                savedAuthorsAndBook.forEach { eachResult in\n                    switch eachResult {\n                    case .success(let savedAuthorAndBook):\n                        assert(savedAuthorAndBook.objectId != nil)\n                        assert(savedAuthorAndBook.createdAt != nil)\n                        assert(savedAuthorAndBook.updatedAt != nil)\n                        assert(savedAuthorAndBook.otherBooks?.count == 2)\n\n                        print(\"Updated: \\(savedAuthorAndBook)\")\n                    case .failure(let error):\n                        assertionFailure(\"Error saving: \\(error)\")\n                    }\n                }\n\n            case .failure(let error):\n                assertionFailure(\"Error saving: \\(error)\")\n            }\n        }\n    case .failure(let error):\n        assertionFailure(\"Error fetching: \\(error)\")\n    }\n}\n\nPlaygroundPage.current.finishExecution()\n//: [Next](@next)\n"
  },
  {
    "path": "ParseSwift.playground/Pages/9 - Files.xcplaygroundpage/Contents.swift",
    "content": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//: `My Mac` or whatever the name of your mac is. Also be sure your `Playground Settings`\n//: in the `File Inspector` is `Platform = macOS`. This is because\n//: Keychain in iOS Playgrounds behaves differently. Every page in Playgrounds should\n//: be set to build for `macOS` unless specified.\n\nimport PlaygroundSupport\nimport Foundation\nimport ParseSwift\nPlaygroundPage.current.needsIndefiniteExecution = true\n\ninitializeParse()\n\n//: Create your own value typed `ParseObject`.\nstruct GameScore: ParseObject {\n    //: These are required by ParseObject\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    //: Your own properties.\n    var points: Int? = 0\n    var profilePicture: ParseFile?\n    var myData: ParseFile?\n\n    /*:\n     Optional - implement your own version of merge\n     for faster decoding after updating your `ParseObject`.\n     */\n    func merge(with object: Self) throws -> Self {\n        var updated = try mergeParse(with: object)\n        if updated.shouldRestoreKey(\\.points,\n                                     original: object) {\n            updated.points = object.points\n        }\n        if updated.shouldRestoreKey(\\.profilePicture,\n                                     original: object) {\n            updated.profilePicture = object.profilePicture\n        }\n        if updated.shouldRestoreKey(\\.myData,\n                                     original: object) {\n            updated.myData = object.myData\n        }\n        return updated\n    }\n}\n\n//: It's recommended to place custom initializers in an extension\n//: to preserve the memberwise initializer.\nextension GameScore {\n    //: Custom initializer.\n    init(points: Int) {\n        self.points = points\n    }\n\n    init(objectId: String?) {\n        self.objectId = objectId\n    }\n}\n\n//: Define initial GameScore.\nvar score = GameScore(points: 52)\n\n//: Set the link online for the file.\nlet linkToFile = URL(string: \"https://parseplatform.org/img/logo.svg\")!\n\n//: Create a new `ParseFile` for your picture.\nlet profilePic = ParseFile(name: \"profile.svg\", cloudURL: linkToFile)\n\n//: Set the picture as part of your ParseObject\nscore.profilePicture = profilePic\n\n/*:\n Save asynchronously (preferred way) - Performs work on background\n queue and returns to specified callbackQueue.\n If no callbackQueue is specified it returns to main queue.\n*/\nscore.save { result in\n    switch result {\n    case .success(let savedScore):\n        assert(savedScore.objectId != nil)\n        assert(savedScore.createdAt != nil)\n        assert(savedScore.updatedAt != nil)\n        assert(savedScore.points == 52)\n        assert(savedScore.profilePicture != nil)\n\n        print(\"Your profile picture has been successfully saved\")\n\n        //: To get the contents updated `ParseFile`, you need to fetch your GameScore.\n        savedScore.fetch { result in\n            switch result {\n            case .success(let fetchedScore):\n                guard let picture = fetchedScore.profilePicture,\n                      let url = fetchedScore.profilePicture?.url else {\n                    return\n                }\n                print(\"The new name of your saved profilePicture is: \\(picture.name)\")\n                print(\"The profilePicture is saved to your Parse Server at: \\(url)\")\n                print(\"The full details of your profilePicture ParseFile are: \\(picture)\")\n\n                //: If you need to download your profilePicture\n                picture.fetch { result in\n                    switch result {\n                    case .success(let fetchedFile):\n                        print(\"The file is now saved on your device at: \\(String(describing: fetchedFile.localURL))\")\n                        print(\"The full details of your profilePicture ParseFile are: \\(fetchedFile)\")\n                    case .failure(let error):\n                        assertionFailure(\"Error fetching: \\(error)\")\n                    }\n                }\n\n            case .failure(let error):\n                assertionFailure(\"Error fetching: \\(error)\")\n            }\n        }\n    case .failure(let error):\n        assertionFailure(\"Error saving: \\(error)\")\n    }\n}\n\n/*:\n Files can also be saved from data. Below is how to do it synchronously, but async is similar to above\n Create a new `ParseFile` for your data.\n */\nlet sampleData = \"Hello World\".data(using: .utf8)!\nlet helloFile = ParseFile(name: \"hello.txt\", data: sampleData)\n\n//: Define another GameScore.\nvar score2 = GameScore(points: 105)\nscore2.myData = helloFile\n\n//: Save synchronously (not preferred - all operations on current queue).\ndo {\n    let savedScore = try score2.save()\n    print(\"Your hello file has been successfully saved\")\n\n    //: To get the contents updated `ParseFile`, you need to fetch your GameScore.\n    let fetchedScore = try savedScore.fetch()\n    if let myData = fetchedScore.myData {\n\n        guard let url = myData.url else {\n            fatalError(\"Error: file should have url.\")\n        }\n        print(\"The new name of your saved data is: \\(myData.name)\")\n        print(\"The file is saved to your Parse Server at: \\(url)\")\n        print(\"The full details of your data file are: \\(myData)\")\n\n        //: If you need to download your file.\n        let fetchedFile = try myData.fetch()\n        if fetchedFile.localURL != nil {\n            print(\"The file is now saved at: \\(fetchedFile.localURL!)\")\n            print(\"The full details of your data ParseFile are: \\(fetchedFile)\")\n\n            /*:\n             If you want to use the data from the file to display the text file or image, you need to retreive\n             the data from the file.\n            */\n            guard let dataFromParseFile = try? Data(contentsOf: fetchedFile.localURL!) else {\n                fatalError(\"Error: Could not get data from file.\")\n            }\n\n            //: Checking to make sure the data saved on the Parse Server is the same as the original\n            if dataFromParseFile != sampleData {\n                assertionFailure(\"Data is not the same. Something went wrong.\")\n            }\n\n            guard let parseFileString = String(data: dataFromParseFile, encoding: .utf8) else {\n                fatalError(\"Error: Could not create String from data.\")\n            }\n            print(\"The data saved on parse is: \\\"\\(parseFileString)\\\"\")\n        } else {\n            assertionFailure(\"Error fetching: there should be a localURL\")\n        }\n    } else {\n        assertionFailure(\"Error fetching: there should be a localURL\")\n    }\n} catch {\n    fatalError(\"Error saving: \\(error)\")\n}\n\n/*:\n Files can also be saved from files located on your device by using:\n let localFile = ParseFile(name: \"hello.txt\", localURL: URL).\n*/\n\nPlaygroundPage.current.finishExecution()\n//: [Next](@next)\n"
  },
  {
    "path": "ParseSwift.playground/Sources/Common.swift",
    "content": "import Foundation\nimport ParseSwift\n\npublic func initializeParse(customObjectId: Bool = false) {\n    ParseSwift.initialize(applicationId: \"applicationId\",\n                          clientKey: \"clientKey\",\n                          masterKey: \"masterKey\",\n                          serverURL: URL(string: \"http://localhost:1337/1\")!,\n                          allowingCustomObjectIds: customObjectId,\n                          usingEqualQueryConstraint: false,\n                          usingDataProtectionKeychain: false)\n}\n"
  },
  {
    "path": "ParseSwift.playground/contents.xcplayground",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<playground version='6.0' target-platform='macos' display-mode='raw' buildActiveScheme='true' last-migration='1130'>\n    <pages>\n        <page name='1 - Your first Object'/>\n        <page name='2 - Finding Objects'/>\n        <page name='3 - User - Sign Up'/>\n        <page name='4 - User - Continued'/>\n        <page name='5 - ACL'/>\n        <page name='6 - Installation'/>\n        <page name='7 - GeoPoint'/>\n        <page name='8 - Pointers'/>\n        <page name='9 - Files'/>\n        <page name='10 - Cloud Code'/>\n        <page name='11 - LiveQuery'/>\n        <page name='12 - Roles and Relations'/>\n        <page name='13 - Operations'/>\n        <page name='14 - Config'/>\n        <page name='15 - Custom ObjectId'/>\n        <page name='16 - Analytics'/>\n        <page name='17 - SwiftUI - Finding Objects'/>\n        <page name='18 - SwiftUI - Finding Objects With Custom ViewModel'/>\n        <page name='19 - SwiftUI - LiveQuery'/>\n        <page name='20 - Cloud Schemas'/>\n        <page name='21 - Cloud Push Notifications'/>\n        <page name='22 - Cloud Hook Functions'/>\n        <page name='23 - Cloud Hook Triggers'/>\n    </pages>\n</playground>"
  },
  {
    "path": "ParseSwift.podtemplate",
    "content": "Pod::Spec.new do |s|\n  s.name     = \"ParseSwift\"\n  s.version  = \"[[VERSION]]\"\n  s.summary  = \"Parse Pure Swift SDK\"\n  s.homepage = \"https://github.com/parse-community/Parse-Swift\"\n  s.authors = {\n      'Corey E. Baker' => 'coreyearleon@icloud.com'\n  }\n  s.source = {\n      :git => \"#{s.homepage}.git\",\n      :tag => \"#{s.version}\",\n  }\n  s.ios.deployment_target = \"13.0\"\n  s.osx.deployment_target = \"10.15\"\n  s.tvos.deployment_target = \"13.0\"\n  s.watchos.deployment_target = \"6.0\"\n  s.swift_versions = ['5.3', '5.4', '5.5', '5.6']\n  s.source_files = \"Sources/ParseSwift/**/*.swift\"\n  s.license = {\n    :type => \"MIT\",\n    :text => <<-LICENSE\n      Copyright (c) 2022 parse-community\n      Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n      The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n      THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n    LICENSE\n  }\nend\n"
  },
  {
    "path": "ParseSwift.xcodeproj/project.pbxproj",
    "content": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section */\n\t\t4A82B7F61F254CCE0063D731 /* Parse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EE1F254B820063D731 /* Parse.swift */; };\n\t\t4AA8075B1F794242008CD551 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AA8075A1F794242008CD551 /* AppDelegate.swift */; };\n\t\t4AA807601F794242008CD551 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4AA8075E1F794242008CD551 /* Main.storyboard */; };\n\t\t4AA807621F794242008CD551 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4AA807611F794242008CD551 /* Assets.xcassets */; };\n\t\t4AA807651F794242008CD551 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4AA807631F794242008CD551 /* LaunchScreen.storyboard */; };\n\t\t4AA807701F794C31008CD551 /* KeychainStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AA8076E1F794C1C008CD551 /* KeychainStoreTests.swift */; };\n\t\t4AB8B4FE1F254AE10070F682 /* ParseSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4AB8B4F41F254AE10070F682 /* ParseSwift.framework */; };\n\t\t4AB8B5051F254AE10070F682 /* Parse.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AB8B4F71F254AE10070F682 /* Parse.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t4AFDA72A1F26DAE1002AE4FC /* Parse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EE1F254B820063D731 /* Parse.swift */; };\n\t\t4AFDA7391F26DAF8002AE4FC /* Parse.h in Headers */ = {isa = PBXBuildFile; fileRef = 4AB8B4F71F254AE10070F682 /* Parse.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t7003957625A0EE770052CB31 /* BatchUtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7003957525A0EE770052CB31 /* BatchUtilsTests.swift */; };\n\t\t7003957725A0EE770052CB31 /* BatchUtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7003957525A0EE770052CB31 /* BatchUtilsTests.swift */; };\n\t\t7003957825A0EE770052CB31 /* BatchUtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7003957525A0EE770052CB31 /* BatchUtilsTests.swift */; };\n\t\t7003959525A10DFC0052CB31 /* Messages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7003959425A10DFC0052CB31 /* Messages.swift */; };\n\t\t7003959625A10DFC0052CB31 /* Messages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7003959425A10DFC0052CB31 /* Messages.swift */; };\n\t\t7003959725A10DFC0052CB31 /* Messages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7003959425A10DFC0052CB31 /* Messages.swift */; };\n\t\t7003959825A10DFC0052CB31 /* Messages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7003959425A10DFC0052CB31 /* Messages.swift */; };\n\t\t700395A325A119430052CB31 /* Operations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700395A225A119430052CB31 /* Operations.swift */; };\n\t\t700395A425A119430052CB31 /* Operations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700395A225A119430052CB31 /* Operations.swift */; };\n\t\t700395A525A119430052CB31 /* Operations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700395A225A119430052CB31 /* Operations.swift */; };\n\t\t700395A625A119430052CB31 /* Operations.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700395A225A119430052CB31 /* Operations.swift */; };\n\t\t700395BA25A1470F0052CB31 /* Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700395B925A1470F0052CB31 /* Subscription.swift */; };\n\t\t700395BB25A1470F0052CB31 /* Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700395B925A1470F0052CB31 /* Subscription.swift */; };\n\t\t700395BC25A1470F0052CB31 /* Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700395B925A1470F0052CB31 /* Subscription.swift */; };\n\t\t700395BD25A1470F0052CB31 /* Subscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700395B925A1470F0052CB31 /* Subscription.swift */; };\n\t\t700395D125A147BE0052CB31 /* QuerySubscribable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700395D025A147BE0052CB31 /* QuerySubscribable.swift */; };\n\t\t700395D225A147BE0052CB31 /* QuerySubscribable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700395D025A147BE0052CB31 /* QuerySubscribable.swift */; };\n\t\t700395D325A147BE0052CB31 /* QuerySubscribable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700395D025A147BE0052CB31 /* QuerySubscribable.swift */; };\n\t\t700395D425A147BE0052CB31 /* QuerySubscribable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700395D025A147BE0052CB31 /* QuerySubscribable.swift */; };\n\t\t700395F225A171320052CB31 /* LiveQueryable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700395F125A171320052CB31 /* LiveQueryable.swift */; };\n\t\t700395F325A171320052CB31 /* LiveQueryable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700395F125A171320052CB31 /* LiveQueryable.swift */; };\n\t\t700395F425A171320052CB31 /* LiveQueryable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700395F125A171320052CB31 /* LiveQueryable.swift */; };\n\t\t700395F525A171320052CB31 /* LiveQueryable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700395F125A171320052CB31 /* LiveQueryable.swift */; };\n\t\t7003960925A184EF0052CB31 /* ParseLiveQuery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7003960825A184EF0052CB31 /* ParseLiveQuery.swift */; };\n\t\t7003960A25A184EF0052CB31 /* ParseLiveQuery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7003960825A184EF0052CB31 /* ParseLiveQuery.swift */; };\n\t\t7003960B25A184EF0052CB31 /* ParseLiveQuery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7003960825A184EF0052CB31 /* ParseLiveQuery.swift */; };\n\t\t7003960C25A184EF0052CB31 /* ParseLiveQuery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7003960825A184EF0052CB31 /* ParseLiveQuery.swift */; };\n\t\t7003963B25A288100052CB31 /* ParseLiveQueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7003963A25A288100052CB31 /* ParseLiveQueryTests.swift */; };\n\t\t7003963C25A288100052CB31 /* ParseLiveQueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7003963A25A288100052CB31 /* ParseLiveQueryTests.swift */; };\n\t\t7003963D25A288100052CB31 /* ParseLiveQueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7003963A25A288100052CB31 /* ParseLiveQueryTests.swift */; };\n\t\t700396EA25A3892D0052CB31 /* LiveQuerySocketDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700396E925A3892D0052CB31 /* LiveQuerySocketDelegate.swift */; };\n\t\t700396EB25A3892D0052CB31 /* LiveQuerySocketDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700396E925A3892D0052CB31 /* LiveQuerySocketDelegate.swift */; };\n\t\t700396EC25A3892D0052CB31 /* LiveQuerySocketDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700396E925A3892D0052CB31 /* LiveQuerySocketDelegate.swift */; };\n\t\t700396ED25A3892D0052CB31 /* LiveQuerySocketDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700396E925A3892D0052CB31 /* LiveQuerySocketDelegate.swift */; };\n\t\t700396F825A394AE0052CB31 /* ParseLiveQueryDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700396F725A394AE0052CB31 /* ParseLiveQueryDelegate.swift */; };\n\t\t700396F925A394AE0052CB31 /* ParseLiveQueryDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700396F725A394AE0052CB31 /* ParseLiveQueryDelegate.swift */; };\n\t\t700396FA25A394AE0052CB31 /* ParseLiveQueryDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700396F725A394AE0052CB31 /* ParseLiveQueryDelegate.swift */; };\n\t\t700396FB25A394AE0052CB31 /* ParseLiveQueryDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700396F725A394AE0052CB31 /* ParseLiveQueryDelegate.swift */; };\n\t\t7003972A25A3B0140052CB31 /* ParseURLSessionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7003972925A3B0130052CB31 /* ParseURLSessionDelegate.swift */; };\n\t\t7003972B25A3B0140052CB31 /* ParseURLSessionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7003972925A3B0130052CB31 /* ParseURLSessionDelegate.swift */; };\n\t\t7003972C25A3B0140052CB31 /* ParseURLSessionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7003972925A3B0130052CB31 /* ParseURLSessionDelegate.swift */; };\n\t\t7003972D25A3B0140052CB31 /* ParseURLSessionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7003972925A3B0130052CB31 /* ParseURLSessionDelegate.swift */; };\n\t\t7004C22025B63C7A005E0AD9 /* ParseRelation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7004C21F25B63C7A005E0AD9 /* ParseRelation.swift */; };\n\t\t7004C22125B63C7A005E0AD9 /* ParseRelation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7004C21F25B63C7A005E0AD9 /* ParseRelation.swift */; };\n\t\t7004C22225B63C7A005E0AD9 /* ParseRelation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7004C21F25B63C7A005E0AD9 /* ParseRelation.swift */; };\n\t\t7004C22325B63C7A005E0AD9 /* ParseRelation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7004C21F25B63C7A005E0AD9 /* ParseRelation.swift */; };\n\t\t7004C24D25B69207005E0AD9 /* ParseRoleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7004C22D25B69077005E0AD9 /* ParseRoleTests.swift */; };\n\t\t7004C25725B6920A005E0AD9 /* ParseRoleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7004C22D25B69077005E0AD9 /* ParseRoleTests.swift */; };\n\t\t7004C26125B6920B005E0AD9 /* ParseRoleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7004C22D25B69077005E0AD9 /* ParseRoleTests.swift */; };\n\t\t700AFE03289C3508006C1CD9 /* ParseQueryCacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700AFE02289C3508006C1CD9 /* ParseQueryCacheTests.swift */; };\n\t\t700AFE04289C3508006C1CD9 /* ParseQueryCacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700AFE02289C3508006C1CD9 /* ParseQueryCacheTests.swift */; };\n\t\t700AFE05289C3508006C1CD9 /* ParseQueryCacheTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 700AFE02289C3508006C1CD9 /* ParseQueryCacheTests.swift */; };\n\t\t70110D52250680140091CC1D /* ParseConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70110D51250680140091CC1D /* ParseConstants.swift */; };\n\t\t70110D53250680140091CC1D /* ParseConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70110D51250680140091CC1D /* ParseConstants.swift */; };\n\t\t70110D54250680140091CC1D /* ParseConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70110D51250680140091CC1D /* ParseConstants.swift */; };\n\t\t70110D55250680140091CC1D /* ParseConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70110D51250680140091CC1D /* ParseConstants.swift */; };\n\t\t70110D572506CE890091CC1D /* BaseParseInstallation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70110D562506CE890091CC1D /* BaseParseInstallation.swift */; };\n\t\t70110D582506CE890091CC1D /* BaseParseInstallation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70110D562506CE890091CC1D /* BaseParseInstallation.swift */; };\n\t\t70110D592506CE890091CC1D /* BaseParseInstallation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70110D562506CE890091CC1D /* BaseParseInstallation.swift */; };\n\t\t70110D5A2506CE890091CC1D /* BaseParseInstallation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70110D562506CE890091CC1D /* BaseParseInstallation.swift */; };\n\t\t70110D5C2506ED0E0091CC1D /* ParseInstallationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70110D5B2506ED0E0091CC1D /* ParseInstallationTests.swift */; };\n\t\t7016ED3225C3BA2000038648 /* ParseUser+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7016ED3125C3BA2000038648 /* ParseUser+combine.swift */; };\n\t\t7016ED3325C3BA2000038648 /* ParseUser+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7016ED3125C3BA2000038648 /* ParseUser+combine.swift */; };\n\t\t7016ED3425C3BA2000038648 /* ParseUser+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7016ED3125C3BA2000038648 /* ParseUser+combine.swift */; };\n\t\t7016ED3525C3BA2000038648 /* ParseUser+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7016ED3125C3BA2000038648 /* ParseUser+combine.swift */; };\n\t\t7016ED4025C4A25A00038648 /* ParseUserCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7016ED3F25C4A25A00038648 /* ParseUserCombineTests.swift */; };\n\t\t7016ED4125C4A25A00038648 /* ParseUserCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7016ED3F25C4A25A00038648 /* ParseUserCombineTests.swift */; };\n\t\t7016ED4225C4A25A00038648 /* ParseUserCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7016ED3F25C4A25A00038648 /* ParseUserCombineTests.swift */; };\n\t\t7016ED5625C4C32B00038648 /* ParseInstallation+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7016ED5525C4C32B00038648 /* ParseInstallation+combine.swift */; };\n\t\t7016ED5725C4C32B00038648 /* ParseInstallation+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7016ED5525C4C32B00038648 /* ParseInstallation+combine.swift */; };\n\t\t7016ED5825C4C32B00038648 /* ParseInstallation+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7016ED5525C4C32B00038648 /* ParseInstallation+combine.swift */; };\n\t\t7016ED5925C4C32B00038648 /* ParseInstallation+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7016ED5525C4C32B00038648 /* ParseInstallation+combine.swift */; };\n\t\t7016ED6425C4C46B00038648 /* ParseObject+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7016ED6325C4C46B00038648 /* ParseObject+combine.swift */; };\n\t\t7016ED6525C4C46B00038648 /* ParseObject+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7016ED6325C4C46B00038648 /* ParseObject+combine.swift */; };\n\t\t7016ED6625C4C46B00038648 /* ParseObject+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7016ED6325C4C46B00038648 /* ParseObject+combine.swift */; };\n\t\t7016ED6725C4C46B00038648 /* ParseObject+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7016ED6325C4C46B00038648 /* ParseObject+combine.swift */; };\n\t\t70170A442656B02D0070C905 /* ParseAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70170A432656B02C0070C905 /* ParseAnalytics.swift */; };\n\t\t70170A452656B02D0070C905 /* ParseAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70170A432656B02C0070C905 /* ParseAnalytics.swift */; };\n\t\t70170A462656B02D0070C905 /* ParseAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70170A432656B02C0070C905 /* ParseAnalytics.swift */; };\n\t\t70170A472656B02D0070C905 /* ParseAnalytics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70170A432656B02C0070C905 /* ParseAnalytics.swift */; };\n\t\t70170A492656E2FE0070C905 /* ParseAnalytics+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70170A482656E2FE0070C905 /* ParseAnalytics+combine.swift */; };\n\t\t70170A4A2656E2FE0070C905 /* ParseAnalytics+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70170A482656E2FE0070C905 /* ParseAnalytics+combine.swift */; };\n\t\t70170A4B2656E2FE0070C905 /* ParseAnalytics+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70170A482656E2FE0070C905 /* ParseAnalytics+combine.swift */; };\n\t\t70170A4C2656E2FE0070C905 /* ParseAnalytics+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70170A482656E2FE0070C905 /* ParseAnalytics+combine.swift */; };\n\t\t70170A4E2656EBA50070C905 /* ParseAnalyticsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70170A4D2656EBA50070C905 /* ParseAnalyticsTests.swift */; };\n\t\t70170A4F2656EBA50070C905 /* ParseAnalyticsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70170A4D2656EBA50070C905 /* ParseAnalyticsTests.swift */; };\n\t\t70170A502656EBA50070C905 /* ParseAnalyticsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70170A4D2656EBA50070C905 /* ParseAnalyticsTests.swift */; };\n\t\t70212D132854C82B00386163 /* ParsePushFirebaseNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70212D122854C82B00386163 /* ParsePushFirebaseNotification.swift */; };\n\t\t70212D142854C82B00386163 /* ParsePushFirebaseNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70212D122854C82B00386163 /* ParsePushFirebaseNotification.swift */; };\n\t\t70212D152854C82B00386163 /* ParsePushFirebaseNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70212D122854C82B00386163 /* ParsePushFirebaseNotification.swift */; };\n\t\t70212D162854C82B00386163 /* ParsePushFirebaseNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70212D122854C82B00386163 /* ParsePushFirebaseNotification.swift */; };\n\t\t70212D2B2855266400386163 /* ParsePushPayloadAppleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70212D262855260F00386163 /* ParsePushPayloadAppleTests.swift */; };\n\t\t70212D2C2855266400386163 /* ParsePushTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70212D172855256F00386163 /* ParsePushTests.swift */; };\n\t\t70212D2D2855266400386163 /* ParsePushAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70212D1C2855259100386163 /* ParsePushAsyncTests.swift */; };\n\t\t70212D2E2855266400386163 /* ParsePushCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70212D21285525A600386163 /* ParsePushCombineTests.swift */; };\n\t\t70212D2F2855266500386163 /* ParsePushPayloadAppleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70212D262855260F00386163 /* ParsePushPayloadAppleTests.swift */; };\n\t\t70212D302855266500386163 /* ParsePushTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70212D172855256F00386163 /* ParsePushTests.swift */; };\n\t\t70212D312855266500386163 /* ParsePushAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70212D1C2855259100386163 /* ParsePushAsyncTests.swift */; };\n\t\t70212D322855266500386163 /* ParsePushCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70212D21285525A600386163 /* ParsePushCombineTests.swift */; };\n\t\t70212D332855266600386163 /* ParsePushPayloadAppleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70212D262855260F00386163 /* ParsePushPayloadAppleTests.swift */; };\n\t\t70212D342855266600386163 /* ParsePushTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70212D172855256F00386163 /* ParsePushTests.swift */; };\n\t\t70212D352855266600386163 /* ParsePushAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70212D1C2855259100386163 /* ParsePushAsyncTests.swift */; };\n\t\t70212D362855266600386163 /* ParsePushCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70212D21285525A600386163 /* ParsePushCombineTests.swift */; };\n\t\t7023800F2747FCCD00EFC443 /* ExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7023800E2747FCCD00EFC443 /* ExtensionsTests.swift */; };\n\t\t702380102747FCCD00EFC443 /* ExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7023800E2747FCCD00EFC443 /* ExtensionsTests.swift */; };\n\t\t702380112747FCCD00EFC443 /* ExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7023800E2747FCCD00EFC443 /* ExtensionsTests.swift */; };\n\t\t7028373426BD8883007688C9 /* ParseObject+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7028373326BD8883007688C9 /* ParseObject+async.swift */; };\n\t\t7028373526BD8883007688C9 /* ParseObject+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7028373326BD8883007688C9 /* ParseObject+async.swift */; };\n\t\t7028373626BD8883007688C9 /* ParseObject+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7028373326BD8883007688C9 /* ParseObject+async.swift */; };\n\t\t7028373726BD8883007688C9 /* ParseObject+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7028373326BD8883007688C9 /* ParseObject+async.swift */; };\n\t\t7028373926BD8C89007688C9 /* ParseUser+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7028373826BD8C89007688C9 /* ParseUser+async.swift */; };\n\t\t7028373A26BD8C89007688C9 /* ParseUser+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7028373826BD8C89007688C9 /* ParseUser+async.swift */; };\n\t\t7028373B26BD8C89007688C9 /* ParseUser+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7028373826BD8C89007688C9 /* ParseUser+async.swift */; };\n\t\t7028373C26BD8C89007688C9 /* ParseUser+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7028373826BD8C89007688C9 /* ParseUser+async.swift */; };\n\t\t7033ECB325584A83009770F3 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7033ECB225584A83009770F3 /* AppDelegate.swift */; };\n\t\t7033ECB525584A83009770F3 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7033ECB425584A83009770F3 /* ViewController.swift */; };\n\t\t7033ECB825584A83009770F3 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7033ECB625584A83009770F3 /* Main.storyboard */; };\n\t\t7033ECBA25584A85009770F3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7033ECB925584A85009770F3 /* Assets.xcassets */; };\n\t\t7033ECBD25584A85009770F3 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7033ECBB25584A85009770F3 /* LaunchScreen.storyboard */; };\n\t\t7037DAB226384DE1005D7E62 /* TestParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7037DAB126384DE1005D7E62 /* TestParseEncoder.swift */; };\n\t\t7037DAB326384DE1005D7E62 /* TestParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7037DAB126384DE1005D7E62 /* TestParseEncoder.swift */; };\n\t\t7037DAB426384DE1005D7E62 /* TestParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7037DAB126384DE1005D7E62 /* TestParseEncoder.swift */; };\n\t\t70385E6428563FD10084D306 /* ParsePushPayloadFirebaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70385E6328563FD10084D306 /* ParsePushPayloadFirebaseTests.swift */; };\n\t\t70385E6528563FD10084D306 /* ParsePushPayloadFirebaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70385E6328563FD10084D306 /* ParsePushPayloadFirebaseTests.swift */; };\n\t\t70385E6628563FD10084D306 /* ParsePushPayloadFirebaseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70385E6328563FD10084D306 /* ParsePushPayloadFirebaseTests.swift */; };\n\t\t70385E68285640A30084D306 /* ParsePushPayloadAnyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70385E67285640A30084D306 /* ParsePushPayloadAnyTests.swift */; };\n\t\t70385E69285640A30084D306 /* ParsePushPayloadAnyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70385E67285640A30084D306 /* ParsePushPayloadAnyTests.swift */; };\n\t\t70385E6A285640A30084D306 /* ParsePushPayloadAnyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70385E67285640A30084D306 /* ParsePushPayloadAnyTests.swift */; };\n\t\t70385E712858D2DD0084D306 /* ParseHookTriggerable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70385E702858D2DD0084D306 /* ParseHookTriggerable.swift */; };\n\t\t70385E722858D2DD0084D306 /* ParseHookTriggerable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70385E702858D2DD0084D306 /* ParseHookTriggerable.swift */; };\n\t\t70385E732858D2DD0084D306 /* ParseHookTriggerable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70385E702858D2DD0084D306 /* ParseHookTriggerable.swift */; };\n\t\t70385E742858D2DD0084D306 /* ParseHookTriggerable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70385E702858D2DD0084D306 /* ParseHookTriggerable.swift */; };\n\t\t70385E762858E1000084D306 /* ParseHookFunctionable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70385E752858E1000084D306 /* ParseHookFunctionable.swift */; };\n\t\t70385E772858E1000084D306 /* ParseHookFunctionable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70385E752858E1000084D306 /* ParseHookFunctionable.swift */; };\n\t\t70385E782858E1000084D306 /* ParseHookFunctionable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70385E752858E1000084D306 /* ParseHookFunctionable.swift */; };\n\t\t70385E792858E1000084D306 /* ParseHookFunctionable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70385E752858E1000084D306 /* ParseHookFunctionable.swift */; };\n\t\t70385E802858EAA90084D306 /* ParseHookFunctionRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70385E7F2858EAA90084D306 /* ParseHookFunctionRequest.swift */; };\n\t\t70385E812858EAA90084D306 /* ParseHookFunctionRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70385E7F2858EAA90084D306 /* ParseHookFunctionRequest.swift */; };\n\t\t70385E822858EAA90084D306 /* ParseHookFunctionRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70385E7F2858EAA90084D306 /* ParseHookFunctionRequest.swift */; };\n\t\t70385E832858EAA90084D306 /* ParseHookFunctionRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70385E7F2858EAA90084D306 /* ParseHookFunctionRequest.swift */; };\n\t\t70385E852858F9750084D306 /* ParseHookParametable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70385E842858F9750084D306 /* ParseHookParametable.swift */; };\n\t\t70385E862858F9750084D306 /* ParseHookParametable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70385E842858F9750084D306 /* ParseHookParametable.swift */; };\n\t\t70385E872858F9750084D306 /* ParseHookParametable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70385E842858F9750084D306 /* ParseHookParametable.swift */; };\n\t\t70385E882858F9750084D306 /* ParseHookParametable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70385E842858F9750084D306 /* ParseHookParametable.swift */; };\n\t\t70386A0625D9718C0048EC1B /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70386A0525D9718C0048EC1B /* Data.swift */; };\n\t\t70386A0725D9718C0048EC1B /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70386A0525D9718C0048EC1B /* Data.swift */; };\n\t\t70386A0825D9718C0048EC1B /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70386A0525D9718C0048EC1B /* Data.swift */; };\n\t\t70386A0925D9718C0048EC1B /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70386A0525D9718C0048EC1B /* Data.swift */; };\n\t\t70386A3825D998D90048EC1B /* ParseLDAP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70386A3725D998D90048EC1B /* ParseLDAP.swift */; };\n\t\t70386A3925D998D90048EC1B /* ParseLDAP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70386A3725D998D90048EC1B /* ParseLDAP.swift */; };\n\t\t70386A3A25D998D90048EC1B /* ParseLDAP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70386A3725D998D90048EC1B /* ParseLDAP.swift */; };\n\t\t70386A3B25D998D90048EC1B /* ParseLDAP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70386A3725D998D90048EC1B /* ParseLDAP.swift */; };\n\t\t70386A4625D99C8B0048EC1B /* ParseLDAPTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70386A4525D99C8B0048EC1B /* ParseLDAPTests.swift */; };\n\t\t70386A4725D99C8B0048EC1B /* ParseLDAPTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70386A4525D99C8B0048EC1B /* ParseLDAPTests.swift */; };\n\t\t70386A4825D99C8B0048EC1B /* ParseLDAPTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70386A4525D99C8B0048EC1B /* ParseLDAPTests.swift */; };\n\t\t70386A5C25D9A4020048EC1B /* ParseLDAPCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70386A5B25D9A4010048EC1B /* ParseLDAPCombineTests.swift */; };\n\t\t70386A5D25D9A4020048EC1B /* ParseLDAPCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70386A5B25D9A4010048EC1B /* ParseLDAPCombineTests.swift */; };\n\t\t70386A5E25D9A4020048EC1B /* ParseLDAPCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70386A5B25D9A4010048EC1B /* ParseLDAPCombineTests.swift */; };\n\t\t703B08FD26BD953B005A112F /* ParseHealth+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B08FC26BD953B005A112F /* ParseHealth+async.swift */; };\n\t\t703B08FE26BD953B005A112F /* ParseHealth+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B08FC26BD953B005A112F /* ParseHealth+async.swift */; };\n\t\t703B08FF26BD953B005A112F /* ParseHealth+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B08FC26BD953B005A112F /* ParseHealth+async.swift */; };\n\t\t703B090026BD953B005A112F /* ParseHealth+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B08FC26BD953B005A112F /* ParseHealth+async.swift */; };\n\t\t703B090226BD9652005A112F /* ParseAnalytics+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B090126BD9652005A112F /* ParseAnalytics+async.swift */; };\n\t\t703B090326BD9652005A112F /* ParseAnalytics+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B090126BD9652005A112F /* ParseAnalytics+async.swift */; };\n\t\t703B090426BD9652005A112F /* ParseAnalytics+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B090126BD9652005A112F /* ParseAnalytics+async.swift */; };\n\t\t703B090526BD9652005A112F /* ParseAnalytics+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B090126BD9652005A112F /* ParseAnalytics+async.swift */; };\n\t\t703B090726BD9764005A112F /* ParseCloudable+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B090626BD9764005A112F /* ParseCloudable+async.swift */; };\n\t\t703B090826BD9764005A112F /* ParseCloudable+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B090626BD9764005A112F /* ParseCloudable+async.swift */; };\n\t\t703B090926BD9764005A112F /* ParseCloudable+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B090626BD9764005A112F /* ParseCloudable+async.swift */; };\n\t\t703B090A26BD9764005A112F /* ParseCloudable+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B090626BD9764005A112F /* ParseCloudable+async.swift */; };\n\t\t703B090C26BD984D005A112F /* ParseConfig+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B090B26BD984D005A112F /* ParseConfig+async.swift */; };\n\t\t703B090D26BD984D005A112F /* ParseConfig+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B090B26BD984D005A112F /* ParseConfig+async.swift */; };\n\t\t703B090E26BD984D005A112F /* ParseConfig+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B090B26BD984D005A112F /* ParseConfig+async.swift */; };\n\t\t703B090F26BD984D005A112F /* ParseConfig+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B090B26BD984D005A112F /* ParseConfig+async.swift */; };\n\t\t703B091126BD992E005A112F /* ParseOperation+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B091026BD992E005A112F /* ParseOperation+async.swift */; };\n\t\t703B091226BD992E005A112F /* ParseOperation+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B091026BD992E005A112F /* ParseOperation+async.swift */; };\n\t\t703B091326BD992E005A112F /* ParseOperation+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B091026BD992E005A112F /* ParseOperation+async.swift */; };\n\t\t703B091426BD992E005A112F /* ParseOperation+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B091026BD992E005A112F /* ParseOperation+async.swift */; };\n\t\t703B091626BD99BC005A112F /* ParseLiveQuery+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B091526BD99BC005A112F /* ParseLiveQuery+async.swift */; };\n\t\t703B091726BD99BC005A112F /* ParseLiveQuery+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B091526BD99BC005A112F /* ParseLiveQuery+async.swift */; };\n\t\t703B091826BD99BC005A112F /* ParseLiveQuery+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B091526BD99BC005A112F /* ParseLiveQuery+async.swift */; };\n\t\t703B091926BD99BC005A112F /* ParseLiveQuery+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B091526BD99BC005A112F /* ParseLiveQuery+async.swift */; };\n\t\t703B091F26BDE78D005A112F /* ParseObjectAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B091A26BDE774005A112F /* ParseObjectAsyncTests.swift */; };\n\t\t703B092026BDE78F005A112F /* ParseObjectAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B091A26BDE774005A112F /* ParseObjectAsyncTests.swift */; };\n\t\t703B092126BDE790005A112F /* ParseObjectAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B091A26BDE774005A112F /* ParseObjectAsyncTests.swift */; };\n\t\t703B092326BDFAB2005A112F /* ParseUserAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B092226BDFAB2005A112F /* ParseUserAsyncTests.swift */; };\n\t\t703B092426BDFAB2005A112F /* ParseUserAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B092226BDFAB2005A112F /* ParseUserAsyncTests.swift */; };\n\t\t703B092526BDFAB2005A112F /* ParseUserAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B092226BDFAB2005A112F /* ParseUserAsyncTests.swift */; };\n\t\t703B092726BE0719005A112F /* ParseInstallationAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B092626BE0719005A112F /* ParseInstallationAsyncTests.swift */; };\n\t\t703B092826BE0719005A112F /* ParseInstallationAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B092626BE0719005A112F /* ParseInstallationAsyncTests.swift */; };\n\t\t703B092926BE0719005A112F /* ParseInstallationAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B092626BE0719005A112F /* ParseInstallationAsyncTests.swift */; };\n\t\t703B092B26BF290B005A112F /* ParseAuthentication+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B092A26BF290B005A112F /* ParseAuthentication+async.swift */; };\n\t\t703B092C26BF290B005A112F /* ParseAuthentication+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B092A26BF290B005A112F /* ParseAuthentication+async.swift */; };\n\t\t703B092D26BF290B005A112F /* ParseAuthentication+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B092A26BF290B005A112F /* ParseAuthentication+async.swift */; };\n\t\t703B092E26BF290B005A112F /* ParseAuthentication+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B092A26BF290B005A112F /* ParseAuthentication+async.swift */; };\n\t\t703B093026BF42C2005A112F /* ParseAnonymous+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B092F26BF42C2005A112F /* ParseAnonymous+combine.swift */; };\n\t\t703B093126BF42C2005A112F /* ParseAnonymous+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B092F26BF42C2005A112F /* ParseAnonymous+combine.swift */; };\n\t\t703B093226BF42C2005A112F /* ParseAnonymous+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B092F26BF42C2005A112F /* ParseAnonymous+combine.swift */; };\n\t\t703B093326BF42C2005A112F /* ParseAnonymous+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B092F26BF42C2005A112F /* ParseAnonymous+combine.swift */; };\n\t\t703B093526BF43D9005A112F /* ParseAnonymous+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B093426BF43D9005A112F /* ParseAnonymous+async.swift */; };\n\t\t703B093626BF43D9005A112F /* ParseAnonymous+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B093426BF43D9005A112F /* ParseAnonymous+async.swift */; };\n\t\t703B093726BF43D9005A112F /* ParseAnonymous+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B093426BF43D9005A112F /* ParseAnonymous+async.swift */; };\n\t\t703B093826BF43D9005A112F /* ParseAnonymous+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B093426BF43D9005A112F /* ParseAnonymous+async.swift */; };\n\t\t703B093A26BF4799005A112F /* ParseApple+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B093926BF4799005A112F /* ParseApple+combine.swift */; };\n\t\t703B093B26BF4799005A112F /* ParseApple+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B093926BF4799005A112F /* ParseApple+combine.swift */; };\n\t\t703B093C26BF4799005A112F /* ParseApple+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B093926BF4799005A112F /* ParseApple+combine.swift */; };\n\t\t703B093D26BF4799005A112F /* ParseApple+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B093926BF4799005A112F /* ParseApple+combine.swift */; };\n\t\t703B093F26BF47AC005A112F /* ParseApple+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B093E26BF47AC005A112F /* ParseApple+async.swift */; };\n\t\t703B094026BF47AC005A112F /* ParseApple+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B093E26BF47AC005A112F /* ParseApple+async.swift */; };\n\t\t703B094126BF47AC005A112F /* ParseApple+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B093E26BF47AC005A112F /* ParseApple+async.swift */; };\n\t\t703B094226BF47AC005A112F /* ParseApple+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B093E26BF47AC005A112F /* ParseApple+async.swift */; };\n\t\t703B094426BF47C0005A112F /* ParseLDAP+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B094326BF47C0005A112F /* ParseLDAP+combine.swift */; };\n\t\t703B094526BF47C0005A112F /* ParseLDAP+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B094326BF47C0005A112F /* ParseLDAP+combine.swift */; };\n\t\t703B094626BF47C0005A112F /* ParseLDAP+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B094326BF47C0005A112F /* ParseLDAP+combine.swift */; };\n\t\t703B094726BF47C0005A112F /* ParseLDAP+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B094326BF47C0005A112F /* ParseLDAP+combine.swift */; };\n\t\t703B094926BF47D0005A112F /* ParseLDAP+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B094826BF47D0005A112F /* ParseLDAP+async.swift */; };\n\t\t703B094A26BF47D0005A112F /* ParseLDAP+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B094826BF47D0005A112F /* ParseLDAP+async.swift */; };\n\t\t703B094B26BF47D0005A112F /* ParseLDAP+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B094826BF47D0005A112F /* ParseLDAP+async.swift */; };\n\t\t703B094C26BF47D0005A112F /* ParseLDAP+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B094826BF47D0005A112F /* ParseLDAP+async.swift */; };\n\t\t703B094E26BF47E3005A112F /* ParseTwitter+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B094D26BF47E3005A112F /* ParseTwitter+combine.swift */; };\n\t\t703B094F26BF47E3005A112F /* ParseTwitter+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B094D26BF47E3005A112F /* ParseTwitter+combine.swift */; };\n\t\t703B095026BF47E3005A112F /* ParseTwitter+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B094D26BF47E3005A112F /* ParseTwitter+combine.swift */; };\n\t\t703B095126BF47E3005A112F /* ParseTwitter+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B094D26BF47E3005A112F /* ParseTwitter+combine.swift */; };\n\t\t703B095326BF47FD005A112F /* ParseTwitter+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B095226BF47FD005A112F /* ParseTwitter+async.swift */; };\n\t\t703B095426BF47FD005A112F /* ParseTwitter+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B095226BF47FD005A112F /* ParseTwitter+async.swift */; };\n\t\t703B095526BF47FD005A112F /* ParseTwitter+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B095226BF47FD005A112F /* ParseTwitter+async.swift */; };\n\t\t703B095626BF47FD005A112F /* ParseTwitter+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B095226BF47FD005A112F /* ParseTwitter+async.swift */; };\n\t\t703B095826BF480D005A112F /* ParseFacebook+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B095726BF480D005A112F /* ParseFacebook+combine.swift */; };\n\t\t703B095926BF480D005A112F /* ParseFacebook+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B095726BF480D005A112F /* ParseFacebook+combine.swift */; };\n\t\t703B095A26BF480D005A112F /* ParseFacebook+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B095726BF480D005A112F /* ParseFacebook+combine.swift */; };\n\t\t703B095B26BF480D005A112F /* ParseFacebook+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B095726BF480D005A112F /* ParseFacebook+combine.swift */; };\n\t\t703B095D26BF481F005A112F /* ParseFacebook+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B095C26BF481F005A112F /* ParseFacebook+async.swift */; };\n\t\t703B095E26BF481F005A112F /* ParseFacebook+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B095C26BF481F005A112F /* ParseFacebook+async.swift */; };\n\t\t703B095F26BF481F005A112F /* ParseFacebook+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B095C26BF481F005A112F /* ParseFacebook+async.swift */; };\n\t\t703B096026BF481F005A112F /* ParseFacebook+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 703B095C26BF481F005A112F /* ParseFacebook+async.swift */; };\n\t\t7044C17525C4ECFF0011F6E7 /* ParseCloudable+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C17425C4ECFF0011F6E7 /* ParseCloudable+combine.swift */; };\n\t\t7044C17625C4ECFF0011F6E7 /* ParseCloudable+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C17425C4ECFF0011F6E7 /* ParseCloudable+combine.swift */; };\n\t\t7044C17725C4ECFF0011F6E7 /* ParseCloudable+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C17425C4ECFF0011F6E7 /* ParseCloudable+combine.swift */; };\n\t\t7044C17825C4ECFF0011F6E7 /* ParseCloudable+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C17425C4ECFF0011F6E7 /* ParseCloudable+combine.swift */; };\n\t\t7044C18325C4EFC10011F6E7 /* ParseConfig+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C18225C4EFC10011F6E7 /* ParseConfig+combine.swift */; };\n\t\t7044C18425C4EFC10011F6E7 /* ParseConfig+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C18225C4EFC10011F6E7 /* ParseConfig+combine.swift */; };\n\t\t7044C18525C4EFC10011F6E7 /* ParseConfig+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C18225C4EFC10011F6E7 /* ParseConfig+combine.swift */; };\n\t\t7044C18625C4EFC10011F6E7 /* ParseConfig+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C18225C4EFC10011F6E7 /* ParseConfig+combine.swift */; };\n\t\t7044C19125C4F5B60011F6E7 /* ParseFile+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C19025C4F5B60011F6E7 /* ParseFile+combine.swift */; };\n\t\t7044C19225C4F5B60011F6E7 /* ParseFile+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C19025C4F5B60011F6E7 /* ParseFile+combine.swift */; };\n\t\t7044C19325C4F5B60011F6E7 /* ParseFile+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C19025C4F5B60011F6E7 /* ParseFile+combine.swift */; };\n\t\t7044C19425C4F5B60011F6E7 /* ParseFile+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C19025C4F5B60011F6E7 /* ParseFile+combine.swift */; };\n\t\t7044C19F25C4FA870011F6E7 /* ParseOperation+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C19E25C4FA870011F6E7 /* ParseOperation+combine.swift */; };\n\t\t7044C1A025C4FA870011F6E7 /* ParseOperation+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C19E25C4FA870011F6E7 /* ParseOperation+combine.swift */; };\n\t\t7044C1A125C4FA870011F6E7 /* ParseOperation+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C19E25C4FA870011F6E7 /* ParseOperation+combine.swift */; };\n\t\t7044C1A225C4FA870011F6E7 /* ParseOperation+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C19E25C4FA870011F6E7 /* ParseOperation+combine.swift */; };\n\t\t7044C1AD25C4FC080011F6E7 /* Query+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C1AC25C4FC080011F6E7 /* Query+combine.swift */; };\n\t\t7044C1AE25C4FC080011F6E7 /* Query+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C1AC25C4FC080011F6E7 /* Query+combine.swift */; };\n\t\t7044C1AF25C4FC080011F6E7 /* Query+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C1AC25C4FC080011F6E7 /* Query+combine.swift */; };\n\t\t7044C1B025C4FC080011F6E7 /* Query+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C1AC25C4FC080011F6E7 /* Query+combine.swift */; };\n\t\t7044C1BB25C52E410011F6E7 /* ParseInstallationCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C1BA25C52E410011F6E7 /* ParseInstallationCombineTests.swift */; };\n\t\t7044C1BC25C52E410011F6E7 /* ParseInstallationCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C1BA25C52E410011F6E7 /* ParseInstallationCombineTests.swift */; };\n\t\t7044C1BD25C52E410011F6E7 /* ParseInstallationCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C1BA25C52E410011F6E7 /* ParseInstallationCombineTests.swift */; };\n\t\t7044C1C825C5B2B10011F6E7 /* ParseAuthentication+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C1C725C5B2B10011F6E7 /* ParseAuthentication+combine.swift */; };\n\t\t7044C1C925C5B2B10011F6E7 /* ParseAuthentication+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C1C725C5B2B10011F6E7 /* ParseAuthentication+combine.swift */; };\n\t\t7044C1CA25C5B2B10011F6E7 /* ParseAuthentication+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C1C725C5B2B10011F6E7 /* ParseAuthentication+combine.swift */; };\n\t\t7044C1CB25C5B2B10011F6E7 /* ParseAuthentication+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C1C725C5B2B10011F6E7 /* ParseAuthentication+combine.swift */; };\n\t\t7044C1DF25C5C70D0011F6E7 /* ParseObjectCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C1DE25C5C70D0011F6E7 /* ParseObjectCombineTests.swift */; };\n\t\t7044C1E025C5C70D0011F6E7 /* ParseObjectCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C1DE25C5C70D0011F6E7 /* ParseObjectCombineTests.swift */; };\n\t\t7044C1E125C5C70D0011F6E7 /* ParseObjectCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C1DE25C5C70D0011F6E7 /* ParseObjectCombineTests.swift */; };\n\t\t7044C1EC25C5CC930011F6E7 /* ParseOperationCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C1EB25C5CC930011F6E7 /* ParseOperationCombineTests.swift */; };\n\t\t7044C1ED25C5CC930011F6E7 /* ParseOperationCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C1EB25C5CC930011F6E7 /* ParseOperationCombineTests.swift */; };\n\t\t7044C1EE25C5CC930011F6E7 /* ParseOperationCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C1EB25C5CC930011F6E7 /* ParseOperationCombineTests.swift */; };\n\t\t7044C1F925C5CFAB0011F6E7 /* ParseFileCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C1F825C5CFAB0011F6E7 /* ParseFileCombineTests.swift */; };\n\t\t7044C1FA25C5CFAB0011F6E7 /* ParseFileCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C1F825C5CFAB0011F6E7 /* ParseFileCombineTests.swift */; };\n\t\t7044C1FB25C5CFAB0011F6E7 /* ParseFileCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C1F825C5CFAB0011F6E7 /* ParseFileCombineTests.swift */; };\n\t\t7044C20625C5D6780011F6E7 /* ParseQueryCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C20525C5D6780011F6E7 /* ParseQueryCombineTests.swift */; };\n\t\t7044C20725C5D6780011F6E7 /* ParseQueryCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C20525C5D6780011F6E7 /* ParseQueryCombineTests.swift */; };\n\t\t7044C20825C5D6780011F6E7 /* ParseQueryCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C20525C5D6780011F6E7 /* ParseQueryCombineTests.swift */; };\n\t\t7044C21325C5DE490011F6E7 /* ParseCloudableCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C21225C5DE490011F6E7 /* ParseCloudableCombineTests.swift */; };\n\t\t7044C21425C5DE490011F6E7 /* ParseCloudableCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C21225C5DE490011F6E7 /* ParseCloudableCombineTests.swift */; };\n\t\t7044C21525C5DE490011F6E7 /* ParseCloudableCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C21225C5DE490011F6E7 /* ParseCloudableCombineTests.swift */; };\n\t\t7044C22025C5E0160011F6E7 /* ParseConfigCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C21F25C5E0160011F6E7 /* ParseConfigCombineTests.swift */; };\n\t\t7044C22125C5E0160011F6E7 /* ParseConfigCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C21F25C5E0160011F6E7 /* ParseConfigCombineTests.swift */; };\n\t\t7044C22225C5E0160011F6E7 /* ParseConfigCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C21F25C5E0160011F6E7 /* ParseConfigCombineTests.swift */; };\n\t\t7044C22D25C5E4E90011F6E7 /* ParseAnonymousCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C22C25C5E4E90011F6E7 /* ParseAnonymousCombineTests.swift */; };\n\t\t7044C22E25C5E4E90011F6E7 /* ParseAnonymousCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C22C25C5E4E90011F6E7 /* ParseAnonymousCombineTests.swift */; };\n\t\t7044C22F25C5E4E90011F6E7 /* ParseAnonymousCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C22C25C5E4E90011F6E7 /* ParseAnonymousCombineTests.swift */; };\n\t\t7044C24325C5EA360011F6E7 /* ParseAppleCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C24225C5EA360011F6E7 /* ParseAppleCombineTests.swift */; };\n\t\t7044C24425C5EA360011F6E7 /* ParseAppleCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C24225C5EA360011F6E7 /* ParseAppleCombineTests.swift */; };\n\t\t7044C24525C5EA360011F6E7 /* ParseAppleCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7044C24225C5EA360011F6E7 /* ParseAppleCombineTests.swift */; };\n\t\t7045769326BD8F8100F86F71 /* ParseInstallation+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7045769226BD8F8100F86F71 /* ParseInstallation+async.swift */; };\n\t\t7045769426BD8F8100F86F71 /* ParseInstallation+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7045769226BD8F8100F86F71 /* ParseInstallation+async.swift */; };\n\t\t7045769526BD8F8100F86F71 /* ParseInstallation+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7045769226BD8F8100F86F71 /* ParseInstallation+async.swift */; };\n\t\t7045769626BD8F8100F86F71 /* ParseInstallation+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7045769226BD8F8100F86F71 /* ParseInstallation+async.swift */; };\n\t\t7045769826BD917500F86F71 /* Query+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7045769726BD917500F86F71 /* Query+async.swift */; };\n\t\t7045769926BD917500F86F71 /* Query+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7045769726BD917500F86F71 /* Query+async.swift */; };\n\t\t7045769A26BD917500F86F71 /* Query+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7045769726BD917500F86F71 /* Query+async.swift */; };\n\t\t7045769B26BD917500F86F71 /* Query+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7045769726BD917500F86F71 /* Query+async.swift */; };\n\t\t7045769D26BD934000F86F71 /* ParseFile+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7045769C26BD934000F86F71 /* ParseFile+async.swift */; };\n\t\t7045769E26BD934000F86F71 /* ParseFile+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7045769C26BD934000F86F71 /* ParseFile+async.swift */; };\n\t\t7045769F26BD934000F86F71 /* ParseFile+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7045769C26BD934000F86F71 /* ParseFile+async.swift */; };\n\t\t704576A026BD934000F86F71 /* ParseFile+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7045769C26BD934000F86F71 /* ParseFile+async.swift */; };\n\t\t704C886C28BE69A8008E6B01 /* ParseConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704C886B28BE69A8008E6B01 /* ParseConfiguration.swift */; };\n\t\t704C886D28BE69A8008E6B01 /* ParseConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704C886B28BE69A8008E6B01 /* ParseConfiguration.swift */; };\n\t\t704C886E28BE69A8008E6B01 /* ParseConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704C886B28BE69A8008E6B01 /* ParseConfiguration.swift */; };\n\t\t704C886F28BE69A8008E6B01 /* ParseConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704C886B28BE69A8008E6B01 /* ParseConfiguration.swift */; };\n\t\t704E781728CFD8A00075F952 /* ParseFileTransferable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704E781628CFD8A00075F952 /* ParseFileTransferable.swift */; };\n\t\t704E781828CFD8A00075F952 /* ParseFileTransferable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704E781628CFD8A00075F952 /* ParseFileTransferable.swift */; };\n\t\t704E781928CFD8A00075F952 /* ParseFileTransferable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704E781628CFD8A00075F952 /* ParseFileTransferable.swift */; };\n\t\t704E781A28CFD8A00075F952 /* ParseFileTransferable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704E781628CFD8A00075F952 /* ParseFileTransferable.swift */; };\n\t\t704E781C28CFFAF80075F952 /* ParseFileDefaultTransfer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704E781B28CFFAF80075F952 /* ParseFileDefaultTransfer.swift */; };\n\t\t704E781D28CFFAF80075F952 /* ParseFileDefaultTransfer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704E781B28CFFAF80075F952 /* ParseFileDefaultTransfer.swift */; };\n\t\t704E781E28CFFAF80075F952 /* ParseFileDefaultTransfer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704E781B28CFFAF80075F952 /* ParseFileDefaultTransfer.swift */; };\n\t\t704E781F28CFFAF80075F952 /* ParseFileDefaultTransfer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704E781B28CFFAF80075F952 /* ParseFileDefaultTransfer.swift */; };\n\t\t704E782128D0D73E0075F952 /* ParseFileTransferableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704E782028D0D73E0075F952 /* ParseFileTransferableTests.swift */; };\n\t\t704E782228D0D73E0075F952 /* ParseFileTransferableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704E782028D0D73E0075F952 /* ParseFileTransferableTests.swift */; };\n\t\t704E782328D0D73E0075F952 /* ParseFileTransferableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 704E782028D0D73E0075F952 /* ParseFileTransferableTests.swift */; };\n\t\t705025992842FD3B008D6624 /* ParseCLPTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025982842FD3B008D6624 /* ParseCLPTests.swift */; };\n\t\t7050259A2842FD3B008D6624 /* ParseCLPTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025982842FD3B008D6624 /* ParseCLPTests.swift */; };\n\t\t7050259B2842FD3B008D6624 /* ParseCLPTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025982842FD3B008D6624 /* ParseCLPTests.swift */; };\n\t\t7050259D2843F0CF008D6624 /* ParseSchemaAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7050259C2843F0CF008D6624 /* ParseSchemaAsyncTests.swift */; };\n\t\t7050259E2843F0CF008D6624 /* ParseSchemaAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7050259C2843F0CF008D6624 /* ParseSchemaAsyncTests.swift */; };\n\t\t7050259F2843F0CF008D6624 /* ParseSchemaAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7050259C2843F0CF008D6624 /* ParseSchemaAsyncTests.swift */; };\n\t\t705025A12843F0E7008D6624 /* ParseSchemaCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025A02843F0E7008D6624 /* ParseSchemaCombineTests.swift */; };\n\t\t705025A22843F0E7008D6624 /* ParseSchemaCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025A02843F0E7008D6624 /* ParseSchemaCombineTests.swift */; };\n\t\t705025A32843F0E7008D6624 /* ParseSchemaCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025A02843F0E7008D6624 /* ParseSchemaCombineTests.swift */; };\n\t\t705025A5284407C4008D6624 /* ParseSchemaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025A4284407C4008D6624 /* ParseSchemaTests.swift */; };\n\t\t705025A6284407C4008D6624 /* ParseSchemaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025A4284407C4008D6624 /* ParseSchemaTests.swift */; };\n\t\t705025A7284407C4008D6624 /* ParseSchemaTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025A4284407C4008D6624 /* ParseSchemaTests.swift */; };\n\t\t705025A928441C96008D6624 /* ParseFieldOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025A828441C96008D6624 /* ParseFieldOptions.swift */; };\n\t\t705025AA28441C96008D6624 /* ParseFieldOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025A828441C96008D6624 /* ParseFieldOptions.swift */; };\n\t\t705025AB28441C96008D6624 /* ParseFieldOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025A828441C96008D6624 /* ParseFieldOptions.swift */; };\n\t\t705025AC28441C96008D6624 /* ParseFieldOptions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025A828441C96008D6624 /* ParseFieldOptions.swift */; };\n\t\t705025AE28456106008D6624 /* ParsePushStatusable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025AD28456106008D6624 /* ParsePushStatusable.swift */; };\n\t\t705025AF28456106008D6624 /* ParsePushStatusable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025AD28456106008D6624 /* ParsePushStatusable.swift */; };\n\t\t705025B028456106008D6624 /* ParsePushStatusable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025AD28456106008D6624 /* ParsePushStatusable.swift */; };\n\t\t705025B128456106008D6624 /* ParsePushStatusable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025AD28456106008D6624 /* ParsePushStatusable.swift */; };\n\t\t705025B32845C302008D6624 /* ParsePushStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025B22845C302008D6624 /* ParsePushStatus.swift */; };\n\t\t705025B42845C302008D6624 /* ParsePushStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025B22845C302008D6624 /* ParsePushStatus.swift */; };\n\t\t705025B52845C302008D6624 /* ParsePushStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025B22845C302008D6624 /* ParsePushStatus.swift */; };\n\t\t705025B62845C302008D6624 /* ParsePushStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025B22845C302008D6624 /* ParsePushStatus.swift */; };\n\t\t705025BD284C610C008D6624 /* ParsePush.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025BC284C610C008D6624 /* ParsePush.swift */; };\n\t\t705025BE284C610C008D6624 /* ParsePush.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025BC284C610C008D6624 /* ParsePush.swift */; };\n\t\t705025BF284C610C008D6624 /* ParsePush.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025BC284C610C008D6624 /* ParsePush.swift */; };\n\t\t705025C0284C610C008D6624 /* ParsePush.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025BC284C610C008D6624 /* ParsePush.swift */; };\n\t\t705025C2284C7842008D6624 /* ParsePush+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025C1284C7841008D6624 /* ParsePush+async.swift */; };\n\t\t705025C3284C7842008D6624 /* ParsePush+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025C1284C7841008D6624 /* ParsePush+async.swift */; };\n\t\t705025C4284C7842008D6624 /* ParsePush+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025C1284C7841008D6624 /* ParsePush+async.swift */; };\n\t\t705025C5284C7842008D6624 /* ParsePush+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025C1284C7841008D6624 /* ParsePush+async.swift */; };\n\t\t705025C7284C7883008D6624 /* ParsePush+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025C6284C7883008D6624 /* ParsePush+combine.swift */; };\n\t\t705025C8284C7883008D6624 /* ParsePush+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025C6284C7883008D6624 /* ParsePush+combine.swift */; };\n\t\t705025C9284C7883008D6624 /* ParsePush+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025C6284C7883008D6624 /* ParsePush+combine.swift */; };\n\t\t705025CA284C7883008D6624 /* ParsePush+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025C6284C7883008D6624 /* ParsePush+combine.swift */; };\n\t\t705025CC284CE4C2008D6624 /* ParsePushPayloadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025CB284CE4C2008D6624 /* ParsePushPayloadable.swift */; };\n\t\t705025CD284CE4C2008D6624 /* ParsePushPayloadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025CB284CE4C2008D6624 /* ParsePushPayloadable.swift */; };\n\t\t705025CE284CE4C2008D6624 /* ParsePushPayloadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025CB284CE4C2008D6624 /* ParsePushPayloadable.swift */; };\n\t\t705025CF284CE4C2008D6624 /* ParsePushPayloadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025CB284CE4C2008D6624 /* ParsePushPayloadable.swift */; };\n\t\t705025D1284CFCDE008D6624 /* ParsePushAppleAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025D0284CFCDE008D6624 /* ParsePushAppleAlert.swift */; };\n\t\t705025D2284CFCDE008D6624 /* ParsePushAppleAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025D0284CFCDE008D6624 /* ParsePushAppleAlert.swift */; };\n\t\t705025D3284CFCDE008D6624 /* ParsePushAppleAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025D0284CFCDE008D6624 /* ParsePushAppleAlert.swift */; };\n\t\t705025D4284CFCDE008D6624 /* ParsePushAppleAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025D0284CFCDE008D6624 /* ParsePushAppleAlert.swift */; };\n\t\t705025D6284D0C1D008D6624 /* ParsePushPayloadApple.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025D5284D0C1D008D6624 /* ParsePushPayloadApple.swift */; };\n\t\t705025D7284D0C1D008D6624 /* ParsePushPayloadApple.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025D5284D0C1D008D6624 /* ParsePushPayloadApple.swift */; };\n\t\t705025D8284D0C1D008D6624 /* ParsePushPayloadApple.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025D5284D0C1D008D6624 /* ParsePushPayloadApple.swift */; };\n\t\t705025D9284D0C1D008D6624 /* ParsePushPayloadApple.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025D5284D0C1D008D6624 /* ParsePushPayloadApple.swift */; };\n\t\t705025DB284D0D56008D6624 /* ParsePushAppleSound.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025DA284D0D56008D6624 /* ParsePushAppleSound.swift */; };\n\t\t705025DC284D0D56008D6624 /* ParsePushAppleSound.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025DA284D0D56008D6624 /* ParsePushAppleSound.swift */; };\n\t\t705025DD284D0D56008D6624 /* ParsePushAppleSound.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025DA284D0D56008D6624 /* ParsePushAppleSound.swift */; };\n\t\t705025DE284D0D56008D6624 /* ParsePushAppleSound.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025DA284D0D56008D6624 /* ParsePushAppleSound.swift */; };\n\t\t705025E02851006F008D6624 /* ParsePushPayloadFirebase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025DF2851006F008D6624 /* ParsePushPayloadFirebase.swift */; };\n\t\t705025E12851006F008D6624 /* ParsePushPayloadFirebase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025DF2851006F008D6624 /* ParsePushPayloadFirebase.swift */; };\n\t\t705025E22851006F008D6624 /* ParsePushPayloadFirebase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025DF2851006F008D6624 /* ParsePushPayloadFirebase.swift */; };\n\t\t705025E32851006F008D6624 /* ParsePushPayloadFirebase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025DF2851006F008D6624 /* ParsePushPayloadFirebase.swift */; };\n\t\t705025E628514F36008D6624 /* ParsePushPayloadAny.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025E528514F36008D6624 /* ParsePushPayloadAny.swift */; };\n\t\t705025E728514F36008D6624 /* ParsePushPayloadAny.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025E528514F36008D6624 /* ParsePushPayloadAny.swift */; };\n\t\t705025E828514F36008D6624 /* ParsePushPayloadAny.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025E528514F36008D6624 /* ParsePushPayloadAny.swift */; };\n\t\t705025E928514F36008D6624 /* ParsePushPayloadAny.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025E528514F36008D6624 /* ParsePushPayloadAny.swift */; };\n\t\t705025EB285153BC008D6624 /* ParsePushApplePayloadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025EA285153BC008D6624 /* ParsePushApplePayloadable.swift */; };\n\t\t705025EC285153BC008D6624 /* ParsePushApplePayloadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025EA285153BC008D6624 /* ParsePushApplePayloadable.swift */; };\n\t\t705025ED285153BC008D6624 /* ParsePushApplePayloadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025EA285153BC008D6624 /* ParsePushApplePayloadable.swift */; };\n\t\t705025EE285153BC008D6624 /* ParsePushApplePayloadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025EA285153BC008D6624 /* ParsePushApplePayloadable.swift */; };\n\t\t705025F02851542D008D6624 /* ParsePushFirebasePayloadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025EF2851542D008D6624 /* ParsePushFirebasePayloadable.swift */; };\n\t\t705025F12851542D008D6624 /* ParsePushFirebasePayloadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025EF2851542D008D6624 /* ParsePushFirebasePayloadable.swift */; };\n\t\t705025F22851542D008D6624 /* ParsePushFirebasePayloadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025EF2851542D008D6624 /* ParsePushFirebasePayloadable.swift */; };\n\t\t705025F32851542D008D6624 /* ParsePushFirebasePayloadable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705025EF2851542D008D6624 /* ParsePushFirebasePayloadable.swift */; };\n\t\t70510AAC259EE25E00FEA700 /* LiveQuerySocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70510AAB259EE25E00FEA700 /* LiveQuerySocket.swift */; };\n\t\t70510AAD259EE25E00FEA700 /* LiveQuerySocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70510AAB259EE25E00FEA700 /* LiveQuerySocket.swift */; };\n\t\t70510AAE259EE25E00FEA700 /* LiveQuerySocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70510AAB259EE25E00FEA700 /* LiveQuerySocket.swift */; };\n\t\t70510AAF259EE25E00FEA700 /* LiveQuerySocket.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70510AAB259EE25E00FEA700 /* LiveQuerySocket.swift */; };\n\t\t70572671259033A700F0ADD5 /* ParseFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70572670259033A700F0ADD5 /* ParseFileManager.swift */; };\n\t\t70572672259033A700F0ADD5 /* ParseFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70572670259033A700F0ADD5 /* ParseFileManager.swift */; };\n\t\t70572673259033A700F0ADD5 /* ParseFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70572670259033A700F0ADD5 /* ParseFileManager.swift */; };\n\t\t70572674259033A700F0ADD5 /* ParseFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70572670259033A700F0ADD5 /* ParseFileManager.swift */; };\n\t\t705727B12593FF8800F0ADD5 /* ParseFileTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705727882593FF8000F0ADD5 /* ParseFileTests.swift */; };\n\t\t705727BB2593FF8B00F0ADD5 /* ParseFileTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705727882593FF8000F0ADD5 /* ParseFileTests.swift */; };\n\t\t705727BC2593FF8C00F0ADD5 /* ParseFileTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705727882593FF8000F0ADD5 /* ParseFileTests.swift */; };\n\t\t705A99F9259807F900B3547F /* ParseFileManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705A99F8259807F900B3547F /* ParseFileManagerTests.swift */; };\n\t\t705A99FA259807F900B3547F /* ParseFileManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705A99F8259807F900B3547F /* ParseFileManagerTests.swift */; };\n\t\t705A99FB259807F900B3547F /* ParseFileManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705A99F8259807F900B3547F /* ParseFileManagerTests.swift */; };\n\t\t705A9A2F25991C1400B3547F /* Fileable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705A9A2E25991C1400B3547F /* Fileable.swift */; };\n\t\t705A9A3025991C1400B3547F /* Fileable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705A9A2E25991C1400B3547F /* Fileable.swift */; };\n\t\t705A9A3125991C1400B3547F /* Fileable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705A9A2E25991C1400B3547F /* Fileable.swift */; };\n\t\t705A9A3225991C1400B3547F /* Fileable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705A9A2E25991C1400B3547F /* Fileable.swift */; };\n\t\t705D950825BE4C08003EF6F8 /* SubscriptionCallback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705D950725BE4C08003EF6F8 /* SubscriptionCallback.swift */; };\n\t\t705D950925BE4C08003EF6F8 /* SubscriptionCallback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705D950725BE4C08003EF6F8 /* SubscriptionCallback.swift */; };\n\t\t705D950A25BE4C08003EF6F8 /* SubscriptionCallback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705D950725BE4C08003EF6F8 /* SubscriptionCallback.swift */; };\n\t\t705D950B25BE4C08003EF6F8 /* SubscriptionCallback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 705D950725BE4C08003EF6F8 /* SubscriptionCallback.swift */; };\n\t\t7064369B273313D5007C6461 /* LiveQueryConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7064369A273313D5007C6461 /* LiveQueryConstants.swift */; };\n\t\t7064369C273313D5007C6461 /* LiveQueryConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7064369A273313D5007C6461 /* LiveQueryConstants.swift */; };\n\t\t7064369D273313D5007C6461 /* LiveQueryConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7064369A273313D5007C6461 /* LiveQueryConstants.swift */; };\n\t\t7064369E273313D5007C6461 /* LiveQueryConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7064369A273313D5007C6461 /* LiveQueryConstants.swift */; };\n\t\t706436A427341F6E007C6461 /* Encodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 706436A327341F6E007C6461 /* Encodable.swift */; };\n\t\t706436A527341F6E007C6461 /* Encodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 706436A327341F6E007C6461 /* Encodable.swift */; };\n\t\t706436A627341F6E007C6461 /* Encodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 706436A327341F6E007C6461 /* Encodable.swift */; };\n\t\t706436A727341F6E007C6461 /* Encodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 706436A327341F6E007C6461 /* Encodable.swift */; };\n\t\t706436A927341FD0007C6461 /* Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = 706436A827341FD0007C6461 /* Date.swift */; };\n\t\t706436AA27341FD0007C6461 /* Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = 706436A827341FD0007C6461 /* Date.swift */; };\n\t\t706436AB27341FD0007C6461 /* Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = 706436A827341FD0007C6461 /* Date.swift */; };\n\t\t706436AC27341FD0007C6461 /* Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = 706436A827341FD0007C6461 /* Date.swift */; };\n\t\t70647E9C259E3A9A004C1004 /* ParseEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70647E9B259E3A9A004C1004 /* ParseEncodable.swift */; };\n\t\t70647E9D259E3A9A004C1004 /* ParseEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70647E9B259E3A9A004C1004 /* ParseEncodable.swift */; };\n\t\t70647E9E259E3A9A004C1004 /* ParseEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70647E9B259E3A9A004C1004 /* ParseEncodable.swift */; };\n\t\t70647E9F259E3A9A004C1004 /* ParseEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70647E9B259E3A9A004C1004 /* ParseEncodable.swift */; };\n\t\t70732C5A2606CCAD000CAB81 /* ParseObjectCustomObjectIdTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70732C592606CCAD000CAB81 /* ParseObjectCustomObjectIdTests.swift */; };\n\t\t70732C5B2606CCAD000CAB81 /* ParseObjectCustomObjectIdTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70732C592606CCAD000CAB81 /* ParseObjectCustomObjectIdTests.swift */; };\n\t\t70732C5C2606CCAD000CAB81 /* ParseObjectCustomObjectIdTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70732C592606CCAD000CAB81 /* ParseObjectCustomObjectIdTests.swift */; };\n\t\t707A3BF125B0A4F0000D215C /* ParseAuthentication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 707A3BF025B0A4F0000D215C /* ParseAuthentication.swift */; };\n\t\t707A3BF225B0A4F0000D215C /* ParseAuthentication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 707A3BF025B0A4F0000D215C /* ParseAuthentication.swift */; };\n\t\t707A3BF325B0A4F0000D215C /* ParseAuthentication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 707A3BF025B0A4F0000D215C /* ParseAuthentication.swift */; };\n\t\t707A3BF425B0A4F0000D215C /* ParseAuthentication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 707A3BF025B0A4F0000D215C /* ParseAuthentication.swift */; };\n\t\t707A3C1125B0A8E8000D215C /* ParseAnonymous.swift in Sources */ = {isa = PBXBuildFile; fileRef = 707A3C1025B0A8E8000D215C /* ParseAnonymous.swift */; };\n\t\t707A3C1225B0A8E8000D215C /* ParseAnonymous.swift in Sources */ = {isa = PBXBuildFile; fileRef = 707A3C1025B0A8E8000D215C /* ParseAnonymous.swift */; };\n\t\t707A3C1325B0A8E8000D215C /* ParseAnonymous.swift in Sources */ = {isa = PBXBuildFile; fileRef = 707A3C1025B0A8E8000D215C /* ParseAnonymous.swift */; };\n\t\t707A3C1425B0A8E8000D215C /* ParseAnonymous.swift in Sources */ = {isa = PBXBuildFile; fileRef = 707A3C1025B0A8E8000D215C /* ParseAnonymous.swift */; };\n\t\t707A3C2025B14BD0000D215C /* ParseApple.swift in Sources */ = {isa = PBXBuildFile; fileRef = 707A3C1F25B14BCF000D215C /* ParseApple.swift */; };\n\t\t707A3C2125B14BD0000D215C /* ParseApple.swift in Sources */ = {isa = PBXBuildFile; fileRef = 707A3C1F25B14BCF000D215C /* ParseApple.swift */; };\n\t\t707A3C2225B14BD0000D215C /* ParseApple.swift in Sources */ = {isa = PBXBuildFile; fileRef = 707A3C1F25B14BCF000D215C /* ParseApple.swift */; };\n\t\t707A3C2325B14BD0000D215C /* ParseApple.swift in Sources */ = {isa = PBXBuildFile; fileRef = 707A3C1F25B14BCF000D215C /* ParseApple.swift */; };\n\t\t7085DD9426CBF3A70033B977 /* Documentation.docc in Sources */ = {isa = PBXBuildFile; fileRef = 7085DD9326CBF3A70033B977 /* Documentation.docc */; };\n\t\t7085DD9526CBF3A70033B977 /* Documentation.docc in Sources */ = {isa = PBXBuildFile; fileRef = 7085DD9326CBF3A70033B977 /* Documentation.docc */; };\n\t\t7085DD9626CBF3A70033B977 /* Documentation.docc in Sources */ = {isa = PBXBuildFile; fileRef = 7085DD9326CBF3A70033B977 /* Documentation.docc */; };\n\t\t7085DD9726CBF3A70033B977 /* Documentation.docc in Sources */ = {isa = PBXBuildFile; fileRef = 7085DD9326CBF3A70033B977 /* Documentation.docc */; };\n\t\t7085DDA326CC8A470033B977 /* ParseHealth+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7085DDA226CC8A470033B977 /* ParseHealth+combine.swift */; };\n\t\t7085DDA426CC8A470033B977 /* ParseHealth+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7085DDA226CC8A470033B977 /* ParseHealth+combine.swift */; };\n\t\t7085DDA526CC8A470033B977 /* ParseHealth+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7085DDA226CC8A470033B977 /* ParseHealth+combine.swift */; };\n\t\t7085DDA626CC8A470033B977 /* ParseHealth+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7085DDA226CC8A470033B977 /* ParseHealth+combine.swift */; };\n\t\t7085DDB326D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7085DDB226D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift */; };\n\t\t7085DDB426D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7085DDB226D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift */; };\n\t\t7085DDB526D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7085DDB226D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift */; };\n\t\t708CADCF2872263D0066C279 /* ParseKeychainAccessGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708CADCE2872263D0066C279 /* ParseKeychainAccessGroupTests.swift */; };\n\t\t708CADD02872263D0066C279 /* ParseKeychainAccessGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708CADCE2872263D0066C279 /* ParseKeychainAccessGroupTests.swift */; };\n\t\t708CADD12872263D0066C279 /* ParseKeychainAccessGroupTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708CADCE2872263D0066C279 /* ParseKeychainAccessGroupTests.swift */; };\n\t\t708D035225215F9B00646C70 /* Deletable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708D035125215F9B00646C70 /* Deletable.swift */; };\n\t\t708D035325215F9B00646C70 /* Deletable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708D035125215F9B00646C70 /* Deletable.swift */; };\n\t\t708D035425215F9B00646C70 /* Deletable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708D035125215F9B00646C70 /* Deletable.swift */; };\n\t\t708D035525215F9B00646C70 /* Deletable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708D035125215F9B00646C70 /* Deletable.swift */; };\n\t\t708EF0BD28D5F4140052EF35 /* API+Command+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708EF0BC28D5F4140052EF35 /* API+Command+async.swift */; };\n\t\t708EF0BE28D5F4140052EF35 /* API+Command+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708EF0BC28D5F4140052EF35 /* API+Command+async.swift */; };\n\t\t708EF0BF28D5F4140052EF35 /* API+Command+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708EF0BC28D5F4140052EF35 /* API+Command+async.swift */; };\n\t\t708EF0C028D5F4140052EF35 /* API+Command+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708EF0BC28D5F4140052EF35 /* API+Command+async.swift */; };\n\t\t708EF0C228D5FDF10052EF35 /* API+NonParseBodyCommand+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708EF0C128D5FDF10052EF35 /* API+NonParseBodyCommand+async.swift */; };\n\t\t708EF0C328D5FDF10052EF35 /* API+NonParseBodyCommand+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708EF0C128D5FDF10052EF35 /* API+NonParseBodyCommand+async.swift */; };\n\t\t708EF0C428D5FDF10052EF35 /* API+NonParseBodyCommand+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708EF0C128D5FDF10052EF35 /* API+NonParseBodyCommand+async.swift */; };\n\t\t708EF0C528D5FDF10052EF35 /* API+NonParseBodyCommand+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 708EF0C128D5FDF10052EF35 /* API+NonParseBodyCommand+async.swift */; };\n\t\t709A147D283949D100BF85E5 /* ParseSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A147C283949D100BF85E5 /* ParseSchema.swift */; };\n\t\t709A147E283949D100BF85E5 /* ParseSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A147C283949D100BF85E5 /* ParseSchema.swift */; };\n\t\t709A147F283949D100BF85E5 /* ParseSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A147C283949D100BF85E5 /* ParseSchema.swift */; };\n\t\t709A1480283949D100BF85E5 /* ParseSchema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A147C283949D100BF85E5 /* ParseSchema.swift */; };\n\t\t709A148228395ED100BF85E5 /* ParseSchema+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A148128395ED100BF85E5 /* ParseSchema+async.swift */; };\n\t\t709A148328395ED100BF85E5 /* ParseSchema+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A148128395ED100BF85E5 /* ParseSchema+async.swift */; };\n\t\t709A148428395ED100BF85E5 /* ParseSchema+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A148128395ED100BF85E5 /* ParseSchema+async.swift */; };\n\t\t709A148528395ED100BF85E5 /* ParseSchema+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A148128395ED100BF85E5 /* ParseSchema+async.swift */; };\n\t\t709A148728396B1D00BF85E5 /* ParseField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A148628396B1C00BF85E5 /* ParseField.swift */; };\n\t\t709A148828396B1D00BF85E5 /* ParseField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A148628396B1C00BF85E5 /* ParseField.swift */; };\n\t\t709A148928396B1D00BF85E5 /* ParseField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A148628396B1C00BF85E5 /* ParseField.swift */; };\n\t\t709A148A28396B1D00BF85E5 /* ParseField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A148628396B1C00BF85E5 /* ParseField.swift */; };\n\t\t709A148C2839A1DB00BF85E5 /* Operation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A148B2839A1DB00BF85E5 /* Operation.swift */; };\n\t\t709A148D2839A1DB00BF85E5 /* Operation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A148B2839A1DB00BF85E5 /* Operation.swift */; };\n\t\t709A148E2839A1DB00BF85E5 /* Operation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A148B2839A1DB00BF85E5 /* Operation.swift */; };\n\t\t709A148F2839A1DB00BF85E5 /* Operation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A148B2839A1DB00BF85E5 /* Operation.swift */; };\n\t\t709A14A02839CABD00BF85E5 /* ParseCLP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A149F2839CABD00BF85E5 /* ParseCLP.swift */; };\n\t\t709A14A12839CABD00BF85E5 /* ParseCLP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A149F2839CABD00BF85E5 /* ParseCLP.swift */; };\n\t\t709A14A22839CABD00BF85E5 /* ParseCLP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A149F2839CABD00BF85E5 /* ParseCLP.swift */; };\n\t\t709A14A32839CABD00BF85E5 /* ParseCLP.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A149F2839CABD00BF85E5 /* ParseCLP.swift */; };\n\t\t709A14A5283AAF4C00BF85E5 /* ParseSchema+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A14A4283AAF4C00BF85E5 /* ParseSchema+combine.swift */; };\n\t\t709A14A6283AAF4C00BF85E5 /* ParseSchema+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A14A4283AAF4C00BF85E5 /* ParseSchema+combine.swift */; };\n\t\t709A14A7283AAF4C00BF85E5 /* ParseSchema+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A14A4283AAF4C00BF85E5 /* ParseSchema+combine.swift */; };\n\t\t709A14A8283AAF4C00BF85E5 /* ParseSchema+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709A14A4283AAF4C00BF85E5 /* ParseSchema+combine.swift */; };\n\t\t709B40C1268F999000ED2EAC /* IOS13Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709B40C0268F999000ED2EAC /* IOS13Tests.swift */; };\n\t\t709B40C2268F999000ED2EAC /* IOS13Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709B40C0268F999000ED2EAC /* IOS13Tests.swift */; };\n\t\t709B40C3268F999000ED2EAC /* IOS13Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 709B40C0268F999000ED2EAC /* IOS13Tests.swift */; };\n\t\t709B98352556EC7400507778 /* ParseSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 912C9BD824D3011F009947C3 /* ParseSwift.framework */; };\n\t\t709B984B2556ECAA00507778 /* MockURLProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 911DB13224C494390027F3C7 /* MockURLProtocol.swift */; };\n\t\t709B984C2556ECAA00507778 /* APICommandTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 911DB12D24C4837E0027F3C7 /* APICommandTests.swift */; };\n\t\t709B984D2556ECAA00507778 /* AnyDecodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FFF552D2217E729007C3B4E /* AnyDecodableTests.swift */; };\n\t\t709B984E2556ECAA00507778 /* ParseGeoPointTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70BC0B32251903D1001556DB /* ParseGeoPointTests.swift */; };\n\t\t709B984F2556ECAA00507778 /* AnyCodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FFF552C2217E729007C3B4E /* AnyCodableTests.swift */; };\n\t\t709B98502556ECAA00507778 /* KeychainStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AA8076E1F794C1C008CD551 /* KeychainStoreTests.swift */; };\n\t\t709B98512556ECAA00507778 /* ParseEncoderExtraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F971F4F524DE381A006CB79B /* ParseEncoderExtraTests.swift */; };\n\t\t709B98522556ECAA00507778 /* ParseUserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C7DC1D24D20E530050419B /* ParseUserTests.swift */; };\n\t\t709B98532556ECAA00507778 /* ParsePointerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE1D882545BF730018D572 /* ParsePointerTests.swift */; };\n\t\t709B98542556ECAA00507778 /* ParseInstallationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70110D5B2506ED0E0091CC1D /* ParseInstallationTests.swift */; };\n\t\t709B98552556ECAA00507778 /* ParseQueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C7DC1F24D20F180050419B /* ParseQueryTests.swift */; };\n\t\t709B98562556ECAA00507778 /* ParseObjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 911DB13524C4FC100027F3C7 /* ParseObjectTests.swift */; };\n\t\t709B98572556ECAA00507778 /* ParseACLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9194657724F16E330070296B /* ParseACLTests.swift */; };\n\t\t709B98582556ECAA00507778 /* AnyEncodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FFF552B2217E729007C3B4E /* AnyEncodableTests.swift */; };\n\t\t709B98592556ECAA00507778 /* MockURLResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 911DB12B24C3F7720027F3C7 /* MockURLResponse.swift */; };\n\t\t709B985A2556ECAA00507778 /* ParseObjectBatchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C7DC2024D20F190050419B /* ParseObjectBatchTests.swift */; };\n\t\t70A2D81F25B36A7D001BEB7D /* ParseAuthenticationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70A2D81E25B36A7D001BEB7D /* ParseAuthenticationTests.swift */; };\n\t\t70A2D82025B36A7D001BEB7D /* ParseAuthenticationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70A2D81E25B36A7D001BEB7D /* ParseAuthenticationTests.swift */; };\n\t\t70A2D82125B36A7D001BEB7D /* ParseAuthenticationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70A2D81E25B36A7D001BEB7D /* ParseAuthenticationTests.swift */; };\n\t\t70A2D86B25B3ADB6001BEB7D /* ParseAnonymousTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70A2D86A25B3ADB6001BEB7D /* ParseAnonymousTests.swift */; };\n\t\t70A2D86C25B3ADB6001BEB7D /* ParseAnonymousTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70A2D86A25B3ADB6001BEB7D /* ParseAnonymousTests.swift */; };\n\t\t70A2D86D25B3ADB6001BEB7D /* ParseAnonymousTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70A2D86A25B3ADB6001BEB7D /* ParseAnonymousTests.swift */; };\n\t\t70A98D822794AB3C009B58F2 /* ParseQueryScorable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70A98D812794AB3C009B58F2 /* ParseQueryScorable.swift */; };\n\t\t70A98D832794AB3C009B58F2 /* ParseQueryScorable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70A98D812794AB3C009B58F2 /* ParseQueryScorable.swift */; };\n\t\t70A98D842794AB3C009B58F2 /* ParseQueryScorable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70A98D812794AB3C009B58F2 /* ParseQueryScorable.swift */; };\n\t\t70A98D852794AB3C009B58F2 /* ParseQueryScorable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70A98D812794AB3C009B58F2 /* ParseQueryScorable.swift */; };\n\t\t70B4E0BC2762F1D5004C9757 /* QueryConstraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B4E0BB2762F1D5004C9757 /* QueryConstraint.swift */; };\n\t\t70B4E0BD2762F1D5004C9757 /* QueryConstraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B4E0BB2762F1D5004C9757 /* QueryConstraint.swift */; };\n\t\t70B4E0BE2762F1D5004C9757 /* QueryConstraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B4E0BB2762F1D5004C9757 /* QueryConstraint.swift */; };\n\t\t70B4E0BF2762F1D5004C9757 /* QueryConstraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B4E0BB2762F1D5004C9757 /* QueryConstraint.swift */; };\n\t\t70B4E0C12762F313004C9757 /* QueryWhere.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B4E0C02762F313004C9757 /* QueryWhere.swift */; };\n\t\t70B4E0C22762F313004C9757 /* QueryWhere.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B4E0C02762F313004C9757 /* QueryWhere.swift */; };\n\t\t70B4E0C32762F313004C9757 /* QueryWhere.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B4E0C02762F313004C9757 /* QueryWhere.swift */; };\n\t\t70B4E0C42762F313004C9757 /* QueryWhere.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B4E0C02762F313004C9757 /* QueryWhere.swift */; };\n\t\t70BC0B33251903D1001556DB /* ParseGeoPointTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70BC0B32251903D1001556DB /* ParseGeoPointTests.swift */; };\n\t\t70BC9890252A5B5C00FF3074 /* Objectable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70BC988F252A5B5C00FF3074 /* Objectable.swift */; };\n\t\t70BC9891252A5B5C00FF3074 /* Objectable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70BC988F252A5B5C00FF3074 /* Objectable.swift */; };\n\t\t70BC9892252A5B5C00FF3074 /* Objectable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70BC988F252A5B5C00FF3074 /* Objectable.swift */; };\n\t\t70BC9893252A5B5C00FF3074 /* Objectable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70BC988F252A5B5C00FF3074 /* Objectable.swift */; };\n\t\t70BDA2B3250536FF00FC2237 /* ParseInstallation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70BDA2B2250536FF00FC2237 /* ParseInstallation.swift */; };\n\t\t70BDA2B4250536FF00FC2237 /* ParseInstallation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70BDA2B2250536FF00FC2237 /* ParseInstallation.swift */; };\n\t\t70BDA2B5250536FF00FC2237 /* ParseInstallation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70BDA2B2250536FF00FC2237 /* ParseInstallation.swift */; };\n\t\t70BDA2B6250536FF00FC2237 /* ParseInstallation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70BDA2B2250536FF00FC2237 /* ParseInstallation.swift */; };\n\t\t70C048C12880D7E600401689 /* Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C048C02880D7E500401689 /* Dictionary.swift */; };\n\t\t70C048C22880D7E600401689 /* Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C048C02880D7E500401689 /* Dictionary.swift */; };\n\t\t70C048C32880D7E600401689 /* Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C048C02880D7E500401689 /* Dictionary.swift */; };\n\t\t70C048C42880D7E600401689 /* Dictionary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C048C02880D7E500401689 /* Dictionary.swift */; };\n\t\t70C167AF27304EE4009F4E30 /* Pointer+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C167AE27304EE4009F4E30 /* Pointer+combine.swift */; };\n\t\t70C167B027304EE4009F4E30 /* Pointer+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C167AE27304EE4009F4E30 /* Pointer+combine.swift */; };\n\t\t70C167B127304EE4009F4E30 /* Pointer+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C167AE27304EE4009F4E30 /* Pointer+combine.swift */; };\n\t\t70C167B227304EE4009F4E30 /* Pointer+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C167AE27304EE4009F4E30 /* Pointer+combine.swift */; };\n\t\t70C167B427304F09009F4E30 /* Pointer+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C167B327304F09009F4E30 /* Pointer+async.swift */; };\n\t\t70C167B527304F09009F4E30 /* Pointer+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C167B327304F09009F4E30 /* Pointer+async.swift */; };\n\t\t70C167B627304F09009F4E30 /* Pointer+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C167B327304F09009F4E30 /* Pointer+async.swift */; };\n\t\t70C167B727304F09009F4E30 /* Pointer+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C167B327304F09009F4E30 /* Pointer+async.swift */; };\n\t\t70C167B927305101009F4E30 /* ParsePointerAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C167B827305101009F4E30 /* ParsePointerAsyncTests.swift */; };\n\t\t70C167BA27305101009F4E30 /* ParsePointerAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C167B827305101009F4E30 /* ParsePointerAsyncTests.swift */; };\n\t\t70C167BB27305101009F4E30 /* ParsePointerAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C167B827305101009F4E30 /* ParsePointerAsyncTests.swift */; };\n\t\t70C5502225B3D8F700B5DBC2 /* ParseAppleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5502125B3D8F700B5DBC2 /* ParseAppleTests.swift */; };\n\t\t70C5502325B3D8F700B5DBC2 /* ParseAppleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5502125B3D8F700B5DBC2 /* ParseAppleTests.swift */; };\n\t\t70C5502425B3D8F700B5DBC2 /* ParseAppleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5502125B3D8F700B5DBC2 /* ParseAppleTests.swift */; };\n\t\t70C5503825B406B800B5DBC2 /* ParseSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5503725B406B800B5DBC2 /* ParseSession.swift */; };\n\t\t70C5503925B406B800B5DBC2 /* ParseSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5503725B406B800B5DBC2 /* ParseSession.swift */; };\n\t\t70C5503A25B406B800B5DBC2 /* ParseSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5503725B406B800B5DBC2 /* ParseSession.swift */; };\n\t\t70C5503B25B406B800B5DBC2 /* ParseSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5503725B406B800B5DBC2 /* ParseSession.swift */; };\n\t\t70C5504625B40D5200B5DBC2 /* ParseSessionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5504525B40D5200B5DBC2 /* ParseSessionTests.swift */; };\n\t\t70C5504725B40D5200B5DBC2 /* ParseSessionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5504525B40D5200B5DBC2 /* ParseSessionTests.swift */; };\n\t\t70C5504825B40D5200B5DBC2 /* ParseSessionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5504525B40D5200B5DBC2 /* ParseSessionTests.swift */; };\n\t\t70C5507725B49D3A00B5DBC2 /* ParseRole.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5507625B49D3A00B5DBC2 /* ParseRole.swift */; };\n\t\t70C5507825B49D3A00B5DBC2 /* ParseRole.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5507625B49D3A00B5DBC2 /* ParseRole.swift */; };\n\t\t70C5507925B49D3A00B5DBC2 /* ParseRole.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5507625B49D3A00B5DBC2 /* ParseRole.swift */; };\n\t\t70C5507A25B49D3A00B5DBC2 /* ParseRole.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5507625B49D3A00B5DBC2 /* ParseRole.swift */; };\n\t\t70C5508525B4A68700B5DBC2 /* ParseOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5508425B4A68700B5DBC2 /* ParseOperationTests.swift */; };\n\t\t70C5508625B4A68700B5DBC2 /* ParseOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5508425B4A68700B5DBC2 /* ParseOperationTests.swift */; };\n\t\t70C5508725B4A68700B5DBC2 /* ParseOperationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5508425B4A68700B5DBC2 /* ParseOperationTests.swift */; };\n\t\t70C5509225B4A99100B5DBC2 /* AddRelation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5509125B4A99100B5DBC2 /* AddRelation.swift */; };\n\t\t70C5509325B4A99100B5DBC2 /* AddRelation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5509125B4A99100B5DBC2 /* AddRelation.swift */; };\n\t\t70C5509425B4A99100B5DBC2 /* AddRelation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5509125B4A99100B5DBC2 /* AddRelation.swift */; };\n\t\t70C5509525B4A99100B5DBC2 /* AddRelation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5509125B4A99100B5DBC2 /* AddRelation.swift */; };\n\t\t70C550A025B4A9F600B5DBC2 /* RemoveRelation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5509F25B4A9F600B5DBC2 /* RemoveRelation.swift */; };\n\t\t70C550A125B4A9F600B5DBC2 /* RemoveRelation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5509F25B4A9F600B5DBC2 /* RemoveRelation.swift */; };\n\t\t70C550A225B4A9F600B5DBC2 /* RemoveRelation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5509F25B4A9F600B5DBC2 /* RemoveRelation.swift */; };\n\t\t70C550A325B4A9F600B5DBC2 /* RemoveRelation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5509F25B4A9F600B5DBC2 /* RemoveRelation.swift */; };\n\t\t70C5655925AA147B00BDD57F /* ParseLiveQueryConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5655825AA147B00BDD57F /* ParseLiveQueryConstants.swift */; };\n\t\t70C5655A25AA147B00BDD57F /* ParseLiveQueryConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5655825AA147B00BDD57F /* ParseLiveQueryConstants.swift */; };\n\t\t70C5655B25AA147B00BDD57F /* ParseLiveQueryConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5655825AA147B00BDD57F /* ParseLiveQueryConstants.swift */; };\n\t\t70C5655C25AA147B00BDD57F /* ParseLiveQueryConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C5655825AA147B00BDD57F /* ParseLiveQueryConstants.swift */; };\n\t\t70C7DC1E24D20E530050419B /* ParseUserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C7DC1D24D20E530050419B /* ParseUserTests.swift */; };\n\t\t70C7DC2124D20F190050419B /* ParseQueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C7DC1F24D20F180050419B /* ParseQueryTests.swift */; };\n\t\t70C7DC2224D20F190050419B /* ParseObjectBatchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C7DC2024D20F190050419B /* ParseObjectBatchTests.swift */; };\n\t\t70CE0A9428590A0A00DAEA86 /* ParseHookResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0A9328590A0A00DAEA86 /* ParseHookResponse.swift */; };\n\t\t70CE0A9528590A0A00DAEA86 /* ParseHookResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0A9328590A0A00DAEA86 /* ParseHookResponse.swift */; };\n\t\t70CE0A9628590A0A00DAEA86 /* ParseHookResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0A9328590A0A00DAEA86 /* ParseHookResponse.swift */; };\n\t\t70CE0A9728590A0A00DAEA86 /* ParseHookResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0A9328590A0A00DAEA86 /* ParseHookResponse.swift */; };\n\t\t70CE0A9E28592A2B00DAEA86 /* ParseCloudUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0A9D28592A2B00DAEA86 /* ParseCloudUser.swift */; };\n\t\t70CE0A9F28592A2B00DAEA86 /* ParseCloudUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0A9D28592A2B00DAEA86 /* ParseCloudUser.swift */; };\n\t\t70CE0AA028592A2B00DAEA86 /* ParseCloudUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0A9D28592A2B00DAEA86 /* ParseCloudUser.swift */; };\n\t\t70CE0AA128592A2B00DAEA86 /* ParseCloudUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0A9D28592A2B00DAEA86 /* ParseCloudUser.swift */; };\n\t\t70CE0AA328595E5E00DAEA86 /* ParseHookRequestable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AA228595E5E00DAEA86 /* ParseHookRequestable.swift */; };\n\t\t70CE0AA428595E5E00DAEA86 /* ParseHookRequestable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AA228595E5E00DAEA86 /* ParseHookRequestable.swift */; };\n\t\t70CE0AA528595E5E00DAEA86 /* ParseHookRequestable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AA228595E5E00DAEA86 /* ParseHookRequestable.swift */; };\n\t\t70CE0AA628595E5E00DAEA86 /* ParseHookRequestable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AA228595E5E00DAEA86 /* ParseHookRequestable.swift */; };\n\t\t70CE0AA828595FCE00DAEA86 /* ParseHookRequestable+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AA728595FCE00DAEA86 /* ParseHookRequestable+async.swift */; };\n\t\t70CE0AA928595FCE00DAEA86 /* ParseHookRequestable+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AA728595FCE00DAEA86 /* ParseHookRequestable+async.swift */; };\n\t\t70CE0AAA28595FCE00DAEA86 /* ParseHookRequestable+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AA728595FCE00DAEA86 /* ParseHookRequestable+async.swift */; };\n\t\t70CE0AAB28595FCE00DAEA86 /* ParseHookRequestable+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AA728595FCE00DAEA86 /* ParseHookRequestable+async.swift */; };\n\t\t70CE0AAD28595FDE00DAEA86 /* ParseHookRequestable+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AAC28595FDE00DAEA86 /* ParseHookRequestable+combine.swift */; };\n\t\t70CE0AAE28595FDE00DAEA86 /* ParseHookRequestable+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AAC28595FDE00DAEA86 /* ParseHookRequestable+combine.swift */; };\n\t\t70CE0AAF28595FDE00DAEA86 /* ParseHookRequestable+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AAC28595FDE00DAEA86 /* ParseHookRequestable+combine.swift */; };\n\t\t70CE0AB028595FDE00DAEA86 /* ParseHookRequestable+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AAC28595FDE00DAEA86 /* ParseHookRequestable+combine.swift */; };\n\t\t70CE0AB2285963A300DAEA86 /* ParseHookTriggerRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AB1285963A300DAEA86 /* ParseHookTriggerRequest.swift */; };\n\t\t70CE0AB3285963A300DAEA86 /* ParseHookTriggerRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AB1285963A300DAEA86 /* ParseHookTriggerRequest.swift */; };\n\t\t70CE0AB4285963A300DAEA86 /* ParseHookTriggerRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AB1285963A300DAEA86 /* ParseHookTriggerRequest.swift */; };\n\t\t70CE0AB5285963A300DAEA86 /* ParseHookTriggerRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AB1285963A300DAEA86 /* ParseHookTriggerRequest.swift */; };\n\t\t70CE0AB7285A83B100DAEA86 /* ParseHookable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AB6285A83B100DAEA86 /* ParseHookable.swift */; };\n\t\t70CE0AB8285A83B100DAEA86 /* ParseHookable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AB6285A83B100DAEA86 /* ParseHookable.swift */; };\n\t\t70CE0AB9285A83B100DAEA86 /* ParseHookable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AB6285A83B100DAEA86 /* ParseHookable.swift */; };\n\t\t70CE0ABA285A83B100DAEA86 /* ParseHookable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AB6285A83B100DAEA86 /* ParseHookable.swift */; };\n\t\t70CE0ABC285F8FF900DAEA86 /* ParseTypeable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0ABB285F8FF900DAEA86 /* ParseTypeable.swift */; };\n\t\t70CE0ABD285F8FF900DAEA86 /* ParseTypeable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0ABB285F8FF900DAEA86 /* ParseTypeable.swift */; };\n\t\t70CE0ABE285F8FF900DAEA86 /* ParseTypeable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0ABB285F8FF900DAEA86 /* ParseTypeable.swift */; };\n\t\t70CE0ABF285F8FF900DAEA86 /* ParseTypeable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0ABB285F8FF900DAEA86 /* ParseTypeable.swift */; };\n\t\t70CE0AC1285FD59B00DAEA86 /* ParseHookFunctionable+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AC0285FD59B00DAEA86 /* ParseHookFunctionable+async.swift */; };\n\t\t70CE0AC2285FD59B00DAEA86 /* ParseHookFunctionable+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AC0285FD59B00DAEA86 /* ParseHookFunctionable+async.swift */; };\n\t\t70CE0AC3285FD59B00DAEA86 /* ParseHookFunctionable+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AC0285FD59B00DAEA86 /* ParseHookFunctionable+async.swift */; };\n\t\t70CE0AC4285FD59B00DAEA86 /* ParseHookFunctionable+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AC0285FD59B00DAEA86 /* ParseHookFunctionable+async.swift */; };\n\t\t70CE0AC6285FD5A800DAEA86 /* ParseHookFunctionable+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AC5285FD5A800DAEA86 /* ParseHookFunctionable+combine.swift */; };\n\t\t70CE0AC7285FD5A800DAEA86 /* ParseHookFunctionable+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AC5285FD5A800DAEA86 /* ParseHookFunctionable+combine.swift */; };\n\t\t70CE0AC8285FD5A800DAEA86 /* ParseHookFunctionable+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AC5285FD5A800DAEA86 /* ParseHookFunctionable+combine.swift */; };\n\t\t70CE0AC9285FD5A800DAEA86 /* ParseHookFunctionable+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AC5285FD5A800DAEA86 /* ParseHookFunctionable+combine.swift */; };\n\t\t70CE0ACB285FD5CB00DAEA86 /* ParseHookTriggerable+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0ACA285FD5CB00DAEA86 /* ParseHookTriggerable+async.swift */; };\n\t\t70CE0ACC285FD5CB00DAEA86 /* ParseHookTriggerable+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0ACA285FD5CB00DAEA86 /* ParseHookTriggerable+async.swift */; };\n\t\t70CE0ACD285FD5CB00DAEA86 /* ParseHookTriggerable+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0ACA285FD5CB00DAEA86 /* ParseHookTriggerable+async.swift */; };\n\t\t70CE0ACE285FD5CB00DAEA86 /* ParseHookTriggerable+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0ACA285FD5CB00DAEA86 /* ParseHookTriggerable+async.swift */; };\n\t\t70CE0AD0285FD5D700DAEA86 /* ParseHookTriggerable+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0ACF285FD5D700DAEA86 /* ParseHookTriggerable+combine.swift */; };\n\t\t70CE0AD1285FD5D700DAEA86 /* ParseHookTriggerable+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0ACF285FD5D700DAEA86 /* ParseHookTriggerable+combine.swift */; };\n\t\t70CE0AD2285FD5D700DAEA86 /* ParseHookTriggerable+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0ACF285FD5D700DAEA86 /* ParseHookTriggerable+combine.swift */; };\n\t\t70CE0AD3285FD5D700DAEA86 /* ParseHookTriggerable+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0ACF285FD5D700DAEA86 /* ParseHookTriggerable+combine.swift */; };\n\t\t70CE1D892545BF730018D572 /* ParsePointerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE1D882545BF730018D572 /* ParsePointerTests.swift */; };\n\t\t70D1BD8725B8C37200A42E7C /* ParseRelationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D1BD8625B8C37200A42E7C /* ParseRelationTests.swift */; };\n\t\t70D1BD8825B8C37200A42E7C /* ParseRelationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D1BD8625B8C37200A42E7C /* ParseRelationTests.swift */; };\n\t\t70D1BD8925B8C37200A42E7C /* ParseRelationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D1BD8625B8C37200A42E7C /* ParseRelationTests.swift */; };\n\t\t70D1BDBA25BB17A600A42E7C /* ParseConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D1BDB925BB17A600A42E7C /* ParseConfig.swift */; };\n\t\t70D1BDBB25BB17A600A42E7C /* ParseConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D1BDB925BB17A600A42E7C /* ParseConfig.swift */; };\n\t\t70D1BDBC25BB17A600A42E7C /* ParseConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D1BDB925BB17A600A42E7C /* ParseConfig.swift */; };\n\t\t70D1BDBD25BB17A600A42E7C /* ParseConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D1BDB925BB17A600A42E7C /* ParseConfig.swift */; };\n\t\t70D1BE4B25BB312700A42E7C /* ParseConfigTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D1BE0625BB2BF400A42E7C /* ParseConfigTests.swift */; };\n\t\t70D1BE5525BB312900A42E7C /* ParseConfigTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D1BE0625BB2BF400A42E7C /* ParseConfigTests.swift */; };\n\t\t70D1BE5F25BB312A00A42E7C /* ParseConfigTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D1BE0625BB2BF400A42E7C /* ParseConfigTests.swift */; };\n\t\t70D1BE7325BB43EB00A42E7C /* BaseConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D1BE7225BB43EB00A42E7C /* BaseConfig.swift */; };\n\t\t70D1BE7425BB43EB00A42E7C /* BaseConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D1BE7225BB43EB00A42E7C /* BaseConfig.swift */; };\n\t\t70D1BE7525BB43EB00A42E7C /* BaseConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D1BE7225BB43EB00A42E7C /* BaseConfig.swift */; };\n\t\t70D1BE7625BB43EB00A42E7C /* BaseConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D1BE7225BB43EB00A42E7C /* BaseConfig.swift */; };\n\t\t70D41D6728B0235100613510 /* MigrateObjCSDKTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D41D6628B0235100613510 /* MigrateObjCSDKTests.swift */; };\n\t\t70D41D6828B0235100613510 /* MigrateObjCSDKTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D41D6628B0235100613510 /* MigrateObjCSDKTests.swift */; };\n\t\t70D41D6928B0235100613510 /* MigrateObjCSDKTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D41D6628B0235100613510 /* MigrateObjCSDKTests.swift */; };\n\t\t70D41D6B28B294C100613510 /* MigrateObjCSDKCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D41D6A28B294C100613510 /* MigrateObjCSDKCombineTests.swift */; };\n\t\t70D41D6C28B294C100613510 /* MigrateObjCSDKCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D41D6A28B294C100613510 /* MigrateObjCSDKCombineTests.swift */; };\n\t\t70D41D6D28B294C100613510 /* MigrateObjCSDKCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D41D6A28B294C100613510 /* MigrateObjCSDKCombineTests.swift */; };\n\t\t70D41D8028B520E200613510 /* ParseKeychainAccessGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D41D7F28B520E200613510 /* ParseKeychainAccessGroup.swift */; };\n\t\t70D41D8128B520E200613510 /* ParseKeychainAccessGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D41D7F28B520E200613510 /* ParseKeychainAccessGroup.swift */; };\n\t\t70D41D8228B520E200613510 /* ParseKeychainAccessGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D41D7F28B520E200613510 /* ParseKeychainAccessGroup.swift */; };\n\t\t70D41D8328B520E200613510 /* ParseKeychainAccessGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70D41D7F28B520E200613510 /* ParseKeychainAccessGroup.swift */; };\n\t\t70DFEA8A2618E77800F8EB4B /* InitializeSDKTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70DFEA892618E77800F8EB4B /* InitializeSDKTests.swift */; };\n\t\t70DFEA8B2618E77800F8EB4B /* InitializeSDKTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70DFEA892618E77800F8EB4B /* InitializeSDKTests.swift */; };\n\t\t70DFEA8C2618E77800F8EB4B /* InitializeSDKTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70DFEA892618E77800F8EB4B /* InitializeSDKTests.swift */; };\n\t\t70E09E1C262F0634002DD451 /* ParsePointerCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E09E1B262F0634002DD451 /* ParsePointerCombineTests.swift */; };\n\t\t70E09E1D262F0634002DD451 /* ParsePointerCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E09E1B262F0634002DD451 /* ParsePointerCombineTests.swift */; };\n\t\t70E09E1E262F0634002DD451 /* ParsePointerCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E09E1B262F0634002DD451 /* ParsePointerCombineTests.swift */; };\n\t\t70E6B016286120E00043EC4A /* ParseHookFunctionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B015286120E00043EC4A /* ParseHookFunctionTests.swift */; };\n\t\t70E6B017286120E00043EC4A /* ParseHookFunctionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B015286120E00043EC4A /* ParseHookFunctionTests.swift */; };\n\t\t70E6B018286120E00043EC4A /* ParseHookFunctionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B015286120E00043EC4A /* ParseHookFunctionTests.swift */; };\n\t\t70E6B01A28612A820043EC4A /* ParseHookFunctionCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B01928612A820043EC4A /* ParseHookFunctionCombineTests.swift */; };\n\t\t70E6B01B28612A820043EC4A /* ParseHookFunctionCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B01928612A820043EC4A /* ParseHookFunctionCombineTests.swift */; };\n\t\t70E6B01C28612A820043EC4A /* ParseHookFunctionCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B01928612A820043EC4A /* ParseHookFunctionCombineTests.swift */; };\n\t\t70E6B01E28612FF00043EC4A /* ParseHookTriggerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B01D28612FF00043EC4A /* ParseHookTriggerTests.swift */; };\n\t\t70E6B01F28612FF00043EC4A /* ParseHookTriggerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B01D28612FF00043EC4A /* ParseHookTriggerTests.swift */; };\n\t\t70E6B02028612FF00043EC4A /* ParseHookTriggerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B01D28612FF00043EC4A /* ParseHookTriggerTests.swift */; };\n\t\t70E6B022286131720043EC4A /* ParseHookTriggerCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B021286131720043EC4A /* ParseHookTriggerCombineTests.swift */; };\n\t\t70E6B023286131720043EC4A /* ParseHookTriggerCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B021286131720043EC4A /* ParseHookTriggerCombineTests.swift */; };\n\t\t70E6B024286131720043EC4A /* ParseHookTriggerCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B021286131720043EC4A /* ParseHookTriggerCombineTests.swift */; };\n\t\t70E6B026286132BC0043EC4A /* ParseHookFunctionRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B025286132BC0043EC4A /* ParseHookFunctionRequestTests.swift */; };\n\t\t70E6B027286132BC0043EC4A /* ParseHookFunctionRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B025286132BC0043EC4A /* ParseHookFunctionRequestTests.swift */; };\n\t\t70E6B028286132BC0043EC4A /* ParseHookFunctionRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B025286132BC0043EC4A /* ParseHookFunctionRequestTests.swift */; };\n\t\t70E6B02A28614C5F0043EC4A /* ParseHookFunctionRequestCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B02928614C5F0043EC4A /* ParseHookFunctionRequestCombineTests.swift */; };\n\t\t70E6B02B28614C5F0043EC4A /* ParseHookFunctionRequestCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B02928614C5F0043EC4A /* ParseHookFunctionRequestCombineTests.swift */; };\n\t\t70E6B02C28614C5F0043EC4A /* ParseHookFunctionRequestCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B02928614C5F0043EC4A /* ParseHookFunctionRequestCombineTests.swift */; };\n\t\t70E6B02E28614E480043EC4A /* ParseHookTriggerRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B02D28614E480043EC4A /* ParseHookTriggerRequestTests.swift */; };\n\t\t70E6B02F28614E480043EC4A /* ParseHookTriggerRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B02D28614E480043EC4A /* ParseHookTriggerRequestTests.swift */; };\n\t\t70E6B03028614E480043EC4A /* ParseHookTriggerRequestTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B02D28614E480043EC4A /* ParseHookTriggerRequestTests.swift */; };\n\t\t70E6B032286152550043EC4A /* ParseHookTriggerRequestCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B031286152550043EC4A /* ParseHookTriggerRequestCombineTests.swift */; };\n\t\t70E6B033286152550043EC4A /* ParseHookTriggerRequestCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B031286152550043EC4A /* ParseHookTriggerRequestCombineTests.swift */; };\n\t\t70E6B034286152550043EC4A /* ParseHookTriggerRequestCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B031286152550043EC4A /* ParseHookTriggerRequestCombineTests.swift */; };\n\t\t70E6B036286289FF0043EC4A /* ParseHookResponseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B035286289FF0043EC4A /* ParseHookResponseTests.swift */; };\n\t\t70E6B037286289FF0043EC4A /* ParseHookResponseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B035286289FF0043EC4A /* ParseHookResponseTests.swift */; };\n\t\t70E6B038286289FF0043EC4A /* ParseHookResponseTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70E6B035286289FF0043EC4A /* ParseHookResponseTests.swift */; };\n\t\t70F03A232780BDE200E5AFB4 /* ParseGoogle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A222780BDE200E5AFB4 /* ParseGoogle.swift */; };\n\t\t70F03A252780BDF700E5AFB4 /* ParseGoogle+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A242780BDF700E5AFB4 /* ParseGoogle+async.swift */; };\n\t\t70F03A272780BE0F00E5AFB4 /* ParseGoogle+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A262780BE0F00E5AFB4 /* ParseGoogle+combine.swift */; };\n\t\t70F03A282780BE2900E5AFB4 /* ParseGoogle+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A242780BDF700E5AFB4 /* ParseGoogle+async.swift */; };\n\t\t70F03A292780BE2900E5AFB4 /* ParseGoogle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A222780BDE200E5AFB4 /* ParseGoogle.swift */; };\n\t\t70F03A2A2780BE2900E5AFB4 /* ParseGoogle+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A262780BE0F00E5AFB4 /* ParseGoogle+combine.swift */; };\n\t\t70F03A2B2780BE2B00E5AFB4 /* ParseGoogle+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A242780BDF700E5AFB4 /* ParseGoogle+async.swift */; };\n\t\t70F03A2C2780BE2B00E5AFB4 /* ParseGoogle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A222780BDE200E5AFB4 /* ParseGoogle.swift */; };\n\t\t70F03A2D2780BE2B00E5AFB4 /* ParseGoogle+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A262780BE0F00E5AFB4 /* ParseGoogle+combine.swift */; };\n\t\t70F03A2E2780BE2C00E5AFB4 /* ParseGoogle+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A242780BDF700E5AFB4 /* ParseGoogle+async.swift */; };\n\t\t70F03A2F2780BE2C00E5AFB4 /* ParseGoogle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A222780BDE200E5AFB4 /* ParseGoogle.swift */; };\n\t\t70F03A302780BE2C00E5AFB4 /* ParseGoogle+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A262780BE0F00E5AFB4 /* ParseGoogle+combine.swift */; };\n\t\t70F03A342780CA4300E5AFB4 /* ParseGitHub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A332780CA4300E5AFB4 /* ParseGitHub.swift */; };\n\t\t70F03A352780CA4D00E5AFB4 /* ParseGitHub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A332780CA4300E5AFB4 /* ParseGitHub.swift */; };\n\t\t70F03A362780CA4D00E5AFB4 /* ParseGitHub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A332780CA4300E5AFB4 /* ParseGitHub.swift */; };\n\t\t70F03A372780CA4E00E5AFB4 /* ParseGitHub.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A332780CA4300E5AFB4 /* ParseGitHub.swift */; };\n\t\t70F03A392780CA6F00E5AFB4 /* ParseGitHub+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A382780CA6F00E5AFB4 /* ParseGitHub+async.swift */; };\n\t\t70F03A3A2780CA6F00E5AFB4 /* ParseGitHub+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A382780CA6F00E5AFB4 /* ParseGitHub+async.swift */; };\n\t\t70F03A3B2780CA6F00E5AFB4 /* ParseGitHub+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A382780CA6F00E5AFB4 /* ParseGitHub+async.swift */; };\n\t\t70F03A3C2780CA6F00E5AFB4 /* ParseGitHub+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A382780CA6F00E5AFB4 /* ParseGitHub+async.swift */; };\n\t\t70F03A3E2780CA8F00E5AFB4 /* ParseGitHub+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A3D2780CA8F00E5AFB4 /* ParseGitHub+combine.swift */; };\n\t\t70F03A3F2780CA8F00E5AFB4 /* ParseGitHub+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A3D2780CA8F00E5AFB4 /* ParseGitHub+combine.swift */; };\n\t\t70F03A402780CA8F00E5AFB4 /* ParseGitHub+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A3D2780CA8F00E5AFB4 /* ParseGitHub+combine.swift */; };\n\t\t70F03A412780CA8F00E5AFB4 /* ParseGitHub+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A3D2780CA8F00E5AFB4 /* ParseGitHub+combine.swift */; };\n\t\t70F03A432780D21600E5AFB4 /* ParseLinkedIn.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A422780D21600E5AFB4 /* ParseLinkedIn.swift */; };\n\t\t70F03A442780D21600E5AFB4 /* ParseLinkedIn.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A422780D21600E5AFB4 /* ParseLinkedIn.swift */; };\n\t\t70F03A452780D21600E5AFB4 /* ParseLinkedIn.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A422780D21600E5AFB4 /* ParseLinkedIn.swift */; };\n\t\t70F03A462780D21600E5AFB4 /* ParseLinkedIn.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A422780D21600E5AFB4 /* ParseLinkedIn.swift */; };\n\t\t70F03A482780D27700E5AFB4 /* ParseLinkedIn+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A472780D27700E5AFB4 /* ParseLinkedIn+async.swift */; };\n\t\t70F03A492780D27700E5AFB4 /* ParseLinkedIn+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A472780D27700E5AFB4 /* ParseLinkedIn+async.swift */; };\n\t\t70F03A4A2780D27700E5AFB4 /* ParseLinkedIn+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A472780D27700E5AFB4 /* ParseLinkedIn+async.swift */; };\n\t\t70F03A4B2780D27700E5AFB4 /* ParseLinkedIn+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A472780D27700E5AFB4 /* ParseLinkedIn+async.swift */; };\n\t\t70F03A4D2780D28A00E5AFB4 /* ParseLinkedIn+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A4C2780D28A00E5AFB4 /* ParseLinkedIn+combine.swift */; };\n\t\t70F03A4E2780D28A00E5AFB4 /* ParseLinkedIn+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A4C2780D28A00E5AFB4 /* ParseLinkedIn+combine.swift */; };\n\t\t70F03A4F2780D28A00E5AFB4 /* ParseLinkedIn+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A4C2780D28A00E5AFB4 /* ParseLinkedIn+combine.swift */; };\n\t\t70F03A502780D28A00E5AFB4 /* ParseLinkedIn+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A4C2780D28A00E5AFB4 /* ParseLinkedIn+combine.swift */; };\n\t\t70F03A522780DA9200E5AFB4 /* ParseGoogleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A512780DA9200E5AFB4 /* ParseGoogleTests.swift */; };\n\t\t70F03A532780DA9200E5AFB4 /* ParseGoogleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A512780DA9200E5AFB4 /* ParseGoogleTests.swift */; };\n\t\t70F03A542780DA9200E5AFB4 /* ParseGoogleTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A512780DA9200E5AFB4 /* ParseGoogleTests.swift */; };\n\t\t70F03A562780E8E300E5AFB4 /* ParseGoogleCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A552780E8E300E5AFB4 /* ParseGoogleCombineTests.swift */; };\n\t\t70F03A572780E8E300E5AFB4 /* ParseGoogleCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A552780E8E300E5AFB4 /* ParseGoogleCombineTests.swift */; };\n\t\t70F03A582780E8E300E5AFB4 /* ParseGoogleCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A552780E8E300E5AFB4 /* ParseGoogleCombineTests.swift */; };\n\t\t70F03A5A2780EAB000E5AFB4 /* ParseGitHubCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A592780EAB000E5AFB4 /* ParseGitHubCombineTests.swift */; };\n\t\t70F03A5B2780EAB000E5AFB4 /* ParseGitHubCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A592780EAB000E5AFB4 /* ParseGitHubCombineTests.swift */; };\n\t\t70F03A5C2780EAB100E5AFB4 /* ParseGitHubCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A592780EAB000E5AFB4 /* ParseGitHubCombineTests.swift */; };\n\t\t70F03A5E2780EAC700E5AFB4 /* ParseGitHubTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A5D2780EAC700E5AFB4 /* ParseGitHubTests.swift */; };\n\t\t70F03A5F2780EAC700E5AFB4 /* ParseGitHubTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A5D2780EAC700E5AFB4 /* ParseGitHubTests.swift */; };\n\t\t70F03A602780EAC700E5AFB4 /* ParseGitHubTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A5D2780EAC700E5AFB4 /* ParseGitHubTests.swift */; };\n\t\t70F03A622780EADD00E5AFB4 /* ParseLinkedInCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A612780EADD00E5AFB4 /* ParseLinkedInCombineTests.swift */; };\n\t\t70F03A632780EADD00E5AFB4 /* ParseLinkedInCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A612780EADD00E5AFB4 /* ParseLinkedInCombineTests.swift */; };\n\t\t70F03A642780EADD00E5AFB4 /* ParseLinkedInCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A612780EADD00E5AFB4 /* ParseLinkedInCombineTests.swift */; };\n\t\t70F03A662780EAFA00E5AFB4 /* ParseLinkedInTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A652780EAFA00E5AFB4 /* ParseLinkedInTests.swift */; };\n\t\t70F03A672780EAFA00E5AFB4 /* ParseLinkedInTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A652780EAFA00E5AFB4 /* ParseLinkedInTests.swift */; };\n\t\t70F03A682780EAFA00E5AFB4 /* ParseLinkedInTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F03A652780EAFA00E5AFB4 /* ParseLinkedInTests.swift */; };\n\t\t70F2E255254F247000B2EA5C /* ParseSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4AFDA7121F26D9A5002AE4FC /* ParseSwift.framework */; };\n\t\t70F2E2B3254F283000B2EA5C /* ParseUserTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C7DC1D24D20E530050419B /* ParseUserTests.swift */; };\n\t\t70F2E2B4254F283000B2EA5C /* ParseQueryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C7DC1F24D20F180050419B /* ParseQueryTests.swift */; };\n\t\t70F2E2B5254F283000B2EA5C /* ParseEncoderExtraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F971F4F524DE381A006CB79B /* ParseEncoderExtraTests.swift */; };\n\t\t70F2E2B6254F283000B2EA5C /* ParseACLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9194657724F16E330070296B /* ParseACLTests.swift */; };\n\t\t70F2E2B7254F283000B2EA5C /* ParsePointerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE1D882545BF730018D572 /* ParsePointerTests.swift */; };\n\t\t70F2E2B8254F283000B2EA5C /* AnyEncodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FFF552B2217E729007C3B4E /* AnyEncodableTests.swift */; };\n\t\t70F2E2B9254F283000B2EA5C /* KeychainStoreTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AA8076E1F794C1C008CD551 /* KeychainStoreTests.swift */; };\n\t\t70F2E2BA254F283000B2EA5C /* ParseInstallationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70110D5B2506ED0E0091CC1D /* ParseInstallationTests.swift */; };\n\t\t70F2E2BB254F283000B2EA5C /* ParseGeoPointTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70BC0B32251903D1001556DB /* ParseGeoPointTests.swift */; };\n\t\t70F2E2BC254F283000B2EA5C /* ParseObjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 911DB13524C4FC100027F3C7 /* ParseObjectTests.swift */; };\n\t\t70F2E2BD254F283000B2EA5C /* AnyDecodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FFF552D2217E729007C3B4E /* AnyDecodableTests.swift */; };\n\t\t70F2E2BE254F283000B2EA5C /* ParseObjectBatchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70C7DC2024D20F190050419B /* ParseObjectBatchTests.swift */; };\n\t\t70F2E2BF254F283000B2EA5C /* MockURLProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 911DB13224C494390027F3C7 /* MockURLProtocol.swift */; };\n\t\t70F2E2C0254F283000B2EA5C /* MockURLResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 911DB12B24C3F7720027F3C7 /* MockURLResponse.swift */; };\n\t\t70F2E2C1254F283000B2EA5C /* AnyCodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FFF552C2217E729007C3B4E /* AnyCodableTests.swift */; };\n\t\t70F2E2C2254F283000B2EA5C /* APICommandTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 911DB12D24C4837E0027F3C7 /* APICommandTests.swift */; };\n\t\t70F79A192639CE6F00731C46 /* ParseHealth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F79A182639CE6F00731C46 /* ParseHealth.swift */; };\n\t\t70F79A1A2639CE6F00731C46 /* ParseHealth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F79A182639CE6F00731C46 /* ParseHealth.swift */; };\n\t\t70F79A1B2639CE6F00731C46 /* ParseHealth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F79A182639CE6F00731C46 /* ParseHealth.swift */; };\n\t\t70F79A1C2639CE6F00731C46 /* ParseHealth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F79A182639CE6F00731C46 /* ParseHealth.swift */; };\n\t\t70F79A672639DE9700731C46 /* ParseHealthCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F79A662639DE9700731C46 /* ParseHealthCombineTests.swift */; };\n\t\t70F79A682639DE9700731C46 /* ParseHealthCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F79A662639DE9700731C46 /* ParseHealthCombineTests.swift */; };\n\t\t70F79A692639DE9700731C46 /* ParseHealthCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F79A662639DE9700731C46 /* ParseHealthCombineTests.swift */; };\n\t\t70F79A732639DEA000731C46 /* ParseHealthTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F79A4F2639DE6900731C46 /* ParseHealthTests.swift */; };\n\t\t70F79A7D2639DEA100731C46 /* ParseHealthTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F79A4F2639DE6900731C46 /* ParseHealthTests.swift */; };\n\t\t70F79A872639DEA200731C46 /* ParseHealthTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70F79A4F2639DE6900731C46 /* ParseHealthTests.swift */; };\n\t\t7C4C092B285E746800F202C6 /* ParseInstagram.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4C092A285E746800F202C6 /* ParseInstagram.swift */; };\n\t\t7C4C092C285E746800F202C6 /* ParseInstagram.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4C092A285E746800F202C6 /* ParseInstagram.swift */; };\n\t\t7C4C092D285E746800F202C6 /* ParseInstagram.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4C092A285E746800F202C6 /* ParseInstagram.swift */; };\n\t\t7C4C092E285E746800F202C6 /* ParseInstagram.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4C092A285E746800F202C6 /* ParseInstagram.swift */; };\n\t\t7C4C0930285E986F00F202C6 /* ParseInstagram+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4C092F285E986F00F202C6 /* ParseInstagram+async.swift */; };\n\t\t7C4C0931285E986F00F202C6 /* ParseInstagram+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4C092F285E986F00F202C6 /* ParseInstagram+async.swift */; };\n\t\t7C4C0932285E986F00F202C6 /* ParseInstagram+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4C092F285E986F00F202C6 /* ParseInstagram+async.swift */; };\n\t\t7C4C0933285E986F00F202C6 /* ParseInstagram+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4C092F285E986F00F202C6 /* ParseInstagram+async.swift */; };\n\t\t7C4C093A285E9A3700F202C6 /* ParseInstagram+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4C0939285E9A3700F202C6 /* ParseInstagram+combine.swift */; };\n\t\t7C4C093B285E9A3700F202C6 /* ParseInstagram+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4C0939285E9A3700F202C6 /* ParseInstagram+combine.swift */; };\n\t\t7C4C093C285E9A3700F202C6 /* ParseInstagram+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4C0939285E9A3700F202C6 /* ParseInstagram+combine.swift */; };\n\t\t7C4C093D285E9A3700F202C6 /* ParseInstagram+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4C0939285E9A3700F202C6 /* ParseInstagram+combine.swift */; };\n\t\t7C4C093F285EA3A000F202C6 /* ParseInstagramTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4C093E285EA3A000F202C6 /* ParseInstagramTests.swift */; };\n\t\t7C4C0940285EA3A000F202C6 /* ParseInstagramTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4C093E285EA3A000F202C6 /* ParseInstagramTests.swift */; };\n\t\t7C4C0941285EA3A000F202C6 /* ParseInstagramTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4C093E285EA3A000F202C6 /* ParseInstagramTests.swift */; };\n\t\t7C4C0943285EA56E00F202C6 /* ParseInstagramCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4C0942285EA56E00F202C6 /* ParseInstagramCombineTests.swift */; };\n\t\t7C4C0944285EA56E00F202C6 /* ParseInstagramCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4C0942285EA56E00F202C6 /* ParseInstagramCombineTests.swift */; };\n\t\t7C4C0945285EA56E00F202C6 /* ParseInstagramCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4C0942285EA56E00F202C6 /* ParseInstagramCombineTests.swift */; };\n\t\t7C4C0947285EA60E00F202C6 /* ParseInstagramAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4C0946285EA60E00F202C6 /* ParseInstagramAsyncTests.swift */; };\n\t\t7C4C0948285EA60E00F202C6 /* ParseInstagramAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4C0946285EA60E00F202C6 /* ParseInstagramAsyncTests.swift */; };\n\t\t7C4C0949285EA60E00F202C6 /* ParseInstagramAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C4C0946285EA60E00F202C6 /* ParseInstagramAsyncTests.swift */; };\n\t\t7C55F9E72860CD6B002A352D /* ParseSpotify.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C55F9E62860CD6B002A352D /* ParseSpotify.swift */; };\n\t\t7C55F9E82860CD6B002A352D /* ParseSpotify.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C55F9E62860CD6B002A352D /* ParseSpotify.swift */; };\n\t\t7C55F9E92860CD6B002A352D /* ParseSpotify.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C55F9E62860CD6B002A352D /* ParseSpotify.swift */; };\n\t\t7C55F9EA2860CD6B002A352D /* ParseSpotify.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C55F9E62860CD6B002A352D /* ParseSpotify.swift */; };\n\t\t7C55F9EC2860CEA6002A352D /* ParseSpotify+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C55F9EB2860CEA6002A352D /* ParseSpotify+async.swift */; };\n\t\t7C55F9ED2860CEA6002A352D /* ParseSpotify+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C55F9EB2860CEA6002A352D /* ParseSpotify+async.swift */; };\n\t\t7C55F9EE2860CEA6002A352D /* ParseSpotify+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C55F9EB2860CEA6002A352D /* ParseSpotify+async.swift */; };\n\t\t7C55F9EF2860CEA6002A352D /* ParseSpotify+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C55F9EB2860CEA6002A352D /* ParseSpotify+async.swift */; };\n\t\t7C55F9F12860CEEF002A352D /* ParseSpotify+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C55F9F02860CEEF002A352D /* ParseSpotify+combine.swift */; };\n\t\t7C55F9F22860CEEF002A352D /* ParseSpotify+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C55F9F02860CEEF002A352D /* ParseSpotify+combine.swift */; };\n\t\t7C55F9F32860CEEF002A352D /* ParseSpotify+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C55F9F02860CEEF002A352D /* ParseSpotify+combine.swift */; };\n\t\t7C55F9F42860CEEF002A352D /* ParseSpotify+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C55F9F02860CEEF002A352D /* ParseSpotify+combine.swift */; };\n\t\t7C995D252861F8330077805A /* ParseSpotifyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C995D242861F8330077805A /* ParseSpotifyTests.swift */; };\n\t\t7C995D262861F8330077805A /* ParseSpotifyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C995D242861F8330077805A /* ParseSpotifyTests.swift */; };\n\t\t7C995D272861F8330077805A /* ParseSpotifyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C995D242861F8330077805A /* ParseSpotifyTests.swift */; };\n\t\t7C995D292861FA0B0077805A /* ParseSpotifyAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C995D282861FA0B0077805A /* ParseSpotifyAsyncTests.swift */; };\n\t\t7C995D2A2861FA0B0077805A /* ParseSpotifyAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C995D282861FA0B0077805A /* ParseSpotifyAsyncTests.swift */; };\n\t\t7C995D2B2861FA0B0077805A /* ParseSpotifyAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C995D282861FA0B0077805A /* ParseSpotifyAsyncTests.swift */; };\n\t\t7C995D2D2861FAE40077805A /* ParseSpotifyCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C995D2C2861FAE40077805A /* ParseSpotifyCombineTests.swift */; };\n\t\t7C995D2E2861FAE40077805A /* ParseSpotifyCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C995D2C2861FAE40077805A /* ParseSpotifyCombineTests.swift */; };\n\t\t7C995D2F2861FAE40077805A /* ParseSpotifyCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C995D2C2861FAE40077805A /* ParseSpotifyCombineTests.swift */; };\n\t\t7FFF552E2217E72A007C3B4E /* AnyEncodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FFF552B2217E729007C3B4E /* AnyEncodableTests.swift */; };\n\t\t7FFF552F2217E72A007C3B4E /* AnyCodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FFF552C2217E729007C3B4E /* AnyCodableTests.swift */; };\n\t\t7FFF55302217E72A007C3B4E /* AnyDecodableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7FFF552D2217E729007C3B4E /* AnyDecodableTests.swift */; };\n\t\t89899CCF2603CE3A002E2043 /* ParseFacebook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89899CCE2603CE3A002E2043 /* ParseFacebook.swift */; };\n\t\t89899CD02603CE3A002E2043 /* ParseFacebook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89899CCE2603CE3A002E2043 /* ParseFacebook.swift */; };\n\t\t89899CD12603CE3A002E2043 /* ParseFacebook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89899CCE2603CE3A002E2043 /* ParseFacebook.swift */; };\n\t\t89899CD22603CE3A002E2043 /* ParseFacebook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89899CCE2603CE3A002E2043 /* ParseFacebook.swift */; };\n\t\t89899D282603CF35002E2043 /* ParseTwitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89899CC02603CE2A002E2043 /* ParseTwitter.swift */; };\n\t\t89899D322603CF35002E2043 /* ParseTwitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89899CC02603CE2A002E2043 /* ParseTwitter.swift */; };\n\t\t89899D332603CF36002E2043 /* ParseTwitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89899CC02603CE2A002E2043 /* ParseTwitter.swift */; };\n\t\t89899D342603CF36002E2043 /* ParseTwitter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89899CC02603CE2A002E2043 /* ParseTwitter.swift */; };\n\t\t89899D592603CF3E002E2043 /* ParseTwitterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89899CDC2603CE73002E2043 /* ParseTwitterTests.swift */; };\n\t\t89899D632603CF3E002E2043 /* ParseTwitterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89899CDC2603CE73002E2043 /* ParseTwitterTests.swift */; };\n\t\t89899D642603CF3F002E2043 /* ParseTwitterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89899CDC2603CE73002E2043 /* ParseTwitterTests.swift */; };\n\t\t89899D772603CF66002E2043 /* ParseFacebookTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89899CF32603CE9D002E2043 /* ParseFacebookTests.swift */; };\n\t\t89899D812603CF67002E2043 /* ParseFacebookTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89899CF32603CE9D002E2043 /* ParseFacebookTests.swift */; };\n\t\t89899D822603CF67002E2043 /* ParseFacebookTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89899CF32603CE9D002E2043 /* ParseFacebookTests.swift */; };\n\t\t89899D9F26045998002E2043 /* ParseTwitterCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89899D9E26045998002E2043 /* ParseTwitterCombineTests.swift */; };\n\t\t89899DA026045998002E2043 /* ParseTwitterCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89899D9E26045998002E2043 /* ParseTwitterCombineTests.swift */; };\n\t\t89899DA126045998002E2043 /* ParseTwitterCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89899D9E26045998002E2043 /* ParseTwitterCombineTests.swift */; };\n\t\t89899DB526045DC4002E2043 /* ParseFacebookCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89899DB426045DC4002E2043 /* ParseFacebookCombineTests.swift */; };\n\t\t89899DB626045DC4002E2043 /* ParseFacebookCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89899DB426045DC4002E2043 /* ParseFacebookCombineTests.swift */; };\n\t\t89899DB726045DC4002E2043 /* ParseFacebookCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89899DB426045DC4002E2043 /* ParseFacebookCombineTests.swift */; };\n\t\t9116F66F26A35D610082F6D6 /* URLCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9116F66E26A35D600082F6D6 /* URLCache.swift */; };\n\t\t9116F67026A35D610082F6D6 /* URLCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9116F66E26A35D600082F6D6 /* URLCache.swift */; };\n\t\t9116F67126A35D620082F6D6 /* URLCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9116F66E26A35D600082F6D6 /* URLCache.swift */; };\n\t\t9116F67226A35D620082F6D6 /* URLCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9116F66E26A35D600082F6D6 /* URLCache.swift */; };\n\t\t911DB12C24C3F7720027F3C7 /* MockURLResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 911DB12B24C3F7720027F3C7 /* MockURLResponse.swift */; };\n\t\t911DB12E24C4837E0027F3C7 /* APICommandTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 911DB12D24C4837E0027F3C7 /* APICommandTests.swift */; };\n\t\t911DB13324C494390027F3C7 /* MockURLProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 911DB13224C494390027F3C7 /* MockURLProtocol.swift */; };\n\t\t911DB13624C4FC100027F3C7 /* ParseObjectTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 911DB13524C4FC100027F3C7 /* ParseObjectTests.swift */; };\n\t\t91285B132698DBF20051B544 /* ParseBytes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91285B122698DBF20051B544 /* ParseBytes.swift */; };\n\t\t91285B142698DBF20051B544 /* ParseBytes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91285B122698DBF20051B544 /* ParseBytes.swift */; };\n\t\t91285B152698DBF20051B544 /* ParseBytes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91285B122698DBF20051B544 /* ParseBytes.swift */; };\n\t\t91285B162698DBF20051B544 /* ParseBytes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91285B122698DBF20051B544 /* ParseBytes.swift */; };\n\t\t91285B182698E66D0051B544 /* ParseBytesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91285B172698E66D0051B544 /* ParseBytesTests.swift */; };\n\t\t91285B192698E66D0051B544 /* ParseBytesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91285B172698E66D0051B544 /* ParseBytesTests.swift */; };\n\t\t91285B1A2698E66D0051B544 /* ParseBytesTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91285B172698E66D0051B544 /* ParseBytesTests.swift */; };\n\t\t91285B1C26990D7F0051B544 /* ParsePolygon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91285B1B26990D7F0051B544 /* ParsePolygon.swift */; };\n\t\t91285B1D26990D7F0051B544 /* ParsePolygon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91285B1B26990D7F0051B544 /* ParsePolygon.swift */; };\n\t\t91285B1E26990D7F0051B544 /* ParsePolygon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91285B1B26990D7F0051B544 /* ParsePolygon.swift */; };\n\t\t91285B1F26990D7F0051B544 /* ParsePolygon.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91285B1B26990D7F0051B544 /* ParsePolygon.swift */; };\n\t\t91285B2126991EE80051B544 /* ParsePolygonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91285B2026991EE80051B544 /* ParsePolygonTests.swift */; };\n\t\t91285B2226991EE80051B544 /* ParsePolygonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91285B2026991EE80051B544 /* ParsePolygonTests.swift */; };\n\t\t91285B2326991EE80051B544 /* ParsePolygonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91285B2026991EE80051B544 /* ParsePolygonTests.swift */; };\n\t\t912C9BCF24D3005D009947C3 /* ParseSwift_watchOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 912C9BCD24D3005D009947C3 /* ParseSwift_watchOS.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t912C9BDC24D3011F009947C3 /* ParseSwift_tvOS.h in Headers */ = {isa = PBXBuildFile; fileRef = 912C9BDA24D3011F009947C3 /* ParseSwift_tvOS.h */; settings = {ATTRIBUTES = (Public, ); }; };\n\t\t912C9BE024D302B0009947C3 /* Parse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EE1F254B820063D731 /* Parse.swift */; };\n\t\t912C9BFD24D302B2009947C3 /* Parse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A82B7EE1F254B820063D731 /* Parse.swift */; };\n\t\t916786E2259B7DDA00BB5B4E /* ParseCloudable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 916786E1259B7DDA00BB5B4E /* ParseCloudable.swift */; };\n\t\t916786E3259B7DDA00BB5B4E /* ParseCloudable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 916786E1259B7DDA00BB5B4E /* ParseCloudable.swift */; };\n\t\t916786E4259B7DDA00BB5B4E /* ParseCloudable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 916786E1259B7DDA00BB5B4E /* ParseCloudable.swift */; };\n\t\t916786E5259B7DDA00BB5B4E /* ParseCloudable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 916786E1259B7DDA00BB5B4E /* ParseCloudable.swift */; };\n\t\t91678706259BC5D400BB5B4E /* ParseCloudableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 916786EF259BC59600BB5B4E /* ParseCloudableTests.swift */; };\n\t\t91678710259BC5D600BB5B4E /* ParseCloudableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 916786EF259BC59600BB5B4E /* ParseCloudableTests.swift */; };\n\t\t9167871A259BC5D600BB5B4E /* ParseCloudableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 916786EF259BC59600BB5B4E /* ParseCloudableTests.swift */; };\n\t\t91679D64268E596300F71809 /* ParseVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91679D63268E596300F71809 /* ParseVersion.swift */; };\n\t\t91679D65268E596300F71809 /* ParseVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91679D63268E596300F71809 /* ParseVersion.swift */; };\n\t\t91679D66268E596300F71809 /* ParseVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91679D63268E596300F71809 /* ParseVersion.swift */; };\n\t\t91679D67268E596300F71809 /* ParseVersion.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91679D63268E596300F71809 /* ParseVersion.swift */; };\n\t\t91679D6D268F261800F71809 /* ParseVersionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91679D68268F25EA00F71809 /* ParseVersionTests.swift */; };\n\t\t91679D6E268F261900F71809 /* ParseVersionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91679D68268F25EA00F71809 /* ParseVersionTests.swift */; };\n\t\t91679D6F268F261A00F71809 /* ParseVersionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91679D68268F25EA00F71809 /* ParseVersionTests.swift */; };\n\t\t917BA4262703DB4600F8D747 /* ParseQueryAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4252703DB4600F8D747 /* ParseQueryAsyncTests.swift */; };\n\t\t917BA4272703DB4600F8D747 /* ParseQueryAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4252703DB4600F8D747 /* ParseQueryAsyncTests.swift */; };\n\t\t917BA4282703DB4600F8D747 /* ParseQueryAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4252703DB4600F8D747 /* ParseQueryAsyncTests.swift */; };\n\t\t917BA42A2703E03F00F8D747 /* ParseAnalyticsAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4292703E03F00F8D747 /* ParseAnalyticsAsyncTests.swift */; };\n\t\t917BA42B2703E03F00F8D747 /* ParseAnalyticsAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4292703E03F00F8D747 /* ParseAnalyticsAsyncTests.swift */; };\n\t\t917BA42C2703E03F00F8D747 /* ParseAnalyticsAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4292703E03F00F8D747 /* ParseAnalyticsAsyncTests.swift */; };\n\t\t917BA42E2703E20E00F8D747 /* ParseCloudableAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA42D2703E20E00F8D747 /* ParseCloudableAsyncTests.swift */; };\n\t\t917BA42F2703E20E00F8D747 /* ParseCloudableAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA42D2703E20E00F8D747 /* ParseCloudableAsyncTests.swift */; };\n\t\t917BA4302703E20E00F8D747 /* ParseCloudableAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA42D2703E20E00F8D747 /* ParseCloudableAsyncTests.swift */; };\n\t\t917BA4322703E36800F8D747 /* ParseConfigAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4312703E36800F8D747 /* ParseConfigAsyncTests.swift */; };\n\t\t917BA4332703E36800F8D747 /* ParseConfigAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4312703E36800F8D747 /* ParseConfigAsyncTests.swift */; };\n\t\t917BA4342703E36800F8D747 /* ParseConfigAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4312703E36800F8D747 /* ParseConfigAsyncTests.swift */; };\n\t\t917BA4362703E4CB00F8D747 /* ParseFileAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4352703E4CB00F8D747 /* ParseFileAsyncTests.swift */; };\n\t\t917BA4372703E4CB00F8D747 /* ParseFileAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4352703E4CB00F8D747 /* ParseFileAsyncTests.swift */; };\n\t\t917BA4382703E4CB00F8D747 /* ParseFileAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4352703E4CB00F8D747 /* ParseFileAsyncTests.swift */; };\n\t\t917BA43A2703E6D800F8D747 /* ParseHealthAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4392703E6D800F8D747 /* ParseHealthAsyncTests.swift */; };\n\t\t917BA43B2703E6D800F8D747 /* ParseHealthAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4392703E6D800F8D747 /* ParseHealthAsyncTests.swift */; };\n\t\t917BA43C2703E6D800F8D747 /* ParseHealthAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4392703E6D800F8D747 /* ParseHealthAsyncTests.swift */; };\n\t\t917BA43E2703E84000F8D747 /* ParseOperationAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA43D2703E84000F8D747 /* ParseOperationAsyncTests.swift */; };\n\t\t917BA43F2703E84000F8D747 /* ParseOperationAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA43D2703E84000F8D747 /* ParseOperationAsyncTests.swift */; };\n\t\t917BA4402703E84000F8D747 /* ParseOperationAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA43D2703E84000F8D747 /* ParseOperationAsyncTests.swift */; };\n\t\t917BA4422703EAC700F8D747 /* ParseLiveQueryAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4412703EAC700F8D747 /* ParseLiveQueryAsyncTests.swift */; };\n\t\t917BA4432703EAC700F8D747 /* ParseLiveQueryAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4412703EAC700F8D747 /* ParseLiveQueryAsyncTests.swift */; };\n\t\t917BA4442703EAC700F8D747 /* ParseLiveQueryAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4412703EAC700F8D747 /* ParseLiveQueryAsyncTests.swift */; };\n\t\t917BA4462703EEA700F8D747 /* ParseAnonymousAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4452703EEA700F8D747 /* ParseAnonymousAsyncTests.swift */; };\n\t\t917BA4472703EEA700F8D747 /* ParseAnonymousAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4452703EEA700F8D747 /* ParseAnonymousAsyncTests.swift */; };\n\t\t917BA4482703EEA700F8D747 /* ParseAnonymousAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4452703EEA700F8D747 /* ParseAnonymousAsyncTests.swift */; };\n\t\t917BA44A2703F10400F8D747 /* ParseAppleAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4492703F10400F8D747 /* ParseAppleAsyncTests.swift */; };\n\t\t917BA44B2703F10400F8D747 /* ParseAppleAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4492703F10400F8D747 /* ParseAppleAsyncTests.swift */; };\n\t\t917BA44C2703F10400F8D747 /* ParseAppleAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4492703F10400F8D747 /* ParseAppleAsyncTests.swift */; };\n\t\t917BA44E2703F2B400F8D747 /* ParseFacebookAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA44D2703F2B400F8D747 /* ParseFacebookAsyncTests.swift */; };\n\t\t917BA44F2703F2B400F8D747 /* ParseFacebookAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA44D2703F2B400F8D747 /* ParseFacebookAsyncTests.swift */; };\n\t\t917BA4502703F2B400F8D747 /* ParseFacebookAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA44D2703F2B400F8D747 /* ParseFacebookAsyncTests.swift */; };\n\t\t917BA4522703F55700F8D747 /* ParseTwitterAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4512703F55700F8D747 /* ParseTwitterAsyncTests.swift */; };\n\t\t917BA4532703F55700F8D747 /* ParseTwitterAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4512703F55700F8D747 /* ParseTwitterAsyncTests.swift */; };\n\t\t917BA4542703F55700F8D747 /* ParseTwitterAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4512703F55700F8D747 /* ParseTwitterAsyncTests.swift */; };\n\t\t917BA4562703F75E00F8D747 /* ParseLDAPAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4552703F75E00F8D747 /* ParseLDAPAsyncTests.swift */; };\n\t\t917BA4572703F75E00F8D747 /* ParseLDAPAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4552703F75E00F8D747 /* ParseLDAPAsyncTests.swift */; };\n\t\t917BA4582703F75E00F8D747 /* ParseLDAPAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4552703F75E00F8D747 /* ParseLDAPAsyncTests.swift */; };\n\t\t917BA45A2703FD2200F8D747 /* ParseAuthenticationAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4592703FD2200F8D747 /* ParseAuthenticationAsyncTests.swift */; };\n\t\t917BA45B2703FD2200F8D747 /* ParseAuthenticationAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4592703FD2200F8D747 /* ParseAuthenticationAsyncTests.swift */; };\n\t\t917BA45C2703FD2200F8D747 /* ParseAuthenticationAsyncTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 917BA4592703FD2200F8D747 /* ParseAuthenticationAsyncTests.swift */; };\n\t\t918CED592684C74000CFDC83 /* ParseLiveQuery+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 918CED582684C74000CFDC83 /* ParseLiveQuery+combine.swift */; };\n\t\t918CED5A2684C74000CFDC83 /* ParseLiveQuery+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 918CED582684C74000CFDC83 /* ParseLiveQuery+combine.swift */; };\n\t\t918CED5B2684C74000CFDC83 /* ParseLiveQuery+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 918CED582684C74000CFDC83 /* ParseLiveQuery+combine.swift */; };\n\t\t918CED5C2684C74000CFDC83 /* ParseLiveQuery+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 918CED582684C74000CFDC83 /* ParseLiveQuery+combine.swift */; };\n\t\t918CED5E268618C600CFDC83 /* ParseLiveQueryCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 918CED5D268618C600CFDC83 /* ParseLiveQueryCombineTests.swift */; };\n\t\t918CED5F268618C600CFDC83 /* ParseLiveQueryCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 918CED5D268618C600CFDC83 /* ParseLiveQueryCombineTests.swift */; };\n\t\t918CED60268618C600CFDC83 /* ParseLiveQueryCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 918CED5D268618C600CFDC83 /* ParseLiveQueryCombineTests.swift */; };\n\t\t9194657824F16E330070296B /* ParseACLTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9194657724F16E330070296B /* ParseACLTests.swift */; };\n\t\t91B40651267A66ED00B129CD /* ParseErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91B40650267A66ED00B129CD /* ParseErrorTests.swift */; };\n\t\t91B40652267A66ED00B129CD /* ParseErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91B40650267A66ED00B129CD /* ParseErrorTests.swift */; };\n\t\t91B40653267A66ED00B129CD /* ParseErrorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91B40650267A66ED00B129CD /* ParseErrorTests.swift */; };\n\t\t91B79AC326EE3A4E00073F2C /* API+NonParseBodyCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91B79AC226EE3A4E00073F2C /* API+NonParseBodyCommand.swift */; };\n\t\t91B79AC426EE3A4E00073F2C /* API+NonParseBodyCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91B79AC226EE3A4E00073F2C /* API+NonParseBodyCommand.swift */; };\n\t\t91B79AC526EE3A4E00073F2C /* API+NonParseBodyCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91B79AC226EE3A4E00073F2C /* API+NonParseBodyCommand.swift */; };\n\t\t91B79AC626EE3A4E00073F2C /* API+NonParseBodyCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91B79AC226EE3A4E00073F2C /* API+NonParseBodyCommand.swift */; };\n\t\t91B79AC826EE3C5D00073F2C /* API+BatchCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91B79AC726EE3C5D00073F2C /* API+BatchCommand.swift */; };\n\t\t91B79AC926EE3C5D00073F2C /* API+BatchCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91B79AC726EE3C5D00073F2C /* API+BatchCommand.swift */; };\n\t\t91B79ACA26EE3C5D00073F2C /* API+BatchCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91B79AC726EE3C5D00073F2C /* API+BatchCommand.swift */; };\n\t\t91B79ACB26EE3C5D00073F2C /* API+BatchCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91B79AC726EE3C5D00073F2C /* API+BatchCommand.swift */; };\n\t\t91BB8FCA2690AC99005A6BA5 /* QueryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91BB8FC92690AC99005A6BA5 /* QueryViewModel.swift */; };\n\t\t91BB8FCB2690AC99005A6BA5 /* QueryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91BB8FC92690AC99005A6BA5 /* QueryViewModel.swift */; };\n\t\t91BB8FCC2690AC99005A6BA5 /* QueryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91BB8FC92690AC99005A6BA5 /* QueryViewModel.swift */; };\n\t\t91BB8FCD2690AC99005A6BA5 /* QueryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91BB8FC92690AC99005A6BA5 /* QueryViewModel.swift */; };\n\t\t91BB8FCF2690BA70005A6BA5 /* QueryObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91BB8FCE2690BA70005A6BA5 /* QueryObservable.swift */; };\n\t\t91BB8FD02690BA70005A6BA5 /* QueryObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91BB8FCE2690BA70005A6BA5 /* QueryObservable.swift */; };\n\t\t91BB8FD12690BA70005A6BA5 /* QueryObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91BB8FCE2690BA70005A6BA5 /* QueryObservable.swift */; };\n\t\t91BB8FD22690BA70005A6BA5 /* QueryObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91BB8FCE2690BA70005A6BA5 /* QueryObservable.swift */; };\n\t\t91BB8FD42690D586005A6BA5 /* ParseQueryViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91BB8FD32690D586005A6BA5 /* ParseQueryViewModelTests.swift */; };\n\t\t91BB8FD52690D586005A6BA5 /* ParseQueryViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91BB8FD32690D586005A6BA5 /* ParseQueryViewModelTests.swift */; };\n\t\t91BB8FD62690D586005A6BA5 /* ParseQueryViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91BB8FD32690D586005A6BA5 /* ParseQueryViewModelTests.swift */; };\n\t\t91CB9537265966DF0043E5D6 /* ParseAnalyticsCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91CB9536265966DF0043E5D6 /* ParseAnalyticsCombineTests.swift */; };\n\t\t91CB9538265966DF0043E5D6 /* ParseAnalyticsCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91CB9536265966DF0043E5D6 /* ParseAnalyticsCombineTests.swift */; };\n\t\t91CB9539265966DF0043E5D6 /* ParseAnalyticsCombineTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91CB9536265966DF0043E5D6 /* ParseAnalyticsCombineTests.swift */; };\n\t\t91F346B9269B766C005727B6 /* CloudViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F346B8269B766C005727B6 /* CloudViewModel.swift */; };\n\t\t91F346BA269B766D005727B6 /* CloudViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F346B8269B766C005727B6 /* CloudViewModel.swift */; };\n\t\t91F346BB269B766D005727B6 /* CloudViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F346B8269B766C005727B6 /* CloudViewModel.swift */; };\n\t\t91F346BC269B766D005727B6 /* CloudViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F346B8269B766C005727B6 /* CloudViewModel.swift */; };\n\t\t91F346BE269B77B5005727B6 /* CloudObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F346BD269B77B5005727B6 /* CloudObservable.swift */; };\n\t\t91F346BF269B77B5005727B6 /* CloudObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F346BD269B77B5005727B6 /* CloudObservable.swift */; };\n\t\t91F346C0269B77B5005727B6 /* CloudObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F346BD269B77B5005727B6 /* CloudObservable.swift */; };\n\t\t91F346C1269B77B5005727B6 /* CloudObservable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F346BD269B77B5005727B6 /* CloudObservable.swift */; };\n\t\t91F346C3269B88F7005727B6 /* ParseCloudViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F346C2269B88F7005727B6 /* ParseCloudViewModelTests.swift */; };\n\t\t91F346C4269B88F7005727B6 /* ParseCloudViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F346C2269B88F7005727B6 /* ParseCloudViewModelTests.swift */; };\n\t\t91F346C5269B88F7005727B6 /* ParseCloudViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 91F346C2269B88F7005727B6 /* ParseCloudViewModelTests.swift */; };\n\t\tF971F4F624DE381A006CB79B /* ParseEncoderExtraTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F971F4F524DE381A006CB79B /* ParseEncoderExtraTests.swift */; };\n\t\tF97B45CE24D9C6F200F4A88B /* ParseCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B424D9C6F200F4A88B /* ParseCoding.swift */; };\n\t\tF97B45CF24D9C6F200F4A88B /* ParseCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B424D9C6F200F4A88B /* ParseCoding.swift */; };\n\t\tF97B45D024D9C6F200F4A88B /* ParseCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B424D9C6F200F4A88B /* ParseCoding.swift */; };\n\t\tF97B45D124D9C6F200F4A88B /* ParseCoding.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B424D9C6F200F4A88B /* ParseCoding.swift */; };\n\t\tF97B45D224D9C6F200F4A88B /* AnyDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B524D9C6F200F4A88B /* AnyDecodable.swift */; };\n\t\tF97B45D324D9C6F200F4A88B /* AnyDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B524D9C6F200F4A88B /* AnyDecodable.swift */; };\n\t\tF97B45D424D9C6F200F4A88B /* AnyDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B524D9C6F200F4A88B /* AnyDecodable.swift */; };\n\t\tF97B45D524D9C6F200F4A88B /* AnyDecodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B524D9C6F200F4A88B /* AnyDecodable.swift */; };\n\t\tF97B45D624D9C6F200F4A88B /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B624D9C6F200F4A88B /* ParseEncoder.swift */; };\n\t\tF97B45D724D9C6F200F4A88B /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B624D9C6F200F4A88B /* ParseEncoder.swift */; };\n\t\tF97B45D824D9C6F200F4A88B /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B624D9C6F200F4A88B /* ParseEncoder.swift */; };\n\t\tF97B45D924D9C6F200F4A88B /* ParseEncoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B624D9C6F200F4A88B /* ParseEncoder.swift */; };\n\t\tF97B45DE24D9C6F200F4A88B /* AnyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B824D9C6F200F4A88B /* AnyCodable.swift */; };\n\t\tF97B45DF24D9C6F200F4A88B /* AnyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B824D9C6F200F4A88B /* AnyCodable.swift */; };\n\t\tF97B45E024D9C6F200F4A88B /* AnyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B824D9C6F200F4A88B /* AnyCodable.swift */; };\n\t\tF97B45E124D9C6F200F4A88B /* AnyCodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B824D9C6F200F4A88B /* AnyCodable.swift */; };\n\t\tF97B45E224D9C6F200F4A88B /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B924D9C6F200F4A88B /* AnyEncodable.swift */; };\n\t\tF97B45E324D9C6F200F4A88B /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B924D9C6F200F4A88B /* AnyEncodable.swift */; };\n\t\tF97B45E424D9C6F200F4A88B /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B924D9C6F200F4A88B /* AnyEncodable.swift */; };\n\t\tF97B45E524D9C6F200F4A88B /* AnyEncodable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45B924D9C6F200F4A88B /* AnyEncodable.swift */; };\n\t\tF97B45E624D9C6F200F4A88B /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BB24D9C6F200F4A88B /* Query.swift */; };\n\t\tF97B45E724D9C6F200F4A88B /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BB24D9C6F200F4A88B /* Query.swift */; };\n\t\tF97B45E824D9C6F200F4A88B /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BB24D9C6F200F4A88B /* Query.swift */; };\n\t\tF97B45E924D9C6F200F4A88B /* Query.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BB24D9C6F200F4A88B /* Query.swift */; };\n\t\tF97B45EA24D9C6F200F4A88B /* ParseGeoPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BC24D9C6F200F4A88B /* ParseGeoPoint.swift */; };\n\t\tF97B45EB24D9C6F200F4A88B /* ParseGeoPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BC24D9C6F200F4A88B /* ParseGeoPoint.swift */; };\n\t\tF97B45EC24D9C6F200F4A88B /* ParseGeoPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BC24D9C6F200F4A88B /* ParseGeoPoint.swift */; };\n\t\tF97B45ED24D9C6F200F4A88B /* ParseGeoPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BC24D9C6F200F4A88B /* ParseGeoPoint.swift */; };\n\t\tF97B45EE24D9C6F200F4A88B /* BaseParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BD24D9C6F200F4A88B /* BaseParseUser.swift */; };\n\t\tF97B45EF24D9C6F200F4A88B /* BaseParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BD24D9C6F200F4A88B /* BaseParseUser.swift */; };\n\t\tF97B45F024D9C6F200F4A88B /* BaseParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BD24D9C6F200F4A88B /* BaseParseUser.swift */; };\n\t\tF97B45F124D9C6F200F4A88B /* BaseParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BD24D9C6F200F4A88B /* BaseParseUser.swift */; };\n\t\tF97B45F224D9C6F200F4A88B /* Pointer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BE24D9C6F200F4A88B /* Pointer.swift */; };\n\t\tF97B45F324D9C6F200F4A88B /* Pointer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BE24D9C6F200F4A88B /* Pointer.swift */; };\n\t\tF97B45F424D9C6F200F4A88B /* Pointer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BE24D9C6F200F4A88B /* Pointer.swift */; };\n\t\tF97B45F524D9C6F200F4A88B /* Pointer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BE24D9C6F200F4A88B /* Pointer.swift */; };\n\t\tF97B45F624D9C6F200F4A88B /* ParseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BF24D9C6F200F4A88B /* ParseError.swift */; };\n\t\tF97B45F724D9C6F200F4A88B /* ParseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BF24D9C6F200F4A88B /* ParseError.swift */; };\n\t\tF97B45F824D9C6F200F4A88B /* ParseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BF24D9C6F200F4A88B /* ParseError.swift */; };\n\t\tF97B45F924D9C6F200F4A88B /* ParseError.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45BF24D9C6F200F4A88B /* ParseError.swift */; };\n\t\tF97B45FA24D9C6F200F4A88B /* ParseACL.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C024D9C6F200F4A88B /* ParseACL.swift */; };\n\t\tF97B45FB24D9C6F200F4A88B /* ParseACL.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C024D9C6F200F4A88B /* ParseACL.swift */; };\n\t\tF97B45FC24D9C6F200F4A88B /* ParseACL.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C024D9C6F200F4A88B /* ParseACL.swift */; };\n\t\tF97B45FD24D9C6F200F4A88B /* ParseACL.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C024D9C6F200F4A88B /* ParseACL.swift */; };\n\t\tF97B45FE24D9C6F200F4A88B /* ParseFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C124D9C6F200F4A88B /* ParseFile.swift */; };\n\t\tF97B45FF24D9C6F200F4A88B /* ParseFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C124D9C6F200F4A88B /* ParseFile.swift */; };\n\t\tF97B460024D9C6F200F4A88B /* ParseFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C124D9C6F200F4A88B /* ParseFile.swift */; };\n\t\tF97B460124D9C6F200F4A88B /* ParseFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C124D9C6F200F4A88B /* ParseFile.swift */; };\n\t\tF97B460224D9C6F200F4A88B /* NoBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C224D9C6F200F4A88B /* NoBody.swift */; };\n\t\tF97B460324D9C6F200F4A88B /* NoBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C224D9C6F200F4A88B /* NoBody.swift */; };\n\t\tF97B460424D9C6F200F4A88B /* NoBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C224D9C6F200F4A88B /* NoBody.swift */; };\n\t\tF97B460524D9C6F200F4A88B /* NoBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C224D9C6F200F4A88B /* NoBody.swift */; };\n\t\tF97B460624D9C6F200F4A88B /* ParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C424D9C6F200F4A88B /* ParseUser.swift */; };\n\t\tF97B460724D9C6F200F4A88B /* ParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C424D9C6F200F4A88B /* ParseUser.swift */; };\n\t\tF97B460824D9C6F200F4A88B /* ParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C424D9C6F200F4A88B /* ParseUser.swift */; };\n\t\tF97B460924D9C6F200F4A88B /* ParseUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C424D9C6F200F4A88B /* ParseUser.swift */; };\n\t\tF97B460A24D9C6F200F4A88B /* Fetchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C524D9C6F200F4A88B /* Fetchable.swift */; };\n\t\tF97B460B24D9C6F200F4A88B /* Fetchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C524D9C6F200F4A88B /* Fetchable.swift */; };\n\t\tF97B460C24D9C6F200F4A88B /* Fetchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C524D9C6F200F4A88B /* Fetchable.swift */; };\n\t\tF97B460D24D9C6F200F4A88B /* Fetchable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C524D9C6F200F4A88B /* Fetchable.swift */; };\n\t\tF97B460E24D9C6F200F4A88B /* ParseObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C624D9C6F200F4A88B /* ParseObject.swift */; };\n\t\tF97B460F24D9C6F200F4A88B /* ParseObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C624D9C6F200F4A88B /* ParseObject.swift */; };\n\t\tF97B461024D9C6F200F4A88B /* ParseObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C624D9C6F200F4A88B /* ParseObject.swift */; };\n\t\tF97B461124D9C6F200F4A88B /* ParseObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C624D9C6F200F4A88B /* ParseObject.swift */; };\n\t\tF97B461224D9C6F200F4A88B /* Savable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C724D9C6F200F4A88B /* Savable.swift */; };\n\t\tF97B461324D9C6F200F4A88B /* Savable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C724D9C6F200F4A88B /* Savable.swift */; };\n\t\tF97B461424D9C6F200F4A88B /* Savable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C724D9C6F200F4A88B /* Savable.swift */; };\n\t\tF97B461524D9C6F200F4A88B /* Savable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C724D9C6F200F4A88B /* Savable.swift */; };\n\t\tF97B461624D9C6F200F4A88B /* Queryable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C824D9C6F200F4A88B /* Queryable.swift */; };\n\t\tF97B461724D9C6F200F4A88B /* Queryable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C824D9C6F200F4A88B /* Queryable.swift */; };\n\t\tF97B461824D9C6F200F4A88B /* Queryable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C824D9C6F200F4A88B /* Queryable.swift */; };\n\t\tF97B461924D9C6F200F4A88B /* Queryable.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45C824D9C6F200F4A88B /* Queryable.swift */; };\n\t\tF97B461E24D9C6F200F4A88B /* ParseStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45CC24D9C6F200F4A88B /* ParseStorage.swift */; };\n\t\tF97B461F24D9C6F200F4A88B /* ParseStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45CC24D9C6F200F4A88B /* ParseStorage.swift */; };\n\t\tF97B462024D9C6F200F4A88B /* ParseStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45CC24D9C6F200F4A88B /* ParseStorage.swift */; };\n\t\tF97B462124D9C6F200F4A88B /* ParseStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45CC24D9C6F200F4A88B /* ParseStorage.swift */; };\n\t\tF97B462224D9C6F200F4A88B /* ParseKeyValueStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45CD24D9C6F200F4A88B /* ParseKeyValueStore.swift */; };\n\t\tF97B462324D9C6F200F4A88B /* ParseKeyValueStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45CD24D9C6F200F4A88B /* ParseKeyValueStore.swift */; };\n\t\tF97B462424D9C6F200F4A88B /* ParseKeyValueStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45CD24D9C6F200F4A88B /* ParseKeyValueStore.swift */; };\n\t\tF97B462524D9C6F200F4A88B /* ParseKeyValueStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B45CD24D9C6F200F4A88B /* ParseKeyValueStore.swift */; };\n\t\tF97B462724D9C72700F4A88B /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462624D9C72700F4A88B /* API.swift */; };\n\t\tF97B462824D9C72700F4A88B /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462624D9C72700F4A88B /* API.swift */; };\n\t\tF97B462924D9C72700F4A88B /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462624D9C72700F4A88B /* API.swift */; };\n\t\tF97B462A24D9C72700F4A88B /* API.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462624D9C72700F4A88B /* API.swift */; };\n\t\tF97B462F24D9C74400F4A88B /* BatchUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462B24D9C74400F4A88B /* BatchUtils.swift */; };\n\t\tF97B463024D9C74400F4A88B /* BatchUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462B24D9C74400F4A88B /* BatchUtils.swift */; };\n\t\tF97B463124D9C74400F4A88B /* BatchUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462B24D9C74400F4A88B /* BatchUtils.swift */; };\n\t\tF97B463224D9C74400F4A88B /* BatchUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462B24D9C74400F4A88B /* BatchUtils.swift */; };\n\t\tF97B463324D9C74400F4A88B /* URLSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462C24D9C74400F4A88B /* URLSession.swift */; };\n\t\tF97B463424D9C74400F4A88B /* URLSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462C24D9C74400F4A88B /* URLSession.swift */; };\n\t\tF97B463524D9C74400F4A88B /* URLSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462C24D9C74400F4A88B /* URLSession.swift */; };\n\t\tF97B463624D9C74400F4A88B /* URLSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462C24D9C74400F4A88B /* URLSession.swift */; };\n\t\tF97B463724D9C74400F4A88B /* Responses.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462D24D9C74400F4A88B /* Responses.swift */; };\n\t\tF97B463824D9C74400F4A88B /* Responses.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462D24D9C74400F4A88B /* Responses.swift */; };\n\t\tF97B463924D9C74400F4A88B /* Responses.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462D24D9C74400F4A88B /* Responses.swift */; };\n\t\tF97B463A24D9C74400F4A88B /* Responses.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462D24D9C74400F4A88B /* Responses.swift */; };\n\t\tF97B463B24D9C74400F4A88B /* API+Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462E24D9C74400F4A88B /* API+Command.swift */; };\n\t\tF97B463C24D9C74400F4A88B /* API+Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462E24D9C74400F4A88B /* API+Command.swift */; };\n\t\tF97B463D24D9C74400F4A88B /* API+Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462E24D9C74400F4A88B /* API+Command.swift */; };\n\t\tF97B463E24D9C74400F4A88B /* API+Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B462E24D9C74400F4A88B /* API+Command.swift */; };\n\t\tF97B464624D9C78B00F4A88B /* ParseOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464024D9C78B00F4A88B /* ParseOperation.swift */; };\n\t\tF97B464724D9C78B00F4A88B /* ParseOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464024D9C78B00F4A88B /* ParseOperation.swift */; };\n\t\tF97B464824D9C78B00F4A88B /* ParseOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464024D9C78B00F4A88B /* ParseOperation.swift */; };\n\t\tF97B464924D9C78B00F4A88B /* ParseOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464024D9C78B00F4A88B /* ParseOperation.swift */; };\n\t\tF97B464A24D9C78B00F4A88B /* Delete.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464124D9C78B00F4A88B /* Delete.swift */; };\n\t\tF97B464B24D9C78B00F4A88B /* Delete.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464124D9C78B00F4A88B /* Delete.swift */; };\n\t\tF97B464C24D9C78B00F4A88B /* Delete.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464124D9C78B00F4A88B /* Delete.swift */; };\n\t\tF97B464D24D9C78B00F4A88B /* Delete.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464124D9C78B00F4A88B /* Delete.swift */; };\n\t\tF97B464E24D9C78B00F4A88B /* Add.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464224D9C78B00F4A88B /* Add.swift */; };\n\t\tF97B464F24D9C78B00F4A88B /* Add.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464224D9C78B00F4A88B /* Add.swift */; };\n\t\tF97B465024D9C78B00F4A88B /* Add.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464224D9C78B00F4A88B /* Add.swift */; };\n\t\tF97B465124D9C78C00F4A88B /* Add.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464224D9C78B00F4A88B /* Add.swift */; };\n\t\tF97B465224D9C78C00F4A88B /* AddUnique.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464324D9C78B00F4A88B /* AddUnique.swift */; };\n\t\tF97B465324D9C78C00F4A88B /* AddUnique.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464324D9C78B00F4A88B /* AddUnique.swift */; };\n\t\tF97B465424D9C78C00F4A88B /* AddUnique.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464324D9C78B00F4A88B /* AddUnique.swift */; };\n\t\tF97B465524D9C78C00F4A88B /* AddUnique.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464324D9C78B00F4A88B /* AddUnique.swift */; };\n\t\tF97B465624D9C78C00F4A88B /* Remove.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464424D9C78B00F4A88B /* Remove.swift */; };\n\t\tF97B465724D9C78C00F4A88B /* Remove.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464424D9C78B00F4A88B /* Remove.swift */; };\n\t\tF97B465824D9C78C00F4A88B /* Remove.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464424D9C78B00F4A88B /* Remove.swift */; };\n\t\tF97B465924D9C78C00F4A88B /* Remove.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464424D9C78B00F4A88B /* Remove.swift */; };\n\t\tF97B465A24D9C78C00F4A88B /* Increment.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464524D9C78B00F4A88B /* Increment.swift */; };\n\t\tF97B465B24D9C78C00F4A88B /* Increment.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464524D9C78B00F4A88B /* Increment.swift */; };\n\t\tF97B465C24D9C78C00F4A88B /* Increment.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464524D9C78B00F4A88B /* Increment.swift */; };\n\t\tF97B465D24D9C78C00F4A88B /* Increment.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B464524D9C78B00F4A88B /* Increment.swift */; };\n\t\tF97B465F24D9C7B500F4A88B /* KeychainStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B465E24D9C7B500F4A88B /* KeychainStore.swift */; };\n\t\tF97B466024D9C7B500F4A88B /* KeychainStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B465E24D9C7B500F4A88B /* KeychainStore.swift */; };\n\t\tF97B466124D9C7B500F4A88B /* KeychainStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B465E24D9C7B500F4A88B /* KeychainStore.swift */; };\n\t\tF97B466224D9C7B500F4A88B /* KeychainStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B465E24D9C7B500F4A88B /* KeychainStore.swift */; };\n\t\tF97B466424D9C88600F4A88B /* SecureStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B466324D9C88600F4A88B /* SecureStorage.swift */; };\n\t\tF97B466524D9C88600F4A88B /* SecureStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B466324D9C88600F4A88B /* SecureStorage.swift */; };\n\t\tF97B466624D9C88600F4A88B /* SecureStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B466324D9C88600F4A88B /* SecureStorage.swift */; };\n\t\tF97B466724D9C88600F4A88B /* SecureStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = F97B466324D9C88600F4A88B /* SecureStorage.swift */; };\n/* End PBXBuildFile section */\n\n/* Begin PBXContainerItemProxy section */\n\t\t4AA8076A1F79424A008CD551 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 4AB8B4EB1F254AE10070F682 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 4AA807571F794242008CD551;\n\t\t\tremoteInfo = TestHost;\n\t\t};\n\t\t4AB8B4FF1F254AE10070F682 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 4AB8B4EB1F254AE10070F682 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 4AB8B4F31F254AE10070F682;\n\t\t\tremoteInfo = Parse;\n\t\t};\n\t\t7033ECCB25584AAF009770F3 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 4AB8B4EB1F254AE10070F682 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 7033ECAF25584A83009770F3;\n\t\t\tremoteInfo = TestHostTV;\n\t\t};\n\t\t709B98362556EC7400507778 /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 4AB8B4EB1F254AE10070F682 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 912C9BD724D3011F009947C3;\n\t\t\tremoteInfo = \"ParseSwift (tvOS)\";\n\t\t};\n\t\t70F2E256254F247000B2EA5C /* PBXContainerItemProxy */ = {\n\t\t\tisa = PBXContainerItemProxy;\n\t\t\tcontainerPortal = 4AB8B4EB1F254AE10070F682 /* Project object */;\n\t\t\tproxyType = 1;\n\t\t\tremoteGlobalIDString = 4AFDA7111F26D9A5002AE4FC;\n\t\t\tremoteInfo = \"ParseSwift (macOS)\";\n\t\t};\n/* End PBXContainerItemProxy section */\n\n/* Begin PBXFileReference section */\n\t\t4A1120BF1F49FC3300E32D94 /* LinuxMain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinuxMain.swift; sourceTree = \"<group>\"; };\n\t\t4A82B7EE1F254B820063D731 /* Parse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Parse.swift; sourceTree = \"<group>\"; };\n\t\t4AA807581F794242008CD551 /* TestHost.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestHost.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t4AA8075A1F794242008CD551 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\t4AA8075F1F794242008CD551 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\t4AA807611F794242008CD551 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t4AA807641F794242008CD551 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\t4AA807661F794242008CD551 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t4AA8076D1F794C1C008CD551 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t4AA8076E1F794C1C008CD551 /* KeychainStoreTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainStoreTests.swift; sourceTree = \"<group>\"; };\n\t\t4AB8B4F41F254AE10070F682 /* ParseSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ParseSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t4AB8B4F71F254AE10070F682 /* Parse.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Parse.h; sourceTree = \"<group>\"; };\n\t\t4AB8B4F81F254AE10070F682 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t4AB8B4FD1F254AE10070F682 /* ParseSwiftTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ParseSwiftTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t4ACFC2E21F3CA21F0046F3A3 /* ParseSwift.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = ParseSwift.playground; sourceTree = \"<group>\"; };\n\t\t4AFDA7121F26D9A5002AE4FC /* ParseSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ParseSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t4AFDA7151F26D9A5002AE4FC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t7003957525A0EE770052CB31 /* BatchUtilsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatchUtilsTests.swift; sourceTree = \"<group>\"; };\n\t\t7003959425A10DFC0052CB31 /* Messages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Messages.swift; sourceTree = \"<group>\"; };\n\t\t700395A225A119430052CB31 /* Operations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Operations.swift; sourceTree = \"<group>\"; };\n\t\t700395B925A1470F0052CB31 /* Subscription.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Subscription.swift; sourceTree = \"<group>\"; };\n\t\t700395D025A147BE0052CB31 /* QuerySubscribable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuerySubscribable.swift; sourceTree = \"<group>\"; };\n\t\t700395F125A171320052CB31 /* LiveQueryable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveQueryable.swift; sourceTree = \"<group>\"; };\n\t\t7003960825A184EF0052CB31 /* ParseLiveQuery.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseLiveQuery.swift; sourceTree = \"<group>\"; };\n\t\t7003963A25A288100052CB31 /* ParseLiveQueryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseLiveQueryTests.swift; sourceTree = \"<group>\"; };\n\t\t700396E925A3892D0052CB31 /* LiveQuerySocketDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveQuerySocketDelegate.swift; sourceTree = \"<group>\"; };\n\t\t700396F725A394AE0052CB31 /* ParseLiveQueryDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseLiveQueryDelegate.swift; sourceTree = \"<group>\"; };\n\t\t7003972925A3B0130052CB31 /* ParseURLSessionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseURLSessionDelegate.swift; sourceTree = \"<group>\"; };\n\t\t7004C21F25B63C7A005E0AD9 /* ParseRelation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseRelation.swift; sourceTree = \"<group>\"; };\n\t\t7004C22D25B69077005E0AD9 /* ParseRoleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseRoleTests.swift; sourceTree = \"<group>\"; };\n\t\t700AFE02289C3508006C1CD9 /* ParseQueryCacheTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseQueryCacheTests.swift; sourceTree = \"<group>\"; };\n\t\t70110D51250680140091CC1D /* ParseConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseConstants.swift; sourceTree = \"<group>\"; };\n\t\t70110D562506CE890091CC1D /* BaseParseInstallation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseParseInstallation.swift; sourceTree = \"<group>\"; };\n\t\t70110D5B2506ED0E0091CC1D /* ParseInstallationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseInstallationTests.swift; sourceTree = \"<group>\"; };\n\t\t7016ED3125C3BA2000038648 /* ParseUser+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseUser+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t7016ED3F25C4A25A00038648 /* ParseUserCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseUserCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t7016ED5525C4C32B00038648 /* ParseInstallation+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseInstallation+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t7016ED6325C4C46B00038648 /* ParseObject+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseObject+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t70170A432656B02C0070C905 /* ParseAnalytics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAnalytics.swift; sourceTree = \"<group>\"; };\n\t\t70170A482656E2FE0070C905 /* ParseAnalytics+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseAnalytics+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t70170A4D2656EBA50070C905 /* ParseAnalyticsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAnalyticsTests.swift; sourceTree = \"<group>\"; };\n\t\t70212D122854C82B00386163 /* ParsePushFirebaseNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePushFirebaseNotification.swift; sourceTree = \"<group>\"; };\n\t\t70212D172855256F00386163 /* ParsePushTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePushTests.swift; sourceTree = \"<group>\"; };\n\t\t70212D1C2855259100386163 /* ParsePushAsyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePushAsyncTests.swift; sourceTree = \"<group>\"; };\n\t\t70212D21285525A600386163 /* ParsePushCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePushCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t70212D262855260F00386163 /* ParsePushPayloadAppleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePushPayloadAppleTests.swift; sourceTree = \"<group>\"; };\n\t\t7023800E2747FCCD00EFC443 /* ExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionsTests.swift; sourceTree = \"<group>\"; };\n\t\t7028373326BD8883007688C9 /* ParseObject+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseObject+async.swift\"; sourceTree = \"<group>\"; };\n\t\t7028373826BD8C89007688C9 /* ParseUser+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseUser+async.swift\"; sourceTree = \"<group>\"; };\n\t\t7033ECB025584A83009770F3 /* TestHostTV.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestHostTV.app; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t7033ECB225584A83009770F3 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = \"<group>\"; };\n\t\t7033ECB425584A83009770F3 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = \"<group>\"; };\n\t\t7033ECB725584A83009770F3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = \"<group>\"; };\n\t\t7033ECB925584A85009770F3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = \"<group>\"; };\n\t\t7033ECBC25584A85009770F3 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = \"<group>\"; };\n\t\t7033ECBE25584A85009770F3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t7037DAB126384DE1005D7E62 /* TestParseEncoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestParseEncoder.swift; sourceTree = \"<group>\"; };\n\t\t70385E6328563FD10084D306 /* ParsePushPayloadFirebaseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePushPayloadFirebaseTests.swift; sourceTree = \"<group>\"; };\n\t\t70385E67285640A30084D306 /* ParsePushPayloadAnyTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePushPayloadAnyTests.swift; sourceTree = \"<group>\"; };\n\t\t70385E702858D2DD0084D306 /* ParseHookTriggerable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookTriggerable.swift; sourceTree = \"<group>\"; };\n\t\t70385E752858E1000084D306 /* ParseHookFunctionable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookFunctionable.swift; sourceTree = \"<group>\"; };\n\t\t70385E7F2858EAA90084D306 /* ParseHookFunctionRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookFunctionRequest.swift; sourceTree = \"<group>\"; };\n\t\t70385E842858F9750084D306 /* ParseHookParametable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookParametable.swift; sourceTree = \"<group>\"; };\n\t\t70386A0525D9718C0048EC1B /* Data.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = \"<group>\"; };\n\t\t70386A3725D998D90048EC1B /* ParseLDAP.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseLDAP.swift; sourceTree = \"<group>\"; };\n\t\t70386A4525D99C8B0048EC1B /* ParseLDAPTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseLDAPTests.swift; sourceTree = \"<group>\"; };\n\t\t70386A5B25D9A4010048EC1B /* ParseLDAPCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseLDAPCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t703B08FC26BD953B005A112F /* ParseHealth+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseHealth+async.swift\"; sourceTree = \"<group>\"; };\n\t\t703B090126BD9652005A112F /* ParseAnalytics+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseAnalytics+async.swift\"; sourceTree = \"<group>\"; };\n\t\t703B090626BD9764005A112F /* ParseCloudable+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseCloudable+async.swift\"; sourceTree = \"<group>\"; };\n\t\t703B090B26BD984D005A112F /* ParseConfig+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseConfig+async.swift\"; sourceTree = \"<group>\"; };\n\t\t703B091026BD992E005A112F /* ParseOperation+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseOperation+async.swift\"; sourceTree = \"<group>\"; };\n\t\t703B091526BD99BC005A112F /* ParseLiveQuery+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseLiveQuery+async.swift\"; sourceTree = \"<group>\"; };\n\t\t703B091A26BDE774005A112F /* ParseObjectAsyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseObjectAsyncTests.swift; sourceTree = \"<group>\"; };\n\t\t703B092226BDFAB2005A112F /* ParseUserAsyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseUserAsyncTests.swift; sourceTree = \"<group>\"; };\n\t\t703B092626BE0719005A112F /* ParseInstallationAsyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseInstallationAsyncTests.swift; sourceTree = \"<group>\"; };\n\t\t703B092A26BF290B005A112F /* ParseAuthentication+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseAuthentication+async.swift\"; sourceTree = \"<group>\"; };\n\t\t703B092F26BF42C2005A112F /* ParseAnonymous+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseAnonymous+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t703B093426BF43D9005A112F /* ParseAnonymous+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseAnonymous+async.swift\"; sourceTree = \"<group>\"; };\n\t\t703B093926BF4799005A112F /* ParseApple+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseApple+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t703B093E26BF47AC005A112F /* ParseApple+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseApple+async.swift\"; sourceTree = \"<group>\"; };\n\t\t703B094326BF47C0005A112F /* ParseLDAP+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseLDAP+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t703B094826BF47D0005A112F /* ParseLDAP+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseLDAP+async.swift\"; sourceTree = \"<group>\"; };\n\t\t703B094D26BF47E3005A112F /* ParseTwitter+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseTwitter+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t703B095226BF47FD005A112F /* ParseTwitter+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseTwitter+async.swift\"; sourceTree = \"<group>\"; };\n\t\t703B095726BF480D005A112F /* ParseFacebook+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseFacebook+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t703B095C26BF481F005A112F /* ParseFacebook+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseFacebook+async.swift\"; sourceTree = \"<group>\"; };\n\t\t7044C17425C4ECFF0011F6E7 /* ParseCloudable+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseCloudable+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t7044C18225C4EFC10011F6E7 /* ParseConfig+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseConfig+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t7044C19025C4F5B60011F6E7 /* ParseFile+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseFile+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t7044C19E25C4FA870011F6E7 /* ParseOperation+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseOperation+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t7044C1AC25C4FC080011F6E7 /* Query+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"Query+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t7044C1BA25C52E410011F6E7 /* ParseInstallationCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseInstallationCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t7044C1C725C5B2B10011F6E7 /* ParseAuthentication+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseAuthentication+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t7044C1DE25C5C70D0011F6E7 /* ParseObjectCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseObjectCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t7044C1EB25C5CC930011F6E7 /* ParseOperationCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseOperationCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t7044C1F825C5CFAB0011F6E7 /* ParseFileCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseFileCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t7044C20525C5D6780011F6E7 /* ParseQueryCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseQueryCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t7044C21225C5DE490011F6E7 /* ParseCloudableCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseCloudableCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t7044C21F25C5E0160011F6E7 /* ParseConfigCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseConfigCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t7044C22C25C5E4E90011F6E7 /* ParseAnonymousCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAnonymousCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t7044C24225C5EA360011F6E7 /* ParseAppleCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAppleCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t7045769226BD8F8100F86F71 /* ParseInstallation+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseInstallation+async.swift\"; sourceTree = \"<group>\"; };\n\t\t7045769726BD917500F86F71 /* Query+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"Query+async.swift\"; sourceTree = \"<group>\"; };\n\t\t7045769C26BD934000F86F71 /* ParseFile+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseFile+async.swift\"; sourceTree = \"<group>\"; };\n\t\t704C886B28BE69A8008E6B01 /* ParseConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseConfiguration.swift; sourceTree = \"<group>\"; };\n\t\t704E781628CFD8A00075F952 /* ParseFileTransferable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseFileTransferable.swift; sourceTree = \"<group>\"; };\n\t\t704E781B28CFFAF80075F952 /* ParseFileDefaultTransfer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseFileDefaultTransfer.swift; sourceTree = \"<group>\"; };\n\t\t704E782028D0D73E0075F952 /* ParseFileTransferableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseFileTransferableTests.swift; sourceTree = \"<group>\"; };\n\t\t705025982842FD3B008D6624 /* ParseCLPTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseCLPTests.swift; sourceTree = \"<group>\"; };\n\t\t7050259C2843F0CF008D6624 /* ParseSchemaAsyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseSchemaAsyncTests.swift; sourceTree = \"<group>\"; };\n\t\t705025A02843F0E7008D6624 /* ParseSchemaCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseSchemaCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t705025A4284407C4008D6624 /* ParseSchemaTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseSchemaTests.swift; sourceTree = \"<group>\"; };\n\t\t705025A828441C96008D6624 /* ParseFieldOptions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseFieldOptions.swift; sourceTree = \"<group>\"; };\n\t\t705025AD28456106008D6624 /* ParsePushStatusable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePushStatusable.swift; sourceTree = \"<group>\"; };\n\t\t705025B22845C302008D6624 /* ParsePushStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePushStatus.swift; sourceTree = \"<group>\"; };\n\t\t705025BC284C610C008D6624 /* ParsePush.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePush.swift; sourceTree = \"<group>\"; };\n\t\t705025C1284C7841008D6624 /* ParsePush+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParsePush+async.swift\"; sourceTree = \"<group>\"; };\n\t\t705025C6284C7883008D6624 /* ParsePush+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParsePush+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t705025CB284CE4C2008D6624 /* ParsePushPayloadable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePushPayloadable.swift; sourceTree = \"<group>\"; };\n\t\t705025D0284CFCDE008D6624 /* ParsePushAppleAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePushAppleAlert.swift; sourceTree = \"<group>\"; };\n\t\t705025D5284D0C1D008D6624 /* ParsePushPayloadApple.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePushPayloadApple.swift; sourceTree = \"<group>\"; };\n\t\t705025DA284D0D56008D6624 /* ParsePushAppleSound.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePushAppleSound.swift; sourceTree = \"<group>\"; };\n\t\t705025DF2851006F008D6624 /* ParsePushPayloadFirebase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePushPayloadFirebase.swift; sourceTree = \"<group>\"; };\n\t\t705025E528514F36008D6624 /* ParsePushPayloadAny.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePushPayloadAny.swift; sourceTree = \"<group>\"; };\n\t\t705025EA285153BC008D6624 /* ParsePushApplePayloadable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePushApplePayloadable.swift; sourceTree = \"<group>\"; };\n\t\t705025EF2851542D008D6624 /* ParsePushFirebasePayloadable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePushFirebasePayloadable.swift; sourceTree = \"<group>\"; };\n\t\t70510AAB259EE25E00FEA700 /* LiveQuerySocket.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveQuerySocket.swift; sourceTree = \"<group>\"; };\n\t\t70572670259033A700F0ADD5 /* ParseFileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseFileManager.swift; sourceTree = \"<group>\"; };\n\t\t705727882593FF8000F0ADD5 /* ParseFileTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseFileTests.swift; sourceTree = \"<group>\"; };\n\t\t705A99F8259807F900B3547F /* ParseFileManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseFileManagerTests.swift; sourceTree = \"<group>\"; };\n\t\t705A9A2E25991C1400B3547F /* Fileable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Fileable.swift; sourceTree = \"<group>\"; };\n\t\t705D950725BE4C08003EF6F8 /* SubscriptionCallback.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionCallback.swift; sourceTree = \"<group>\"; };\n\t\t7064369A273313D5007C6461 /* LiveQueryConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveQueryConstants.swift; sourceTree = \"<group>\"; };\n\t\t706436A327341F6E007C6461 /* Encodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Encodable.swift; sourceTree = \"<group>\"; };\n\t\t706436A827341FD0007C6461 /* Date.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Date.swift; sourceTree = \"<group>\"; };\n\t\t70647E9B259E3A9A004C1004 /* ParseEncodable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseEncodable.swift; sourceTree = \"<group>\"; };\n\t\t70732C592606CCAD000CAB81 /* ParseObjectCustomObjectIdTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseObjectCustomObjectIdTests.swift; sourceTree = \"<group>\"; };\n\t\t707A3BF025B0A4F0000D215C /* ParseAuthentication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAuthentication.swift; sourceTree = \"<group>\"; };\n\t\t707A3C1025B0A8E8000D215C /* ParseAnonymous.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAnonymous.swift; sourceTree = \"<group>\"; };\n\t\t707A3C1F25B14BCF000D215C /* ParseApple.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseApple.swift; sourceTree = \"<group>\"; };\n\t\t7085DD9326CBF3A70033B977 /* Documentation.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = Documentation.docc; sourceTree = \"<group>\"; };\n\t\t7085DDA226CC8A470033B977 /* ParseHealth+combine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = \"ParseHealth+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t7085DDB226D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAuthenticationCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t708CADCE2872263D0066C279 /* ParseKeychainAccessGroupTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseKeychainAccessGroupTests.swift; sourceTree = \"<group>\"; };\n\t\t708D035125215F9B00646C70 /* Deletable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Deletable.swift; sourceTree = \"<group>\"; };\n\t\t708EF0BC28D5F4140052EF35 /* API+Command+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"API+Command+async.swift\"; sourceTree = \"<group>\"; };\n\t\t708EF0C128D5FDF10052EF35 /* API+NonParseBodyCommand+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"API+NonParseBodyCommand+async.swift\"; sourceTree = \"<group>\"; };\n\t\t709A147C283949D100BF85E5 /* ParseSchema.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseSchema.swift; sourceTree = \"<group>\"; };\n\t\t709A148128395ED100BF85E5 /* ParseSchema+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseSchema+async.swift\"; sourceTree = \"<group>\"; };\n\t\t709A148628396B1C00BF85E5 /* ParseField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseField.swift; sourceTree = \"<group>\"; };\n\t\t709A148B2839A1DB00BF85E5 /* Operation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Operation.swift; sourceTree = \"<group>\"; };\n\t\t709A149F2839CABD00BF85E5 /* ParseCLP.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseCLP.swift; sourceTree = \"<group>\"; };\n\t\t709A14A4283AAF4C00BF85E5 /* ParseSchema+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseSchema+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t709B40C0268F999000ED2EAC /* IOS13Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IOS13Tests.swift; sourceTree = \"<group>\"; };\n\t\t709B98302556EC7400507778 /* ParseSwiftTeststvOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ParseSwiftTeststvOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t709B98342556EC7400507778 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t70A2D81E25B36A7D001BEB7D /* ParseAuthenticationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAuthenticationTests.swift; sourceTree = \"<group>\"; };\n\t\t70A2D86A25B3ADB6001BEB7D /* ParseAnonymousTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAnonymousTests.swift; sourceTree = \"<group>\"; };\n\t\t70A98D812794AB3C009B58F2 /* ParseQueryScorable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseQueryScorable.swift; sourceTree = \"<group>\"; };\n\t\t70B4E0BB2762F1D5004C9757 /* QueryConstraint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryConstraint.swift; sourceTree = \"<group>\"; };\n\t\t70B4E0C02762F313004C9757 /* QueryWhere.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryWhere.swift; sourceTree = \"<group>\"; };\n\t\t70BC0B32251903D1001556DB /* ParseGeoPointTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseGeoPointTests.swift; sourceTree = \"<group>\"; };\n\t\t70BC988F252A5B5C00FF3074 /* Objectable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Objectable.swift; sourceTree = \"<group>\"; };\n\t\t70BDA2B2250536FF00FC2237 /* ParseInstallation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseInstallation.swift; sourceTree = \"<group>\"; };\n\t\t70C048C02880D7E500401689 /* Dictionary.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dictionary.swift; sourceTree = \"<group>\"; };\n\t\t70C167AE27304EE4009F4E30 /* Pointer+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"Pointer+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t70C167B327304F09009F4E30 /* Pointer+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"Pointer+async.swift\"; sourceTree = \"<group>\"; };\n\t\t70C167B827305101009F4E30 /* ParsePointerAsyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePointerAsyncTests.swift; sourceTree = \"<group>\"; };\n\t\t70C5502125B3D8F700B5DBC2 /* ParseAppleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAppleTests.swift; sourceTree = \"<group>\"; };\n\t\t70C5503725B406B800B5DBC2 /* ParseSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseSession.swift; sourceTree = \"<group>\"; };\n\t\t70C5504525B40D5200B5DBC2 /* ParseSessionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseSessionTests.swift; sourceTree = \"<group>\"; };\n\t\t70C5507625B49D3A00B5DBC2 /* ParseRole.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseRole.swift; sourceTree = \"<group>\"; };\n\t\t70C5508425B4A68700B5DBC2 /* ParseOperationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseOperationTests.swift; sourceTree = \"<group>\"; };\n\t\t70C5509125B4A99100B5DBC2 /* AddRelation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddRelation.swift; sourceTree = \"<group>\"; };\n\t\t70C5509F25B4A9F600B5DBC2 /* RemoveRelation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoveRelation.swift; sourceTree = \"<group>\"; };\n\t\t70C5655825AA147B00BDD57F /* ParseLiveQueryConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseLiveQueryConstants.swift; sourceTree = \"<group>\"; };\n\t\t70C7DC1D24D20E530050419B /* ParseUserTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseUserTests.swift; sourceTree = \"<group>\"; };\n\t\t70C7DC1F24D20F180050419B /* ParseQueryTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseQueryTests.swift; sourceTree = \"<group>\"; };\n\t\t70C7DC2024D20F190050419B /* ParseObjectBatchTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseObjectBatchTests.swift; sourceTree = \"<group>\"; };\n\t\t70CE0A9328590A0A00DAEA86 /* ParseHookResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookResponse.swift; sourceTree = \"<group>\"; };\n\t\t70CE0A9D28592A2B00DAEA86 /* ParseCloudUser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseCloudUser.swift; sourceTree = \"<group>\"; };\n\t\t70CE0AA228595E5E00DAEA86 /* ParseHookRequestable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookRequestable.swift; sourceTree = \"<group>\"; };\n\t\t70CE0AA728595FCE00DAEA86 /* ParseHookRequestable+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseHookRequestable+async.swift\"; sourceTree = \"<group>\"; };\n\t\t70CE0AAC28595FDE00DAEA86 /* ParseHookRequestable+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseHookRequestable+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t70CE0AB1285963A300DAEA86 /* ParseHookTriggerRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookTriggerRequest.swift; sourceTree = \"<group>\"; };\n\t\t70CE0AB6285A83B100DAEA86 /* ParseHookable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookable.swift; sourceTree = \"<group>\"; };\n\t\t70CE0ABB285F8FF900DAEA86 /* ParseTypeable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseTypeable.swift; sourceTree = \"<group>\"; };\n\t\t70CE0AC0285FD59B00DAEA86 /* ParseHookFunctionable+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseHookFunctionable+async.swift\"; sourceTree = \"<group>\"; };\n\t\t70CE0AC5285FD5A800DAEA86 /* ParseHookFunctionable+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseHookFunctionable+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t70CE0ACA285FD5CB00DAEA86 /* ParseHookTriggerable+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseHookTriggerable+async.swift\"; sourceTree = \"<group>\"; };\n\t\t70CE0ACF285FD5D700DAEA86 /* ParseHookTriggerable+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseHookTriggerable+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t70CE1D882545BF730018D572 /* ParsePointerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePointerTests.swift; sourceTree = \"<group>\"; };\n\t\t70D1BD8625B8C37200A42E7C /* ParseRelationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseRelationTests.swift; sourceTree = \"<group>\"; };\n\t\t70D1BDA525BA192700A42E7C /* CHANGELOG.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = \"<group>\"; };\n\t\t70D1BDA625BA193500A42E7C /* CONTRIBUTING.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CONTRIBUTING.md; sourceTree = \"<group>\"; };\n\t\t70D1BDB925BB17A600A42E7C /* ParseConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseConfig.swift; sourceTree = \"<group>\"; };\n\t\t70D1BE0625BB2BF400A42E7C /* ParseConfigTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseConfigTests.swift; sourceTree = \"<group>\"; };\n\t\t70D1BE7225BB43EB00A42E7C /* BaseConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseConfig.swift; sourceTree = \"<group>\"; };\n\t\t70D41D6628B0235100613510 /* MigrateObjCSDKTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateObjCSDKTests.swift; sourceTree = \"<group>\"; };\n\t\t70D41D6A28B294C100613510 /* MigrateObjCSDKCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrateObjCSDKCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t70D41D7F28B520E200613510 /* ParseKeychainAccessGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseKeychainAccessGroup.swift; sourceTree = \"<group>\"; };\n\t\t70DFEA892618E77800F8EB4B /* InitializeSDKTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InitializeSDKTests.swift; sourceTree = \"<group>\"; };\n\t\t70E09E1B262F0634002DD451 /* ParsePointerCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePointerCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t70E6B015286120E00043EC4A /* ParseHookFunctionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookFunctionTests.swift; sourceTree = \"<group>\"; };\n\t\t70E6B01928612A820043EC4A /* ParseHookFunctionCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookFunctionCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t70E6B01D28612FF00043EC4A /* ParseHookTriggerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookTriggerTests.swift; sourceTree = \"<group>\"; };\n\t\t70E6B021286131720043EC4A /* ParseHookTriggerCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookTriggerCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t70E6B025286132BC0043EC4A /* ParseHookFunctionRequestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookFunctionRequestTests.swift; sourceTree = \"<group>\"; };\n\t\t70E6B02928614C5F0043EC4A /* ParseHookFunctionRequestCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookFunctionRequestCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t70E6B02D28614E480043EC4A /* ParseHookTriggerRequestTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookTriggerRequestTests.swift; sourceTree = \"<group>\"; };\n\t\t70E6B031286152550043EC4A /* ParseHookTriggerRequestCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookTriggerRequestCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t70E6B035286289FF0043EC4A /* ParseHookResponseTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookResponseTests.swift; sourceTree = \"<group>\"; };\n\t\t70F03A222780BDE200E5AFB4 /* ParseGoogle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseGoogle.swift; sourceTree = \"<group>\"; };\n\t\t70F03A242780BDF700E5AFB4 /* ParseGoogle+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseGoogle+async.swift\"; sourceTree = \"<group>\"; };\n\t\t70F03A262780BE0F00E5AFB4 /* ParseGoogle+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseGoogle+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t70F03A332780CA4300E5AFB4 /* ParseGitHub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseGitHub.swift; sourceTree = \"<group>\"; };\n\t\t70F03A382780CA6F00E5AFB4 /* ParseGitHub+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseGitHub+async.swift\"; sourceTree = \"<group>\"; };\n\t\t70F03A3D2780CA8F00E5AFB4 /* ParseGitHub+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseGitHub+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t70F03A422780D21600E5AFB4 /* ParseLinkedIn.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseLinkedIn.swift; sourceTree = \"<group>\"; };\n\t\t70F03A472780D27700E5AFB4 /* ParseLinkedIn+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseLinkedIn+async.swift\"; sourceTree = \"<group>\"; };\n\t\t70F03A4C2780D28A00E5AFB4 /* ParseLinkedIn+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseLinkedIn+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t70F03A512780DA9200E5AFB4 /* ParseGoogleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseGoogleTests.swift; sourceTree = \"<group>\"; };\n\t\t70F03A552780E8E300E5AFB4 /* ParseGoogleCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseGoogleCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t70F03A592780EAB000E5AFB4 /* ParseGitHubCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseGitHubCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t70F03A5D2780EAC700E5AFB4 /* ParseGitHubTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseGitHubTests.swift; sourceTree = \"<group>\"; };\n\t\t70F03A612780EADD00E5AFB4 /* ParseLinkedInCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseLinkedInCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t70F03A652780EAFA00E5AFB4 /* ParseLinkedInTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseLinkedInTests.swift; sourceTree = \"<group>\"; };\n\t\t70F2E23E254F246000B2EA5C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t70F2E250254F247000B2EA5C /* ParseSwiftTestsmacOS.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ParseSwiftTestsmacOS.xctest; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t70F2E254254F247000B2EA5C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t70F79A182639CE6F00731C46 /* ParseHealth.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHealth.swift; sourceTree = \"<group>\"; };\n\t\t70F79A4F2639DE6900731C46 /* ParseHealthTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHealthTests.swift; sourceTree = \"<group>\"; };\n\t\t70F79A662639DE9700731C46 /* ParseHealthCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHealthCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t7C4C092A285E746800F202C6 /* ParseInstagram.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseInstagram.swift; sourceTree = \"<group>\"; };\n\t\t7C4C092F285E986F00F202C6 /* ParseInstagram+async.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = \"ParseInstagram+async.swift\"; sourceTree = \"<group>\"; };\n\t\t7C4C0939285E9A3700F202C6 /* ParseInstagram+combine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = \"ParseInstagram+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t7C4C093E285EA3A000F202C6 /* ParseInstagramTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseInstagramTests.swift; sourceTree = \"<group>\"; };\n\t\t7C4C0942285EA56E00F202C6 /* ParseInstagramCombineTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseInstagramCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t7C4C0946285EA60E00F202C6 /* ParseInstagramAsyncTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseInstagramAsyncTests.swift; sourceTree = \"<group>\"; };\n\t\t7C55F9E62860CD6B002A352D /* ParseSpotify.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseSpotify.swift; sourceTree = \"<group>\"; };\n\t\t7C55F9EB2860CEA6002A352D /* ParseSpotify+async.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = \"ParseSpotify+async.swift\"; sourceTree = \"<group>\"; };\n\t\t7C55F9F02860CEEF002A352D /* ParseSpotify+combine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = \"ParseSpotify+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t7C995D242861F8330077805A /* ParseSpotifyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseSpotifyTests.swift; sourceTree = \"<group>\"; };\n\t\t7C995D282861FA0B0077805A /* ParseSpotifyAsyncTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseSpotifyAsyncTests.swift; sourceTree = \"<group>\"; };\n\t\t7C995D2C2861FAE40077805A /* ParseSpotifyCombineTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseSpotifyCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t7FFF552B2217E729007C3B4E /* AnyEncodableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyEncodableTests.swift; sourceTree = \"<group>\"; };\n\t\t7FFF552C2217E729007C3B4E /* AnyCodableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyCodableTests.swift; sourceTree = \"<group>\"; };\n\t\t7FFF552D2217E729007C3B4E /* AnyDecodableTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyDecodableTests.swift; sourceTree = \"<group>\"; };\n\t\t89899CC02603CE2A002E2043 /* ParseTwitter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseTwitter.swift; sourceTree = \"<group>\"; };\n\t\t89899CCE2603CE3A002E2043 /* ParseFacebook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseFacebook.swift; sourceTree = \"<group>\"; };\n\t\t89899CDC2603CE73002E2043 /* ParseTwitterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseTwitterTests.swift; sourceTree = \"<group>\"; };\n\t\t89899CF32603CE9D002E2043 /* ParseFacebookTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseFacebookTests.swift; sourceTree = \"<group>\"; };\n\t\t89899D9E26045998002E2043 /* ParseTwitterCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseTwitterCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t89899DB426045DC4002E2043 /* ParseFacebookCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseFacebookCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t9116F66E26A35D600082F6D6 /* URLCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLCache.swift; sourceTree = \"<group>\"; };\n\t\t911DB12B24C3F7720027F3C7 /* MockURLResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockURLResponse.swift; sourceTree = \"<group>\"; };\n\t\t911DB12D24C4837E0027F3C7 /* APICommandTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APICommandTests.swift; sourceTree = \"<group>\"; };\n\t\t911DB13224C494390027F3C7 /* MockURLProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockURLProtocol.swift; sourceTree = \"<group>\"; };\n\t\t911DB13524C4FC100027F3C7 /* ParseObjectTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseObjectTests.swift; sourceTree = \"<group>\"; };\n\t\t91285B122698DBF20051B544 /* ParseBytes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseBytes.swift; sourceTree = \"<group>\"; };\n\t\t91285B172698E66D0051B544 /* ParseBytesTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseBytesTests.swift; sourceTree = \"<group>\"; };\n\t\t91285B1B26990D7F0051B544 /* ParsePolygon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePolygon.swift; sourceTree = \"<group>\"; };\n\t\t91285B2026991EE80051B544 /* ParsePolygonTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParsePolygonTests.swift; sourceTree = \"<group>\"; };\n\t\t912C9BCB24D3005D009947C3 /* ParseSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ParseSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t912C9BCD24D3005D009947C3 /* ParseSwift_watchOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ParseSwift_watchOS.h; sourceTree = \"<group>\"; };\n\t\t912C9BCE24D3005D009947C3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t912C9BD824D3011F009947C3 /* ParseSwift.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ParseSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; };\n\t\t912C9BDA24D3011F009947C3 /* ParseSwift_tvOS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ParseSwift_tvOS.h; sourceTree = \"<group>\"; };\n\t\t912C9BDB24D3011F009947C3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = \"<group>\"; };\n\t\t9158916A256A07DD0024BE9A /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = \"<group>\"; };\n\t\t916786E1259B7DDA00BB5B4E /* ParseCloudable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseCloudable.swift; sourceTree = \"<group>\"; };\n\t\t916786EF259BC59600BB5B4E /* ParseCloudableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseCloudableTests.swift; sourceTree = \"<group>\"; };\n\t\t91679D63268E596300F71809 /* ParseVersion.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseVersion.swift; sourceTree = \"<group>\"; };\n\t\t91679D68268F25EA00F71809 /* ParseVersionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseVersionTests.swift; sourceTree = \"<group>\"; };\n\t\t917BA4252703DB4600F8D747 /* ParseQueryAsyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseQueryAsyncTests.swift; sourceTree = \"<group>\"; };\n\t\t917BA4292703E03F00F8D747 /* ParseAnalyticsAsyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAnalyticsAsyncTests.swift; sourceTree = \"<group>\"; };\n\t\t917BA42D2703E20E00F8D747 /* ParseCloudableAsyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseCloudableAsyncTests.swift; sourceTree = \"<group>\"; };\n\t\t917BA4312703E36800F8D747 /* ParseConfigAsyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseConfigAsyncTests.swift; sourceTree = \"<group>\"; };\n\t\t917BA4352703E4CB00F8D747 /* ParseFileAsyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseFileAsyncTests.swift; sourceTree = \"<group>\"; };\n\t\t917BA4392703E6D800F8D747 /* ParseHealthAsyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHealthAsyncTests.swift; sourceTree = \"<group>\"; };\n\t\t917BA43D2703E84000F8D747 /* ParseOperationAsyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseOperationAsyncTests.swift; sourceTree = \"<group>\"; };\n\t\t917BA4412703EAC700F8D747 /* ParseLiveQueryAsyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseLiveQueryAsyncTests.swift; sourceTree = \"<group>\"; };\n\t\t917BA4452703EEA700F8D747 /* ParseAnonymousAsyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAnonymousAsyncTests.swift; sourceTree = \"<group>\"; };\n\t\t917BA4492703F10400F8D747 /* ParseAppleAsyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAppleAsyncTests.swift; sourceTree = \"<group>\"; };\n\t\t917BA44D2703F2B400F8D747 /* ParseFacebookAsyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseFacebookAsyncTests.swift; sourceTree = \"<group>\"; };\n\t\t917BA4512703F55700F8D747 /* ParseTwitterAsyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseTwitterAsyncTests.swift; sourceTree = \"<group>\"; };\n\t\t917BA4552703F75E00F8D747 /* ParseLDAPAsyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseLDAPAsyncTests.swift; sourceTree = \"<group>\"; };\n\t\t917BA4592703FD2200F8D747 /* ParseAuthenticationAsyncTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAuthenticationAsyncTests.swift; sourceTree = \"<group>\"; };\n\t\t918CED582684C74000CFDC83 /* ParseLiveQuery+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"ParseLiveQuery+combine.swift\"; sourceTree = \"<group>\"; };\n\t\t918CED5D268618C600CFDC83 /* ParseLiveQueryCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseLiveQueryCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t9194657724F16E330070296B /* ParseACLTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseACLTests.swift; sourceTree = \"<group>\"; };\n\t\t91B40650267A66ED00B129CD /* ParseErrorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseErrorTests.swift; sourceTree = \"<group>\"; };\n\t\t91B79AC226EE3A4E00073F2C /* API+NonParseBodyCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"API+NonParseBodyCommand.swift\"; sourceTree = \"<group>\"; };\n\t\t91B79AC726EE3C5D00073F2C /* API+BatchCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = \"API+BatchCommand.swift\"; sourceTree = \"<group>\"; };\n\t\t91BB8FC92690AC99005A6BA5 /* QueryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryViewModel.swift; sourceTree = \"<group>\"; };\n\t\t91BB8FCE2690BA70005A6BA5 /* QueryObservable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryObservable.swift; sourceTree = \"<group>\"; };\n\t\t91BB8FD32690D586005A6BA5 /* ParseQueryViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseQueryViewModelTests.swift; sourceTree = \"<group>\"; };\n\t\t91CB9536265966DF0043E5D6 /* ParseAnalyticsCombineTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAnalyticsCombineTests.swift; sourceTree = \"<group>\"; };\n\t\t91F346B8269B766C005727B6 /* CloudViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudViewModel.swift; sourceTree = \"<group>\"; };\n\t\t91F346BD269B77B5005727B6 /* CloudObservable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CloudObservable.swift; sourceTree = \"<group>\"; };\n\t\t91F346C2269B88F7005727B6 /* ParseCloudViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseCloudViewModelTests.swift; sourceTree = \"<group>\"; };\n\t\tF971F4F524DE381A006CB79B /* ParseEncoderExtraTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseEncoderExtraTests.swift; sourceTree = \"<group>\"; };\n\t\tF97B45B424D9C6F200F4A88B /* ParseCoding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseCoding.swift; sourceTree = \"<group>\"; };\n\t\tF97B45B524D9C6F200F4A88B /* AnyDecodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyDecodable.swift; sourceTree = \"<group>\"; };\n\t\tF97B45B624D9C6F200F4A88B /* ParseEncoder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseEncoder.swift; sourceTree = \"<group>\"; };\n\t\tF97B45B824D9C6F200F4A88B /* AnyCodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyCodable.swift; sourceTree = \"<group>\"; };\n\t\tF97B45B924D9C6F200F4A88B /* AnyEncodable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnyEncodable.swift; sourceTree = \"<group>\"; };\n\t\tF97B45BB24D9C6F200F4A88B /* Query.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Query.swift; sourceTree = \"<group>\"; };\n\t\tF97B45BC24D9C6F200F4A88B /* ParseGeoPoint.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseGeoPoint.swift; sourceTree = \"<group>\"; };\n\t\tF97B45BD24D9C6F200F4A88B /* BaseParseUser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseParseUser.swift; sourceTree = \"<group>\"; };\n\t\tF97B45BE24D9C6F200F4A88B /* Pointer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Pointer.swift; sourceTree = \"<group>\"; };\n\t\tF97B45BF24D9C6F200F4A88B /* ParseError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseError.swift; sourceTree = \"<group>\"; };\n\t\tF97B45C024D9C6F200F4A88B /* ParseACL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseACL.swift; sourceTree = \"<group>\"; };\n\t\tF97B45C124D9C6F200F4A88B /* ParseFile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseFile.swift; sourceTree = \"<group>\"; };\n\t\tF97B45C224D9C6F200F4A88B /* NoBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoBody.swift; sourceTree = \"<group>\"; };\n\t\tF97B45C424D9C6F200F4A88B /* ParseUser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseUser.swift; sourceTree = \"<group>\"; };\n\t\tF97B45C524D9C6F200F4A88B /* Fetchable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Fetchable.swift; sourceTree = \"<group>\"; };\n\t\tF97B45C624D9C6F200F4A88B /* ParseObject.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseObject.swift; sourceTree = \"<group>\"; };\n\t\tF97B45C724D9C6F200F4A88B /* Savable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Savable.swift; sourceTree = \"<group>\"; };\n\t\tF97B45C824D9C6F200F4A88B /* Queryable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Queryable.swift; sourceTree = \"<group>\"; };\n\t\tF97B45CC24D9C6F200F4A88B /* ParseStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseStorage.swift; sourceTree = \"<group>\"; };\n\t\tF97B45CD24D9C6F200F4A88B /* ParseKeyValueStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseKeyValueStore.swift; sourceTree = \"<group>\"; };\n\t\tF97B462624D9C72700F4A88B /* API.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = API.swift; sourceTree = \"<group>\"; };\n\t\tF97B462B24D9C74400F4A88B /* BatchUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BatchUtils.swift; sourceTree = \"<group>\"; };\n\t\tF97B462C24D9C74400F4A88B /* URLSession.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLSession.swift; sourceTree = \"<group>\"; };\n\t\tF97B462D24D9C74400F4A88B /* Responses.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Responses.swift; sourceTree = \"<group>\"; };\n\t\tF97B462E24D9C74400F4A88B /* API+Command.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = \"API+Command.swift\"; sourceTree = \"<group>\"; };\n\t\tF97B464024D9C78B00F4A88B /* ParseOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseOperation.swift; sourceTree = \"<group>\"; };\n\t\tF97B464124D9C78B00F4A88B /* Delete.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Delete.swift; sourceTree = \"<group>\"; };\n\t\tF97B464224D9C78B00F4A88B /* Add.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Add.swift; sourceTree = \"<group>\"; };\n\t\tF97B464324D9C78B00F4A88B /* AddUnique.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddUnique.swift; sourceTree = \"<group>\"; };\n\t\tF97B464424D9C78B00F4A88B /* Remove.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Remove.swift; sourceTree = \"<group>\"; };\n\t\tF97B464524D9C78B00F4A88B /* Increment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Increment.swift; sourceTree = \"<group>\"; };\n\t\tF97B465E24D9C7B500F4A88B /* KeychainStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainStore.swift; sourceTree = \"<group>\"; };\n\t\tF97B466324D9C88600F4A88B /* SecureStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SecureStorage.swift; sourceTree = \"<group>\"; };\n/* End PBXFileReference section */\n\n/* Begin PBXFrameworksBuildPhase section */\n\t\t4AA807551F794242008CD551 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4AB8B4F01F254AE10070F682 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4AB8B4FA1F254AE10070F682 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4AB8B4FE1F254AE10070F682 /* ParseSwift.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4AFDA70E1F26D9A5002AE4FC /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t7033ECAD25584A83009770F3 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t709B982D2556EC7400507778 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t709B98352556EC7400507778 /* ParseSwift.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t70F2E24D254F247000B2EA5C /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t70F2E255254F247000B2EA5C /* ParseSwift.framework in Frameworks */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t912C9BC824D3005D009947C3 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t912C9BD524D3011F009947C3 /* Frameworks */ = {\n\t\t\tisa = PBXFrameworksBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXFrameworksBuildPhase section */\n\n/* Begin PBXGroup section */\n\t\t4A5EE45F1F49E9E000D3CAE3 /* Sources */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4AB8B4F61F254AE10070F682 /* ParseSwift */,\n\t\t\t);\n\t\t\tpath = Sources;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4A5EE4601F49EA0600D3CAE3 /* Tests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4A1120BF1F49FC3300E32D94 /* LinuxMain.swift */,\n\t\t\t\t4AA8076C1F794C1C008CD551 /* ParseSwiftTests */,\n\t\t\t);\n\t\t\tpath = Tests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4A65114E1F48E3CE005237DF /* ParseSwift-iOS */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4AB8B4F81F254AE10070F682 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = \"ParseSwift-iOS\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4AA807591F794242008CD551 /* TestHost */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4AA8075A1F794242008CD551 /* AppDelegate.swift */,\n\t\t\t\t4AA8075E1F794242008CD551 /* Main.storyboard */,\n\t\t\t\t4AA807611F794242008CD551 /* Assets.xcassets */,\n\t\t\t\t4AA807631F794242008CD551 /* LaunchScreen.storyboard */,\n\t\t\t\t4AA807661F794242008CD551 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = TestHost;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4AA8076C1F794C1C008CD551 /* ParseSwiftTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4AA8076D1F794C1C008CD551 /* Info.plist */,\n\t\t\t\t911DB12D24C4837E0027F3C7 /* APICommandTests.swift */,\n\t\t\t\t7003957525A0EE770052CB31 /* BatchUtilsTests.swift */,\n\t\t\t\t7023800E2747FCCD00EFC443 /* ExtensionsTests.swift */,\n\t\t\t\t70DFEA892618E77800F8EB4B /* InitializeSDKTests.swift */,\n\t\t\t\t709B40C0268F999000ED2EAC /* IOS13Tests.swift */,\n\t\t\t\t4AA8076E1F794C1C008CD551 /* KeychainStoreTests.swift */,\n\t\t\t\t70D41D6A28B294C100613510 /* MigrateObjCSDKCombineTests.swift */,\n\t\t\t\t70D41D6628B0235100613510 /* MigrateObjCSDKTests.swift */,\n\t\t\t\t9194657724F16E330070296B /* ParseACLTests.swift */,\n\t\t\t\t917BA4292703E03F00F8D747 /* ParseAnalyticsAsyncTests.swift */,\n\t\t\t\t91CB9536265966DF0043E5D6 /* ParseAnalyticsCombineTests.swift */,\n\t\t\t\t70170A4D2656EBA50070C905 /* ParseAnalyticsTests.swift */,\n\t\t\t\t917BA4452703EEA700F8D747 /* ParseAnonymousAsyncTests.swift */,\n\t\t\t\t7044C22C25C5E4E90011F6E7 /* ParseAnonymousCombineTests.swift */,\n\t\t\t\t70A2D86A25B3ADB6001BEB7D /* ParseAnonymousTests.swift */,\n\t\t\t\t917BA4492703F10400F8D747 /* ParseAppleAsyncTests.swift */,\n\t\t\t\t7044C24225C5EA360011F6E7 /* ParseAppleCombineTests.swift */,\n\t\t\t\t70C5502125B3D8F700B5DBC2 /* ParseAppleTests.swift */,\n\t\t\t\t917BA4592703FD2200F8D747 /* ParseAuthenticationAsyncTests.swift */,\n\t\t\t\t7085DDB226D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift */,\n\t\t\t\t70A2D81E25B36A7D001BEB7D /* ParseAuthenticationTests.swift */,\n\t\t\t\t91285B172698E66D0051B544 /* ParseBytesTests.swift */,\n\t\t\t\t917BA42D2703E20E00F8D747 /* ParseCloudableAsyncTests.swift */,\n\t\t\t\t7044C21225C5DE490011F6E7 /* ParseCloudableCombineTests.swift */,\n\t\t\t\t916786EF259BC59600BB5B4E /* ParseCloudableTests.swift */,\n\t\t\t\t91F346C2269B88F7005727B6 /* ParseCloudViewModelTests.swift */,\n\t\t\t\t705025982842FD3B008D6624 /* ParseCLPTests.swift */,\n\t\t\t\t917BA4312703E36800F8D747 /* ParseConfigAsyncTests.swift */,\n\t\t\t\t7044C21F25C5E0160011F6E7 /* ParseConfigCombineTests.swift */,\n\t\t\t\t70D1BE0625BB2BF400A42E7C /* ParseConfigTests.swift */,\n\t\t\t\t91B40650267A66ED00B129CD /* ParseErrorTests.swift */,\n\t\t\t\t917BA44D2703F2B400F8D747 /* ParseFacebookAsyncTests.swift */,\n\t\t\t\t89899DB426045DC4002E2043 /* ParseFacebookCombineTests.swift */,\n\t\t\t\t89899CF32603CE9D002E2043 /* ParseFacebookTests.swift */,\n\t\t\t\t917BA4352703E4CB00F8D747 /* ParseFileAsyncTests.swift */,\n\t\t\t\t7044C1F825C5CFAB0011F6E7 /* ParseFileCombineTests.swift */,\n\t\t\t\t705A99F8259807F900B3547F /* ParseFileManagerTests.swift */,\n\t\t\t\t705727882593FF8000F0ADD5 /* ParseFileTests.swift */,\n\t\t\t\t704E782028D0D73E0075F952 /* ParseFileTransferableTests.swift */,\n\t\t\t\t70BC0B32251903D1001556DB /* ParseGeoPointTests.swift */,\n\t\t\t\t70F03A592780EAB000E5AFB4 /* ParseGitHubCombineTests.swift */,\n\t\t\t\t70F03A5D2780EAC700E5AFB4 /* ParseGitHubTests.swift */,\n\t\t\t\t70F03A552780E8E300E5AFB4 /* ParseGoogleCombineTests.swift */,\n\t\t\t\t70F03A512780DA9200E5AFB4 /* ParseGoogleTests.swift */,\n\t\t\t\t917BA4392703E6D800F8D747 /* ParseHealthAsyncTests.swift */,\n\t\t\t\t70F79A662639DE9700731C46 /* ParseHealthCombineTests.swift */,\n\t\t\t\t70F79A4F2639DE6900731C46 /* ParseHealthTests.swift */,\n\t\t\t\t70E6B01928612A820043EC4A /* ParseHookFunctionCombineTests.swift */,\n\t\t\t\t70E6B02928614C5F0043EC4A /* ParseHookFunctionRequestCombineTests.swift */,\n\t\t\t\t70E6B025286132BC0043EC4A /* ParseHookFunctionRequestTests.swift */,\n\t\t\t\t70E6B015286120E00043EC4A /* ParseHookFunctionTests.swift */,\n\t\t\t\t70E6B035286289FF0043EC4A /* ParseHookResponseTests.swift */,\n\t\t\t\t70E6B021286131720043EC4A /* ParseHookTriggerCombineTests.swift */,\n\t\t\t\t70E6B031286152550043EC4A /* ParseHookTriggerRequestCombineTests.swift */,\n\t\t\t\t70E6B02D28614E480043EC4A /* ParseHookTriggerRequestTests.swift */,\n\t\t\t\t70E6B01D28612FF00043EC4A /* ParseHookTriggerTests.swift */,\n\t\t\t\t7C4C0946285EA60E00F202C6 /* ParseInstagramAsyncTests.swift */,\n\t\t\t\t7C4C0942285EA56E00F202C6 /* ParseInstagramCombineTests.swift */,\n\t\t\t\t7C4C093E285EA3A000F202C6 /* ParseInstagramTests.swift */,\n\t\t\t\t703B092626BE0719005A112F /* ParseInstallationAsyncTests.swift */,\n\t\t\t\t7044C1BA25C52E410011F6E7 /* ParseInstallationCombineTests.swift */,\n\t\t\t\t70110D5B2506ED0E0091CC1D /* ParseInstallationTests.swift */,\n\t\t\t\t708CADCE2872263D0066C279 /* ParseKeychainAccessGroupTests.swift */,\n\t\t\t\t917BA4552703F75E00F8D747 /* ParseLDAPAsyncTests.swift */,\n\t\t\t\t70386A5B25D9A4010048EC1B /* ParseLDAPCombineTests.swift */,\n\t\t\t\t70386A4525D99C8B0048EC1B /* ParseLDAPTests.swift */,\n\t\t\t\t70F03A612780EADD00E5AFB4 /* ParseLinkedInCombineTests.swift */,\n\t\t\t\t70F03A652780EAFA00E5AFB4 /* ParseLinkedInTests.swift */,\n\t\t\t\t917BA4412703EAC700F8D747 /* ParseLiveQueryAsyncTests.swift */,\n\t\t\t\t918CED5D268618C600CFDC83 /* ParseLiveQueryCombineTests.swift */,\n\t\t\t\t7003963A25A288100052CB31 /* ParseLiveQueryTests.swift */,\n\t\t\t\t703B091A26BDE774005A112F /* ParseObjectAsyncTests.swift */,\n\t\t\t\t70C7DC2024D20F190050419B /* ParseObjectBatchTests.swift */,\n\t\t\t\t7044C1DE25C5C70D0011F6E7 /* ParseObjectCombineTests.swift */,\n\t\t\t\t70732C592606CCAD000CAB81 /* ParseObjectCustomObjectIdTests.swift */,\n\t\t\t\t911DB13524C4FC100027F3C7 /* ParseObjectTests.swift */,\n\t\t\t\t917BA43D2703E84000F8D747 /* ParseOperationAsyncTests.swift */,\n\t\t\t\t7044C1EB25C5CC930011F6E7 /* ParseOperationCombineTests.swift */,\n\t\t\t\t70C5508425B4A68700B5DBC2 /* ParseOperationTests.swift */,\n\t\t\t\t70C167B827305101009F4E30 /* ParsePointerAsyncTests.swift */,\n\t\t\t\t70E09E1B262F0634002DD451 /* ParsePointerCombineTests.swift */,\n\t\t\t\t70CE1D882545BF730018D572 /* ParsePointerTests.swift */,\n\t\t\t\t91285B2026991EE80051B544 /* ParsePolygonTests.swift */,\n\t\t\t\t70212D1C2855259100386163 /* ParsePushAsyncTests.swift */,\n\t\t\t\t70212D21285525A600386163 /* ParsePushCombineTests.swift */,\n\t\t\t\t70385E67285640A30084D306 /* ParsePushPayloadAnyTests.swift */,\n\t\t\t\t70212D262855260F00386163 /* ParsePushPayloadAppleTests.swift */,\n\t\t\t\t70385E6328563FD10084D306 /* ParsePushPayloadFirebaseTests.swift */,\n\t\t\t\t70212D172855256F00386163 /* ParsePushTests.swift */,\n\t\t\t\t917BA4252703DB4600F8D747 /* ParseQueryAsyncTests.swift */,\n\t\t\t\t700AFE02289C3508006C1CD9 /* ParseQueryCacheTests.swift */,\n\t\t\t\t7044C20525C5D6780011F6E7 /* ParseQueryCombineTests.swift */,\n\t\t\t\t70C7DC1F24D20F180050419B /* ParseQueryTests.swift */,\n\t\t\t\t91BB8FD32690D586005A6BA5 /* ParseQueryViewModelTests.swift */,\n\t\t\t\t70D1BD8625B8C37200A42E7C /* ParseRelationTests.swift */,\n\t\t\t\t7004C22D25B69077005E0AD9 /* ParseRoleTests.swift */,\n\t\t\t\t7050259C2843F0CF008D6624 /* ParseSchemaAsyncTests.swift */,\n\t\t\t\t705025A02843F0E7008D6624 /* ParseSchemaCombineTests.swift */,\n\t\t\t\t705025A4284407C4008D6624 /* ParseSchemaTests.swift */,\n\t\t\t\t70C5504525B40D5200B5DBC2 /* ParseSessionTests.swift */,\n\t\t\t\t7C995D282861FA0B0077805A /* ParseSpotifyAsyncTests.swift */,\n\t\t\t\t7C995D2C2861FAE40077805A /* ParseSpotifyCombineTests.swift */,\n\t\t\t\t7C995D242861F8330077805A /* ParseSpotifyTests.swift */,\n\t\t\t\t917BA4512703F55700F8D747 /* ParseTwitterAsyncTests.swift */,\n\t\t\t\t89899D9E26045998002E2043 /* ParseTwitterCombineTests.swift */,\n\t\t\t\t89899CDC2603CE73002E2043 /* ParseTwitterTests.swift */,\n\t\t\t\t703B092226BDFAB2005A112F /* ParseUserAsyncTests.swift */,\n\t\t\t\t7016ED3F25C4A25A00038648 /* ParseUserCombineTests.swift */,\n\t\t\t\t70C7DC1D24D20E530050419B /* ParseUserTests.swift */,\n\t\t\t\t91679D68268F25EA00F71809 /* ParseVersionTests.swift */,\n\t\t\t\t7FFF552A2217E729007C3B4E /* AnyCodableTests */,\n\t\t\t\t911DB12A24C3F7260027F3C7 /* NetworkMocking */,\n\t\t\t\t7037DAC726384E46005D7E62 /* ParseEncoderTests */,\n\t\t\t);\n\t\t\tpath = ParseSwiftTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4AB8B4EA1F254AE10070F682 = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t9158916A256A07DD0024BE9A /* README.md */,\n\t\t\t\t70D1BDA525BA192700A42E7C /* CHANGELOG.md */,\n\t\t\t\t70D1BDA625BA193500A42E7C /* CONTRIBUTING.md */,\n\t\t\t\t4A5EE45F1F49E9E000D3CAE3 /* Sources */,\n\t\t\t\t4A5EE4601F49EA0600D3CAE3 /* Tests */,\n\t\t\t\t4A65114E1F48E3CE005237DF /* ParseSwift-iOS */,\n\t\t\t\t4AFDA7131F26D9A5002AE4FC /* ParseSwift-macOS */,\n\t\t\t\t912C9BD924D3011F009947C3 /* ParseSwift-tvOS */,\n\t\t\t\t912C9BCC24D3005D009947C3 /* ParseSwift-watchOS */,\n\t\t\t\t4AA807591F794242008CD551 /* TestHost */,\n\t\t\t\t70F2E23B254F246000B2EA5C /* ParseSwiftTeststvOS */,\n\t\t\t\t70F2E251254F247000B2EA5C /* ParseSwiftTestsmacOS */,\n\t\t\t\t709B98312556EC7400507778 /* ParseSwiftTeststvOS */,\n\t\t\t\t7033ECB125584A83009770F3 /* TestHostTV */,\n\t\t\t\t4AB8B4F51F254AE10070F682 /* Products */,\n\t\t\t\t4ACFC2E21F3CA21F0046F3A3 /* ParseSwift.playground */,\n\t\t\t);\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4AB8B4F51F254AE10070F682 /* Products */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4AB8B4F41F254AE10070F682 /* ParseSwift.framework */,\n\t\t\t\t4AB8B4FD1F254AE10070F682 /* ParseSwiftTests.xctest */,\n\t\t\t\t4AFDA7121F26D9A5002AE4FC /* ParseSwift.framework */,\n\t\t\t\t4AA807581F794242008CD551 /* TestHost.app */,\n\t\t\t\t912C9BCB24D3005D009947C3 /* ParseSwift.framework */,\n\t\t\t\t912C9BD824D3011F009947C3 /* ParseSwift.framework */,\n\t\t\t\t70F2E250254F247000B2EA5C /* ParseSwiftTestsmacOS.xctest */,\n\t\t\t\t709B98302556EC7400507778 /* ParseSwiftTeststvOS.xctest */,\n\t\t\t\t7033ECB025584A83009770F3 /* TestHostTV.app */,\n\t\t\t);\n\t\t\tname = Products;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4AB8B4F61F254AE10070F682 /* ParseSwift */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t7085DD9326CBF3A70033B977 /* Documentation.docc */,\n\t\t\t\t4AB8B4F71F254AE10070F682 /* Parse.h */,\n\t\t\t\t4A82B7EE1F254B820063D731 /* Parse.swift */,\n\t\t\t\t70110D51250680140091CC1D /* ParseConstants.swift */,\n\t\t\t\tF97B45C924D9C6F200F4A88B /* API */,\n\t\t\t\t707A3BEF25B0A3B8000D215C /* Authentication */,\n\t\t\t\tF97B45B324D9C6F200F4A88B /* Coding */,\n\t\t\t\t706436A227341F36007C6461 /* Extensions */,\n\t\t\t\t70110D5D250849B30091CC1D /* InternalObjects */,\n\t\t\t\t70510AAA259EE23700FEA700 /* LiveQuery */,\n\t\t\t\tF97B45C324D9C6F200F4A88B /* Objects */,\n\t\t\t\tF97B463F24D9C78B00F4A88B /* Operations */,\n\t\t\t\t70110D5E25084AF80091CC1D /* Protocols */,\n\t\t\t\tF97B45CB24D9C6F200F4A88B /* Storage */,\n\t\t\t\tF97B45BA24D9C6F200F4A88B /* Types */,\n\t\t\t);\n\t\t\tpath = ParseSwift;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4AFDA7131F26D9A5002AE4FC /* ParseSwift-macOS */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t4AFDA7151F26D9A5002AE4FC /* Info.plist */,\n\t\t\t);\n\t\t\tpath = \"ParseSwift-macOS\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t700395DE25A147C40052CB31 /* Protocols */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t700395F125A171320052CB31 /* LiveQueryable.swift */,\n\t\t\t\t700396E925A3892D0052CB31 /* LiveQuerySocketDelegate.swift */,\n\t\t\t\t700396F725A394AE0052CB31 /* ParseLiveQueryDelegate.swift */,\n\t\t\t\t700395D025A147BE0052CB31 /* QuerySubscribable.swift */,\n\t\t\t);\n\t\t\tpath = Protocols;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t70110D5D250849B30091CC1D /* InternalObjects */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t70D1BE7225BB43EB00A42E7C /* BaseConfig.swift */,\n\t\t\t\t70110D562506CE890091CC1D /* BaseParseInstallation.swift */,\n\t\t\t\tF97B45BD24D9C6F200F4A88B /* BaseParseUser.swift */,\n\t\t\t\tF97B45C224D9C6F200F4A88B /* NoBody.swift */,\n\t\t\t);\n\t\t\tpath = InternalObjects;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t70110D5E25084AF80091CC1D /* Protocols */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t91F346BD269B77B5005727B6 /* CloudObservable.swift */,\n\t\t\t\t708D035125215F9B00646C70 /* Deletable.swift */,\n\t\t\t\tF97B45C524D9C6F200F4A88B /* Fetchable.swift */,\n\t\t\t\t705A9A2E25991C1400B3547F /* Fileable.swift */,\n\t\t\t\t70BC988F252A5B5C00FF3074 /* Objectable.swift */,\n\t\t\t\t916786E1259B7DDA00BB5B4E /* ParseCloudable.swift */,\n\t\t\t\t703B090626BD9764005A112F /* ParseCloudable+async.swift */,\n\t\t\t\t7044C17425C4ECFF0011F6E7 /* ParseCloudable+combine.swift */,\n\t\t\t\t70647E9B259E3A9A004C1004 /* ParseEncodable.swift */,\n\t\t\t\t704E781628CFD8A00075F952 /* ParseFileTransferable.swift */,\n\t\t\t\t70CE0AB6285A83B100DAEA86 /* ParseHookable.swift */,\n\t\t\t\t70385E752858E1000084D306 /* ParseHookFunctionable.swift */,\n\t\t\t\t70CE0AC0285FD59B00DAEA86 /* ParseHookFunctionable+async.swift */,\n\t\t\t\t70CE0AC5285FD5A800DAEA86 /* ParseHookFunctionable+combine.swift */,\n\t\t\t\t70385E842858F9750084D306 /* ParseHookParametable.swift */,\n\t\t\t\t70CE0AA228595E5E00DAEA86 /* ParseHookRequestable.swift */,\n\t\t\t\t70CE0AA728595FCE00DAEA86 /* ParseHookRequestable+async.swift */,\n\t\t\t\t70CE0AAC28595FDE00DAEA86 /* ParseHookRequestable+combine.swift */,\n\t\t\t\t70385E702858D2DD0084D306 /* ParseHookTriggerable.swift */,\n\t\t\t\t70CE0ACA285FD5CB00DAEA86 /* ParseHookTriggerable+async.swift */,\n\t\t\t\t70CE0ACF285FD5D700DAEA86 /* ParseHookTriggerable+combine.swift */,\n\t\t\t\t705025EA285153BC008D6624 /* ParsePushApplePayloadable.swift */,\n\t\t\t\t705025EF2851542D008D6624 /* ParsePushFirebasePayloadable.swift */,\n\t\t\t\t705025CB284CE4C2008D6624 /* ParsePushPayloadable.swift */,\n\t\t\t\t70A98D812794AB3C009B58F2 /* ParseQueryScorable.swift */,\n\t\t\t\t70CE0ABB285F8FF900DAEA86 /* ParseTypeable.swift */,\n\t\t\t\tF97B45C824D9C6F200F4A88B /* Queryable.swift */,\n\t\t\t\t91BB8FCE2690BA70005A6BA5 /* QueryObservable.swift */,\n\t\t\t\tF97B45C724D9C6F200F4A88B /* Savable.swift */,\n\t\t\t);\n\t\t\tpath = Protocols;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t7033ECB125584A83009770F3 /* TestHostTV */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t7033ECB225584A83009770F3 /* AppDelegate.swift */,\n\t\t\t\t7033ECB425584A83009770F3 /* ViewController.swift */,\n\t\t\t\t7033ECB625584A83009770F3 /* Main.storyboard */,\n\t\t\t\t7033ECB925584A85009770F3 /* Assets.xcassets */,\n\t\t\t\t7033ECBB25584A85009770F3 /* LaunchScreen.storyboard */,\n\t\t\t\t7033ECBE25584A85009770F3 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = TestHostTV;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t7037DAC726384E46005D7E62 /* ParseEncoderTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF971F4F524DE381A006CB79B /* ParseEncoderExtraTests.swift */,\n\t\t\t\t7037DAB126384DE1005D7E62 /* TestParseEncoder.swift */,\n\t\t\t);\n\t\t\tpath = ParseEncoderTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t703B096126BF484E005A112F /* ParseApple */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t707A3C1F25B14BCF000D215C /* ParseApple.swift */,\n\t\t\t\t703B093E26BF47AC005A112F /* ParseApple+async.swift */,\n\t\t\t\t703B093926BF4799005A112F /* ParseApple+combine.swift */,\n\t\t\t);\n\t\t\tpath = ParseApple;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t703B096226BF486C005A112F /* ParseLDAP */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t70386A3725D998D90048EC1B /* ParseLDAP.swift */,\n\t\t\t\t703B094826BF47D0005A112F /* ParseLDAP+async.swift */,\n\t\t\t\t703B094326BF47C0005A112F /* ParseLDAP+combine.swift */,\n\t\t\t);\n\t\t\tpath = ParseLDAP;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t703B096326BF487E005A112F /* ParseTwitter */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t89899CC02603CE2A002E2043 /* ParseTwitter.swift */,\n\t\t\t\t703B095226BF47FD005A112F /* ParseTwitter+async.swift */,\n\t\t\t\t703B094D26BF47E3005A112F /* ParseTwitter+combine.swift */,\n\t\t\t);\n\t\t\tpath = ParseTwitter;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t703B096426BF4896005A112F /* ParseFacebook */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t89899CCE2603CE3A002E2043 /* ParseFacebook.swift */,\n\t\t\t\t703B095C26BF481F005A112F /* ParseFacebook+async.swift */,\n\t\t\t\t703B095726BF480D005A112F /* ParseFacebook+combine.swift */,\n\t\t\t);\n\t\t\tpath = ParseFacebook;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t705025E428514E91008D6624 /* ParsePushPayload */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t705025E528514F36008D6624 /* ParsePushPayloadAny.swift */,\n\t\t\t\t705025F428541DBE008D6624 /* Apple */,\n\t\t\t\t705025F528541E62008D6624 /* Firebase */,\n\t\t\t);\n\t\t\tpath = ParsePushPayload;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t705025F428541DBE008D6624 /* Apple */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t705025D0284CFCDE008D6624 /* ParsePushAppleAlert.swift */,\n\t\t\t\t705025DA284D0D56008D6624 /* ParsePushAppleSound.swift */,\n\t\t\t\t705025D5284D0C1D008D6624 /* ParsePushPayloadApple.swift */,\n\t\t\t);\n\t\t\tpath = Apple;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t705025F528541E62008D6624 /* Firebase */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t70212D122854C82B00386163 /* ParsePushFirebaseNotification.swift */,\n\t\t\t\t705025DF2851006F008D6624 /* ParsePushPayloadFirebase.swift */,\n\t\t\t);\n\t\t\tpath = Firebase;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t70510AAA259EE23700FEA700 /* LiveQuery */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t7064369A273313D5007C6461 /* LiveQueryConstants.swift */,\n\t\t\t\t70510AAB259EE25E00FEA700 /* LiveQuerySocket.swift */,\n\t\t\t\t7003959425A10DFC0052CB31 /* Messages.swift */,\n\t\t\t\t700395A225A119430052CB31 /* Operations.swift */,\n\t\t\t\t7003960825A184EF0052CB31 /* ParseLiveQuery.swift */,\n\t\t\t\t703B091526BD99BC005A112F /* ParseLiveQuery+async.swift */,\n\t\t\t\t918CED582684C74000CFDC83 /* ParseLiveQuery+combine.swift */,\n\t\t\t\t70C5655825AA147B00BDD57F /* ParseLiveQueryConstants.swift */,\n\t\t\t\t700395B925A1470F0052CB31 /* Subscription.swift */,\n\t\t\t\t705D950725BE4C08003EF6F8 /* SubscriptionCallback.swift */,\n\t\t\t\t700395DE25A147C40052CB31 /* Protocols */,\n\t\t\t);\n\t\t\tpath = LiveQuery;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t706436A227341F36007C6461 /* Extensions */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t70386A0525D9718C0048EC1B /* Data.swift */,\n\t\t\t\t706436A827341FD0007C6461 /* Date.swift */,\n\t\t\t\t70C048C02880D7E500401689 /* Dictionary.swift */,\n\t\t\t\t706436A327341F6E007C6461 /* Encodable.swift */,\n\t\t\t\t9116F66E26A35D600082F6D6 /* URLCache.swift */,\n\t\t\t\tF97B462C24D9C74400F4A88B /* URLSession.swift */,\n\t\t\t);\n\t\t\tpath = Extensions;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t707A3BEF25B0A3B8000D215C /* Authentication */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t70A2D81325B358FA001BEB7D /* 3rd Party */,\n\t\t\t\t70A2D81425B35905001BEB7D /* Internal */,\n\t\t\t\t707A3C1E25B14BAE000D215C /* Protocols */,\n\t\t\t);\n\t\t\tpath = Authentication;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t707A3C1E25B14BAE000D215C /* Protocols */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t707A3BF025B0A4F0000D215C /* ParseAuthentication.swift */,\n\t\t\t\t7044C1C725C5B2B10011F6E7 /* ParseAuthentication+combine.swift */,\n\t\t\t\t703B092A26BF290B005A112F /* ParseAuthentication+async.swift */,\n\t\t\t);\n\t\t\tpath = Protocols;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t709B98312556EC7400507778 /* ParseSwiftTeststvOS */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t709B98342556EC7400507778 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = ParseSwiftTeststvOS;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t70A2D81325B358FA001BEB7D /* 3rd Party */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t7C4C0929285E745400F202C6 /* ParseInstagram */,\n\t\t\t\t703B096126BF484E005A112F /* ParseApple */,\n\t\t\t\t703B096426BF4896005A112F /* ParseFacebook */,\n\t\t\t\t70F03A312780C7DD00E5AFB4 /* ParseGithub */,\n\t\t\t\t70F03A212780B8D000E5AFB4 /* ParseGoogle */,\n\t\t\t\t703B096226BF486C005A112F /* ParseLDAP */,\n\t\t\t\t70F03A322780C7EB00E5AFB4 /* ParseLinkedIn */,\n\t\t\t\t7C55F9E52860CD48002A352D /* ParseSpotify */,\n\t\t\t\t703B096326BF487E005A112F /* ParseTwitter */,\n\t\t\t);\n\t\t\tpath = \"3rd Party\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t70A2D81425B35905001BEB7D /* Internal */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t707A3C1025B0A8E8000D215C /* ParseAnonymous.swift */,\n\t\t\t\t703B093426BF43D9005A112F /* ParseAnonymous+async.swift */,\n\t\t\t\t703B092F26BF42C2005A112F /* ParseAnonymous+combine.swift */,\n\t\t\t);\n\t\t\tpath = Internal;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t70F03A212780B8D000E5AFB4 /* ParseGoogle */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t70F03A222780BDE200E5AFB4 /* ParseGoogle.swift */,\n\t\t\t\t70F03A242780BDF700E5AFB4 /* ParseGoogle+async.swift */,\n\t\t\t\t70F03A262780BE0F00E5AFB4 /* ParseGoogle+combine.swift */,\n\t\t\t);\n\t\t\tpath = ParseGoogle;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t70F03A312780C7DD00E5AFB4 /* ParseGithub */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t70F03A332780CA4300E5AFB4 /* ParseGitHub.swift */,\n\t\t\t\t70F03A382780CA6F00E5AFB4 /* ParseGitHub+async.swift */,\n\t\t\t\t70F03A3D2780CA8F00E5AFB4 /* ParseGitHub+combine.swift */,\n\t\t\t);\n\t\t\tpath = ParseGithub;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t70F03A322780C7EB00E5AFB4 /* ParseLinkedIn */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t70F03A422780D21600E5AFB4 /* ParseLinkedIn.swift */,\n\t\t\t\t70F03A472780D27700E5AFB4 /* ParseLinkedIn+async.swift */,\n\t\t\t\t70F03A4C2780D28A00E5AFB4 /* ParseLinkedIn+combine.swift */,\n\t\t\t);\n\t\t\tpath = ParseLinkedIn;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t70F2E23B254F246000B2EA5C /* ParseSwiftTeststvOS */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t70F2E23E254F246000B2EA5C /* Info.plist */,\n\t\t\t);\n\t\t\tpath = ParseSwiftTeststvOS;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t70F2E251254F247000B2EA5C /* ParseSwiftTestsmacOS */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t70F2E254254F247000B2EA5C /* Info.plist */,\n\t\t\t);\n\t\t\tpath = ParseSwiftTestsmacOS;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t7C4C0929285E745400F202C6 /* ParseInstagram */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t7C4C092A285E746800F202C6 /* ParseInstagram.swift */,\n\t\t\t\t7C4C092F285E986F00F202C6 /* ParseInstagram+async.swift */,\n\t\t\t\t7C4C0939285E9A3700F202C6 /* ParseInstagram+combine.swift */,\n\t\t\t);\n\t\t\tpath = ParseInstagram;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t7C55F9E52860CD48002A352D /* ParseSpotify */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t7C55F9E62860CD6B002A352D /* ParseSpotify.swift */,\n\t\t\t\t7C55F9EB2860CEA6002A352D /* ParseSpotify+async.swift */,\n\t\t\t\t7C55F9F02860CEEF002A352D /* ParseSpotify+combine.swift */,\n\t\t\t);\n\t\t\tpath = ParseSpotify;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t7FFF552A2217E729007C3B4E /* AnyCodableTests */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t7FFF552B2217E729007C3B4E /* AnyEncodableTests.swift */,\n\t\t\t\t7FFF552C2217E729007C3B4E /* AnyCodableTests.swift */,\n\t\t\t\t7FFF552D2217E729007C3B4E /* AnyDecodableTests.swift */,\n\t\t\t);\n\t\t\tpath = AnyCodableTests;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t911DB12A24C3F7260027F3C7 /* NetworkMocking */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t911DB12B24C3F7720027F3C7 /* MockURLResponse.swift */,\n\t\t\t\t911DB13224C494390027F3C7 /* MockURLProtocol.swift */,\n\t\t\t);\n\t\t\tpath = NetworkMocking;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t912C9BCC24D3005D009947C3 /* ParseSwift-watchOS */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t912C9BCD24D3005D009947C3 /* ParseSwift_watchOS.h */,\n\t\t\t\t912C9BCE24D3005D009947C3 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = \"ParseSwift-watchOS\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t912C9BD924D3011F009947C3 /* ParseSwift-tvOS */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t912C9BDA24D3011F009947C3 /* ParseSwift_tvOS.h */,\n\t\t\t\t912C9BDB24D3011F009947C3 /* Info.plist */,\n\t\t\t);\n\t\t\tpath = \"ParseSwift-tvOS\";\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF97B45B324D9C6F200F4A88B /* Coding */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF97B45B824D9C6F200F4A88B /* AnyCodable.swift */,\n\t\t\t\tF97B45B524D9C6F200F4A88B /* AnyDecodable.swift */,\n\t\t\t\tF97B45B924D9C6F200F4A88B /* AnyEncodable.swift */,\n\t\t\t\tF97B45B424D9C6F200F4A88B /* ParseCoding.swift */,\n\t\t\t\tF97B45B624D9C6F200F4A88B /* ParseEncoder.swift */,\n\t\t\t);\n\t\t\tpath = Coding;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF97B45BA24D9C6F200F4A88B /* Types */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t91F346B8269B766C005727B6 /* CloudViewModel.swift */,\n\t\t\t\tF97B45C024D9C6F200F4A88B /* ParseACL.swift */,\n\t\t\t\t70170A432656B02C0070C905 /* ParseAnalytics.swift */,\n\t\t\t\t703B090126BD9652005A112F /* ParseAnalytics+async.swift */,\n\t\t\t\t70170A482656E2FE0070C905 /* ParseAnalytics+combine.swift */,\n\t\t\t\t91285B122698DBF20051B544 /* ParseBytes.swift */,\n\t\t\t\t709A149F2839CABD00BF85E5 /* ParseCLP.swift */,\n\t\t\t\t70D1BDB925BB17A600A42E7C /* ParseConfig.swift */,\n\t\t\t\t703B090B26BD984D005A112F /* ParseConfig+async.swift */,\n\t\t\t\t7044C18225C4EFC10011F6E7 /* ParseConfig+combine.swift */,\n\t\t\t\t704C886B28BE69A8008E6B01 /* ParseConfiguration.swift */,\n\t\t\t\tF97B45BF24D9C6F200F4A88B /* ParseError.swift */,\n\t\t\t\t709A148628396B1C00BF85E5 /* ParseField.swift */,\n\t\t\t\t705025A828441C96008D6624 /* ParseFieldOptions.swift */,\n\t\t\t\tF97B45C124D9C6F200F4A88B /* ParseFile.swift */,\n\t\t\t\t7045769C26BD934000F86F71 /* ParseFile+async.swift */,\n\t\t\t\t7044C19025C4F5B60011F6E7 /* ParseFile+combine.swift */,\n\t\t\t\t704E781B28CFFAF80075F952 /* ParseFileDefaultTransfer.swift */,\n\t\t\t\tF97B45BC24D9C6F200F4A88B /* ParseGeoPoint.swift */,\n\t\t\t\t70F79A182639CE6F00731C46 /* ParseHealth.swift */,\n\t\t\t\t703B08FC26BD953B005A112F /* ParseHealth+async.swift */,\n\t\t\t\t7085DDA226CC8A470033B977 /* ParseHealth+combine.swift */,\n\t\t\t\t70385E7F2858EAA90084D306 /* ParseHookFunctionRequest.swift */,\n\t\t\t\t70CE0A9328590A0A00DAEA86 /* ParseHookResponse.swift */,\n\t\t\t\t70CE0AB1285963A300DAEA86 /* ParseHookTriggerRequest.swift */,\n\t\t\t\t70D41D7F28B520E200613510 /* ParseKeychainAccessGroup.swift */,\n\t\t\t\tF97B464024D9C78B00F4A88B /* ParseOperation.swift */,\n\t\t\t\t703B091026BD992E005A112F /* ParseOperation+async.swift */,\n\t\t\t\t7044C19E25C4FA870011F6E7 /* ParseOperation+combine.swift */,\n\t\t\t\t91285B1B26990D7F0051B544 /* ParsePolygon.swift */,\n\t\t\t\t705025BC284C610C008D6624 /* ParsePush.swift */,\n\t\t\t\t705025C1284C7841008D6624 /* ParsePush+async.swift */,\n\t\t\t\t705025C6284C7883008D6624 /* ParsePush+combine.swift */,\n\t\t\t\t705025B22845C302008D6624 /* ParsePushStatus.swift */,\n\t\t\t\t7004C21F25B63C7A005E0AD9 /* ParseRelation.swift */,\n\t\t\t\t709A147C283949D100BF85E5 /* ParseSchema.swift */,\n\t\t\t\t709A148128395ED100BF85E5 /* ParseSchema+async.swift */,\n\t\t\t\t709A14A4283AAF4C00BF85E5 /* ParseSchema+combine.swift */,\n\t\t\t\t91679D63268E596300F71809 /* ParseVersion.swift */,\n\t\t\t\tF97B45BE24D9C6F200F4A88B /* Pointer.swift */,\n\t\t\t\t70C167B327304F09009F4E30 /* Pointer+async.swift */,\n\t\t\t\t70C167AE27304EE4009F4E30 /* Pointer+combine.swift */,\n\t\t\t\tF97B45BB24D9C6F200F4A88B /* Query.swift */,\n\t\t\t\t7045769726BD917500F86F71 /* Query+async.swift */,\n\t\t\t\t7044C1AC25C4FC080011F6E7 /* Query+combine.swift */,\n\t\t\t\t70B4E0BB2762F1D5004C9757 /* QueryConstraint.swift */,\n\t\t\t\t91BB8FC92690AC99005A6BA5 /* QueryViewModel.swift */,\n\t\t\t\t70B4E0C02762F313004C9757 /* QueryWhere.swift */,\n\t\t\t\t705025E428514E91008D6624 /* ParsePushPayload */,\n\t\t\t);\n\t\t\tpath = Types;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF97B45C324D9C6F200F4A88B /* Objects */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\t70CE0A9D28592A2B00DAEA86 /* ParseCloudUser.swift */,\n\t\t\t\t70BDA2B2250536FF00FC2237 /* ParseInstallation.swift */,\n\t\t\t\t7045769226BD8F8100F86F71 /* ParseInstallation+async.swift */,\n\t\t\t\t7016ED5525C4C32B00038648 /* ParseInstallation+combine.swift */,\n\t\t\t\tF97B45C624D9C6F200F4A88B /* ParseObject.swift */,\n\t\t\t\t7028373326BD8883007688C9 /* ParseObject+async.swift */,\n\t\t\t\t7016ED6325C4C46B00038648 /* ParseObject+combine.swift */,\n\t\t\t\t705025AD28456106008D6624 /* ParsePushStatusable.swift */,\n\t\t\t\t70C5507625B49D3A00B5DBC2 /* ParseRole.swift */,\n\t\t\t\t70C5503725B406B800B5DBC2 /* ParseSession.swift */,\n\t\t\t\tF97B45C424D9C6F200F4A88B /* ParseUser.swift */,\n\t\t\t\t7028373826BD8C89007688C9 /* ParseUser+async.swift */,\n\t\t\t\t7016ED3125C3BA2000038648 /* ParseUser+combine.swift */,\n\t\t\t);\n\t\t\tpath = Objects;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF97B45C924D9C6F200F4A88B /* API */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF97B462624D9C72700F4A88B /* API.swift */,\n\t\t\t\t91B79AC726EE3C5D00073F2C /* API+BatchCommand.swift */,\n\t\t\t\tF97B462E24D9C74400F4A88B /* API+Command.swift */,\n\t\t\t\t708EF0BC28D5F4140052EF35 /* API+Command+async.swift */,\n\t\t\t\t91B79AC226EE3A4E00073F2C /* API+NonParseBodyCommand.swift */,\n\t\t\t\t708EF0C128D5FDF10052EF35 /* API+NonParseBodyCommand+async.swift */,\n\t\t\t\tF97B462B24D9C74400F4A88B /* BatchUtils.swift */,\n\t\t\t\t7003972925A3B0130052CB31 /* ParseURLSessionDelegate.swift */,\n\t\t\t\tF97B462D24D9C74400F4A88B /* Responses.swift */,\n\t\t\t);\n\t\t\tpath = API;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF97B45CB24D9C6F200F4A88B /* Storage */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF97B465E24D9C7B500F4A88B /* KeychainStore.swift */,\n\t\t\t\t70572670259033A700F0ADD5 /* ParseFileManager.swift */,\n\t\t\t\tF97B45CC24D9C6F200F4A88B /* ParseStorage.swift */,\n\t\t\t\tF97B45CD24D9C6F200F4A88B /* ParseKeyValueStore.swift */,\n\t\t\t\tF97B466324D9C88600F4A88B /* SecureStorage.swift */,\n\t\t\t);\n\t\t\tpath = Storage;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\tF97B463F24D9C78B00F4A88B /* Operations */ = {\n\t\t\tisa = PBXGroup;\n\t\t\tchildren = (\n\t\t\t\tF97B464224D9C78B00F4A88B /* Add.swift */,\n\t\t\t\t70C5509125B4A99100B5DBC2 /* AddRelation.swift */,\n\t\t\t\tF97B464324D9C78B00F4A88B /* AddUnique.swift */,\n\t\t\t\tF97B464124D9C78B00F4A88B /* Delete.swift */,\n\t\t\t\tF97B464524D9C78B00F4A88B /* Increment.swift */,\n\t\t\t\tF97B464424D9C78B00F4A88B /* Remove.swift */,\n\t\t\t\t70C5509F25B4A9F600B5DBC2 /* RemoveRelation.swift */,\n\t\t\t\t709A148B2839A1DB00BF85E5 /* Operation.swift */,\n\t\t\t);\n\t\t\tpath = Operations;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXGroup section */\n\n/* Begin PBXHeadersBuildPhase section */\n\t\t4AB8B4F11F254AE10070F682 /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4AB8B5051F254AE10070F682 /* Parse.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4AFDA70F1F26D9A5002AE4FC /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4AFDA7391F26DAF8002AE4FC /* Parse.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t912C9BC624D3005D009947C3 /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t912C9BCF24D3005D009947C3 /* ParseSwift_watchOS.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t912C9BD324D3011F009947C3 /* Headers */ = {\n\t\t\tisa = PBXHeadersBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t912C9BDC24D3011F009947C3 /* ParseSwift_tvOS.h in Headers */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXHeadersBuildPhase section */\n\n/* Begin PBXNativeTarget section */\n\t\t4AA807571F794242008CD551 /* TestHost */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 4AA807671F794242008CD551 /* Build configuration list for PBXNativeTarget \"TestHost\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t4AA807541F794242008CD551 /* Sources */,\n\t\t\t\t4AA807551F794242008CD551 /* Frameworks */,\n\t\t\t\t4AA807561F794242008CD551 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = TestHost;\n\t\t\tproductName = TestHost;\n\t\t\tproductReference = 4AA807581F794242008CD551 /* TestHost.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\t4AB8B4F31F254AE10070F682 /* ParseSwift (iOS) */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 4AB8B5081F254AE10070F682 /* Build configuration list for PBXNativeTarget \"ParseSwift (iOS)\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t4AB8B4EF1F254AE10070F682 /* Sources */,\n\t\t\t\t4AB8B4F01F254AE10070F682 /* Frameworks */,\n\t\t\t\t4AB8B4F11F254AE10070F682 /* Headers */,\n\t\t\t\t4AB8B4F21F254AE10070F682 /* Resources */,\n\t\t\t\t4A6511551F49D544005237DF /* SwiftLint */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"ParseSwift (iOS)\";\n\t\t\tproductName = Parse;\n\t\t\tproductReference = 4AB8B4F41F254AE10070F682 /* ParseSwift.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\t4AB8B4FC1F254AE10070F682 /* ParseSwiftTests */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 4AB8B50B1F254AE10070F682 /* Build configuration list for PBXNativeTarget \"ParseSwiftTests\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t4AB8B4F91F254AE10070F682 /* Sources */,\n\t\t\t\t4AB8B4FA1F254AE10070F682 /* Frameworks */,\n\t\t\t\t4AB8B4FB1F254AE10070F682 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t4AB8B5001F254AE10070F682 /* PBXTargetDependency */,\n\t\t\t\t4AA8076B1F79424A008CD551 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = ParseSwiftTests;\n\t\t\tproductName = ParseTests;\n\t\t\tproductReference = 4AB8B4FD1F254AE10070F682 /* ParseSwiftTests.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\t4AFDA7111F26D9A5002AE4FC /* ParseSwift (macOS) */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 4AFDA7231F26D9A5002AE4FC /* Build configuration list for PBXNativeTarget \"ParseSwift (macOS)\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t4AFDA70D1F26D9A5002AE4FC /* Sources */,\n\t\t\t\t4AFDA70E1F26D9A5002AE4FC /* Frameworks */,\n\t\t\t\t4AFDA70F1F26D9A5002AE4FC /* Headers */,\n\t\t\t\t4AFDA7101F26D9A5002AE4FC /* Resources */,\n\t\t\t\t4A6511541F49D53C005237DF /* SwiftLint */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"ParseSwift (macOS)\";\n\t\t\tproductName = \"Parse-macOS\";\n\t\t\tproductReference = 4AFDA7121F26D9A5002AE4FC /* ParseSwift.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\t7033ECAF25584A83009770F3 /* TestHostTV */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 7033ECC125584A85009770F3 /* Build configuration list for PBXNativeTarget \"TestHostTV\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t7033ECAC25584A83009770F3 /* Sources */,\n\t\t\t\t7033ECAD25584A83009770F3 /* Frameworks */,\n\t\t\t\t7033ECAE25584A83009770F3 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = TestHostTV;\n\t\t\tproductName = TestHostTV;\n\t\t\tproductReference = 7033ECB025584A83009770F3 /* TestHostTV.app */;\n\t\t\tproductType = \"com.apple.product-type.application\";\n\t\t};\n\t\t709B982F2556EC7400507778 /* ParseSwiftTeststvOS */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 709B983A2556EC7400507778 /* Build configuration list for PBXNativeTarget \"ParseSwiftTeststvOS\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t709B982C2556EC7400507778 /* Sources */,\n\t\t\t\t709B982D2556EC7400507778 /* Frameworks */,\n\t\t\t\t709B982E2556EC7400507778 /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t709B98372556EC7400507778 /* PBXTargetDependency */,\n\t\t\t\t7033ECCC25584AAF009770F3 /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = ParseSwiftTeststvOS;\n\t\t\tproductName = ParseSwiftTeststvOS;\n\t\t\tproductReference = 709B98302556EC7400507778 /* ParseSwiftTeststvOS.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\t70F2E24F254F247000B2EA5C /* ParseSwiftTestsmacOS */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 70F2E258254F247000B2EA5C /* Build configuration list for PBXNativeTarget \"ParseSwiftTestsmacOS\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t70F2E24C254F247000B2EA5C /* Sources */,\n\t\t\t\t70F2E24D254F247000B2EA5C /* Frameworks */,\n\t\t\t\t70F2E24E254F247000B2EA5C /* Resources */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t\t70F2E257254F247000B2EA5C /* PBXTargetDependency */,\n\t\t\t);\n\t\t\tname = ParseSwiftTestsmacOS;\n\t\t\tproductName = ParseSwiftTestsmacOS;\n\t\t\tproductReference = 70F2E250254F247000B2EA5C /* ParseSwiftTestsmacOS.xctest */;\n\t\t\tproductType = \"com.apple.product-type.bundle.unit-test\";\n\t\t};\n\t\t912C9BCA24D3005D009947C3 /* ParseSwift (watchOS) */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 912C9BD024D3005D009947C3 /* Build configuration list for PBXNativeTarget \"ParseSwift (watchOS)\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t912C9BC624D3005D009947C3 /* Headers */,\n\t\t\t\t912C9BC724D3005D009947C3 /* Sources */,\n\t\t\t\t912C9BC824D3005D009947C3 /* Frameworks */,\n\t\t\t\t912C9BC924D3005D009947C3 /* Resources */,\n\t\t\t\t918CED62268A23E600CFDC83 /* SwiftLint */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"ParseSwift (watchOS)\";\n\t\t\tproductName = \"ParseSwift-watchOS\";\n\t\t\tproductReference = 912C9BCB24D3005D009947C3 /* ParseSwift.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n\t\t912C9BD724D3011F009947C3 /* ParseSwift (tvOS) */ = {\n\t\t\tisa = PBXNativeTarget;\n\t\t\tbuildConfigurationList = 912C9BDD24D3011F009947C3 /* Build configuration list for PBXNativeTarget \"ParseSwift (tvOS)\" */;\n\t\t\tbuildPhases = (\n\t\t\t\t912C9BD324D3011F009947C3 /* Headers */,\n\t\t\t\t912C9BD424D3011F009947C3 /* Sources */,\n\t\t\t\t912C9BD524D3011F009947C3 /* Frameworks */,\n\t\t\t\t912C9BD624D3011F009947C3 /* Resources */,\n\t\t\t\t918CED61268A23A700CFDC83 /* SwiftLint */,\n\t\t\t);\n\t\t\tbuildRules = (\n\t\t\t);\n\t\t\tdependencies = (\n\t\t\t);\n\t\t\tname = \"ParseSwift (tvOS)\";\n\t\t\tproductName = \"ParseSwift-tvOS\";\n\t\t\tproductReference = 912C9BD824D3011F009947C3 /* ParseSwift.framework */;\n\t\t\tproductType = \"com.apple.product-type.framework\";\n\t\t};\n/* End PBXNativeTarget section */\n\n/* Begin PBXProject section */\n\t\t4AB8B4EB1F254AE10070F682 /* Project object */ = {\n\t\t\tisa = PBXProject;\n\t\t\tattributes = {\n\t\t\t\tBuildIndependentTargetsInParallel = YES;\n\t\t\t\tLastSwiftUpdateCheck = 1210;\n\t\t\t\tLastUpgradeCheck = 1400;\n\t\t\t\tORGANIZATIONNAME = \"Parse Community\";\n\t\t\t\tTargetAttributes = {\n\t\t\t\t\t4AA807571F794242008CD551 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 9.0;\n\t\t\t\t\t\tLastSwiftMigration = 1130;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t\t4AB8B4F31F254AE10070F682 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 9.0;\n\t\t\t\t\t\tLastSwiftMigration = 1130;\n\t\t\t\t\t};\n\t\t\t\t\t4AB8B4FC1F254AE10070F682 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 9.0;\n\t\t\t\t\t\tLastSwiftMigration = 1130;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t\tTestTargetID = 4AA807571F794242008CD551;\n\t\t\t\t\t};\n\t\t\t\t\t4AFDA7111F26D9A5002AE4FC = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 9.0;\n\t\t\t\t\t\tLastSwiftMigration = 1130;\n\t\t\t\t\t};\n\t\t\t\t\t7033ECAF25584A83009770F3 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 12.1;\n\t\t\t\t\t\tProvisioningStyle = Automatic;\n\t\t\t\t\t};\n\t\t\t\t\t709B982F2556EC7400507778 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 12.1;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t\tTestTargetID = 7033ECAF25584A83009770F3;\n\t\t\t\t\t};\n\t\t\t\t\t70F2E24F254F247000B2EA5C = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 12.1;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t\t912C9BCA24D3005D009947C3 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 11.6;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t\t912C9BD724D3011F009947C3 = {\n\t\t\t\t\t\tCreatedOnToolsVersion = 11.6;\n\t\t\t\t\t\tProvisioningStyle = Manual;\n\t\t\t\t\t};\n\t\t\t\t};\n\t\t\t};\n\t\t\tbuildConfigurationList = 4AB8B4EE1F254AE10070F682 /* Build configuration list for PBXProject \"ParseSwift\" */;\n\t\t\tcompatibilityVersion = \"Xcode 8.0\";\n\t\t\tdevelopmentRegion = en;\n\t\t\thasScannedForEncodings = 0;\n\t\t\tknownRegions = (\n\t\t\t\ten,\n\t\t\t\tBase,\n\t\t\t);\n\t\t\tmainGroup = 4AB8B4EA1F254AE10070F682;\n\t\t\tpackageReferences = (\n\t\t\t);\n\t\t\tproductRefGroup = 4AB8B4F51F254AE10070F682 /* Products */;\n\t\t\tprojectDirPath = \"\";\n\t\t\tprojectRoot = \"\";\n\t\t\ttargets = (\n\t\t\t\t4AB8B4F31F254AE10070F682 /* ParseSwift (iOS) */,\n\t\t\t\t4AFDA7111F26D9A5002AE4FC /* ParseSwift (macOS) */,\n\t\t\t\t912C9BD724D3011F009947C3 /* ParseSwift (tvOS) */,\n\t\t\t\t912C9BCA24D3005D009947C3 /* ParseSwift (watchOS) */,\n\t\t\t\t4AB8B4FC1F254AE10070F682 /* ParseSwiftTests */,\n\t\t\t\t4AA807571F794242008CD551 /* TestHost */,\n\t\t\t\t70F2E24F254F247000B2EA5C /* ParseSwiftTestsmacOS */,\n\t\t\t\t709B982F2556EC7400507778 /* ParseSwiftTeststvOS */,\n\t\t\t\t7033ECAF25584A83009770F3 /* TestHostTV */,\n\t\t\t);\n\t\t};\n/* End PBXProject section */\n\n/* Begin PBXResourcesBuildPhase section */\n\t\t4AA807561F794242008CD551 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4AA807651F794242008CD551 /* LaunchScreen.storyboard in Resources */,\n\t\t\t\t4AA807621F794242008CD551 /* Assets.xcassets in Resources */,\n\t\t\t\t4AA807601F794242008CD551 /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4AB8B4F21F254AE10070F682 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4AB8B4FB1F254AE10070F682 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4AFDA7101F26D9A5002AE4FC /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t7033ECAE25584A83009770F3 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t7033ECBD25584A85009770F3 /* LaunchScreen.storyboard in Resources */,\n\t\t\t\t7033ECBA25584A85009770F3 /* Assets.xcassets in Resources */,\n\t\t\t\t7033ECB825584A83009770F3 /* Main.storyboard in Resources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t709B982E2556EC7400507778 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t70F2E24E254F247000B2EA5C /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t912C9BC924D3005D009947C3 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t912C9BD624D3011F009947C3 /* Resources */ = {\n\t\t\tisa = PBXResourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXResourcesBuildPhase section */\n\n/* Begin PBXShellScriptBuildPhase section */\n\t\t4A6511541F49D53C005237DF /* SwiftLint */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\talwaysOutOfDate = 1;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = SwiftLint;\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"if which swiftlint >/dev/null; then\\n    swiftlint --strict\\nelse\\n    echo \\\"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\\\"\\nfi\\n\";\n\t\t};\n\t\t4A6511551F49D544005237DF /* SwiftLint */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\talwaysOutOfDate = 1;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = SwiftLint;\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"if test -d \\\"/opt/homebrew/bin/\\\"; then\\n  PATH=\\\"/opt/homebrew/bin/:${PATH}\\\"\\nfi\\n\\nexport PATH\\n\\nif which swiftlint >/dev/null; then\\n    swiftlint --fix && swiftlint --strict\\nelse\\n    echo \\\"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\\\"\\nfi\\n\";\n\t\t};\n\t\t918CED61268A23A700CFDC83 /* SwiftLint */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\talwaysOutOfDate = 1;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = SwiftLint;\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"if which swiftlint >/dev/null; then\\n    swiftlint --strict\\nelse\\n    echo \\\"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\\\"\\nfi\\n\";\n\t\t};\n\t\t918CED62268A23E600CFDC83 /* SwiftLint */ = {\n\t\t\tisa = PBXShellScriptBuildPhase;\n\t\t\talwaysOutOfDate = 1;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t);\n\t\t\tinputFileListPaths = (\n\t\t\t);\n\t\t\tinputPaths = (\n\t\t\t);\n\t\t\tname = SwiftLint;\n\t\t\toutputFileListPaths = (\n\t\t\t);\n\t\t\toutputPaths = (\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t\tshellPath = /bin/sh;\n\t\t\tshellScript = \"if which swiftlint >/dev/null; then\\n    swiftlint --strict\\nelse\\n    echo \\\"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\\\"\\nfi\\n\";\n\t\t};\n/* End PBXShellScriptBuildPhase section */\n\n/* Begin PBXSourcesBuildPhase section */\n\t\t4AA807541F794242008CD551 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t4AA8075B1F794242008CD551 /* AppDelegate.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4AB8B4EF1F254AE10070F682 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tF97B463724D9C74400F4A88B /* Responses.swift in Sources */,\n\t\t\t\t7C55F9EC2860CEA6002A352D /* ParseSpotify+async.swift in Sources */,\n\t\t\t\t916786E2259B7DDA00BB5B4E /* ParseCloudable.swift in Sources */,\n\t\t\t\t70CE0AC6285FD5A800DAEA86 /* ParseHookFunctionable+combine.swift in Sources */,\n\t\t\t\t91F346B9269B766C005727B6 /* CloudViewModel.swift in Sources */,\n\t\t\t\t708EF0C228D5FDF10052EF35 /* API+NonParseBodyCommand+async.swift in Sources */,\n\t\t\t\t709A148C2839A1DB00BF85E5 /* Operation.swift in Sources */,\n\t\t\t\t70CE0AD0285FD5D700DAEA86 /* ParseHookTriggerable+combine.swift in Sources */,\n\t\t\t\t709A14A5283AAF4C00BF85E5 /* ParseSchema+combine.swift in Sources */,\n\t\t\t\tF97B461624D9C6F200F4A88B /* Queryable.swift in Sources */,\n\t\t\t\t7028373426BD8883007688C9 /* ParseObject+async.swift in Sources */,\n\t\t\t\t705025C7284C7883008D6624 /* ParsePush+combine.swift in Sources */,\n\t\t\t\t70C5503825B406B800B5DBC2 /* ParseSession.swift in Sources */,\n\t\t\t\t7044C1C825C5B2B10011F6E7 /* ParseAuthentication+combine.swift in Sources */,\n\t\t\t\t707A3BF125B0A4F0000D215C /* ParseAuthentication.swift in Sources */,\n\t\t\t\t70D1BE7325BB43EB00A42E7C /* BaseConfig.swift in Sources */,\n\t\t\t\t703B090726BD9764005A112F /* ParseCloudable+async.swift in Sources */,\n\t\t\t\t918CED592684C74000CFDC83 /* ParseLiveQuery+combine.swift in Sources */,\n\t\t\t\t70386A0625D9718C0048EC1B /* Data.swift in Sources */,\n\t\t\t\tF97B465F24D9C7B500F4A88B /* KeychainStore.swift in Sources */,\n\t\t\t\t70B4E0C12762F313004C9757 /* QueryWhere.swift in Sources */,\n\t\t\t\t70170A442656B02D0070C905 /* ParseAnalytics.swift in Sources */,\n\t\t\t\t70110D52250680140091CC1D /* ParseConstants.swift in Sources */,\n\t\t\t\t91B79AC326EE3A4E00073F2C /* API+NonParseBodyCommand.swift in Sources */,\n\t\t\t\t708EF0BD28D5F4140052EF35 /* API+Command+async.swift in Sources */,\n\t\t\t\t70D1BDBA25BB17A600A42E7C /* ParseConfig.swift in Sources */,\n\t\t\t\t7C4C092B285E746800F202C6 /* ParseInstagram.swift in Sources */,\n\t\t\t\t703B08FD26BD953B005A112F /* ParseHealth+async.swift in Sources */,\n\t\t\t\t7085DDA326CC8A470033B977 /* ParseHealth+combine.swift in Sources */,\n\t\t\t\t70CE0AC1285FD59B00DAEA86 /* ParseHookFunctionable+async.swift in Sources */,\n\t\t\t\tF97B465224D9C78C00F4A88B /* AddUnique.swift in Sources */,\n\t\t\t\t70C048C12880D7E600401689 /* Dictionary.swift in Sources */,\n\t\t\t\t91B79AC826EE3C5D00073F2C /* API+BatchCommand.swift in Sources */,\n\t\t\t\t70385E712858D2DD0084D306 /* ParseHookTriggerable.swift in Sources */,\n\t\t\t\t91679D64268E596300F71809 /* ParseVersion.swift in Sources */,\n\t\t\t\t91285B1C26990D7F0051B544 /* ParsePolygon.swift in Sources */,\n\t\t\t\t91BB8FCA2690AC99005A6BA5 /* QueryViewModel.swift in Sources */,\n\t\t\t\t7085DD9426CBF3A70033B977 /* Documentation.docc in Sources */,\n\t\t\t\t705025EB285153BC008D6624 /* ParsePushApplePayloadable.swift in Sources */,\n\t\t\t\t705025A928441C96008D6624 /* ParseFieldOptions.swift in Sources */,\n\t\t\t\tF97B45D624D9C6F200F4A88B /* ParseEncoder.swift in Sources */,\n\t\t\t\t7C4C093A285E9A3700F202C6 /* ParseInstagram+combine.swift in Sources */,\n\t\t\t\t700395A325A119430052CB31 /* Operations.swift in Sources */,\n\t\t\t\t91BB8FCF2690BA70005A6BA5 /* QueryObservable.swift in Sources */,\n\t\t\t\t70F03A232780BDE200E5AFB4 /* ParseGoogle.swift in Sources */,\n\t\t\t\t705025E628514F36008D6624 /* ParsePushPayloadAny.swift in Sources */,\n\t\t\t\t709A148228395ED100BF85E5 /* ParseSchema+async.swift in Sources */,\n\t\t\t\t705025D1284CFCDE008D6624 /* ParsePushAppleAlert.swift in Sources */,\n\t\t\t\t704E781C28CFFAF80075F952 /* ParseFileDefaultTransfer.swift in Sources */,\n\t\t\t\t7045769826BD917500F86F71 /* Query+async.swift in Sources */,\n\t\t\t\t703B094E26BF47E3005A112F /* ParseTwitter+combine.swift in Sources */,\n\t\t\t\t70386A3825D998D90048EC1B /* ParseLDAP.swift in Sources */,\n\t\t\t\t709A14A02839CABD00BF85E5 /* ParseCLP.swift in Sources */,\n\t\t\t\t700395F225A171320052CB31 /* LiveQueryable.swift in Sources */,\n\t\t\t\t70F03A252780BDF700E5AFB4 /* ParseGoogle+async.swift in Sources */,\n\t\t\t\tF97B45F224D9C6F200F4A88B /* Pointer.swift in Sources */,\n\t\t\t\t703B095826BF480D005A112F /* ParseFacebook+combine.swift in Sources */,\n\t\t\t\t7C4C0930285E986F00F202C6 /* ParseInstagram+async.swift in Sources */,\n\t\t\t\t705025D6284D0C1D008D6624 /* ParsePushPayloadApple.swift in Sources */,\n\t\t\t\t70510AAC259EE25E00FEA700 /* LiveQuerySocket.swift in Sources */,\n\t\t\t\t70C167AF27304EE4009F4E30 /* Pointer+combine.swift in Sources */,\n\t\t\t\t7044C19125C4F5B60011F6E7 /* ParseFile+combine.swift in Sources */,\n\t\t\t\t70A98D822794AB3C009B58F2 /* ParseQueryScorable.swift in Sources */,\n\t\t\t\t70385E852858F9750084D306 /* ParseHookParametable.swift in Sources */,\n\t\t\t\t70F79A192639CE6F00731C46 /* ParseHealth.swift in Sources */,\n\t\t\t\t70212D132854C82B00386163 /* ParsePushFirebaseNotification.swift in Sources */,\n\t\t\t\t7044C19F25C4FA870011F6E7 /* ParseOperation+combine.swift in Sources */,\n\t\t\t\tF97B461E24D9C6F200F4A88B /* ParseStorage.swift in Sources */,\n\t\t\t\t7044C1AD25C4FC080011F6E7 /* Query+combine.swift in Sources */,\n\t\t\t\tF97B45D224D9C6F200F4A88B /* AnyDecodable.swift in Sources */,\n\t\t\t\t70C550A025B4A9F600B5DBC2 /* RemoveRelation.swift in Sources */,\n\t\t\t\t705025BD284C610C008D6624 /* ParsePush.swift in Sources */,\n\t\t\t\tF97B463B24D9C74400F4A88B /* API+Command.swift in Sources */,\n\t\t\t\tF97B464624D9C78B00F4A88B /* ParseOperation.swift in Sources */,\n\t\t\t\t7064369B273313D5007C6461 /* LiveQueryConstants.swift in Sources */,\n\t\t\t\t89899CCF2603CE3A002E2043 /* ParseFacebook.swift in Sources */,\n\t\t\t\t7028373926BD8C89007688C9 /* ParseUser+async.swift in Sources */,\n\t\t\t\t70CE0A9E28592A2B00DAEA86 /* ParseCloudUser.swift in Sources */,\n\t\t\t\t705A9A2F25991C1400B3547F /* Fileable.swift in Sources */,\n\t\t\t\t89899D342603CF36002E2043 /* ParseTwitter.swift in Sources */,\n\t\t\t\t7C55F9F12860CEEF002A352D /* ParseSpotify+combine.swift in Sources */,\n\t\t\t\t704C886C28BE69A8008E6B01 /* ParseConfiguration.swift in Sources */,\n\t\t\t\t70B4E0BC2762F1D5004C9757 /* QueryConstraint.swift in Sources */,\n\t\t\t\t70C167B427304F09009F4E30 /* Pointer+async.swift in Sources */,\n\t\t\t\t705025AE28456106008D6624 /* ParsePushStatusable.swift in Sources */,\n\t\t\t\tF97B464A24D9C78B00F4A88B /* Delete.swift in Sources */,\n\t\t\t\t705025CC284CE4C2008D6624 /* ParsePushPayloadable.swift in Sources */,\n\t\t\t\t70F03A4D2780D28A00E5AFB4 /* ParseLinkedIn+combine.swift in Sources */,\n\t\t\t\tF97B460624D9C6F200F4A88B /* ParseUser.swift in Sources */,\n\t\t\t\t70F03A3E2780CA8F00E5AFB4 /* ParseGitHub+combine.swift in Sources */,\n\t\t\t\t700396F825A394AE0052CB31 /* ParseLiveQueryDelegate.swift in Sources */,\n\t\t\t\tF97B465A24D9C78C00F4A88B /* Increment.swift in Sources */,\n\t\t\t\t7045769326BD8F8100F86F71 /* ParseInstallation+async.swift in Sources */,\n\t\t\t\t7C55F9E72860CD6B002A352D /* ParseSpotify.swift in Sources */,\n\t\t\t\t7003960925A184EF0052CB31 /* ParseLiveQuery.swift in Sources */,\n\t\t\t\t7044C17525C4ECFF0011F6E7 /* ParseCloudable+combine.swift in Sources */,\n\t\t\t\t705025B32845C302008D6624 /* ParsePushStatus.swift in Sources */,\n\t\t\t\tF97B45E224D9C6F200F4A88B /* AnyEncodable.swift in Sources */,\n\t\t\t\t700396EA25A3892D0052CB31 /* LiveQuerySocketDelegate.swift in Sources */,\n\t\t\t\t9116F66F26A35D610082F6D6 /* URLCache.swift in Sources */,\n\t\t\t\t70CE0AB2285963A300DAEA86 /* ParseHookTriggerRequest.swift in Sources */,\n\t\t\t\t709A148728396B1D00BF85E5 /* ParseField.swift in Sources */,\n\t\t\t\t70572671259033A700F0ADD5 /* ParseFileManager.swift in Sources */,\n\t\t\t\t70F03A342780CA4300E5AFB4 /* ParseGitHub.swift in Sources */,\n\t\t\t\t707A3C2025B14BD0000D215C /* ParseApple.swift in Sources */,\n\t\t\t\t703B095D26BF481F005A112F /* ParseFacebook+async.swift in Sources */,\n\t\t\t\t709A147D283949D100BF85E5 /* ParseSchema.swift in Sources */,\n\t\t\t\t704E781728CFD8A00075F952 /* ParseFileTransferable.swift in Sources */,\n\t\t\t\tF97B462224D9C6F200F4A88B /* ParseKeyValueStore.swift in Sources */,\n\t\t\t\t703B090226BD9652005A112F /* ParseAnalytics+async.swift in Sources */,\n\t\t\t\t703B093F26BF47AC005A112F /* ParseApple+async.swift in Sources */,\n\t\t\t\tF97B45E624D9C6F200F4A88B /* Query.swift in Sources */,\n\t\t\t\t703B093526BF43D9005A112F /* ParseAnonymous+async.swift in Sources */,\n\t\t\t\t705D950825BE4C08003EF6F8 /* SubscriptionCallback.swift in Sources */,\n\t\t\t\t70C5509225B4A99100B5DBC2 /* AddRelation.swift in Sources */,\n\t\t\t\t708D035225215F9B00646C70 /* Deletable.swift in Sources */,\n\t\t\t\tF97B466424D9C88600F4A88B /* SecureStorage.swift in Sources */,\n\t\t\t\t7004C22025B63C7A005E0AD9 /* ParseRelation.swift in Sources */,\n\t\t\t\t7003959525A10DFC0052CB31 /* Messages.swift in Sources */,\n\t\t\t\t703B091126BD992E005A112F /* ParseOperation+async.swift in Sources */,\n\t\t\t\t70C5655925AA147B00BDD57F /* ParseLiveQueryConstants.swift in Sources */,\n\t\t\t\t91F346BE269B77B5005727B6 /* CloudObservable.swift in Sources */,\n\t\t\t\tF97B462F24D9C74400F4A88B /* BatchUtils.swift in Sources */,\n\t\t\t\t70385E802858EAA90084D306 /* ParseHookFunctionRequest.swift in Sources */,\n\t\t\t\t70CE0AAD28595FDE00DAEA86 /* ParseHookRequestable+combine.swift in Sources */,\n\t\t\t\t4A82B7F61F254CCE0063D731 /* Parse.swift in Sources */,\n\t\t\t\tF97B45EA24D9C6F200F4A88B /* ParseGeoPoint.swift in Sources */,\n\t\t\t\tF97B460224D9C6F200F4A88B /* NoBody.swift in Sources */,\n\t\t\t\t703B093026BF42C2005A112F /* ParseAnonymous+combine.swift in Sources */,\n\t\t\t\t706436A927341FD0007C6461 /* Date.swift in Sources */,\n\t\t\t\t700395BA25A1470F0052CB31 /* Subscription.swift in Sources */,\n\t\t\t\t91285B132698DBF20051B544 /* ParseBytes.swift in Sources */,\n\t\t\t\t7016ED5625C4C32B00038648 /* ParseInstallation+combine.swift in Sources */,\n\t\t\t\t70F03A432780D21600E5AFB4 /* ParseLinkedIn.swift in Sources */,\n\t\t\t\t7003972A25A3B0140052CB31 /* ParseURLSessionDelegate.swift in Sources */,\n\t\t\t\t703B094426BF47C0005A112F /* ParseLDAP+combine.swift in Sources */,\n\t\t\t\t700395D125A147BE0052CB31 /* QuerySubscribable.swift in Sources */,\n\t\t\t\t70170A492656E2FE0070C905 /* ParseAnalytics+combine.swift in Sources */,\n\t\t\t\t703B092B26BF290B005A112F /* ParseAuthentication+async.swift in Sources */,\n\t\t\t\t70CE0AB7285A83B100DAEA86 /* ParseHookable.swift in Sources */,\n\t\t\t\tF97B45F624D9C6F200F4A88B /* ParseError.swift in Sources */,\n\t\t\t\t7045769D26BD934000F86F71 /* ParseFile+async.swift in Sources */,\n\t\t\t\tF97B463324D9C74400F4A88B /* URLSession.swift in Sources */,\n\t\t\t\tF97B464E24D9C78B00F4A88B /* Add.swift in Sources */,\n\t\t\t\t70D41D8028B520E200613510 /* ParseKeychainAccessGroup.swift in Sources */,\n\t\t\t\t70385E762858E1000084D306 /* ParseHookFunctionable.swift in Sources */,\n\t\t\t\t703B095326BF47FD005A112F /* ParseTwitter+async.swift in Sources */,\n\t\t\t\t70CE0ABC285F8FF900DAEA86 /* ParseTypeable.swift in Sources */,\n\t\t\t\t70BC9890252A5B5C00FF3074 /* Objectable.swift in Sources */,\n\t\t\t\tF97B45FE24D9C6F200F4A88B /* ParseFile.swift in Sources */,\n\t\t\t\tF97B45EE24D9C6F200F4A88B /* BaseParseUser.swift in Sources */,\n\t\t\t\t706436A427341F6E007C6461 /* Encodable.swift in Sources */,\n\t\t\t\tF97B460A24D9C6F200F4A88B /* Fetchable.swift in Sources */,\n\t\t\t\t70CE0A9428590A0A00DAEA86 /* ParseHookResponse.swift in Sources */,\n\t\t\t\t70F03A482780D27700E5AFB4 /* ParseLinkedIn+async.swift in Sources */,\n\t\t\t\t70CE0AA328595E5E00DAEA86 /* ParseHookRequestable.swift in Sources */,\n\t\t\t\t703B090C26BD984D005A112F /* ParseConfig+async.swift in Sources */,\n\t\t\t\tF97B460E24D9C6F200F4A88B /* ParseObject.swift in Sources */,\n\t\t\t\t70F03A272780BE0F00E5AFB4 /* ParseGoogle+combine.swift in Sources */,\n\t\t\t\tF97B461224D9C6F200F4A88B /* Savable.swift in Sources */,\n\t\t\t\t703B094926BF47D0005A112F /* ParseLDAP+async.swift in Sources */,\n\t\t\t\tF97B45CE24D9C6F200F4A88B /* ParseCoding.swift in Sources */,\n\t\t\t\t70CE0AA828595FCE00DAEA86 /* ParseHookRequestable+async.swift in Sources */,\n\t\t\t\tF97B465624D9C78C00F4A88B /* Remove.swift in Sources */,\n\t\t\t\tF97B45FA24D9C6F200F4A88B /* ParseACL.swift in Sources */,\n\t\t\t\t7016ED6425C4C46B00038648 /* ParseObject+combine.swift in Sources */,\n\t\t\t\t705025F02851542D008D6624 /* ParsePushFirebasePayloadable.swift in Sources */,\n\t\t\t\t705025DB284D0D56008D6624 /* ParsePushAppleSound.swift in Sources */,\n\t\t\t\t70BDA2B3250536FF00FC2237 /* ParseInstallation.swift in Sources */,\n\t\t\t\t70CE0ACB285FD5CB00DAEA86 /* ParseHookTriggerable+async.swift in Sources */,\n\t\t\t\t705025C2284C7842008D6624 /* ParsePush+async.swift in Sources */,\n\t\t\t\tF97B462724D9C72700F4A88B /* API.swift in Sources */,\n\t\t\t\t70647E9C259E3A9A004C1004 /* ParseEncodable.swift in Sources */,\n\t\t\t\t707A3C1125B0A8E8000D215C /* ParseAnonymous.swift in Sources */,\n\t\t\t\t70110D572506CE890091CC1D /* BaseParseInstallation.swift in Sources */,\n\t\t\t\t70F03A392780CA6F00E5AFB4 /* ParseGitHub+async.swift in Sources */,\n\t\t\t\tF97B45DE24D9C6F200F4A88B /* AnyCodable.swift in Sources */,\n\t\t\t\t705025E02851006F008D6624 /* ParsePushPayloadFirebase.swift in Sources */,\n\t\t\t\t70C5507725B49D3A00B5DBC2 /* ParseRole.swift in Sources */,\n\t\t\t\t703B093A26BF4799005A112F /* ParseApple+combine.swift in Sources */,\n\t\t\t\t7044C18325C4EFC10011F6E7 /* ParseConfig+combine.swift in Sources */,\n\t\t\t\t7016ED3225C3BA2000038648 /* ParseUser+combine.swift in Sources */,\n\t\t\t\t703B091626BD99BC005A112F /* ParseLiveQuery+async.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4AB8B4F91F254AE10070F682 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t918CED5E268618C600CFDC83 /* ParseLiveQueryCombineTests.swift in Sources */,\n\t\t\t\t91679D6D268F261800F71809 /* ParseVersionTests.swift in Sources */,\n\t\t\t\t917BA44E2703F2B400F8D747 /* ParseFacebookAsyncTests.swift in Sources */,\n\t\t\t\t7C995D292861FA0B0077805A /* ParseSpotifyAsyncTests.swift in Sources */,\n\t\t\t\t911DB13624C4FC100027F3C7 /* ParseObjectTests.swift in Sources */,\n\t\t\t\t70C167B927305101009F4E30 /* ParsePointerAsyncTests.swift in Sources */,\n\t\t\t\t70F03A662780EAFA00E5AFB4 /* ParseLinkedInTests.swift in Sources */,\n\t\t\t\t70E09E1C262F0634002DD451 /* ParsePointerCombineTests.swift in Sources */,\n\t\t\t\t89899D592603CF3E002E2043 /* ParseTwitterTests.swift in Sources */,\n\t\t\t\t70CE1D892545BF730018D572 /* ParsePointerTests.swift in Sources */,\n\t\t\t\t70E6B022286131720043EC4A /* ParseHookTriggerCombineTests.swift in Sources */,\n\t\t\t\t89899D772603CF66002E2043 /* ParseFacebookTests.swift in Sources */,\n\t\t\t\t7C4C0943285EA56E00F202C6 /* ParseInstagramCombineTests.swift in Sources */,\n\t\t\t\t70386A4625D99C8B0048EC1B /* ParseLDAPTests.swift in Sources */,\n\t\t\t\t709B40C1268F999000ED2EAC /* IOS13Tests.swift in Sources */,\n\t\t\t\t91285B182698E66D0051B544 /* ParseBytesTests.swift in Sources */,\n\t\t\t\t917BA4522703F55700F8D747 /* ParseTwitterAsyncTests.swift in Sources */,\n\t\t\t\t911DB12E24C4837E0027F3C7 /* APICommandTests.swift in Sources */,\n\t\t\t\t70385E6428563FD10084D306 /* ParsePushPayloadFirebaseTests.swift in Sources */,\n\t\t\t\t70732C5A2606CCAD000CAB81 /* ParseObjectCustomObjectIdTests.swift in Sources */,\n\t\t\t\t911DB12C24C3F7720027F3C7 /* MockURLResponse.swift in Sources */,\n\t\t\t\t7044C24325C5EA360011F6E7 /* ParseAppleCombineTests.swift in Sources */,\n\t\t\t\t7C995D2D2861FAE40077805A /* ParseSpotifyCombineTests.swift in Sources */,\n\t\t\t\t70DFEA8A2618E77800F8EB4B /* InitializeSDKTests.swift in Sources */,\n\t\t\t\t91285B2126991EE80051B544 /* ParsePolygonTests.swift in Sources */,\n\t\t\t\t70170A4E2656EBA50070C905 /* ParseAnalyticsTests.swift in Sources */,\n\t\t\t\t7C4C093F285EA3A000F202C6 /* ParseInstagramTests.swift in Sources */,\n\t\t\t\t70E6B01A28612A820043EC4A /* ParseHookFunctionCombineTests.swift in Sources */,\n\t\t\t\t703B091F26BDE78D005A112F /* ParseObjectAsyncTests.swift in Sources */,\n\t\t\t\t917BA4362703E4CB00F8D747 /* ParseFileAsyncTests.swift in Sources */,\n\t\t\t\t70E6B02A28614C5F0043EC4A /* ParseHookFunctionRequestCombineTests.swift in Sources */,\n\t\t\t\t7044C1DF25C5C70D0011F6E7 /* ParseObjectCombineTests.swift in Sources */,\n\t\t\t\t70212D2E2855266400386163 /* ParsePushCombineTests.swift in Sources */,\n\t\t\t\t700AFE03289C3508006C1CD9 /* ParseQueryCacheTests.swift in Sources */,\n\t\t\t\t70E6B026286132BC0043EC4A /* ParseHookFunctionRequestTests.swift in Sources */,\n\t\t\t\t70F03A622780EADD00E5AFB4 /* ParseLinkedInCombineTests.swift in Sources */,\n\t\t\t\t89899D9F26045998002E2043 /* ParseTwitterCombineTests.swift in Sources */,\n\t\t\t\t70212D2B2855266400386163 /* ParsePushPayloadAppleTests.swift in Sources */,\n\t\t\t\t917BA43A2703E6D800F8D747 /* ParseHealthAsyncTests.swift in Sources */,\n\t\t\t\t917BA4462703EEA700F8D747 /* ParseAnonymousAsyncTests.swift in Sources */,\n\t\t\t\t70F79A672639DE9700731C46 /* ParseHealthCombineTests.swift in Sources */,\n\t\t\t\t91CB9537265966DF0043E5D6 /* ParseAnalyticsCombineTests.swift in Sources */,\n\t\t\t\t703B092326BDFAB2005A112F /* ParseUserAsyncTests.swift in Sources */,\n\t\t\t\t70E6B016286120E00043EC4A /* ParseHookFunctionTests.swift in Sources */,\n\t\t\t\t70C5504625B40D5200B5DBC2 /* ParseSessionTests.swift in Sources */,\n\t\t\t\t70110D5C2506ED0E0091CC1D /* ParseInstallationTests.swift in Sources */,\n\t\t\t\t70F03A562780E8E300E5AFB4 /* ParseGoogleCombineTests.swift in Sources */,\n\t\t\t\t7C4C0947285EA60E00F202C6 /* ParseInstagramAsyncTests.swift in Sources */,\n\t\t\t\t917BA4422703EAC700F8D747 /* ParseLiveQueryAsyncTests.swift in Sources */,\n\t\t\t\t7C995D252861F8330077805A /* ParseSpotifyTests.swift in Sources */,\n\t\t\t\t7016ED4025C4A25A00038648 /* ParseUserCombineTests.swift in Sources */,\n\t\t\t\t91F346C3269B88F7005727B6 /* ParseCloudViewModelTests.swift in Sources */,\n\t\t\t\t917BA4262703DB4600F8D747 /* ParseQueryAsyncTests.swift in Sources */,\n\t\t\t\t70E6B02E28614E480043EC4A /* ParseHookTriggerRequestTests.swift in Sources */,\n\t\t\t\t91B40651267A66ED00B129CD /* ParseErrorTests.swift in Sources */,\n\t\t\t\t705727B12593FF8800F0ADD5 /* ParseFileTests.swift in Sources */,\n\t\t\t\t917BA42A2703E03F00F8D747 /* ParseAnalyticsAsyncTests.swift in Sources */,\n\t\t\t\t70BC0B33251903D1001556DB /* ParseGeoPointTests.swift in Sources */,\n\t\t\t\t7003957625A0EE770052CB31 /* BatchUtilsTests.swift in Sources */,\n\t\t\t\t705025992842FD3B008D6624 /* ParseCLPTests.swift in Sources */,\n\t\t\t\t705A99F9259807F900B3547F /* ParseFileManagerTests.swift in Sources */,\n\t\t\t\t70F03A522780DA9200E5AFB4 /* ParseGoogleTests.swift in Sources */,\n\t\t\t\t7044C20625C5D6780011F6E7 /* ParseQueryCombineTests.swift in Sources */,\n\t\t\t\t70C5508525B4A68700B5DBC2 /* ParseOperationTests.swift in Sources */,\n\t\t\t\t7023800F2747FCCD00EFC443 /* ExtensionsTests.swift in Sources */,\n\t\t\t\t704E782128D0D73E0075F952 /* ParseFileTransferableTests.swift in Sources */,\n\t\t\t\t917BA43E2703E84000F8D747 /* ParseOperationAsyncTests.swift in Sources */,\n\t\t\t\t7037DAB226384DE1005D7E62 /* TestParseEncoder.swift in Sources */,\n\t\t\t\t7004C24D25B69207005E0AD9 /* ParseRoleTests.swift in Sources */,\n\t\t\t\t917BA42E2703E20E00F8D747 /* ParseCloudableAsyncTests.swift in Sources */,\n\t\t\t\t70D41D6728B0235100613510 /* MigrateObjCSDKTests.swift in Sources */,\n\t\t\t\t91678706259BC5D400BB5B4E /* ParseCloudableTests.swift in Sources */,\n\t\t\t\t70386A5C25D9A4020048EC1B /* ParseLDAPCombineTests.swift in Sources */,\n\t\t\t\t70D41D6B28B294C100613510 /* MigrateObjCSDKCombineTests.swift in Sources */,\n\t\t\t\t70D1BD8725B8C37200A42E7C /* ParseRelationTests.swift in Sources */,\n\t\t\t\t7003963B25A288100052CB31 /* ParseLiveQueryTests.swift in Sources */,\n\t\t\t\t70E6B032286152550043EC4A /* ParseHookTriggerRequestCombineTests.swift in Sources */,\n\t\t\t\t70F03A5A2780EAB000E5AFB4 /* ParseGitHubCombineTests.swift in Sources */,\n\t\t\t\t7FFF552E2217E72A007C3B4E /* AnyEncodableTests.swift in Sources */,\n\t\t\t\t7044C22025C5E0160011F6E7 /* ParseConfigCombineTests.swift in Sources */,\n\t\t\t\t7FFF55302217E72A007C3B4E /* AnyDecodableTests.swift in Sources */,\n\t\t\t\t70212D2C2855266400386163 /* ParsePushTests.swift in Sources */,\n\t\t\t\t7050259D2843F0CF008D6624 /* ParseSchemaAsyncTests.swift in Sources */,\n\t\t\t\t70C7DC2224D20F190050419B /* ParseObjectBatchTests.swift in Sources */,\n\t\t\t\t7044C1BB25C52E410011F6E7 /* ParseInstallationCombineTests.swift in Sources */,\n\t\t\t\t917BA45A2703FD2200F8D747 /* ParseAuthenticationAsyncTests.swift in Sources */,\n\t\t\t\t7FFF552F2217E72A007C3B4E /* AnyCodableTests.swift in Sources */,\n\t\t\t\t70212D2D2855266400386163 /* ParsePushAsyncTests.swift in Sources */,\n\t\t\t\t703B092726BE0719005A112F /* ParseInstallationAsyncTests.swift in Sources */,\n\t\t\t\t70F03A5E2780EAC700E5AFB4 /* ParseGitHubTests.swift in Sources */,\n\t\t\t\t4AA807701F794C31008CD551 /* KeychainStoreTests.swift in Sources */,\n\t\t\t\t7085DDB326D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift in Sources */,\n\t\t\t\t70E6B01E28612FF00043EC4A /* ParseHookTriggerTests.swift in Sources */,\n\t\t\t\t705025A12843F0E7008D6624 /* ParseSchemaCombineTests.swift in Sources */,\n\t\t\t\t7044C1F925C5CFAB0011F6E7 /* ParseFileCombineTests.swift in Sources */,\n\t\t\t\t70C5502225B3D8F700B5DBC2 /* ParseAppleTests.swift in Sources */,\n\t\t\t\t917BA4322703E36800F8D747 /* ParseConfigAsyncTests.swift in Sources */,\n\t\t\t\t89899DB526045DC4002E2043 /* ParseFacebookCombineTests.swift in Sources */,\n\t\t\t\tF971F4F624DE381A006CB79B /* ParseEncoderExtraTests.swift in Sources */,\n\t\t\t\t70E6B036286289FF0043EC4A /* ParseHookResponseTests.swift in Sources */,\n\t\t\t\t70C7DC2124D20F190050419B /* ParseQueryTests.swift in Sources */,\n\t\t\t\t917BA4562703F75E00F8D747 /* ParseLDAPAsyncTests.swift in Sources */,\n\t\t\t\t70385E68285640A30084D306 /* ParsePushPayloadAnyTests.swift in Sources */,\n\t\t\t\t70F79A732639DEA000731C46 /* ParseHealthTests.swift in Sources */,\n\t\t\t\t7044C22D25C5E4E90011F6E7 /* ParseAnonymousCombineTests.swift in Sources */,\n\t\t\t\t9194657824F16E330070296B /* ParseACLTests.swift in Sources */,\n\t\t\t\t7044C21325C5DE490011F6E7 /* ParseCloudableCombineTests.swift in Sources */,\n\t\t\t\t70A2D86B25B3ADB6001BEB7D /* ParseAnonymousTests.swift in Sources */,\n\t\t\t\t7044C1EC25C5CC930011F6E7 /* ParseOperationCombineTests.swift in Sources */,\n\t\t\t\t70C7DC1E24D20E530050419B /* ParseUserTests.swift in Sources */,\n\t\t\t\t70A2D81F25B36A7D001BEB7D /* ParseAuthenticationTests.swift in Sources */,\n\t\t\t\t70D1BE4B25BB312700A42E7C /* ParseConfigTests.swift in Sources */,\n\t\t\t\t91BB8FD42690D586005A6BA5 /* ParseQueryViewModelTests.swift in Sources */,\n\t\t\t\t911DB13324C494390027F3C7 /* MockURLProtocol.swift in Sources */,\n\t\t\t\t917BA44A2703F10400F8D747 /* ParseAppleAsyncTests.swift in Sources */,\n\t\t\t\t705025A5284407C4008D6624 /* ParseSchemaTests.swift in Sources */,\n\t\t\t\t708CADCF2872263D0066C279 /* ParseKeychainAccessGroupTests.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t4AFDA70D1F26D9A5002AE4FC /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tF97B463824D9C74400F4A88B /* Responses.swift in Sources */,\n\t\t\t\t7C55F9ED2860CEA6002A352D /* ParseSpotify+async.swift in Sources */,\n\t\t\t\t916786E3259B7DDA00BB5B4E /* ParseCloudable.swift in Sources */,\n\t\t\t\t70CE0AC7285FD5A800DAEA86 /* ParseHookFunctionable+combine.swift in Sources */,\n\t\t\t\t91F346BA269B766D005727B6 /* CloudViewModel.swift in Sources */,\n\t\t\t\t708EF0C328D5FDF10052EF35 /* API+NonParseBodyCommand+async.swift in Sources */,\n\t\t\t\t709A148D2839A1DB00BF85E5 /* Operation.swift in Sources */,\n\t\t\t\t70CE0AD1285FD5D700DAEA86 /* ParseHookTriggerable+combine.swift in Sources */,\n\t\t\t\t709A14A6283AAF4C00BF85E5 /* ParseSchema+combine.swift in Sources */,\n\t\t\t\tF97B461724D9C6F200F4A88B /* Queryable.swift in Sources */,\n\t\t\t\t7028373526BD8883007688C9 /* ParseObject+async.swift in Sources */,\n\t\t\t\t705025C8284C7883008D6624 /* ParsePush+combine.swift in Sources */,\n\t\t\t\t70C5503925B406B800B5DBC2 /* ParseSession.swift in Sources */,\n\t\t\t\t7044C1C925C5B2B10011F6E7 /* ParseAuthentication+combine.swift in Sources */,\n\t\t\t\t707A3BF225B0A4F0000D215C /* ParseAuthentication.swift in Sources */,\n\t\t\t\t70D1BE7425BB43EB00A42E7C /* BaseConfig.swift in Sources */,\n\t\t\t\t703B090826BD9764005A112F /* ParseCloudable+async.swift in Sources */,\n\t\t\t\t918CED5A2684C74000CFDC83 /* ParseLiveQuery+combine.swift in Sources */,\n\t\t\t\t70386A0725D9718C0048EC1B /* Data.swift in Sources */,\n\t\t\t\tF97B466024D9C7B500F4A88B /* KeychainStore.swift in Sources */,\n\t\t\t\t70B4E0C22762F313004C9757 /* QueryWhere.swift in Sources */,\n\t\t\t\t70170A452656B02D0070C905 /* ParseAnalytics.swift in Sources */,\n\t\t\t\t70110D53250680140091CC1D /* ParseConstants.swift in Sources */,\n\t\t\t\t91B79AC426EE3A4E00073F2C /* API+NonParseBodyCommand.swift in Sources */,\n\t\t\t\t708EF0BE28D5F4140052EF35 /* API+Command+async.swift in Sources */,\n\t\t\t\t70D1BDBB25BB17A600A42E7C /* ParseConfig.swift in Sources */,\n\t\t\t\t7C4C092C285E746800F202C6 /* ParseInstagram.swift in Sources */,\n\t\t\t\t703B08FE26BD953B005A112F /* ParseHealth+async.swift in Sources */,\n\t\t\t\t7085DDA426CC8A470033B977 /* ParseHealth+combine.swift in Sources */,\n\t\t\t\t70CE0AC2285FD59B00DAEA86 /* ParseHookFunctionable+async.swift in Sources */,\n\t\t\t\tF97B465324D9C78C00F4A88B /* AddUnique.swift in Sources */,\n\t\t\t\t70C048C22880D7E600401689 /* Dictionary.swift in Sources */,\n\t\t\t\t91B79AC926EE3C5D00073F2C /* API+BatchCommand.swift in Sources */,\n\t\t\t\t70385E722858D2DD0084D306 /* ParseHookTriggerable.swift in Sources */,\n\t\t\t\t91679D65268E596300F71809 /* ParseVersion.swift in Sources */,\n\t\t\t\t91285B1D26990D7F0051B544 /* ParsePolygon.swift in Sources */,\n\t\t\t\t91BB8FCB2690AC99005A6BA5 /* QueryViewModel.swift in Sources */,\n\t\t\t\t7085DD9526CBF3A70033B977 /* Documentation.docc in Sources */,\n\t\t\t\t705025EC285153BC008D6624 /* ParsePushApplePayloadable.swift in Sources */,\n\t\t\t\t705025AA28441C96008D6624 /* ParseFieldOptions.swift in Sources */,\n\t\t\t\tF97B45D724D9C6F200F4A88B /* ParseEncoder.swift in Sources */,\n\t\t\t\t7C4C093B285E9A3700F202C6 /* ParseInstagram+combine.swift in Sources */,\n\t\t\t\t700395A425A119430052CB31 /* Operations.swift in Sources */,\n\t\t\t\t91BB8FD02690BA70005A6BA5 /* QueryObservable.swift in Sources */,\n\t\t\t\t7045769926BD917500F86F71 /* Query+async.swift in Sources */,\n\t\t\t\t705025E728514F36008D6624 /* ParsePushPayloadAny.swift in Sources */,\n\t\t\t\t709A148328395ED100BF85E5 /* ParseSchema+async.swift in Sources */,\n\t\t\t\t705025D2284CFCDE008D6624 /* ParsePushAppleAlert.swift in Sources */,\n\t\t\t\t704E781D28CFFAF80075F952 /* ParseFileDefaultTransfer.swift in Sources */,\n\t\t\t\t703B094F26BF47E3005A112F /* ParseTwitter+combine.swift in Sources */,\n\t\t\t\t70386A3925D998D90048EC1B /* ParseLDAP.swift in Sources */,\n\t\t\t\t700395F325A171320052CB31 /* LiveQueryable.swift in Sources */,\n\t\t\t\t709A14A12839CABD00BF85E5 /* ParseCLP.swift in Sources */,\n\t\t\t\tF97B45F324D9C6F200F4A88B /* Pointer.swift in Sources */,\n\t\t\t\t703B095926BF480D005A112F /* ParseFacebook+combine.swift in Sources */,\n\t\t\t\t70510AAD259EE25E00FEA700 /* LiveQuerySocket.swift in Sources */,\n\t\t\t\t70C167B027304EE4009F4E30 /* Pointer+combine.swift in Sources */,\n\t\t\t\t7C4C0931285E986F00F202C6 /* ParseInstagram+async.swift in Sources */,\n\t\t\t\t705025D7284D0C1D008D6624 /* ParsePushPayloadApple.swift in Sources */,\n\t\t\t\t7044C19225C4F5B60011F6E7 /* ParseFile+combine.swift in Sources */,\n\t\t\t\t70F79A1A2639CE6F00731C46 /* ParseHealth.swift in Sources */,\n\t\t\t\t7044C1A025C4FA870011F6E7 /* ParseOperation+combine.swift in Sources */,\n\t\t\t\t70A98D832794AB3C009B58F2 /* ParseQueryScorable.swift in Sources */,\n\t\t\t\t70385E862858F9750084D306 /* ParseHookParametable.swift in Sources */,\n\t\t\t\tF97B461F24D9C6F200F4A88B /* ParseStorage.swift in Sources */,\n\t\t\t\t70212D142854C82B00386163 /* ParsePushFirebaseNotification.swift in Sources */,\n\t\t\t\t7044C1AE25C4FC080011F6E7 /* Query+combine.swift in Sources */,\n\t\t\t\tF97B45D324D9C6F200F4A88B /* AnyDecodable.swift in Sources */,\n\t\t\t\t70C550A125B4A9F600B5DBC2 /* RemoveRelation.swift in Sources */,\n\t\t\t\tF97B463C24D9C74400F4A88B /* API+Command.swift in Sources */,\n\t\t\t\tF97B464724D9C78B00F4A88B /* ParseOperation.swift in Sources */,\n\t\t\t\t705025BE284C610C008D6624 /* ParsePush.swift in Sources */,\n\t\t\t\t7064369C273313D5007C6461 /* LiveQueryConstants.swift in Sources */,\n\t\t\t\t89899CD02603CE3A002E2043 /* ParseFacebook.swift in Sources */,\n\t\t\t\t70F03A282780BE2900E5AFB4 /* ParseGoogle+async.swift in Sources */,\n\t\t\t\t7028373A26BD8C89007688C9 /* ParseUser+async.swift in Sources */,\n\t\t\t\t705A9A3025991C1400B3547F /* Fileable.swift in Sources */,\n\t\t\t\t70CE0A9F28592A2B00DAEA86 /* ParseCloudUser.swift in Sources */,\n\t\t\t\t89899D332603CF36002E2043 /* ParseTwitter.swift in Sources */,\n\t\t\t\t70B4E0BD2762F1D5004C9757 /* QueryConstraint.swift in Sources */,\n\t\t\t\t7C55F9F22860CEEF002A352D /* ParseSpotify+combine.swift in Sources */,\n\t\t\t\t704C886D28BE69A8008E6B01 /* ParseConfiguration.swift in Sources */,\n\t\t\t\t70C167B527304F09009F4E30 /* Pointer+async.swift in Sources */,\n\t\t\t\tF97B464B24D9C78B00F4A88B /* Delete.swift in Sources */,\n\t\t\t\t705025AF28456106008D6624 /* ParsePushStatusable.swift in Sources */,\n\t\t\t\tF97B460724D9C6F200F4A88B /* ParseUser.swift in Sources */,\n\t\t\t\t705025CD284CE4C2008D6624 /* ParsePushPayloadable.swift in Sources */,\n\t\t\t\t70F03A4E2780D28A00E5AFB4 /* ParseLinkedIn+combine.swift in Sources */,\n\t\t\t\t700396F925A394AE0052CB31 /* ParseLiveQueryDelegate.swift in Sources */,\n\t\t\t\t70F03A3F2780CA8F00E5AFB4 /* ParseGitHub+combine.swift in Sources */,\n\t\t\t\tF97B465B24D9C78C00F4A88B /* Increment.swift in Sources */,\n\t\t\t\t7045769426BD8F8100F86F71 /* ParseInstallation+async.swift in Sources */,\n\t\t\t\t7003960A25A184EF0052CB31 /* ParseLiveQuery.swift in Sources */,\n\t\t\t\t7C55F9E82860CD6B002A352D /* ParseSpotify.swift in Sources */,\n\t\t\t\t7044C17625C4ECFF0011F6E7 /* ParseCloudable+combine.swift in Sources */,\n\t\t\t\tF97B45E324D9C6F200F4A88B /* AnyEncodable.swift in Sources */,\n\t\t\t\t705025B42845C302008D6624 /* ParsePushStatus.swift in Sources */,\n\t\t\t\t700396EB25A3892D0052CB31 /* LiveQuerySocketDelegate.swift in Sources */,\n\t\t\t\t9116F67026A35D610082F6D6 /* URLCache.swift in Sources */,\n\t\t\t\t70572672259033A700F0ADD5 /* ParseFileManager.swift in Sources */,\n\t\t\t\t70CE0AB3285963A300DAEA86 /* ParseHookTriggerRequest.swift in Sources */,\n\t\t\t\t709A148828396B1D00BF85E5 /* ParseField.swift in Sources */,\n\t\t\t\t707A3C2125B14BD0000D215C /* ParseApple.swift in Sources */,\n\t\t\t\t70F03A352780CA4D00E5AFB4 /* ParseGitHub.swift in Sources */,\n\t\t\t\t703B095E26BF481F005A112F /* ParseFacebook+async.swift in Sources */,\n\t\t\t\tF97B462324D9C6F200F4A88B /* ParseKeyValueStore.swift in Sources */,\n\t\t\t\t709A147E283949D100BF85E5 /* ParseSchema.swift in Sources */,\n\t\t\t\t704E781828CFD8A00075F952 /* ParseFileTransferable.swift in Sources */,\n\t\t\t\t703B090326BD9652005A112F /* ParseAnalytics+async.swift in Sources */,\n\t\t\t\t703B094026BF47AC005A112F /* ParseApple+async.swift in Sources */,\n\t\t\t\tF97B45E724D9C6F200F4A88B /* Query.swift in Sources */,\n\t\t\t\t703B093626BF43D9005A112F /* ParseAnonymous+async.swift in Sources */,\n\t\t\t\t705D950925BE4C08003EF6F8 /* SubscriptionCallback.swift in Sources */,\n\t\t\t\t70C5509325B4A99100B5DBC2 /* AddRelation.swift in Sources */,\n\t\t\t\t708D035325215F9B00646C70 /* Deletable.swift in Sources */,\n\t\t\t\tF97B466524D9C88600F4A88B /* SecureStorage.swift in Sources */,\n\t\t\t\t7004C22125B63C7A005E0AD9 /* ParseRelation.swift in Sources */,\n\t\t\t\t7003959625A10DFC0052CB31 /* Messages.swift in Sources */,\n\t\t\t\t703B091226BD992E005A112F /* ParseOperation+async.swift in Sources */,\n\t\t\t\t70C5655A25AA147B00BDD57F /* ParseLiveQueryConstants.swift in Sources */,\n\t\t\t\t91F346BF269B77B5005727B6 /* CloudObservable.swift in Sources */,\n\t\t\t\tF97B463024D9C74400F4A88B /* BatchUtils.swift in Sources */,\n\t\t\t\t4AFDA72A1F26DAE1002AE4FC /* Parse.swift in Sources */,\n\t\t\t\t70385E812858EAA90084D306 /* ParseHookFunctionRequest.swift in Sources */,\n\t\t\t\t70CE0AAE28595FDE00DAEA86 /* ParseHookRequestable+combine.swift in Sources */,\n\t\t\t\tF97B45EB24D9C6F200F4A88B /* ParseGeoPoint.swift in Sources */,\n\t\t\t\tF97B460324D9C6F200F4A88B /* NoBody.swift in Sources */,\n\t\t\t\t703B093126BF42C2005A112F /* ParseAnonymous+combine.swift in Sources */,\n\t\t\t\t706436AA27341FD0007C6461 /* Date.swift in Sources */,\n\t\t\t\t700395BB25A1470F0052CB31 /* Subscription.swift in Sources */,\n\t\t\t\t91285B142698DBF20051B544 /* ParseBytes.swift in Sources */,\n\t\t\t\t7016ED5725C4C32B00038648 /* ParseInstallation+combine.swift in Sources */,\n\t\t\t\t7003972B25A3B0140052CB31 /* ParseURLSessionDelegate.swift in Sources */,\n\t\t\t\t70F03A442780D21600E5AFB4 /* ParseLinkedIn.swift in Sources */,\n\t\t\t\t703B094526BF47C0005A112F /* ParseLDAP+combine.swift in Sources */,\n\t\t\t\t700395D225A147BE0052CB31 /* QuerySubscribable.swift in Sources */,\n\t\t\t\t70170A4A2656E2FE0070C905 /* ParseAnalytics+combine.swift in Sources */,\n\t\t\t\t703B092C26BF290B005A112F /* ParseAuthentication+async.swift in Sources */,\n\t\t\t\t70F03A292780BE2900E5AFB4 /* ParseGoogle.swift in Sources */,\n\t\t\t\t70CE0AB8285A83B100DAEA86 /* ParseHookable.swift in Sources */,\n\t\t\t\tF97B45F724D9C6F200F4A88B /* ParseError.swift in Sources */,\n\t\t\t\t7045769E26BD934000F86F71 /* ParseFile+async.swift in Sources */,\n\t\t\t\tF97B463424D9C74400F4A88B /* URLSession.swift in Sources */,\n\t\t\t\tF97B464F24D9C78B00F4A88B /* Add.swift in Sources */,\n\t\t\t\t70D41D8128B520E200613510 /* ParseKeychainAccessGroup.swift in Sources */,\n\t\t\t\t70385E772858E1000084D306 /* ParseHookFunctionable.swift in Sources */,\n\t\t\t\t703B095426BF47FD005A112F /* ParseTwitter+async.swift in Sources */,\n\t\t\t\t70CE0ABD285F8FF900DAEA86 /* ParseTypeable.swift in Sources */,\n\t\t\t\t70BC9891252A5B5C00FF3074 /* Objectable.swift in Sources */,\n\t\t\t\tF97B45FF24D9C6F200F4A88B /* ParseFile.swift in Sources */,\n\t\t\t\tF97B45EF24D9C6F200F4A88B /* BaseParseUser.swift in Sources */,\n\t\t\t\t706436A527341F6E007C6461 /* Encodable.swift in Sources */,\n\t\t\t\tF97B460B24D9C6F200F4A88B /* Fetchable.swift in Sources */,\n\t\t\t\t70CE0A9528590A0A00DAEA86 /* ParseHookResponse.swift in Sources */,\n\t\t\t\t70F03A492780D27700E5AFB4 /* ParseLinkedIn+async.swift in Sources */,\n\t\t\t\t70CE0AA428595E5E00DAEA86 /* ParseHookRequestable.swift in Sources */,\n\t\t\t\t703B090D26BD984D005A112F /* ParseConfig+async.swift in Sources */,\n\t\t\t\tF97B460F24D9C6F200F4A88B /* ParseObject.swift in Sources */,\n\t\t\t\t70F03A2A2780BE2900E5AFB4 /* ParseGoogle+combine.swift in Sources */,\n\t\t\t\tF97B461324D9C6F200F4A88B /* Savable.swift in Sources */,\n\t\t\t\t703B094A26BF47D0005A112F /* ParseLDAP+async.swift in Sources */,\n\t\t\t\tF97B45CF24D9C6F200F4A88B /* ParseCoding.swift in Sources */,\n\t\t\t\t70CE0AA928595FCE00DAEA86 /* ParseHookRequestable+async.swift in Sources */,\n\t\t\t\tF97B465724D9C78C00F4A88B /* Remove.swift in Sources */,\n\t\t\t\tF97B45FB24D9C6F200F4A88B /* ParseACL.swift in Sources */,\n\t\t\t\t7016ED6525C4C46B00038648 /* ParseObject+combine.swift in Sources */,\n\t\t\t\t705025F12851542D008D6624 /* ParsePushFirebasePayloadable.swift in Sources */,\n\t\t\t\t705025DC284D0D56008D6624 /* ParsePushAppleSound.swift in Sources */,\n\t\t\t\t70BDA2B4250536FF00FC2237 /* ParseInstallation.swift in Sources */,\n\t\t\t\t70CE0ACC285FD5CB00DAEA86 /* ParseHookTriggerable+async.swift in Sources */,\n\t\t\t\t705025C3284C7842008D6624 /* ParsePush+async.swift in Sources */,\n\t\t\t\tF97B462824D9C72700F4A88B /* API.swift in Sources */,\n\t\t\t\t70647E9D259E3A9A004C1004 /* ParseEncodable.swift in Sources */,\n\t\t\t\t707A3C1225B0A8E8000D215C /* ParseAnonymous.swift in Sources */,\n\t\t\t\t70110D582506CE890091CC1D /* BaseParseInstallation.swift in Sources */,\n\t\t\t\t70F03A3A2780CA6F00E5AFB4 /* ParseGitHub+async.swift in Sources */,\n\t\t\t\tF97B45DF24D9C6F200F4A88B /* AnyCodable.swift in Sources */,\n\t\t\t\t705025E12851006F008D6624 /* ParsePushPayloadFirebase.swift in Sources */,\n\t\t\t\t70C5507825B49D3A00B5DBC2 /* ParseRole.swift in Sources */,\n\t\t\t\t703B093B26BF4799005A112F /* ParseApple+combine.swift in Sources */,\n\t\t\t\t7044C18425C4EFC10011F6E7 /* ParseConfig+combine.swift in Sources */,\n\t\t\t\t7016ED3325C3BA2000038648 /* ParseUser+combine.swift in Sources */,\n\t\t\t\t703B091726BD99BC005A112F /* ParseLiveQuery+async.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t7033ECAC25584A83009770F3 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t7033ECB525584A83009770F3 /* ViewController.swift in Sources */,\n\t\t\t\t7033ECB325584A83009770F3 /* AppDelegate.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t709B982C2556EC7400507778 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t918CED60268618C600CFDC83 /* ParseLiveQueryCombineTests.swift in Sources */,\n\t\t\t\t91679D6F268F261A00F71809 /* ParseVersionTests.swift in Sources */,\n\t\t\t\t917BA4502703F2B400F8D747 /* ParseFacebookAsyncTests.swift in Sources */,\n\t\t\t\t7C995D2B2861FA0B0077805A /* ParseSpotifyAsyncTests.swift in Sources */,\n\t\t\t\t709B98512556ECAA00507778 /* ParseEncoderExtraTests.swift in Sources */,\n\t\t\t\t70C167BB27305101009F4E30 /* ParsePointerAsyncTests.swift in Sources */,\n\t\t\t\t70F03A682780EAFA00E5AFB4 /* ParseLinkedInTests.swift in Sources */,\n\t\t\t\t70E09E1E262F0634002DD451 /* ParsePointerCombineTests.swift in Sources */,\n\t\t\t\t89899D642603CF3F002E2043 /* ParseTwitterTests.swift in Sources */,\n\t\t\t\t709B98532556ECAA00507778 /* ParsePointerTests.swift in Sources */,\n\t\t\t\t70E6B024286131720043EC4A /* ParseHookTriggerCombineTests.swift in Sources */,\n\t\t\t\t89899D822603CF67002E2043 /* ParseFacebookTests.swift in Sources */,\n\t\t\t\t7C4C0945285EA56E00F202C6 /* ParseInstagramCombineTests.swift in Sources */,\n\t\t\t\t70386A4825D99C8B0048EC1B /* ParseLDAPTests.swift in Sources */,\n\t\t\t\t709B40C3268F999000ED2EAC /* IOS13Tests.swift in Sources */,\n\t\t\t\t91285B1A2698E66D0051B544 /* ParseBytesTests.swift in Sources */,\n\t\t\t\t917BA4542703F55700F8D747 /* ParseTwitterAsyncTests.swift in Sources */,\n\t\t\t\t709B984C2556ECAA00507778 /* APICommandTests.swift in Sources */,\n\t\t\t\t70385E6628563FD10084D306 /* ParsePushPayloadFirebaseTests.swift in Sources */,\n\t\t\t\t70732C5C2606CCAD000CAB81 /* ParseObjectCustomObjectIdTests.swift in Sources */,\n\t\t\t\t709B984D2556ECAA00507778 /* AnyDecodableTests.swift in Sources */,\n\t\t\t\t7044C24525C5EA360011F6E7 /* ParseAppleCombineTests.swift in Sources */,\n\t\t\t\t7C995D2F2861FAE40077805A /* ParseSpotifyCombineTests.swift in Sources */,\n\t\t\t\t70DFEA8C2618E77800F8EB4B /* InitializeSDKTests.swift in Sources */,\n\t\t\t\t91285B2326991EE80051B544 /* ParsePolygonTests.swift in Sources */,\n\t\t\t\t70170A502656EBA50070C905 /* ParseAnalyticsTests.swift in Sources */,\n\t\t\t\t7C4C0941285EA3A000F202C6 /* ParseInstagramTests.swift in Sources */,\n\t\t\t\t70E6B01C28612A820043EC4A /* ParseHookFunctionCombineTests.swift in Sources */,\n\t\t\t\t703B092126BDE790005A112F /* ParseObjectAsyncTests.swift in Sources */,\n\t\t\t\t917BA4382703E4CB00F8D747 /* ParseFileAsyncTests.swift in Sources */,\n\t\t\t\t70E6B02C28614C5F0043EC4A /* ParseHookFunctionRequestCombineTests.swift in Sources */,\n\t\t\t\t7044C1E125C5C70D0011F6E7 /* ParseObjectCombineTests.swift in Sources */,\n\t\t\t\t70212D362855266600386163 /* ParsePushCombineTests.swift in Sources */,\n\t\t\t\t700AFE05289C3508006C1CD9 /* ParseQueryCacheTests.swift in Sources */,\n\t\t\t\t70E6B028286132BC0043EC4A /* ParseHookFunctionRequestTests.swift in Sources */,\n\t\t\t\t70F03A642780EADD00E5AFB4 /* ParseLinkedInCombineTests.swift in Sources */,\n\t\t\t\t89899DA126045998002E2043 /* ParseTwitterCombineTests.swift in Sources */,\n\t\t\t\t70212D332855266600386163 /* ParsePushPayloadAppleTests.swift in Sources */,\n\t\t\t\t917BA43C2703E6D800F8D747 /* ParseHealthAsyncTests.swift in Sources */,\n\t\t\t\t917BA4482703EEA700F8D747 /* ParseAnonymousAsyncTests.swift in Sources */,\n\t\t\t\t70F79A692639DE9700731C46 /* ParseHealthCombineTests.swift in Sources */,\n\t\t\t\t91CB9539265966DF0043E5D6 /* ParseAnalyticsCombineTests.swift in Sources */,\n\t\t\t\t703B092526BDFAB2005A112F /* ParseUserAsyncTests.swift in Sources */,\n\t\t\t\t70E6B018286120E00043EC4A /* ParseHookFunctionTests.swift in Sources */,\n\t\t\t\t70C5504825B40D5200B5DBC2 /* ParseSessionTests.swift in Sources */,\n\t\t\t\t709B98572556ECAA00507778 /* ParseACLTests.swift in Sources */,\n\t\t\t\t70F03A582780E8E300E5AFB4 /* ParseGoogleCombineTests.swift in Sources */,\n\t\t\t\t7C4C0949285EA60E00F202C6 /* ParseInstagramAsyncTests.swift in Sources */,\n\t\t\t\t917BA4442703EAC700F8D747 /* ParseLiveQueryAsyncTests.swift in Sources */,\n\t\t\t\t7C995D272861F8330077805A /* ParseSpotifyTests.swift in Sources */,\n\t\t\t\t7016ED4225C4A25A00038648 /* ParseUserCombineTests.swift in Sources */,\n\t\t\t\t91F346C5269B88F7005727B6 /* ParseCloudViewModelTests.swift in Sources */,\n\t\t\t\t917BA4282703DB4600F8D747 /* ParseQueryAsyncTests.swift in Sources */,\n\t\t\t\t70E6B03028614E480043EC4A /* ParseHookTriggerRequestTests.swift in Sources */,\n\t\t\t\t91B40653267A66ED00B129CD /* ParseErrorTests.swift in Sources */,\n\t\t\t\t705727BC2593FF8C00F0ADD5 /* ParseFileTests.swift in Sources */,\n\t\t\t\t917BA42C2703E03F00F8D747 /* ParseAnalyticsAsyncTests.swift in Sources */,\n\t\t\t\t709B984F2556ECAA00507778 /* AnyCodableTests.swift in Sources */,\n\t\t\t\t7003957825A0EE770052CB31 /* BatchUtilsTests.swift in Sources */,\n\t\t\t\t7050259B2842FD3B008D6624 /* ParseCLPTests.swift in Sources */,\n\t\t\t\t705A99FB259807F900B3547F /* ParseFileManagerTests.swift in Sources */,\n\t\t\t\t70F03A542780DA9200E5AFB4 /* ParseGoogleTests.swift in Sources */,\n\t\t\t\t7044C20825C5D6780011F6E7 /* ParseQueryCombineTests.swift in Sources */,\n\t\t\t\t70C5508725B4A68700B5DBC2 /* ParseOperationTests.swift in Sources */,\n\t\t\t\t702380112747FCCD00EFC443 /* ExtensionsTests.swift in Sources */,\n\t\t\t\t704E782328D0D73E0075F952 /* ParseFileTransferableTests.swift in Sources */,\n\t\t\t\t917BA4402703E84000F8D747 /* ParseOperationAsyncTests.swift in Sources */,\n\t\t\t\t7037DAB426384DE1005D7E62 /* TestParseEncoder.swift in Sources */,\n\t\t\t\t7004C26125B6920B005E0AD9 /* ParseRoleTests.swift in Sources */,\n\t\t\t\t917BA4302703E20E00F8D747 /* ParseCloudableAsyncTests.swift in Sources */,\n\t\t\t\t70D41D6928B0235100613510 /* MigrateObjCSDKTests.swift in Sources */,\n\t\t\t\t9167871A259BC5D600BB5B4E /* ParseCloudableTests.swift in Sources */,\n\t\t\t\t70386A5E25D9A4020048EC1B /* ParseLDAPCombineTests.swift in Sources */,\n\t\t\t\t70D41D6D28B294C100613510 /* MigrateObjCSDKCombineTests.swift in Sources */,\n\t\t\t\t70D1BD8925B8C37200A42E7C /* ParseRelationTests.swift in Sources */,\n\t\t\t\t7003963D25A288100052CB31 /* ParseLiveQueryTests.swift in Sources */,\n\t\t\t\t70E6B034286152550043EC4A /* ParseHookTriggerRequestCombineTests.swift in Sources */,\n\t\t\t\t70F03A5C2780EAB100E5AFB4 /* ParseGitHubCombineTests.swift in Sources */,\n\t\t\t\t709B98592556ECAA00507778 /* MockURLResponse.swift in Sources */,\n\t\t\t\t7044C22225C5E0160011F6E7 /* ParseConfigCombineTests.swift in Sources */,\n\t\t\t\t709B98522556ECAA00507778 /* ParseUserTests.swift in Sources */,\n\t\t\t\t70212D342855266600386163 /* ParsePushTests.swift in Sources */,\n\t\t\t\t7050259F2843F0CF008D6624 /* ParseSchemaAsyncTests.swift in Sources */,\n\t\t\t\t709B984E2556ECAA00507778 /* ParseGeoPointTests.swift in Sources */,\n\t\t\t\t7044C1BD25C52E410011F6E7 /* ParseInstallationCombineTests.swift in Sources */,\n\t\t\t\t917BA45C2703FD2200F8D747 /* ParseAuthenticationAsyncTests.swift in Sources */,\n\t\t\t\t709B984B2556ECAA00507778 /* MockURLProtocol.swift in Sources */,\n\t\t\t\t70212D352855266600386163 /* ParsePushAsyncTests.swift in Sources */,\n\t\t\t\t703B092926BE0719005A112F /* ParseInstallationAsyncTests.swift in Sources */,\n\t\t\t\t70F03A602780EAC700E5AFB4 /* ParseGitHubTests.swift in Sources */,\n\t\t\t\t709B98552556ECAA00507778 /* ParseQueryTests.swift in Sources */,\n\t\t\t\t7085DDB526D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift in Sources */,\n\t\t\t\t70E6B02028612FF00043EC4A /* ParseHookTriggerTests.swift in Sources */,\n\t\t\t\t705025A32843F0E7008D6624 /* ParseSchemaCombineTests.swift in Sources */,\n\t\t\t\t7044C1FB25C5CFAB0011F6E7 /* ParseFileCombineTests.swift in Sources */,\n\t\t\t\t70C5502425B3D8F700B5DBC2 /* ParseAppleTests.swift in Sources */,\n\t\t\t\t917BA4342703E36800F8D747 /* ParseConfigAsyncTests.swift in Sources */,\n\t\t\t\t89899DB726045DC4002E2043 /* ParseFacebookCombineTests.swift in Sources */,\n\t\t\t\t709B98502556ECAA00507778 /* KeychainStoreTests.swift in Sources */,\n\t\t\t\t70E6B038286289FF0043EC4A /* ParseHookResponseTests.swift in Sources */,\n\t\t\t\t709B98562556ECAA00507778 /* ParseObjectTests.swift in Sources */,\n\t\t\t\t917BA4582703F75E00F8D747 /* ParseLDAPAsyncTests.swift in Sources */,\n\t\t\t\t70385E6A285640A30084D306 /* ParsePushPayloadAnyTests.swift in Sources */,\n\t\t\t\t70F79A872639DEA200731C46 /* ParseHealthTests.swift in Sources */,\n\t\t\t\t7044C22F25C5E4E90011F6E7 /* ParseAnonymousCombineTests.swift in Sources */,\n\t\t\t\t709B985A2556ECAA00507778 /* ParseObjectBatchTests.swift in Sources */,\n\t\t\t\t7044C21525C5DE490011F6E7 /* ParseCloudableCombineTests.swift in Sources */,\n\t\t\t\t70A2D86D25B3ADB6001BEB7D /* ParseAnonymousTests.swift in Sources */,\n\t\t\t\t7044C1EE25C5CC930011F6E7 /* ParseOperationCombineTests.swift in Sources */,\n\t\t\t\t709B98582556ECAA00507778 /* AnyEncodableTests.swift in Sources */,\n\t\t\t\t70A2D82125B36A7D001BEB7D /* ParseAuthenticationTests.swift in Sources */,\n\t\t\t\t70D1BE5F25BB312A00A42E7C /* ParseConfigTests.swift in Sources */,\n\t\t\t\t91BB8FD62690D586005A6BA5 /* ParseQueryViewModelTests.swift in Sources */,\n\t\t\t\t709B98542556ECAA00507778 /* ParseInstallationTests.swift in Sources */,\n\t\t\t\t917BA44C2703F10400F8D747 /* ParseAppleAsyncTests.swift in Sources */,\n\t\t\t\t705025A7284407C4008D6624 /* ParseSchemaTests.swift in Sources */,\n\t\t\t\t708CADD12872263D0066C279 /* ParseKeychainAccessGroupTests.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t70F2E24C254F247000B2EA5C /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\t918CED5F268618C600CFDC83 /* ParseLiveQueryCombineTests.swift in Sources */,\n\t\t\t\t91679D6E268F261900F71809 /* ParseVersionTests.swift in Sources */,\n\t\t\t\t917BA44F2703F2B400F8D747 /* ParseFacebookAsyncTests.swift in Sources */,\n\t\t\t\t7C995D2A2861FA0B0077805A /* ParseSpotifyAsyncTests.swift in Sources */,\n\t\t\t\t70F2E2B6254F283000B2EA5C /* ParseACLTests.swift in Sources */,\n\t\t\t\t70C167BA27305101009F4E30 /* ParsePointerAsyncTests.swift in Sources */,\n\t\t\t\t70F03A672780EAFA00E5AFB4 /* ParseLinkedInTests.swift in Sources */,\n\t\t\t\t70E09E1D262F0634002DD451 /* ParsePointerCombineTests.swift in Sources */,\n\t\t\t\t89899D632603CF3E002E2043 /* ParseTwitterTests.swift in Sources */,\n\t\t\t\t70F2E2B7254F283000B2EA5C /* ParsePointerTests.swift in Sources */,\n\t\t\t\t70E6B023286131720043EC4A /* ParseHookTriggerCombineTests.swift in Sources */,\n\t\t\t\t89899D812603CF67002E2043 /* ParseFacebookTests.swift in Sources */,\n\t\t\t\t7C4C0944285EA56E00F202C6 /* ParseInstagramCombineTests.swift in Sources */,\n\t\t\t\t70386A4725D99C8B0048EC1B /* ParseLDAPTests.swift in Sources */,\n\t\t\t\t709B40C2268F999000ED2EAC /* IOS13Tests.swift in Sources */,\n\t\t\t\t91285B192698E66D0051B544 /* ParseBytesTests.swift in Sources */,\n\t\t\t\t917BA4532703F55700F8D747 /* ParseTwitterAsyncTests.swift in Sources */,\n\t\t\t\t70F2E2B5254F283000B2EA5C /* ParseEncoderExtraTests.swift in Sources */,\n\t\t\t\t70385E6528563FD10084D306 /* ParsePushPayloadFirebaseTests.swift in Sources */,\n\t\t\t\t70732C5B2606CCAD000CAB81 /* ParseObjectCustomObjectIdTests.swift in Sources */,\n\t\t\t\t70F2E2C2254F283000B2EA5C /* APICommandTests.swift in Sources */,\n\t\t\t\t7044C24425C5EA360011F6E7 /* ParseAppleCombineTests.swift in Sources */,\n\t\t\t\t7C995D2E2861FAE40077805A /* ParseSpotifyCombineTests.swift in Sources */,\n\t\t\t\t70DFEA8B2618E77800F8EB4B /* InitializeSDKTests.swift in Sources */,\n\t\t\t\t91285B2226991EE80051B544 /* ParsePolygonTests.swift in Sources */,\n\t\t\t\t70170A4F2656EBA50070C905 /* ParseAnalyticsTests.swift in Sources */,\n\t\t\t\t7C4C0940285EA3A000F202C6 /* ParseInstagramTests.swift in Sources */,\n\t\t\t\t70E6B01B28612A820043EC4A /* ParseHookFunctionCombineTests.swift in Sources */,\n\t\t\t\t703B092026BDE78F005A112F /* ParseObjectAsyncTests.swift in Sources */,\n\t\t\t\t917BA4372703E4CB00F8D747 /* ParseFileAsyncTests.swift in Sources */,\n\t\t\t\t70E6B02B28614C5F0043EC4A /* ParseHookFunctionRequestCombineTests.swift in Sources */,\n\t\t\t\t7044C1E025C5C70D0011F6E7 /* ParseObjectCombineTests.swift in Sources */,\n\t\t\t\t70212D322855266500386163 /* ParsePushCombineTests.swift in Sources */,\n\t\t\t\t700AFE04289C3508006C1CD9 /* ParseQueryCacheTests.swift in Sources */,\n\t\t\t\t70E6B027286132BC0043EC4A /* ParseHookFunctionRequestTests.swift in Sources */,\n\t\t\t\t70F03A632780EADD00E5AFB4 /* ParseLinkedInCombineTests.swift in Sources */,\n\t\t\t\t89899DA026045998002E2043 /* ParseTwitterCombineTests.swift in Sources */,\n\t\t\t\t70212D2F2855266500386163 /* ParsePushPayloadAppleTests.swift in Sources */,\n\t\t\t\t917BA43B2703E6D800F8D747 /* ParseHealthAsyncTests.swift in Sources */,\n\t\t\t\t917BA4472703EEA700F8D747 /* ParseAnonymousAsyncTests.swift in Sources */,\n\t\t\t\t70F79A682639DE9700731C46 /* ParseHealthCombineTests.swift in Sources */,\n\t\t\t\t91CB9538265966DF0043E5D6 /* ParseAnalyticsCombineTests.swift in Sources */,\n\t\t\t\t703B092426BDFAB2005A112F /* ParseUserAsyncTests.swift in Sources */,\n\t\t\t\t70E6B017286120E00043EC4A /* ParseHookFunctionTests.swift in Sources */,\n\t\t\t\t70C5504725B40D5200B5DBC2 /* ParseSessionTests.swift in Sources */,\n\t\t\t\t70F2E2BC254F283000B2EA5C /* ParseObjectTests.swift in Sources */,\n\t\t\t\t70F03A572780E8E300E5AFB4 /* ParseGoogleCombineTests.swift in Sources */,\n\t\t\t\t7C4C0948285EA60E00F202C6 /* ParseInstagramAsyncTests.swift in Sources */,\n\t\t\t\t917BA4432703EAC700F8D747 /* ParseLiveQueryAsyncTests.swift in Sources */,\n\t\t\t\t7C995D262861F8330077805A /* ParseSpotifyTests.swift in Sources */,\n\t\t\t\t7016ED4125C4A25A00038648 /* ParseUserCombineTests.swift in Sources */,\n\t\t\t\t91F346C4269B88F7005727B6 /* ParseCloudViewModelTests.swift in Sources */,\n\t\t\t\t917BA4272703DB4600F8D747 /* ParseQueryAsyncTests.swift in Sources */,\n\t\t\t\t70E6B02F28614E480043EC4A /* ParseHookTriggerRequestTests.swift in Sources */,\n\t\t\t\t91B40652267A66ED00B129CD /* ParseErrorTests.swift in Sources */,\n\t\t\t\t705727BB2593FF8B00F0ADD5 /* ParseFileTests.swift in Sources */,\n\t\t\t\t917BA42B2703E03F00F8D747 /* ParseAnalyticsAsyncTests.swift in Sources */,\n\t\t\t\t70F2E2BD254F283000B2EA5C /* AnyDecodableTests.swift in Sources */,\n\t\t\t\t7003957725A0EE770052CB31 /* BatchUtilsTests.swift in Sources */,\n\t\t\t\t7050259A2842FD3B008D6624 /* ParseCLPTests.swift in Sources */,\n\t\t\t\t705A99FA259807F900B3547F /* ParseFileManagerTests.swift in Sources */,\n\t\t\t\t70F03A532780DA9200E5AFB4 /* ParseGoogleTests.swift in Sources */,\n\t\t\t\t7044C20725C5D6780011F6E7 /* ParseQueryCombineTests.swift in Sources */,\n\t\t\t\t70C5508625B4A68700B5DBC2 /* ParseOperationTests.swift in Sources */,\n\t\t\t\t702380102747FCCD00EFC443 /* ExtensionsTests.swift in Sources */,\n\t\t\t\t704E782228D0D73E0075F952 /* ParseFileTransferableTests.swift in Sources */,\n\t\t\t\t917BA43F2703E84000F8D747 /* ParseOperationAsyncTests.swift in Sources */,\n\t\t\t\t7037DAB326384DE1005D7E62 /* TestParseEncoder.swift in Sources */,\n\t\t\t\t7004C25725B6920A005E0AD9 /* ParseRoleTests.swift in Sources */,\n\t\t\t\t917BA42F2703E20E00F8D747 /* ParseCloudableAsyncTests.swift in Sources */,\n\t\t\t\t70D41D6828B0235100613510 /* MigrateObjCSDKTests.swift in Sources */,\n\t\t\t\t91678710259BC5D600BB5B4E /* ParseCloudableTests.swift in Sources */,\n\t\t\t\t70386A5D25D9A4020048EC1B /* ParseLDAPCombineTests.swift in Sources */,\n\t\t\t\t70D41D6C28B294C100613510 /* MigrateObjCSDKCombineTests.swift in Sources */,\n\t\t\t\t70D1BD8825B8C37200A42E7C /* ParseRelationTests.swift in Sources */,\n\t\t\t\t7003963C25A288100052CB31 /* ParseLiveQueryTests.swift in Sources */,\n\t\t\t\t70E6B033286152550043EC4A /* ParseHookTriggerRequestCombineTests.swift in Sources */,\n\t\t\t\t70F03A5B2780EAB000E5AFB4 /* ParseGitHubCombineTests.swift in Sources */,\n\t\t\t\t70F2E2C1254F283000B2EA5C /* AnyCodableTests.swift in Sources */,\n\t\t\t\t7044C22125C5E0160011F6E7 /* ParseConfigCombineTests.swift in Sources */,\n\t\t\t\t70F2E2B3254F283000B2EA5C /* ParseUserTests.swift in Sources */,\n\t\t\t\t70212D302855266500386163 /* ParsePushTests.swift in Sources */,\n\t\t\t\t7050259E2843F0CF008D6624 /* ParseSchemaAsyncTests.swift in Sources */,\n\t\t\t\t70F2E2C0254F283000B2EA5C /* MockURLResponse.swift in Sources */,\n\t\t\t\t7044C1BC25C52E410011F6E7 /* ParseInstallationCombineTests.swift in Sources */,\n\t\t\t\t917BA45B2703FD2200F8D747 /* ParseAuthenticationAsyncTests.swift in Sources */,\n\t\t\t\t70F2E2BE254F283000B2EA5C /* ParseObjectBatchTests.swift in Sources */,\n\t\t\t\t70212D312855266500386163 /* ParsePushAsyncTests.swift in Sources */,\n\t\t\t\t703B092826BE0719005A112F /* ParseInstallationAsyncTests.swift in Sources */,\n\t\t\t\t70F03A5F2780EAC700E5AFB4 /* ParseGitHubTests.swift in Sources */,\n\t\t\t\t70F2E2BF254F283000B2EA5C /* MockURLProtocol.swift in Sources */,\n\t\t\t\t7085DDB426D1EC7F0033B977 /* ParseAuthenticationCombineTests.swift in Sources */,\n\t\t\t\t70E6B01F28612FF00043EC4A /* ParseHookTriggerTests.swift in Sources */,\n\t\t\t\t705025A22843F0E7008D6624 /* ParseSchemaCombineTests.swift in Sources */,\n\t\t\t\t7044C1FA25C5CFAB0011F6E7 /* ParseFileCombineTests.swift in Sources */,\n\t\t\t\t70C5502325B3D8F700B5DBC2 /* ParseAppleTests.swift in Sources */,\n\t\t\t\t917BA4332703E36800F8D747 /* ParseConfigAsyncTests.swift in Sources */,\n\t\t\t\t89899DB626045DC4002E2043 /* ParseFacebookCombineTests.swift in Sources */,\n\t\t\t\t70F2E2BB254F283000B2EA5C /* ParseGeoPointTests.swift in Sources */,\n\t\t\t\t70E6B037286289FF0043EC4A /* ParseHookResponseTests.swift in Sources */,\n\t\t\t\t70F2E2B8254F283000B2EA5C /* AnyEncodableTests.swift in Sources */,\n\t\t\t\t917BA4572703F75E00F8D747 /* ParseLDAPAsyncTests.swift in Sources */,\n\t\t\t\t70385E69285640A30084D306 /* ParsePushPayloadAnyTests.swift in Sources */,\n\t\t\t\t70F79A7D2639DEA100731C46 /* ParseHealthTests.swift in Sources */,\n\t\t\t\t7044C22E25C5E4E90011F6E7 /* ParseAnonymousCombineTests.swift in Sources */,\n\t\t\t\t70F2E2B4254F283000B2EA5C /* ParseQueryTests.swift in Sources */,\n\t\t\t\t7044C21425C5DE490011F6E7 /* ParseCloudableCombineTests.swift in Sources */,\n\t\t\t\t70A2D86C25B3ADB6001BEB7D /* ParseAnonymousTests.swift in Sources */,\n\t\t\t\t7044C1ED25C5CC930011F6E7 /* ParseOperationCombineTests.swift in Sources */,\n\t\t\t\t70F2E2BA254F283000B2EA5C /* ParseInstallationTests.swift in Sources */,\n\t\t\t\t70A2D82025B36A7D001BEB7D /* ParseAuthenticationTests.swift in Sources */,\n\t\t\t\t70D1BE5525BB312900A42E7C /* ParseConfigTests.swift in Sources */,\n\t\t\t\t91BB8FD52690D586005A6BA5 /* ParseQueryViewModelTests.swift in Sources */,\n\t\t\t\t70F2E2B9254F283000B2EA5C /* KeychainStoreTests.swift in Sources */,\n\t\t\t\t917BA44B2703F10400F8D747 /* ParseAppleAsyncTests.swift in Sources */,\n\t\t\t\t705025A6284407C4008D6624 /* ParseSchemaTests.swift in Sources */,\n\t\t\t\t708CADD02872263D0066C279 /* ParseKeychainAccessGroupTests.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t912C9BC724D3005D009947C3 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tF97B45D524D9C6F200F4A88B /* AnyDecodable.swift in Sources */,\n\t\t\t\t7C55F9EF2860CEA6002A352D /* ParseSpotify+async.swift in Sources */,\n\t\t\t\t916786E5259B7DDA00BB5B4E /* ParseCloudable.swift in Sources */,\n\t\t\t\t70CE0AC9285FD5A800DAEA86 /* ParseHookFunctionable+combine.swift in Sources */,\n\t\t\t\t91F346BC269B766D005727B6 /* CloudViewModel.swift in Sources */,\n\t\t\t\t708EF0C528D5FDF10052EF35 /* API+NonParseBodyCommand+async.swift in Sources */,\n\t\t\t\t709A148F2839A1DB00BF85E5 /* Operation.swift in Sources */,\n\t\t\t\t70CE0AD3285FD5D700DAEA86 /* ParseHookTriggerable+combine.swift in Sources */,\n\t\t\t\t709A14A8283AAF4C00BF85E5 /* ParseSchema+combine.swift in Sources */,\n\t\t\t\tF97B45E924D9C6F200F4A88B /* Query.swift in Sources */,\n\t\t\t\tF97B463624D9C74400F4A88B /* URLSession.swift in Sources */,\n\t\t\t\t705025CA284C7883008D6624 /* ParsePush+combine.swift in Sources */,\n\t\t\t\t7028373726BD8883007688C9 /* ParseObject+async.swift in Sources */,\n\t\t\t\t70C5503B25B406B800B5DBC2 /* ParseSession.swift in Sources */,\n\t\t\t\t7044C1CB25C5B2B10011F6E7 /* ParseAuthentication+combine.swift in Sources */,\n\t\t\t\t707A3BF425B0A4F0000D215C /* ParseAuthentication.swift in Sources */,\n\t\t\t\t70D1BE7625BB43EB00A42E7C /* BaseConfig.swift in Sources */,\n\t\t\t\t703B090A26BD9764005A112F /* ParseCloudable+async.swift in Sources */,\n\t\t\t\t918CED5C2684C74000CFDC83 /* ParseLiveQuery+combine.swift in Sources */,\n\t\t\t\t70386A0925D9718C0048EC1B /* Data.swift in Sources */,\n\t\t\t\t70B4E0C42762F313004C9757 /* QueryWhere.swift in Sources */,\n\t\t\t\tF97B460524D9C6F200F4A88B /* NoBody.swift in Sources */,\n\t\t\t\t70170A472656B02D0070C905 /* ParseAnalytics.swift in Sources */,\n\t\t\t\tF97B45E124D9C6F200F4A88B /* AnyCodable.swift in Sources */,\n\t\t\t\t708EF0C028D5F4140052EF35 /* API+Command+async.swift in Sources */,\n\t\t\t\t91B79AC626EE3A4E00073F2C /* API+NonParseBodyCommand.swift in Sources */,\n\t\t\t\t7C4C092E285E746800F202C6 /* ParseInstagram.swift in Sources */,\n\t\t\t\t70D1BDBD25BB17A600A42E7C /* ParseConfig.swift in Sources */,\n\t\t\t\t703B090026BD953B005A112F /* ParseHealth+async.swift in Sources */,\n\t\t\t\t70CE0AC4285FD59B00DAEA86 /* ParseHookFunctionable+async.swift in Sources */,\n\t\t\t\t7085DDA626CC8A470033B977 /* ParseHealth+combine.swift in Sources */,\n\t\t\t\t70C048C42880D7E600401689 /* Dictionary.swift in Sources */,\n\t\t\t\tF97B45E524D9C6F200F4A88B /* AnyEncodable.swift in Sources */,\n\t\t\t\t70385E742858D2DD0084D306 /* ParseHookTriggerable.swift in Sources */,\n\t\t\t\t91B79ACB26EE3C5D00073F2C /* API+BatchCommand.swift in Sources */,\n\t\t\t\t91679D67268E596300F71809 /* ParseVersion.swift in Sources */,\n\t\t\t\t91285B1F26990D7F0051B544 /* ParsePolygon.swift in Sources */,\n\t\t\t\t91BB8FCD2690AC99005A6BA5 /* QueryViewModel.swift in Sources */,\n\t\t\t\t705025EE285153BC008D6624 /* ParsePushApplePayloadable.swift in Sources */,\n\t\t\t\t705025AC28441C96008D6624 /* ParseFieldOptions.swift in Sources */,\n\t\t\t\t7085DD9726CBF3A70033B977 /* Documentation.docc in Sources */,\n\t\t\t\t7C4C093D285E9A3700F202C6 /* ParseInstagram+combine.swift in Sources */,\n\t\t\t\tF97B465D24D9C78C00F4A88B /* Increment.swift in Sources */,\n\t\t\t\t700395A625A119430052CB31 /* Operations.swift in Sources */,\n\t\t\t\t91BB8FD22690BA70005A6BA5 /* QueryObservable.swift in Sources */,\n\t\t\t\t705025E928514F36008D6624 /* ParsePushPayloadAny.swift in Sources */,\n\t\t\t\t709A148528395ED100BF85E5 /* ParseSchema+async.swift in Sources */,\n\t\t\t\t705025D4284CFCDE008D6624 /* ParsePushAppleAlert.swift in Sources */,\n\t\t\t\t704E781F28CFFAF80075F952 /* ParseFileDefaultTransfer.swift in Sources */,\n\t\t\t\t7045769B26BD917500F86F71 /* Query+async.swift in Sources */,\n\t\t\t\t703B095126BF47E3005A112F /* ParseTwitter+combine.swift in Sources */,\n\t\t\t\t70386A3B25D998D90048EC1B /* ParseLDAP.swift in Sources */,\n\t\t\t\t709A14A32839CABD00BF85E5 /* ParseCLP.swift in Sources */,\n\t\t\t\t700395F525A171320052CB31 /* LiveQueryable.swift in Sources */,\n\t\t\t\tF97B45FD24D9C6F200F4A88B /* ParseACL.swift in Sources */,\n\t\t\t\t703B095B26BF480D005A112F /* ParseFacebook+combine.swift in Sources */,\n\t\t\t\t70510AAF259EE25E00FEA700 /* LiveQuerySocket.swift in Sources */,\n\t\t\t\t7C4C0933285E986F00F202C6 /* ParseInstagram+async.swift in Sources */,\n\t\t\t\t705025D9284D0C1D008D6624 /* ParsePushPayloadApple.swift in Sources */,\n\t\t\t\t70C167B227304EE4009F4E30 /* Pointer+combine.swift in Sources */,\n\t\t\t\t7044C19425C4F5B60011F6E7 /* ParseFile+combine.swift in Sources */,\n\t\t\t\t70F79A1C2639CE6F00731C46 /* ParseHealth.swift in Sources */,\n\t\t\t\t70A98D852794AB3C009B58F2 /* ParseQueryScorable.swift in Sources */,\n\t\t\t\t70385E882858F9750084D306 /* ParseHookParametable.swift in Sources */,\n\t\t\t\t7044C1A225C4FA870011F6E7 /* ParseOperation+combine.swift in Sources */,\n\t\t\t\t70212D162854C82B00386163 /* ParsePushFirebaseNotification.swift in Sources */,\n\t\t\t\tF97B465124D9C78C00F4A88B /* Add.swift in Sources */,\n\t\t\t\t7044C1B025C4FC080011F6E7 /* Query+combine.swift in Sources */,\n\t\t\t\tF97B461124D9C6F200F4A88B /* ParseObject.swift in Sources */,\n\t\t\t\t70C550A325B4A9F600B5DBC2 /* RemoveRelation.swift in Sources */,\n\t\t\t\tF97B460D24D9C6F200F4A88B /* Fetchable.swift in Sources */,\n\t\t\t\t705025C0284C610C008D6624 /* ParsePush.swift in Sources */,\n\t\t\t\tF97B45ED24D9C6F200F4A88B /* ParseGeoPoint.swift in Sources */,\n\t\t\t\t7064369E273313D5007C6461 /* LiveQueryConstants.swift in Sources */,\n\t\t\t\t70F03A2E2780BE2C00E5AFB4 /* ParseGoogle+async.swift in Sources */,\n\t\t\t\t89899CD22603CE3A002E2043 /* ParseFacebook.swift in Sources */,\n\t\t\t\t7028373C26BD8C89007688C9 /* ParseUser+async.swift in Sources */,\n\t\t\t\t70CE0AA128592A2B00DAEA86 /* ParseCloudUser.swift in Sources */,\n\t\t\t\t705A9A3225991C1400B3547F /* Fileable.swift in Sources */,\n\t\t\t\t70B4E0BF2762F1D5004C9757 /* QueryConstraint.swift in Sources */,\n\t\t\t\t7C55F9F42860CEEF002A352D /* ParseSpotify+combine.swift in Sources */,\n\t\t\t\t704C886F28BE69A8008E6B01 /* ParseConfiguration.swift in Sources */,\n\t\t\t\t89899D282603CF35002E2043 /* ParseTwitter.swift in Sources */,\n\t\t\t\t70C167B727304F09009F4E30 /* Pointer+async.swift in Sources */,\n\t\t\t\t705025B128456106008D6624 /* ParsePushStatusable.swift in Sources */,\n\t\t\t\tF97B45F524D9C6F200F4A88B /* Pointer.swift in Sources */,\n\t\t\t\t705025CF284CE4C2008D6624 /* ParsePushPayloadable.swift in Sources */,\n\t\t\t\t70F03A502780D28A00E5AFB4 /* ParseLinkedIn+combine.swift in Sources */,\n\t\t\t\tF97B460924D9C6F200F4A88B /* ParseUser.swift in Sources */,\n\t\t\t\t70F03A412780CA8F00E5AFB4 /* ParseGitHub+combine.swift in Sources */,\n\t\t\t\t700396FB25A394AE0052CB31 /* ParseLiveQueryDelegate.swift in Sources */,\n\t\t\t\tF97B463A24D9C74400F4A88B /* Responses.swift in Sources */,\n\t\t\t\t7045769626BD8F8100F86F71 /* ParseInstallation+async.swift in Sources */,\n\t\t\t\t7C55F9EA2860CD6B002A352D /* ParseSpotify.swift in Sources */,\n\t\t\t\t7003960C25A184EF0052CB31 /* ParseLiveQuery.swift in Sources */,\n\t\t\t\t7044C17825C4ECFF0011F6E7 /* ParseCloudable+combine.swift in Sources */,\n\t\t\t\t705025B62845C302008D6624 /* ParsePushStatus.swift in Sources */,\n\t\t\t\t700396ED25A3892D0052CB31 /* LiveQuerySocketDelegate.swift in Sources */,\n\t\t\t\t9116F67226A35D620082F6D6 /* URLCache.swift in Sources */,\n\t\t\t\t70572674259033A700F0ADD5 /* ParseFileManager.swift in Sources */,\n\t\t\t\t70CE0AB5285963A300DAEA86 /* ParseHookTriggerRequest.swift in Sources */,\n\t\t\t\t709A148A28396B1D00BF85E5 /* ParseField.swift in Sources */,\n\t\t\t\t707A3C2325B14BD0000D215C /* ParseApple.swift in Sources */,\n\t\t\t\t70F03A372780CA4E00E5AFB4 /* ParseGitHub.swift in Sources */,\n\t\t\t\t703B096026BF481F005A112F /* ParseFacebook+async.swift in Sources */,\n\t\t\t\tF97B462124D9C6F200F4A88B /* ParseStorage.swift in Sources */,\n\t\t\t\t709A1480283949D100BF85E5 /* ParseSchema.swift in Sources */,\n\t\t\t\t704E781A28CFD8A00075F952 /* ParseFileTransferable.swift in Sources */,\n\t\t\t\t703B090526BD9652005A112F /* ParseAnalytics+async.swift in Sources */,\n\t\t\t\t703B094226BF47AC005A112F /* ParseApple+async.swift in Sources */,\n\t\t\t\tF97B466724D9C88600F4A88B /* SecureStorage.swift in Sources */,\n\t\t\t\t703B093826BF43D9005A112F /* ParseAnonymous+async.swift in Sources */,\n\t\t\t\t705D950B25BE4C08003EF6F8 /* SubscriptionCallback.swift in Sources */,\n\t\t\t\t70C5509525B4A99100B5DBC2 /* AddRelation.swift in Sources */,\n\t\t\t\t708D035525215F9B00646C70 /* Deletable.swift in Sources */,\n\t\t\t\t70110D55250680140091CC1D /* ParseConstants.swift in Sources */,\n\t\t\t\t7004C22325B63C7A005E0AD9 /* ParseRelation.swift in Sources */,\n\t\t\t\t7003959825A10DFC0052CB31 /* Messages.swift in Sources */,\n\t\t\t\t703B091426BD992E005A112F /* ParseOperation+async.swift in Sources */,\n\t\t\t\t70C5655C25AA147B00BDD57F /* ParseLiveQueryConstants.swift in Sources */,\n\t\t\t\t91F346C1269B77B5005727B6 /* CloudObservable.swift in Sources */,\n\t\t\t\t70BDA2B6250536FF00FC2237 /* ParseInstallation.swift in Sources */,\n\t\t\t\tF97B465924D9C78C00F4A88B /* Remove.swift in Sources */,\n\t\t\t\t70385E832858EAA90084D306 /* ParseHookFunctionRequest.swift in Sources */,\n\t\t\t\t70CE0AB028595FDE00DAEA86 /* ParseHookRequestable+combine.swift in Sources */,\n\t\t\t\t70110D5A2506CE890091CC1D /* BaseParseInstallation.swift in Sources */,\n\t\t\t\tF97B45F924D9C6F200F4A88B /* ParseError.swift in Sources */,\n\t\t\t\t703B093326BF42C2005A112F /* ParseAnonymous+combine.swift in Sources */,\n\t\t\t\t706436AC27341FD0007C6461 /* Date.swift in Sources */,\n\t\t\t\t700395BD25A1470F0052CB31 /* Subscription.swift in Sources */,\n\t\t\t\t91285B162698DBF20051B544 /* ParseBytes.swift in Sources */,\n\t\t\t\t7016ED5925C4C32B00038648 /* ParseInstallation+combine.swift in Sources */,\n\t\t\t\t7003972D25A3B0140052CB31 /* ParseURLSessionDelegate.swift in Sources */,\n\t\t\t\t70F03A462780D21600E5AFB4 /* ParseLinkedIn.swift in Sources */,\n\t\t\t\t703B094726BF47C0005A112F /* ParseLDAP+combine.swift in Sources */,\n\t\t\t\t700395D425A147BE0052CB31 /* QuerySubscribable.swift in Sources */,\n\t\t\t\t70170A4C2656E2FE0070C905 /* ParseAnalytics+combine.swift in Sources */,\n\t\t\t\t703B092E26BF290B005A112F /* ParseAuthentication+async.swift in Sources */,\n\t\t\t\t70F03A2F2780BE2C00E5AFB4 /* ParseGoogle.swift in Sources */,\n\t\t\t\t70CE0ABA285A83B100DAEA86 /* ParseHookable.swift in Sources */,\n\t\t\t\tF97B460124D9C6F200F4A88B /* ParseFile.swift in Sources */,\n\t\t\t\t704576A026BD934000F86F71 /* ParseFile+async.swift in Sources */,\n\t\t\t\tF97B464924D9C78B00F4A88B /* ParseOperation.swift in Sources */,\n\t\t\t\tF97B45D124D9C6F200F4A88B /* ParseCoding.swift in Sources */,\n\t\t\t\t70D41D8328B520E200613510 /* ParseKeychainAccessGroup.swift in Sources */,\n\t\t\t\t70385E792858E1000084D306 /* ParseHookFunctionable.swift in Sources */,\n\t\t\t\t703B095626BF47FD005A112F /* ParseTwitter+async.swift in Sources */,\n\t\t\t\t70CE0ABF285F8FF900DAEA86 /* ParseTypeable.swift in Sources */,\n\t\t\t\t70BC9893252A5B5C00FF3074 /* Objectable.swift in Sources */,\n\t\t\t\tF97B465524D9C78C00F4A88B /* AddUnique.swift in Sources */,\n\t\t\t\tF97B464D24D9C78B00F4A88B /* Delete.swift in Sources */,\n\t\t\t\t706436A727341F6E007C6461 /* Encodable.swift in Sources */,\n\t\t\t\tF97B461524D9C6F200F4A88B /* Savable.swift in Sources */,\n\t\t\t\t70CE0A9728590A0A00DAEA86 /* ParseHookResponse.swift in Sources */,\n\t\t\t\t70F03A4B2780D27700E5AFB4 /* ParseLinkedIn+async.swift in Sources */,\n\t\t\t\t70CE0AA628595E5E00DAEA86 /* ParseHookRequestable.swift in Sources */,\n\t\t\t\t703B090F26BD984D005A112F /* ParseConfig+async.swift in Sources */,\n\t\t\t\tF97B462524D9C6F200F4A88B /* ParseKeyValueStore.swift in Sources */,\n\t\t\t\t70F03A302780BE2C00E5AFB4 /* ParseGoogle+combine.swift in Sources */,\n\t\t\t\tF97B466224D9C7B500F4A88B /* KeychainStore.swift in Sources */,\n\t\t\t\t703B094C26BF47D0005A112F /* ParseLDAP+async.swift in Sources */,\n\t\t\t\tF97B463E24D9C74400F4A88B /* API+Command.swift in Sources */,\n\t\t\t\t70CE0AAB28595FCE00DAEA86 /* ParseHookRequestable+async.swift in Sources */,\n\t\t\t\tF97B462A24D9C72700F4A88B /* API.swift in Sources */,\n\t\t\t\tF97B463224D9C74400F4A88B /* BatchUtils.swift in Sources */,\n\t\t\t\t7016ED6725C4C46B00038648 /* ParseObject+combine.swift in Sources */,\n\t\t\t\t705025F32851542D008D6624 /* ParsePushFirebasePayloadable.swift in Sources */,\n\t\t\t\t705025DE284D0D56008D6624 /* ParsePushAppleSound.swift in Sources */,\n\t\t\t\tF97B45F124D9C6F200F4A88B /* BaseParseUser.swift in Sources */,\n\t\t\t\t70CE0ACE285FD5CB00DAEA86 /* ParseHookTriggerable+async.swift in Sources */,\n\t\t\t\t705025C5284C7842008D6624 /* ParsePush+async.swift in Sources */,\n\t\t\t\tF97B45D924D9C6F200F4A88B /* ParseEncoder.swift in Sources */,\n\t\t\t\t70647E9F259E3A9A004C1004 /* ParseEncodable.swift in Sources */,\n\t\t\t\t707A3C1425B0A8E8000D215C /* ParseAnonymous.swift in Sources */,\n\t\t\t\t912C9BFD24D302B2009947C3 /* Parse.swift in Sources */,\n\t\t\t\t70F03A3C2780CA6F00E5AFB4 /* ParseGitHub+async.swift in Sources */,\n\t\t\t\tF97B461924D9C6F200F4A88B /* Queryable.swift in Sources */,\n\t\t\t\t705025E32851006F008D6624 /* ParsePushPayloadFirebase.swift in Sources */,\n\t\t\t\t70C5507A25B49D3A00B5DBC2 /* ParseRole.swift in Sources */,\n\t\t\t\t703B093D26BF4799005A112F /* ParseApple+combine.swift in Sources */,\n\t\t\t\t7044C18625C4EFC10011F6E7 /* ParseConfig+combine.swift in Sources */,\n\t\t\t\t7016ED3525C3BA2000038648 /* ParseUser+combine.swift in Sources */,\n\t\t\t\t703B091926BD99BC005A112F /* ParseLiveQuery+async.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n\t\t912C9BD424D3011F009947C3 /* Sources */ = {\n\t\t\tisa = PBXSourcesBuildPhase;\n\t\t\tbuildActionMask = 2147483647;\n\t\t\tfiles = (\n\t\t\t\tF97B45D424D9C6F200F4A88B /* AnyDecodable.swift in Sources */,\n\t\t\t\t7C55F9EE2860CEA6002A352D /* ParseSpotify+async.swift in Sources */,\n\t\t\t\t916786E4259B7DDA00BB5B4E /* ParseCloudable.swift in Sources */,\n\t\t\t\t70CE0AC8285FD5A800DAEA86 /* ParseHookFunctionable+combine.swift in Sources */,\n\t\t\t\t91F346BB269B766D005727B6 /* CloudViewModel.swift in Sources */,\n\t\t\t\t708EF0C428D5FDF10052EF35 /* API+NonParseBodyCommand+async.swift in Sources */,\n\t\t\t\t709A148E2839A1DB00BF85E5 /* Operation.swift in Sources */,\n\t\t\t\t70CE0AD2285FD5D700DAEA86 /* ParseHookTriggerable+combine.swift in Sources */,\n\t\t\t\t709A14A7283AAF4C00BF85E5 /* ParseSchema+combine.swift in Sources */,\n\t\t\t\tF97B45E824D9C6F200F4A88B /* Query.swift in Sources */,\n\t\t\t\tF97B463524D9C74400F4A88B /* URLSession.swift in Sources */,\n\t\t\t\t705025C9284C7883008D6624 /* ParsePush+combine.swift in Sources */,\n\t\t\t\t7028373626BD8883007688C9 /* ParseObject+async.swift in Sources */,\n\t\t\t\t70C5503A25B406B800B5DBC2 /* ParseSession.swift in Sources */,\n\t\t\t\t7044C1CA25C5B2B10011F6E7 /* ParseAuthentication+combine.swift in Sources */,\n\t\t\t\t707A3BF325B0A4F0000D215C /* ParseAuthentication.swift in Sources */,\n\t\t\t\t70D1BE7525BB43EB00A42E7C /* BaseConfig.swift in Sources */,\n\t\t\t\t703B090926BD9764005A112F /* ParseCloudable+async.swift in Sources */,\n\t\t\t\t918CED5B2684C74000CFDC83 /* ParseLiveQuery+combine.swift in Sources */,\n\t\t\t\t70386A0825D9718C0048EC1B /* Data.swift in Sources */,\n\t\t\t\t70B4E0C32762F313004C9757 /* QueryWhere.swift in Sources */,\n\t\t\t\tF97B460424D9C6F200F4A88B /* NoBody.swift in Sources */,\n\t\t\t\t70170A462656B02D0070C905 /* ParseAnalytics.swift in Sources */,\n\t\t\t\tF97B45E024D9C6F200F4A88B /* AnyCodable.swift in Sources */,\n\t\t\t\t708EF0BF28D5F4140052EF35 /* API+Command+async.swift in Sources */,\n\t\t\t\t91B79AC526EE3A4E00073F2C /* API+NonParseBodyCommand.swift in Sources */,\n\t\t\t\t7C4C092D285E746800F202C6 /* ParseInstagram.swift in Sources */,\n\t\t\t\t70D1BDBC25BB17A600A42E7C /* ParseConfig.swift in Sources */,\n\t\t\t\t703B08FF26BD953B005A112F /* ParseHealth+async.swift in Sources */,\n\t\t\t\t70CE0AC3285FD59B00DAEA86 /* ParseHookFunctionable+async.swift in Sources */,\n\t\t\t\t7085DDA526CC8A470033B977 /* ParseHealth+combine.swift in Sources */,\n\t\t\t\t70C048C32880D7E600401689 /* Dictionary.swift in Sources */,\n\t\t\t\tF97B45E424D9C6F200F4A88B /* AnyEncodable.swift in Sources */,\n\t\t\t\t70385E732858D2DD0084D306 /* ParseHookTriggerable.swift in Sources */,\n\t\t\t\t91B79ACA26EE3C5D00073F2C /* API+BatchCommand.swift in Sources */,\n\t\t\t\t91679D66268E596300F71809 /* ParseVersion.swift in Sources */,\n\t\t\t\t91285B1E26990D7F0051B544 /* ParsePolygon.swift in Sources */,\n\t\t\t\t91BB8FCC2690AC99005A6BA5 /* QueryViewModel.swift in Sources */,\n\t\t\t\t705025ED285153BC008D6624 /* ParsePushApplePayloadable.swift in Sources */,\n\t\t\t\t705025AB28441C96008D6624 /* ParseFieldOptions.swift in Sources */,\n\t\t\t\t7085DD9626CBF3A70033B977 /* Documentation.docc in Sources */,\n\t\t\t\t7C4C093C285E9A3700F202C6 /* ParseInstagram+combine.swift in Sources */,\n\t\t\t\tF97B465C24D9C78C00F4A88B /* Increment.swift in Sources */,\n\t\t\t\t700395A525A119430052CB31 /* Operations.swift in Sources */,\n\t\t\t\t91BB8FD12690BA70005A6BA5 /* QueryObservable.swift in Sources */,\n\t\t\t\t705025E828514F36008D6624 /* ParsePushPayloadAny.swift in Sources */,\n\t\t\t\t709A148428395ED100BF85E5 /* ParseSchema+async.swift in Sources */,\n\t\t\t\t705025D3284CFCDE008D6624 /* ParsePushAppleAlert.swift in Sources */,\n\t\t\t\t704E781E28CFFAF80075F952 /* ParseFileDefaultTransfer.swift in Sources */,\n\t\t\t\t7045769A26BD917500F86F71 /* Query+async.swift in Sources */,\n\t\t\t\t703B095026BF47E3005A112F /* ParseTwitter+combine.swift in Sources */,\n\t\t\t\t70386A3A25D998D90048EC1B /* ParseLDAP.swift in Sources */,\n\t\t\t\t709A14A22839CABD00BF85E5 /* ParseCLP.swift in Sources */,\n\t\t\t\t700395F425A171320052CB31 /* LiveQueryable.swift in Sources */,\n\t\t\t\tF97B45FC24D9C6F200F4A88B /* ParseACL.swift in Sources */,\n\t\t\t\t703B095A26BF480D005A112F /* ParseFacebook+combine.swift in Sources */,\n\t\t\t\t70510AAE259EE25E00FEA700 /* LiveQuerySocket.swift in Sources */,\n\t\t\t\t7C4C0932285E986F00F202C6 /* ParseInstagram+async.swift in Sources */,\n\t\t\t\t705025D8284D0C1D008D6624 /* ParsePushPayloadApple.swift in Sources */,\n\t\t\t\t70C167B127304EE4009F4E30 /* Pointer+combine.swift in Sources */,\n\t\t\t\t7044C19325C4F5B60011F6E7 /* ParseFile+combine.swift in Sources */,\n\t\t\t\t70F79A1B2639CE6F00731C46 /* ParseHealth.swift in Sources */,\n\t\t\t\t70A98D842794AB3C009B58F2 /* ParseQueryScorable.swift in Sources */,\n\t\t\t\t70385E872858F9750084D306 /* ParseHookParametable.swift in Sources */,\n\t\t\t\t7044C1A125C4FA870011F6E7 /* ParseOperation+combine.swift in Sources */,\n\t\t\t\t70212D152854C82B00386163 /* ParsePushFirebaseNotification.swift in Sources */,\n\t\t\t\tF97B465024D9C78B00F4A88B /* Add.swift in Sources */,\n\t\t\t\t7044C1AF25C4FC080011F6E7 /* Query+combine.swift in Sources */,\n\t\t\t\tF97B461024D9C6F200F4A88B /* ParseObject.swift in Sources */,\n\t\t\t\t70C550A225B4A9F600B5DBC2 /* RemoveRelation.swift in Sources */,\n\t\t\t\tF97B460C24D9C6F200F4A88B /* Fetchable.swift in Sources */,\n\t\t\t\t705025BF284C610C008D6624 /* ParsePush.swift in Sources */,\n\t\t\t\tF97B45EC24D9C6F200F4A88B /* ParseGeoPoint.swift in Sources */,\n\t\t\t\t7064369D273313D5007C6461 /* LiveQueryConstants.swift in Sources */,\n\t\t\t\t70F03A2B2780BE2B00E5AFB4 /* ParseGoogle+async.swift in Sources */,\n\t\t\t\t89899CD12603CE3A002E2043 /* ParseFacebook.swift in Sources */,\n\t\t\t\t7028373B26BD8C89007688C9 /* ParseUser+async.swift in Sources */,\n\t\t\t\t70CE0AA028592A2B00DAEA86 /* ParseCloudUser.swift in Sources */,\n\t\t\t\t705A9A3125991C1400B3547F /* Fileable.swift in Sources */,\n\t\t\t\t70B4E0BE2762F1D5004C9757 /* QueryConstraint.swift in Sources */,\n\t\t\t\t7C55F9F32860CEEF002A352D /* ParseSpotify+combine.swift in Sources */,\n\t\t\t\t704C886E28BE69A8008E6B01 /* ParseConfiguration.swift in Sources */,\n\t\t\t\t89899D322603CF35002E2043 /* ParseTwitter.swift in Sources */,\n\t\t\t\t70C167B627304F09009F4E30 /* Pointer+async.swift in Sources */,\n\t\t\t\t705025B028456106008D6624 /* ParsePushStatusable.swift in Sources */,\n\t\t\t\tF97B45F424D9C6F200F4A88B /* Pointer.swift in Sources */,\n\t\t\t\t705025CE284CE4C2008D6624 /* ParsePushPayloadable.swift in Sources */,\n\t\t\t\t70F03A4F2780D28A00E5AFB4 /* ParseLinkedIn+combine.swift in Sources */,\n\t\t\t\tF97B460824D9C6F200F4A88B /* ParseUser.swift in Sources */,\n\t\t\t\t70F03A402780CA8F00E5AFB4 /* ParseGitHub+combine.swift in Sources */,\n\t\t\t\t700396FA25A394AE0052CB31 /* ParseLiveQueryDelegate.swift in Sources */,\n\t\t\t\tF97B463924D9C74400F4A88B /* Responses.swift in Sources */,\n\t\t\t\t7045769526BD8F8100F86F71 /* ParseInstallation+async.swift in Sources */,\n\t\t\t\t7C55F9E92860CD6B002A352D /* ParseSpotify.swift in Sources */,\n\t\t\t\t7003960B25A184EF0052CB31 /* ParseLiveQuery.swift in Sources */,\n\t\t\t\t7044C17725C4ECFF0011F6E7 /* ParseCloudable+combine.swift in Sources */,\n\t\t\t\t705025B52845C302008D6624 /* ParsePushStatus.swift in Sources */,\n\t\t\t\t700396EC25A3892D0052CB31 /* LiveQuerySocketDelegate.swift in Sources */,\n\t\t\t\t9116F67126A35D620082F6D6 /* URLCache.swift in Sources */,\n\t\t\t\t70572673259033A700F0ADD5 /* ParseFileManager.swift in Sources */,\n\t\t\t\t70CE0AB4285963A300DAEA86 /* ParseHookTriggerRequest.swift in Sources */,\n\t\t\t\t709A148928396B1D00BF85E5 /* ParseField.swift in Sources */,\n\t\t\t\t707A3C2225B14BD0000D215C /* ParseApple.swift in Sources */,\n\t\t\t\t70F03A362780CA4D00E5AFB4 /* ParseGitHub.swift in Sources */,\n\t\t\t\t703B095F26BF481F005A112F /* ParseFacebook+async.swift in Sources */,\n\t\t\t\tF97B462024D9C6F200F4A88B /* ParseStorage.swift in Sources */,\n\t\t\t\t709A147F283949D100BF85E5 /* ParseSchema.swift in Sources */,\n\t\t\t\t704E781928CFD8A00075F952 /* ParseFileTransferable.swift in Sources */,\n\t\t\t\t703B090426BD9652005A112F /* ParseAnalytics+async.swift in Sources */,\n\t\t\t\t703B094126BF47AC005A112F /* ParseApple+async.swift in Sources */,\n\t\t\t\tF97B466624D9C88600F4A88B /* SecureStorage.swift in Sources */,\n\t\t\t\t703B093726BF43D9005A112F /* ParseAnonymous+async.swift in Sources */,\n\t\t\t\t705D950A25BE4C08003EF6F8 /* SubscriptionCallback.swift in Sources */,\n\t\t\t\t70C5509425B4A99100B5DBC2 /* AddRelation.swift in Sources */,\n\t\t\t\t708D035425215F9B00646C70 /* Deletable.swift in Sources */,\n\t\t\t\t70110D54250680140091CC1D /* ParseConstants.swift in Sources */,\n\t\t\t\t7004C22225B63C7A005E0AD9 /* ParseRelation.swift in Sources */,\n\t\t\t\t7003959725A10DFC0052CB31 /* Messages.swift in Sources */,\n\t\t\t\t703B091326BD992E005A112F /* ParseOperation+async.swift in Sources */,\n\t\t\t\t70C5655B25AA147B00BDD57F /* ParseLiveQueryConstants.swift in Sources */,\n\t\t\t\t91F346C0269B77B5005727B6 /* CloudObservable.swift in Sources */,\n\t\t\t\t70BDA2B5250536FF00FC2237 /* ParseInstallation.swift in Sources */,\n\t\t\t\tF97B465824D9C78C00F4A88B /* Remove.swift in Sources */,\n\t\t\t\t70385E822858EAA90084D306 /* ParseHookFunctionRequest.swift in Sources */,\n\t\t\t\t70CE0AAF28595FDE00DAEA86 /* ParseHookRequestable+combine.swift in Sources */,\n\t\t\t\t70110D592506CE890091CC1D /* BaseParseInstallation.swift in Sources */,\n\t\t\t\tF97B45F824D9C6F200F4A88B /* ParseError.swift in Sources */,\n\t\t\t\t703B093226BF42C2005A112F /* ParseAnonymous+combine.swift in Sources */,\n\t\t\t\t706436AB27341FD0007C6461 /* Date.swift in Sources */,\n\t\t\t\t700395BC25A1470F0052CB31 /* Subscription.swift in Sources */,\n\t\t\t\t91285B152698DBF20051B544 /* ParseBytes.swift in Sources */,\n\t\t\t\t7016ED5825C4C32B00038648 /* ParseInstallation+combine.swift in Sources */,\n\t\t\t\t7003972C25A3B0140052CB31 /* ParseURLSessionDelegate.swift in Sources */,\n\t\t\t\t70F03A452780D21600E5AFB4 /* ParseLinkedIn.swift in Sources */,\n\t\t\t\t703B094626BF47C0005A112F /* ParseLDAP+combine.swift in Sources */,\n\t\t\t\t700395D325A147BE0052CB31 /* QuerySubscribable.swift in Sources */,\n\t\t\t\t70170A4B2656E2FE0070C905 /* ParseAnalytics+combine.swift in Sources */,\n\t\t\t\t703B092D26BF290B005A112F /* ParseAuthentication+async.swift in Sources */,\n\t\t\t\t70F03A2C2780BE2B00E5AFB4 /* ParseGoogle.swift in Sources */,\n\t\t\t\t70CE0AB9285A83B100DAEA86 /* ParseHookable.swift in Sources */,\n\t\t\t\tF97B460024D9C6F200F4A88B /* ParseFile.swift in Sources */,\n\t\t\t\t7045769F26BD934000F86F71 /* ParseFile+async.swift in Sources */,\n\t\t\t\tF97B464824D9C78B00F4A88B /* ParseOperation.swift in Sources */,\n\t\t\t\tF97B45D024D9C6F200F4A88B /* ParseCoding.swift in Sources */,\n\t\t\t\t70D41D8228B520E200613510 /* ParseKeychainAccessGroup.swift in Sources */,\n\t\t\t\t70385E782858E1000084D306 /* ParseHookFunctionable.swift in Sources */,\n\t\t\t\t703B095526BF47FD005A112F /* ParseTwitter+async.swift in Sources */,\n\t\t\t\t70CE0ABE285F8FF900DAEA86 /* ParseTypeable.swift in Sources */,\n\t\t\t\t70BC9892252A5B5C00FF3074 /* Objectable.swift in Sources */,\n\t\t\t\tF97B465424D9C78C00F4A88B /* AddUnique.swift in Sources */,\n\t\t\t\tF97B464C24D9C78B00F4A88B /* Delete.swift in Sources */,\n\t\t\t\t706436A627341F6E007C6461 /* Encodable.swift in Sources */,\n\t\t\t\tF97B461424D9C6F200F4A88B /* Savable.swift in Sources */,\n\t\t\t\t70CE0A9628590A0A00DAEA86 /* ParseHookResponse.swift in Sources */,\n\t\t\t\t70F03A4A2780D27700E5AFB4 /* ParseLinkedIn+async.swift in Sources */,\n\t\t\t\t70CE0AA528595E5E00DAEA86 /* ParseHookRequestable.swift in Sources */,\n\t\t\t\t703B090E26BD984D005A112F /* ParseConfig+async.swift in Sources */,\n\t\t\t\tF97B462424D9C6F200F4A88B /* ParseKeyValueStore.swift in Sources */,\n\t\t\t\t70F03A2D2780BE2B00E5AFB4 /* ParseGoogle+combine.swift in Sources */,\n\t\t\t\tF97B466124D9C7B500F4A88B /* KeychainStore.swift in Sources */,\n\t\t\t\t703B094B26BF47D0005A112F /* ParseLDAP+async.swift in Sources */,\n\t\t\t\tF97B463D24D9C74400F4A88B /* API+Command.swift in Sources */,\n\t\t\t\t70CE0AAA28595FCE00DAEA86 /* ParseHookRequestable+async.swift in Sources */,\n\t\t\t\tF97B462924D9C72700F4A88B /* API.swift in Sources */,\n\t\t\t\tF97B463124D9C74400F4A88B /* BatchUtils.swift in Sources */,\n\t\t\t\t7016ED6625C4C46B00038648 /* ParseObject+combine.swift in Sources */,\n\t\t\t\t705025F22851542D008D6624 /* ParsePushFirebasePayloadable.swift in Sources */,\n\t\t\t\t705025DD284D0D56008D6624 /* ParsePushAppleSound.swift in Sources */,\n\t\t\t\tF97B45F024D9C6F200F4A88B /* BaseParseUser.swift in Sources */,\n\t\t\t\t70CE0ACD285FD5CB00DAEA86 /* ParseHookTriggerable+async.swift in Sources */,\n\t\t\t\t705025C4284C7842008D6624 /* ParsePush+async.swift in Sources */,\n\t\t\t\tF97B45D824D9C6F200F4A88B /* ParseEncoder.swift in Sources */,\n\t\t\t\t70647E9E259E3A9A004C1004 /* ParseEncodable.swift in Sources */,\n\t\t\t\t707A3C1325B0A8E8000D215C /* ParseAnonymous.swift in Sources */,\n\t\t\t\t912C9BE024D302B0009947C3 /* Parse.swift in Sources */,\n\t\t\t\t70F03A3B2780CA6F00E5AFB4 /* ParseGitHub+async.swift in Sources */,\n\t\t\t\tF97B461824D9C6F200F4A88B /* Queryable.swift in Sources */,\n\t\t\t\t705025E22851006F008D6624 /* ParsePushPayloadFirebase.swift in Sources */,\n\t\t\t\t70C5507925B49D3A00B5DBC2 /* ParseRole.swift in Sources */,\n\t\t\t\t703B093C26BF4799005A112F /* ParseApple+combine.swift in Sources */,\n\t\t\t\t7044C18525C4EFC10011F6E7 /* ParseConfig+combine.swift in Sources */,\n\t\t\t\t7016ED3425C3BA2000038648 /* ParseUser+combine.swift in Sources */,\n\t\t\t\t703B091826BD99BC005A112F /* ParseLiveQuery+async.swift in Sources */,\n\t\t\t);\n\t\t\trunOnlyForDeploymentPostprocessing = 0;\n\t\t};\n/* End PBXSourcesBuildPhase section */\n\n/* Begin PBXTargetDependency section */\n\t\t4AA8076B1F79424A008CD551 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 4AA807571F794242008CD551 /* TestHost */;\n\t\t\ttargetProxy = 4AA8076A1F79424A008CD551 /* PBXContainerItemProxy */;\n\t\t};\n\t\t4AB8B5001F254AE10070F682 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 4AB8B4F31F254AE10070F682 /* ParseSwift (iOS) */;\n\t\t\ttargetProxy = 4AB8B4FF1F254AE10070F682 /* PBXContainerItemProxy */;\n\t\t};\n\t\t7033ECCC25584AAF009770F3 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 7033ECAF25584A83009770F3 /* TestHostTV */;\n\t\t\ttargetProxy = 7033ECCB25584AAF009770F3 /* PBXContainerItemProxy */;\n\t\t};\n\t\t709B98372556EC7400507778 /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 912C9BD724D3011F009947C3 /* ParseSwift (tvOS) */;\n\t\t\ttargetProxy = 709B98362556EC7400507778 /* PBXContainerItemProxy */;\n\t\t};\n\t\t70F2E257254F247000B2EA5C /* PBXTargetDependency */ = {\n\t\t\tisa = PBXTargetDependency;\n\t\t\ttarget = 4AFDA7111F26D9A5002AE4FC /* ParseSwift (macOS) */;\n\t\t\ttargetProxy = 70F2E256254F247000B2EA5C /* PBXContainerItemProxy */;\n\t\t};\n/* End PBXTargetDependency section */\n\n/* Begin PBXVariantGroup section */\n\t\t4AA8075E1F794242008CD551 /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4AA8075F1F794242008CD551 /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t4AA807631F794242008CD551 /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t4AA807641F794242008CD551 /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t7033ECB625584A83009770F3 /* Main.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t7033ECB725584A83009770F3 /* Base */,\n\t\t\t);\n\t\t\tname = Main.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n\t\t7033ECBB25584A85009770F3 /* LaunchScreen.storyboard */ = {\n\t\t\tisa = PBXVariantGroup;\n\t\t\tchildren = (\n\t\t\t\t7033ECBC25584A85009770F3 /* Base */,\n\t\t\t);\n\t\t\tname = LaunchScreen.storyboard;\n\t\t\tsourceTree = \"<group>\";\n\t\t};\n/* End PBXVariantGroup section */\n\n/* Begin XCBuildConfiguration section */\n\t\t4AA807681F794242008CD551 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_CODE_COVERAGE = NO;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tGCC_GENERATE_TEST_COVERAGE_FILES = NO;\n\t\t\t\tINFOPLIST_FILE = TestHost/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.parse.TestHost;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t4AA807691F794242008CD551 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;\n\t\t\t\tCLANG_ENABLE_CODE_COVERAGE = NO;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tGCC_GENERATE_TEST_COVERAGE_FILES = NO;\n\t\t\t\tINFOPLIST_FILE = TestHost/Info.plist;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.parse.TestHost;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t4AB8B5061F254AE10070F682 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = dwarf;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tENABLE_TESTABILITY = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_DYNAMIC_NO_PIC = NO;\n\t\t\t\tGCC_GENERATE_TEST_COVERAGE_FILES = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_OPTIMIZATION_LEVEL = 0;\n\t\t\t\tGCC_PREPROCESSOR_DEFINITIONS = (\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t);\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.13;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = YES;\n\t\t\t\tONLY_ACTIVE_ARCH = YES;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-Onone\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 6.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t4AB8B5071F254AE10070F682 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_SEARCH_USER_PATHS = NO;\n\t\t\t\tCLANG_ANALYZER_NONNULL = YES;\n\t\t\t\tCLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;\n\t\t\t\tCLANG_CXX_LANGUAGE_STANDARD = \"gnu++14\";\n\t\t\t\tCLANG_CXX_LIBRARY = \"libc++\";\n\t\t\t\tCLANG_ENABLE_MODULES = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_ARC = YES;\n\t\t\t\tCLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;\n\t\t\t\tCLANG_WARN_BOOL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_COMMA = YES;\n\t\t\t\tCLANG_WARN_CONSTANT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;\n\t\t\t\tCLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;\n\t\t\t\tCLANG_WARN_DOCUMENTATION_COMMENTS = YES;\n\t\t\t\tCLANG_WARN_EMPTY_BODY = YES;\n\t\t\t\tCLANG_WARN_ENUM_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_INFINITE_RECURSION = YES;\n\t\t\t\tCLANG_WARN_INT_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;\n\t\t\t\tCLANG_WARN_OBJC_LITERAL_CONVERSION = YES;\n\t\t\t\tCLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;\n\t\t\t\tCLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;\n\t\t\t\tCLANG_WARN_RANGE_LOOP_ANALYSIS = YES;\n\t\t\t\tCLANG_WARN_STRICT_PROTOTYPES = YES;\n\t\t\t\tCLANG_WARN_SUSPICIOUS_MOVE = YES;\n\t\t\t\tCLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;\n\t\t\t\tCLANG_WARN_UNREACHABLE_CODE = YES;\n\t\t\t\tCLANG_WARN__DUPLICATE_METHOD_MATCH = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"iPhone Developer\";\n\t\t\t\tCOPY_PHASE_STRIP = NO;\n\t\t\t\tCURRENT_PROJECT_VERSION = 1;\n\t\t\t\tDEBUG_INFORMATION_FORMAT = \"dwarf-with-dsym\";\n\t\t\t\tENABLE_NS_ASSERTIONS = NO;\n\t\t\t\tENABLE_STRICT_OBJC_MSGSEND = YES;\n\t\t\t\tGCC_C_LANGUAGE_STANDARD = gnu11;\n\t\t\t\tGCC_GENERATE_TEST_COVERAGE_FILES = NO;\n\t\t\t\tGCC_NO_COMMON_BLOCKS = YES;\n\t\t\t\tGCC_WARN_64_TO_32_BIT_CONVERSION = YES;\n\t\t\t\tGCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;\n\t\t\t\tGCC_WARN_UNDECLARED_SELECTOR = YES;\n\t\t\t\tGCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;\n\t\t\t\tGCC_WARN_UNUSED_FUNCTION = YES;\n\t\t\t\tGCC_WARN_UNUSED_VARIABLE = YES;\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.13;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = NO;\n\t\t\t\tSDKROOT = iphoneos;\n\t\t\t\tSWIFT_COMPILATION_MODE = wholemodule;\n\t\t\t\tSWIFT_OPTIMIZATION_LEVEL = \"-O\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tVALIDATE_PRODUCT = YES;\n\t\t\t\tVERSIONING_SYSTEM = \"apple-generic\";\n\t\t\t\tVERSION_INFO_PREFIX = \"\";\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 6.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t4AB8B5091F254AE10070F682 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_IDENTITY = \"\";\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tGCC_GENERATE_TEST_COVERAGE_FILES = YES;\n\t\t\t\tINFOPLIST_FILE = \"ParseSwift-iOS/Info.plist\";\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.8.3;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwift;\n\t\t\t\tPRODUCT_NAME = ParseSwift;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_SWIFT3_OBJC_INFERENCE = Off;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 12.0;\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t4AB8B50A1F254AE10070F682 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_IDENTITY = \"\";\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tGCC_GENERATE_TEST_COVERAGE_FILES = YES;\n\t\t\t\tINFOPLIST_FILE = \"ParseSwift-iOS/Info.plist\";\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tIPHONEOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.8.3;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwift;\n\t\t\t\tPRODUCT_NAME = ParseSwift;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_SWIFT3_OBJC_INFERENCE = Off;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 12.0;\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 5.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t4AB8B50C1F254AE10070F682 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tCLANG_ENABLE_CODE_COVERAGE = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=macosx*]\" = \"-\";\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tGCC_GENERATE_TEST_COVERAGE_FILES = YES;\n\t\t\t\tINFOPLIST_FILE = Tests/ParseSwiftTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwiftTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\t\"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]\" = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/TestHost.app/TestHost\";\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t4AB8B50D1F254AE10070F682 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;\n\t\t\t\tCLANG_ENABLE_CODE_COVERAGE = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"Apple Development\";\n\t\t\t\t\"CODE_SIGN_IDENTITY[sdk=macosx*]\" = \"-\";\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tGCC_GENERATE_TEST_COVERAGE_FILES = YES;\n\t\t\t\tINFOPLIST_FILE = Tests/ParseSwiftTests/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwiftTests;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\t\"PROVISIONING_PROFILE_SPECIFIER[sdk=macosx*]\" = \"\";\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = \"1,2\";\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/TestHost.app/TestHost\";\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t4AFDA7241F26D9A5002AE4FC /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tDEAD_CODE_STRIPPING = YES;\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tFRAMEWORK_VERSION = A;\n\t\t\t\tGCC_GENERATE_TEST_COVERAGE_FILES = YES;\n\t\t\t\tINFOPLIST_FILE = \"ParseSwift-macOS/Info.plist\";\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.15;\n\t\t\t\tMARKETING_VERSION = 1.8.3;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwift;\n\t\t\t\tPRODUCT_NAME = ParseSwift;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_SWIFT3_OBJC_INFERENCE = Off;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 12.0;\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t4AFDA7251F26D9A5002AE4FC /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tDEAD_CODE_STRIPPING = YES;\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tFRAMEWORK_VERSION = A;\n\t\t\t\tGCC_GENERATE_TEST_COVERAGE_FILES = YES;\n\t\t\t\tINFOPLIST_FILE = \"ParseSwift-macOS/Info.plist\";\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.15;\n\t\t\t\tMARKETING_VERSION = 1.8.3;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwift;\n\t\t\t\tPRODUCT_NAME = ParseSwift;\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_SWIFT3_OBJC_INFERENCE = Off;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 12.0;\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 5.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t7033ECBF25584A85009770F3 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = \"App Icon & Top Shelf Image\";\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCLANG_ENABLE_CODE_COVERAGE = NO;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tGCC_GENERATE_TEST_COVERAGE_FILES = NO;\n\t\t\t\tINFOPLIST_FILE = TestHostTV/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.parse.TestHostTV;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = appletvos;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 3;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t7033ECC025584A85009770F3 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tASSETCATALOG_COMPILER_APPICON_NAME = \"App Icon & Top Shelf Image\";\n\t\t\t\tASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;\n\t\t\t\tCLANG_ENABLE_CODE_COVERAGE = NO;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_STYLE = Automatic;\n\t\t\t\tGCC_GENERATE_TEST_COVERAGE_FILES = NO;\n\t\t\t\tINFOPLIST_FILE = TestHostTV/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = com.parse.TestHostTV;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tSDKROOT = appletvos;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 3;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t709B98382556EC7400507778 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_CODE_COVERAGE = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tGCC_GENERATE_TEST_COVERAGE_FILES = YES;\n\t\t\t\tINFOPLIST_FILE = ParseSwiftTeststvOS/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = edu.uky.cs.netrecon.ParseSwiftTeststvOS;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSDKROOT = appletvos;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 3;\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/TestHostTV.app/TestHostTV\";\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 14.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t709B98392556EC7400507778 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_CODE_COVERAGE = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tGCC_GENERATE_TEST_COVERAGE_FILES = YES;\n\t\t\t\tINFOPLIST_FILE = ParseSwiftTeststvOS/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = edu.uky.cs.netrecon.ParseSwiftTeststvOS;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSDKROOT = appletvos;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 3;\n\t\t\t\tTEST_HOST = \"$(BUILT_PRODUCTS_DIR)/TestHostTV.app/TestHostTV\";\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 14.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t70F2E259254F247000B2EA5C /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_CODE_COVERAGE = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tDEAD_CODE_STRIPPING = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tGCC_GENERATE_TEST_COVERAGE_FILES = YES;\n\t\t\t\tINFOPLIST_FILE = ParseSwiftTestsmacOS/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t\t\"@loader_path/../Frameworks\",\n\t\t\t\t);\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.15;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = edu.uky.cs.netrecon.ParseSwiftTestsmacOS;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t70F2E25A254F247000B2EA5C /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_CODE_COVERAGE = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_IDENTITY = \"-\";\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tCOMBINE_HIDPI_IMAGES = YES;\n\t\t\t\tDEAD_CODE_STRIPPING = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tGCC_GENERATE_TEST_COVERAGE_FILES = YES;\n\t\t\t\tINFOPLIST_FILE = ParseSwiftTestsmacOS/Info.plist;\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/../Frameworks\",\n\t\t\t\t\t\"@loader_path/../Frameworks\",\n\t\t\t\t);\n\t\t\t\tMACOSX_DEPLOYMENT_TARGET = 10.15;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = edu.uky.cs.netrecon.ParseSwiftTestsmacOS;\n\t\t\t\tPRODUCT_NAME = \"$(TARGET_NAME)\";\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSDKROOT = macosx;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t912C9BD124D3005D009947C3 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tAPPLICATION_EXTENSION_API_ONLY = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tGCC_GENERATE_TEST_COVERAGE_FILES = YES;\n\t\t\t\tINFOPLIST_FILE = \"ParseSwift-watchOS/Info.plist\";\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.8.3;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.parse.ParseSwift-watchOS\";\n\t\t\t\tPRODUCT_NAME = ParseSwift;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSDKROOT = watchos;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 4;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 12.0;\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 6.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t912C9BD224D3005D009947C3 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tAPPLICATION_EXTENSION_API_ONLY = YES;\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tGCC_GENERATE_TEST_COVERAGE_FILES = YES;\n\t\t\t\tINFOPLIST_FILE = \"ParseSwift-watchOS/Info.plist\";\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.8.3;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.parse.ParseSwift-watchOS\";\n\t\t\t\tPRODUCT_NAME = ParseSwift;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSDKROOT = watchos;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 4;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 12.0;\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 6.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n\t\t912C9BDE24D3011F009947C3 /* Debug */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tGCC_GENERATE_TEST_COVERAGE_FILES = YES;\n\t\t\t\tINFOPLIST_FILE = \"ParseSwift-tvOS/Info.plist\";\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.8.3;\n\t\t\t\tMTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.parse.ParseSwift-tvOS\";\n\t\t\t\tPRODUCT_NAME = ParseSwift;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSDKROOT = appletvos;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 3;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 5.0;\n\t\t\t};\n\t\t\tname = Debug;\n\t\t};\n\t\t912C9BDF24D3011F009947C3 /* Release */ = {\n\t\t\tisa = XCBuildConfiguration;\n\t\t\tbuildSettings = {\n\t\t\t\tCLANG_ENABLE_OBJC_WEAK = YES;\n\t\t\t\tCODE_SIGN_STYLE = Manual;\n\t\t\t\tDEFINES_MODULE = YES;\n\t\t\t\tDEVELOPMENT_TEAM = \"\";\n\t\t\t\tDYLIB_COMPATIBILITY_VERSION = 1;\n\t\t\t\tDYLIB_CURRENT_VERSION = 1;\n\t\t\t\tDYLIB_INSTALL_NAME_BASE = \"@rpath\";\n\t\t\t\tGCC_GENERATE_TEST_COVERAGE_FILES = YES;\n\t\t\t\tINFOPLIST_FILE = \"ParseSwift-tvOS/Info.plist\";\n\t\t\t\tINSTALL_PATH = \"$(LOCAL_LIBRARY_DIR)/Frameworks\";\n\t\t\t\tLD_RUNPATH_SEARCH_PATHS = (\n\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t\t\"@loader_path/Frameworks\",\n\t\t\t\t);\n\t\t\t\tMARKETING_VERSION = 1.8.3;\n\t\t\t\tMTL_FAST_MATH = YES;\n\t\t\t\tPRODUCT_BUNDLE_IDENTIFIER = \"com.parse.ParseSwift-tvOS\";\n\t\t\t\tPRODUCT_NAME = ParseSwift;\n\t\t\t\tPROVISIONING_PROFILE_SPECIFIER = \"\";\n\t\t\t\tSDKROOT = appletvos;\n\t\t\t\tSKIP_INSTALL = YES;\n\t\t\t\tSWIFT_VERSION = 5.0;\n\t\t\t\tTARGETED_DEVICE_FAMILY = 3;\n\t\t\t\tTVOS_DEPLOYMENT_TARGET = 13.0;\n\t\t\t\tWATCHOS_DEPLOYMENT_TARGET = 5.0;\n\t\t\t};\n\t\t\tname = Release;\n\t\t};\n/* End XCBuildConfiguration section */\n\n/* Begin XCConfigurationList section */\n\t\t4AA807671F794242008CD551 /* Build configuration list for PBXNativeTarget \"TestHost\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t4AA807681F794242008CD551 /* Debug */,\n\t\t\t\t4AA807691F794242008CD551 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t4AB8B4EE1F254AE10070F682 /* Build configuration list for PBXProject \"ParseSwift\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t4AB8B5061F254AE10070F682 /* Debug */,\n\t\t\t\t4AB8B5071F254AE10070F682 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t4AB8B5081F254AE10070F682 /* Build configuration list for PBXNativeTarget \"ParseSwift (iOS)\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t4AB8B5091F254AE10070F682 /* Debug */,\n\t\t\t\t4AB8B50A1F254AE10070F682 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t4AB8B50B1F254AE10070F682 /* Build configuration list for PBXNativeTarget \"ParseSwiftTests\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t4AB8B50C1F254AE10070F682 /* Debug */,\n\t\t\t\t4AB8B50D1F254AE10070F682 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t4AFDA7231F26D9A5002AE4FC /* Build configuration list for PBXNativeTarget \"ParseSwift (macOS)\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t4AFDA7241F26D9A5002AE4FC /* Debug */,\n\t\t\t\t4AFDA7251F26D9A5002AE4FC /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t7033ECC125584A85009770F3 /* Build configuration list for PBXNativeTarget \"TestHostTV\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t7033ECBF25584A85009770F3 /* Debug */,\n\t\t\t\t7033ECC025584A85009770F3 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t709B983A2556EC7400507778 /* Build configuration list for PBXNativeTarget \"ParseSwiftTeststvOS\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t709B98382556EC7400507778 /* Debug */,\n\t\t\t\t709B98392556EC7400507778 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t70F2E258254F247000B2EA5C /* Build configuration list for PBXNativeTarget \"ParseSwiftTestsmacOS\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t70F2E259254F247000B2EA5C /* Debug */,\n\t\t\t\t70F2E25A254F247000B2EA5C /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t912C9BD024D3005D009947C3 /* Build configuration list for PBXNativeTarget \"ParseSwift (watchOS)\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t912C9BD124D3005D009947C3 /* Debug */,\n\t\t\t\t912C9BD224D3005D009947C3 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n\t\t912C9BDD24D3011F009947C3 /* Build configuration list for PBXNativeTarget \"ParseSwift (tvOS)\" */ = {\n\t\t\tisa = XCConfigurationList;\n\t\t\tbuildConfigurations = (\n\t\t\t\t912C9BDE24D3011F009947C3 /* Debug */,\n\t\t\t\t912C9BDF24D3011F009947C3 /* Release */,\n\t\t\t);\n\t\t\tdefaultConfigurationIsVisible = 0;\n\t\t\tdefaultConfigurationName = Release;\n\t\t};\n/* End XCConfigurationList section */\n\t};\n\trootObject = 4AB8B4EB1F254AE10070F682 /* Project object */;\n}\n"
  },
  {
    "path": "ParseSwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n   version = \"1.0\">\n   <FileRef\n      location = \"self:\">\n   </FileRef>\n</Workspace>\n"
  },
  {
    "path": "ParseSwift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>IDEDidComputeMac32BitWarning</key>\n\t<true/>\n</dict>\n</plist>\n"
  },
  {
    "path": "ParseSwift.xcodeproj/xcshareddata/xcschemes/ParseSwift (iOS).xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1400\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"4AB8B4F31F254AE10070F682\"\n               BuildableName = \"ParseSwift.framework\"\n               BlueprintName = \"ParseSwift (iOS)\"\n               ReferencedContainer = \"container:ParseSwift.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      codeCoverageEnabled = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"4AB8B4F31F254AE10070F682\"\n            BuildableName = \"ParseSwift.framework\"\n            BlueprintName = \"ParseSwift (iOS)\"\n            ReferencedContainer = \"container:ParseSwift.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n      <Testables>\n         <TestableReference\n            skipped = \"NO\"\n            testExecutionOrdering = \"random\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"4AB8B4FC1F254AE10070F682\"\n               BuildableName = \"ParseSwiftTests.xctest\"\n               BlueprintName = \"ParseSwiftTests\"\n               ReferencedContainer = \"container:ParseSwift.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"4AB8B4F31F254AE10070F682\"\n            BuildableName = \"ParseSwift.framework\"\n            BlueprintName = \"ParseSwift (iOS)\"\n            ReferencedContainer = \"container:ParseSwift.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"4AB8B4F31F254AE10070F682\"\n            BuildableName = \"ParseSwift.framework\"\n            BlueprintName = \"ParseSwift (iOS)\"\n            ReferencedContainer = \"container:ParseSwift.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "ParseSwift.xcodeproj/xcshareddata/xcschemes/ParseSwift (macOS).xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1400\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"4AFDA7111F26D9A5002AE4FC\"\n               BuildableName = \"ParseSwift.framework\"\n               BlueprintName = \"ParseSwift (macOS)\"\n               ReferencedContainer = \"container:ParseSwift.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      codeCoverageEnabled = \"YES\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\"\n            testExecutionOrdering = \"random\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"70F2E24F254F247000B2EA5C\"\n               BuildableName = \"ParseSwiftTestsmacOS.xctest\"\n               BlueprintName = \"ParseSwiftTestsmacOS\"\n               ReferencedContainer = \"container:ParseSwift.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"4AFDA7111F26D9A5002AE4FC\"\n            BuildableName = \"ParseSwift.framework\"\n            BlueprintName = \"ParseSwift (macOS)\"\n            ReferencedContainer = \"container:ParseSwift.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"4AFDA7111F26D9A5002AE4FC\"\n            BuildableName = \"ParseSwift.framework\"\n            BlueprintName = \"ParseSwift (macOS)\"\n            ReferencedContainer = \"container:ParseSwift.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "ParseSwift.xcodeproj/xcshareddata/xcschemes/ParseSwift (tvOS).xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1400\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"912C9BD724D3011F009947C3\"\n               BuildableName = \"ParseSwift.framework\"\n               BlueprintName = \"ParseSwift (tvOS)\"\n               ReferencedContainer = \"container:ParseSwift.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      codeCoverageEnabled = \"YES\">\n      <Testables>\n         <TestableReference\n            skipped = \"NO\"\n            testExecutionOrdering = \"random\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"709B982F2556EC7400507778\"\n               BuildableName = \"ParseSwiftTeststvOS.xctest\"\n               BlueprintName = \"ParseSwiftTeststvOS\"\n               ReferencedContainer = \"container:ParseSwift.xcodeproj\">\n            </BuildableReference>\n         </TestableReference>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"912C9BD724D3011F009947C3\"\n            BuildableName = \"ParseSwift.framework\"\n            BlueprintName = \"ParseSwift (tvOS)\"\n            ReferencedContainer = \"container:ParseSwift.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "ParseSwift.xcodeproj/xcshareddata/xcschemes/ParseSwift (watchOS).xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1400\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"912C9BCA24D3005D009947C3\"\n               BuildableName = \"ParseSwift.framework\"\n               BlueprintName = \"ParseSwift (watchOS)\"\n               ReferencedContainer = \"container:ParseSwift.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      codeCoverageEnabled = \"YES\">\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <MacroExpansion>\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"912C9BCA24D3005D009947C3\"\n            BuildableName = \"ParseSwift.framework\"\n            BlueprintName = \"ParseSwift (watchOS)\"\n            ReferencedContainer = \"container:ParseSwift.xcodeproj\">\n         </BuildableReference>\n      </MacroExpansion>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "ParseSwift.xcodeproj/xcshareddata/xcschemes/TestHost.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1400\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"4AA807571F794242008CD551\"\n               BuildableName = \"TestHost.app\"\n               BlueprintName = \"TestHost\"\n               ReferencedContainer = \"container:ParseSwift.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"4AA807571F794242008CD551\"\n            BuildableName = \"TestHost.app\"\n            BlueprintName = \"TestHost\"\n            ReferencedContainer = \"container:ParseSwift.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"4AA807571F794242008CD551\"\n            BuildableName = \"TestHost.app\"\n            BlueprintName = \"TestHost\"\n            ReferencedContainer = \"container:ParseSwift.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "ParseSwift.xcodeproj/xcshareddata/xcschemes/TestHostTV.xcscheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n   LastUpgradeVersion = \"1400\"\n   version = \"1.3\">\n   <BuildAction\n      parallelizeBuildables = \"YES\"\n      buildImplicitDependencies = \"YES\">\n      <BuildActionEntries>\n         <BuildActionEntry\n            buildForTesting = \"YES\"\n            buildForRunning = \"YES\"\n            buildForProfiling = \"YES\"\n            buildForArchiving = \"YES\"\n            buildForAnalyzing = \"YES\">\n            <BuildableReference\n               BuildableIdentifier = \"primary\"\n               BlueprintIdentifier = \"7033ECAF25584A83009770F3\"\n               BuildableName = \"TestHostTV.app\"\n               BlueprintName = \"TestHostTV\"\n               ReferencedContainer = \"container:ParseSwift.xcodeproj\">\n            </BuildableReference>\n         </BuildActionEntry>\n      </BuildActionEntries>\n   </BuildAction>\n   <TestAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\">\n      <Testables>\n      </Testables>\n   </TestAction>\n   <LaunchAction\n      buildConfiguration = \"Debug\"\n      selectedDebuggerIdentifier = \"Xcode.DebuggerFoundation.Debugger.LLDB\"\n      selectedLauncherIdentifier = \"Xcode.DebuggerFoundation.Launcher.LLDB\"\n      launchStyle = \"0\"\n      useCustomWorkingDirectory = \"NO\"\n      ignoresPersistentStateOnLaunch = \"NO\"\n      debugDocumentVersioning = \"YES\"\n      debugServiceExtension = \"internal\"\n      allowLocationSimulation = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"7033ECAF25584A83009770F3\"\n            BuildableName = \"TestHostTV.app\"\n            BlueprintName = \"TestHostTV\"\n            ReferencedContainer = \"container:ParseSwift.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </LaunchAction>\n   <ProfileAction\n      buildConfiguration = \"Release\"\n      shouldUseLaunchSchemeArgsEnv = \"YES\"\n      savedToolIdentifier = \"\"\n      useCustomWorkingDirectory = \"NO\"\n      debugDocumentVersioning = \"YES\">\n      <BuildableProductRunnable\n         runnableDebuggingMode = \"0\">\n         <BuildableReference\n            BuildableIdentifier = \"primary\"\n            BlueprintIdentifier = \"7033ECAF25584A83009770F3\"\n            BuildableName = \"TestHostTV.app\"\n            BlueprintName = \"TestHostTV\"\n            ReferencedContainer = \"container:ParseSwift.xcodeproj\">\n         </BuildableReference>\n      </BuildableProductRunnable>\n   </ProfileAction>\n   <AnalyzeAction\n      buildConfiguration = \"Debug\">\n   </AnalyzeAction>\n   <ArchiveAction\n      buildConfiguration = \"Release\"\n      revealArchiveInOrganizer = \"YES\">\n   </ArchiveAction>\n</Scheme>\n"
  },
  {
    "path": "ParseSwiftTestsmacOS/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n    <key>NSAppTransportSecurity</key>\n    <dict>\n        <key>NSAllowsArbitraryLoads</key>\n        <false/>\n        <key>NSExceptionDomains</key>\n        <dict>\n            <key>localhost</key>\n            <dict>\n                <key>NSAllowsArbitraryLoads</key>\n                <true/>\n            </dict>\n        </dict>\n    </dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "ParseSwiftTeststvOS/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n    <key>NSAppTransportSecurity</key>\n    <dict>\n        <key>NSAllowsArbitraryLoads</key>\n        <false/>\n        <key>NSExceptionDomains</key>\n        <dict>\n            <key>localhost</key>\n            <dict>\n                <key>NSAllowsArbitraryLoads</key>\n                <true/>\n            </dict>\n        </dict>\n    </dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "README.md",
    "content": "![parse-repository-header-sdk-swift](https://user-images.githubusercontent.com/5673677/138289926-a26ca0bd-1713-4c30-b69a-acd840ccead0.png)\n\n<h3 align=\"center\">iOS · macOS · watchOS · tvOS · Linux · Android · Windows</h3>\n\n---\n\n[![Build Status CI](https://github.com/parse-community/Parse-Swift/workflows/ci/badge.svg?branch=main)](https://github.com/parse-community/Parse-Swift/actions?query=workflow%3Aci+branch%3Amain)\n[![Build Status Release](https://github.com/parse-community/Parse-Swift/workflows/release/badge.svg)](https://github.com/parse-community/Parse-Swift/actions?query=workflow%3Arelease)\n[![Coverage](https://codecov.io/gh/parse-community/Parse-Swift/branch/main/graph/badge.svg)](https://codecov.io/gh/parse-community/Parse-Swift/branches)\n[![Carthage](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/carthage/carthage)\n[![Pod](https://img.shields.io/cocoapods/v/ParseSwift.svg)](https://cocoapods.org/pods/ParseSwift)\n\n[![Swift Versions](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fparse-community%2FParse-Swift%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/parse-community/Parse-Swift)\n[![Platforms](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fparse-community%2FParse-Swift%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/parse-community/Parse-Swift)\n\n[![Backers on Open Collective](https://opencollective.com/parse-server/backers/badge.svg)][open-collective-link]\n[![Sponsors on Open Collective](https://opencollective.com/parse-server/sponsors/badge.svg)][open-collective-link]\n[![License](https://img.shields.io/badge/license-MIT-lightgrey.svg)][license-link]\n[![Forum](https://img.shields.io/discourse/https/community.parseplatform.org/topics.svg)](https://community.parseplatform.org/c/client-sdks/parseswift-sdk)\n[![Twitter](https://img.shields.io/twitter/follow/ParsePlatform.svg?label=Follow&style=social)](https://twitter.com/intent/follow?screen_name=ParsePlatform)\n\n---\n\nA pure Swift library that gives you access to the powerful Parse Server backend from your Swift applications.\n\nFor more information about the Parse Platform and its features, see the public [documentation][docs]. The ParseSwift SDK is not a port of the [Parse-SDK-iOS-OSX SDK](https://github.com/parse-community/Parse-SDK-iOS-OSX) and though some of it may feel familiar, it is not backwards compatible and is designed using [protocol oriented programming (POP) and value types](https://www.pluralsight.com/guides/protocol-oriented-programming-in-swift) instead of OOP and reference types. You can learn more about POP by watching [Protocol-Oriented Programming in Swift](https://developer.apple.com/videos/play/wwdc2015/408/) or [Protocol and Value Oriented Programming in UIKit Apps](https://developer.apple.com/videos/play/wwdc2016/419/) videos from previous WWDC's. For more details about ParseSwift, visit the [api documentation](http://parseplatform.org/Parse-Swift/release/documentation/parseswift/).\n\nTo learn how to use or experiment with ParseSwift, you can run and edit the [ParseSwift.playground](https://github.com/parse-community/Parse-Swift/tree/main/ParseSwift.playground/Pages). You can use the parse-server in [this repo](https://github.com/netreconlab/parse-hipaa/tree/parse-swift) which has docker compose files (`docker-compose up` gives you a working server) configured to connect with the playground files, has [Parse Dashboard](https://github.com/parse-community/parse-dashboard), and can be used with MongoDB or PostgreSQL. You can also configure the Swift Playgrounds to work with your own Parse Server by editing the configuation in [Common.swift](https://github.com/parse-community/Parse-Swift/blob/e9ba846c399257100b285d25d2bd055628b13b4b/ParseSwift.playground/Sources/Common.swift#L4-L19). To learn more, check out [CONTRIBUTING.md](https://github.com/parse-community/Parse-Swift/blob/main/CONTRIBUTING.md#swift-playgrounds).\n\n---\n\n- [Installation](#installation)\n  - [Swift Package Manager](#swift-package-manager)\n  - [CocoaPods](#cocoapods)\n  - [Carthage](#carthage)\n- [Usage Guide](#usage-guide)\n- [LiveQuery](#livequery)\n  - [Setup Server](#setup-server)\n  - [Use Client](#use-client)\n    - [SwiftUI View Models Using Combine](#swiftui-view-models-using-combine)\n    - [Traditional Callbacks](#traditional-callbacks)\n  - [Advanced Usage](#advanced-usage)\n- [Migration from Parse ObjC SDK](#migration-from-parse-objc-sdk)\n\n## Installation\n\n### [Swift Package Manager](https://swift.org/package-manager/)\n\nYou can use The Swift Package Manager (SPM) to install ParseSwift by adding the following description to your `Package.swift` file:\n\n```swift\n// swift-tools-version:5.5\nimport PackageDescription\n\nlet package = Package(\n    name: \"YOUR_PROJECT_NAME\",\n    dependencies: [\n        .package(url: \"https://github.com/parse-community/Parse-Swift\", .upToNextMajor(from: \"4.0.0\")),\n    ]\n)\n```\nThen run `swift build`. \n\nYou can also install using SPM in your Xcode project by going to \n\"Project->NameOfYourProject->Swift Packages\" and placing `https://github.com/parse-community/Parse-Swift.git` in the \nsearch field.\n\n### [CocoaPods](https://cocoapods.org)\n\nAdd the following line to your Podfile:\n\n```ruby\npod 'ParseSwift'\n```\n\nRun `pod install`, and you should now have the latest version from the main branch.\n\n### [Carthage](https://github.com/carthage/carthage)\n\nAdd the following line to your Cartfile:\n```\ngithub \"parse-community/Parse-Swift\"\n```\nRun `carthage update`, and you should now have the latest version of ParseSwift SDK in your Carthage folder.\n\n## Usage Guide\n\nAfter installing ParseSwift, to use it first `import ParseSwift` in your AppDelegate.swift and then add the following code in your `application:didFinishLaunchingWithOptions:` method:\n```swift\nParseSwift.initialize(applicationId: \"xxxxxxxxxx\", clientKey: \"xxxxxxxxxx\", serverURL: URL(string: \"https://example.com\")!)\n```\nPlease checkout the [Swift Playground](https://github.com/parse-community/Parse-Swift/tree/main/ParseSwift.playground) for more usage information.\n\n## LiveQuery\n\n`Query` is one of the key concepts on the Parse Platform. It allows you to retrieve `ParseObject`s by specifying some conditions, making it easy to build apps such as a dashboard, a todo list or even some strategy games. However, `Query` is based on a pull model, which is not suitable for apps that need real-time support.\n\nSuppose you are building an app that allows multiple users to edit the same file at the same time. `Query` would not be an ideal tool since you can not know when to query from the server to get the updates.\n\nTo solve this problem, we introduce Parse LiveQuery. This tool allows you to subscribe to a `Query` you are interested in. Once subscribed, the server will notify clients whenever a `ParseObject` that matches the `Query` is created or updated, in real-time.\n\n### Setup Server\n\nParse LiveQuery contains two parts, the LiveQuery server and the LiveQuery clients (this SDK). In order to use live queries, you need to at least setup the server.\n\nThe easiest way to setup the LiveQuery server is to make it run with the [Open Source Parse Server](https://github.com/ParsePlatform/parse-server/wiki/Parse-LiveQuery#server-setup).\n\n\n### Use Client\n\n#### SwiftUI View Models Using Combine\n\nThe LiveQuery client interface is based around the concept of `Subscription`s. You can register any `Query` for live updates from the associated live query server and use the query as a view model for a SwiftUI view by simply using the `subscribe` property of a query:\n\n```swift\nlet myQuery = GameScore.query(\"points\" > 9)\n\nstruct ContentView: View {\n\n    //: A LiveQuery subscription can be used as a view model in SwiftUI\n    @StateObject var subscription = myQuery.subscribe!\n    \n    var body: some View {\n        VStack {\n\n            if subscription.subscribed != nil {\n                Text(\"Subscribed to query!\")\n            } else if subscription.unsubscribed != nil {\n                Text(\"Unsubscribed from query!\")\n            } else if let event = subscription.event {\n\n                //: This is how you register to receive notificaitons of events related to your LiveQuery.\n                switch event.event {\n\n                case .entered(let object):\n                    Text(\"Entered with points: \\(object.points)\")\n                case .left(let object):\n                    Text(\"Left with points: \\(object.points)\")\n                case .created(let object):\n                    Text(\"Created with points: \\(object.points)\")\n                case .updated(let object):\n                    Text(\"Updated with points: \\(object.points)\")\n                case .deleted(let object):\n                    Text(\"Deleted with points: \\(object.points)\")\n                }\n            } else {\n                Text(\"Not subscribed to a query\")\n            }\n\n            Spacer()\n\n            Text(\"Update GameScore in Parse Dashboard to see changes here\")\n\n            Button(action: {\n                try? query.unsubscribe()\n            }, label: {\n                Text(\"Unsubscribe\")\n                    .font(.headline)\n                    .background(Color.red)\n                    .foregroundColor(.white)\n                    .padding()\n                    .cornerRadius(20.0)\n                    .frame(width: 300, height: 50)\n            })\n        }\n    }\n}\n```\n\nor by calling the `subscribe(_ client: ParseLiveQuery)` method of a query. If you want to customize your view model more you can subclass `Subscription` or add the subscription to your own view model. You can test out LiveQuery subscriptions in [Swift Playgrounds](https://github.com/parse-community/Parse-Swift/blob/a8b3d00b848f3351d2c61a569d4ad4a3c96890d2/ParseSwift.playground/Pages/11%20-%20LiveQuery.xcplaygroundpage/Contents.swift#L38-L95).\n\n#### Traditional Callbacks\n\nYou can also use asynchronous call backs to subscribe to a LiveQuery:\n\n```swift\nlet myQuery = Message.query(\"from\" == \"parse\")\nguard let subscription = myQuery.subscribeCallback else {\n    print(\"Error subscribing...\")\n    return\n}\n```\n\nor by calling the `subscribeCallback(_ client: ParseLiveQuery)` method of a query.\n\nWhere `Message` is a ParseObject.\n\nOnce you've subscribed to a query, you can `handle` events on them, like so:\n\n```swift\nsubscription.handleSubscribe { subscribedQuery, isNew in\n\n    //Handle the subscription however you like.\n    if isNew {\n        print(\"Successfully subscribed to new query \\(subscribedQuery)\")\n    } else {\n        print(\"Successfully updated subscription to new query \\(subscribedQuery)\")\n    }\n}\n```\n\nYou can handle any event listed in the LiveQuery [spec](https://github.com/parse-community/parse-server/wiki/Parse-LiveQuery-Protocol-Specification#event-message):\n```swift\nsubscription.handleEvent { _, event in\n    // Called whenever an object was created\n    switch event {\n\n    case .entered(let object):\n        print(\"Entered: \\(object)\")\n    case .left(let object):\n        print(\"Left: \\(object)\")\n    case .created(let object):\n        print(\"Created: \\(object)\")\n    case .updated(let object):\n        print(\"Updated: \\(object)\")\n    case .deleted(let object):\n        print(\"Deleted: \\(object)\")\n    }\n}\n```\n\nSimiliarly, you can unsubscribe and register to be notified when it occurs:\n```swift\nsubscription.handleUnsubscribe { query in\n    print(\"Unsubscribed from \\(query)\")\n}\n\n//: To unsubscribe from your query.\ndo {\n    try query.unsubscribe()\n} catch {\n    print(error)\n}\n```\n\nHandling errors is and other events is similar, take a look at the `Subscription` class for more information. You can test out LiveQuery subscriptions in [Swift Playgrounds](https://github.com/parse-community/Parse-Swift/blob/a8b3d00b848f3351d2c61a569d4ad4a3c96890d2/ParseSwift.playground/Pages/11%20-%20LiveQuery.xcplaygroundpage/Contents.swift#L97-L142).\n\n### Advanced Usage\n\nYou are not limited to a single Live Query Client - you can create multiple instances of `ParseLiveQuery`, use certificate authentication and pinning, receive metrics about each client connection, connect to individual server URLs, and more.\n\n[docs]: https://docs.parseplatform.org\n[license-link]: LICENSE\n[open-collective-link]: https://opencollective.com/parse-server\n\n## Migration from Parse ObjC SDK\n\nSee the [Migration Guide](MIGRATION.md) to help you migrate from the Parse ObjC SDK."
  },
  {
    "path": "Scripts/carthage.sh",
    "content": "# carthage.sh\n# Usage example: ./carthage.sh build --platform iOS\n\nset -euo pipefail\n\nxcconfig=$(mktemp /tmp/static.xcconfig.XXXXXX)\ntrap 'rm -f \"$xcconfig\"' INT TERM HUP EXIT\n\n# For Xcode 12 make sure EXCLUDED_ARCHS is set to arm architectures otherwise\n# the build will fail on lipo due to duplicate architectures.\n\nCURRENT_XCODE_VERSION=$(xcodebuild -version | grep \"Build version\" | cut -d' ' -f3)\necho \"EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1200__BUILD_$CURRENT_XCODE_VERSION = arm64 arm64e armv7 armv7s armv6 armv8\" >> $xcconfig\n\necho 'EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1200 = $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_simulator__NATIVE_ARCH_64_BIT_x86_64__XCODE_1200__BUILD_$(XCODE_PRODUCT_BUILD_VERSION))' >> $xcconfig\necho 'EXCLUDED_ARCHS = $(inherited) $(EXCLUDED_ARCHS__EFFECTIVE_PLATFORM_SUFFIX_$(EFFECTIVE_PLATFORM_SUFFIX)__NATIVE_ARCH_64_BIT_$(NATIVE_ARCH_64_BIT)__XCODE_$(XCODE_VERSION_MAJOR))' >> $xcconfig\n\nexport XCODE_XCCONFIG_FILE=\"$xcconfig\"\ncarthage \"$@\"\n"
  },
  {
    "path": "Scripts/generate-documentation",
    "content": "#!/bin/bash\n#\n# Copyright (c) 2022, Apple Inc. All rights reserved.\n# \n# Redistribution and use in source and binary forms, with or without modification,\n# are permitted provided that the following conditions are met:\n# \n# 1.  Redistributions of source code must retain the above copyright notice, this\n# list of conditions and the following disclaimer.\n# \n# 2.  Redistributions in binary form must reproduce the above copyright notice,\n# this list of conditions and the following disclaimer in the documentation and/or\n# other materials provided with the distribution.\n# \n# 3. Neither the name of the copyright holder(s) nor the names of any contributors\n# may be used to endorse or promote products derived from this software without\n# specific prior written permission. No license is granted to the trademarks of\n# the copyright holders even if such marks are included in this software.\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE\n# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\n# A `realpath` alternative using the default C implementation.\nfilepath() {\n    [[ $1 = /* ]] && echo \"$1\" || echo \"$PWD/${1#./}\"\n}\n\n# First get the absolute path to this file so we can get the absolute file path to the Swift-DocC root source dir.\nPROJECT_ROOT=\"$(dirname $(dirname $(filepath $0)))\"\nDOCS_DIR=\"$PROJECT_ROOT/.build/swift-docc\"\nSGFS_DIR=\"$DOCS_DIR/symbol-graph-files\"\nTEMP_WORKSPACE_DIR=\"$DOCS_DIR/temporary-workspace-holding-directory\"\n\nDOCC_CMD=convert\nOUTPUT_PATH=\"$DOCS_DIR/ParseSwift.doccarchive\"\nHOSTING_BASE_PATH=\"\"\nPUBLISH=\"NO\"\n\n# Process command line arguments\nOUTPUT_PATH_PROCESSED=0\nHOSTING_BASE_PATH_PROCESSED=0\nwhile test $# -gt 0; do\n  case \"$1\" in\n    --help)\n      echo \"Usage: $(basename $0) [<output-path>] [<hosting-base-path>] [--preview] [--publish] [--help]\"\n      echo\n      echo \"Builds ParseSwift and generates or previews the Swift-DocC documentation.\"\n      echo\n      echo \"    --preview: Starts a preview server after generating documentation.\"\n      echo \"    --publish: Configures the documentation build for publishing on GitHub pages.\"\n      echo\n      exit 0\n      ;;\n    --preview)\n      DOCC_CMD=preview\n      shift\n      ;;\n    --publish)\n      PUBLISH=\"YES\"\n      shift\n    ;;\n    *)\n      if [ ${OUTPUT_PATH_PROCESSED} -eq 0 ]; then\n        OUTPUT_PATH=\"$1\"\n        OUTPUT_PATH_PROCESSED=1\n      elif [ ${HOSTING_BASE_PATH_PROCESSED} -eq 0 ]; then\n        HOSTING_BASE_PATH=\"$1\"\n        HOSTING_BASE_PATH_PROCESSED=1\n      else\n        echo \"Unrecognised argument \\\"$1\\\"\"\n        exit 1\n      fi\n      ;;\n  esac\n  shift\ndone\n\nif [ \"$PUBLISH\" = \"YES\" ]; then\n  if [ ${HOSTING_BASE_PATH_PROCESSED} -eq 0 ]; then\n    echo \"A hosting base path must be provided if the '--publish' flag is passed.\"\n    echo \"See '--help' for details.\"\n    exit 1\n  fi\nfi\n\n# Create the output directory for the symbol graphs if needed.\nmkdir -p \"$DOCS_DIR\"\nmkdir -p \"$SGFS_DIR\"\nrm -f $SGFS_DIR/*.*\n\ncd \"$PROJECT_ROOT\"  \n\n# Temporarily move the Xcode workspace aside so that xcodebuild uses the Swift package directly\nmkdir \"$TEMP_WORKSPACE_DIR\"\nmv Parse.xcworkspace \"$TEMP_WORKSPACE_DIR/Parse.xcworkspace\"\n\nxcodebuild clean build -scheme ParseSwift\\ \\(iOS\\) \\\n    -destination generic/platform=iOS \\\n    OTHER_SWIFT_FLAGS=\"-emit-symbol-graph -emit-symbol-graph-dir '$SGFS_DIR'\" | xcpretty\n\nmv \"$TEMP_WORKSPACE_DIR/Parse.xcworkspace\" ./Parse.xcworkspace\nrm -r \"$TEMP_WORKSPACE_DIR\"\n\n# Pretty print DocC JSON output so that it can be consistently diffed between commits\nexport DOCC_JSON_PRETTYPRINT=\"YES\"\n\n# By default pass the --index flag so we produce a full DocC archive.\nEXTRA_DOCC_FLAGS=\"--index\"\n\n# If building for publishing, don't pass the --index flag but pass additional flags for\n# static hosting configuration.\nif [ \"$PUBLISH\" = \"YES\" ]; then\n    EXTRA_DOCC_FLAGS=\"--transform-for-static-hosting --hosting-base-path Parse-Swift/$HOSTING_BASE_PATH\"\nfi\n\n# Handle the case where a DocC catalog does not exist in the ParseSwift repo\nif [ -d Sources/ParseSwift/Documentation.docc ]; then\n    # The DocC catalog exists, so pass it to the docc invocation.\n    DOCC_CMD=\"$DOCC_CMD Sources/ParseSwift/Documentation.docc\"\nfi\n\nxcrun docc $DOCC_CMD \\\n    --additional-symbol-graph-dir \"$SGFS_DIR\" \\\n    --output-path \"$OUTPUT_PATH\" $EXTRA_DOCC_FLAGS \\\n    --fallback-display-name ParseSwift \\\n    --fallback-bundle-identifier com.parse.ParseSwift \\\n    --fallback-bundle-version 1.0.0\n\nif [[ \"$DOCC_CMD\" == \"convert\"* ]]; then\n    echo\n    echo \"Generated DocC archive at: $OUTPUT_PATH\"\nfi\n\n"
  },
  {
    "path": "Scripts/update-gh-pages-documentation-site",
    "content": "#!/bin/bash\n#\n# Copyright (c) 2022, Apple Inc. All rights reserved.\n# \n# Redistribution and use in source and binary forms, with or without modification,\n# are permitted provided that the following conditions are met:\n# \n# 1.  Redistributions of source code must retain the above copyright notice, this\n# list of conditions and the following disclaimer.\n# \n# 2.  Redistributions in binary form must reproduce the above copyright notice,\n# this list of conditions and the following disclaimer in the documentation and/or\n# other materials provided with the distribution.\n# \n# 3. Neither the name of the copyright holder(s) nor the names of any contributors\n# may be used to endorse or promote products derived from this software without\n# specific prior written permission. No license is granted to the trademarks of\n# the copyright holders even if such marks are included in this software.\n# \n# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE\n# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\n# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\nset -eu\n\n# A `realpath` alternative using the default C implementation.\nfilepath() {\n  [[ $1 = /* ]] && echo \"$1\" || echo \"$PWD/${1#./}\"\n}\n\nPROJECT_ROOT=\"$(dirname $(dirname $(filepath $0)))\"\n\n# Set current directory to the repository root\ncd \"$PROJECT_ROOT\"\n\n# Use git worktree to checkout the gh-pages branch of this repository in a gh-pages sub-directory\ngit fetch\ngit worktree add --checkout gh-pages origin/gh-pages\n\n# Get the name of the current branch to use as the subdirectory for the deployment\nif [ -z ${CURRENT_BRANCH_NAME+x} ]; then\n  CURRENT_BRANCH_NAME=`git rev-parse --abbrev-ref HEAD`\nfi\n\n# Replace any forward slashes in the current branch name with dashes\nDEPLOYMENT_SUBDIRECTORY=${CURRENT_BRANCH_NAME//\\//-}\n\n# Create a subdirectory for the current branch name if it doesn't exist\nmkdir -p \"./gh-pages/$DEPLOYMENT_SUBDIRECTORY\"\n\n# Generate documentation output it\n# to the /docs subdirectory in the gh-pages worktree directory.\n./Scripts/generate-documentation \"$PROJECT_ROOT/gh-pages/$DEPLOYMENT_SUBDIRECTORY\" \"$DEPLOYMENT_SUBDIRECTORY\" --publish\n\n# Save the current commit we've just built documentation from in a variable\nCURRENT_COMMIT_HASH=`git rev-parse --short HEAD`\n\n# Commit and push our changes to the gh-pages branch\ncd gh-pages\ngit add \"$DEPLOYMENT_SUBDIRECTORY\"\n\nif [ -n \"$(git status --porcelain)\" ]; then\n    echo \"Documentation changes found. Commiting the changes to the 'gh-pages' branch and pushing to origin.\"\n    git commit -m \"Update documentation to $CURRENT_COMMIT_HASH on '$CURRENT_BRANCH_NAME'\"\n    git push origin HEAD:gh-pages\nelse\n  # No changes found, nothing to commit.\n  echo \"No documentation changes found.\"\nfi\n\n# Delete the git worktree we created\ncd ..\ngit worktree remove gh-pages"
  },
  {
    "path": "Scripts/update_build",
    "content": "#!/bin/bash\n\n# Prepare podspec update\nTEMPLATE_FILE_NAME=\"ParseSwift.podtemplate\"\nOUT_FILE_NAME=\"ParseSwift.podspec\"\n\n# Load the template podspec and replace version\nTEMPLATE=$(cat \"$TEMPLATE_FILE_NAME\" | sed \"s/\\[\\[VERSION\\]\\]/${BUILD_VERSION}/g\")\n\necho \"$TEMPLATE\" > \"$OUT_FILE_NAME\"\n"
  },
  {
    "path": "Sources/ParseSwift/API/API+BatchCommand.swift",
    "content": "//\n//  API+BatchCommand.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/12/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\n\ninternal extension API {\n    // MARK: API.BatchCommand\n    struct BatchCommand<T, U>: Encodable where T: Encodable {\n        typealias ReturnType = U // swiftlint:disable:this nesting\n        let method: API.Method\n        let path: API.Endpoint\n        let body: T?\n        let mapper: ((BaseObjectable) throws -> U)\n\n        init(method: API.Method,\n             path: API.Endpoint,\n             body: T? = nil,\n             mapper: @escaping ((BaseObjectable) throws -> U)) {\n            self.method = method\n            self.path = path\n            self.body = body\n            self.mapper = mapper\n        }\n\n        enum CodingKeys: String, CodingKey { // swiftlint:disable:this nesting\n            case method, body, path\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/API/API+Command+async.swift",
    "content": "//\n//  API+Command+async.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/17/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\n\ninternal extension API.Command {\n    // MARK: Asynchronous Execution\n    func executeAsync(options: API.Options,\n                      batching: Bool = false,\n                      callbackQueue: DispatchQueue,\n                      notificationQueue: DispatchQueue? = nil,\n                      childObjects: [String: PointerType]? = nil,\n                      childFiles: [UUID: ParseFile]? = nil,\n                      uploadProgress: ((URLSessionTask, Int64, Int64, Int64) -> Void)? = nil,\n                      // swiftlint:disable:next line_length\n                      downloadProgress: ((URLSessionDownloadTask, Int64, Int64, Int64) -> Void)? = nil) async throws -> U {\n        try await withCheckedThrowingContinuation { continuation in\n            self.executeAsync(options: options,\n                              batching: batching,\n                              callbackQueue: callbackQueue,\n                              notificationQueue: notificationQueue,\n                              childObjects: childObjects,\n                              childFiles: childFiles,\n                              uploadProgress: uploadProgress,\n                              downloadProgress: downloadProgress,\n                              completion: continuation.resume)\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/API/API+Command.swift",
    "content": "//\n//  API+Command.swift\n//  ParseSwift\n//\n//  Created by Florent Vilmart on 17-09-24.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\n\ninternal extension API {\n    // MARK: API.Command\n    struct Command<T, U>: Encodable where T: ParseEncodable {\n        typealias ReturnType = U // swiftlint:disable:this nesting\n        let method: API.Method\n        let path: API.Endpoint\n        let body: T?\n        let mapper: ((Data) throws -> U)\n        let params: [String: String?]?\n        let uploadData: Data?\n        let uploadFile: URL?\n        let parseURL: URL?\n        let otherURL: URL?\n        let stream: InputStream?\n\n        init(method: API.Method,\n             path: API.Endpoint,\n             params: [String: String]? = nil,\n             body: T? = nil,\n             uploadData: Data? = nil,\n             uploadFile: URL? = nil,\n             parseURL: URL? = nil,\n             otherURL: URL? = nil,\n             stream: InputStream? = nil,\n             mapper: @escaping ((Data) throws -> U)) {\n            self.method = method\n            self.path = path\n            self.body = body\n            self.uploadData = uploadData\n            self.uploadFile = uploadFile\n            self.parseURL = parseURL\n            self.otherURL = otherURL\n            self.stream = stream\n            self.mapper = mapper\n            self.params = params\n        }\n\n        // MARK: Synchronous Execution\n        func executeStream(options: API.Options,\n                           callbackQueue: DispatchQueue,\n                           childObjects: [String: PointerType]? = nil,\n                           childFiles: [UUID: ParseFile]? = nil,\n                           uploadProgress: ((URLSessionTask, Int64, Int64, Int64) -> Void)? = nil,\n                           stream: InputStream) throws {\n            switch self.prepareURLRequest(options: options,\n                                          batching: false,\n                                          childObjects: childObjects,\n                                          childFiles: childFiles) {\n\n            case .success(let urlRequest):\n                if method == .POST || method == .PUT || method == .PATCH {\n                    let task = URLSession.parse.uploadTask(withStreamedRequest: urlRequest)\n                    Parse.sessionDelegate.streamDelegates[task] = stream\n                    #if compiler(>=5.5.2) && canImport(_Concurrency)\n                    Task {\n                        await Parse.sessionDelegate.delegates.updateUpload(task, callback: uploadProgress)\n                        await Parse.sessionDelegate.delegates.updateTask(task, queue: callbackQueue)\n                        task.resume()\n                    }\n                    #else\n                    Parse.sessionDelegate.uploadDelegates[task] = uploadProgress\n                    Parse.sessionDelegate.taskCallbackQueues[task] = callbackQueue\n                    task.resume()\n                    #endif\n                    return\n                }\n            case .failure(let error):\n                throw error\n            }\n        }\n\n        func execute(options: API.Options,\n                     batching: Bool = false,\n                     notificationQueue: DispatchQueue? = nil,\n                     childObjects: [String: PointerType]? = nil,\n                     childFiles: [UUID: ParseFile]? = nil,\n                     uploadProgress: ((URLSessionTask, Int64, Int64, Int64) -> Void)? = nil,\n                     downloadProgress: ((URLSessionDownloadTask, Int64, Int64, Int64) -> Void)? = nil) throws -> U {\n            var responseResult: Result<U, ParseError>?\n            let synchronizationQueue = DispatchQueue(label: \"com.parse.Command.sync.\\(UUID().uuidString)\",\n                                                     qos: .default,\n                                                     attributes: .concurrent,\n                                                     autoreleaseFrequency: .inherit,\n                                                     target: nil)\n            let group = DispatchGroup()\n            group.enter()\n            self.executeAsync(options: options,\n                              batching: batching,\n                              callbackQueue: synchronizationQueue,\n                              notificationQueue: notificationQueue,\n                              childObjects: childObjects,\n                              childFiles: childFiles,\n                              uploadProgress: uploadProgress,\n                              downloadProgress: downloadProgress) { result in\n                responseResult = result\n                group.leave()\n            }\n            group.wait()\n\n            guard let response = responseResult else {\n                throw ParseError(code: .unknownError,\n                                 message: \"Could not unrwrap server response\")\n            }\n            return try response.get()\n        }\n\n        // MARK: Asynchronous Execution\n        // swiftlint:disable:next function_body_length cyclomatic_complexity\n        func executeAsync(options: API.Options,\n                          batching: Bool = false,\n                          callbackQueue: DispatchQueue,\n                          notificationQueue: DispatchQueue? = nil,\n                          childObjects: [String: PointerType]? = nil,\n                          childFiles: [UUID: ParseFile]? = nil,\n                          uploadProgress: ((URLSessionTask, Int64, Int64, Int64) -> Void)? = nil,\n                          downloadProgress: ((URLSessionDownloadTask, Int64, Int64, Int64) -> Void)? = nil,\n                          completion: @escaping(Result<U, ParseError>) -> Void) {\n            let currentNotificationQueue: DispatchQueue!\n            if let notificationQueue = notificationQueue {\n                currentNotificationQueue = notificationQueue\n            } else {\n                currentNotificationQueue = callbackQueue\n            }\n            if !path.urlComponent.contains(\"/files/\") {\n                // All ParseObjects use the shared URLSession\n                switch self.prepareURLRequest(options: options,\n                                              batching: batching,\n                                              childObjects: childObjects,\n                                              childFiles: childFiles) {\n                case .success(let urlRequest):\n                    URLSession.parse.dataTask(with: urlRequest,\n                                              callbackQueue: callbackQueue,\n                                              mapper: mapper) { result in\n                        callbackQueue.async {\n                            switch result {\n\n                            case .success(let decoded):\n                                completion(.success(decoded))\n                            case .failure(let error):\n                                completion(.failure(error))\n                            }\n                        }\n                    }\n                case .failure(let error):\n                    callbackQueue.async {\n                        completion(.failure(error))\n                    }\n                }\n            } else {\n                // ParseFiles are handled with a dedicated URLSession\n                if method == .POST || method == .PUT || method == .PATCH {\n                    switch self.prepareURLRequest(options: options,\n                                                  batching: batching,\n                                                  childObjects: childObjects,\n                                                  childFiles: childFiles) {\n\n                    case .success(let urlRequest):\n\n                        URLSession\n                            .parse\n                            .uploadTask(notificationQueue: currentNotificationQueue,\n                                        with: urlRequest,\n                                        from: uploadData,\n                                        from: uploadFile,\n                                        progress: uploadProgress,\n                                        mapper: mapper) { result in\n                                callbackQueue.async {\n                                    switch result {\n\n                                    case .success(let decoded):\n                                        completion(.success(decoded))\n                                    case .failure(let error):\n                                        completion(.failure(error))\n                                    }\n                                }\n                            }\n                    case .failure(let error):\n                        callbackQueue.async {\n                            completion(.failure(error))\n                        }\n                    }\n                } else if method == .DELETE {\n\n                    switch self.prepareURLRequest(options: options,\n                                                  batching: batching,\n                                                  childObjects: childObjects,\n                                                  childFiles: childFiles) {\n                    case .success(let urlRequest):\n                        URLSession.parse.dataTask(with: urlRequest,\n                                                  callbackQueue: callbackQueue,\n                                                  mapper: mapper) { result in\n                            callbackQueue.async {\n                                switch result {\n\n                                case .success(let decoded):\n                                    completion(.success(decoded))\n                                case .failure(let error):\n                                    completion(.failure(error))\n                                }\n                            }\n                        }\n                    case .failure(let error):\n                        callbackQueue.async {\n                            completion(.failure(error))\n                        }\n                    }\n\n                } else {\n\n                    if parseURL != nil {\n                        switch self.prepareURLRequest(options: options,\n                                                      batching: batching,\n                                                      childObjects: childObjects,\n                                                      childFiles: childFiles) {\n\n                        case .success(let urlRequest):\n                            URLSession\n                                .parse\n                                .downloadTask(notificationQueue: currentNotificationQueue,\n                                              with: urlRequest,\n                                              progress: downloadProgress,\n                                              mapper: mapper) { result in\n                                    callbackQueue.async {\n                                        switch result {\n\n                                        case .success(let decoded):\n                                            completion(.success(decoded))\n                                        case .failure(let error):\n                                            completion(.failure(error))\n                                        }\n                                    }\n                                }\n                        case .failure(let error):\n                            callbackQueue.async {\n                                completion(.failure(error))\n                            }\n                        }\n                    } else if let otherURL = self.otherURL {\n                        //Non-parse servers do not receive any parse dedicated request info\n                        var request = URLRequest(url: otherURL)\n                        request.cachePolicy = requestCachePolicy(options: options)\n                        URLSession.parse.downloadTask(with: request, mapper: mapper) { result in\n                            callbackQueue.async {\n                                switch result {\n\n                                case .success(let decoded):\n                                    completion(.success(decoded))\n                                case .failure(let error):\n                                    completion(.failure(error))\n                                }\n                            }\n                        }\n                    } else {\n                        callbackQueue.async {\n                            completion(.failure(ParseError(code: .unknownError,\n                                                           // swiftlint:disable:next line_length\n                                                           message: \"Cannot download the file without specifying the url\")))\n                        }\n                    }\n                }\n            }\n        }\n\n        // MARK: URL Preperation\n        func prepareURLRequest(options: API.Options,\n                               batching: Bool = false,\n                               childObjects: [String: PointerType]? = nil,\n                               childFiles: [UUID: ParseFile]? = nil) -> Result<URLRequest, ParseError> {\n            let params = self.params?.getURLQueryItems()\n            var headers = API.getHeaders(options: options)\n            if method == .GET || method == .DELETE {\n                headers.removeValue(forKey: \"X-Parse-Request-Id\")\n            }\n            let url = parseURL == nil ?\n                Parse.configuration.serverURL.appendingPathComponent(path.urlComponent) : parseURL!\n\n            guard var components = URLComponents(url: url, resolvingAgainstBaseURL: false) else {\n                return .failure(ParseError(code: .unknownError,\n                                           message: \"Could not unrwrap url components for \\(url)\"))\n            }\n            components.queryItems = params\n\n            guard let urlComponents = components.url else {\n                return .failure(ParseError(code: .unknownError,\n                                           message: \"Could not create url from components for \\(components)\"))\n            }\n\n            var urlRequest = URLRequest(url: urlComponents)\n            urlRequest.allHTTPHeaderFields = headers\n            if let urlBody = body {\n                if (urlBody as? ParseCloudTypeable) != nil {\n                    guard let bodyData = try? ParseCoding.parseEncoder().encode(urlBody, skipKeys: .cloud) else {\n                        return .failure(ParseError(code: .unknownError,\n                                                       message: \"Could not encode body \\(urlBody)\"))\n                    }\n                    urlRequest.httpBody = bodyData\n                } else {\n                    guard let bodyData = try? ParseCoding\n                            .parseEncoder()\n                            .encode(urlBody,\n                                    batching: batching,\n                                    collectChildren: false,\n                                    objectsSavedBeforeThisOne: childObjects,\n                                    filesSavedBeforeThisOne: childFiles) else {\n                            return .failure(ParseError(code: .unknownError,\n                                                       message: \"Could not encode body \\(urlBody)\"))\n                    }\n                    urlRequest.httpBody = bodyData.encoded\n                }\n            }\n            urlRequest.httpMethod = method.rawValue\n            urlRequest.cachePolicy = requestCachePolicy(options: options)\n            return .success(urlRequest)\n        }\n\n        enum CodingKeys: String, CodingKey { // swiftlint:disable:this nesting\n            case method, body, path\n        }\n    }\n\n    static func requestCachePolicy(options: API.Options) -> URLRequest.CachePolicy {\n        var policy: URLRequest.CachePolicy = Parse.configuration.requestCachePolicy\n        options.forEach { option in\n            if case .cachePolicy(let updatedPolicy) = option {\n                policy = updatedPolicy\n            }\n        }\n        return policy\n    }\n}\n\ninternal extension API.Command {\n\n    // MARK: Uploading File\n    static func uploadFile(_ object: ParseFile) throws -> API.Command<ParseFile, ParseFile> {\n        if !object.isSaved {\n            return createFile(object)\n        } else {\n            throw ParseError(code: .unknownError,\n                             message: \"File is already saved and cannot be updated.\")\n        }\n    }\n\n    // MARK: Uploading File - private\n    private static func createFile(_ object: ParseFile) -> API.Command<ParseFile, ParseFile> {\n        API.Command(method: .POST,\n                    path: .file(fileName: object.name),\n                    uploadData: object.data,\n                    uploadFile: object.localURL) { (data) -> ParseFile in\n            try ParseCoding.jsonDecoder().decode(FileUploadResponse.self, from: data).apply(to: object)\n        }\n    }\n\n    // MARK: Downloading File\n    static func downloadFile(_ object: ParseFile) -> API.Command<ParseFile, ParseFile> {\n        API.Command(method: .GET,\n                    path: .file(fileName: object.name),\n                    parseURL: object.url,\n                    otherURL: object.cloudURL) { (data) -> ParseFile in\n            let tempFileLocation = try ParseCoding.jsonDecoder().decode(URL.self, from: data)\n            guard let fileManager = ParseFileManager() else {\n                throw ParseError(code: .unknownError, message: \"Cannot create fileManager\")\n            }\n            let downloadDirectoryPath = try ParseFileManager.downloadDirectory()\n            try fileManager.createDirectoryIfNeeded(downloadDirectoryPath.relativePath)\n            let fileNameURL = URL(fileURLWithPath: object.name)\n            let fileLocation = downloadDirectoryPath.appendingPathComponent(fileNameURL.lastPathComponent)\n            if tempFileLocation != fileLocation {\n                try? FileManager.default.removeItem(at: fileLocation) // Remove file if it is already present\n                try FileManager.default.moveItem(at: tempFileLocation, to: fileLocation)\n            }\n            var object = object\n            object.localURL = fileLocation\n            return object\n        }\n    }\n\n    // MARK: Deleting File\n    static func deleteFile(_ object: ParseFile) -> API.Command<ParseFile, NoBody> {\n        API.Command(method: .DELETE,\n                    path: .file(fileName: object.name),\n                    parseURL: object.url) { (data) -> NoBody in\n            let parseError: ParseError!\n            do {\n                parseError = try ParseCoding.jsonDecoder().decode(ParseError.self, from: data)\n            } catch {\n                return try ParseCoding.jsonDecoder().decode(NoBody.self, from: data)\n            }\n            throw parseError\n        }\n    }\n\n    // MARK: Saving ParseObjects\n    static func save<T>(_ object: T,\n                        original data: Data?,\n                        ignoringCustomObjectIdConfig: Bool,\n                        batching: Bool = false) throws -> API.Command<T, T> where T: ParseObject {\n        if Parse.configuration.isRequiringCustomObjectIds\n            && object.objectId == nil && !ignoringCustomObjectIdConfig {\n            throw ParseError(code: .missingObjectId, message: \"objectId must not be nil\")\n        }\n        if object.isSaved {\n            // MARK: Should be switched to \"update\" when server supports PATCH.\n            return try replace(object,\n                               original: data)\n        }\n        return create(object)\n    }\n\n    static func create<T>(_ object: T) -> API.Command<T, T> where T: ParseObject {\n        var object = object\n        if object.ACL == nil,\n            let acl = try? ParseACL.defaultACL() {\n            object.ACL = acl\n        }\n        let mapper = { (data) -> T in\n            try ParseCoding.jsonDecoder().decode(CreateResponse.self, from: data).apply(to: object)\n        }\n        return API.Command<T, T>(method: .POST,\n                                 path: object.endpoint(.POST),\n                                 body: object,\n                                 mapper: mapper)\n    }\n\n    static func replace<T>(_ object: T,\n                           original data: Data?) throws -> API.Command<T, T> where T: ParseObject {\n        guard object.objectId != nil else {\n            throw ParseError(code: .missingObjectId,\n                             message: \"objectId must not be nil\")\n        }\n        let mapper = { (mapperData: Data) -> T in\n            var updatedObject = object\n            updatedObject.originalData = nil\n            updatedObject = try ParseCoding\n                .jsonDecoder()\n                .decode(ReplaceResponse.self, from: mapperData)\n                .apply(to: updatedObject)\n            guard let originalData = data,\n                  let original = try? ParseCoding.jsonDecoder().decode(T.self,\n                                                                       from: originalData),\n                  original.hasSameObjectId(as: updatedObject) else {\n                      return updatedObject\n                  }\n            return try updatedObject.merge(with: original)\n        }\n        return API.Command<T, T>(method: .PUT,\n                                 path: object.endpoint,\n                                 body: object,\n                                 mapper: mapper)\n    }\n\n    static func update<T>(_ object: T,\n                          original data: Data?) throws -> API.Command<T, T> where T: ParseObject {\n        guard object.objectId != nil else {\n            throw ParseError(code: .missingObjectId,\n                             message: \"objectId must not be nil\")\n        }\n        let mapper = { (mapperData: Data) -> T in\n            var updatedObject = object\n            updatedObject.originalData = nil\n            updatedObject = try ParseCoding\n                .jsonDecoder()\n                .decode(UpdateResponse.self, from: mapperData)\n                .apply(to: updatedObject)\n            guard let originalData = data,\n                  let original = try? ParseCoding.jsonDecoder().decode(T.self,\n                                                                       from: originalData),\n                  original.hasSameObjectId(as: updatedObject) else {\n                      return updatedObject\n                  }\n            return try updatedObject.merge(with: original)\n        }\n        return API.Command<T, T>(method: .PATCH,\n                                 path: object.endpoint,\n                                 body: object,\n                                 mapper: mapper)\n    }\n\n    // MARK: Fetching ParseObjects\n    static func fetch<T>(_ object: T, include: [String]?) throws -> API.Command<T, T> where T: ParseObject {\n        guard object.objectId != nil else {\n            throw ParseError(code: .missingObjectId,\n                             message: \"objectId must not be nil\")\n        }\n\n        var params: [String: String]?\n        if let includeParams = include {\n            params = [\"include\": \"\\(Set(includeParams))\"]\n        }\n\n        return API.Command<T, T>(\n            method: .GET,\n            path: object.endpoint,\n            params: params\n        ) { (data) -> T in\n            try ParseCoding.jsonDecoder().decode(T.self, from: data)\n        }\n    }\n}\n\ninternal extension API.Command where T: ParseObject {\n\n    // MARK: Batch - Saving, Fetching ParseObjects\n    static func batch(commands: [API.Command<T, T>],\n                      transaction: Bool) -> RESTBatchCommandType<T> {\n        let batchCommands = commands.compactMap { (command) -> API.Command<T, T>? in\n            let path = Parse.configuration.mountPath + command.path.urlComponent\n            guard let body = command.body else {\n                return nil\n            }\n            return API.Command<T, T>(method: command.method,\n                                     path: .any(path),\n                                     body: body,\n                                     mapper: command.mapper)\n        }\n\n        let mapper = { (data: Data) -> [Result<T, ParseError>] in\n\n            let decodingType = [BatchResponseItem<BatchResponse>].self\n            do {\n                let responses = try ParseCoding.jsonDecoder().decode(decodingType, from: data)\n                return commands.enumerated().map({ (object) -> (Result<T, ParseError>) in\n                    let response = responses[object.offset]\n                    if let success = response.success,\n                       let body = object.element.body {\n                        do {\n                            let updatedObject = try success.apply(to: body,\n                                                                  method: object.element.method)\n                            return .success(updatedObject)\n                        } catch {\n                            guard let parseError = error as? ParseError else {\n                                return .failure(ParseError(code: .unknownError,\n                                                           message: error.localizedDescription))\n                            }\n                            return .failure(parseError)\n                        }\n                    } else {\n                        guard let parseError = response.error else {\n                            return .failure(ParseError(code: .unknownError, message: \"unknown error\"))\n                        }\n\n                        return .failure(parseError)\n                    }\n                })\n            } catch {\n                guard let parseError = error as? ParseError else {\n                    return [(.failure(ParseError(code: .unknownError, message: \"decoding error: \\(error)\")))]\n                }\n                return [(.failure(parseError))]\n            }\n        }\n\n        let batchCommand = BatchCommand(requests: batchCommands, transaction: transaction)\n        return RESTBatchCommandType<T>(method: .POST, path: .batch, body: batchCommand, mapper: mapper)\n    }\n\n    // MARK: Batch - Deleting ParseObjects\n    static func batch(commands: [API.NonParseBodyCommand<NoBody, NoBody>],\n                      transaction: Bool) -> RESTBatchCommandNoBodyType<NoBody> {\n        let commands = commands.compactMap { (command) -> API.NonParseBodyCommand<NoBody, NoBody>? in\n            let path = Parse.configuration.mountPath + command.path.urlComponent\n            return API.NonParseBodyCommand<NoBody, NoBody>(\n                method: command.method,\n                path: .any(path), mapper: command.mapper)\n        }\n\n        let mapper = { (data: Data) -> [(Result<Void, ParseError>)] in\n\n            let decodingType = [BatchResponseItem<NoBody>].self\n            do {\n                let responses = try ParseCoding.jsonDecoder().decode(decodingType, from: data)\n                return responses.enumerated().map({ (object) -> (Result<Void, ParseError>) in\n                    let response = responses[object.offset]\n                    if response.success != nil {\n                        return .success(())\n                    } else {\n                        guard let parseError = response.error else {\n                            return .failure(ParseError(code: .unknownError, message: \"unknown error\"))\n                        }\n\n                        return .failure(parseError)\n                    }\n                })\n            } catch {\n                guard let parseError = error as? ParseError else {\n                    return [(.failure(ParseError(code: .unknownError, message: \"decoding error: \\(error)\")))]\n                }\n                return [(.failure(parseError))]\n            }\n        }\n\n        let batchCommand = BatchCommandEncodable(requests: commands, transaction: transaction)\n        return RESTBatchCommandNoBodyType<NoBody>(method: .POST, path: .batch, body: batchCommand, mapper: mapper)\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/API/API+NonParseBodyCommand+async.swift",
    "content": "//\n//  API+NonParseBodyCommand+async.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/17/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\n\nextension API.NonParseBodyCommand {\n    // MARK: Asynchronous Execution\n    func executeAsync(options: API.Options,\n                      callbackQueue: DispatchQueue) async throws -> U {\n        try await withCheckedThrowingContinuation { continuation in\n            self.executeAsync(options: options,\n                              callbackQueue: callbackQueue,\n                              completion: continuation.resume)\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/API/API+NonParseBodyCommand.swift",
    "content": "//\n//  API+NonParseBodyCommand.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/12/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\n\ninternal extension API {\n    // MARK: API.NonParseBodyCommand\n    struct NonParseBodyCommand<T, U>: Encodable where T: Encodable {\n        typealias ReturnType = U // swiftlint:disable:this nesting\n        let method: API.Method\n        let path: API.Endpoint\n        let body: T?\n        let mapper: ((Data) throws -> U)\n        let params: [String: String?]?\n\n        init(method: API.Method,\n             path: API.Endpoint,\n             params: [String: String]? = nil,\n             body: T? = nil,\n             mapper: @escaping ((Data) throws -> U)) {\n            self.method = method\n            self.path = path\n            self.params = params\n            self.body = body\n            self.mapper = mapper\n        }\n\n        func execute(options: API.Options) throws -> U {\n            var responseResult: Result<U, ParseError>?\n            let synchronizationQueue = DispatchQueue(label: \"com.parse.NonParseBodyCommand.sync.\\(UUID().uuidString)\",\n                                                     qos: .default,\n                                                     attributes: .concurrent,\n                                                     autoreleaseFrequency: .inherit,\n                                                     target: nil)\n            let group = DispatchGroup()\n            group.enter()\n            self.executeAsync(options: options,\n                              callbackQueue: synchronizationQueue) { result in\n                responseResult = result\n                group.leave()\n            }\n            group.wait()\n\n            guard let response = responseResult else {\n                throw ParseError(code: .unknownError,\n                                 message: \"Could not unrwrap server response\")\n            }\n            return try response.get()\n        }\n\n        // MARK: Asynchronous Execution\n        func executeAsync(options: API.Options,\n                          callbackQueue: DispatchQueue,\n                          completion: @escaping(Result<U, ParseError>) -> Void) {\n\n            switch self.prepareURLRequest(options: options) {\n            case .success(let urlRequest):\n                URLSession.parse.dataTask(with: urlRequest,\n                                          callbackQueue: callbackQueue,\n                                          mapper: mapper) { result in\n                    callbackQueue.async {\n                        switch result {\n\n                        case .success(let decoded):\n                            completion(.success(decoded))\n                        case .failure(let error):\n                            completion(.failure(error))\n                        }\n                    }\n                }\n            case .failure(let error):\n                callbackQueue.async {\n                    completion(.failure(error))\n                }\n            }\n        }\n\n        // MARK: URL Preperation\n        func prepareURLRequest(options: API.Options) -> Result<URLRequest, ParseError> {\n            let params = self.params?.getURLQueryItems()\n            var headers = API.getHeaders(options: options)\n            if method == .GET || method == .DELETE {\n                headers.removeValue(forKey: \"X-Parse-Request-Id\")\n            }\n            let url = Parse.configuration.serverURL.appendingPathComponent(path.urlComponent)\n\n            guard var components = URLComponents(url: url, resolvingAgainstBaseURL: false) else {\n                return .failure(ParseError(code: .unknownError,\n                                           message: \"Could not unrwrap url components for \\(url)\"))\n            }\n            components.queryItems = params\n\n            guard let urlComponents = components.url else {\n                return .failure(ParseError(code: .unknownError,\n                                           message: \"Could not create url from components for \\(components)\"))\n            }\n\n            var urlRequest = URLRequest(url: urlComponents)\n            urlRequest.allHTTPHeaderFields = headers\n            if let urlBody = body {\n                guard let bodyData = try? ParseCoding.jsonEncoder().encode(urlBody) else {\n                    return .failure(ParseError(code: .unknownError,\n                                                   message: \"Could not encode body \\(urlBody)\"))\n                }\n                urlRequest.httpBody = bodyData\n            }\n            urlRequest.httpMethod = method.rawValue\n            urlRequest.cachePolicy = requestCachePolicy(options: options)\n            return .success(urlRequest)\n        }\n\n        enum CodingKeys: String, CodingKey { // swiftlint:disable:this nesting\n            case method, body, path\n        }\n    }\n}\n\ninternal extension API.NonParseBodyCommand {\n\n    // MARK: Deleting\n    static func delete<T>(_ object: T) throws -> API.NonParseBodyCommand<NoBody, NoBody> where T: ParseObject {\n        guard object.isSaved else {\n            throw ParseError(code: .unknownError,\n                             message: \"Cannot delete an object without an objectId\")\n        }\n\n        let mapper = { (data: Data) -> NoBody in\n            if let error = try? ParseCoding\n                .jsonDecoder()\n                .decode(ParseError.self,\n                        from: data) {\n                throw error\n            } else {\n                return NoBody()\n            }\n        }\n\n        return API.NonParseBodyCommand<NoBody, NoBody>(method: .DELETE,\n                                                       path: object.endpoint,\n                                                       mapper: mapper)\n    }\n}\n\ninternal extension API.NonParseBodyCommand {\n    // MARK: Batch - Child Objects\n    static func batch(objects: [ParseEncodable],\n                      transaction: Bool) throws -> RESTBatchCommandTypeEncodablePointer<AnyCodable> {\n        let batchCommands = try objects.compactMap { (object) -> API.BatchCommand<AnyCodable, PointerType>? in\n            guard var objectable = object as? Objectable else {\n                return nil\n            }\n            let method: API.Method!\n            if objectable.isSaved {\n                method = .PUT\n            } else {\n                method = .POST\n            }\n\n            let mapper = { (baseObjectable: BaseObjectable) throws -> PointerType in\n                objectable.objectId = baseObjectable.objectId\n                return try objectable.toPointer()\n            }\n\n            let path = Parse.configuration.mountPath + objectable.endpoint.urlComponent\n            let encoded = try ParseCoding.parseEncoder().encode(object, batching: true)\n            let body = try ParseCoding.jsonDecoder().decode(AnyCodable.self, from: encoded)\n            return API.BatchCommand<AnyCodable, PointerType>(method: method,\n                                                             path: .any(path),\n                                                             body: body,\n                                                             mapper: mapper)\n        }\n\n        let mapper = { (data: Data) -> [Result<PointerType, ParseError>] in\n            let decodingType = [BatchResponseItem<BaseObjectable>].self\n            do {\n                let responses = try ParseCoding.jsonDecoder().decode(decodingType, from: data)\n                return batchCommands.enumerated().map({ (object) -> (Result<PointerType, ParseError>) in\n                    let response = responses[object.offset]\n                    if let success = response.success {\n                        guard let successfulResponse = try? object.element.mapper(success) else {\n                            return.failure(ParseError(code: .unknownError, message: \"unknown error\"))\n                        }\n                        return .success(successfulResponse)\n                    } else {\n                        guard let parseError = response.error else {\n                            return .failure(ParseError(code: .unknownError, message: \"unknown error\"))\n                        }\n                        return .failure(parseError)\n                    }\n                })\n            } catch {\n                guard let parseError = error as? ParseError else {\n                    return [(.failure(ParseError(code: .unknownError, message: \"decoding error: \\(error)\")))]\n                }\n                return [(.failure(parseError))]\n            }\n        }\n        let batchCommand = BatchChildCommand(requests: batchCommands,\n                                             transaction: transaction)\n        return RESTBatchCommandTypeEncodablePointer<AnyCodable>(method: .POST,\n                                                                path: .batch,\n                                                                body: batchCommand,\n                                                                mapper: mapper)\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/API/API.swift",
    "content": "//\n//  API.swift\n//  ParseSwift\n//\n//  Created by Florent Vilmart on 17-08-19.\n//  Copyright © 2017 Parse. All rights reserved.\n//\n\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\n\n// swiftlint:disable line_length\n\n/// The REST API for communicating with a Parse Server.\npublic struct API {\n\n    internal enum Method: String, Encodable {\n        case GET, POST, PUT, PATCH, DELETE\n    }\n\n    internal enum Endpoint: Encodable {\n        case batch\n        case objects(className: String)\n        case object(className: String, objectId: String)\n        case users\n        case user(objectId: String)\n        case installations\n        case installation(objectId: String)\n        case sessions\n        case session(objectId: String)\n        case event(event: String)\n        case roles\n        case role(objectId: String)\n        case login\n        case logout\n        case file(fileName: String)\n        case passwordReset\n        case verifyPassword\n        case verificationEmail\n        case functions(name: String)\n        case jobs(name: String)\n        case aggregate(className: String)\n        case config\n        case health\n        case schemas\n        case schema(className: String)\n        case purge(className: String)\n        case push\n        case hookFunctions\n        case hookFunction(request: FunctionRequest)\n        case hookTriggers\n        case hookTrigger(request: TriggerRequest)\n        case any(String)\n\n        var urlComponent: String {\n            switch self {\n            case .batch:\n                return \"/batch\"\n            case .objects(let className):\n                return \"/classes/\\(className)\"\n            case .object(let className, let objectId):\n                return \"/classes/\\(className)/\\(objectId)\"\n            case .users:\n                return \"/users\"\n            case .user(let objectId):\n                return \"/users/\\(objectId)\"\n            case .installations:\n                return \"/installations\"\n            case .installation(let objectId):\n                return \"/installations/\\(objectId)\"\n            case .sessions:\n                return \"/sessions\"\n            case .session(let objectId):\n                return \"/sessions/\\(objectId)\"\n            case .event(let event):\n                return \"/events/\\(event)\"\n            case .aggregate(let className):\n                return \"/aggregate/\\(className)\"\n            case .roles:\n                return \"/roles\"\n            case .role(let objectId):\n                return \"/roles/\\(objectId)\"\n            case .login:\n                return \"/login\"\n            case .logout:\n                return \"/logout\"\n            case .file(let fileName):\n                return \"/files/\\(fileName)\"\n            case .passwordReset:\n                return \"/requestPasswordReset\"\n            case .verifyPassword:\n                return \"/verifyPassword\"\n            case .verificationEmail:\n                return \"/verificationEmailRequest\"\n            case .functions(name: let name):\n                return \"/functions/\\(name)\"\n            case .jobs(name: let name):\n                return \"/jobs/\\(name)\"\n            case .config:\n                return \"/config\"\n            case .health:\n                return \"/health\"\n            case .schemas:\n                return \"/schemas\"\n            case .schema(let className):\n                return \"/schemas/\\(className)\"\n            case .purge(let className):\n                return \"/purge/\\(className)\"\n            case .push:\n                return \"/push\"\n            case .hookFunctions:\n                return \"/hooks/functions/\"\n            case .hookFunction(let request):\n                return \"/hooks/functions/\\(request.functionName)\"\n            case .hookTriggers:\n                return \"/hooks/triggers/\"\n            case .hookTrigger(let request):\n                return \"/hooks/triggers/\\(request.className)/\\(request.triggerName)\"\n            case .any(let path):\n                return path\n            }\n        }\n\n        public func encode(to encoder: Encoder) throws {\n            var container = encoder.singleValueContainer()\n            try container.encode(urlComponent)\n        }\n    }\n\n    /// A type alias for the set of options.\n    public typealias Options = Set<API.Option>\n\n    /// Options available to send to Parse Server.\n    public enum Option: Hashable {\n\n        /// Use the masterKey if it was provided during initial configuraration.\n        case useMasterKey // swiftlint:disable:this inclusive_language\n        /// Use a specific session token.\n        /// - note: The session token of the current user is provided by default.\n        case sessionToken(String)\n        /// Use a specific installationId.\n        /// - note: The installationId of the current user is provided by default.\n        case installationId(String)\n        /// Specify mimeType.\n        case mimeType(String)\n        /// Specify fileSize.\n        case fileSize(String)\n        /// Remove mimeType.\n        /// - note: This is typically used indirectly by `ParseFile`.\n        case removeMimeType\n        /// Specify metadata.\n        /// - note: This is typically used indirectly by `ParseFile`.\n        case metadata([String: String])\n        /// Specify tags.\n        /// - note: This is typically used indirectly by `ParseFile`.\n        case tags([String: String])\n        /// Add context.\n        /// - warning: Requires Parse Server 5.0.0+.\n        case context(Encodable)\n        /// The caching policy to use for a specific http request. Determines when to\n        /// return a response from the cache. See Apple's\n        /// [documentation](https://developer.apple.com/documentation/foundation/url_loading_system/accessing_cached_data)\n        /// for more info.\n        case cachePolicy(URLRequest.CachePolicy)\n\n        public func hash(into hasher: inout Hasher) {\n            switch self {\n            case .useMasterKey:\n                hasher.combine(1)\n            case .sessionToken:\n                hasher.combine(2)\n            case .installationId:\n                hasher.combine(3)\n            case .mimeType:\n                hasher.combine(4)\n            case .fileSize:\n                hasher.combine(5)\n            case .removeMimeType:\n                hasher.combine(6)\n            case .metadata:\n                hasher.combine(7)\n            case .tags:\n                hasher.combine(8)\n            case .context:\n                hasher.combine(9)\n            case .cachePolicy:\n                hasher.combine(10)\n            }\n        }\n\n        public static func == (lhs: API.Option, rhs: API.Option) -> Bool {\n            lhs.hashValue == rhs.hashValue\n        }\n    }\n\n    // swiftlint:disable:next cyclomatic_complexity\n    internal static func getHeaders(options: API.Options) -> [String: String] {\n        var headers: [String: String] = [\"X-Parse-Application-Id\": Parse.configuration.applicationId,\n                                         \"Content-Type\": \"application/json\"]\n        if let clientKey = Parse.configuration.clientKey {\n            headers[\"X-Parse-Client-Key\"] = clientKey\n        }\n\n        if let token = BaseParseUser.currentContainer?.sessionToken {\n            headers[\"X-Parse-Session-Token\"] = token\n        }\n\n        if let installationId = BaseParseInstallation.currentContainer.installationId {\n            headers[\"X-Parse-Installation-Id\"] = installationId\n        }\n\n        headers[\"X-Parse-Client-Version\"] = clientVersion()\n        headers[\"X-Parse-Request-Id\"] = UUID().uuidString.lowercased()\n\n        options.forEach { (option) in\n            switch option {\n            case .useMasterKey:\n                headers[\"X-Parse-Master-Key\"] = Parse.configuration.masterKey\n            case .sessionToken(let sessionToken):\n                headers[\"X-Parse-Session-Token\"] = sessionToken\n            case .installationId(let installationId):\n                headers[\"X-Parse-Installation-Id\"] = installationId\n            case .mimeType(let mimeType):\n                headers[\"Content-Type\"] = mimeType\n            case .fileSize(let fileSize):\n                headers[\"Content-Length\"] = fileSize\n            case .removeMimeType:\n                headers.removeValue(forKey: \"Content-Type\")\n            case .metadata(let metadata):\n                metadata.forEach {(key, value) -> Void in\n                    headers[key] = value\n                }\n            case .tags(let tags):\n                tags.forEach {(key, value) -> Void in\n                    headers[key] = value\n                }\n            case .context(let context):\n                let context = AnyEncodable(context)\n                if let encoded = try? ParseCoding.jsonEncoder().encode(context),\n                   let encodedString = String(data: encoded, encoding: .utf8) {\n                    headers[\"X-Parse-Cloud-Context\"] = encodedString\n                }\n            default:\n                break\n            }\n        }\n\n        return headers\n    }\n\n    internal static func clientVersion() -> String {\n        ParseConstants.sdk+ParseConstants.version\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/API/BatchUtils.swift",
    "content": "//\n//  RESTBatchCommand.swift\n//  ParseSwift\n//\n//  Created by Florent Vilmart on 17-08-19.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\ntypealias ParseObjectBatchCommand<T> = BatchCommand<T, T> where T: ParseObject\ntypealias ParseObjectBatchResponse<T> = [(Result<T, ParseError>)]\n// swiftlint:disable line_length\ntypealias RESTBatchCommandType<T> = API.Command<ParseObjectBatchCommand<T>, ParseObjectBatchResponse<T>> where T: ParseObject\n\ntypealias ParseObjectBatchCommandNoBody<T> = BatchCommandEncodable<NoBody, NoBody>\ntypealias ParseObjectBatchResponseNoBody<NoBody> = [(Result<Void, ParseError>)]\ntypealias RESTBatchCommandNoBodyType<T> = API.NonParseBodyCommand<ParseObjectBatchCommandNoBody<T>, ParseObjectBatchResponseNoBody<T>> where T: Encodable\n\ntypealias ParseObjectBatchCommandEncodablePointer<T> = BatchChildCommand<T, PointerType> where T: Encodable\ntypealias ParseObjectBatchResponseEncodablePointer<U> = [(Result<PointerType, ParseError>)]\n// swiftlint:disable line_length\ntypealias RESTBatchCommandTypeEncodablePointer<T> = API.NonParseBodyCommand<ParseObjectBatchCommandEncodablePointer<T>, ParseObjectBatchResponseEncodablePointer<Encodable>> where T: Encodable\n // swiftlint:enable line_length\n\ninternal struct BatchCommand<T, U>: ParseEncodable where T: ParseEncodable {\n    let requests: [API.Command<T, U>]\n    var transaction: Bool\n}\n\ninternal struct BatchCommandEncodable<T, U>: Encodable where T: Encodable {\n    let requests: [API.NonParseBodyCommand<T, U>]\n    var transaction: Bool\n}\n\ninternal struct BatchChildCommand<T, U>: Encodable where T: Encodable {\n    let requests: [API.BatchCommand<T, U>]\n    var transaction: Bool\n}\n\nstruct BatchUtils {\n    static func splitArray<U>(_ array: [U], valuesPerSegment: Int) -> [[U]] {\n        if array.count < valuesPerSegment {\n            return [array]\n        }\n\n        var returnArray = [[U]]()\n        var index = 0\n        while index < array.count {\n            let length = Swift.min(array.count - index, valuesPerSegment)\n            let subArray = Array(array[index..<index+length])\n            returnArray.append(subArray)\n            index += length\n        }\n        return returnArray\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/API/ParseURLSessionDelegate.swift",
    "content": "//\n//  ParseURLSessionDelegate.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/4/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\n\nclass ParseURLSessionDelegate: NSObject\n{\n    var callbackQueue: DispatchQueue\n    var authentication: ((URLAuthenticationChallenge,\n                          (URLSession.AuthChallengeDisposition,\n                           URLCredential?) -> Void) -> Void)?\n    var streamDelegates = [URLSessionTask: InputStream]()\n    #if compiler(>=5.5.2) && canImport(_Concurrency)\n    actor SessionDelegate: Sendable {\n        var downloadDelegates = [URLSessionDownloadTask: ((URLSessionDownloadTask, Int64, Int64, Int64) -> Void)]()\n        var uploadDelegates = [URLSessionTask: ((URLSessionTask, Int64, Int64, Int64) -> Void)]()\n        var taskCallbackQueues = [URLSessionTask: DispatchQueue]()\n\n        func updateDownload(_ task: URLSessionDownloadTask,\n                            callback: ((URLSessionDownloadTask, Int64, Int64, Int64) -> Void)?) {\n            downloadDelegates[task] = callback\n        }\n\n        func removeDownload(_ task: URLSessionDownloadTask) {\n            downloadDelegates.removeValue(forKey: task)\n            taskCallbackQueues.removeValue(forKey: task)\n        }\n\n        func updateUpload(_ task: URLSessionTask,\n                          callback: ((URLSessionTask, Int64, Int64, Int64) -> Void)?) {\n            uploadDelegates[task] = callback\n        }\n\n        func removeUpload(_ task: URLSessionTask) {\n            uploadDelegates.removeValue(forKey: task)\n            taskCallbackQueues.removeValue(forKey: task)\n        }\n\n        func updateTask(_ task: URLSessionTask,\n                        queue: DispatchQueue) {\n            taskCallbackQueues[task] = queue\n        }\n\n        func removeTask(_ task: URLSessionTask) {\n            taskCallbackQueues.removeValue(forKey: task)\n        }\n    }\n\n    var delegates = SessionDelegate()\n\n    #else\n    var downloadDelegates = [URLSessionDownloadTask: ((URLSessionDownloadTask, Int64, Int64, Int64) -> Void)]()\n    var uploadDelegates = [URLSessionTask: ((URLSessionTask, Int64, Int64, Int64) -> Void)]()\n    var taskCallbackQueues = [URLSessionTask: DispatchQueue]()\n    #endif\n\n    init (callbackQueue: DispatchQueue,\n          authentication: ((URLAuthenticationChallenge,\n                            (URLSession.AuthChallengeDisposition,\n                             URLCredential?) -> Void) -> Void)?) {\n        self.callbackQueue = callbackQueue\n        self.authentication = authentication\n        super.init()\n    }\n}\n\nextension ParseURLSessionDelegate: URLSessionDelegate {\n    func urlSession(_ session: URLSession,\n                    didReceive challenge: URLAuthenticationChallenge,\n                    completionHandler: @escaping (URLSession.AuthChallengeDisposition,\n                                                  URLCredential?) -> Void) {\n        if let authentication = authentication {\n            callbackQueue.async {\n                authentication(challenge, completionHandler)\n            }\n        } else {\n            completionHandler(.performDefaultHandling, nil)\n        }\n    }\n}\n\nextension ParseURLSessionDelegate: URLSessionDataDelegate {\n    func urlSession(_ session: URLSession,\n                    task: URLSessionTask,\n                    didSendBodyData bytesSent: Int64,\n                    totalBytesSent: Int64,\n                    totalBytesExpectedToSend: Int64) {\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            if let callback = await delegates.uploadDelegates[task],\n               let queue = await delegates.taskCallbackQueues[task] {\n                queue.async {\n                    callback(task, bytesSent, totalBytesSent, totalBytesExpectedToSend)\n                }\n            }\n        }\n        #else\n        if let callback = uploadDelegates[task],\n           let queue = taskCallbackQueues[task] {\n            queue.async {\n                callback(task, bytesSent, totalBytesSent, totalBytesExpectedToSend)\n            }\n        }\n        #endif\n    }\n\n    func urlSession(_ session: URLSession,\n                    task: URLSessionTask,\n                    needNewBodyStream completionHandler: @escaping (InputStream?) -> Void) {\n        if let stream = streamDelegates[task] {\n            completionHandler(stream)\n        }\n    }\n\n    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {\n        streamDelegates.removeValue(forKey: task)\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            await delegates.removeUpload(task)\n            if let downloadTask = task as? URLSessionDownloadTask {\n                await delegates.removeDownload(downloadTask)\n            }\n        }\n        #else\n        uploadDelegates.removeValue(forKey: task)\n        taskCallbackQueues.removeValue(forKey: task)\n        if let downloadTask = task as? URLSessionDownloadTask {\n            downloadDelegates.removeValue(forKey: downloadTask)\n        }\n        #endif\n    }\n}\n\nextension ParseURLSessionDelegate: URLSessionDownloadDelegate {\n    func urlSession(_ session: URLSession,\n                    downloadTask: URLSessionDownloadTask,\n                    didWriteData bytesWritten: Int64,\n                    totalBytesWritten: Int64,\n                    totalBytesExpectedToWrite: Int64) {\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            if let callback = await delegates.downloadDelegates[downloadTask],\n               let queue = await delegates.taskCallbackQueues[downloadTask] {\n                queue.async {\n                    callback(downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite)\n                }\n            }\n        }\n        #else\n        if let callback = downloadDelegates[downloadTask],\n           let queue = taskCallbackQueues[downloadTask] {\n            queue.async {\n                callback(downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite)\n            }\n        }\n        #endif\n    }\n\n    func urlSession(_ session: URLSession,\n                    downloadTask: URLSessionDownloadTask,\n                    didFinishDownloadingTo location: URL) {\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            await delegates.removeDownload(downloadTask)\n        }\n        #else\n        downloadDelegates.removeValue(forKey: downloadTask)\n        taskCallbackQueues.removeValue(forKey: downloadTask)\n        #endif\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/API/Responses.swift",
    "content": "//\n//  Responses.swift\n//  ParseSwift\n//\n//  Created by Florent Vilmart on 17-08-20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\ninternal struct CreateResponse: Decodable {\n    var objectId: String\n    var createdAt: Date\n    var updatedAt: Date {\n        return createdAt\n    }\n\n    func apply<T>(to object: T) -> T where T: ParseObject {\n        var object = object\n        object.objectId = objectId\n        object.createdAt = createdAt\n        object.updatedAt = updatedAt\n        return object\n    }\n}\n\ninternal struct ReplaceResponse: Decodable {\n    var createdAt: Date?\n    var updatedAt: Date?\n\n    func apply<T>(to object: T) throws -> T where T: ParseObject {\n        guard let objectId = object.objectId else {\n            throw ParseError(code: .missingObjectId,\n                             message: \"Response from server should not have an objectId of nil\")\n        }\n        guard let createdAt = createdAt else {\n            guard let updatedAt = updatedAt else {\n                throw ParseError(code: .unknownError,\n                                 message: \"Response from server should not have an updatedAt of nil\")\n            }\n            return UpdateResponse(updatedAt: updatedAt).apply(to: object)\n        }\n        return CreateResponse(objectId: objectId,\n                              createdAt: createdAt).apply(to: object)\n    }\n}\n\ninternal struct UpdateResponse: Decodable {\n    var updatedAt: Date\n\n    func apply<T>(to object: T) -> T where T: ParseObject {\n        var object = object\n        object.updatedAt = updatedAt\n        return object\n    }\n}\n\ninternal struct UpdateSessionTokenResponse: Decodable {\n    var updatedAt: Date\n    let sessionToken: String?\n}\n\n// MARK: ParseObject Batch\ninternal struct BatchResponseItem<T>: Codable where T: Codable {\n    let success: T?\n    let error: ParseError?\n}\n\ninternal struct BatchResponse: Codable {\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n\n    func asCreateResponse() throws -> CreateResponse {\n        guard let objectId = objectId else {\n            throw ParseError(code: .missingObjectId,\n                             message: \"Response from server should not have an objectId of nil\")\n        }\n        guard let createdAt = createdAt else {\n            throw ParseError(code: .unknownError,\n                             message: \"Response from server should not have an createdAt of nil\")\n        }\n        return CreateResponse(objectId: objectId, createdAt: createdAt)\n    }\n\n    func asReplaceResponse() -> ReplaceResponse {\n        ReplaceResponse(createdAt: createdAt, updatedAt: updatedAt)\n    }\n\n    func asUpdateResponse() throws -> UpdateResponse {\n        guard let updatedAt = updatedAt else {\n            throw ParseError(code: .unknownError,\n                             message: \"Response from server should not have an updatedAt of nil\")\n        }\n        return UpdateResponse(updatedAt: updatedAt)\n    }\n\n    func apply<T>(to object: T, method: API.Method) throws -> T where T: ParseObject {\n        switch method {\n        case .POST:\n            return try asCreateResponse().apply(to: object)\n        case .PUT:\n            return try asReplaceResponse().apply(to: object)\n        case .PATCH:\n            return try asUpdateResponse().apply(to: object)\n        case .GET:\n            fatalError(\"Parse-server does not support batch fetching like this. Try \\\"fetchAll\\\".\")\n        default:\n            fatalError(\"There is no configured way to apply for method: \\(method)\")\n        }\n    }\n}\n\n// MARK: Query\ninternal struct QueryResponse<T>: Codable where T: ParseObject {\n    let results: [T]\n    let count: Int?\n}\n\n// MARK: ParseUser\ninternal struct LoginSignupResponse: Codable {\n    let createdAt: Date\n    let objectId: String\n    let sessionToken: String\n    var updatedAt: Date?\n    let username: String?\n\n    func applySignup<T>(to object: T) -> T where T: ParseUser {\n        var object = object\n        object.objectId = objectId\n        object.createdAt = createdAt\n        object.updatedAt = createdAt\n        object.password = nil // password should be removed\n\n        return object\n    }\n}\n\n// MARK: ParseFile\ninternal struct FileUploadResponse: Codable {\n    let name: String\n    let url: URL\n\n    func apply(to file: ParseFile) -> ParseFile {\n        var file = file\n        file.name = name\n        file.url = url\n        return file\n    }\n}\n\n// MARK: AnyResultResponse\ninternal struct AnyResultResponse<U: Decodable>: Decodable {\n    let result: U\n}\n\n// MARK: AnyResultsResponse\ninternal struct AnyResultsResponse<U: Decodable>: Decodable {\n    let results: [U]\n}\n\ninternal struct AnyResultsMongoResponse<U: Decodable>: Decodable {\n    let results: U\n}\n\n// MARK: ConfigResponse\ninternal struct ConfigFetchResponse<T>: Codable where T: ParseConfig {\n    let params: T\n}\n\ninternal struct BooleanResponse: Codable {\n    let result: Bool\n}\n\n// MARK: HealthResponse\ninternal struct HealthResponse: Codable {\n    let status: String\n}\n\n// MARK: PushResponse\ninternal struct PushResponse: Codable {\n    let data: Data\n    let statusId: String\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseApple/ParseApple+async.swift",
    "content": "//\n//  ParseApple+async.swift\n//  ParseApple+async\n//\n//  Created by Corey Baker on 8/7/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n\npublic extension ParseApple {\n    // MARK: Async/Await\n\n    /**\n     Login a `ParseUser` *asynchronously* using Apple authentication.\n     - parameter user: The `user` from `ASAuthorizationAppleIDCredential`.\n     - parameter identityToken: The **identityToken** from `ASAuthorizationAppleIDCredential`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func login(user: String,\n               identityToken: Data,\n               options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.login(user: user,\n                       identityToken: identityToken,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using Apple authentication.\n     - parameter authData: Dictionary containing key/values.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func login(authData: [String: String],\n               options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.login(authData: authData,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n}\n\npublic extension ParseApple {\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Apple authentication.\n     - parameter user: The `user` from `ASAuthorizationAppleIDCredential`.\n     - parameter identityToken: The **identityToken** from `ASAuthorizationAppleIDCredential`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func link(user: String,\n              identityToken: Data,\n              options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.link(user: user,\n                      identityToken: identityToken,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Apple authentication.\n     - parameter authData: Dictionary containing key/values.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func link(authData: [String: String],\n              options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.link(authData: authData,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseApple/ParseApple+combine.swift",
    "content": "//\n//  ParseApple+combine.swift\n//  ParseApple+combine\n//\n//  Created by Corey Baker on 8/7/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\npublic extension ParseApple {\n    // MARK: Combine\n\n    /**\n     Login a `ParseUser` *asynchronously* using Apple authentication. Publishes when complete.\n     - parameter user: The `user` from `ASAuthorizationAppleIDCredential`.\n     - parameter identityToken: The **identityToken** from `ASAuthorizationAppleIDCredential`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func loginPublisher(user: String,\n                        identityToken: Data,\n                        options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.login(user: user,\n                       identityToken: identityToken,\n                       options: options,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using Apple authentication. Publishes when complete.\n     - parameter authData: Dictionary containing key/values.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func loginPublisher(authData: [String: String],\n                        options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.login(authData: authData,\n                       options: options,\n                       completion: promise)\n        }\n    }\n}\n\npublic extension ParseApple {\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Apple authentication. Publishes when complete.\n     - parameter user: The `user` from `ASAuthorizationAppleIDCredential`.\n     - parameter identityToken: The **identityToken** from `ASAuthorizationAppleIDCredential`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func linkPublisher(user: String,\n                       identityToken: Data,\n                       options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.link(user: user,\n                      identityToken: identityToken,\n                      options: options,\n                      completion: promise)\n        }\n    }\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Apple authentication. Publishes when complete.\n     - parameter authData: Dictionary containing key/values.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func linkPublisher(authData: [String: String],\n                       options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.link(authData: authData,\n                      options: options,\n                      completion: promise)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseApple/ParseApple.swift",
    "content": "//\n//  ParseApple.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/14/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n// swiftlint:disable line_length\n\n/**\n Provides utility functions for working with Apple User Authentication and `ParseUser`'s.\n Be sure your Parse Server is configured for [sign in with Apple](https://docs.parseplatform.org/parse-server/guide/#configuring-parse-server-for-sign-in-with-apple).\n For information on acquiring Apple sign-in credentials to use with `ParseApple`, refer to [Apple's Documentation](https://developer.apple.com/documentation/authenticationservices/implementing_user_authentication_with_sign_in_with_apple).\n */\npublic struct ParseApple<AuthenticatedUser: ParseUser>: ParseAuthentication {\n\n    /// Authentication keys required for Apple authentication.\n    enum AuthenticationKeys: String, Codable {\n        case id\n        case token\n\n        /// Properly makes an authData dictionary with the required keys.\n        /// - parameter user: Required id for the user.\n        /// - parameter identityToken: Required identity token for the user.\n        /// - returns: authData dictionary.\n        /// - throws: `ParseError` if the **identityToken** cannot be converted\n        /// to a string.\n        func makeDictionary(user: String,\n                            identityToken: Data) throws -> [String: String] {\n            guard let identityTokenString = String(data: identityToken, encoding: .utf8) else {\n                throw ParseError(code: .unknownError, message: \"Could not convert identityToken to String\")\n            }\n            return [AuthenticationKeys.id.rawValue: user,\n             AuthenticationKeys.token.rawValue: identityTokenString]\n        }\n\n        /// Verifies all mandatory keys are in authData.\n        /// - parameter authData: Dictionary containing key/values.\n        /// - returns: **true** if all the mandatory keys are present, **false** otherwise.\n        func verifyMandatoryKeys(authData: [String: String]) -> Bool {\n            guard authData[AuthenticationKeys.id.rawValue] != nil,\n                  authData[AuthenticationKeys.token.rawValue] != nil else {\n                return false\n            }\n            return true\n        }\n    }\n\n    public static var __type: String { // swiftlint:disable:this identifier_name\n        \"apple\"\n    }\n\n    public init() { }\n}\n\n// MARK: Login\npublic extension ParseApple {\n    /**\n     Login a `ParseUser` *asynchronously* using Apple authentication.\n     - parameter user: The `user` from `ASAuthorizationAppleIDCredential`.\n     - parameter identityToken: The **identityToken** from `ASAuthorizationAppleIDCredential`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func login(user: String,\n               identityToken: Data,\n               options: API.Options = [],\n               callbackQueue: DispatchQueue = .main,\n               completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n\n        guard let appleAuthData = try? AuthenticationKeys.id.makeDictionary(user: user, identityToken: identityToken) else {\n            callbackQueue.async {\n                completion(.failure(.init(code: .unknownError,\n                                          message: \"Could not create authData.\")))\n            }\n            return\n        }\n        login(authData: appleAuthData,\n              options: options,\n              callbackQueue: callbackQueue,\n              completion: completion)\n    }\n\n    func login(authData: [String: String],\n               options: API.Options = [],\n               callbackQueue: DispatchQueue = .main,\n               completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        guard AuthenticationKeys.id.verifyMandatoryKeys(authData: authData) else {\n            callbackQueue.async {\n                completion(.failure(.init(code: .unknownError,\n                                          message: \"Should have authData in consisting of keys \\\"id\\\" and \\\"token\\\".\")))\n            }\n            return\n        }\n        AuthenticatedUser.login(Self.__type,\n                                authData: authData,\n                                options: options,\n                                callbackQueue: callbackQueue,\n                                completion: completion)\n    }\n}\n\n// MARK: Link\npublic extension ParseApple {\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Apple authentication.\n     - parameter user: The `user` from `ASAuthorizationAppleIDCredential`.\n     - parameter identityToken: The **identityToken** from `ASAuthorizationAppleIDCredential`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func link(user: String,\n              identityToken: Data,\n              options: API.Options = [],\n              callbackQueue: DispatchQueue = .main,\n              completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        guard let appleAuthData = try? AuthenticationKeys.id.makeDictionary(user: user, identityToken: identityToken) else {\n            callbackQueue.async {\n                completion(.failure(.init(code: .unknownError,\n                                          message: \"Could not create authData.\")))\n            }\n            return\n        }\n        link(authData: appleAuthData,\n             options: options,\n             callbackQueue: callbackQueue,\n             completion: completion)\n    }\n\n    func link(authData: [String: String],\n              options: API.Options = [],\n              callbackQueue: DispatchQueue = .main,\n              completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        guard AuthenticationKeys.id.verifyMandatoryKeys(authData: authData) else {\n            let error = ParseError(code: .unknownError,\n                                   message: \"Should have authData in consisting of keys \\\"id\\\" and \\\"token\\\".\")\n            callbackQueue.async {\n                completion(.failure(error))\n            }\n            return\n        }\n        AuthenticatedUser.link(Self.__type,\n                               authData: authData,\n                               options: options,\n                               callbackQueue: callbackQueue,\n                               completion: completion)\n    }\n}\n\n// MARK: 3rd Party Authentication - ParseApple\npublic extension ParseUser {\n\n    /// An apple `ParseUser`.\n    static var apple: ParseApple<Self> {\n        ParseApple<Self>()\n    }\n\n    /// An apple `ParseUser`.\n    var apple: ParseApple<Self> {\n        Self.apple\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseFacebook/ParseFacebook+async.swift",
    "content": "//\n//  ParseFacebook+async.swift\n//  ParseFacebook+async\n//\n//  Created by Corey Baker on 8/7/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n\npublic extension ParseFacebook {\n    // MARK: Async/Await\n\n    /**\n     Login a `ParseUser` *asynchronously* using Facebook authentication for limited login.\n     - parameter userId: The **id** from **FacebookSDK**.\n     - parameter authenticationToken: The `authenticationToken` from **FacebookSDK**.\n     - parameter expiresIn: Optional expiration in seconds for Facebook login.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func login(userId: String,\n               authenticationToken: String,\n               expiresIn: Int? = nil,\n               options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.login(userId: userId,\n                       authenticationToken: authenticationToken,\n                       expiresIn: expiresIn,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using Facebook authentication for graph API login.\n     - parameter userId: The **id** from **FacebookSDK**.\n     - parameter accessToken: The `accessToken` from **FacebookSDK**.\n     - parameter expiresIn: Optional expiration in seconds for Facebook login.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func login(userId: String,\n               accessToken: String,\n               expiresIn: Int? = nil,\n               options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.login(userId: userId,\n                       accessToken: accessToken,\n                       expiresIn: expiresIn,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using Facebook authentication for graph API login.\n     - parameter authData: Dictionary containing key/values.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func login(authData: [String: String],\n               options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.login(authData: authData,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n}\n\npublic extension ParseFacebook {\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Facebook authentication for limited login.\n     - parameter userId: The **id** from **FacebookSDK**.\n     - parameter authenticationToken: The `authenticationToken` from **FacebookSDK**.\n     - parameter expiresIn: Optional expiration in seconds for Facebook login.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func link(userId: String,\n              authenticationToken: String,\n              expiresIn: Int? = nil,\n              options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.link(userId: userId,\n                      authenticationToken: authenticationToken,\n                      expiresIn: expiresIn,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Facebook authentication for graph API login.\n     - parameter userId: The **id** from **FacebookSDK**.\n     - parameter accessToken: The `accessToken` from **FacebookSDK**.\n     - parameter expiresIn: Optional expiration in seconds for Facebook login.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func link(userId: String,\n              accessToken: String,\n              expiresIn: Int? = nil,\n              options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.link(userId: userId,\n                      accessToken: accessToken,\n                      expiresIn: expiresIn,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Facebook authentication for graph API login.\n     - parameter authData: Dictionary containing key/values.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func link(authData: [String: String],\n              options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.link(authData: authData,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseFacebook/ParseFacebook+combine.swift",
    "content": "//\n//  ParseFacebook+combine.swift\n//  ParseFacebook+combine\n//\n//  Created by Corey Baker on 8/7/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\npublic extension ParseFacebook {\n    // MARK: Combine\n    /**\n     Login a `ParseUser` *asynchronously* using Facebook authentication for limited login. Publishes when complete.\n     - parameter userId: The **id** from **FacebookSDK**.\n     - parameter authenticationToken: The `authenticationToken` from **FacebookSDK**.\n     - parameter expiresIn: Optional expiration in seconds for Facebook login.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func loginPublisher(userId: String,\n                        authenticationToken: String,\n                        expiresIn: Int? = nil,\n                        options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.login(userId: userId,\n                       authenticationToken: authenticationToken,\n                       expiresIn: expiresIn,\n                       options: options,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using Facebook authentication for graph API login. Publishes when complete.\n     - parameter userId: The **id** from **FacebookSDK**.\n     - parameter accessToken: The `accessToken` from **FacebookSDK**.\n     - parameter expiresIn: Optional expiration in seconds for Facebook login.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func loginPublisher(userId: String,\n                        accessToken: String,\n                        expiresIn: Int? = nil,\n                        options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.login(userId: userId,\n                       accessToken: accessToken,\n                       expiresIn: expiresIn,\n                       options: options,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using Facebook authentication for graph API login. Publishes when complete.\n     - parameter authData: Dictionary containing key/values.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func loginPublisher(authData: [String: String],\n                        options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.login(authData: authData,\n                       options: options,\n                       completion: promise)\n        }\n    }\n}\n\npublic extension ParseFacebook {\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Facebook authentication for limited login.\n     Publishes when complete.\n     - parameter userId: The **id** from **FacebookSDK**.\n     - parameter authenticationToken: The `authenticationToken` from **FacebookSDK**.\n     - parameter expiresIn: Optional expiration in seconds for Facebook login.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func linkPublisher(userId: String,\n                       authenticationToken: String,\n                       expiresIn: Int? = nil,\n                       options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.link(userId: userId,\n                      authenticationToken: authenticationToken,\n                      expiresIn: expiresIn,\n                      options: options,\n                      completion: promise)\n        }\n    }\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Facebook authentication for graph API login.\n     Publishes when complete.\n     - parameter userId: The **id** from **FacebookSDK**.\n     - parameter accessToken: The `accessToken` from **FacebookSDK**.\n     - parameter expiresIn: Optional expiration in seconds for Facebook login.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func linkPublisher(userId: String,\n                       accessToken: String,\n                       expiresIn: Int? = nil,\n                       options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.link(userId: userId,\n                      accessToken: accessToken,\n                      expiresIn: expiresIn,\n                      options: options,\n                      completion: promise)\n        }\n    }\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Facebook authentication for graph API login.\n     Publishes when complete.\n     - parameter authData: Dictionary containing key/values.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func linkPublisher(authData: [String: String],\n                       options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.link(authData: authData,\n                      options: options,\n                      completion: promise)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseFacebook/ParseFacebook.swift",
    "content": "//\n//  ParseFacebook.swift\n//  ParseSwift\n//\n//  Created by Abdulaziz Alhomaidhi on 3/18/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n\nimport Foundation\n\n// swiftlint:disable line_length\n\n/**\n Provides utility functions for working with Facebook User Authentication and `ParseUser`'s.\n Be sure your Parse Server is configured for [sign in with Facebook](https://docs.parseplatform.org/parse-server/guide/#facebook-authdata).\n For information on acquiring Facebook sign-in credentials to use with `ParseFacebook`, refer to [Facebook's Documentation](https://developers.facebook.com/docs/facebook-login/limited-login).\n */\npublic struct ParseFacebook<AuthenticatedUser: ParseUser>: ParseAuthentication {\n\n    /// Authentication keys required for Facebook authentication.\n    enum AuthenticationKeys: String, Codable {\n        case id\n        case authenticationToken = \"token\"\n        case accessToken = \"access_token\"\n        case expirationDate = \"expiration_date\"\n\n        /// Properly makes an authData dictionary with the required keys.\n        /// - parameter userId: Required id for the user.\n        /// - parameter authenticationToken: Required identity token for Facebook limited login.\n        /// - parameter accessToken: Required identity token for Facebook graph API.\n        /// - parameter expiresIn: Optional expiration in seconds for Facebook login.\n        /// - returns: authData dictionary.\n        func makeDictionary(userId: String,\n                            accessToken: String?,\n                            authenticationToken: String?,\n                            expiresIn: Int? = nil) -> [String: String] {\n\n            var returnDictionary = [AuthenticationKeys.id.rawValue: userId]\n            if let expiresIn = expiresIn,\n                let expirationDate = Calendar.current.date(byAdding: .second,\n                                                             value: expiresIn,\n                                                             to: Date()) {\n                let dateString = ParseCoding.dateFormatter.string(from: expirationDate)\n                returnDictionary[AuthenticationKeys.expirationDate.rawValue] = dateString\n            }\n\n            if let accessToken = accessToken {\n              returnDictionary[AuthenticationKeys.accessToken.rawValue] = accessToken\n            } else if let authenticationToken = authenticationToken {\n              returnDictionary[AuthenticationKeys.authenticationToken.rawValue] = authenticationToken\n            }\n            return returnDictionary\n        }\n\n        /// Verifies all mandatory keys are in authData.\n        /// - parameter authData: Dictionary containing key/values.\n        /// - returns: **true** if all the mandatory keys are present, **false** otherwise.\n        func verifyMandatoryKeys(authData: [String: String]) -> Bool {\n            guard authData[AuthenticationKeys.id.rawValue] != nil else {\n                return false\n            }\n\n            if authData[AuthenticationKeys.accessToken.rawValue] != nil ||\n                authData[AuthenticationKeys.authenticationToken.rawValue] != nil {\n                return true\n            }\n            return false\n        }\n    }\n\n    public static var __type: String { // swiftlint:disable:this identifier_name\n        \"facebook\"\n    }\n\n    public init() { }\n}\n\n// MARK: Login\npublic extension ParseFacebook {\n\n    /**\n     Login a `ParseUser` *asynchronously* using Facebook authentication for limited login.\n     - parameter userId: The `Facebook userId` from **FacebookSDK**.\n     - parameter authenticationToken: The `authenticationToken` from **FacebookSDK**.\n     - parameter expiresIn: Optional expiration in seconds for Facebook login.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func login(userId: String,\n               authenticationToken: String,\n               expiresIn: Int? = nil,\n               options: API.Options = [],\n               callbackQueue: DispatchQueue = .main,\n               completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n\n        let facebookAuthData = AuthenticationKeys.id\n                .makeDictionary(userId: userId, accessToken: nil,\n                                authenticationToken: authenticationToken,\n                                expiresIn: expiresIn)\n        login(authData: facebookAuthData,\n              options: options,\n              callbackQueue: callbackQueue,\n              completion: completion)\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using Facebook authentication for graph API login.\n     - parameter userId: The `Facebook userId` from **FacebookSDK**.\n     - parameter accessToken: The `accessToken` from **FacebookSDK**.\n     - parameter expiresIn: Optional expiration in seconds for Facebook login.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func login(userId: String,\n               accessToken: String,\n               expiresIn: Int? = nil,\n               options: API.Options = [],\n               callbackQueue: DispatchQueue = .main,\n               completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n\n        let facebookAuthData = AuthenticationKeys.id\n                .makeDictionary(userId: userId,\n                                accessToken: accessToken,\n                                authenticationToken: nil,\n                                expiresIn: expiresIn)\n        login(authData: facebookAuthData,\n              options: options,\n              callbackQueue: callbackQueue,\n              completion: completion)\n    }\n\n    func login(authData: [String: String],\n               options: API.Options = [],\n               callbackQueue: DispatchQueue = .main,\n               completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        guard AuthenticationKeys.id.verifyMandatoryKeys(authData: authData) else {\n            callbackQueue.async {\n                completion(.failure(.init(code: .unknownError,\n                                          message: \"Should have authData in consisting of keys \\\"id\\\", \\\"expirationDate\\\" and \\\"authenticationToken\\\" or \\\"accessToken\\\".\")))\n            }\n            return\n        }\n        AuthenticatedUser.login(Self.__type,\n                                authData: authData,\n                                options: options,\n                                callbackQueue: callbackQueue,\n                                completion: completion)\n    }\n}\n\n// MARK: Link\npublic extension ParseFacebook {\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Facebook authentication for limited login.\n     - parameter userId: The **id** from **FacebookSDK**.\n     - parameter authenticationToken: The `authenticationToken` from **FacebookSDK**.\n     - parameter expiresIn: Optional expiration in seconds for Facebook login.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func link(userId: String,\n              authenticationToken: String,\n              expiresIn: Int? = nil,\n              options: API.Options = [],\n              callbackQueue: DispatchQueue = .main,\n              completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        let facebookAuthData = AuthenticationKeys.id\n            .makeDictionary(userId: userId,\n                            accessToken: nil,\n                            authenticationToken: authenticationToken,\n                            expiresIn: expiresIn)\n        link(authData: facebookAuthData,\n             options: options,\n             callbackQueue: callbackQueue,\n             completion: completion)\n    }\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Facebook authentication for graph API login.\n     - parameter userId: The **id** from **FacebookSDK**.\n     - parameter accessToken: The `accessToken` from **FacebookSDK**.\n     - parameter expiresIn: Optional expiration in seconds for Facebook login.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func link(userId: String,\n              accessToken: String,\n              expiresIn: Int? = nil,\n              options: API.Options = [],\n              callbackQueue: DispatchQueue = .main,\n              completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        let facebookAuthData = AuthenticationKeys.id\n            .makeDictionary(userId: userId,\n                            accessToken: accessToken,\n                            authenticationToken: nil,\n                            expiresIn: expiresIn)\n        link(authData: facebookAuthData,\n             options: options,\n             callbackQueue: callbackQueue,\n             completion: completion)\n    }\n\n    func link(authData: [String: String],\n              options: API.Options = [],\n              callbackQueue: DispatchQueue = .main,\n              completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        guard AuthenticationKeys.id.verifyMandatoryKeys(authData: authData) else {\n            callbackQueue.async {\n                completion(.failure(.init(code: .unknownError,\n                                          message: \"Should have authData in consisting of keys \\\"id\\\", \\\"expirationDate\\\" and \\\"authenticationToken\\\" or \\\"accessToken\\\".\")))\n            }\n            return\n        }\n        AuthenticatedUser.link(Self.__type,\n                               authData: authData,\n                               options: options,\n                               callbackQueue: callbackQueue,\n                               completion: completion)\n    }\n}\n\n// MARK: 3rd Party Authentication - ParseFacebook\npublic extension ParseUser {\n\n    /// A facebook `ParseUser`.\n    static var facebook: ParseFacebook<Self> {\n        ParseFacebook<Self>()\n    }\n\n    /// An facebook `ParseUser`.\n    var facebook: ParseFacebook<Self> {\n        Self.facebook\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseGithub/ParseGitHub+async.swift",
    "content": "//\n//  ParseGitHub+async.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/1/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n\npublic extension ParseGitHub {\n    // MARK: Async/Await\n\n    /**\n     Login a `ParseUser` *asynchronously* using GitHub authentication for graph API login.\n     - parameter id: The **id** from **GitHub**.\n     - parameter accessToken: Required **access_token** from **GitHub**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func login(id: String,\n               accessToken: String,\n               options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.login(id: id,\n                       accessToken: accessToken,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using GitHub authentication for graph API login.\n     - parameter authData: Dictionary containing key/values.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func login(authData: [String: String],\n               options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.login(authData: authData,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n}\n\npublic extension ParseGitHub {\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using GitHub authentication for graph API login.\n     - parameter id: The **id** from **GitHub**.\n     - parameter accessToken: Required **access_token** from **GitHub**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func link(id: String,\n              accessToken: String,\n              options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.link(id: id,\n                      accessToken: accessToken,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using GitHub authentication for graph API login.\n     - parameter authData: Dictionary containing key/values.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func link(authData: [String: String],\n              options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.link(authData: authData,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseGithub/ParseGitHub+combine.swift",
    "content": "//\n//  ParseGitHub+combine.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/1/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\npublic extension ParseGitHub {\n    // MARK: Combine\n    /**\n     Login a `ParseUser` *asynchronously* using GitHub authentication for graph API login. Publishes when complete.\n     - parameter id: The **id** from **GitHub**.\n     - parameter accessToken: Required **access_token** from **GitHub**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func loginPublisher(id: String,\n                        accessToken: String,\n                        options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.login(id: id,\n                       accessToken: accessToken,\n                       options: options,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using GitHub authentication for graph API login. Publishes when complete.\n     - parameter authData: Dictionary containing key/values.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func loginPublisher(authData: [String: String],\n                        options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.login(authData: authData,\n                       options: options,\n                       completion: promise)\n        }\n    }\n}\n\npublic extension ParseGitHub {\n    /**\n     Link the *current* `ParseUser` *asynchronously* using GitHub authentication for graph API login.\n     Publishes when complete.\n     - parameter id: The **id** from **GitHub**.\n     - parameter accessToken: Required **access_token** from **GitHub**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func linkPublisher(id: String,\n                       accessToken: String,\n                       options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.link(id: id,\n                      accessToken: accessToken,\n                      options: options,\n                      completion: promise)\n        }\n    }\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using GitHub authentication for graph API login.\n     Publishes when complete.\n     - parameter authData: Dictionary containing key/values.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func linkPublisher(authData: [String: String],\n                       options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.link(authData: authData,\n                      options: options,\n                      completion: promise)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseGithub/ParseGitHub.swift",
    "content": "//\n//  ParseGitHub.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/1/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n// swiftlint:disable line_length\n\n/**\n Provides utility functions for working with GitHub User Authentication and `ParseUser`'s.\n Be sure your Parse Server is configured for [sign in with GitHub](https://docs.parseplatform.org/parse-server/guide/#github-authdata).\n For information on acquiring GitHub sign-in credentials to use with `ParseGitHub`, refer to [GitHub's Documentation](https://docs.github.com/en/developers/apps/building-oauth-apps/authorizing-oauth-apps).\n */\npublic struct ParseGitHub<AuthenticatedUser: ParseUser>: ParseAuthentication {\n\n    /// Authentication keys required for GitHub authentication.\n    enum AuthenticationKeys: String, Codable {\n        case id\n        case accessToken = \"access_token\"\n\n        /// Properly makes an authData dictionary with the required keys.\n        /// - parameter id: Required id for the user.\n        /// - parameter accessToken: Required identity token for GitHub.\n        /// - returns: authData dictionary.\n        func makeDictionary(id: String,\n                            accessToken: String) -> [String: String] {\n\n            let returnDictionary = [\n                AuthenticationKeys.id.rawValue: id,\n                AuthenticationKeys.accessToken.rawValue: accessToken\n            ]\n            return returnDictionary\n        }\n\n        /// Verifies all mandatory keys are in authData.\n        /// - parameter authData: Dictionary containing key/values.\n        /// - returns: **true** if all the mandatory keys are present, **false** otherwise.\n        func verifyMandatoryKeys(authData: [String: String]) -> Bool {\n            guard authData[AuthenticationKeys.id.rawValue] != nil,\n                  authData[AuthenticationKeys.accessToken.rawValue] != nil else {\n                return false\n            }\n            return true\n        }\n    }\n\n    public static var __type: String { // swiftlint:disable:this identifier_name\n        \"github\"\n    }\n\n    public init() { }\n}\n\n// MARK: Login\npublic extension ParseGitHub {\n\n    /**\n     Login a `ParseUser` *asynchronously* using GitHub authentication for graph API login.\n     - parameter id: The `GitHub id` from **GitHub**.\n     - parameter accessToken: Required **access_token** from **GitHub**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func login(id: String,\n               accessToken: String,\n               options: API.Options = [],\n               callbackQueue: DispatchQueue = .main,\n               completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n\n        let githubAuthData = AuthenticationKeys.id\n                .makeDictionary(id: id,\n                                accessToken: accessToken)\n        login(authData: githubAuthData,\n              options: options,\n              callbackQueue: callbackQueue,\n              completion: completion)\n    }\n\n    func login(authData: [String: String],\n               options: API.Options = [],\n               callbackQueue: DispatchQueue = .main,\n               completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        guard AuthenticationKeys.id.verifyMandatoryKeys(authData: authData) else {\n            callbackQueue.async {\n                completion(.failure(.init(code: .unknownError,\n                                          message: \"Should have authData in consisting of keys \\\"id\\\" and \\\"accessToken\\\".\")))\n            }\n            return\n        }\n        AuthenticatedUser.login(Self.__type,\n                                authData: authData,\n                                options: options,\n                                callbackQueue: callbackQueue,\n                                completion: completion)\n    }\n}\n\n// MARK: Link\npublic extension ParseGitHub {\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using GitHub authentication for graph API login.\n     - parameter id: The **id** from **GitHub**.\n     - parameter accessToken: Required **access_token** from **GitHub**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func link(id: String,\n              accessToken: String,\n              options: API.Options = [],\n              callbackQueue: DispatchQueue = .main,\n              completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        let githubAuthData = AuthenticationKeys.id\n            .makeDictionary(id: id,\n                            accessToken: accessToken)\n        link(authData: githubAuthData,\n             options: options,\n             callbackQueue: callbackQueue,\n             completion: completion)\n    }\n\n    func link(authData: [String: String],\n              options: API.Options = [],\n              callbackQueue: DispatchQueue = .main,\n              completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        guard AuthenticationKeys.id.verifyMandatoryKeys(authData: authData) else {\n            callbackQueue.async {\n                completion(.failure(.init(code: .unknownError,\n                                          message: \"Should have authData in consisting of keys \\\"id\\\" and \\\"accessToken\\\".\")))\n            }\n            return\n        }\n        AuthenticatedUser.link(Self.__type,\n                               authData: authData,\n                               options: options,\n                               callbackQueue: callbackQueue,\n                               completion: completion)\n    }\n}\n\n// MARK: 3rd Party Authentication - ParseGitHub\npublic extension ParseUser {\n\n    /// A github `ParseUser`.\n    static var github: ParseGitHub<Self> {\n        ParseGitHub<Self>()\n    }\n\n    /// An github `ParseUser`.\n    var github: ParseGitHub<Self> {\n        Self.github\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseGoogle/ParseGoogle+async.swift",
    "content": "//\n//  ParseGoogle+async.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/1/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n\npublic extension ParseGoogle {\n    // MARK: Async/Await\n\n    /**\n     Login a `ParseUser` *asynchronously* using Google authentication for graph API login.\n     - parameter id: The **id** from **Google**.\n     - parameter idToken: Optional **id_token** from **Google**.\n     - parameter accessToken: Optional **access_token** from **Google**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func login(id: String,\n               idToken: String? = nil,\n               accessToken: String? = nil,\n               options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.login(id: id,\n                       idToken: idToken,\n                       accessToken: accessToken,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using Google authentication for graph API login.\n     - parameter authData: Dictionary containing key/values.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func login(authData: [String: String],\n               options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.login(authData: authData,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n}\n\npublic extension ParseGoogle {\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Google authentication for graph API login.\n     - parameter id: The **id** from **Google**.\n     - parameter idToken: Optional **id_token** from **Google**.\n     - parameter accessToken: Optional **access_token** from **Google**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func link(id: String,\n              idToken: String? = nil,\n              accessToken: String? = nil,\n              options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.link(id: id,\n                      idToken: idToken,\n                      accessToken: accessToken,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Google authentication for graph API login.\n     - parameter authData: Dictionary containing key/values.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func link(authData: [String: String],\n              options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.link(authData: authData,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseGoogle/ParseGoogle+combine.swift",
    "content": "//\n//  ParseGoogle+combine.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/1/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\npublic extension ParseGoogle {\n    // MARK: Combine\n    /**\n     Login a `ParseUser` *asynchronously* using Google authentication for graph API login. Publishes when complete.\n     - parameter id: The **id** from **Google**.\n     - parameter idToken: Optional **id_token** from **Google**.\n     - parameter accessToken: Optional **access_token** from **Google**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func loginPublisher(id: String,\n                        idToken: String? = nil,\n                        accessToken: String? = nil,\n                        options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.login(id: id,\n                       idToken: idToken,\n                       accessToken: accessToken,\n                       options: options,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using Google authentication for graph API login. Publishes when complete.\n     - parameter authData: Dictionary containing key/values.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func loginPublisher(authData: [String: String],\n                        options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.login(authData: authData,\n                       options: options,\n                       completion: promise)\n        }\n    }\n}\n\npublic extension ParseGoogle {\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Google authentication for graph API login.\n     Publishes when complete.\n     - parameter id: The **id** from **Google**.\n     - parameter idToken: Optional **id_token** from **Google**.\n     - parameter accessToken: Optional **access_token** from **Google**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func linkPublisher(id: String,\n                       idToken: String? = nil,\n                       accessToken: String? = nil,\n                       options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.link(id: id,\n                      idToken: idToken,\n                      accessToken: accessToken,\n                      options: options,\n                      completion: promise)\n        }\n    }\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Google authentication for graph API login.\n     Publishes when complete.\n     - parameter authData: Dictionary containing key/values.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func linkPublisher(authData: [String: String],\n                       options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.link(authData: authData,\n                      options: options,\n                      completion: promise)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseGoogle/ParseGoogle.swift",
    "content": "//\n//  ParseGoogle.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/1/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n// swiftlint:disable line_length\n\n/**\n Provides utility functions for working with Google User Authentication and `ParseUser`'s.\n Be sure your Parse Server is configured for [sign in with Google](https://docs.parseplatform.org/parse-server/guide/#google-authdata).\n For information on acquiring Google sign-in credentials to use with `ParseGoogle`, refer to [Google's Documentation](https://developers.google.com/identity/protocols/oauth2).\n */\npublic struct ParseGoogle<AuthenticatedUser: ParseUser>: ParseAuthentication {\n\n    /// Authentication keys required for Google authentication.\n    enum AuthenticationKeys: String, Codable {\n        case id\n        case idToken = \"id_token\"\n        case accessToken = \"access_token\"\n\n        /// Properly makes an authData dictionary with the required keys.\n        /// - parameter id: Required id for the user.\n        /// - parameter idToken: Optional identity token for Google.\n        /// - parameter accessToken: Optional identity token for Google.\n        /// - returns: authData dictionary.\n        func makeDictionary(id: String,\n                            idToken: String? = nil,\n                            accessToken: String? = nil) -> [String: String] {\n\n            var returnDictionary = [AuthenticationKeys.id.rawValue: id]\n            if let accessToken = accessToken {\n              returnDictionary[AuthenticationKeys.accessToken.rawValue] = accessToken\n            } else if let idToken = idToken {\n              returnDictionary[AuthenticationKeys.idToken.rawValue] = idToken\n            }\n            return returnDictionary\n        }\n\n        /// Verifies all mandatory keys are in authData.\n        /// - parameter authData: Dictionary containing key/values.\n        /// - returns: **true** if all the mandatory keys are present, **false** otherwise.\n        func verifyMandatoryKeys(authData: [String: String]) -> Bool {\n            guard authData[AuthenticationKeys.id.rawValue] != nil else {\n                return false\n            }\n\n            if authData[AuthenticationKeys.accessToken.rawValue] != nil ||\n                authData[AuthenticationKeys.idToken.rawValue] != nil {\n                return true\n            }\n            return false\n        }\n    }\n\n    public static var __type: String { // swiftlint:disable:this identifier_name\n        \"google\"\n    }\n\n    public init() { }\n}\n\n// MARK: Login\npublic extension ParseGoogle {\n\n    /**\n     Login a `ParseUser` *asynchronously* using Google authentication for graph API login.\n     - parameter id: The `id` from **Google**.\n     - parameter idToken: Optional **id_token** from **Google**.\n     - parameter accessToken: Optional **access_token** from **Google**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func login(id: String,\n               idToken: String? = nil,\n               accessToken: String? = nil,\n               options: API.Options = [],\n               callbackQueue: DispatchQueue = .main,\n               completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n\n        let googleAuthData = AuthenticationKeys.id\n                .makeDictionary(id: id,\n                                idToken: idToken,\n                                accessToken: accessToken)\n        login(authData: googleAuthData,\n              options: options,\n              callbackQueue: callbackQueue,\n              completion: completion)\n    }\n\n    func login(authData: [String: String],\n               options: API.Options = [],\n               callbackQueue: DispatchQueue = .main,\n               completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        guard AuthenticationKeys.id.verifyMandatoryKeys(authData: authData) else {\n            callbackQueue.async {\n                completion(.failure(.init(code: .unknownError,\n                                          message: \"Should have authData in consisting of keys \\\"id\\\", \\\"idToken\\\" or \\\"accessToken\\\".\")))\n            }\n            return\n        }\n        AuthenticatedUser.login(Self.__type,\n                                authData: authData,\n                                options: options,\n                                callbackQueue: callbackQueue,\n                                completion: completion)\n    }\n}\n\n// MARK: Link\npublic extension ParseGoogle {\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Google authentication for graph API login.\n     - parameter id: The **id** from **Google**.\n     - parameter idToken: Optional **id_token** from **Google**.\n     - parameter accessToken: Optional **access_token** from **Google**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func link(id: String,\n              idToken: String? = nil,\n              accessToken: String? = nil,\n              options: API.Options = [],\n              callbackQueue: DispatchQueue = .main,\n              completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        let googleAuthData = AuthenticationKeys.id\n            .makeDictionary(id: id,\n                            idToken: idToken,\n                            accessToken: accessToken)\n        link(authData: googleAuthData,\n             options: options,\n             callbackQueue: callbackQueue,\n             completion: completion)\n    }\n\n    func link(authData: [String: String],\n              options: API.Options = [],\n              callbackQueue: DispatchQueue = .main,\n              completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        guard AuthenticationKeys.id.verifyMandatoryKeys(authData: authData) else {\n            callbackQueue.async {\n                completion(.failure(.init(code: .unknownError,\n                                          message: \"Should have authData in consisting of keys \\\"id\\\", \\\"idToken\\\" or \\\"accessToken\\\".\")))\n            }\n            return\n        }\n        AuthenticatedUser.link(Self.__type,\n                               authData: authData,\n                               options: options,\n                               callbackQueue: callbackQueue,\n                               completion: completion)\n    }\n}\n\n// MARK: 3rd Party Authentication - ParseGoogle\npublic extension ParseUser {\n\n    /// A google `ParseUser`.\n    static var google: ParseGoogle<Self> {\n        ParseGoogle<Self>()\n    }\n\n    /// An google `ParseUser`.\n    var google: ParseGoogle<Self> {\n        Self.google\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseInstagram/ParseInstagram+async.swift",
    "content": "//\n//  ParseInstagram+async.swift\n//  ParseSwift\n//\n//  Created by Ulaş Sancak on 06/19/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n\npublic extension ParseInstagram {\n    // MARK: Async/Await\n\n    /**\n     Login a `ParseUser` *asynchronously* using Instagram authentication.\n     - parameter id: The **Instagram profile id** from **Instagram**.\n     - parameter accessToken: Required **access_token** from **Instagram**.\n     - parameter apiURL: The `Instagram's most recent graph api url` from **Instagram**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func login(id: String,\n               accessToken: String,\n               apiURL: String = Self.graphAPIBaseURL,\n               options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.login(id: id,\n                       accessToken: accessToken,\n                       apiURL: apiURL,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using Instagram authentication.\n     - parameter authData: Dictionary containing key/values.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func login(authData: [String: String],\n               options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.login(authData: authData,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n}\n\npublic extension ParseInstagram {\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Instagram authentication.\n     - parameter id: The **Instagram profile id** from **Instagram**.\n     - parameter accessToken: Required **access_token** from **Instagram**.\n     - parameter apiURL: The `Instagram's most recent graph api url` from **Instagram**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func link(id: String,\n              accessToken: String,\n              apiURL: String = Self.graphAPIBaseURL,\n              options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.link(id: id,\n                      accessToken: accessToken,\n                      apiURL: apiURL,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Instagram authentication.\n     - parameter authData: Dictionary containing key/values.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func link(authData: [String: String],\n              options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.link(authData: authData,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseInstagram/ParseInstagram+combine.swift",
    "content": "//\n//  ParseInstagram+combine.swift\n//  ParseSwift\n//\n//  Created by Ulaş Sancak on 06/19/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\npublic extension ParseInstagram {\n    // MARK: Combine\n    /**\n     Login a `ParseUser` *asynchronously* using Instagram authentication. Publishes when complete.\n     - parameter id: The **Instagram profile id** from **Instagram**.\n     - parameter accessToken: Required **access_token** from **Instagram**.\n     - parameter apiURL: The `Instagram's most recent graph api url` from **Instagram**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func loginPublisher(id: String,\n                        accessToken: String,\n                        apiURL: String = Self.graphAPIBaseURL,\n                        options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.login(id: id,\n                       accessToken: accessToken,\n                       apiURL: apiURL,\n                       options: options,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using Instagram authentication. Publishes when complete.\n     - parameter authData: Dictionary containing key/values.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func loginPublisher(authData: [String: String],\n                        options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.login(authData: authData,\n                       options: options,\n                       completion: promise)\n        }\n    }\n}\n\npublic extension ParseInstagram {\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Instagram authentication.\n     Publishes when complete.\n     - parameter id: The **Instagram profile id** from **Instagram**.\n     - parameter accessToken: Required **access_token** from **Instagram**.\n     - parameter apiURL: The `Instagram's most recent graph api url` from **Instagram**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func linkPublisher(id: String,\n                       accessToken: String,\n                       apiURL: String = Self.graphAPIBaseURL,\n                       options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.link(id: id,\n                      accessToken: accessToken,\n                      apiURL: apiURL,\n                      options: options,\n                      completion: promise)\n        }\n    }\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Instagram authentication.\n     Publishes when complete.\n     - parameter authData: Dictionary containing key/values.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func linkPublisher(authData: [String: String],\n                       options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.link(authData: authData,\n                      options: options,\n                      completion: promise)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseInstagram/ParseInstagram.swift",
    "content": "//\n//  ParseInstagram.swift\n//  ParseSwift\n//\n//  Created by Ulaş Sancak on 06/19/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n// swiftlint:disable line_length\n\n/**\n Provides utility functions for working with Instagram User Authentication and `ParseUser`'s.\n Be sure your Parse Server is configured for [sign in with Instagram](https://docs.parseplatform.org/parse-server/guide/#instagram-authdata).\n For information on acquiring Instagram sign-in credentials to use with `ParseInstagram`, refer to [Facebook's Documentation](https://developers.facebook.com/docs/instagram-basic-display-api/overview).\n */\npublic struct ParseInstagram<AuthenticatedUser: ParseUser>: ParseAuthentication {\n\n    public static var graphAPIBaseURL: String {\n        \"https://graph.instagram.com/\"\n    }\n\n    /// Authentication keys required for Instagram authentication.\n    enum AuthenticationKeys: String, Codable {\n        case id\n        case accessToken = \"access_token\"\n        case apiURL\n\n        /// Properly makes an authData dictionary with the required keys.\n        /// - parameter id: Required id for the user.\n        /// - parameter accessToken: Required access token for Instagram.\n        /// - returns: authData dictionary.\n        func makeDictionary(id: String,\n                            accessToken: String,\n                            apiURL: String = ParseInstagram.graphAPIBaseURL) -> [String: String] {\n\n            let returnDictionary = [\n                AuthenticationKeys.id.rawValue: id,\n                AuthenticationKeys.accessToken.rawValue: accessToken,\n                AuthenticationKeys.apiURL.rawValue: apiURL\n            ]\n            return returnDictionary\n        }\n\n        /// Verifies all mandatory keys are in authData.\n        /// - parameter authData: Dictionary containing key/values.\n        /// - returns: **true** if all the mandatory keys are present, **false** otherwise.\n        func verifyMandatoryKeys(authData: [String: String]) -> Bool {\n            guard authData[AuthenticationKeys.id.rawValue] != nil,\n                  authData[AuthenticationKeys.accessToken.rawValue] != nil,\n                  authData[AuthenticationKeys.apiURL.rawValue] != nil else {\n                return false\n            }\n            return true\n        }\n    }\n\n    public static var __type: String { // swiftlint:disable:this identifier_name\n        \"instagram\"\n    }\n\n    public init() { }\n}\n\n// MARK: Login\npublic extension ParseInstagram {\n\n    /**\n     Login a `ParseUser` *asynchronously* using Instagram authentication.\n     - parameter id: The **Instagram profile id** from **Instagram**.\n     - parameter accessToken: Required **access_token** from **Instagram**.\n     - parameter apiURL: The `Instagram's most recent graph api url` from **Instagram**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func login(id: String,\n               accessToken: String,\n               apiURL: String = Self.graphAPIBaseURL,\n               options: API.Options = [],\n               callbackQueue: DispatchQueue = .main,\n               completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n\n        let instagramAuthData = AuthenticationKeys.id\n                .makeDictionary(id: id,\n                                accessToken: accessToken,\n                                apiURL: apiURL)\n        login(authData: instagramAuthData,\n              options: options,\n              callbackQueue: callbackQueue,\n              completion: completion)\n    }\n\n    func login(authData: [String: String],\n               options: API.Options = [],\n               callbackQueue: DispatchQueue = .main,\n               completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        guard AuthenticationKeys.id.verifyMandatoryKeys(authData: authData) else {\n            callbackQueue.async {\n                completion(.failure(.init(code: .unknownError,\n                                          message: \"Should have authData in consisting of keys \\\"id\\\", \\\"accessToken\\\", and \\\"isMobileSDK\\\".\")))\n            }\n            return\n        }\n        AuthenticatedUser.login(Self.__type,\n                                authData: authData,\n                                options: options,\n                                callbackQueue: callbackQueue,\n                                completion: completion)\n    }\n}\n\n// MARK: Link\npublic extension ParseInstagram {\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Instagram authentication.\n     - parameter id: The **Instagram profile id** from **Instagram**.\n     - parameter accessToken: Required **access_token** from **Instagram**.\n     - parameter apiURL: The `Instagram's most recent graph api url` from **Instagram**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func link(id: String,\n              accessToken: String,\n              apiURL: String = Self.graphAPIBaseURL,\n              options: API.Options = [],\n              callbackQueue: DispatchQueue = .main,\n              completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        let instagramAuthData = AuthenticationKeys.id\n            .makeDictionary(id: id,\n                            accessToken: accessToken,\n                            apiURL: apiURL)\n        link(authData: instagramAuthData,\n             options: options,\n             callbackQueue: callbackQueue,\n             completion: completion)\n    }\n\n    func link(authData: [String: String],\n              options: API.Options = [],\n              callbackQueue: DispatchQueue = .main,\n              completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        guard AuthenticationKeys.id.verifyMandatoryKeys(authData: authData) else {\n            callbackQueue.async {\n                completion(.failure(.init(code: .unknownError,\n                                          message: \"Should have authData in consisting of keys \\\"id\\\", \\\"accessToken\\\", and \\\"isMobileSDK\\\".\")))\n            }\n            return\n        }\n        AuthenticatedUser.link(Self.__type,\n                               authData: authData,\n                               options: options,\n                               callbackQueue: callbackQueue,\n                               completion: completion)\n    }\n}\n\n// MARK: 3rd Party Authentication - ParseInstagram\npublic extension ParseUser {\n\n    /// A Instagram `ParseUser`.\n    static var instagram: ParseInstagram<Self> {\n        ParseInstagram<Self>()\n    }\n\n    /// An Instagram `ParseUser`.\n    var instagram: ParseInstagram<Self> {\n        Self.instagram\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseLDAP/ParseLDAP+async.swift",
    "content": "//\n//  ParseLDAP+async.swift\n//  ParseLDAP+async\n//\n//  Created by Corey Baker on 8/7/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n\npublic extension ParseLDAP {\n    // MARK: Async/Await\n    /**\n     Login a `ParseUser` *asynchronously* using LDAP authentication.\n     - parameter id: The id of the `user`.\n     - parameter password: The password of the user.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func login(id: String,\n               password: String,\n               options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.login(id: id,\n                       password: password,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using LDAP authentication.\n     - parameter authData: Dictionary containing key/values.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func login(authData: [String: String],\n               options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.login(authData: authData,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n}\n\npublic extension ParseLDAP {\n    /**\n     Link the *current* `ParseUser` *asynchronously* using LDAP authentication.\n     - parameter id: The id of the `user`.\n     - parameter password: The password of the user.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func link(id: String,\n              password: String,\n              options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.link(id: id,\n                      password: password,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using LDAP authentication.\n     - parameter authData: Dictionary containing key/values.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func link(authData: [String: String],\n              options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.link(authData: authData,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseLDAP/ParseLDAP+combine.swift",
    "content": "//\n//  ParseLDAP+combine.swift\n//  ParseLDAP+combine\n//\n//  Created by Corey Baker on 8/7/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\npublic extension ParseLDAP {\n    // MARK: Combine\n    /**\n     Login a `ParseUser` *asynchronously* using LDAP authentication. Publishes when complete.\n     - parameter id: The id of the `user`.\n     - parameter password: The password of the user.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func loginPublisher(id: String,\n                        password: String,\n                        options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.login(id: id,\n                       password: password,\n                       options: options,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using LDAP authentication. Publishes when complete.\n     - parameter authData: Dictionary containing key/values.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func loginPublisher(authData: [String: String],\n                        options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.login(authData: authData,\n                       options: options,\n                       completion: promise)\n        }\n    }\n}\n\npublic extension ParseLDAP {\n    /**\n     Link the *current* `ParseUser` *asynchronously* using LDAP authentication. Publishes when complete.\n     - parameter id: The id of the `user`.\n     - parameter password: The password of the user.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func linkPublisher(id: String,\n                       password: String,\n                       options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.link(id: id,\n                      password: password,\n                      options: options,\n                      completion: promise)\n        }\n    }\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using LDAP authentication. Publishes when complete.\n     - parameter authData: Dictionary containing key/values.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func linkPublisher(authData: [String: String],\n                       options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.link(authData: authData,\n                      options: options,\n                      completion: promise)\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseLDAP/ParseLDAP.swift",
    "content": "//\n//  ParseLDAP.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 2/14/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n// swiftlint:disable line_length\n\n/**\n Provides utility functions for working with LDAP User Authentication and `ParseUser`'s.\n Be sure your Parse Server is configured for [sign in with LDAP](https://docs.parseplatform.org/parse-server/guide/#configuring-parse-server-for-ldap).\n */\npublic struct ParseLDAP<AuthenticatedUser: ParseUser>: ParseAuthentication {\n\n    /// Authentication keys required for LDAP authentication.\n    enum AuthenticationKeys: String, Codable {\n        case id\n        case password\n\n        /// Properly makes an authData dictionary with the required keys.\n        /// - parameter id: Required id.\n        /// - parameter password: Required password.\n        /// - returns: authData dictionary.\n        func makeDictionary(id: String,\n                            password: String) -> [String: String] {\n            [AuthenticationKeys.id.rawValue: id,\n             AuthenticationKeys.password.rawValue: password]\n        }\n\n        /// Verifies all mandatory keys are in authData.\n        /// - parameter authData: Dictionary containing key/values.\n        /// - returns: **true** if all the mandatory keys are present, **false** otherwise.\n        func verifyMandatoryKeys(authData: [String: String]) -> Bool {\n            guard authData[AuthenticationKeys.id.rawValue] != nil,\n                  authData[AuthenticationKeys.password.rawValue] != nil else {\n                return false\n            }\n            return true\n        }\n    }\n\n    public static var __type: String { // swiftlint:disable:this identifier_name\n        \"ldap\"\n    }\n\n    public init() { }\n}\n\n// MARK: Login\npublic extension ParseLDAP {\n    /**\n     Login a `ParseUser` *asynchronously* using LDAP authentication.\n     - parameter id: The id of the `user`.\n     - parameter password: The password of the user.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func login(id: String,\n               password: String,\n               options: API.Options = [],\n               callbackQueue: DispatchQueue = .main,\n               completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        login(authData: AuthenticationKeys.id.makeDictionary(id: id,\n                                                             password: password),\n              options: options,\n              callbackQueue: callbackQueue,\n              completion: completion)\n    }\n\n    func login(authData: [String: String],\n               options: API.Options = [],\n               callbackQueue: DispatchQueue = .main,\n               completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        guard AuthenticationKeys.id.verifyMandatoryKeys(authData: authData) else {\n            callbackQueue.async {\n                completion(.failure(.init(code: .unknownError,\n                                          message: \"Should have authData in consisting of keys \\\"id\\\" and \\\"password\\\".\")))\n            }\n            return\n        }\n        AuthenticatedUser.login(Self.__type,\n                                authData: authData,\n                                options: options,\n                                callbackQueue: callbackQueue,\n                                completion: completion)\n    }\n}\n\n// MARK: Link\npublic extension ParseLDAP {\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using LDAP authentication.\n     - parameter id: The id of the `user`.\n     - parameter password: The password of the user.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func link(id: String,\n              password: String,\n              options: API.Options = [],\n              callbackQueue: DispatchQueue = .main,\n              completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        link(authData: AuthenticationKeys.id.makeDictionary(id: id, password: password),\n                        options: options,\n                        callbackQueue: callbackQueue,\n                        completion: completion)\n    }\n\n    func link(authData: [String: String],\n              options: API.Options = [],\n              callbackQueue: DispatchQueue = .main,\n              completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        guard AuthenticationKeys.id.verifyMandatoryKeys(authData: authData) else {\n            let error = ParseError(code: .unknownError,\n                                   message: \"Should have authData in consisting of keys \\\"id\\\" and \\\"password\\\".\")\n            callbackQueue.async {\n                completion(.failure(error))\n            }\n            return\n        }\n        AuthenticatedUser.link(Self.__type,\n                               authData: authData,\n                               options: options,\n                               callbackQueue: callbackQueue,\n                               completion: completion)\n    }\n}\n\n// MARK: 3rd Party Authentication - ParseLDAP\npublic extension ParseUser {\n\n    /// An ldap `ParseUser`.\n    static var ldap: ParseLDAP<Self> {\n        ParseLDAP<Self>()\n    }\n\n    /// An ldap `ParseUser`.\n    var ldap: ParseLDAP<Self> {\n        Self.ldap\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseLinkedIn/ParseLinkedIn+async.swift",
    "content": "//\n//  ParseLinkedIn+async.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/1/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n\npublic extension ParseLinkedIn {\n    // MARK: Async/Await\n\n    /**\n     Login a `ParseUser` *asynchronously* using LinkedIn authentication for graph API login.\n     - parameter id: The **id** from **LinkedIn**.\n     - parameter accessToken: Required **access_token** from **LinkedIn**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func login(id: String,\n               accessToken: String,\n               isMobileSDK: Bool,\n               options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.login(id: id,\n                       accessToken: accessToken,\n                       isMobileSDK: isMobileSDK,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using LinkedIn authentication for graph API login.\n     - parameter authData: Dictionary containing key/values.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func login(authData: [String: String],\n               options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.login(authData: authData,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n}\n\npublic extension ParseLinkedIn {\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using LinkedIn authentication for graph API login.\n     - parameter id: The **id** from **LinkedIn**.\n     - parameter accessToken: Required **access_token** from **LinkedIn**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func link(id: String,\n              accessToken: String,\n              isMobileSDK: Bool,\n              options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.link(id: id,\n                      accessToken: accessToken,\n                      isMobileSDK: isMobileSDK,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using LinkedIn authentication for graph API login.\n     - parameter authData: Dictionary containing key/values.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func link(authData: [String: String],\n              options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.link(authData: authData,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseLinkedIn/ParseLinkedIn+combine.swift",
    "content": "//\n//  ParseLinkedIn+combine.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/1/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\npublic extension ParseLinkedIn {\n    // MARK: Combine\n    /**\n     Login a `ParseUser` *asynchronously* using LinkedIn authentication for graph API login. Publishes when complete.\n     - parameter id: The **id** from **LinkedIn**.\n     - parameter accessToken: Required **access_token** from **LinkedIn**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func loginPublisher(id: String,\n                        accessToken: String,\n                        isMobileSDK: Bool,\n                        options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.login(id: id,\n                       accessToken: accessToken,\n                       isMobileSDK: isMobileSDK,\n                       options: options,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using LinkedIn authentication for graph API login. Publishes when complete.\n     - parameter authData: Dictionary containing key/values.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func loginPublisher(authData: [String: String],\n                        options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.login(authData: authData,\n                       options: options,\n                       completion: promise)\n        }\n    }\n}\n\npublic extension ParseLinkedIn {\n    /**\n     Link the *current* `ParseUser` *asynchronously* using LinkedIn authentication for graph API login.\n     Publishes when complete.\n     - parameter id: The **id** from **LinkedIn**.\n     - parameter accessToken: Required **access_token** from **LinkedIn**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func linkPublisher(id: String,\n                       accessToken: String,\n                       isMobileSDK: Bool,\n                       options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.link(id: id,\n                      accessToken: accessToken,\n                      isMobileSDK: isMobileSDK,\n                      options: options,\n                      completion: promise)\n        }\n    }\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using LinkedIn authentication for graph API login.\n     Publishes when complete.\n     - parameter authData: Dictionary containing key/values.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func linkPublisher(authData: [String: String],\n                       options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.link(authData: authData,\n                      options: options,\n                      completion: promise)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseLinkedIn/ParseLinkedIn.swift",
    "content": "//\n//  ParseLinkedIn.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/1/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n// swiftlint:disable line_length\n\n/**\n Provides utility functions for working with LinkedIn User Authentication and `ParseUser`'s.\n Be sure your Parse Server is configured for [sign in with LinkedIn](https://docs.parseplatform.org/parse-server/guide/#linkedin-authdata).\n For information on acquiring LinkedIn sign-in credentials to use with `ParseLinkedIn`, refer to [LinkedIn's Documentation](https://docs.microsoft.com/en-us/linkedin/shared/authentication/authentication?context=linkedin/consumer/context).\n */\npublic struct ParseLinkedIn<AuthenticatedUser: ParseUser>: ParseAuthentication {\n\n    /// Authentication keys required for LinkedIn authentication.\n    enum AuthenticationKeys: String, Codable {\n        case id\n        case accessToken = \"access_token\"\n        case isMobileSDK = \"is_mobile_sdk\"\n\n        /// Properly makes an authData dictionary with the required keys.\n        /// - parameter id: Required id for the user.\n        /// - parameter accessToken: Required identity token for LinkedIn.\n        /// - returns: authData dictionary.\n        func makeDictionary(id: String,\n                            accessToken: String,\n                            isMobileSDK: Bool) -> [String: String] {\n\n            let returnDictionary = [\n                AuthenticationKeys.id.rawValue: id,\n                AuthenticationKeys.accessToken.rawValue: accessToken,\n                AuthenticationKeys.isMobileSDK.rawValue: \"\\(isMobileSDK)\"\n            ]\n            return returnDictionary\n        }\n\n        /// Verifies all mandatory keys are in authData.\n        /// - parameter authData: Dictionary containing key/values.\n        /// - returns: **true** if all the mandatory keys are present, **false** otherwise.\n        func verifyMandatoryKeys(authData: [String: String]) -> Bool {\n            guard authData[AuthenticationKeys.id.rawValue] != nil,\n                  authData[AuthenticationKeys.accessToken.rawValue] != nil,\n                  authData[AuthenticationKeys.isMobileSDK.rawValue] != nil else {\n                return false\n            }\n            return true\n        }\n    }\n\n    public static var __type: String { // swiftlint:disable:this identifier_name\n        \"linkedin\"\n    }\n\n    public init() { }\n}\n\n// MARK: Login\npublic extension ParseLinkedIn {\n\n    /**\n     Login a `ParseUser` *asynchronously* using LinkedIn authentication for graph API login.\n     - parameter id: The `LinkedIn id` from **LinkedIn**.\n     - parameter accessToken: Required **access_token** from **LinkedIn**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func login(id: String,\n               accessToken: String,\n               isMobileSDK: Bool,\n               options: API.Options = [],\n               callbackQueue: DispatchQueue = .main,\n               completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n\n        let linkedinAuthData = AuthenticationKeys.id\n                .makeDictionary(id: id,\n                                accessToken: accessToken,\n                                isMobileSDK: isMobileSDK)\n        login(authData: linkedinAuthData,\n              options: options,\n              callbackQueue: callbackQueue,\n              completion: completion)\n    }\n\n    func login(authData: [String: String],\n               options: API.Options = [],\n               callbackQueue: DispatchQueue = .main,\n               completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        guard AuthenticationKeys.id.verifyMandatoryKeys(authData: authData) else {\n            callbackQueue.async {\n                completion(.failure(.init(code: .unknownError,\n                                          message: \"Should have authData in consisting of keys \\\"id\\\", \\\"accessToken\\\", and \\\"isMobileSDK\\\".\")))\n            }\n            return\n        }\n        AuthenticatedUser.login(Self.__type,\n                                authData: authData,\n                                options: options,\n                                callbackQueue: callbackQueue,\n                                completion: completion)\n    }\n}\n\n// MARK: Link\npublic extension ParseLinkedIn {\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using LinkedIn authentication for graph API login.\n     - parameter id: The **id** from **LinkedIn**.\n     - parameter accessToken: Required **access_token** from **LinkedIn**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func link(id: String,\n              accessToken: String,\n              isMobileSDK: Bool,\n              options: API.Options = [],\n              callbackQueue: DispatchQueue = .main,\n              completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        let linkedinAuthData = AuthenticationKeys.id\n            .makeDictionary(id: id,\n                            accessToken: accessToken,\n                            isMobileSDK: isMobileSDK)\n        link(authData: linkedinAuthData,\n             options: options,\n             callbackQueue: callbackQueue,\n             completion: completion)\n    }\n\n    func link(authData: [String: String],\n              options: API.Options = [],\n              callbackQueue: DispatchQueue = .main,\n              completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        guard AuthenticationKeys.id.verifyMandatoryKeys(authData: authData) else {\n            callbackQueue.async {\n                completion(.failure(.init(code: .unknownError,\n                                          message: \"Should have authData in consisting of keys \\\"id\\\", \\\"accessToken\\\", and \\\"isMobileSDK\\\".\")))\n            }\n            return\n        }\n        AuthenticatedUser.link(Self.__type,\n                               authData: authData,\n                               options: options,\n                               callbackQueue: callbackQueue,\n                               completion: completion)\n    }\n}\n\n// MARK: 3rd Party Authentication - ParseLinkedIn\npublic extension ParseUser {\n\n    /// A linkedin `ParseUser`.\n    static var linkedin: ParseLinkedIn<Self> {\n        ParseLinkedIn<Self>()\n    }\n\n    /// An linkedin `ParseUser`.\n    var linkedin: ParseLinkedIn<Self> {\n        Self.linkedin\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseSpotify/ParseSpotify+async.swift",
    "content": "//\n//  ParseSpotify+async.swift\n//  ParseSwift\n//\n//  Created by Ulaş Sancak on 06/20/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n\npublic extension ParseSpotify {\n    // MARK: Async/Await\n\n    /**\n     Login a `ParseUser` *asynchronously* using Spotify authentication.\n     - parameter id: The **Spotify profile id** from **Spotify**.\n     - parameter accessToken: Required **access_token** from **Spotify**.\n     - parameter expiresIn: Optional **expires_in** in seconds from **Spotify**.\n     - parameter refreshToken: Optional **refresh_token** from **Spotify**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func login(id: String,\n               accessToken: String,\n               expiresIn: Int? = nil,\n               refreshToken: String? = nil,\n               options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.login(id: id,\n                       accessToken: accessToken,\n                       expiresIn: expiresIn,\n                       refreshToken: refreshToken,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using Spotify authentication.\n     - parameter authData: Dictionary containing key/values.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func login(authData: [String: String],\n               options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.login(authData: authData,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n}\n\npublic extension ParseSpotify {\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Spotify authentication.\n     - parameter id: The **Spotify profile id** from **Spotify**.\n     - parameter accessToken: Required **access_token** from **Spotify**.\n     - parameter expiresIn: Optional **expires_in** in seconds from **Spotify**.\n     - parameter refreshToken: Optional **refresh_token** from **Spotify**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func link(id: String,\n              accessToken: String,\n              expiresIn: Int? = nil,\n              refreshToken: String? = nil,\n              options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.link(id: id,\n                      accessToken: accessToken,\n                      expiresIn: expiresIn,\n                      refreshToken: refreshToken,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Spotify authentication.\n     - parameter authData: Dictionary containing key/values.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func link(authData: [String: String],\n              options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.link(authData: authData,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseSpotify/ParseSpotify+combine.swift",
    "content": "//\n//  ParseSpotify+combine.swift\n//  ParseSwift\n//\n//  Created by Ulaş Sancak on 06/20/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\npublic extension ParseSpotify {\n    // MARK: Combine\n    /**\n     Login a `ParseUser` *asynchronously* using Spotify authentication. Publishes when complete.\n     - parameter id: The **Spotify profile id** from **Spotify**.\n     - parameter accessToken: Required **access_token** from **Spotify**.\n     - parameter expiresIn: Optional **expires_in** in seconds from **Spotify**.\n     - parameter refreshToken: Optional **refresh_token** from **Spotify**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func loginPublisher(id: String,\n                        accessToken: String,\n                        expiresIn: Int? = nil,\n                        refreshToken: String? = nil,\n                        options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.login(id: id,\n                       accessToken: accessToken,\n                       expiresIn: expiresIn,\n                       refreshToken: refreshToken,\n                       options: options,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using Spotify authentication. Publishes when complete.\n     - parameter authData: Dictionary containing key/values.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func loginPublisher(authData: [String: String],\n                        options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.login(authData: authData,\n                       options: options,\n                       completion: promise)\n        }\n    }\n}\n\npublic extension ParseSpotify {\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Spotify authentication.\n     Publishes when complete.\n     - parameter id: The **Spotify profile id** from **Spotify**.\n     - parameter accessToken: Required **access_token** from **Spotify**.\n     - parameter expiresIn: Optional **expires_in** in seconds from **Spotify**.\n     - parameter refreshToken: Optional **refresh_token** from **Spotify**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func linkPublisher(id: String,\n                       accessToken: String,\n                       expiresIn: Int? = nil,\n                       refreshToken: String? = nil,\n                       options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.link(id: id,\n                      accessToken: accessToken,\n                      expiresIn: expiresIn,\n                      refreshToken: refreshToken,\n                      options: options,\n                      completion: promise)\n        }\n    }\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Spotify authentication.\n     Publishes when complete.\n     - parameter authData: Dictionary containing key/values.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func linkPublisher(authData: [String: String],\n                       options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.link(authData: authData,\n                      options: options,\n                      completion: promise)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseSpotify/ParseSpotify.swift",
    "content": "//\n//  ParseSpotify.swift\n//  ParseSwift\n//\n//  Created by Ulaş Sancak on 06/20/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n// swiftlint:disable line_length\n\n/**\n Provides utility functions for working with Spotify User Authentication and `ParseUser`'s.\n Be sure your Parse Server is configured for [sign in with Spotify](https://docs.parseplatform.org/parse-server/guide/#spotify-authdata)\n For information on acquiring Spotify sign-in credentials to use with `ParseSpotify`, refer to [Spotify's Documentation](https://developer.spotify.com/documentation/general/guides/authorization/)\n */\npublic struct ParseSpotify<AuthenticatedUser: ParseUser>: ParseAuthentication {\n\n    /// Authentication keys required for Spotify authentication.\n    enum AuthenticationKeys: String, Codable {\n        case id\n        case accessToken = \"access_token\"\n        case expirationDate = \"expiration_date\"\n        case refreshToken = \"refresh_token\"\n        /// Properly makes an authData dictionary with the required keys.\n        /// - parameter id: Required id for the user.\n        /// - parameter accessToken: Required access token for Spotify.\n        /// - parameter expiresIn: Optional expiration in seconds for Spotify.\n        /// - parameter refreshToken: Optional refresh token for Spotify.\n        /// - returns: authData dictionary.\n        func makeDictionary(id: String,\n                            accessToken: String,\n                            expiresIn: Int? = nil,\n                            refreshToken: String? = nil) -> [String: String] {\n\n            var returnDictionary = [\n                AuthenticationKeys.id.rawValue: id,\n                AuthenticationKeys.accessToken.rawValue: accessToken\n            ]\n            if let expiresIn = expiresIn,\n                let expirationDate = Calendar.current.date(byAdding: .second,\n                                                             value: expiresIn,\n                                                             to: Date()) {\n                let dateString = ParseCoding.dateFormatter.string(from: expirationDate)\n                returnDictionary[AuthenticationKeys.expirationDate.rawValue] = dateString\n            }\n            if let refreshToken = refreshToken {\n                returnDictionary[AuthenticationKeys.refreshToken.rawValue] = refreshToken\n            }\n            return returnDictionary\n        }\n\n        /// Verifies all mandatory keys are in authData.\n        /// - parameter authData: Dictionary containing key/values.\n        /// - returns: **true** if all the mandatory keys are present, **false** otherwise.\n        func verifyMandatoryKeys(authData: [String: String]) -> Bool {\n            guard authData[AuthenticationKeys.id.rawValue] != nil,\n                  authData[AuthenticationKeys.accessToken.rawValue] != nil else {\n                return false\n            }\n            return true\n        }\n    }\n\n    public static var __type: String { // swiftlint:disable:this identifier_name\n        \"spotify\"\n    }\n\n    public init() { }\n}\n\n// MARK: Login\npublic extension ParseSpotify {\n\n    /**\n     Login a `ParseUser` *asynchronously* using Spotify authentication.\n     - parameter id: The **Spotify profile id** from **Spotify**.\n     - parameter accessToken: Required **access_token** from **Spotify**.\n     - parameter expiresIn: Optional **expires_in** in seconds from **Spotify**.\n     - parameter refreshToken: Optional **refresh_token** from **Spotify**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func login(id: String,\n               accessToken: String,\n               expiresIn: Int? = nil,\n               refreshToken: String? = nil,\n               options: API.Options = [],\n               callbackQueue: DispatchQueue = .main,\n               completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n\n        let spotifyAuthData = AuthenticationKeys.id\n                .makeDictionary(id: id,\n                                accessToken: accessToken,\n                                expiresIn: expiresIn,\n                                refreshToken: refreshToken)\n        login(authData: spotifyAuthData,\n              options: options,\n              callbackQueue: callbackQueue,\n              completion: completion)\n    }\n\n    func login(authData: [String: String],\n               options: API.Options = [],\n               callbackQueue: DispatchQueue = .main,\n               completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        guard AuthenticationKeys.id.verifyMandatoryKeys(authData: authData) else {\n            callbackQueue.async {\n                completion(.failure(.init(code: .unknownError,\n                                          message: \"Should have authData in consisting of keys \\\"id\\\" and \\\"accessToken\\\".\")))\n            }\n            return\n        }\n        AuthenticatedUser.login(Self.__type,\n                                authData: authData,\n                                options: options,\n                                callbackQueue: callbackQueue,\n                                completion: completion)\n    }\n}\n\n// MARK: Link\npublic extension ParseSpotify {\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Spotify authentication.\n     - parameter id: The **Spotify profile id** from **Spotify**.\n     - parameter accessToken: Required **access_token** from **Spotify**.\n     - parameter expiresIn: Optional **expires_in** in seconds from **Spotify**.\n     - parameter refreshToken: Optional **refresh_token** from **Spotify**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func link(id: String,\n              accessToken: String,\n              expiresIn: Int? = nil,\n              refreshToken: String? = nil,\n              options: API.Options = [],\n              callbackQueue: DispatchQueue = .main,\n              completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        let spotifyAuthData = AuthenticationKeys.id\n            .makeDictionary(id: id,\n                            accessToken: accessToken,\n                            expiresIn: expiresIn,\n                            refreshToken: refreshToken)\n        link(authData: spotifyAuthData,\n             options: options,\n             callbackQueue: callbackQueue,\n             completion: completion)\n    }\n\n    func link(authData: [String: String],\n              options: API.Options = [],\n              callbackQueue: DispatchQueue = .main,\n              completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        guard AuthenticationKeys.id.verifyMandatoryKeys(authData: authData) else {\n            callbackQueue.async {\n                completion(.failure(.init(code: .unknownError,\n                                          message: \"Should have authData in consisting of keys \\\"id\\\" and \\\"accessToken\\\".\")))\n            }\n            return\n        }\n        AuthenticatedUser.link(Self.__type,\n                               authData: authData,\n                               options: options,\n                               callbackQueue: callbackQueue,\n                               completion: completion)\n    }\n}\n\n// MARK: 3rd Party Authentication - ParseSpotify\npublic extension ParseUser {\n\n    /// A Spotify `ParseUser`.\n    static var spotify: ParseSpotify<Self> {\n        ParseSpotify<Self>()\n    }\n\n    /// An Spotify `ParseUser`.\n    var spotify: ParseSpotify<Self> {\n        Self.spotify\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseTwitter/ParseTwitter+async.swift",
    "content": "//\n//  ParseTwitter+async.swift\n//  ParseTwitter+async\n//\n//  Created by Corey Baker on 8/7/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n\npublic extension ParseTwitter {\n    // MARK: Async/Await\n\n    /**\n     Login a `ParseUser` *asynchronously* using Twitter authentication.\n     - parameter user: The **id** from **Twitter**.\n     - parameter screenName: The `user screenName` from **Twitter**.\n     - parameter consumerKey: The `consumerKey` from **Twitter**.\n     - parameter consumerSecret: The `consumerSecret` from **Twitter**.\n     - parameter authToken: The Twitter `authToken` obtained from Twitter.\n     - parameter authTokenSecret: The Twitter `authSecretToken` obtained from Twitter.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func login(userId: String,\n               screenName: String? = nil,\n               consumerKey: String,\n               consumerSecret: String,\n               authToken: String,\n               authTokenSecret: String,\n               options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.login(userId: userId,\n                       screenName: screenName,\n                       authToken: consumerKey,\n                       authTokenSecret: consumerSecret,\n                       consumerKey: authToken,\n                       consumerSecret: authTokenSecret,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using Twitter authentication.\n     - parameter authData: Dictionary containing key/values.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func login(authData: [String: String],\n               options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.login(authData: authData,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n}\n\npublic extension ParseTwitter {\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Twitter authentication.\n     - parameter user: The `user` from **Twitter**.\n     - parameter screenName: The `user screenName` from **Twitter**.\n     - parameter consumerKey: The `consumerKey` from **Twitter**.\n     - parameter consumerSecret: The `consumerSecret` from **Twitter**.\n     - parameter authToken: The Twitter `authToken` obtained from Twitter.\n     - parameter authTokenSecret: The Twitter `authSecretToken` obtained from Twitter.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func link(userId: String,\n              screenName: String? = nil,\n              consumerKey: String,\n              consumerSecret: String,\n              authToken: String,\n              authTokenSecret: String,\n              options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.link(userId: userId,\n                      screenName: screenName,\n                      consumerKey: consumerKey,\n                      consumerSecret: consumerSecret,\n                      authToken: authToken,\n                      authTokenSecret: authTokenSecret,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Twitter authentication.\n     - parameter authData: Dictionary containing key/values.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func link(authData: [String: String],\n              options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.link(authData: authData,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseTwitter/ParseTwitter+combine.swift",
    "content": "//\n//  ParseTwitter+combine.swift\n//  ParseTwitter+combine\n//\n//  Created by Corey Baker on 8/7/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\npublic extension ParseTwitter {\n    // MARK: Combine\n\n    /**\n     Login a `ParseUser` *asynchronously* using Twitter authentication. Publishes when complete.\n     - parameter user: The **id** from **Twitter**.\n     - parameter screenName: The `user screenName` from **Twitter**.\n     - parameter consumerKey: The `consumerKey` from **Twitter**.\n     - parameter consumerSecret: The `consumerSecret` from **Twitter**.\n     - parameter authToken: The Twitter `authToken` obtained from Twitter.\n     - parameter authTokenSecret: The Twitter `authSecretToken` obtained from Twitter.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func loginPublisher(userId: String,\n                        screenName: String? = nil,\n                        consumerKey: String,\n                        consumerSecret: String,\n                        authToken: String,\n                        authTokenSecret: String,\n                        options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.login(userId: userId,\n                       screenName: screenName,\n                       authToken: consumerKey,\n                       authTokenSecret: consumerSecret,\n                       consumerKey: authToken,\n                       consumerSecret: authTokenSecret,\n                       options: options,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using Twitter authentication. Publishes when complete.\n     - parameter authData: Dictionary containing key/values.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func loginPublisher(authData: [String: String],\n                        options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.login(authData: authData,\n                       options: options,\n                       completion: promise)\n        }\n    }\n}\n\npublic extension ParseTwitter {\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Twitter authentication. Publishes when complete.\n     - parameter user: The `user` from **Twitter**.\n     - parameter screenName: The `user screenName` from **Twitter**.\n     - parameter consumerKey: The `consumerKey` from **Twitter**.\n     - parameter consumerSecret: The `consumerSecret` from **Twitter**.\n     - parameter authToken: The Twitter `authToken` obtained from Twitter.\n     - parameter authTokenSecret: The Twitter `authSecretToken` obtained from Twitter.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func linkPublisher(userId: String,\n                       screenName: String? = nil,\n                       consumerKey: String,\n                       consumerSecret: String,\n                       authToken: String,\n                       authTokenSecret: String,\n                       options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.link(userId: userId,\n                      screenName: screenName,\n                      consumerKey: consumerKey,\n                      consumerSecret: consumerSecret,\n                      authToken: authToken,\n                      authTokenSecret: authTokenSecret,\n                      options: options,\n                      completion: promise)\n        }\n    }\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Twitter authentication. Publishes when complete.\n     - parameter authData: Dictionary containing key/values.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func linkPublisher(authData: [String: String],\n                       options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.link(authData: authData,\n                      options: options,\n                      completion: promise)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/3rd Party/ParseTwitter/ParseTwitter.swift",
    "content": "//\n//  ParseTwitter.swift\n//  ParseSwift\n//\n//  Created by Abdulaziz Alhomaidhi on 3/17/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n// swiftlint:disable line_length\n// swiftlint:disable function_parameter_count\n\n/**\n Provides utility functions for working with Twitter User Authentication and `ParseUser`'s.\n Be sure your Parse Server is configured for [sign in with Twitter](https://docs.parseplatform.org/parse-server/guide/#twitter-authdata).\n For information on acquiring Twitter sign-in credentials to use with `ParseTwitter`, refer to [Twitter's Documentation](https://developer.twitter.com/en/docs/authentication/guides/log-in-with-twitter).\n */\npublic struct ParseTwitter<AuthenticatedUser: ParseUser>: ParseAuthentication {\n\n    /// Authentication keys required for Twitter authentication.\n    enum AuthenticationKeys: String, Codable {\n        case id\n        case consumerKey = \"consumer_key\"\n        case consumerSecret = \"consumer_secret\"\n        case authToken = \"auth_token\"\n        case authTokenSecret = \"auth_token_secret\"\n        case screenName  = \"screen_name\"\n\n        /// Properly makes an authData dictionary with the required keys.\n        /// - parameter userId: Required id.\n        /// - parameter screenName: The `Twitter screenName` from **Twitter**.\n        /// - parameter consumerKey: The `Twitter consumerKey` from **Twitter**.\n        /// - parameter consumerSecret: The `Twitter consumerSecret` from **Twitter**.\n        /// - parameter authToken: Required Twitter authToken obtained from Twitter.\n        /// - parameter authTokenSecret: Required Twitter authSecretToken obtained from Twitter.\n        /// - returns: authData dictionary.\n        func makeDictionary(userId: String,\n                            screenName: String?,\n                            consumerKey: String,\n                            consumerSecret: String,\n                            authToken: String,\n                            authTokenSecret: String) -> [String: String] {\n            var dictionary = [AuthenticationKeys.id.rawValue: userId,\n                              AuthenticationKeys.consumerKey.rawValue: consumerKey,\n                              AuthenticationKeys.consumerSecret.rawValue: consumerSecret,\n                              AuthenticationKeys.authToken.rawValue: authToken,\n                              AuthenticationKeys.authTokenSecret.rawValue: authTokenSecret]\n            if let screenName = screenName {\n                dictionary[AuthenticationKeys.screenName.rawValue] = screenName\n            }\n            return dictionary\n        }\n\n        /// Verifies all mandatory keys are in authData.\n        /// - parameter authData: Dictionary containing key/values.\n        /// - returns: **true** if all the mandatory keys are present, **false** otherwise.\n        func verifyMandatoryKeys(authData: [String: String]) -> Bool {\n            guard authData[AuthenticationKeys.id.rawValue] != nil,\n                  authData[AuthenticationKeys.consumerKey.rawValue] != nil,\n                  authData[AuthenticationKeys.consumerSecret.rawValue] != nil,\n                  authData[AuthenticationKeys.authToken.rawValue] != nil,\n                  authData[AuthenticationKeys.authTokenSecret.rawValue] != nil else {\n                return false\n            }\n            return true\n        }\n    }\n\n    public static var __type: String { // swiftlint:disable:this identifier_name\n        \"twitter\"\n    }\n\n    public init() { }\n}\n\n// MARK: Login\npublic extension ParseTwitter {\n    /**\n     Login a `ParseUser` *asynchronously* using Twitter authentication.\n     - parameter userId: The `Twitter userId` from **Twitter**.\n     - parameter screenName: The `Twitter screenName` from **Twitter**.\n     - parameter consumerKey: The `Twitter consumerKey` from **Twitter**.\n     - parameter consumerSecret: The `Twitter consumerSecret` from **Twitter**.\n     - parameter authToken: The Twitter `authToken` obtained from Twitter.\n     - parameter authTokenSecret: The Twitter `authSecretToken` obtained from Twitter.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func login(userId: String,\n               screenName: String? = nil,\n               authToken: String,\n               authTokenSecret: String,\n               consumerKey: String,\n               consumerSecret: String,\n               options: API.Options = [],\n               callbackQueue: DispatchQueue = .main,\n               completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n\n        let twitterAuthData = AuthenticationKeys.id\n            .makeDictionary(userId: userId,\n                            screenName: screenName,\n                            consumerKey: consumerKey,\n                            consumerSecret: consumerSecret,\n                            authToken: authToken,\n                            authTokenSecret: authTokenSecret)\n        login(authData: twitterAuthData,\n              options: options,\n              callbackQueue: callbackQueue,\n              completion: completion)\n    }\n\n    func login(authData: [String: String],\n               options: API.Options = [],\n               callbackQueue: DispatchQueue = .main,\n               completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        guard AuthenticationKeys.id.verifyMandatoryKeys(authData: authData) else {\n            callbackQueue.async {\n                completion(.failure(.init(code: .unknownError,\n                                          message:\n                                           \"\"\"\n                                           Should have authData consisting of keys \\\"id,\\\"\n                                           \\\"screenName,\\\" \\\"consumerKey,\\\" \\\"consumerSecret,\\\"\n                                           \\\"authToken,\\\" and \\\"authTokenSecret\\\".\n                                           \"\"\")))\n            }\n            return\n        }\n        AuthenticatedUser.login(Self.__type,\n                                authData: authData,\n                                options: options,\n                                callbackQueue: callbackQueue,\n                                completion: completion)\n    }\n}\n\n// MARK: Link\npublic extension ParseTwitter {\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using Twitter authentication.\n     - parameter user: The **id** from **Twitter**.\n     - parameter screenName: The `user screenName` from **Twitter**.\n     - parameter consumerKey: The `consumerKey` from **Twitter**.\n     - parameter consumerSecret: The `consumerSecret` from **Twitter**.\n     - parameter authToken: The Twitter `authToken` obtained from Twitter.\n     - parameter authTokenSecret: The Twitter `authSecretToken` obtained from Twitter.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter completion: The block to execute.\n     */\n    func link(userId: String,\n              screenName: String? = nil,\n              consumerKey: String,\n              consumerSecret: String,\n              authToken: String,\n              authTokenSecret: String,\n              options: API.Options = [],\n              callbackQueue: DispatchQueue = .main,\n              completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        let twitterAuthData = AuthenticationKeys.id\n            .makeDictionary(userId: userId,\n                            screenName: screenName,\n                            consumerKey: consumerKey,\n                            consumerSecret: consumerKey,\n                            authToken: authToken,\n                            authTokenSecret: authTokenSecret)\n        link(authData: twitterAuthData,\n             options: options,\n             callbackQueue: callbackQueue,\n             completion: completion)\n    }\n\n    func link(authData: [String: String],\n              options: API.Options = [],\n              callbackQueue: DispatchQueue = .main,\n              completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        guard AuthenticationKeys.id.verifyMandatoryKeys(authData: authData) else {\n            let error = ParseError(code: .unknownError,\n                                   message:\n                                    \"\"\"\n                                    Should have authData consisting of keys \\\"id,\\\"\n                                    \\\"screenName,\\\" \\\"consumerKey,\\\" \\\"consumerSecret,\\\"\n                                    \\\"authToken,\\\" and \\\"authTokenSecret\\\".\n                                    \"\"\")\n            callbackQueue.async {\n                completion(.failure(error))\n            }\n            return\n        }\n        AuthenticatedUser.link(Self.__type,\n                               authData: authData,\n                               options: options,\n                               callbackQueue: callbackQueue,\n                               completion: completion)\n    }\n}\n\n// MARK: 3rd Party Authentication - ParseTwitter\npublic extension ParseUser {\n\n    /// A twitter `ParseUser`.\n    static var twitter: ParseTwitter<Self> {\n        ParseTwitter<Self>()\n    }\n\n    /// A twitter`ParseUser`.\n    var twitter: ParseTwitter<Self> {\n        Self.twitter\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/Internal/ParseAnonymous+async.swift",
    "content": "//\n//  ParseAnonymous+async.swift\n//  ParseAnonymous+async\n//\n//  Created by Corey Baker on 8/7/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n\npublic extension ParseAnonymous {\n\n    // MARK: Async/Await\n    /**\n     Login a `ParseUser` *asynchronously* using the respective authentication type.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func login(options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.login(options: options,\n                       completion: continuation.resume)\n        }\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using the respective authentication type.\n     - parameter authData: The authData for the respective authentication type. This will be ignored.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     */\n    func login(authData: [String: String],\n               options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.login(authData: authData,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n}\n\npublic extension ParseAnonymous {\n\n    func link(authData: [String: String],\n              options: API.Options = []) async throws -> AuthenticatedUser {\n        try await withCheckedThrowingContinuation { continuation in\n            self.link(authData: authData,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/Internal/ParseAnonymous+combine.swift",
    "content": "//\n//  ParseAnonymous+combine.swift\n//  ParseAnonymous+combine\n//\n//  Created by Corey Baker on 8/7/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\npublic extension ParseAnonymous {\n\n    // MARK: Login - Combine\n    /**\n     Login a `ParseUser` *asynchronously* using the respective authentication type.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func loginPublisher(options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.login(options: options,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using the respective authentication type.\n     - parameter authData: The authData for the respective authentication type. This will be ignored.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func loginPublisher(authData: [String: String],\n                        options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.login(authData: authData,\n                       options: options,\n                       completion: promise)\n        }\n    }\n}\n\npublic extension ParseAnonymous {\n\n    func linkPublisher(authData: [String: String],\n                       options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        Future { promise in\n            self.link(authData: authData,\n                      options: options,\n                      completion: promise)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/Internal/ParseAnonymous.swift",
    "content": "//\n//  ParseAnonymous.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/14/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n Provides utility functions for working with Anonymously logged-in users.\n \n Anonymous users have some unique characteristics:\n - Anonymous users do not need a user name or password.\n - Once logged out, an anonymous user cannot be recovered.\n - When the current user is anonymous, the following methods can be used to switch\n to a different user or convert the anonymous user into a regular one:\n    - *signup* converts an anonymous user to a standard user with the given username and password.\n Data associated with the anonymous user is retained.\n    - *login* switches users without converting the anonymous user.\n Data associated with the anonymous user will be lost.\n    - Service *login* (e.g. Apple, Facebook, Twitter) will attempt to convert\n the anonymous user into a standard user by linking it to the service.\n If a user already exists that is linked to the service, it will instead switch to the existing user.\n    - Service linking (e.g. Apple, Facebook, Twitter) will convert the anonymous user\n into a standard user by linking it to the service.\n */\npublic struct ParseAnonymous<AuthenticatedUser: ParseUser>: ParseAuthentication {\n\n    enum AuthenticationKeys: String, Codable {\n        case id\n\n        func makeDictionary() -> [String: String] {\n            [AuthenticationKeys.id.rawValue: UUID().uuidString.lowercased()]\n        }\n    }\n\n    public static var __type: String { // swiftlint:disable:this identifier_name\n        \"anonymous\"\n    }\n\n    public init() { }\n}\n\n// MARK: Login\npublic extension ParseAnonymous {\n\n    /**\n     Login a `ParseUser` *synchronously* using the respective authentication type.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n     - returns: the linked `ParseUser`.\n     */\n    func login(options: API.Options = []) throws -> AuthenticatedUser {\n        try self.login(authData: AuthenticationKeys.id.makeDictionary(),\n                       options: options)\n    }\n\n    /**\n     Login a `ParseUser` *synchronously* using the respective authentication type.\n     - parameter authData: The authData for the respective authentication type. This will be ignored.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n     - returns: the linked `ParseUser`.\n     */\n    func login(authData: [String: String],\n               options: API.Options = []) throws -> AuthenticatedUser {\n        try AuthenticatedUser.login(__type,\n                                    authData: authData,\n                                    options: options)\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using the respective authentication type.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func login(options: API.Options = [],\n               callbackQueue: DispatchQueue = .main,\n               completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        self.login(authData: AuthenticationKeys.id.makeDictionary(),\n                   options: options,\n                   callbackQueue: callbackQueue,\n                   completion: completion)\n    }\n\n    /**\n     Login a `ParseUser` *asynchronously* using the respective authentication type.\n     - parameter authData: The authData for the respective authentication type. This will be ignored.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func login(authData: [String: String],\n               options: API.Options = [],\n               callbackQueue: DispatchQueue = .main,\n               completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        AuthenticatedUser.login(__type,\n                                authData: authData,\n                                options: options,\n                                callbackQueue: callbackQueue,\n                                completion: completion)\n    }\n}\n\n// MARK: Link\npublic extension ParseAnonymous {\n    /// Unavailable for `ParseAnonymous`. Will always return an error.\n    func link(authData: [String: String],\n              options: API.Options = [],\n              callbackQueue: DispatchQueue = .main,\n              completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        callbackQueue.async {\n            completion(.failure(ParseError(code: .unknownError, message: \"Not supported\")))\n        }\n    }\n}\n\n// MARK: ParseAnonymous\npublic extension ParseUser {\n\n    /// An anonymous `ParseUser`.\n    static var anonymous: ParseAnonymous<Self> {\n        ParseAnonymous<Self>()\n    }\n\n    /// An anonymous `ParseUser`.\n    var anonymous: ParseAnonymous<Self> {\n        Self.anonymous\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/Protocols/ParseAuthentication+async.swift",
    "content": "//\n//  ParseAuthentication+async.swift\n//  ParseAuthentication+async\n//\n//  Created by Corey Baker on 8/7/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n\npublic extension ParseAuthentication {\n\n    // MARK: Convenience Implementations - Async/Await\n\n    func unlink(_ user: AuthenticatedUser,\n                options: API.Options = []) async throws -> AuthenticatedUser {\n        try await user.unlink(__type, options: options)\n    }\n\n    func unlink(options: API.Options = []) async throws -> AuthenticatedUser {\n        guard let current = AuthenticatedUser.current else {\n            let error = ParseError(code: .invalidLinkedSession, message: \"No current ParseUser.\")\n            return try await withCheckedThrowingContinuation { continuation in\n                continuation.resume(with: .failure(error))\n            }\n        }\n        return try await unlink(current, options: options)\n    }\n}\n\npublic extension ParseUser {\n\n    // MARK: 3rd Party Authentication - Login Async/Await\n\n    /**\n     Makes an *asynchronous* request to log in a user with specified credentials.\n     Returns an instance of the successfully logged in `ParseUser`.\n\n     This also caches the user locally so that calls to *current* will use the latest logged in user.\n     - parameter type: The authentication type.\n     - parameter authData: The data that represents the authentication.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     */\n    static func login(_ type: String,\n                      authData: [String: String],\n                      options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            Self.login(type,\n                       authData: authData,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n\n    /**\n     Unlink the authentication type *asynchronously*.\n     - parameter type: The type to unlink. The user must be logged in on this device.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n     */\n    func unlink(_ type: String,\n                options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.unlink(type,\n                        options: options,\n                        completion: continuation.resume)\n        }\n    }\n\n    /**\n     Makes an *asynchronous* request to link a user with specified credentials. The user should already be logged in.\n     Returns an instance of the successfully linked `ParseUser`.\n\n     This also caches the user locally so that calls to *current* will use the latest logged in user.\n     - parameter type: The authentication type.\n     - parameter authData: The data that represents the authentication.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An instance of the logged in `ParseUser`.\n    */\n    static func link(_ type: String,\n                     authData: [String: String],\n                     options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            Self.link(type,\n                      authData: authData,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/Protocols/ParseAuthentication+combine.swift",
    "content": "//\n//  ParseAuthentication+combine.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/30/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\npublic extension ParseAuthentication {\n\n    // MARK: Convenience Implementations - Combine\n\n    func unlinkPublisher(_ user: AuthenticatedUser,\n                         options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        user.unlinkPublisher(__type, options: options)\n    }\n\n    func unlinkPublisher(options: API.Options = []) -> Future<AuthenticatedUser, ParseError> {\n        guard let current = AuthenticatedUser.current else {\n            let error = ParseError(code: .invalidLinkedSession, message: \"No current ParseUser.\")\n            return Future { promise in\n                promise(.failure(error))\n            }\n        }\n        return unlinkPublisher(current, options: options)\n    }\n}\n\npublic extension ParseUser {\n\n    // MARK: 3rd Party Authentication - Login Combine\n\n    /**\n     Makes an *asynchronous* request to log in a user with specified credentials.\n     Publishes an instance of the successfully logged in `ParseUser`.\n\n     This also caches the user locally so that calls to *current* will use the latest logged in user.\n     - parameter type: The authentication type.\n     - parameter authData: The data that represents the authentication.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    static func loginPublisher(_ type: String,\n                               authData: [String: String],\n                               options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            Self.login(type,\n                       authData: authData,\n                       options: options,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Unlink the authentication type *asynchronously*. Publishes when complete.\n     - parameter type: The type to unlink. The user must be logged in on this device.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func unlinkPublisher(_ type: String,\n                         options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.unlink(type,\n                        options: options,\n                        completion: promise)\n        }\n    }\n\n    /**\n     Makes an *asynchronous* request to link a user with specified credentials. The user should already be logged in.\n     Publishes an instance of the successfully linked `ParseUser`.\n\n     This also caches the user locally so that calls to *current* will use the latest logged in user.\n     - parameter type: The authentication type.\n     - parameter authData: The data that represents the authentication.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n    */\n    static func linkPublisher(_ type: String,\n                              authData: [String: String],\n                              options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            Self.link(type,\n                      authData: authData,\n                      options: options,\n                      completion: promise)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Authentication/Protocols/ParseAuthentication.swift",
    "content": "//\n//  ParseAuthentication.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/14/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n#if canImport(Combine)\nimport Combine\n#endif\n\n// swiftlint:disable line_length\n\n/**\n Objects that conform to the `ParseAuthentication` protocol provide\n convenience implementations for using 3rd party authentication methods.\n The authentication methods supported by the Parse Server can be found\n [here](https://docs.parseplatform.org/parse-server/guide/#oauth-and-3rd-party-authentication).\n */\npublic protocol ParseAuthentication: Codable {\n    associatedtype AuthenticatedUser: ParseUser\n\n    /// The type of authentication.\n    static var __type: String { get } // swiftlint:disable:this identifier_name\n\n    /// Returns **true** if the *current* user is linked to the respective authentication type.\n    var isLinked: Bool { get }\n\n    /// The default initializer for this authentication type.\n    init()\n\n    /**\n     Login a `ParseUser` *asynchronously* using the respective authentication type.\n     - parameter authData: The authData for the respective authentication type.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func login(authData: [String: String],\n               options: API.Options,\n               callbackQueue: DispatchQueue,\n               completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void)\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using the respective authentication type.\n     - parameter authData: The authData for the respective authentication type.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func link(authData: [String: String],\n              options: API.Options,\n              callbackQueue: DispatchQueue,\n              completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void)\n\n    /**\n     Whether the `ParseUser` is logged in with the respective authentication type.\n     - parameter user: The `ParseUser` to check authentication type. The user must be logged in on this device.\n     - returns: **true** if the `ParseUser` is logged in via the repective\n     authentication type. **false** if the user is not.\n     */\n    func isLinked(with user: AuthenticatedUser) -> Bool\n\n    /**\n     Unlink the `ParseUser` *asynchronously* from the respective authentication type.\n     - parameter user: The `ParseUser` to unlink. The user must be logged in on this device.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     */\n    func unlink(_ user: AuthenticatedUser,\n                options: API.Options,\n                callbackQueue: DispatchQueue,\n                completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void)\n\n    /**\n     Unlink the *current* `ParseUser` *asynchronously* from the respective authentication type.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<AuthenticatedUser, ParseError>)`.\n     */\n    func unlink(options: API.Options,\n                callbackQueue: DispatchQueue,\n                completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void)\n\n    /**\n     Strips the *current* user of a respective authentication type.\n     */\n    func strip()\n\n    /**\n     Strips the `ParseUser`of a respective authentication type.\n     - parameter user: The `ParseUser` to strip. The user must be logged in on this device.\n     - returns: The user whose autentication type was stripped. This modified user has not been saved.\n     */\n    func strip(_ user: AuthenticatedUser) -> AuthenticatedUser\n\n    #if canImport(Combine)\n    // MARK: Combine\n    /**\n     Login a `ParseUser` *asynchronously* using the respective authentication type. Publishes when complete.\n     - parameter authData: The authData for the respective authentication type.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func loginPublisher(authData: [String: String],\n                        options: API.Options) -> Future<AuthenticatedUser, ParseError>\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using the respective authentication type. Publishes when complete.\n     - parameter authData: The authData for the respective authentication type.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     */\n    func linkPublisher(authData: [String: String],\n                       options: API.Options) -> Future<AuthenticatedUser, ParseError>\n\n    /**\n     Unlink the `ParseUser` *asynchronously* from the respective authentication type. Publishes when complete.\n     - parameter user: The `ParseUser` to unlink. The user must be logged in on this device.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     */\n    func unlinkPublisher(_ user: AuthenticatedUser,\n                         options: API.Options) -> Future<AuthenticatedUser, ParseError>\n\n    /**\n     Unlink the *current* `ParseUser` *asynchronously* from the respective authentication type. Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func unlinkPublisher(options: API.Options) -> Future<AuthenticatedUser, ParseError>\n    #endif\n\n    #if compiler(>=5.5.2) && canImport(_Concurrency)\n    // MARK: Async/Await\n\n    /**\n     Link the *current* `ParseUser` *asynchronously* using the respective authentication type.\n     - parameter authData: The authData for the respective authentication type.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter returns: An instance of the linked `AuthenticatedUser`.\n     */\n    func link(authData: [String: String],\n              options: API.Options) async throws -> AuthenticatedUser\n\n    /**\n     Unlink the `ParseUser` *asynchronously* from the respective authentication type.\n     - parameter user: The `ParseUser` to unlink. The user must be logged in on this device.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter returns: An instance of the unlinked `AuthenticatedUser`.\n     */\n    func unlink(_ user: AuthenticatedUser,\n                options: API.Options) async throws -> AuthenticatedUser\n\n    /**\n     Unlink the *current* `ParseUser` *asynchronously* from the respective authentication type.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter returns: An instance of the unlinked `AuthenticatedUser`.\n     */\n    func unlink(options: API.Options) async throws -> AuthenticatedUser\n    #endif\n}\n\n// MARK: Convenience Implementations\npublic extension ParseAuthentication {\n\n    var __type: String { // swiftlint:disable:this identifier_name\n        Self.__type\n    }\n\n    var isLinked: Bool {\n        guard let current = AuthenticatedUser.current else {\n            return false\n        }\n        return current.isLinked(with: __type)\n    }\n\n    func isLinked(with user: AuthenticatedUser) -> Bool {\n        user.isLinked(with: __type)\n    }\n\n    func unlink(_ user: AuthenticatedUser,\n                options: API.Options = [],\n                callbackQueue: DispatchQueue = .main,\n                completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        user.unlink(__type, options: options, callbackQueue: callbackQueue, completion: completion)\n    }\n\n    func unlink(options: API.Options = [],\n                callbackQueue: DispatchQueue = .main,\n                completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n        guard let current = AuthenticatedUser.current else {\n            let error = ParseError(code: .invalidLinkedSession, message: \"No current ParseUser.\")\n            callbackQueue.async {\n                completion(.failure(error))\n            }\n            return\n        }\n        unlink(current, options: options, callbackQueue: callbackQueue, completion: completion)\n    }\n\n    func strip() {\n        guard let user = AuthenticatedUser.current else {\n            return\n        }\n        AuthenticatedUser.current = strip(user)\n    }\n\n    func strip(_ user: AuthenticatedUser) -> AuthenticatedUser {\n        if isLinked(with: user) {\n            var user = user\n            user.authData?.updateValue(nil, forKey: __type)\n            return user\n        }\n        return user\n    }\n}\n\npublic extension ParseUser {\n\n    // MARK: 3rd Party Authentication - Login\n    /**\n     Makes a *synchronous* request to login a user with specified credentials.\n\n     Returns an instance of the successfully logged in `ParseUser`.\n     This also caches the user locally so that calls to *current* will use the latest logged in user.\n\n     - parameter type: The authentication type.\n     - parameter authData: The data that represents the authentication.\n     See [supported 3rd party authentications](https://docs.parseplatform.org/parse-server/guide/#supported-3rd-party-authentications) for more information.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n     - returns: An instance of the logged in `ParseUser`.\n     If login failed due to either an incorrect password or incorrect username, it throws a `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    static func login(_ type: String,\n                      authData: [String: String],\n                      options: API.Options) throws -> Self {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        if Self.current != nil {\n            return try Self.link(type, authData: authData, options: options)\n        } else {\n            let body = SignupLoginBody(authData: [type: authData])\n            return try signupCommand(body: body).execute(options: options)\n        }\n    }\n\n    /**\n     Makes an *asynchronous* request to log in a user with specified credentials.\n     Returns an instance of the successfully logged in `ParseUser`.\n\n     This also caches the user locally so that calls to *current* will use the latest logged in user.\n     - parameter type: The authentication type.\n     - parameter authData: The data that represents the authentication.\n     See [supported 3rd party authentications](https://docs.parseplatform.org/parse-server/guide/#supported-3rd-party-authentications) for more information.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n    */\n    static func login(_ type: String,\n                      authData: [String: String],\n                      options: API.Options,\n                      callbackQueue: DispatchQueue = .main,\n                      completion: @escaping (Result<Self, ParseError>) -> Void) {\n        if Self.current != nil {\n            Self.link(type, authData: authData,\n                      options: options,\n                      callbackQueue: callbackQueue,\n                      completion: completion)\n        } else {\n            let body = SignupLoginBody(authData: [type: authData])\n            do {\n                try signupCommand(body: body)\n                    .executeAsync(options: options,\n                                  callbackQueue: callbackQueue) { result in\n                        completion(result)\n                }\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n    }\n\n    // MARK: 3rd Party Authentication - Link\n    /**\n     Whether the `ParseUser` is logged in with the respective authentication string type.\n     - parameter type: The authentication type to check. The user must be logged in on this device.\n     - returns: **true** if the `ParseUser` is logged in via the repective\n     authentication type. **false** if the user is not.\n     */\n    func isLinked(with type: String) -> Bool {\n        guard let authData = self.authData?[type] else {\n            return false\n        }\n        return authData != nil\n    }\n\n    /**\n     Strips the *current* user of a respective authentication type.\n     - parameter type: The authentication type to strip.\n     - returns: The user whose autentication type was stripped.\n     */\n    func strip(_ type: String) -> Self {\n        var user = self\n        user.authData?.updateValue(nil, forKey: type)\n        return user\n    }\n\n    /**\n     Unlink the authentication type *asynchronously*.\n     - parameter type: The type to unlink. The user must be logged in on this device.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     */\n    func unlink(_ type: String,\n                options: API.Options = [],\n                callbackQueue: DispatchQueue = .main,\n                completion: @escaping (Result<Self, ParseError>) -> Void) {\n        guard let current = Self.current,\n              current.authData != nil else {\n            let error = ParseError(code: .unknownError, message: \"Must be logged in to unlink user\")\n            callbackQueue.async {\n                completion(.failure(error))\n            }\n            return\n        }\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        if current.isLinked(with: type) {\n            guard let authData = current.strip(type).authData else {\n                let error = ParseError(code: .unknownError, message: \"Missing authData.\")\n                callbackQueue.async {\n                    completion(.failure(error))\n                }\n                return\n            }\n            let body = SignupLoginBody(authData: authData)\n            current.linkCommand(body: body)\n                .executeAsync(options: options,\n                              callbackQueue: callbackQueue) { result in\n                    completion(result)\n                }\n        } else {\n            callbackQueue.async {\n                completion(.success(self))\n            }\n        }\n    }\n\n    /**\n     Makes a *synchronous* request to link a user with specified credentials. The user should already be logged in.\n\n     Returns an instance of the successfully linked `ParseUser`.\n     This also caches the user locally so that calls to *current* will use the latest logged in user.\n\n     - parameter type: The authentication type.\n     - parameter authData: The data that represents the authentication.\n     See [supported 3rd party authentications](https://docs.parseplatform.org/parse-server/guide/#supported-3rd-party-authentications) for more information.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n     - returns: An instance of the logged in `ParseUser`.\n     If login failed due to either an incorrect password or incorrect username, it throws a `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    static func link(_ type: String,\n                     authData: [String: String],\n                     options: API.Options) throws -> Self {\n        guard let current = Self.current else {\n            throw ParseError(code: .unknownError, message: \"Must be logged in to link user\")\n        }\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        let body = SignupLoginBody(authData: [type: authData])\n        return try current.linkCommand(body: body).execute(options: options)\n    }\n\n    /**\n     Makes an *asynchronous* request to link a user with specified credentials. The user should already be logged in.\n     Returns an instance of the successfully linked `ParseUser`.\n\n     This also caches the user locally so that calls to *current* will use the latest logged in user.\n     - parameter type: The authentication type.\n     - parameter authData: The data that represents the authentication.\n     See [supported 3rd party authentications](https://docs.parseplatform.org/parse-server/guide/#supported-3rd-party-authentications) for more information.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    static func link(_ type: String,\n                     authData: [String: String],\n                     options: API.Options = [],\n                     callbackQueue: DispatchQueue = .main,\n                     completion: @escaping (Result<Self, ParseError>) -> Void) {\n        guard let current = Self.current else {\n            let error = ParseError(code: .unknownError, message: \"Must be logged in to link user\")\n            callbackQueue.async {\n                completion(.failure(error))\n            }\n            return\n        }\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        let body = SignupLoginBody(authData: [type: authData])\n        current.linkCommand(body: body)\n            .executeAsync(options: options,\n                          callbackQueue: callbackQueue) { result in\n                completion(result)\n            }\n    }\n\n    internal func linkCommand() throws -> API.Command<Self, Self> {\n        var mutableSelf = self.anonymous.strip(self)\n        if let current = Self.current {\n            guard current.hasSameObjectId(as: mutableSelf) else {\n                let error = ParseError(code: .unknownError,\n                                       message: \"Cannot signup a user with a different objectId than the current user\")\n                throw error\n            }\n        }\n        return API.Command<Self, Self>(method: .PUT,\n                                       path: endpoint,\n                                       body: mutableSelf) { (data) -> Self in\n            let user = try ParseCoding.jsonDecoder().decode(UpdateSessionTokenResponse.self, from: data)\n            mutableSelf.updatedAt = user.updatedAt\n            if let sessionToken = user.sessionToken {\n                Self.currentContainer = .init(currentUser: mutableSelf,\n                                              sessionToken: sessionToken)\n            }\n            Self.saveCurrentContainerToKeychain()\n            return mutableSelf\n        }\n    }\n\n    internal func linkCommand(body: SignupLoginBody) -> API.Command<SignupLoginBody, Self> {\n        let originalAuthData = Self.current?.authData\n        Self.current?.anonymous.strip()\n        var body = body\n        if var currentAuthData = Self.current?.authData {\n            if let bodyAuthData = body.authData {\n                bodyAuthData.forEach { (key, value) in\n                    currentAuthData[key] = value\n                }\n            }\n            body.authData = currentAuthData\n        }\n\n        return API.Command<SignupLoginBody, Self>(method: .PUT,\n                                                  path: endpoint,\n                                                  body: body) { (data) -> Self in\n            Self.current?.authData = originalAuthData\n            let user = try ParseCoding.jsonDecoder().decode(UpdateSessionTokenResponse.self, from: data)\n            Self.current?.updatedAt = user.updatedAt\n            Self.current?.authData = body.authData\n            guard let current = Self.current else {\n                throw ParseError(code: .unknownError, message: \"Should have a current user.\")\n            }\n            if let sessionToken = user.sessionToken {\n                Self.currentContainer = .init(currentUser: current,\n                                              sessionToken: sessionToken)\n            }\n            Self.saveCurrentContainerToKeychain()\n            return current\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Coding/AnyCodable.swift",
    "content": "import Foundation\n\n/**\n A type-erased `Codable` value.\n \n The `AnyCodable` type forwards encoding and decoding responsibilities\n to an underlying value, hiding its specific underlying type.\n \n You can encode or decode mixed-type values in dictionaries\n and other collections that require `Encodable` or `Decodable` conformance\n by declaring their contained type to be `AnyCodable`.\n \n - SeeAlso: `AnyEncodable`\n - SeeAlso: `AnyDecodable`\n\n Source: https://github.com/Flight-School/AnyCodable\n */\nstruct AnyCodable: Codable {\n\n    let value: Any\n\n    init<T>(_ value: T?) {\n        self.value = value ?? ()\n    }\n}\n\nextension AnyCodable: _AnyEncodable, _AnyDecodable {}\n\nextension AnyCodable: Equatable {\n    static func == (lhs: AnyCodable, rhs: AnyCodable) -> Bool { // swiftlint:disable:this cyclomatic_complexity line_length\n        switch (lhs.value, rhs.value) {\n        case is (Void, Void):\n            return true\n        case let (lhs as Bool, rhs as Bool):\n            return lhs == rhs\n        case let (lhs as Int, rhs as Int):\n            return lhs == rhs\n        case let (lhs as Int8, rhs as Int8):\n            return lhs == rhs\n        case let (lhs as Int16, rhs as Int16):\n            return lhs == rhs\n        case let (lhs as Int32, rhs as Int32):\n            return lhs == rhs\n        case let (lhs as Int64, rhs as Int64):\n            return lhs == rhs\n        case let (lhs as UInt, rhs as UInt):\n            return lhs == rhs\n        case let (lhs as UInt8, rhs as UInt8):\n            return lhs == rhs\n        case let (lhs as UInt16, rhs as UInt16):\n            return lhs == rhs\n        case let (lhs as UInt32, rhs as UInt32):\n            return lhs == rhs\n        case let (lhs as UInt64, rhs as UInt64):\n            return lhs == rhs\n        case let (lhs as Float, rhs as Float):\n            return lhs == rhs\n        case let (lhs as Double, rhs as Double):\n            return lhs == rhs\n        case let (lhs as String, rhs as String):\n            return lhs == rhs\n        case (let lhs as [String: AnyCodable], let rhs as [String: AnyCodable]):\n            return lhs == rhs\n        case (let lhs as [AnyCodable], let rhs as [AnyCodable]):\n            return lhs == rhs\n        default:\n            return lhs.isEqual(rhs)\n        }\n    }\n}\n\nextension AnyCodable: Hashable {\n    public func hash(into hasher: inout Hasher) {\n        do {\n            let encodedData = try ParseCoding.jsonEncoder().encode(self)\n            let encodedString = String(data: encodedData, encoding: .utf8)\n            hasher.combine(encodedString)\n        } catch {\n            hasher.combine(0)\n        }\n    }\n}\n\nextension AnyCodable: CustomStringConvertible {\n    var description: String {\n        switch value {\n        case is Void:\n            return String(describing: nil as Any?)\n        case let value as CustomStringConvertible:\n            return value.description\n        default:\n            return String(describing: value)\n        }\n    }\n}\n\nextension AnyCodable: CustomDebugStringConvertible {\n    var debugDescription: String {\n        switch value {\n        case let value as CustomDebugStringConvertible:\n            return \"AnyCodable(\\(value.debugDescription))\"\n        default:\n            return \"AnyCodable(\\(self.description))\"\n        }\n    }\n}\n\nextension AnyCodable: ExpressibleByNilLiteral {}\nextension AnyCodable: ExpressibleByBooleanLiteral {}\nextension AnyCodable: ExpressibleByIntegerLiteral {}\nextension AnyCodable: ExpressibleByFloatLiteral {}\nextension AnyCodable: ExpressibleByStringLiteral {}\nextension AnyCodable: ExpressibleByArrayLiteral {}\nextension AnyCodable: ExpressibleByDictionaryLiteral {}\n"
  },
  {
    "path": "Sources/ParseSwift/Coding/AnyDecodable.swift",
    "content": "import Foundation\n\n/**\n A type-erased `Decodable` value.\n \n The `AnyDecodable` type forwards decoding responsibilities\n to an underlying value, hiding its specific underlying type.\n \n You can decode mixed-type values in dictionaries\n and other collections that require `Decodable` conformance\n by declaring their contained type to be `AnyDecodable`:\n \n     let json = \"\"\"\n     {\n         \"boolean\": true,\n         \"integer\": 42,\n         \"double\": 3.14159265358979323846,\n         \"string\": \"string\",\n         \"array\": [1, 2, 3],\n         \"nested\": {\n             \"a\": \"alpha\",\n             \"b\": \"bravo\",\n             \"c\": \"charlie\"\n         }\n     }\n     \"\"\".data(using: .utf8)!\n \n     let decoder = JSONDecoder()\n     let dictionary = try! decoder.decode([String: AnyCodable].self, from: json)\n */\nstruct AnyDecodable: Decodable {\n    let value: Any\n    init<T>(_ value: T?) {\n        self.value = value ?? ()\n    }\n}\n\nprotocol _AnyDecodable {\n    var value: Any { get }\n    init<T>(_ value: T?)\n}\n\nextension AnyDecodable: _AnyDecodable {}\n\nextension _AnyDecodable {\n    init(from decoder: Decoder) throws {\n        let container = try decoder.singleValueContainer()\n\n        if container.decodeNil() {\n            #if canImport(Foundation)\n                self.init(NSNull())\n            #else\n                self.init(Self?.none)\n            #endif\n        } else if let bool = try? container.decode(Bool.self) {\n            self.init(bool)\n        } else if let int = try? container.decode(Int.self) {\n            self.init(int)\n        } else if let uint = try? container.decode(UInt.self) {\n            self.init(uint)\n        } else if let double = try? container.decode(Double.self) {\n            self.init(double)\n        } else if let string = try? container.decode(String.self) {\n            self.init(string)\n        } else if let array = try? container.decode([AnyDecodable].self) {\n            self.init(array.map { $0.value })\n        } else if let dictionary = try? container.decode([String: AnyDecodable].self) {\n            self.init(dictionary.mapValues { $0.value })\n        } else {\n            throw DecodingError.dataCorruptedError(in: container,\n                                                   debugDescription: \"AnyDecodable value cannot be decoded\")\n        }\n    }\n}\n\nextension AnyDecodable: Equatable {\n    static func == (lhs: AnyDecodable, rhs: AnyDecodable) -> Bool {\n        switch (lhs.value, rhs.value) {\n#if canImport(Foundation)\n        case is (NSNull, NSNull), is (Void, Void):\n            return true\n#endif\n        case let (lhs as Bool, rhs as Bool):\n            return lhs == rhs\n        case let (lhs as Int, rhs as Int):\n            return lhs == rhs\n        case let (lhs as Int8, rhs as Int8):\n            return lhs == rhs\n        case let (lhs as Int16, rhs as Int16):\n            return lhs == rhs\n        case let (lhs as Int32, rhs as Int32):\n            return lhs == rhs\n        case let (lhs as Int64, rhs as Int64):\n            return lhs == rhs\n        case let (lhs as UInt, rhs as UInt):\n            return lhs == rhs\n        case let (lhs as UInt8, rhs as UInt8):\n            return lhs == rhs\n        case let (lhs as UInt16, rhs as UInt16):\n            return lhs == rhs\n        case let (lhs as UInt32, rhs as UInt32):\n            return lhs == rhs\n        case let (lhs as UInt64, rhs as UInt64):\n            return lhs == rhs\n        case let (lhs as Float, rhs as Float):\n            return lhs == rhs\n        case let (lhs as Double, rhs as Double):\n            return lhs == rhs\n        case let (lhs as String, rhs as String):\n            return lhs == rhs\n        case let (lhs as [String: AnyDecodable], rhs as [String: AnyDecodable]):\n            return lhs == rhs\n        case let (lhs as [AnyDecodable], rhs as [AnyDecodable]):\n            return lhs == rhs\n        default:\n            return false\n        }\n    }\n}\n\nextension AnyDecodable: CustomStringConvertible {\n    var description: String {\n        switch value {\n        case is Void:\n            return String(describing: nil as Any?)\n        case let value as CustomStringConvertible:\n            return value.description\n        default:\n            return String(describing: value)\n        }\n    }\n}\n\nextension AnyDecodable: CustomDebugStringConvertible {\n    var debugDescription: String {\n        switch value {\n        case let value as CustomDebugStringConvertible:\n            return \"AnyDecodable(\\(value.debugDescription))\"\n        default:\n            return \"AnyDecodable(\\(self.description))\"\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Coding/AnyEncodable.swift",
    "content": "import Foundation\n\n/**\n A type-erased `Encodable` value.\n \n The `AnyEncodable` type forwards encoding responsibilities\n to an underlying value, hiding its specific underlying type.\n \n You can encode mixed-type values in dictionaries\n and other collections that require `Encodable` conformance\n by declaring their contained type to be `AnyEncodable`:\n \n     let dictionary: [String: AnyEncodable] = [\n         \"boolean\": true,\n         \"integer\": 42,\n         \"double\": 3.14159265358979323846,\n         \"string\": \"string\",\n         \"array\": [1, 2, 3],\n         \"nested\": [\n             \"a\": \"alpha\",\n             \"b\": \"bravo\",\n             \"c\": \"charlie\"\n         ],\n         \"null\": nil\n     ]\n \n     let encoder = JSONEncoder()\n     let json = try! encoder.encode(dictionary)\n \n Source: https://github.com/Flight-School/AnyCodable\n */\nstruct AnyEncodable: Encodable {\n    let value: Any\n\n    init<T>(_ value: T?) {\n        self.value = value ?? ()\n    }\n}\n\n@usableFromInline\nprotocol _AnyEncodable {\n\n    var value: Any { get }\n    init<T>(_ value: T?)\n}\n\nextension AnyEncodable: _AnyEncodable {}\n\n// MARK: - Encodable\n\nextension _AnyEncodable {\n    // swiftlint:disable:next cyclomatic_complexity function_body_length\n    func encode(to encoder: Encoder) throws {\n\n        var container = encoder.singleValueContainer()\n        switch self.value {\n        #if canImport(Foundation)\n        case let number as NSNumber:\n            try encode(nsnumber: number, into: &container)\n        case is NSNull:\n            try container.encodeNil()\n        #endif\n        case is Void:\n            try container.encodeNil()\n        case let bool as Bool:\n            try container.encode(bool)\n        case let int as Int:\n            try container.encode(int)\n        case let int8 as Int8:\n            try container.encode(int8)\n        case let int16 as Int16:\n            try container.encode(int16)\n        case let int32 as Int32:\n            try container.encode(int32)\n        case let int64 as Int64:\n            try container.encode(int64)\n        case let uint as UInt:\n            try container.encode(uint)\n        case let uint8 as UInt8:\n            try container.encode(uint8)\n        case let uint16 as UInt16:\n            try container.encode(uint16)\n        case let uint32 as UInt32:\n            try container.encode(uint32)\n        case let uint64 as UInt64:\n            try container.encode(uint64)\n        case let float as Float:\n            try container.encode(float)\n        case let double as Double:\n            try container.encode(double)\n        case let string as String:\n            try container.encode(string)\n        #if canImport(Foundation)\n        case let date as Date:\n            try container.encode(date)\n        case let url as URL:\n            try container.encode(url)\n        #endif\n        case let array as [Any?]:\n            try container.encode(array.map { AnyEncodable($0) })\n        case let dictionary as [String: Any?]:\n            try container.encode(dictionary.mapValues { AnyEncodable($0) })\n        case let encodable as Encodable:\n            try encodable.encode(to: encoder)\n        default:\n            let context = EncodingError.Context(codingPath: container.codingPath,\n                                                debugDescription: \"AnyEncodable value cannot be encoded\")\n            throw EncodingError.invalidValue(value, context)\n        }\n    }\n\n    #if canImport(Foundation)\n    private func encode(nsnumber: NSNumber, into container: inout SingleValueEncodingContainer) throws {\n        switch Character(Unicode.Scalar(UInt8(nsnumber.objCType.pointee))) {\n        case \"c\", \"C\":\n            try container.encode(nsnumber.boolValue)\n        case \"s\":\n            try container.encode(nsnumber.int8Value)\n        case \"i\":\n            try container.encode(nsnumber.int16Value)\n        case \"l\":\n            try container.encode(nsnumber.int32Value)\n        case \"q\":\n            try container.encode(nsnumber.int64Value)\n        case \"S\":\n            try container.encode(nsnumber.uint8Value)\n        case \"I\":\n            try container.encode(nsnumber.uint16Value)\n        case \"L\":\n            try container.encode(nsnumber.uint32Value)\n        case \"Q\":\n            try container.encode(nsnumber.uint64Value)\n        case \"f\":\n            try container.encode(nsnumber.floatValue)\n        case \"d\":\n            try container.encode(nsnumber.doubleValue)\n        default:\n            let context = EncodingError.Context(codingPath: container.codingPath,\n                                                // swiftlint:disable:next line_length\n                                                debugDescription: \"NSNumber cannot be encoded because its type is not handled\")\n            throw EncodingError.invalidValue(nsnumber, context)\n        }\n    }\n    #endif\n}\n\nextension AnyEncodable: Equatable {\n    static func == (lhs: AnyEncodable, rhs: AnyEncodable) -> Bool { // swiftlint:disable:this cyclomatic_complexity line_length\n        switch (lhs.value, rhs.value) {\n        case is (Void, Void):\n            return true\n        case let (lhs as Bool, rhs as Bool):\n            return lhs == rhs\n        case let (lhs as Int, rhs as Int):\n            return lhs == rhs\n        case let (lhs as Int8, rhs as Int8):\n            return lhs == rhs\n        case let (lhs as Int16, rhs as Int16):\n            return lhs == rhs\n        case let (lhs as Int32, rhs as Int32):\n            return lhs == rhs\n        case let (lhs as Int64, rhs as Int64):\n            return lhs == rhs\n        case let (lhs as UInt, rhs as UInt):\n            return lhs == rhs\n        case let (lhs as UInt8, rhs as UInt8):\n            return lhs == rhs\n        case let (lhs as UInt16, rhs as UInt16):\n            return lhs == rhs\n        case let (lhs as UInt32, rhs as UInt32):\n            return lhs == rhs\n        case let (lhs as UInt64, rhs as UInt64):\n            return lhs == rhs\n        case let (lhs as Float, rhs as Float):\n            return lhs == rhs\n        case let (lhs as Double, rhs as Double):\n            return lhs == rhs\n        case let (lhs as String, rhs as String):\n            return lhs == rhs\n        case (let lhs as [String: AnyEncodable], let rhs as [String: AnyEncodable]):\n            return lhs == rhs\n        case (let lhs as [AnyEncodable], let rhs as [AnyEncodable]):\n            return lhs == rhs\n        default:\n            return lhs.isEqual(rhs)\n        }\n    }\n}\n\nextension AnyEncodable: Hashable {\n    public func hash(into hasher: inout Hasher) {\n        do {\n            let encodedData = try ParseCoding.jsonEncoder().encode(self)\n            let encodedString = String(data: encodedData, encoding: .utf8)\n            hasher.combine(encodedString)\n        } catch {\n            hasher.combine(0)\n        }\n    }\n}\n\nextension AnyEncodable: CustomStringConvertible {\n    var description: String {\n        switch value {\n        case is Void:\n            return String(describing: nil as Any?)\n        case let value as CustomStringConvertible:\n            return value.description\n        default:\n            return String(describing: value)\n        }\n    }\n}\n\nextension AnyEncodable: CustomDebugStringConvertible {\n    var debugDescription: String {\n        switch value {\n        case let value as CustomDebugStringConvertible:\n            return \"AnyEncodable(\\(value.debugDescription))\"\n        default:\n            return \"AnyEncodable(\\(self.description))\"\n        }\n    }\n}\n\nextension AnyEncodable: ExpressibleByNilLiteral {}\nextension AnyEncodable: ExpressibleByBooleanLiteral {}\nextension AnyEncodable: ExpressibleByIntegerLiteral {}\nextension AnyEncodable: ExpressibleByFloatLiteral {}\nextension AnyEncodable: ExpressibleByStringLiteral {}\nextension AnyEncodable: ExpressibleByStringInterpolation {}\nextension AnyEncodable: ExpressibleByArrayLiteral {}\nextension AnyEncodable: ExpressibleByDictionaryLiteral {}\n\nextension _AnyEncodable {\n    init(nilLiteral _: ()) {\n        self.init(nil as Any?)\n    }\n\n    init(booleanLiteral value: Bool) {\n        self.init(value)\n    }\n\n    init(integerLiteral value: Int) {\n        self.init(value)\n    }\n\n    init(floatLiteral value: Double) {\n        self.init(value)\n    }\n\n    init(extendedGraphemeClusterLiteral value: String) {\n        self.init(value)\n    }\n    init(stringLiteral value: String) {\n        self.init(value)\n    }\n\n    init(arrayLiteral elements: Any...) {\n        self.init(elements)\n    }\n\n    init(dictionaryLiteral elements: (AnyHashable, Any)...) {\n        self.init([AnyHashable: Any](elements, uniquingKeysWith: { (first, _) in first }))\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Coding/ParseCoding.swift",
    "content": "//\n//  ParseCoding.swift\n//  ParseSwift\n//\n//  Created by Florent Vilmart on 17-07-24.\n//  Copyright © 2017 Parse. All rights reserved.\n//\n\nimport Foundation\n\n// MARK: ParseCoding\n/// Custom coding for Parse objects.\nenum ParseCoding {}\n\n// MARK: Coders\nextension ParseCoding {\n\n    /// The JSON Encoder setup with the correct `dateEncodingStrategy`\n    /// strategy for `Parse`.\n    static func jsonEncoder() -> JSONEncoder {\n        let encoder = JSONEncoder()\n        encoder.dateEncodingStrategy = parseDateEncodingStrategy\n        encoder.outputFormatting = .sortedKeys\n        return encoder\n    }\n\n    /// The JSON Decoder setup with the correct `dateDecodingStrategy`\n    /// strategy for `Parse`. This encoder is used to decode all data received\n    /// from the server.\n    static func jsonDecoder() -> JSONDecoder {\n        let decoder = JSONDecoder()\n        decoder.dateDecodingStrategy = dateDecodingStrategy\n        return decoder\n    }\n\n    /// The Parse Encoder is used to JSON encode all `ParseObject`s and\n    /// types in a way meaninful for a Parse Server to consume.\n    static func parseEncoder() -> ParseEncoder {\n        ParseEncoder(\n            dateEncodingStrategy: parseDateEncodingStrategy,\n            outputFormatting: .sortedKeys\n        )\n    }\n}\n\n// MARK: Coding\npublic extension ParseObject {\n\n    /// The Parse encoder is used to JSON encode all `ParseObject`s and\n    /// types in a way meaninful for a Parse Server to consume.\n    static func getEncoder() -> ParseEncoder {\n        return ParseCoding.parseEncoder()\n    }\n\n    /// The Parse encoder is used to JSON encode all `ParseObject`s and\n    /// types in a way meaninful for a Parse Server to consume.\n    func getEncoder() -> ParseEncoder {\n        return Self.getEncoder()\n    }\n\n    /// The JSON encoder setup with the correct `dateEncodingStrategy`\n    /// strategy to send data to a Parse Server.\n    static func getJSONEncoder() -> JSONEncoder {\n        return ParseCoding.jsonEncoder()\n    }\n\n    /// The JSON encoder setup with the correct `dateEncodingStrategy`\n    /// strategy to send data to a Parse Server.\n    func getJSONEncoder() -> JSONEncoder {\n        return Self.getJSONEncoder()\n    }\n\n    /// The JSON decoder setup with the correct `dateDecodingStrategy`\n    /// strategy to decode data from a Parse Server. This encoder is used to decode all data received\n    /// from the server.\n    static func getDecoder() -> JSONDecoder {\n        ParseCoding.jsonDecoder()\n    }\n\n    /// The JSON decoder setup with the correct `dateDecodingStrategy`\n    /// strategy to decode data from a Parse Server. This encoder is used to decode all data received\n    /// from the server.\n    func getDecoder() -> JSONDecoder {\n        Self.getDecoder()\n    }\n}\n\n// MARK: Dates\nextension ParseCoding {\n    enum DateEncodingKeys: String, CodingKey {\n        case iso\n        case type = \"__type\"\n    }\n\n    static let dateFormatter: DateFormatter = {\n        var dateFormatter = DateFormatter()\n        dateFormatter.locale = Locale(identifier: \"en_US_POSIX\")\n        dateFormatter.timeZone = TimeZone(secondsFromGMT: 0)\n        dateFormatter.dateFormat = \"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'\"\n        return dateFormatter\n    }()\n\n    static let parseDateEncodingStrategy: JSONEncoder.DateEncodingStrategy = .custom { (date, encoder) in\n        var container = encoder.container(keyedBy: DateEncodingKeys.self)\n        try container.encode(\"Date\", forKey: .type)\n        let dateString = dateFormatter.string(from: date)\n        try container.encode(dateString, forKey: .iso)\n    }\n\n    static let dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .custom({ (decoder) -> Date in\n        do {\n            let container = try decoder.singleValueContainer()\n            let decodedString = try container.decode(String.self)\n\n            if let date = dateFormatter.date(from: decodedString) {\n                return date\n            } else {\n                throw ParseError(\n                    code: .unknownError,\n                    message: \"An invalid date string was provided when decoding dates.\"\n                )\n            }\n        } catch {\n            let container = try decoder.container(keyedBy: DateEncodingKeys.self)\n\n            if\n                let decoded = try container.decodeIfPresent(String.self, forKey: .iso),\n                let date = dateFormatter.date(from: decoded)\n            {\n                return date\n            } else {\n                throw ParseError(\n                    code: .unknownError,\n                    message: \"An invalid date string was provided when decoding dates.\"\n                )\n            }\n        }\n    })\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Coding/ParseEncoder.swift",
    "content": "//\n//  ParseEncoder.swift\n//  ParseSwift\n//\n//  Created by Pranjal Satija on 7/20/20.\n//  Copyright © 2020 Parse. All rights reserved.\n//\n\n//===----------------------------------------------------------------------===//\n//\n// This source file is part of the Swift.org open source project\n//\n// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors\n// Licensed under Apache License v2.0 with Runtime Library Exception\n//\n// See https://swift.org/LICENSE.txt for license information\n// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors\n//\n//===----------------------------------------------------------------------===//\n\nimport Foundation\n\n/// A marker protocol used to determine whether a value is a `String`-keyed `Dictionary`\n/// containing `Encodable` values (in which case it should be exempt from key conversion strategies).\n///\n/// NOTE: The architecture and environment check is due to a bug in the current (2018-08-08) Swift 4.2\n/// runtime when running on i386 simulator. The issue is tracked in https://bugs.swift.org/browse/SR-8276\n/// Making the protocol `internal` instead of `private` works around this issue.\n/// Once SR-8276 is fixed, this check can be removed and the protocol always be made private.\n#if arch(i386) || arch(arm)\ninternal protocol _JSONStringDictionaryEncodableMarker { }\n#else\nprivate protocol _JSONStringDictionaryEncodableMarker { }\n#endif\nextension Dictionary: _JSONStringDictionaryEncodableMarker where Key == String, Value: Encodable { }\n\n// This rule does not allow types with underscores in their names.\n// swiftlint:disable type_name\n// swiftlint:disable colon\n// swiftlint:disable force_cast\n// swiftlint:disable line_length\n// swiftlint:disable return_arrow_whitespace\n// swiftlint:disable file_length\n// swiftlint:disable redundant_discardable_let\n// swiftlint:disable cyclomatic_complexity\n\n// MARK: ParseEncoder\n/** An object that encodes Parse instances of a data type as JSON objects.\n - note: `JSONEncoder` facilitates the encoding of `Encodable` values into JSON.\n `ParseEncoder` facilitates the encoding of `ParseEncodable` values into JSON.\n All Credit to Apple, this is a custom encoder with capability of skipping keys at runtime.\n ParseEncoder matches the features of the [Swift 5.4 JSONEncoder ](https://github.com/apple/swift/blob/main/stdlib/public/Darwin/Foundation/JSONEncoder.swift).\n Update commits as needed for improvement.\n */\npublic struct ParseEncoder {\n    let dateEncodingStrategy: JSONEncoder.DateEncodingStrategy?\n    let outputFormatting: JSONEncoder.OutputFormatting?\n\n    /// Keys to skip during encoding.\n    public enum SkipKeys {\n        /// Skip keys for `ParseObject`'s.\n        case object\n        /// Skip keys for `ParseCloud` functions or jobs.\n        case cloud\n        /// Do not skip any keys.\n        case none\n        /// Skip keys for `ParseObject`'s when using custom `objectId`'s.\n        case customObjectId\n        /// Specify a custom set of keys to skip.\n        case custom(Set<String>)\n\n        func keys() -> Set<String> {\n            let defaultObjectKeys = Set([\"createdAt\",\n                                         \"updatedAt\",\n                                         \"objectId\",\n                                         \"className\",\n                                         \"emailVerified\",\n                                         \"id\",\n                                         \"score\",\n                                         \"originalData\"])\n            switch self {\n\n            case .object:\n                return defaultObjectKeys\n            case .customObjectId:\n                var mutableKeys = defaultObjectKeys\n                _ = mutableKeys.remove(\"objectId\")\n                return mutableKeys\n            case .cloud:\n                return Set([\"functionJobName\"])\n            case .none:\n                return .init()\n            case .custom(let keys):\n                return keys\n            }\n        }\n    }\n\n    init(\n        dateEncodingStrategy: JSONEncoder.DateEncodingStrategy? = nil,\n        outputFormatting: JSONEncoder.OutputFormatting? = .sortedKeys\n    ) {\n        self.dateEncodingStrategy = dateEncodingStrategy\n        self.outputFormatting = outputFormatting\n    }\n\n    func encode(_ value: Encodable, batching: Bool = false) throws -> Data {\n        var keysToSkip = SkipKeys.none.keys()\n        if batching {\n            keysToSkip = SkipKeys.object.keys()\n        }\n        let encoder = _ParseEncoder(codingPath: [], dictionary: NSMutableDictionary(), skippingKeys: keysToSkip)\n        if let dateEncodingStrategy = dateEncodingStrategy {\n            encoder.dateEncodingStrategy = dateEncodingStrategy\n        }\n        if let outputFormatting = outputFormatting {\n            encoder.outputFormatting = outputFormatting\n        }\n        return try encoder.encodeObject(value,\n                                        batching: batching,\n                                        collectChildren: false,\n                                        uniquePointer: nil,\n                                        objectsSavedBeforeThisOne: nil,\n                                        filesSavedBeforeThisOne: nil).encoded\n    }\n\n    /**\n     Encodes an instance of the indicated `ParseEncodable`.\n     - parameter value: The `ParseEncodable` instance to encode.\n     - parameter skipKeys: The set of keys to skip during encoding.\n     */\n    public func encode<T: ParseEncodable>(_ value: T,\n                                          skipKeys: SkipKeys) throws -> Data {\n        let encoder = _ParseEncoder(codingPath: [], dictionary: NSMutableDictionary(), skippingKeys: skipKeys.keys())\n        if let dateEncodingStrategy = dateEncodingStrategy {\n            encoder.dateEncodingStrategy = dateEncodingStrategy\n        }\n        if let outputFormatting = outputFormatting {\n            encoder.outputFormatting = outputFormatting\n        }\n        return try encoder.encodeObject(value,\n                                        collectChildren: false,\n                                        uniquePointer: nil,\n                                        objectsSavedBeforeThisOne: nil,\n                                        filesSavedBeforeThisOne: nil).encoded\n    }\n\n    // swiftlint:disable large_tuple\n    internal func encode<T: ParseObject>(_ value: T,\n                                         objectsSavedBeforeThisOne: [String: PointerType]?,\n                                         filesSavedBeforeThisOne: [UUID: ParseFile]?) throws -> (encoded: Data,\n                                                                                                 unique: PointerType?,\n                                                                                                 unsavedChildren: [Encodable]) {\n        let keysToSkip: Set<String>!\n        if !Parse.configuration.isRequiringCustomObjectIds {\n            keysToSkip = SkipKeys.object.keys()\n        } else {\n            keysToSkip = SkipKeys.customObjectId.keys()\n        }\n        let encoder = _ParseEncoder(codingPath: [], dictionary: NSMutableDictionary(), skippingKeys: keysToSkip)\n        if let dateEncodingStrategy = dateEncodingStrategy {\n            encoder.dateEncodingStrategy = dateEncodingStrategy\n        }\n        if let outputFormatting = outputFormatting {\n            encoder.outputFormatting = outputFormatting\n        }\n        return try encoder.encodeObject(value,\n                                        collectChildren: true,\n                                        uniquePointer: try? value.toPointer(),\n                                        objectsSavedBeforeThisOne: objectsSavedBeforeThisOne,\n                                        filesSavedBeforeThisOne: filesSavedBeforeThisOne)\n    }\n\n    // swiftlint:disable large_tuple\n    internal func encode(_ value: ParseEncodable,\n                         batching: Bool = false,\n                         collectChildren: Bool,\n                         objectsSavedBeforeThisOne: [String: PointerType]?,\n                         filesSavedBeforeThisOne: [UUID: ParseFile]?) throws -> (encoded: Data, unique: PointerType?, unsavedChildren: [Encodable]) {\n        let keysToSkip: Set<String>!\n        if !Parse.configuration.isRequiringCustomObjectIds {\n            keysToSkip = SkipKeys.object.keys()\n        } else {\n            keysToSkip = SkipKeys.customObjectId.keys()\n        }\n        let encoder = _ParseEncoder(codingPath: [], dictionary: NSMutableDictionary(), skippingKeys: keysToSkip)\n        if let dateEncodingStrategy = dateEncodingStrategy {\n            encoder.dateEncodingStrategy = dateEncodingStrategy\n        }\n        if let outputFormatting = outputFormatting {\n            encoder.outputFormatting = outputFormatting\n        }\n        return try encoder.encodeObject(value,\n                                        batching: batching,\n                                        collectChildren: collectChildren,\n                                        uniquePointer: nil,\n                                        objectsSavedBeforeThisOne: objectsSavedBeforeThisOne,\n                                        filesSavedBeforeThisOne: filesSavedBeforeThisOne)\n    }\n}\n\n// MARK: _ParseEncoder\ninternal class _ParseEncoder: JSONEncoder, Encoder {\n    var codingPath: [CodingKey]\n    let dictionary: NSMutableDictionary\n    let skippedKeys: Set<String>\n    var uniquePointer: PointerType?\n    var uniqueFiles = Set<ParseFile>()\n    var newObjects = [Encodable]()\n    var collectChildren = false\n    var batching = false\n    var objectsSavedBeforeThisOne: [String: PointerType]?\n    var filesSavedBeforeThisOne: [UUID: ParseFile]?\n    /// The encoder's storage.\n    var storage: _ParseEncodingStorage\n    var ignoreSkipKeys = false\n\n    /// Options set on the top-level encoder to pass down the encoding hierarchy.\n    fileprivate struct _Options {\n        let dateEncodingStrategy: DateEncodingStrategy\n        let dataEncodingStrategy: DataEncodingStrategy\n        let nonConformingFloatEncodingStrategy: NonConformingFloatEncodingStrategy\n        let keyEncodingStrategy: KeyEncodingStrategy\n        let userInfo: [CodingUserInfoKey: Any]\n    }\n\n    /// The options set on the top-level encoder.\n    fileprivate var options: _Options {\n        return _Options(dateEncodingStrategy: dateEncodingStrategy,\n                        dataEncodingStrategy: dataEncodingStrategy,\n                        nonConformingFloatEncodingStrategy: nonConformingFloatEncodingStrategy,\n                        keyEncodingStrategy: keyEncodingStrategy,\n                        userInfo: userInfo)\n    }\n\n    init(codingPath: [CodingKey], dictionary: NSMutableDictionary, skippingKeys: Set<String>) {\n        self.codingPath = codingPath\n        self.dictionary = dictionary\n        self.skippedKeys = skippingKeys\n        self.storage = _ParseEncodingStorage()\n        super.init()\n    }\n\n    /// Returns whether a new element can be encoded at this coding path.\n    ///\n    /// **true** if an element has not yet been encoded at this coding path; **false** otherwise.\n    var canEncodeNewValue: Bool {\n        // Every time a new value gets encoded, the key it is encoded for is pushed onto the coding path (even if it is a nil key from an unkeyed container).\n        // At the same time, every time a container is requested, a new value gets pushed onto the storage stack.\n        // If there are more values on the storage stack than on the coding path, it means the value is requesting more than one container, which violates the precondition.\n        //\n        // This means that anytime something that can request a new container goes onto the stack, we MUST push a key onto the coding path.\n        // Things which will not request containers do not need to have the coding path extended for them (but it does not matter if it is, because they will not reach here).\n        return self.storage.count == self.codingPath.count\n    }\n\n    @available(*, unavailable)\n    override func encode<T : Encodable>(_ value: T) throws -> Data {\n        throw ParseError(code: .unknownError,\n                         message: \"This method should not be used. Either use the JSONEncoder or if you are encoding a ParseObject use \\\"encodeObject\\\"\")\n    }\n\n    func encodeObject(_ value: Encodable,\n                      batching: Bool = false,\n                      collectChildren: Bool,\n                      uniquePointer: PointerType?,\n                      objectsSavedBeforeThisOne: [String: PointerType]?,\n                      filesSavedBeforeThisOne: [UUID: ParseFile]?) throws -> (encoded: Data, unique: PointerType?, unsavedChildren: [Encodable]) {\n\n        let encoder = _ParseEncoder(codingPath: codingPath, dictionary: dictionary, skippingKeys: skippedKeys)\n        encoder.outputFormatting = outputFormatting\n        encoder.dateEncodingStrategy = dateEncodingStrategy\n        encoder.dataEncodingStrategy = dataEncodingStrategy\n        encoder.nonConformingFloatEncodingStrategy = nonConformingFloatEncodingStrategy\n        encoder.keyEncodingStrategy = keyEncodingStrategy\n        encoder.userInfo = userInfo\n        encoder.collectChildren = collectChildren\n        encoder.batching = batching\n        encoder.objectsSavedBeforeThisOne = objectsSavedBeforeThisOne\n        encoder.filesSavedBeforeThisOne = filesSavedBeforeThisOne\n        encoder.uniquePointer = uniquePointer\n\n        guard let topLevel = try encoder.box_(value) else {\n            throw EncodingError.invalidValue(value,\n                                             EncodingError.Context(codingPath: [], debugDescription: \"Top-level \\(value) did not encode any values.\"))\n        }\n\n        let writingOptions = JSONSerialization.WritingOptions(rawValue: self.outputFormatting.rawValue).union(.fragmentsAllowed)\n        do {\n            let serialized = try JSONSerialization.data(withJSONObject: topLevel, options: writingOptions)\n            return (serialized, encoder.uniquePointer, encoder.newObjects)\n        } catch {\n            throw EncodingError.invalidValue(value,\n                                             EncodingError.Context(codingPath: [], debugDescription: \"Unable to encode the given top-level value to JSON.\", underlyingError: error))\n        }\n    }\n\n    func container<Key>(keyedBy type: Key.Type) -> KeyedEncodingContainer<Key> where Key: CodingKey {\n\n        // If an existing keyed container was already requested, return that one.\n        let topContainer: NSMutableDictionary\n        if self.canEncodeNewValue {\n            // We have not yet pushed a container at this level; do so here.\n            topContainer = self.storage.pushKeyedContainer()\n        } else {\n            guard let container = self.storage.containers.last as? NSMutableDictionary else {\n                preconditionFailure(\"Attempt to push new keyed encoding container when already previously encoded at this path.\")\n            }\n\n            topContainer = container\n        }\n\n        let container = _ParseEncoderKeyedEncodingContainer<Key>(\n            referencing: self, codingPath: codingPath,\n            wrapping: topContainer\n        )\n\n        return KeyedEncodingContainer(container)\n    }\n\n    func singleValueContainer() -> SingleValueEncodingContainer {\n        self\n    }\n\n    func unkeyedContainer() -> UnkeyedEncodingContainer {\n        // If an existing unkeyed container was already requested, return that one.\n        let topContainer: NSMutableArray\n        if self.canEncodeNewValue {\n            // We have not yet pushed a container at this level; do so here.\n            topContainer = self.storage.pushUnkeyedContainer()\n        } else {\n            guard let container = self.storage.containers.last as? NSMutableArray else {\n                preconditionFailure(\"Attempt to push new unkeyed encoding container when already previously encoded at this path.\")\n            }\n\n            topContainer = container\n        }\n\n        return _ParseEncoderUnkeyedEncodingContainer(\n            referencing: self,\n            codingPath: codingPath,\n            wrapping: topContainer\n        )\n    }\n\n    func deepFindAndReplaceParseObjects(_ value: Encodable) throws -> Encodable? {\n        var valueToEncode: Encodable?\n        if let pointer = value as? ParsePointer {\n            if let uniquePointer = self.uniquePointer,\n               uniquePointer.hasSameObjectId(as: pointer) {\n                throw ParseError(code: .unknownError,\n                                 message: \"Found a circular dependency when encoding.\")\n            }\n            valueToEncode = pointer\n        } else if let object = value as? Objectable {\n            if !batching || (batching && codingPath.last?.stringValue == \"body\"),\n               let pointer = try? PointerType(object) {\n                if let uniquePointer = self.uniquePointer,\n                   uniquePointer.hasSameObjectId(as: pointer) {\n                    throw ParseError(code: .unknownError,\n                                     message: \"Found a circular dependency when encoding.\")\n                }\n                valueToEncode = pointer\n            } else {\n                var object = object\n                if object.ACL == nil,\n                    let acl = try? ParseACL.defaultACL() {\n                    object.ACL = acl\n                }\n                let hashOfCurrentObject = try BaseObjectable.createHash(object)\n                valueToEncode = object\n                if let pointerForCurrentObject = self.objectsSavedBeforeThisOne?[hashOfCurrentObject] {\n                    valueToEncode = pointerForCurrentObject\n                } else if self.collectChildren {\n                    // New object needs to be saved before it can be pointed to\n                    self.newObjects.append(object)\n                } else if dictionary.count > 0 {\n                    // Only top level objects can be saved without a pointer\n                    throw ParseError(code: .unknownError, message: \"Error. Could not resolve unsaved object while encoding.\")\n                }\n            }\n        }\n        return valueToEncode\n    }\n\n    func deepFindAndReplaceParseFiles(_ value: ParseFile) throws -> Encodable? {\n        var valueToEncode: Encodable?\n        if value.isSaved {\n            if self.uniqueFiles.contains(value) {\n                throw ParseError(code: .unknownError, message: \"Found a circular dependency when encoding.\")\n            }\n            self.uniqueFiles.insert(value)\n            if !self.collectChildren {\n                valueToEncode = value\n            }\n        } else {\n            if self.collectChildren {\n                if let updatedFile = self.filesSavedBeforeThisOne?[value.id] {\n                    valueToEncode = updatedFile\n                } else {\n                    //New object needs to be saved before it can be stored\n                    self.newObjects.append(value)\n                }\n            } else if let currentFile = self.filesSavedBeforeThisOne?[value.id] {\n                valueToEncode = currentFile\n            } else if dictionary.count > 0 {\n                //Only top level objects can be saved without a pointer\n                throw ParseError(code: .unknownError, message: \"Error. Could not resolve unsaved file while encoding.\")\n            }\n        }\n        return valueToEncode\n    }\n}\n\n// MARK: _ParseEncoderKeyedEncodingContainer\nprivate struct _ParseEncoderKeyedEncodingContainer<Key: CodingKey>: KeyedEncodingContainerProtocol {\n    let encoder: _ParseEncoder\n    var codingPath: [CodingKey]\n    let container: NSMutableDictionary\n\n    init(referencing encoder: _ParseEncoder, codingPath: [CodingKey], wrapping container: NSMutableDictionary) {\n        self.encoder = encoder\n        self.codingPath = codingPath\n        self.container = container\n    }\n\n    // MARK: - KeyedEncodingContainerProtocol Methods\n    mutating func encodeNil(forKey key: Key) throws {\n        if self.encoder.skippedKeys.contains(key.stringValue) && !self.encoder.ignoreSkipKeys { return }\n        container[key.stringValue] = NSNull()\n    }\n    mutating func encode(_ value: Bool, forKey key: Key) throws {\n        if self.encoder.skippedKeys.contains(key.stringValue) && !self.encoder.ignoreSkipKeys { return }\n        self.container[key.stringValue] = self.encoder.box(value)\n    }\n    mutating func encode(_ value: Int, forKey key: Key) throws {\n        if self.encoder.skippedKeys.contains(key.stringValue) && !self.encoder.ignoreSkipKeys { return }\n        self.container[key.stringValue] = self.encoder.box(value)\n    }\n    mutating func encode(_ value: Int8, forKey key: Key) throws {\n        if self.encoder.skippedKeys.contains(key.stringValue) && !self.encoder.ignoreSkipKeys { return }\n        self.container[key.stringValue] = self.encoder.box(value)\n    }\n    mutating func encode(_ value: Int16, forKey key: Key) throws {\n        if self.encoder.skippedKeys.contains(key.stringValue) && !self.encoder.ignoreSkipKeys { return }\n        self.container[key.stringValue] = self.encoder.box(value)\n    }\n    mutating func encode(_ value: Int32, forKey key: Key) throws {\n        if self.encoder.skippedKeys.contains(key.stringValue) && !self.encoder.ignoreSkipKeys { return }\n        self.container[key.stringValue] = self.encoder.box(value)\n    }\n    mutating func encode(_ value: Int64, forKey key: Key) throws {\n        if self.encoder.skippedKeys.contains(key.stringValue) && !self.encoder.ignoreSkipKeys { return }\n        self.container[key.stringValue] = self.encoder.box(value)\n    }\n    mutating func encode(_ value: UInt, forKey key: Key) throws {\n        if self.encoder.skippedKeys.contains(key.stringValue) && !self.encoder.ignoreSkipKeys { return }\n        self.container[key.stringValue] = self.encoder.box(value)\n    }\n    mutating func encode(_ value: UInt8, forKey key: Key) throws {\n        if self.encoder.skippedKeys.contains(key.stringValue) && !self.encoder.ignoreSkipKeys { return }\n        self.container[key.stringValue] = self.encoder.box(value)\n    }\n    mutating func encode(_ value: UInt16, forKey key: Key) throws {\n        if self.encoder.skippedKeys.contains(key.stringValue) && !self.encoder.ignoreSkipKeys { return }\n        self.container[key.stringValue] = self.encoder.box(value)\n    }\n    mutating func encode(_ value: UInt32, forKey key: Key) throws {\n        if self.encoder.skippedKeys.contains(key.stringValue) && !self.encoder.ignoreSkipKeys { return }\n        self.container[key.stringValue] = self.encoder.box(value)\n    }\n    mutating func encode(_ value: UInt64, forKey key: Key) throws {\n        if self.encoder.skippedKeys.contains(key.stringValue) && !self.encoder.ignoreSkipKeys { return }\n        self.container[key.stringValue] = self.encoder.box(value)\n    }\n    mutating func encode(_ value: String, forKey key: Key) throws {\n        if self.encoder.skippedKeys.contains(key.stringValue) && !self.encoder.ignoreSkipKeys { return }\n        self.container[key.stringValue] = self.encoder.box(value)\n    }\n    mutating func encode(_ value: Float, forKey key: Key) throws {\n        // Since the float may be invalid and throw, the coding path needs to contain this key.\n        if self.encoder.skippedKeys.contains(key.stringValue) && !self.encoder.ignoreSkipKeys { return }\n        self.encoder.codingPath.append(key)\n        defer { self.encoder.codingPath.removeLast() }\n        self.container[key.stringValue] = try self.encoder.box(value)\n    }\n\n    mutating func encode(_ value: Double, forKey key: Key) throws {\n        // Since the double may be invalid and throw, the coding path needs to contain this key.\n        if self.encoder.skippedKeys.contains(key.stringValue) && !self.encoder.ignoreSkipKeys { return }\n        self.encoder.codingPath.append(key)\n        defer { self.encoder.codingPath.removeLast() }\n        self.container[key.stringValue] = try self.encoder.box(value)\n    }\n\n    mutating func encode<T>(_ value: T, forKey key: Key) throws where T: Encodable {\n        if self.encoder.skippedKeys.contains(key.stringValue) && !self.encoder.ignoreSkipKeys { return }\n\n        var valueToEncode: Encodable = value\n        if ((value as? Objectable) != nil)\n            || ((value as? ParsePointer) != nil) {\n            if let replacedObject = try self.encoder.deepFindAndReplaceParseObjects(value) {\n                valueToEncode = replacedObject\n            }\n        } else if let parsePointers = value as? [ParsePointer] {\n            _ = try parsePointers.compactMap { try self.encoder.deepFindAndReplaceParseObjects($0) }\n        } else if let parseObjects = value as? [Objectable] {\n            let replacedObjects = try parseObjects.compactMap {\n                try self.encoder.deepFindAndReplaceParseObjects($0)\n            }\n            if replacedObjects.count > 0 {\n                self.encoder.codingPath.append(key)\n                defer { self.encoder.codingPath.removeLast() }\n                self.container[key.stringValue] = try replacedObjects.map { try self.encoder.box($0) }\n                return\n            }\n        } else if let parseFile = value as? ParseFile {\n            if let replacedObject = try self.encoder.deepFindAndReplaceParseFiles(parseFile) {\n                valueToEncode = replacedObject\n            }\n        } else if let parseFiles = value as? [ParseFile] {\n            let replacedFiles = try parseFiles.compactMap { try self.encoder.deepFindAndReplaceParseFiles($0) }\n            if replacedFiles.count > 0 {\n                self.encoder.codingPath.append(key)\n                defer { self.encoder.codingPath.removeLast() }\n                self.container[key.stringValue] = try replacedFiles.map { try self.encoder.box($0) }\n                return\n            }\n        }\n\n        self.encoder.codingPath.append(key)\n        defer { self.encoder.codingPath.removeLast() }\n        self.container[key.stringValue] = try self.encoder.box(valueToEncode)\n    }\n\n    mutating func nestedContainer<NestedKey>(\n        keyedBy keyType: NestedKey.Type,\n        forKey key: Key\n    ) -> KeyedEncodingContainer<NestedKey> where NestedKey: CodingKey {\n        let containerKey = key.stringValue\n        let dictionary: NSMutableDictionary\n\n        if let existingContainer = self.container[containerKey] {\n            precondition(\n                existingContainer is NSMutableDictionary,\n                \"Attempt to re-encode into nested KeyedEncodingContainer<\\(Key.self)> for key \\\"\\(containerKey)\\\" is invalid: non-keyed container already encoded for this key\"\n            )\n            dictionary = existingContainer as! NSMutableDictionary\n        } else {\n            dictionary = NSMutableDictionary()\n            self.container[containerKey] = dictionary\n        }\n\n        self.codingPath.append(key)\n        defer { self.codingPath.removeLast() }\n\n        let container = _ParseEncoderKeyedEncodingContainer<NestedKey>(referencing: self.encoder, codingPath: self.codingPath,\n                                                                       wrapping: dictionary)\n        return KeyedEncodingContainer(container)\n    }\n\n    mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer {\n        let containerKey = key.stringValue\n        let array: NSMutableArray\n        if let existingContainer = self.container[containerKey] {\n            precondition(\n                existingContainer is NSMutableArray,\n                \"Attempt to re-encode into nested UnkeyedEncodingContainer for key \\\"\\(containerKey)\\\" is invalid: keyed container/single value already encoded for this key\"\n            )\n            array = existingContainer as! NSMutableArray\n        } else {\n            array = NSMutableArray()\n            self.container[containerKey] = array\n        }\n\n        self.codingPath.append(key)\n        defer { self.codingPath.removeLast() }\n        return _ParseEncoderUnkeyedEncodingContainer(\n            referencing: self.encoder,\n            codingPath: codingPath,\n            wrapping: array\n        )\n    }\n\n    mutating func superEncoder() -> Encoder {\n        _ParseReferencingEncoder(referencing: self.encoder, key: _JSONKey.super, wrapping: self.container, skippingKeys: self.encoder.skippedKeys, collectChildren: self.encoder.collectChildren, objectsSavedBeforeThisOne: self.encoder.objectsSavedBeforeThisOne, filesSavedBeforeThisOne: self.encoder.filesSavedBeforeThisOne)\n    }\n\n    mutating func superEncoder(forKey key: Key) -> Encoder {\n        _ParseReferencingEncoder(referencing: self.encoder, key: key, wrapping: self.container, skippingKeys: self.encoder.skippedKeys, collectChildren: self.encoder.collectChildren, objectsSavedBeforeThisOne: self.encoder.objectsSavedBeforeThisOne, filesSavedBeforeThisOne: self.encoder.filesSavedBeforeThisOne)\n    }\n}\n\n// MARK: _ParseEncoderUnkeyedEncodingContainer\nprivate struct _ParseEncoderUnkeyedEncodingContainer: UnkeyedEncodingContainer {\n    /// A reference to the encoder we're writing to.\n    let encoder: _ParseEncoder\n    var codingPath: [CodingKey]\n    let container: NSMutableArray\n\n    /// The number of elements encoded into the container.\n    public var count: Int {\n        return self.container.count\n    }\n\n    init(referencing encoder: _ParseEncoder, codingPath: [CodingKey], wrapping container: NSMutableArray) {\n        self.encoder = encoder\n        self.codingPath = codingPath\n        self.container = container\n    }\n\n    // MARK: - UnkeyedEncodingContainer Methods\n\n    public mutating func encodeNil()             throws { self.container.add(NSNull()) }\n    public mutating func encode(_ value: Bool)   throws { self.container.add(self.encoder.box(value)) }\n    public mutating func encode(_ value: Int)    throws { self.container.add(self.encoder.box(value)) }\n    public mutating func encode(_ value: Int8)   throws { self.container.add(self.encoder.box(value)) }\n    public mutating func encode(_ value: Int16)  throws { self.container.add(self.encoder.box(value)) }\n    public mutating func encode(_ value: Int32)  throws { self.container.add(self.encoder.box(value)) }\n    public mutating func encode(_ value: Int64)  throws { self.container.add(self.encoder.box(value)) }\n    public mutating func encode(_ value: UInt)   throws { self.container.add(self.encoder.box(value)) }\n    public mutating func encode(_ value: UInt8)  throws { self.container.add(self.encoder.box(value)) }\n    public mutating func encode(_ value: UInt16) throws { self.container.add(self.encoder.box(value)) }\n    public mutating func encode(_ value: UInt32) throws { self.container.add(self.encoder.box(value)) }\n    public mutating func encode(_ value: UInt64) throws { self.container.add(self.encoder.box(value)) }\n    public mutating func encode(_ value: String) throws { self.container.add(self.encoder.box(value)) }\n\n    public mutating func encode(_ value: Float)  throws {\n        // Since the float may be invalid and throw, the coding path needs to contain this key.\n        self.encoder.codingPath.append(_JSONKey(index: self.count))\n        defer { self.encoder.codingPath.removeLast() }\n        self.container.add(try self.encoder.box(value))\n    }\n\n    public mutating func encode(_ value: Double) throws {\n        // Since the double may be invalid and throw, the coding path needs to contain this key.\n        self.encoder.codingPath.append(_JSONKey(index: self.count))\n        defer { self.encoder.codingPath.removeLast() }\n        self.container.add(try self.encoder.box(value))\n    }\n\n    public mutating func encode<T : Encodable>(_ value: T) throws {\n        self.encoder.codingPath.append(_JSONKey(index: self.count))\n        defer { self.encoder.codingPath.removeLast() }\n        self.container.add(try self.encoder.box(value))\n    }\n\n    public mutating func nestedContainer<NestedKey>(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer<NestedKey> {\n        self.codingPath.append(_JSONKey(index: self.count))\n        defer { self.codingPath.removeLast() }\n\n        let dictionary = NSMutableDictionary()\n        self.container.add(dictionary)\n\n        let container = _ParseEncoderKeyedEncodingContainer<NestedKey>(referencing: self.encoder, codingPath: self.codingPath, wrapping: dictionary)\n        return KeyedEncodingContainer(container)\n    }\n\n    public mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer {\n        self.codingPath.append(_JSONKey(index: self.count))\n        defer { self.codingPath.removeLast() }\n\n        let array = NSMutableArray()\n        self.container.add(array)\n        return _ParseEncoderUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: array)\n    }\n\n    public mutating func superEncoder() -> Encoder {\n        return _ParseReferencingEncoder(referencing: self.encoder, at: self.container.count, wrapping: self.container, skippingKeys: self.encoder.skippedKeys, collectChildren: self.encoder.collectChildren, objectsSavedBeforeThisOne: self.encoder.objectsSavedBeforeThisOne, filesSavedBeforeThisOne: self.encoder.filesSavedBeforeThisOne)\n    }\n}\n\nextension _ParseEncoder : SingleValueEncodingContainer {\n    // MARK: - SingleValueEncodingContainer Methods\n\n    private func assertCanEncodeNewValue() {\n        precondition(self.canEncodeNewValue, \"Attempt to encode value through single value container when previously value already encoded.\")\n    }\n\n    func encodeNil() throws {\n        assertCanEncodeNewValue()\n        self.storage.push(container: NSNull())\n    }\n\n    func encode(_ value: Bool) throws {\n        assertCanEncodeNewValue()\n        self.storage.push(container: self.box(value))\n    }\n\n    func encode(_ value: Int) throws {\n        assertCanEncodeNewValue()\n        self.storage.push(container: self.box(value))\n    }\n\n    func encode(_ value: Int8) throws {\n        assertCanEncodeNewValue()\n        self.storage.push(container: self.box(value))\n    }\n\n    func encode(_ value: Int16) throws {\n        assertCanEncodeNewValue()\n        self.storage.push(container: self.box(value))\n    }\n\n    func encode(_ value: Int32) throws {\n        assertCanEncodeNewValue()\n        self.storage.push(container: self.box(value))\n    }\n\n    func encode(_ value: Int64) throws {\n        assertCanEncodeNewValue()\n        self.storage.push(container: self.box(value))\n    }\n\n    func encode(_ value: UInt) throws {\n        assertCanEncodeNewValue()\n        self.storage.push(container: self.box(value))\n    }\n\n    func encode(_ value: UInt8) throws {\n        assertCanEncodeNewValue()\n        self.storage.push(container: self.box(value))\n    }\n\n    func encode(_ value: UInt16) throws {\n        assertCanEncodeNewValue()\n        self.storage.push(container: self.box(value))\n    }\n\n    func encode(_ value: UInt32) throws {\n        assertCanEncodeNewValue()\n        self.storage.push(container: self.box(value))\n    }\n\n    func encode(_ value: UInt64) throws {\n        assertCanEncodeNewValue()\n        self.storage.push(container: self.box(value))\n    }\n\n    func encode(_ value: String) throws {\n        assertCanEncodeNewValue()\n        self.storage.push(container: self.box(value))\n    }\n\n    func encode(_ value: Float) throws {\n        assertCanEncodeNewValue()\n        try self.storage.push(container: self.box(value))\n    }\n\n    func encode(_ value: Double) throws {\n        assertCanEncodeNewValue()\n        try self.storage.push(container: self.box(value))\n    }\n\n    func encode<T : Encodable>(_ value: T) throws {\n        assertCanEncodeNewValue()\n        try self.storage.push(container: self.box(value))\n    }\n}\n\n// MARK: - Concrete Value Representations\n// swiftlint:disable force_cast\nextension _ParseEncoder {\n    /// Returns the given value boxed in a container appropriate for pushing onto the container stack.\n    func box(_ value: Bool)   -> NSObject { return NSNumber(value: value) }\n    func box(_ value: Int)    -> NSObject { return NSNumber(value: value) }\n    func box(_ value: Int8)   -> NSObject { return NSNumber(value: value) }\n    func box(_ value: Int16)  -> NSObject { return NSNumber(value: value) }\n    func box(_ value: Int32)  -> NSObject { return NSNumber(value: value) }\n    func box(_ value: Int64)  -> NSObject { return NSNumber(value: value) }\n    func box(_ value: UInt)   -> NSObject { return NSNumber(value: value) }\n    func box(_ value: UInt8)  -> NSObject { return NSNumber(value: value) }\n    func box(_ value: UInt16) -> NSObject { return NSNumber(value: value) }\n    func box(_ value: UInt32) -> NSObject { return NSNumber(value: value) }\n    func box(_ value: UInt64) -> NSObject { return NSNumber(value: value) }\n    func box(_ value: String) -> NSObject { return NSString(string: value) }\n\n    func box(_ float: Float) throws -> NSObject {\n        guard !float.isInfinite && !float.isNaN else {\n            guard case let .convertToString(positiveInfinity: posInfString,\n                                            negativeInfinity: negInfString,\n                                            nan: nanString) = self.options.nonConformingFloatEncodingStrategy else {\n                throw EncodingError._invalidFloatingPointValue(float, at: codingPath)\n            }\n\n            if float == Float.infinity {\n                return NSString(string: posInfString)\n            } else if float == -Float.infinity {\n                return NSString(string: negInfString)\n            } else {\n                return NSString(string: nanString)\n            }\n        }\n\n        return NSNumber(value: float)\n    }\n\n    func box(_ double: Double) throws -> NSObject {\n        guard !double.isInfinite && !double.isNaN else {\n            guard case let .convertToString(positiveInfinity: posInfString,\n                                            negativeInfinity: negInfString,\n                                            nan: nanString) = self.options.nonConformingFloatEncodingStrategy else {\n                throw EncodingError._invalidFloatingPointValue(double, at: codingPath)\n            }\n\n            if double == Double.infinity {\n                return NSString(string: posInfString)\n            } else if double == -Double.infinity {\n                return NSString(string: negInfString)\n            } else {\n                return NSString(string: nanString)\n            }\n        }\n\n        return NSNumber(value: double)\n    }\n\n    func box(_ date: Date) throws -> NSObject {\n        switch self.options.dateEncodingStrategy {\n        case .deferredToDate:\n            // Must be called with a surrounding with(pushedKey:) call.\n            // Dates encode as single-value objects; this cannot both throw and push a container, so no need to catch the error.\n            try date.encode(to: self)\n            return self.storage.popContainer()\n\n        case .secondsSince1970:\n            return NSNumber(value: date.timeIntervalSince1970)\n\n        case .millisecondsSince1970:\n            return NSNumber(value: 1000.0 * date.timeIntervalSince1970)\n\n        case .iso8601:\n            if #available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) {\n                return NSString(string: _iso8601Formatter.string(from: date))\n            } else {\n                fatalError(\"ISO8601DateFormatter is unavailable on this platform.\")\n            }\n\n        case .formatted(let formatter):\n            return NSString(string: formatter.string(from: date))\n\n        case .custom(let closure):\n            let depth = self.storage.count\n            do {\n                try closure(date, self)\n            } catch {\n                // If the value pushed a container before throwing, pop it back off to restore state.\n                if self.storage.count > depth {\n                    let _ = self.storage.popContainer()\n                }\n\n                throw error\n            }\n\n            guard self.storage.count > depth else {\n                // The closure did not encode anything. Return the default keyed container.\n                return NSDictionary()\n            }\n\n            // We can pop because the closure encoded something.\n            return self.storage.popContainer()\n        @unknown default:\n            fatalError(\"Unhandled\")\n        }\n    }\n\n    func box(_ data: Data) throws -> NSObject {\n        switch self.options.dataEncodingStrategy {\n        case .deferredToData:\n            // Must be called with a surrounding with(pushedKey:) call.\n            let depth = self.storage.count\n            do {\n                try data.encode(to: self)\n            } catch {\n                // If the value pushed a container before throwing, pop it back off to restore state.\n                // This should not be possible for Data (which encodes as an array of bytes), but it cannot hurt to catch a failure.\n                if self.storage.count > depth {\n                    let _ = self.storage.popContainer()\n                }\n\n                throw error\n            }\n\n            return self.storage.popContainer()\n\n        case .base64:\n            return NSString(string: data.base64EncodedString())\n\n        case .custom(let closure):\n            let depth = self.storage.count\n            do {\n                try closure(data, self)\n            } catch {\n                // If the value pushed a container before throwing, pop it back off to restore state.\n                if self.storage.count > depth {\n                    let _ = self.storage.popContainer()\n                }\n\n                throw error\n            }\n\n            guard self.storage.count > depth else {\n                // The closure did not encode anything. Return the default keyed container.\n                return NSDictionary()\n            }\n\n            // We can pop because the closure encoded something.\n            return self.storage.popContainer()\n        @unknown default:\n            fatalError(\"Unhandled\")\n        }\n    }\n\n    func box(_ dict: [String : Encodable]) throws -> NSObject? {\n        let depth = self.storage.count\n        let result = self.storage.pushKeyedContainer()\n        do {\n            for (key, value) in dict {\n                self.codingPath.append(_JSONKey(stringValue: key, intValue: nil))\n                defer { self.codingPath.removeLast() }\n                result[key] = try box(value)\n            }\n        } catch {\n            // If the value pushed a container before throwing, pop it back off to restore state.\n            if self.storage.count > depth {\n                let _ = self.storage.popContainer()\n            }\n\n            throw error\n        }\n\n        // The top container should be a new container.\n        guard self.storage.count > depth else {\n            return nil\n        }\n\n        return self.storage.popContainer()\n    }\n\n    func box(_ value: Encodable) throws -> NSObject {\n        return try self.box_(value) ?? NSDictionary()\n    }\n\n    // swiftlint:disable:next line_length\n    // This method is called \"box_\" instead of \"box\" to disambiguate it from the overloads. Because the return type here is different from all of the \"box\" overloads (and is more general), any \"box\" calls in here would call back into \"box\" recursively instead of calling the appropriate overload, which is not what we want.\n    func box_(_ value: Encodable) throws -> NSObject? {\n        // Disambiguation between variable and function is required due to\n        // issue tracked at: https://bugs.swift.org/browse/SR-1846\n        let type = Swift.type(of: value)\n        if type == Date.self || type == NSDate.self {\n            // Respect Date encoding strategy\n            return try self.box((value as! Date))\n        } else if type == Data.self || type == NSData.self {\n            // Respect Data encoding strategy\n            // swiftlint:disable:next force_cast\n            return try self.box((value as! Data))\n        } else if type == URL.self || type == NSURL.self {\n            // Encode URLs as single strings.\n            // swiftlint:disable:next force_cast\n            return self.box((value as! URL).absoluteString)\n        } else if type == Decimal.self || type == NSDecimalNumber.self {\n            // JSONSerialization can natively handle NSDecimalNumber.\n            // swiftlint:disable:next force_cast\n            return (value as! NSDecimalNumber)\n        } else if value is _JSONStringDictionaryEncodableMarker {\n            // COREY: DON'T remove the force cast, it will crash the app\n            // swiftlint:disable:next force_cast\n            return try self.box(value as! [String : Encodable])\n        } else if value is ParsePointer {\n            ignoreSkipKeys = true\n        }\n\n        // The value should request a container from the __JSONEncoder.\n        let depth = self.storage.count\n        do {\n            try value.encode(to: self)\n            ignoreSkipKeys = false\n        } catch {\n            // If the value pushed a container before throwing, pop it back off to restore state.\n            if self.storage.count > depth {\n                let _ = self.storage.popContainer()\n            }\n\n            throw error\n        }\n\n        // The top container should be a new container.\n        guard self.storage.count > depth else {\n            return nil\n        }\n\n        return self.storage.popContainer()\n    }\n}\n\n// MARK: - _ParseReferencingEncoder\n// swiftlint:disable line_length\n/// __JSONReferencingEncoder is a special subclass of __JSONEncoder which has its own storage, but references the contents of a different encoder.\n/// It's used in superEncoder(), which returns a new encoder for encoding a superclass -- the lifetime of the encoder should not escape the scope it is created in, but it does not necessarily know when it is done being used (to write to the original container).\nprivate class _ParseReferencingEncoder: _ParseEncoder {\n    // MARK: Reference types.\n\n    /// The type of container we're referencing.\n    private enum Reference {\n        /// Referencing a specific index in an array container.\n        case array(NSMutableArray, Int)\n\n        /// Referencing a specific key in a dictionary container.\n        case dictionary(NSMutableDictionary, String)\n    }\n\n    // MARK: - Properties\n\n    /// The encoder we're referencing.\n    let encoder: _ParseEncoder\n\n    /// The container reference itself.\n    private let reference: Reference\n\n    // MARK: - Initialization\n\n    /// Initializes `self` by referencing the given array container in the given encoder.\n    init(referencing encoder: _ParseEncoder, at index: Int, wrapping array: NSMutableArray, skippingKeys: Set<String>, collectChildren: Bool, objectsSavedBeforeThisOne: [String: PointerType]?, filesSavedBeforeThisOne: [UUID: ParseFile]?) {\n        self.encoder = encoder\n        self.reference = .array(array, index)\n        super.init(codingPath: encoder.codingPath, dictionary: NSMutableDictionary(), skippingKeys: skippingKeys)\n        self.collectChildren = collectChildren\n        self.objectsSavedBeforeThisOne = objectsSavedBeforeThisOne\n        self.filesSavedBeforeThisOne = filesSavedBeforeThisOne\n        self.codingPath.append(_JSONKey(index: index))\n    }\n\n    /// Initializes `self` by referencing the given dictionary container in the given encoder.\n    init(referencing encoder: _ParseEncoder, key: CodingKey, wrapping dictionary: NSMutableDictionary, skippingKeys: Set<String>, collectChildren: Bool, objectsSavedBeforeThisOne: [String: PointerType]?, filesSavedBeforeThisOne: [UUID: ParseFile]?) {\n        self.encoder = encoder\n        self.reference = .dictionary(dictionary, key.stringValue)\n        super.init(codingPath: encoder.codingPath, dictionary: dictionary, skippingKeys: skippingKeys)\n        self.collectChildren = collectChildren\n        self.objectsSavedBeforeThisOne = objectsSavedBeforeThisOne\n        self.filesSavedBeforeThisOne = filesSavedBeforeThisOne\n        self.codingPath.append(key)\n    }\n\n    // MARK: - Coding Path Operations\n\n    override var canEncodeNewValue: Bool {\n        // With a regular encoder, the storage and coding path grow together.\n        // A referencing encoder, however, inherits its parents coding path, as well as the key it was created for.\n        // We have to take this into account.\n        return self.storage.count == self.codingPath.count - self.encoder.codingPath.count - 1\n    }\n\n    // MARK: - Deinitialization\n\n    // Finalizes `self` by writing the contents of our storage to the referenced encoder's storage.\n    deinit {\n        let value: Any\n        switch self.storage.count {\n        case 0: value = NSDictionary()\n        case 1: value = self.storage.popContainer()\n        default: fatalError(\"Referencing encoder deallocated with multiple containers on stack.\")\n        }\n\n        switch self.reference {\n        case .array(let array, let index):\n            array.insert(value, at: index)\n\n        case .dictionary(let dictionary, let key):\n            dictionary[NSString(string: key)] = value\n        }\n    }\n}\n\n// MARK: - Encoding Storage and Containers\n\ninternal struct _ParseEncodingStorage {\n    // MARK: Properties\n\n    /// The container stack.\n    /// Elements may be any one of the JSON types (NSNull, NSNumber, NSString, NSArray, NSDictionary).\n    private(set) var containers: [NSObject] = []\n\n    // MARK: - Initialization\n\n    /// Initializes `self` with no containers.\n    init() {}\n\n    // MARK: - Modifying the Stack\n\n    var count: Int {\n        return self.containers.count\n    }\n\n    mutating func pushKeyedContainer() -> NSMutableDictionary {\n        let dictionary = NSMutableDictionary()\n        self.containers.append(dictionary)\n        return dictionary\n    }\n\n    mutating func pushUnkeyedContainer() -> NSMutableArray {\n        let array = NSMutableArray()\n        self.containers.append(array)\n        return array\n    }\n\n    mutating func push(container: __owned NSObject) {\n        self.containers.append(container)\n    }\n\n    mutating func popContainer() -> NSObject {\n        precondition(!self.containers.isEmpty, \"Empty container stack.\")\n        return self.containers.popLast()!\n    }\n}\n\n//===----------------------------------------------------------------------===//\n// Error Utilities\n//===----------------------------------------------------------------------===//\n\nextension EncodingError {\n    /// Returns a `.invalidValue` error describing the given invalid floating-point value.\n    ///\n    ///\n    /// - parameter value: The value that was invalid to encode.\n    /// - parameter path: The path of `CodingKey`s taken to encode this value.\n    /// - returns: An `EncodingError` with the appropriate path and debug description.\n    fileprivate static func _invalidFloatingPointValue<T : FloatingPoint>(_ value: T, at codingPath: [CodingKey]) -> EncodingError {\n        let valueDescription: String\n        if value == T.infinity {\n            valueDescription = \"\\(T.self).infinity\"\n        } else if value == -T.infinity {\n            valueDescription = \"-\\(T.self).infinity\"\n        } else {\n            valueDescription = \"\\(T.self).nan\"\n        }\n\n        let debugDescription = \"Unable to encode \\(valueDescription) directly in JSON. Use JSONEncoder.NonConformingFloatEncodingStrategy.convertToString to specify how the value should be encoded.\"\n        return .invalidValue(value, EncodingError.Context(codingPath: codingPath, debugDescription: debugDescription))\n    }\n}\n\n//===----------------------------------------------------------------------===//\n// Shared Key Types\n//===----------------------------------------------------------------------===//\n\nprivate struct _JSONKey : CodingKey {\n    public var stringValue: String\n    public var intValue: Int?\n\n    public init?(stringValue: String) {\n        self.stringValue = stringValue\n        self.intValue = nil\n    }\n\n    public init?(intValue: Int) {\n        self.stringValue = \"\\(intValue)\"\n        self.intValue = intValue\n    }\n\n    public init(stringValue: String, intValue: Int?) {\n        self.stringValue = stringValue\n        self.intValue = intValue\n    }\n\n    init(index: Int) {\n        self.stringValue = \"Index \\(index)\"\n        self.intValue = index\n    }\n\n    static let `super` = _JSONKey(stringValue: \"super\")!\n}\n\n//===----------------------------------------------------------------------===//\n// Shared ISO8601 Date Formatter\n//===----------------------------------------------------------------------===//\n// swiftlint:disable:next line_length\n// NOTE: This value is implicitly lazy and _must_ be lazy. We're compiled against the latest SDK (w/ ISO8601DateFormatter), but linked against whichever Foundation the user has. ISO8601DateFormatter might not exist, so we better not hit this code path on an older OS.\n@available(macOS 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *)\nprivate var _iso8601Formatter: ISO8601DateFormatter = {\n    let formatter = ISO8601DateFormatter()\n    formatter.formatOptions = .withInternetDateTime\n    return formatter\n}()\n"
  },
  {
    "path": "Sources/ParseSwift/Documentation.docc/ParseSwift.md",
    "content": "# ``ParseSwift``\nA pure Swift library that gives you access to the powerful Parse Server backend from your Swift applications.\n\n## Overview\n![Parse logo](parse-swift.png)\nFor more information about the Parse Platform and its features, see the public [documentation](https://docs.parseplatform.org). The ParseSwift SDK is not a port of the [Parse-SDK-iOS-OSX SDK](https://github.com/parse-community/Parse-SDK-iOS-OSX) and though some of it may feel familiar, it is not backwards compatible and is designed using [protocol oriented programming (POP) and value types](https://www.pluralsight.com/guides/protocol-oriented-programming-in-swift) instead of OOP and reference types. You can learn more about POP by watching [Protocol-Oriented Programming in Swift](https://developer.apple.com/videos/play/wwdc2015/408/) or [Protocol and Value Oriented Programming in UIKit Apps](https://developer.apple.com/videos/play/wwdc2016/419/) videos from previous WWDC's. For more details about ParseSwift, visit the [api documentation](http://parseplatform.org/Parse-Swift/release/documentation/parseswift/).\n\nTo learn how to use or experiment with ParseSwift, you can run and edit the [ParseSwift.playground](https://github.com/parse-community/Parse-Swift/tree/main/ParseSwift.playground/Pages). You can use the parse-server in [this repo](https://github.com/netreconlab/parse-hipaa/tree/parse-swift) which has docker compose files (`docker-compose up` gives you a working server) configured to connect with the playground files, has [Parse Dashboard](https://github.com/parse-community/parse-dashboard), and can be used with MongoDB or PostgreSQL. You can also configure the Swift Playgrounds to work with your own Parse Server by editing the configuation in [Common.swift](https://github.com/parse-community/Parse-Swift/blob/e9ba846c399257100b285d25d2bd055628b13b4b/ParseSwift.playground/Sources/Common.swift#L4-L19). To learn more, check out [CONTRIBUTING.md](https://github.com/parse-community/Parse-Swift/blob/main/CONTRIBUTING.md#swift-playgrounds).\n\n## Topics\n\n### Configure SDK\n\n- ``ParseSwift/initialize(configuration:)``\n- ``ParseSwift/initialize(applicationId:clientKey:masterKey:serverURL:liveQueryServerURL:requiringCustomObjectIds:usingTransactions:usingEqualQueryConstraint:usingPostForQuery:primitiveStore:requestCachePolicy:cacheMemoryCapacity:cacheDiskCapacity:usingDataProtectionKeychain:deletingKeychainIfNeeded:httpAdditionalHeaders:maxConnectionAttempts:parseFileTransfer:authentication:)``\n- ``ParseSwift/initialize(applicationId:clientKey:masterKey:serverURL:liveQueryServerURL:allowingCustomObjectIds:usingTransactions:usingEqualQueryConstraint:usingPostForQuery:keyValueStore:requestCachePolicy:cacheMemoryCapacity:cacheDiskCapacity:usingDataProtectionKeychain:deletingKeychainIfNeeded:httpAdditionalHeaders:maxConnectionAttempts:parseFileTransfer:authentication:)``\n- ``ParseSwift/initialize(applicationId:clientKey:masterKey:serverURL:liveQueryServerURL:allowingCustomObjectIds:usingTransactions:usingEqualQueryConstraint:usingPostForQuery:keyValueStore:requestCachePolicy:cacheMemoryCapacity:cacheDiskCapacity:migratingFromObjcSDK:usingDataProtectionKeychain:deletingKeychainIfNeeded:httpAdditionalHeaders:maxConnectionAttempts:parseFileTransfer:authentication:)``\n- ``ParseSwift/configuration``\n- ``ParseSwift/setAccessGroup(_:synchronizeAcrossDevices:)``\n- ``ParseSwift/updateAuthentication(_:)``\n- ``ParseSwift/clearCache()``\n- ``ParseSwift/deleteObjectiveCKeychain()``\n"
  },
  {
    "path": "Sources/ParseSwift/Documentation.docc/ParseSwift.tutorial",
    "content": "@Tutorials(name: \"ParseSwift\") {\n    @Intro(title: \"Welcome to ParseSwift\") {\n        \n    }\n    \n    @Chapter(name: \"Your first Object\") {\n        \n        @Image(source: parse-swift.png, alt: \"Parse image\")\n        \n        @TutorialReference(tutorial: \"doc:Your-First-Object\")\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Documentation.docc/Your First Object.tutorial",
    "content": "@Tutorial(time: 1) {\n    @Intro(title: \"Your First Object\") {\n        \n    }\n    \n    @Section(title: \"Check server health\") {\n        @Steps {\n            \n            @Step {\n                Check your server health.\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Extensions/Data.swift",
    "content": "//\n//  Data.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 2/14/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n// Credit to: https://stackoverflow.com/questions/39075043/how-to-convert-data-to-hex-string-in-swift\ninternal extension Data {\n    struct HexEncodingOptions: OptionSet {\n        let rawValue: Int\n        static let upperCase = HexEncodingOptions(rawValue: 1 << 0)\n    }\n\n    func hexEncodedString(options: HexEncodingOptions = []) -> String {\n        let hexDigits = options.contains(.upperCase) ? \"0123456789ABCDEF\" : \"0123456789abcdef\"\n        if #available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *) {\n            let utf8Digits = Array(hexDigits.utf8)\n            return String(unsafeUninitializedCapacity: 2 * count) { (ptr) -> Int in\n                var mutablePtr = ptr.baseAddress!\n                for byte in self {\n                    mutablePtr[0] = utf8Digits[Int(byte / 16)]\n                    mutablePtr[1] = utf8Digits[Int(byte % 16)]\n                    mutablePtr += 2\n                }\n                return 2 * count\n            }\n        } else {\n            let utf16Digits = Array(hexDigits.utf16)\n            var chars: [unichar] = []\n            chars.reserveCapacity(2 * count)\n            for byte in self {\n                chars.append(utf16Digits[Int(byte / 16)])\n                chars.append(utf16Digits[Int(byte % 16)])\n            }\n            return String(utf16CodeUnits: chars, count: chars.count)\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Extensions/Date.swift",
    "content": "//\n//  Date.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 11/4/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n// MARK: Date\ninternal extension Date {\n    var parseFormatted: String {\n        ParseCoding.dateFormatter.string(from: self)\n    }\n\n    var parseRepresentation: [String: String] {\n        [\"__type\": \"Date\", \"iso\": parseFormatted]\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Extensions/Dictionary.swift",
    "content": "//\n//  Dictionary.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 7/14/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\ninternal extension Dictionary where Key == String, Value == String? {\n    func getURLQueryItems() -> [URLQueryItem] {\n        sorted { $0.key < $1.key }.map { (key, value) -> URLQueryItem in\n            URLQueryItem(name: key, value: value)\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Extensions/Encodable.swift",
    "content": "//\n//  Encodable.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 11/4/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\ninternal extension Encodable {\n    func isEqual(_ other: Encodable?) -> Bool {\n        guard let lhsData = try? ParseCoding.parseEncoder().encode(self),\n              let lhsString = String(data: lhsData, encoding: .utf8),\n              let other = other,\n              let rhsData = try? ParseCoding.parseEncoder().encode(other),\n              let rhsString = String(data: rhsData, encoding: .utf8) else {\n         return false\n        }\n        return lhsString == rhsString\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Extensions/URLCache.swift",
    "content": "//\n//  URLCache.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 7/17/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\n\ninternal extension URLCache {\n    static let parse: URLCache = {\n        guard let cacheURL = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first else {\n            return URLCache(memoryCapacity: Parse.configuration.cacheMemoryCapacity,\n                            diskCapacity: Parse.configuration.cacheDiskCapacity,\n                            diskPath: nil)\n        }\n        let parseCacheDirectory = \"ParseCache\"\n        let diskURL = cacheURL.appendingPathComponent(parseCacheDirectory, isDirectory: true)\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        return URLCache(memoryCapacity: Parse.configuration.cacheMemoryCapacity,\n                        diskCapacity: Parse.configuration.cacheDiskCapacity,\n                        directory: diskURL)\n        #else\n        return URLCache(memoryCapacity: Parse.configuration.cacheMemoryCapacity,\n                        diskCapacity: Parse.configuration.cacheDiskCapacity,\n                        diskPath: diskURL.absoluteString)\n        #endif\n    }()\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Extensions/URLSession.swift",
    "content": "//\n//  URLSession.swift\n//  ParseSwift\n//\n//  Original file, URLSession+sync.swift, created by Florent Vilmart on 17-09-24.\n//  Name change to URLSession.swift and support for sync/async by Corey Baker on 7/25/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\n\ninternal extension URLSession {\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    static var parse = URLSession.shared\n    #else\n    static var parse: URLSession = /* URLSession.shared */ {\n        if !Parse.configuration.isTestingSDK {\n            let configuration = URLSessionConfiguration.default\n            configuration.urlCache = URLCache.parse\n            configuration.requestCachePolicy = Parse.configuration.requestCachePolicy\n            configuration.httpAdditionalHeaders = Parse.configuration.httpAdditionalHeaders\n            return URLSession(configuration: configuration,\n                              delegate: Parse.sessionDelegate,\n                              delegateQueue: nil)\n        } else {\n            let session = URLSession.shared\n            session.configuration.urlCache = URLCache.parse\n            session.configuration.requestCachePolicy = Parse.configuration.requestCachePolicy\n            session.configuration.httpAdditionalHeaders = Parse.configuration.httpAdditionalHeaders\n            return session\n        }\n    }()\n    #endif\n\n    static func updateParseURLSession() {\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        if !Parse.configuration.isTestingSDK {\n            let configuration = URLSessionConfiguration.default\n            configuration.urlCache = URLCache.parse\n            configuration.requestCachePolicy = Parse.configuration.requestCachePolicy\n            configuration.httpAdditionalHeaders = Parse.configuration.httpAdditionalHeaders\n            Self.parse = URLSession(configuration: configuration,\n                                    delegate: Parse.sessionDelegate,\n                                    delegateQueue: nil)\n        } else {\n            let session = URLSession.shared\n            session.configuration.urlCache = URLCache.parse\n            session.configuration.requestCachePolicy = Parse.configuration.requestCachePolicy\n            session.configuration.httpAdditionalHeaders = Parse.configuration.httpAdditionalHeaders\n            Self.parse = session\n        }\n        #endif\n    }\n\n    static func reconnectInterval(_ maxExponent: Int) -> Int {\n        let min = NSDecimalNumber(decimal: Swift.min(30, pow(2, maxExponent) - 1))\n        return Int.random(in: 0 ..< Int(truncating: min))\n    }\n\n    func makeResult<U>(request: URLRequest,\n                       responseData: Data?,\n                       urlResponse: URLResponse?,\n                       responseError: Error?,\n                       mapper: @escaping (Data) throws -> U) -> Result<U, ParseError> {\n        if let responseError = responseError {\n            guard let parseError = responseError as? ParseError else {\n                return .failure(ParseError(code: .unknownError,\n                                           message: \"Unable to connect with parse-server: \\(responseError)\"))\n            }\n            return .failure(parseError)\n        }\n        guard let response = urlResponse else {\n            guard let parseError = responseError as? ParseError else {\n                return .failure(ParseError(code: .unknownError,\n                                           message: \"No response from server\"))\n            }\n            return .failure(parseError)\n        }\n        if var responseData = responseData {\n            if let error = try? ParseCoding.jsonDecoder().decode(ParseError.self, from: responseData) {\n                return .failure(error)\n            }\n            if URLSession.parse.configuration.urlCache?.cachedResponse(for: request) == nil {\n                URLSession.parse.configuration.urlCache?\n                    .storeCachedResponse(.init(response: response,\n                                               data: responseData),\n                                         for: request)\n            }\n            if let httpResponse = response as? HTTPURLResponse {\n                if let pushStatusId = httpResponse.value(forHTTPHeaderField: \"X-Parse-Push-Status-Id\") {\n                    let pushStatus = PushResponse(data: responseData, statusId: pushStatusId)\n                    do {\n                        responseData = try ParseCoding.jsonEncoder().encode(pushStatus)\n                    } catch {\n                        URLSession.parse.configuration.urlCache?.removeCachedResponse(for: request)\n                        return .failure(ParseError(code: .unknownError, message: error.localizedDescription))\n                    }\n                }\n            }\n            do {\n                return try .success(mapper(responseData))\n            } catch {\n                URLSession.parse.configuration.urlCache?.removeCachedResponse(for: request)\n                guard let parseError = error as? ParseError else {\n                    guard JSONSerialization.isValidJSONObject(responseData),\n                          let json = try? JSONSerialization\n                            .data(withJSONObject: responseData,\n                              options: .prettyPrinted) else {\n                        let nsError = error as NSError\n                        if nsError.code == 4865,\n                          let description = nsError.userInfo[\"NSDebugDescription\"] {\n                            return .failure(ParseError(code: .unknownError, message: \"Invalid struct: \\(description)\"))\n                        }\n                        return .failure(ParseError(code: .unknownError,\n                                                   // swiftlint:disable:next line_length\n                                                   message: \"Error decoding parse-server response: \\(response) with error: \\(String(describing: error)) Format: \\(String(describing: String(data: responseData, encoding: .utf8)))\"))\n                    }\n                    return .failure(ParseError(code: .unknownError,\n                                               // swiftlint:disable:next line_length\n                                               message: \"Error decoding parse-server response: \\(response) with error: \\(String(describing: error)) Format: \\(String(describing: String(data: json, encoding: .utf8)))\"))\n                }\n                return .failure(parseError)\n            }\n        }\n\n        return .failure(ParseError(code: .unknownError,\n                                   message: \"Unable to connect with parse-server: \\(String(describing: urlResponse)).\"))\n    }\n\n    func makeResult<U>(request: URLRequest,\n                       location: URL?,\n                       urlResponse: URLResponse?,\n                       responseError: Error?,\n                       mapper: @escaping (Data) throws -> U) -> Result<U, ParseError> {\n        guard let response = urlResponse else {\n            guard let parseError = responseError as? ParseError else {\n                return .failure(ParseError(code: .unknownError,\n                                           message: \"No response from server\"))\n            }\n            return .failure(parseError)\n        }\n        if let responseError = responseError {\n            guard let parseError = responseError as? ParseError else {\n                return .failure(ParseError(code: .unknownError,\n                                           message: \"Unable to connect with parse-server: \\(responseError)\"))\n            }\n            return .failure(parseError)\n        }\n\n        if let location = location {\n            do {\n                let data = try ParseCoding.jsonEncoder().encode(location)\n                return try .success(mapper(data))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              // swiftlint:disable:next line_length\n                                              message: \"Error decoding parse-server response: \\(response) with error: \\(String(describing: error))\")\n                let parseError = error as? ParseError ?? defaultError\n                return .failure(parseError)\n            }\n        }\n\n        return .failure(ParseError(code: .unknownError,\n                                   message: \"Unable to connect with parse-server: \\(response).\"))\n    }\n\n    func dataTask<U>(\n        with request: URLRequest,\n        callbackQueue: DispatchQueue,\n        attempts: Int = 1,\n        mapper: @escaping (Data) throws -> U,\n        completion: @escaping(Result<U, ParseError>) -> Void\n    ) {\n\n        dataTask(with: request) { (responseData, urlResponse, responseError) in\n            guard let httpResponse = urlResponse as? HTTPURLResponse else {\n                completion(self.makeResult(request: request,\n                                           responseData: responseData,\n                                           urlResponse: urlResponse,\n                                           responseError: responseError,\n                                           mapper: mapper))\n                return\n            }\n            let statusCode = httpResponse.statusCode\n            guard (200...299).contains(statusCode) else {\n                guard statusCode >= 500,\n                      attempts <= Parse.configuration.maxConnectionAttempts + 1,\n                      responseData == nil else {\n                          completion(self.makeResult(request: request,\n                                                     responseData: responseData,\n                                                     urlResponse: urlResponse,\n                                                     responseError: responseError,\n                                                     mapper: mapper))\n                          return\n                    }\n                let attempts = attempts + 1\n                callbackQueue.asyncAfter(deadline: .now() + DispatchTimeInterval\n                                                .seconds(Self.reconnectInterval(2))) {\n                    self.dataTask(with: request,\n                                  callbackQueue: callbackQueue,\n                                  attempts: attempts,\n                                  mapper: mapper,\n                                  completion: completion)\n                }\n                return\n            }\n            completion(self.makeResult(request: request,\n                                       responseData: responseData,\n                                       urlResponse: urlResponse,\n                                       responseError: responseError,\n                                       mapper: mapper))\n        }.resume()\n    }\n}\n\ninternal extension URLSession {\n    func uploadTask<U>( // swiftlint:disable:this function_parameter_count\n        notificationQueue: DispatchQueue,\n        with request: URLRequest,\n        from data: Data?,\n        from file: URL?,\n        progress: ((URLSessionTask, Int64, Int64, Int64) -> Void)?,\n        mapper: @escaping (Data) throws -> U,\n        completion: @escaping(Result<U, ParseError>) -> Void\n    ) {\n        var task: URLSessionTask?\n        if let data = data {\n            do {\n                task = try ParseSwift\n                    .configuration\n                    .parseFileTransfer\n                    .upload(with: request,\n                            from: data) { (responseData, urlResponse, updatedRequest, responseError) in\n                    completion(self.makeResult(request: updatedRequest ?? request,\n                                               responseData: responseData,\n                                               urlResponse: urlResponse,\n                                               responseError: responseError,\n                                               mapper: mapper))\n                }\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: \"Error uploading file: \\(String(describing: error))\")\n                let parseError = error as? ParseError ?? defaultError\n                completion(.failure(parseError))\n            }\n        } else if let file = file {\n            do {\n                task = try ParseSwift\n                    .configuration\n                    .parseFileTransfer\n                    .upload(with: request,\n                            fromFile: file) { (responseData, urlResponse, updatedRequest, responseError) in\n                    completion(self.makeResult(request: updatedRequest ?? request,\n                                               responseData: responseData,\n                                               urlResponse: urlResponse,\n                                               responseError: responseError,\n                                               mapper: mapper))\n                }\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: \"Error uploading file: \\(String(describing: error))\")\n                let parseError = error as? ParseError ?? defaultError\n                completion(.failure(parseError))\n            }\n        } else {\n            completion(.failure(ParseError(code: .unknownError, message: \"data and file both cannot be nil\")))\n        }\n        guard let task = task else {\n            return\n        }\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            await Parse.sessionDelegate.delegates.updateUpload(task, callback: progress)\n            await Parse.sessionDelegate.delegates.updateTask(task, queue: notificationQueue)\n            task.resume()\n        }\n        #else\n        Parse.sessionDelegate.uploadDelegates[task] = progress\n        Parse.sessionDelegate.taskCallbackQueues[task] = notificationQueue\n        task.resume()\n        #endif\n    }\n\n    func downloadTask<U>(\n        notificationQueue: DispatchQueue,\n        with request: URLRequest,\n        progress: ((URLSessionDownloadTask, Int64, Int64, Int64) -> Void)?,\n        mapper: @escaping (Data) throws -> U,\n        completion: @escaping(Result<U, ParseError>) -> Void\n    ) {\n        let task = downloadTask(with: request) { (location, urlResponse, responseError) in\n            let result = self.makeResult(request: request,\n                                         location: location,\n                                         urlResponse: urlResponse,\n                                         responseError: responseError, mapper: mapper)\n            completion(result)\n        }\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            await Parse.sessionDelegate.delegates.updateDownload(task, callback: progress)\n            await Parse.sessionDelegate.delegates.updateTask(task, queue: notificationQueue)\n            task.resume()\n        }\n        #else\n        Parse.sessionDelegate.downloadDelegates[task] = progress\n        Parse.sessionDelegate.taskCallbackQueues[task] = notificationQueue\n        task.resume()\n        #endif\n    }\n\n    func downloadTask<U>(\n        with request: URLRequest,\n        mapper: @escaping (Data) throws -> U,\n        completion: @escaping(Result<U, ParseError>) -> Void\n    ) {\n        downloadTask(with: request) { (location, urlResponse, responseError) in\n            completion(self.makeResult(request: request,\n                                       location: location,\n                                       urlResponse: urlResponse,\n                                       responseError: responseError,\n                                       mapper: mapper))\n        }.resume()\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/InternalObjects/BaseConfig.swift",
    "content": "//\n//  BaseConfig.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/22/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\nstruct BaseConfig: ParseConfig {}\n"
  },
  {
    "path": "Sources/ParseSwift/InternalObjects/BaseParseInstallation.swift",
    "content": "//\n//  BaseParseInstallation.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/7/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\ninternal struct BaseParseInstallation: ParseInstallation {\n    var deviceType: String?\n    var installationId: String?\n    var deviceToken: String?\n    var badge: Int?\n    var timeZone: String?\n    var channels: [String]?\n    var appName: String?\n    var appIdentifier: String?\n    var appVersion: String?\n    var parseVersion: String?\n    var localeIdentifier: String?\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n\n    static func createNewInstallationIfNeeded() {\n        guard let installationId = Self.currentContainer.installationId,\n              Self.currentContainer.currentInstallation?.installationId == installationId else {\n            try? ParseStorage.shared.delete(valueFor: ParseStorage.Keys.currentInstallation)\n            #if !os(Linux) && !os(Android) && !os(Windows)\n            try? KeychainStore.shared.delete(valueFor: ParseStorage.Keys.currentInstallation)\n            #endif\n            _ = Self.currentContainer\n            return\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/InternalObjects/BaseParseUser.swift",
    "content": "//\n//  BaseParseUser.swift\n//  \n//\n//  Created by Pranjal Satija on 7/19/20.\n//\n\nimport Foundation\n\n/// Used internally to form a concrete type representing `ParseUser`.\ninternal struct BaseParseUser: ParseUser {\n    var authData: [String: [String: String]?]?\n    var username: String?\n    var email: String?\n    var emailVerified: Bool?\n    var password: String?\n    var objectId: String?\n    var createdAt: Date?\n    var updatedAt: Date?\n    var ACL: ParseACL?\n    var originalData: Data?\n}\n"
  },
  {
    "path": "Sources/ParseSwift/InternalObjects/NoBody.swift",
    "content": "//\n//  NoBody.swift\n//  ParseSwift\n//\n//  Created by Florent Vilmart on 17-07-24.\n//  Copyright © 2020 Parse. All rights reserved.\n//\n\ninternal struct NoBody: ParseEncodable, Decodable {}\n"
  },
  {
    "path": "Sources/ParseSwift/LiveQuery/LiveQueryConstants.swift",
    "content": "//\n//  LiveQueryConstants.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 11/3/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n Represents an update on a specific object from the `ParseLiveQuery` Server.\n - Entered: The object has been updated, and is now included in the query.\n - Left:    The object has been updated, and is no longer included in the query.\n - Created: The object has been created, and is a part of the query.\n - Updated: The object has been updated, and is still a part of the query.\n - Deleted: The object has been deleted, and is no longer included in the query.\n */\npublic enum Event<T: ParseObject>: Equatable {\n    /// The object has been updated, and is now included in the query.\n    case entered(T)\n\n    /// The object has been updated, and is no longer included in the query.\n    case left(T)\n\n    /// The object has been created, and is a part of the query.\n    case created(T)\n\n    /// The object has been updated, and is still a part of the query.\n    case updated(T)\n\n    /// The object has been deleted, and is no longer included in the query.\n    case deleted(T)\n\n    init?(event: EventResponse<T>) {\n        switch event.op {\n        case .enter: self = .entered(event.object)\n        case .leave: self = .left(event.object)\n        case .create: self = .created(event.object)\n        case .update: self = .updated(event.object)\n        case .delete: self = .deleted(event.object)\n        default: return nil\n        }\n    }\n\n    public static func == <T>(lhs: Event<T>, rhs: Event<T>) -> Bool {\n        switch (lhs, rhs) {\n        case (.entered(let obj1), .entered(let obj2)): return obj1 == obj2\n        case (.left(let obj1), .left(let obj2)):       return obj1 == obj2\n        case (.created(let obj1), .created(let obj2)): return obj1 == obj2\n        case (.updated(let obj1), .updated(let obj2)): return obj1 == obj2\n        case (.deleted(let obj1), .deleted(let obj2)): return obj1 == obj2\n        default: return false\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/LiveQuery/LiveQuerySocket.swift",
    "content": "//\n//  LiveQuerySocket.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 12/31/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n#if !os(Linux) && !os(Android) && !os(Windows)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\n\nfinal class LiveQuerySocket: NSObject {\n    private var session: URLSession!\n    var delegates = [URLSessionWebSocketTask: LiveQuerySocketDelegate]()\n    var receivingTasks = [URLSessionWebSocketTask: Bool]()\n    weak var authenticationDelegate: LiveQuerySocketDelegate?\n\n    override init() {\n        super.init()\n        session = URLSession(configuration: .default, delegate: self, delegateQueue: nil)\n    }\n\n    func createTask(_ url: URL, taskDelegate: LiveQuerySocketDelegate) -> URLSessionWebSocketTask {\n        let task = session.webSocketTask(with: url)\n        delegates[task] = taskDelegate\n        receive(task)\n        return task\n    }\n\n    func removeTaskFromDelegates(_ task: URLSessionWebSocketTask) {\n        receivingTasks.removeValue(forKey: task)\n        delegates.removeValue(forKey: task)\n    }\n\n    func closeAll() {\n        delegates.forEach { (_, client) -> Void in\n            client.close(useDedicatedQueue: false)\n        }\n    }\n}\n\n// MARK: Status\nextension LiveQuerySocket {\n    enum Status: String {\n        case open\n        case closed\n    }\n}\n\n// MARK: Connect\nextension LiveQuerySocket {\n    func connect(task: URLSessionWebSocketTask,\n                 completion: @escaping (Error?) -> Void) throws {\n        let encoded = try ParseCoding.jsonEncoder()\n            .encode(StandardMessage(operation: .connect,\n                                    additionalProperties: true))\n        guard let encodedAsString = String(data: encoded, encoding: .utf8) else {\n            let error = ParseError(code: .unknownError,\n                                   message: \"Could not encode connect message: \\(encoded)\")\n            completion(error)\n            return\n        }\n        task.send(.string(encodedAsString)) { error in\n            if error == nil {\n                self.receive(task)\n            }\n            completion(error)\n        }\n    }\n}\n\n// MARK: Send\nextension LiveQuerySocket {\n    func send(_ data: Data, task: URLSessionWebSocketTask, completion: @escaping (Error?) -> Void) {\n        guard let encodedAsString = String(data: data, encoding: .utf8) else {\n            completion(nil)\n            return\n        }\n        task.send(.string(encodedAsString)) { error in\n            completion(error)\n        }\n    }\n}\n\n// MARK: Receive\nextension LiveQuerySocket {\n\n    func receive(_ task: URLSessionWebSocketTask) {\n        if receivingTasks[task] != nil {\n            // Receive has already been called for this task\n            return\n        }\n        receivingTasks[task] = true\n        task.receive { result in\n            self.receivingTasks.removeValue(forKey: task)\n            switch result {\n            case .success(.string(let message)):\n                if let data = message.data(using: .utf8) {\n                    self.delegates[task]?.received(data)\n                } else {\n                    let parseError = ParseError(code: .unknownError,\n                                                message: \"Could not encode LiveQuery string as data\")\n                    self.delegates[task]?.receivedError(parseError)\n                }\n                self.receive(task)\n            case .success(.data(let data)):\n                self.delegates[task]?.receivedUnsupported(data, socketMessage: nil)\n                self.receive(task)\n            case .success(let message):\n                self.delegates[task]?.receivedUnsupported(nil, socketMessage: message)\n                self.receive(task)\n            case .failure(let error):\n                self.delegates[task]?.receivedError(error)\n            }\n        }\n    }\n}\n\n// MARK: Ping\nextension LiveQuerySocket {\n\n    func sendPing(_ task: URLSessionWebSocketTask, pongReceiveHandler: @escaping (Error?) -> Void) {\n        task.sendPing(pongReceiveHandler: pongReceiveHandler)\n    }\n}\n\n// MARK: URLSession\nextension URLSession {\n    static let liveQuery = LiveQuerySocket()\n}\n\n// MARK: URLSessionWebSocketDelegate\nextension LiveQuerySocket: URLSessionWebSocketDelegate {\n    func urlSession(_ session: URLSession,\n                    webSocketTask: URLSessionWebSocketTask,\n                    didOpenWithProtocol protocol: String?) {\n        delegates[webSocketTask]?.status(.open,\n                                         closeCode: nil,\n                                         reason: nil)\n    }\n\n    func urlSession(_ session: URLSession,\n                    webSocketTask: URLSessionWebSocketTask,\n                    didCloseWith closeCode: URLSessionWebSocketTask.CloseCode,\n                    reason: Data?) {\n        delegates[webSocketTask]?.status(.closed,\n                                         closeCode: closeCode,\n                                         reason: reason)\n    }\n\n    func urlSession(_ session: URLSession,\n                    didReceive challenge: URLAuthenticationChallenge,\n                    completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {\n        if let authenticationDelegate = authenticationDelegate {\n            authenticationDelegate.received(challenge: challenge, completionHandler: completionHandler)\n        } else {\n            completionHandler(.performDefaultHandling, nil)\n        }\n    }\n\n    #if !os(watchOS)\n    func urlSession(_ session: URLSession,\n                    task: URLSessionTask,\n                    didFinishCollecting metrics: URLSessionTaskMetrics) {\n        if let socketTask = task as? URLSessionWebSocketTask,\n           let transactionMetrics = metrics.transactionMetrics.last {\n                delegates[socketTask]?.received(transactionMetrics)\n        }\n    }\n    #endif\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/LiveQuery/Messages.swift",
    "content": "//\n//  Messages.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/2/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n// MARK: Sending\nstruct StandardMessage: LiveQueryable, Codable {\n    var op: ClientOperation // swiftlint:disable:this identifier_name\n    var applicationId: String?\n    var clientKey: String?\n    var masterKey: String? // swiftlint:disable:this inclusive_language\n    var sessionToken: String?\n    var installationId: String?\n    var requestId: Int?\n\n    init(operation: ClientOperation, additionalProperties: Bool = false) {\n        self.op = operation\n        if additionalProperties {\n            self.applicationId = Parse.configuration.applicationId\n            self.masterKey = Parse.configuration.masterKey\n            self.clientKey = Parse.configuration.clientKey\n            self.sessionToken = BaseParseUser.currentContainer?.sessionToken\n            self.installationId = BaseParseInstallation.currentContainer.installationId\n        }\n    }\n\n    init(operation: ClientOperation, requestId: RequestId) {\n        self.init(operation: operation)\n        self.requestId = requestId.value\n    }\n}\n\nstruct SubscribeQuery: Encodable {\n    let className: String\n    let `where`: QueryWhere\n    let fields: Set<String>?\n}\n\nstruct SubscribeMessage<T: ParseObject>: LiveQueryable, Encodable {\n    var op: ClientOperation // swiftlint:disable:this identifier_name\n    var applicationId: String?\n    var clientKey: String?\n    var sessionToken: String?\n    var installationId: String?\n    var requestId: Int?\n    var query: SubscribeQuery?\n\n    init(operation: ClientOperation,\n         requestId: RequestId,\n         query: Query<T>? = nil,\n         additionalProperties: Bool = false) {\n        self.op = operation\n        self.requestId = requestId.value\n        if let query = query {\n            self.query = SubscribeQuery(className: query.className,\n                                        where: query.where,\n                                        fields: query.fields ?? query.keys)\n        }\n        self.sessionToken = BaseParseUser.currentContainer?.sessionToken\n    }\n}\n\n// MARK: Receiving\nstruct RedirectResponse: LiveQueryable, Codable {\n    let op: ServerResponse // swiftlint:disable:this identifier_name\n    let url: URL\n}\n\nstruct ConnectionResponse: LiveQueryable, Codable {\n    let op: ServerResponse // swiftlint:disable:this identifier_name\n    let clientId: String\n    let installationId: String?\n}\n\nstruct UnsubscribedResponse: LiveQueryable, Codable {\n    let op: ServerResponse // swiftlint:disable:this identifier_name\n    let requestId: Int\n    let clientId: String\n    let installationId: String?\n}\n\nstruct EventResponse<T: ParseObject>: LiveQueryable, Codable {\n    let op: ServerResponse // swiftlint:disable:this identifier_name\n    let requestId: Int\n    let object: T\n    let clientId: String\n    let installationId: String?\n}\n\nstruct ErrorResponse: LiveQueryable, Codable {\n    let op: OperationErrorResponse // swiftlint:disable:this identifier_name\n    let code: Int\n    let message: String\n    let reconnect: Bool\n\n    enum CodingKeys: String, CodingKey {\n        case op // swiftlint:disable:this identifier_name\n        case code\n        case message = \"error\"\n        case reconnect\n    }\n}\n\nstruct PreliminaryMessageResponse: LiveQueryable, Codable {\n    let op: ServerResponse // swiftlint:disable:this identifier_name\n    let requestId: Int\n    let clientId: String\n    let installationId: String?\n}\n"
  },
  {
    "path": "Sources/ParseSwift/LiveQuery/Operations.swift",
    "content": "//\n//  Operations.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/2/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\nenum ClientOperation: String, Codable {\n    case connect\n    case subscribe\n    case unsubscribe\n    case update\n}\n\nenum ServerResponse: String, Codable {\n    case connected, subscribed, unsubscribed, redirect,\n         create, enter, update, leave, delete\n}\n\nenum OperationErrorResponse: String, Codable {\n    case error\n}\n\n// An opaque placeholder structed used to ensure that we type-safely create request IDs and do not shoot ourself in\n// the foot with array indexes.\nstruct RequestId: Hashable, Equatable, Codable {\n    let value: Int\n}\n"
  },
  {
    "path": "Sources/ParseSwift/LiveQuery/ParseLiveQuery+async.swift",
    "content": "//\n//  ParseLiveQuery+async.swift\n//  ParseLiveQuery+async\n//\n//  Created by Corey Baker on 8/6/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency) && !os(Linux) && !os(Android) && !os(Windows)\nimport Foundation\n\nextension ParseLiveQuery {\n    // MARK: Connection - Async/Await\n\n    /**\n     Manually establish a connection to the `ParseLiveQuery` Server.\n      - parameter isUserWantsToConnect: Specifies if the user is calling this function. Defaults to **true**.\n      - returns: An instance of the logged in `ParseUser`.\n      - throws: An error of type `ParseError`.\n    */\n    public func open(isUserWantsToConnect: Bool = true) async throws {\n        let _: Void = try await withCheckedThrowingContinuation { continuation in\n            self.open(isUserWantsToConnect: isUserWantsToConnect) { error in\n                guard let error = error else {\n                    continuation.resume(with: .success(()))\n                    return\n                }\n                continuation.resume(with: .failure(error))\n            }\n        }\n    }\n\n    /**\n     Sends a ping frame from the client side. Returns when a pong is received from the\n     server endpoint.\n     - throws: An error of type `ParseError`.\n    */\n    public func sendPing() async throws {\n        let _: Void = try await withCheckedThrowingContinuation { continuation in\n            self.sendPing { error in\n                guard let error = error else {\n                    continuation.resume(with: .success(()))\n                    return\n                }\n                continuation.resume(with: .failure(error))\n            }\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/LiveQuery/ParseLiveQuery+combine.swift",
    "content": "//\n//  ParseLiveQuery+combine.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/24/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\nextension ParseLiveQuery {\n    // MARK: Connection - Combine\n\n    /**\n     Manually establish a connection to the `ParseLiveQuery` Server. Publishes when established.\n      - parameter isUserWantsToConnect: Specifies if the user is calling this function. Defaults to **true**.\n      - returns: A publisher that eventually produces a single value and then finishes or fails.\n    */\n    public func openPublisher(isUserWantsToConnect: Bool = true) -> Future<Void, Error> {\n        Future { promise in\n            self.open(isUserWantsToConnect: isUserWantsToConnect) { error in\n                guard let error = error else {\n                    promise(.success(()))\n                    return\n                }\n                promise(.failure(error))\n            }\n        }\n    }\n\n    /**\n     Sends a ping frame from the client side. Publishes when a pong is received from the\n     server endpoint.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n    */\n    public func sendPingPublisher() -> Future<Void, Error> {\n        Future { promise in\n            self.sendPing { error in\n                guard let error = error else {\n                    promise(.success(()))\n                    return\n                }\n                promise(.failure(error))\n            }\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/LiveQuery/ParseLiveQuery.swift",
    "content": "//\n//  ParseLiveQuery.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/2/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n#if !os(Linux) && !os(Android) && !os(Windows)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\n\n/**\n The `ParseLiveQuery` class enables two-way communication to a Parse Live Query\n Server.\n \n In most cases, you should not call this class directly as a LiveQuery can be indirectly\n created from `Query` using:\n ```swift\n // If \"Message\" is a \"ParseObject\"\n let myQuery = Message.query(\"from\" == \"parse\")\n guard let subscription = myQuery.subscribe else {\n     \"Error subscribing...\"\n     return\n }\n subscription.handleSubscribe { subscribedQuery, isNew in\n\n     //Handle the subscription however you like.\n     if isNew {\n         print(\"Successfully subscribed to new query \\(subscribedQuery)\")\n     } else {\n         print(\"Successfully updated subscription to new query \\(subscribedQuery)\")\n     }\n }\n ```\n The above creates a `ParseLiveQuery` using either the `liveQueryServerURL` (if it has been set)\n or `serverURL` when using `ParseSwift.initialize`. All additional queries will be\n created in the same way. The times you will want to initialize a new `ParseLiveQuery` instance\n are:\n 1. If you want to become a `ParseLiveQueryDelegate` to respond to authentification challenges\n and/or receive metrics and error messages for a `ParseLiveQuery`client.\n 2. You have specific LiveQueries that need to subscribe to a server that have a different url than\n the default.\n 3. You want to change the default url for all LiveQuery connections when the app is already\n running. Initializing new instances will create a new task/connection to the `ParseLiveQuery` server.\n When an instance is deinitialized it will automatically close it is connection gracefully.\n */\npublic final class ParseLiveQuery: NSObject {\n    // Queues\n    let synchronizationQueue: DispatchQueue\n    let notificationQueue: DispatchQueue\n\n    //Task\n    var task: URLSessionWebSocketTask! {\n        willSet {\n            if newValue == nil && isSocketEstablished {\n                isSocketEstablished = false\n            }\n        }\n    }\n    var url: URL!\n    var clientId: String!\n    var attempts: Int = 1 {\n        willSet {\n            if newValue >= ParseLiveQueryConstants.maxConnectionAttempts + 1 {\n                let error = ParseError(code: .unknownError,\n                                       message: \"\"\"\nParseLiveQuery Error: Reached max attempts of\n\\(ParseLiveQueryConstants.maxConnectionAttempts).\nNot attempting to open ParseLiveQuery socket anymore\n\"\"\")\n                notificationQueue.async {\n                    self.receiveDelegate?.received(error)\n                }\n                close() // Quit trying to reconnect\n            }\n        }\n    }\n    var isDisconnectedByUser = false {\n        willSet {\n            if newValue {\n                isConnected = false\n            }\n        }\n    }\n\n    /// Have all `ParseLiveQuery` authentication challenges delegated to you. There can only\n    /// be one of these for all `ParseLiveQuery` connections. The default is to\n    /// delegate to the `authentication` call block passed to `ParseSwift.initialize`\n    /// or if there is not one, delegate to the OS. Conforms to `ParseLiveQueryDelegate`.\n    public weak var authenticationDelegate: ParseLiveQueryDelegate? {\n        willSet {\n            if newValue != nil {\n                URLSession.liveQuery.authenticationDelegate = self\n            } else {\n                if let delegate = URLSession.liveQuery.authenticationDelegate as? ParseLiveQuery {\n                    if delegate == self {\n                        URLSession.liveQuery.authenticationDelegate = nil\n                    }\n                }\n            }\n        }\n    }\n\n    /// Have `ParseLiveQuery` connection metrics, errors, etc delegated to you. A delegate\n    /// can be assigned to individual connections. Conforms to `ParseLiveQueryDelegate`.\n    public weak var receiveDelegate: ParseLiveQueryDelegate?\n\n    /// True if the connection to the url is up and available. False otherwise.\n    public internal(set) var isSocketEstablished = false { //URLSession has an established socket\n        willSet {\n            if !newValue {\n                isConnected = newValue\n            }\n        }\n    }\n\n    /// True if this client is connected. False otherwise.\n    public internal(set) var isConnected = false {\n        willSet {\n            isConnecting = false\n            if newValue {\n                if isSocketEstablished {\n                    if let task = self.task {\n                        attempts = 1\n\n                        //Resubscribe to all subscriptions by moving them in front of pending\n                        var tempPendingSubscriptions = [(RequestId, SubscriptionRecord)]()\n                        self.subscriptions.forEach { (key, value) -> Void in\n                            tempPendingSubscriptions.append((key, value))\n                        }\n                        self.subscriptions.removeAll()\n                        tempPendingSubscriptions.append(contentsOf: pendingSubscriptions)\n                        pendingSubscriptions = tempPendingSubscriptions\n\n                        //Send all pending messages in order\n                        self.pendingSubscriptions.forEach {\n                            let messageToSend = $0\n                            URLSession.liveQuery.send(messageToSend.1.messageData, task: task) { _ in }\n                        }\n                    }\n                }\n            } else {\n                clientId = nil\n            }\n        }\n        didSet {\n            if !isSocketEstablished {\n                self.isConnected = false\n            }\n        }\n    }\n\n    /// True if this client is connecting. False otherwise.\n    public internal(set) var isConnecting = false {\n        didSet {\n            if !isSocketEstablished {\n                self.isConnecting = false\n            }\n        }\n    }\n\n    //Subscription\n    let requestIdGenerator: () -> RequestId\n    var subscriptions = [RequestId: SubscriptionRecord]()\n    var pendingSubscriptions = [(RequestId, SubscriptionRecord)]() // Behave as FIFO to maintain sending order\n\n    /**\n     - parameter serverURL: The URL of the `ParseLiveQuery` Server to connect to.\n     Defaults to `nil` in which case, it will use the URL passed in\n     `ParseSwift.initialize(...liveQueryServerURL: URL)`. If no URL was passed,\n     this assumes the current Parse Server URL is also the LiveQuery server.\n     - parameter isDefault: Set this `ParseLiveQuery` client as the default client for all LiveQuery connections.\n     Defaults value of false.\n     - parameter notificationQueue: The queue to return to for all delegate notifications. Default value of .main.\n     */\n    public init(serverURL: URL? = nil, isDefault: Bool = false, notificationQueue: DispatchQueue = .main) throws {\n        self.notificationQueue = notificationQueue\n        synchronizationQueue = DispatchQueue(label: \"com.parse.liveQuery.\\(UUID().uuidString)\",\n                                             qos: .default,\n                                             attributes: .concurrent,\n                                             autoreleaseFrequency: .inherit,\n                                             target: nil)\n\n        // Simple incrementing generator\n        var currentRequestId = 0\n        requestIdGenerator = {\n            currentRequestId += 1\n            return RequestId(value: currentRequestId)\n        }\n        super.init()\n\n        if let userSuppliedURL = serverURL {\n            url = userSuppliedURL\n        } else if let liveQueryConfigURL = Parse.configuration.liveQuerysServerURL {\n            url = liveQueryConfigURL\n        } else {\n            url = Parse.configuration.serverURL\n        }\n\n        guard var components = URLComponents(url: url,\n                                             resolvingAgainstBaseURL: false) else {\n            let error = ParseError(code: .unknownError,\n                                   message: \"ParseLiveQuery Error: Could not create components from url: \\(url!)\")\n            throw error\n        }\n        components.scheme = (components.scheme == \"https\" || components.scheme == \"wss\") ? \"wss\" : \"ws\"\n        url = components.url\n        self.task = URLSession.liveQuery.createTask(self.url,\n                                                    taskDelegate: self)\n        self.resumeTask { _ in }\n        if isDefault {\n            Self.defaultClient = self\n        }\n    }\n\n    /// Gracefully disconnects from the ParseLiveQuery Server.\n    deinit {\n        close(useDedicatedQueue: false)\n        authenticationDelegate = nil\n        receiveDelegate = nil\n    }\n}\n\n// MARK: Client Intents\nextension ParseLiveQuery {\n\n    /// Current LiveQuery client.\n    public private(set) static var client = try? ParseLiveQuery()\n\n    func resumeTask(completion: @escaping (Error?) -> Void) {\n        synchronizationQueue.sync {\n            switch self.task.state {\n            case .suspended:\n                URLSession.liveQuery.receive(task)\n                self.task.resume()\n                completion(nil)\n            case .completed, .canceling:\n                let oldTask = self.task\n                self.task = URLSession.liveQuery.createTask(self.url,\n                                                            taskDelegate: self)\n                self.task.resume()\n                if let oldTask = oldTask {\n                    URLSession.liveQuery.removeTaskFromDelegates(oldTask)\n                }\n                completion(nil)\n            case .running:\n                self.open(isUserWantsToConnect: false, completion: completion)\n            @unknown default:\n                break\n            }\n        }\n    }\n\n    func removePendingSubscription(_ requestId: Int) {\n        self.pendingSubscriptions.removeAll(where: { $0.0.value == requestId })\n        closeWebsocketIfNoSubscriptions()\n    }\n\n    func closeWebsocketIfNoSubscriptions() {\n        self.notificationQueue.async {\n            if self.subscriptions.isEmpty && self.pendingSubscriptions.isEmpty {\n                self.close()\n            }\n        }\n    }\n\n    /// The default `ParseLiveQuery` client for all LiveQuery connections.\n    class public var defaultClient: ParseLiveQuery? {\n        get {\n            Self.client\n        }\n        set {\n            Self.client = nil\n            Self.client = newValue\n        }\n    }\n\n    /// Set a specific ParseLiveQuery client to be the default for all `ParseLiveQuery` connections.\n    /// - parameter client: The client to set as the default.\n    /// - warning: This will be removed in ParseSwift 5.0.0 in favor of `defaultClient`.\n    @available(*, deprecated, renamed: \"defaultClient\")\n    class public func setDefault(_ client: ParseLiveQuery) {\n        Self.defaultClient = client\n    }\n\n    /// Get the default `ParseLiveQuery` client for all LiveQuery connections.\n    /// - returns: The default `ParseLiveQuery` client.\n    /// - warning: This will be removed in ParseSwift 5.0.0 in favor of `defaultClient`.\n    @available(*, deprecated, renamed: \"defaultClient\")\n    class public func getDefault() -> ParseLiveQuery? {\n        Self.defaultClient\n    }\n\n    /// Check if a query has an active subscription on this `ParseLiveQuery` client.\n    /// - parameter query: Query to verify.\n    /// - returns: **true** if subscribed. **false** otherwise.\n    /// - throws: An error of type `ParseError`.\n    public func isSubscribed<T: ParseObject>(_ query: Query<T>) throws -> Bool {\n        let queryData = try ParseCoding.jsonEncoder().encode(query)\n        return subscriptions.contains(where: { (_, value) -> Bool in\n            if queryData == value.queryData {\n                return true\n            } else {\n                return false\n            }\n        })\n    }\n\n    /// Check if a query has a pending subscription on this `ParseLiveQuery` client.\n    /// - parameter query: Query to verify.\n    /// - returns: **true** if query is a pending subscription. **false** otherwise.\n    /// - throws: An error of type `ParseError`.\n    public func isPendingSubscription<T: ParseObject>(_ query: Query<T>) throws -> Bool {\n        let queryData = try ParseCoding.jsonEncoder().encode(query)\n        return pendingSubscriptions.contains(where: { (_, value) -> Bool in\n            if queryData == value.queryData {\n                return true\n            } else {\n                return false\n            }\n        })\n    }\n\n    /// Remove a pending subscription on this `ParseLiveQuery` client.\n    /// - parameter query: Query to remove.\n    /// - throws: An error of type `ParseError`.\n    public func removePendingSubscription<T: ParseObject>(_ query: Query<T>) throws {\n        let queryData = try ParseCoding.jsonEncoder().encode(query)\n        pendingSubscriptions.removeAll(where: { (_, value) -> Bool in\n            self.closeWebsocketIfNoSubscriptions()\n            if queryData == value.queryData {\n                return true\n            } else {\n                return false\n            }\n        })\n    }\n}\n\n// MARK: Delegate\nextension ParseLiveQuery: LiveQuerySocketDelegate {\n\n    func status(_ status: LiveQuerySocket.Status,\n                closeCode: URLSessionWebSocketTask.CloseCode? = nil,\n                reason: Data? = nil) {\n        synchronizationQueue.sync {\n            switch status {\n\n            case .open:\n                self.isSocketEstablished = true\n                self.open(isUserWantsToConnect: false) { _ in }\n            case .closed:\n                self.notificationQueue.async {\n                    self.receiveDelegate?.closedSocket(closeCode, reason: reason)\n                }\n                self.isSocketEstablished = false\n                if !self.isDisconnectedByUser {\n                    // Try to reconnect\n                    self.open(isUserWantsToConnect: false) { _ in }\n                }\n            }\n        }\n    }\n\n    func received(_ data: Data) {\n        synchronizationQueue.sync {\n            if let redirect = try? ParseCoding.jsonDecoder().decode(RedirectResponse.self, from: data) {\n                if redirect.op == .redirect {\n                    self.url = redirect.url\n                    if self.isConnected {\n                        self.close(useDedicatedQueue: true)\n                        //Try to reconnect\n                        self.resumeTask { _ in }\n                    }\n                }\n                return\n            }\n\n            //Check if this is an error response\n            if let error = try? ParseCoding.jsonDecoder().decode(ErrorResponse.self, from: data) {\n                if !error.reconnect {\n                    //Treat this as a user disconnect because the server does not want to hear from us anymore\n                    self.close()\n                }\n                guard let parseError = try? ParseCoding.jsonDecoder().decode(ParseError.self, from: data) else {\n                    //Turn LiveQuery error into ParseError\n                    let parseError = ParseError(code: .unknownError,\n                                                // swiftlint:disable:next line_length\n                                                message: \"ParseLiveQuery Error: code: \\(error.code), message: \\(error.message)\")\n                    self.notificationQueue.async {\n                        self.receiveDelegate?.received(parseError)\n                    }\n                    return\n                }\n                self.notificationQueue.async {\n                    self.receiveDelegate?.received(parseError)\n                }\n                return\n            } else if !self.isConnected {\n                //Check if this is a connected response\n                guard let response = try? ParseCoding.jsonDecoder().decode(ConnectionResponse.self, from: data),\n                      response.op == .connected else {\n                    //If not connected, should not receive anything other than a connection response\n                    guard let outOfOrderMessage = try? ParseCoding\n                            .jsonDecoder()\n                            .decode(AnyCodable.self, from: data) else {\n                        let error = ParseError(code: .unknownError,\n                                               // swiftlint:disable:next line_length\n                                               message: \"ParseLiveQuery Error: Received message out of order, but could not decode it\")\n                        self.notificationQueue.async {\n                            self.receiveDelegate?.received(error)\n                        }\n                        return\n                    }\n                    let error = ParseError(code: .unknownError,\n                                           // swiftlint:disable:next line_length\n                                           message: \"ParseLiveQuery Error: Received message out of order: \\(outOfOrderMessage)\")\n                    self.notificationQueue.async {\n                        self.receiveDelegate?.received(error)\n                    }\n                    return\n                }\n                self.clientId = response.clientId\n                self.isConnected = true\n            } else {\n\n                if let preliminaryMessage = try? ParseCoding.jsonDecoder()\n                            .decode(PreliminaryMessageResponse.self,\n                                    from: data) {\n\n                    if preliminaryMessage.clientId != self.clientId {\n                        let error = ParseError(code: .unknownError,\n                                               // swiftlint:disable:next line_length\n                                               message: \"ParseLiveQuery Error: Received a message from a server who sent clientId \\(preliminaryMessage.clientId) while it should be \\(String(describing: self.clientId)). Not accepting message...\")\n                        self.notificationQueue.async {\n                            self.receiveDelegate?.received(error)\n                        }\n                    }\n\n                    if let installationId = BaseParseInstallation.currentContainer.installationId {\n                        if installationId != preliminaryMessage.installationId {\n                            let error = ParseError(code: .unknownError,\n                                                   // swiftlint:disable:next line_length\n                                                   message: \"ParseLiveQuery Error: Received a message from a server who sent an installationId of \\(String(describing: preliminaryMessage.installationId)) while it should be \\(installationId). Not accepting message...\")\n                            self.notificationQueue.async {\n                                self.receiveDelegate?.received(error)\n                            }\n                        }\n                    }\n\n                    switch preliminaryMessage.op {\n                    case .subscribed:\n\n                        if let subscribed = self.pendingSubscriptions\n                            .first(where: { $0.0.value == preliminaryMessage.requestId }) {\n                            let requestId = RequestId(value: preliminaryMessage.requestId)\n                            let isNew: Bool!\n                            if self.subscriptions[requestId] != nil {\n                                isNew = false\n                            } else {\n                                isNew = true\n                            }\n                            self.subscriptions[subscribed.0] = subscribed.1\n                            self.removePendingSubscription(subscribed.0.value)\n                            self.notificationQueue.async {\n                                subscribed.1.subscribeHandlerClosure?(isNew)\n                            }\n                        }\n                    case .unsubscribed:\n                        let requestId = RequestId(value: preliminaryMessage.requestId)\n                        guard let subscription = self.subscriptions[requestId] else {\n                            return\n                        }\n                        self.subscriptions.removeValue(forKey: requestId)\n                        self.removePendingSubscription(preliminaryMessage.requestId)\n                        self.notificationQueue.async {\n                            subscription.unsubscribeHandlerClosure?()\n                        }\n                    case .create, .update, .delete, .enter, .leave:\n                        let requestId = RequestId(value: preliminaryMessage.requestId)\n                        guard let subscription = self.subscriptions[requestId] else {\n                            return\n                        }\n                        self.notificationQueue.async {\n                            subscription.eventHandlerClosure?(data)\n                        }\n                    default:\n                        let error = ParseError(code: .unknownError,\n                                               message: \"ParseLiveQuery Error: Hit an undefined state.\")\n                        self.notificationQueue.async {\n                            self.receiveDelegate?.received(error)\n                        }\n                    }\n\n                } else {\n                    let error = ParseError(code: .unknownError,\n                                           message: \"ParseLiveQuery Error: Hit an undefined state.\")\n                    self.notificationQueue.async {\n                        self.receiveDelegate?.received(error)\n                    }\n                }\n            }\n        }\n    }\n\n    func receivedError(_ error: Error) {\n        if !isPosixError(error) {\n            if !isURLError(error) {\n                notificationQueue.async {\n                    self.receiveDelegate?.received(error)\n                }\n            }\n        }\n    }\n\n    func isPosixError(_ error: Error) -> Bool {\n        guard let posixError = error as? POSIXError else {\n            notificationQueue.async {\n                self.receiveDelegate?.received(error)\n            }\n            return false\n        }\n        if posixError.code == .ENOTCONN {\n            isSocketEstablished = false\n            open(isUserWantsToConnect: false) { error in\n                guard let error = error else {\n                    // Resumed task successfully\n                    return\n                }\n                self.notificationQueue.async {\n                    self.receiveDelegate?.received(error)\n                }\n            }\n        } else {\n            notificationQueue.async {\n                self.receiveDelegate?.received(error)\n            }\n        }\n        return true\n    }\n\n    func isURLError(_ error: Error) -> Bool {\n        guard let urlError = error as? URLError else {\n            notificationQueue.async {\n                self.receiveDelegate?.received(error)\n            }\n            return false\n        }\n        if [-1001, -1005, -1011].contains(urlError.errorCode) {\n            isSocketEstablished = false\n            open(isUserWantsToConnect: false) { error in\n                guard let error = error else {\n                    // Resumed task successfully\n                    return\n                }\n                self.notificationQueue.async {\n                    self.receiveDelegate?.received(error)\n                }\n            }\n        } else {\n            notificationQueue.async {\n                self.receiveDelegate?.received(error)\n            }\n        }\n        return true\n    }\n\n    func receivedUnsupported(_ data: Data?, socketMessage: URLSessionWebSocketTask.Message?) {\n        notificationQueue.async {\n            self.receiveDelegate?.receivedUnsupported(data, socketMessage: socketMessage)\n        }\n    }\n\n    func received(challenge: URLAuthenticationChallenge,\n                  completionHandler: @escaping (URLSession.AuthChallengeDisposition,\n                                                URLCredential?) -> Void) {\n        notificationQueue.async {\n            if let delegate = self.authenticationDelegate {\n                delegate.received(challenge, completionHandler: completionHandler)\n            } else if let parseAuthentication = Parse.sessionDelegate.authentication {\n                parseAuthentication(challenge, completionHandler)\n            } else {\n                completionHandler(.performDefaultHandling, nil)\n            }\n        }\n    }\n\n    #if !os(watchOS)\n    func received(_ metrics: URLSessionTaskTransactionMetrics) {\n        notificationQueue.async {\n            self.receiveDelegate?.received(metrics)\n        }\n    }\n    #endif\n}\n\n// MARK: Connection\nextension ParseLiveQuery {\n\n    /// Manually establish a connection to the `ParseLiveQuery` Server.\n    /// - parameter isUserWantsToConnect: Specifies if the user is calling this function. Defaults to **true**.\n    /// - parameter completion: Returns `nil` if successful, an `Error` otherwise.\n    public func open(isUserWantsToConnect: Bool = true, completion: @escaping (Error?) -> Void) {\n        synchronizationQueue.sync {\n            if isUserWantsToConnect {\n                self.isDisconnectedByUser = false\n            }\n            if self.isConnected || self.isDisconnectedByUser {\n                completion(nil)\n                return\n            }\n            if self.isConnecting {\n                completion(nil)\n                return\n            }\n            if isSocketEstablished {\n                do {\n                    try URLSession.liveQuery.connect(task: self.task) { error in\n                        if error == nil {\n                            self.isConnecting = true\n                        }\n                        completion(error)\n                    }\n                } catch {\n                    completion(error)\n                }\n            } else {\n                self.synchronizationQueue\n                    .asyncAfter(deadline: .now() + DispatchTimeInterval\n                                    .seconds(URLSession.reconnectInterval(attempts))) {\n                        self.attempts += 1\n                        self.resumeTask { _ in }\n                        let error = ParseError(code: .unknownError,\n                                               // swiftlint:disable:next line_length\n                                               message: \"ParseLiveQuery Error: attempted to open socket \\(self.attempts) time(s)\")\n                        completion(error)\n                }\n            }\n        }\n    }\n\n    /// Manually disconnect from the `ParseLiveQuery` Server.\n    public func close() {\n        synchronizationQueue.sync {\n            if self.isConnected {\n                self.task.cancel(with: .goingAway, reason: nil)\n                self.isDisconnectedByUser = true\n                let oldTask = self.task\n                isSocketEstablished = false\n                // Prepare new task for future use.\n                self.task = URLSession.liveQuery.createTask(self.url,\n                                                            taskDelegate: self)\n                if let oldTask = oldTask {\n                    URLSession.liveQuery.removeTaskFromDelegates(oldTask)\n                }\n            }\n        }\n    }\n\n    /// Manually disconnect all sessions and subscriptions from the `ParseLiveQuery` Server.\n    public func closeAll() {\n        synchronizationQueue.sync {\n            URLSession.liveQuery.closeAll()\n        }\n    }\n\n    /**\n     Sends a ping frame from the client side, with a closure to receive the pong from the server endpoint.\n     - parameter pongReceiveHandler: A closure called by the task when it receives the pong\n     from the server. The closure receives an  `Error` that indicates a lost connection or other problem,\n     or nil if no error occurred.\n     */\n    public func sendPing(pongReceiveHandler: @escaping (Error?) -> Void) {\n        synchronizationQueue.sync {\n            if self.task.state == .running {\n                URLSession.liveQuery.sendPing(task, pongReceiveHandler: pongReceiveHandler)\n            } else {\n                let error = ParseError(code: .unknownError,\n                                       // swiftlint:disable:next line_length\n                                       message: \"ParseLiveQuery Error: socket status needs to be \\\"\\(URLSessionTask.State.running.rawValue)\\\" before pinging server. Current status is \\\"\\(self.task.state.rawValue)\\\". Try calling \\\"open()\\\" to change socket status.\")\n                pongReceiveHandler(error)\n            }\n        }\n    }\n\n    func close(useDedicatedQueue: Bool) {\n        if useDedicatedQueue {\n            synchronizationQueue.async {\n                if self.isConnected {\n                    self.task.cancel(with: .goingAway, reason: nil)\n                    let oldTask = self.task\n                    self.isSocketEstablished = false\n                    // Prepare new task for future use.\n                    self.task = URLSession.liveQuery.createTask(self.url,\n                                                                taskDelegate: self)\n                    if let oldTask = oldTask {\n                        URLSession.liveQuery.removeTaskFromDelegates(oldTask)\n                    }\n                }\n            }\n        } else {\n            if self.isConnected {\n                self.task.cancel(with: .goingAway, reason: nil)\n                let oldTask = task\n                isSocketEstablished = false\n                // Prepare new task for future use.\n                self.task = URLSession.liveQuery.createTask(self.url,\n                                                            taskDelegate: self)\n                if let oldTask = oldTask {\n                    URLSession.liveQuery.removeTaskFromDelegates(oldTask)\n                }\n            }\n        }\n    }\n\n    func send(record: SubscriptionRecord, requestId: RequestId, completion: @escaping (Error?) -> Void) {\n        synchronizationQueue.sync {\n            self.pendingSubscriptions.append((requestId, record))\n            if self.isConnected {\n                URLSession.liveQuery.send(record.messageData, task: self.task, completion: completion)\n            } else {\n                self.open(completion: completion)\n            }\n        }\n    }\n}\n\n// MARK: SubscriptionRecord\nextension ParseLiveQuery {\n    class SubscriptionRecord {\n\n        var messageData: Data\n        var queryData: Data\n        var subscriptionHandler: AnyObject\n        var eventHandlerClosure: ((Data) -> Void)?\n        var subscribeHandlerClosure: ((Bool) -> Void)?\n        var unsubscribeHandlerClosure: (() -> Void)?\n\n        init?<T: QuerySubscribable>(query: Query<T.Object>, message: SubscribeMessage<T.Object>, handler: T) {\n            guard let queryData = try? ParseCoding.jsonEncoder().encode(query),\n                  let encoded = try? ParseCoding.jsonEncoder().encode(message) else {\n                return nil\n            }\n            self.queryData = queryData\n            self.messageData = encoded\n            self.subscriptionHandler = handler\n\n            eventHandlerClosure = { event in\n                guard let handler = self.subscriptionHandler as? T else {\n                    return\n                }\n\n                try? handler.didReceive(event)\n            }\n\n            subscribeHandlerClosure = { (new) in\n                guard let handler = self.subscriptionHandler as? T else {\n                    return\n                }\n                handler.didSubscribe(new)\n            }\n\n            unsubscribeHandlerClosure = { () in\n                guard let handler = self.subscriptionHandler as? T else {\n                    return\n                }\n                handler.didUnsubscribe()\n            }\n        }\n\n        func update<T: ParseObject>(query: Query<T>, message: SubscribeMessage<T>) throws {\n            guard let queryData = try? ParseCoding.jsonEncoder().encode(query),\n                  let encoded = try? ParseCoding.jsonEncoder().encode(message) else {\n                throw ParseError(code: .unknownError, message: \"ParseLiveQuery Error: Unable to update subscription.\")\n            }\n            self.queryData = queryData\n            self.messageData = encoded\n        }\n    }\n}\n\n// MARK: Subscribing\nextension ParseLiveQuery {\n\n    func subscribe<T>(_ query: Query<T>) throws -> Subscription<T> {\n        try subscribe(Subscription(query: query))\n    }\n\n    func subscribe<T>(_ query: Query<T>) throws -> SubscriptionCallback<T> {\n        try subscribe(SubscriptionCallback(query: query))\n    }\n\n    public func subscribe<T>(_ handler: T) throws -> T where T: QuerySubscribable {\n\n        let requestId = requestIdGenerator()\n        let message = SubscribeMessage<T.Object>(operation: .subscribe,\n                                                 requestId: requestId,\n                                                 query: handler.query)\n        guard let subscriptionRecord = SubscriptionRecord(\n            query: handler.query,\n            message: message,\n            handler: handler\n        ) else {\n            throw ParseError(code: .unknownError, message: \"ParseLiveQuery Error: Could not create subscription.\")\n        }\n\n        self.send(record: subscriptionRecord, requestId: requestId) { _ in }\n        return handler\n    }\n}\n\n// MARK: Unsubscribing\nextension ParseLiveQuery {\n\n    func unsubscribe<T>(_ query: Query<T>) throws where T: ParseObject {\n        let unsubscribeQuery = try ParseCoding.jsonEncoder().encode(query)\n        try unsubscribe { $0.queryData == unsubscribeQuery }\n    }\n\n    func unsubscribe<T>(_ handler: T) throws where T: QuerySubscribable {\n        let unsubscribeQuery = try ParseCoding.jsonEncoder().encode(handler.query)\n        try unsubscribe { $0.queryData == unsubscribeQuery && $0.subscriptionHandler === handler }\n    }\n\n    func unsubscribe(matching matcher: @escaping (SubscriptionRecord) -> Bool) throws {\n        try subscriptions.forEach { (key, value) -> Void in\n            if matcher(value) {\n                let encoded = try ParseCoding\n                    .jsonEncoder()\n                    .encode(StandardMessage(operation: .unsubscribe,\n                                            requestId: key))\n                let updatedRecord = value\n                updatedRecord.messageData = encoded\n                self.send(record: updatedRecord, requestId: key) { _ in }\n            }\n        }\n    }\n}\n\n// MARK: Updating\nextension ParseLiveQuery {\n\n    func update<T>(_ handler: T) throws where T: QuerySubscribable {\n        try subscriptions.forEach {(key, value) -> Void in\n            if value.subscriptionHandler === handler {\n                let message = SubscribeMessage<T.Object>(operation: .update, requestId: key, query: handler.query)\n                let updatedRecord = value\n                try updatedRecord.update(query: handler.query, message: message)\n                self.send(record: updatedRecord, requestId: key) { _ in }\n            }\n        }\n\n    }\n}\n\n// MARK: ParseLiveQuery - Subscribe\npublic extension Query {\n    #if canImport(Combine)\n    /**\n     Registers the query for live updates, using the default subscription handler,\n     and the default `ParseLiveQuery` client. Suitable for `ObjectObserved`\n     as the subscription can be used as a SwiftUI publisher. Meaning it can serve\n     indepedently as a ViewModel in MVVM.\n     */\n    var subscribe: Subscription<ResultType>? {\n        try? ParseLiveQuery.client?.subscribe(self)\n    }\n\n    /**\n     Registers the query for live updates, using the default subscription handler,\n     and a specific `ParseLiveQuery` client. Suitable for `ObjectObserved`\n     as the subscription can be used as a SwiftUI publisher. Meaning it can serve\n     indepedently as a ViewModel in MVVM.\n     - parameter client: A specific client.\n     - returns: The subscription that has just been registered.\n     - throws: An error of type `ParseError`.\n     */\n    func subscribe(_ client: ParseLiveQuery) throws -> Subscription<ResultType> {\n        try client.subscribe(Subscription(query: self))\n    }\n    #endif\n\n    /**\n     Registers a query for live updates, using a custom subscription handler.\n     - parameter handler: A custom subscription handler. \n     - returns: Your subscription handler, for easy chaining.\n     - throws: An error of type `ParseError`.\n    */\n    static func subscribe<T: QuerySubscribable>(_ handler: T) throws -> T {\n        if let client = ParseLiveQuery.client {\n            return try client.subscribe(handler)\n        } else {\n            throw ParseError(code: .unknownError, message: \"ParseLiveQuery Error: Not able to initialize client.\")\n        }\n    }\n\n    /**\n     Registers a query for live updates, using a custom subscription handler.\n     - parameter handler: A custom subscription handler.\n     - parameter client: A specific client.\n     - returns: Your subscription handler, for easy chaining.\n     - throws: An error of type `ParseError`.\n    */\n    static func subscribe<T: QuerySubscribable>(_ handler: T, client: ParseLiveQuery) throws -> T {\n        try client.subscribe(handler)\n    }\n\n    /**\n     Registers the query for live updates, using the default subscription handler,\n     and the default `ParseLiveQuery` client.\n     */\n    var subscribeCallback: SubscriptionCallback<ResultType>? {\n        try? ParseLiveQuery.client?.subscribe(self)\n    }\n\n    /**\n     Registers the query for live updates, using the default subscription handler,\n     and a specific `ParseLiveQuery` client.\n     - parameter client: A specific client.\n     - returns: The subscription that has just been registered.\n     - throws: An error of type `ParseError`.\n     */\n    func subscribeCallback(_ client: ParseLiveQuery) throws -> SubscriptionCallback<ResultType> {\n        try client.subscribe(SubscriptionCallback(query: self))\n    }\n}\n\n// MARK: ParseLiveQuery - Unsubscribe\npublic extension Query {\n    /**\n     Unsubscribes all current subscriptions for a given query on the default\n     `ParseLiveQuery` client.\n     - throws: An error of type `ParseError`.\n     */\n    func unsubscribe() throws {\n        try ParseLiveQuery.client?.unsubscribe(self)\n    }\n\n    /**\n     Unsubscribes all current subscriptions for a given query on a specific\n     `ParseLiveQuery` client.\n     - parameter client: A specific client.\n     - throws: An error of type `ParseError`.\n     */\n    func unsubscribe(client: ParseLiveQuery) throws {\n        try client.unsubscribe(self)\n    }\n\n    /**\n     Unsubscribes from a specific query-handler on the default\n     `ParseLiveQuery` client.\n     - parameter handler: The specific handler to unsubscribe from.\n     - throws: An error of type `ParseError`.\n     */\n    func unsubscribe<T: QuerySubscribable>(_ handler: T) throws {\n        try ParseLiveQuery.client?.unsubscribe(handler)\n    }\n\n    /**\n     Unsubscribes from a specific query-handler on a specific\n     `ParseLiveQuery` client.\n     - parameter handler: The specific handler to unsubscribe from.\n     - parameter client: A specific client.\n     - throws: An error of type `ParseError`.\n     */\n    func unsubscribe<T: QuerySubscribable>(_ handler: T, client: ParseLiveQuery) throws {\n        try client.unsubscribe(handler)\n    }\n}\n\n// MARK: ParseLiveQuery - Update\npublic extension Query {\n    /**\n     Updates an existing subscription with a new query on the default `ParseLiveQuery` client.\n     Upon completing the registration, the subscribe handler will be called with the new query.\n     - parameter handler: The specific handler to update.\n     - throws: An error of type `ParseError`.\n     */\n    func update<T: QuerySubscribable>(_ handler: T) throws {\n        try ParseLiveQuery.client?.update(handler)\n    }\n\n    /**\n     Updates an existing subscription with a new query on a specific `ParseLiveQuery` client.\n     Upon completing the registration, the subscribe handler will be called with the new query.\n     - parameter handler: The specific handler to update.\n     - parameter client: A specific client.\n     - throws: An error of type `ParseError`.\n     */\n    func update<T: QuerySubscribable>(_ handler: T, client: ParseLiveQuery) throws {\n        try client.update(handler)\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/LiveQuery/ParseLiveQueryConstants.swift",
    "content": "//\n//  ParseLiveQueryConstants.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/9/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\nenum ParseLiveQueryConstants {\n    static let maxConnectionAttempts = 20\n}\n"
  },
  {
    "path": "Sources/ParseSwift/LiveQuery/Protocols/LiveQuerySocketDelegate.swift",
    "content": "//\n//  LiveQuerySocketDelegate.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/4/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n#if !os(Linux) && !os(Android) && !os(Windows)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\n\nprotocol LiveQuerySocketDelegate: AnyObject {\n    func status(_ status: LiveQuerySocket.Status,\n                closeCode: URLSessionWebSocketTask.CloseCode?,\n                reason: Data?)\n    func close(useDedicatedQueue: Bool)\n    func receivedError(_ error: Error)\n    func receivedUnsupported(_ data: Data?, socketMessage: URLSessionWebSocketTask.Message?)\n    func received(challenge: URLAuthenticationChallenge,\n                  completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void)\n    func received(_ data: Data)\n    #if !os(watchOS)\n    func received(_ metrics: URLSessionTaskTransactionMetrics)\n    #endif\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/LiveQuery/Protocols/LiveQueryable.swift",
    "content": "//\n//  LiveQueryable.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/2/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\nprotocol LiveQueryable {}\n"
  },
  {
    "path": "Sources/ParseSwift/LiveQuery/Protocols/ParseLiveQueryDelegate.swift",
    "content": "//\n//  ParseLiveQueryDelegate.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/4/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n#if !os(Linux) && !os(Android) && !os(Windows)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\n\n// swiftlint:disable line_length\n\n/// Receive/respond to notifications from the ParseLiveQuery Server.\npublic protocol ParseLiveQueryDelegate: AnyObject {\n\n    /**\n     Respond to authentication requests from a ParseLiveQuery Server. If you become a delegate\n     and implement this method you will need to with\n     `completionHandler(.performDefaultHandling, nil)` to accept all connections approved\n     by the OS. Becoming a delegate allows you to make authentication decisions for all connections in\n     the `ParseLiveQuery` session, meaning there can only be one delegate for the whole session. The newest\n     instance to become the delegate will be the only one to receive authentication challenges.\n     - parameter challenge: An object that contains the request for authentication.\n     - parameter completionHandler: A handler that your delegate method must call. Its parameters are:\n       - disposition - One of several constants that describes how the challenge should be handled.\n       - credential - The credential that should be used for authentication if disposition is\n     URLSessionAuthChallengeUseCredential; otherwise, `nil`.\n     \n     See Apple's [documentation](https://developer.apple.com/documentation/foundation/urlsessiontaskdelegate/1411595-urlsession) for more for details.\n     */\n    func received(_ challenge: URLAuthenticationChallenge,\n                  completionHandler: @escaping (URLSession.AuthChallengeDisposition,\n                                                URLCredential?) -> Void)\n\n    /**\n    Receive errors from the ParseLiveQuery task/connection.\n     - parameter error: An error from the session task.\n     - note: The type of error received can vary from `ParseError`, `URLError`, `POSIXError`, etc.\n     */\n    func received(_ error: Error)\n\n    /**\n    Receive unsupported data from the ParseLiveQuery task/connection.\n     - parameter error: An error from the session task.\n     */\n    func receivedUnsupported(_ data: Data?, socketMessage: URLSessionWebSocketTask.Message?)\n\n    #if !os(watchOS)\n    /**\n    Receive metrics about the ParseLiveQuery task/connection.\n     - parameter metrics: An object that encapsualtes the performance metrics collected by the URL\n     Loading System during the execution of a session task.\n     See Apple's [documentation](https://developer.apple.com/documentation/foundation/urlsessiontasktransactionmetrics) for more for details.\n     */\n    func received(_ metrics: URLSessionTaskTransactionMetrics)\n    #endif\n\n    /**\n    Receive notifications when the ParseLiveQuery closes a task/connection.\n     - parameter code: The close code provided by the server.\n     - parameter reason: The close reason provided by the server.\n     If the close frame didn’t include a reason, this value is nil.\n     */\n    func closedSocket(_ code: URLSessionWebSocketTask.CloseCode?, reason: Data?)\n}\n\npublic extension ParseLiveQueryDelegate {\n    func received(_ challenge: URLAuthenticationChallenge,\n                  completionHandler: @escaping (URLSession.AuthChallengeDisposition,\n                                                URLCredential?) -> Void) {\n        completionHandler(.performDefaultHandling, nil)\n    }\n    func received(_ error: Error) { }\n    func receivedUnsupported(_ data: Data?, socketMessage: URLSessionWebSocketTask.Message?) { }\n    func received(_ metrics: URLSessionTaskTransactionMetrics) { }\n    func closedSocket(_ code: URLSessionWebSocketTask.CloseCode?, reason: Data?) { }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/LiveQuery/Protocols/QuerySubscribable.swift",
    "content": "//\n//  QuerySubscribable.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/2/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n This protocol describes the interface for handling events from a `ParseLiveQuery` client.\n You can use this protocol on any custom class of yours, instead of `Subscription` or\n `SubscriptionCallback`, if it fits your use case better.\n */\npublic protocol QuerySubscribable: AnyObject {\n\n    /// The `ParseObject` associated with this subscription.\n    associatedtype Object: ParseObject\n\n    /// The query associated with this subscription.\n    var query: Query<Object> { get set }\n\n    /**\n     Creates a new subscription that can be used to handle updates.\n     */\n    init(query: Query<Object>)\n\n    /**\n     Tells the handler that an event has been received from the `ParseLiveQuery` Server.\n     - parameter eventData: The event data that has been recieved from the server.\n     */\n    func didReceive(_ eventData: Data) throws\n\n    /**\n     Tells the handler that a query has been successfully registered with the server.\n     - note: This may be invoked multiple times if the client disconnects/reconnects.\n     */\n    func didSubscribe(_ new: Bool)\n\n    /**\n     Tells the handler that a query has been successfully deregistered from the server.\n     - note: This is not called unless `unsubscribe()` is explicitly called.\n     */\n    func didUnsubscribe()\n}\n"
  },
  {
    "path": "Sources/ParseSwift/LiveQuery/Subscription.swift",
    "content": "//\n//  Subscription.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/2/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n//\n\n#if canImport(Combine)\nimport Foundation\n\n/**\n A default implementation of the `QuerySubscribable` protocol. Suitable for `ObjectObserved`\n as the subscription can be used as a SwiftUI publisher. Meaning it can serve\n indepedently as a ViewModel in MVVM. Also can be used as a Combine publisher. See Apple's\n [documentation](https://developer.apple.com/documentation/combine/observableobject)\n for more details.\n */\nopen class Subscription<T: ParseObject>: QueryViewModel<T>, QuerySubscribable {\n\n    /// Updates and notifies when there is a new event related to a specific query.\n    open var event: (query: Query<T>, event: Event<T>)? {\n        willSet {\n            if newValue != nil {\n                subscribed = nil\n                unsubscribed = nil\n                DispatchQueue.main.async {\n                    self.objectWillChange.send()\n                }\n            }\n        }\n    }\n\n    /// Updates and notifies when a subscription request has been fulfilled and if it is new.\n    open var subscribed: (query: Query<T>, isNew: Bool)? {\n        willSet {\n            if newValue != nil {\n                unsubscribed = nil\n                event = nil\n                DispatchQueue.main.async {\n                    self.objectWillChange.send()\n                }\n            }\n        }\n    }\n\n    /// Updates and notifies when an unsubscribe request has been fulfilled.\n    open var unsubscribed: Query<T>? {\n        willSet {\n            if newValue != nil {\n                subscribed = nil\n                event = nil\n                DispatchQueue.main.async {\n                    self.objectWillChange.send()\n                }\n            }\n        }\n    }\n\n    /**\n     Creates a new subscription that can be used to handle updates.\n     */\n    public required init(query: Query<T>) {\n        super.init(query: query)\n        self.subscribed = nil\n        self.event = nil\n        self.unsubscribed = nil\n    }\n\n    // MARK: QuerySubscribable\n\n    open func didReceive(_ eventData: Data) throws {\n        // Need to decode the event with respect to the `ParseObject`.\n        let eventMessage = try ParseCoding.jsonDecoder().decode(EventResponse<T>.self, from: eventData)\n        guard let event = Event(event: eventMessage) else {\n            throw ParseError(code: .unknownError, message: \"ParseLiveQuery Error: Could not create event.\")\n        }\n        self.event = (query, event)\n    }\n\n    open func didSubscribe(_ new: Bool) {\n        self.subscribed = (query, new)\n    }\n\n    open func didUnsubscribe() {\n        self.unsubscribed = query\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/LiveQuery/SubscriptionCallback.swift",
    "content": "//\n//  SubscriptionCallback.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/24/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n A default implementation of the `QuerySubscribable` protocol using closures for callbacks.\n */\nopen class SubscriptionCallback<T: ParseObject>: QuerySubscribable {\n\n    public var query: Query<T>\n    public typealias Object = T\n    fileprivate var eventHandlers = [(Query<T>, Event<T>) -> Void]()\n    fileprivate var subscribeHandlers = [(Query<T>, Bool) -> Void]()\n    fileprivate var unsubscribeHandlers = [(Query<T>) -> Void]()\n\n    /**\n     Creates a new subscription that can be used to handle updates.\n     */\n    public required init(query: Query<T>) {\n        self.query = query\n    }\n\n    /**\n     Register a callback for when an event occurs.\n     - parameter handler: The callback to register.\n     - returns: The same subscription, for easy chaining.\n     */\n    @discardableResult open func handleEvent(_ handler: @escaping (Query<T>,\n                                                                   Event<T>) -> Void) -> SubscriptionCallback {\n        eventHandlers.append(handler)\n        return self\n    }\n\n    /**\n     Register a callback for when a client successfully subscribes to a query.\n     - parameter handler: The callback to register.\n     - returns: The same subscription, for easy chaining.\n     */\n    @discardableResult open func handleSubscribe(_ handler: @escaping (Query<T>,\n                                                                       Bool) -> Void) -> SubscriptionCallback {\n        subscribeHandlers.append(handler)\n        return self\n    }\n\n    /**\n     Register a callback for when a query has been unsubscribed.\n     - parameter handler: The callback to register.\n     - returns: The same subscription, for easy chaining.\n     */\n    @discardableResult open func handleUnsubscribe(_ handler: @escaping (Query<T>) -> Void) -> SubscriptionCallback {\n        unsubscribeHandlers.append(handler)\n        return self\n    }\n\n    /**\n     Register a callback for when an event occurs of a specific type\n     Example:\n         subscription.handle(Event.Created) { query, object in\n            // Called whenever an object is creaated\n         }\n     - parameter eventType: The event type to handle. You should pass one of the enum cases in `Event`.\n     - parameter handler: The callback to register.\n     - returns: The same subscription, for easy chaining.\n     */\n    @discardableResult public func handle(_ eventType: @escaping (T) -> Event<T>,\n                                          _ handler: @escaping (Query<T>, T) -> Void) -> SubscriptionCallback {\n        return handleEvent { query, event in\n            switch event {\n            case .entered(let obj) where eventType(obj) == event: handler(query, obj)\n            case .left(let obj)  where eventType(obj) == event: handler(query, obj)\n            case .created(let obj) where eventType(obj) == event: handler(query, obj)\n            case .updated(let obj) where eventType(obj) == event: handler(query, obj)\n            case .deleted(let obj) where eventType(obj) == event: handler(query, obj)\n            default: return\n            }\n        }\n    }\n\n    // MARK: QuerySubscribable\n\n    open func didReceive(_ eventData: Data) throws {\n        // Need to decode the event with respect to the `ParseObject`.\n        let eventMessage = try ParseCoding.jsonDecoder().decode(EventResponse<T>.self, from: eventData)\n        guard let event = Event(event: eventMessage) else {\n            throw ParseError(code: .unknownError, message: \"ParseLiveQuery Error: Could not create event.\")\n        }\n        eventHandlers.forEach { $0(query, event) }\n    }\n\n    open func didSubscribe(_ new: Bool) {\n        subscribeHandlers.forEach { $0(query, new) }\n    }\n\n    open func didUnsubscribe() {\n        unsubscribeHandlers.forEach { $0(query) }\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Objects/ParseCloudUser.swift",
    "content": "//\n//  ParseCloudUser.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/14/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/*\n A `ParseUser` that contains additional attributes\n needed for Parse hook calls.\n */\npublic protocol ParseCloudUser: ParseUser {\n    /// The session token of the `ParseUser`.\n    var sessionToken: String? { get set }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Objects/ParseInstallation+async.swift",
    "content": "//\n//  ParseInstallation+async.swift\n//  ParseInstallation+async\n//\n//  Created by Corey Baker on 8/6/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n\npublic extension ParseInstallation {\n\n    // MARK: Async/Await\n    /**\n     Fetches the `ParseInstallation` *aynchronously* with the current data from the server.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys one level deep. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns saved `ParseInstallation`.\n     - throws: An error of type `ParseError`.\n     - important: If an object fetched has the same objectId as current, it will automatically update the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult func fetch(includeKeys: [String]? = nil,\n                                  options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.fetch(includeKeys: includeKeys,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n\n    /**\n     Saves the `ParseInstallation` *asynchronously*.\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns saved `ParseInstallation`.\n     - throws: An error of type `ParseError`.\n     - important: If an object saved has the same objectId as current, it will automatically update the current.\n     - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true`\n     and plan to generate all of your `objectId`'s on the client-side then you should leave\n     `ignoringCustomObjectIdConfig = false`. Setting\n     `ParseConfiguration.isRequiringCustomObjectIds = true` and\n     `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s\n     and the server will generate an `objectId` only when the client does not provide one. This can\n     increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using\n     different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the\n     client-side checks are disabled. Developers are responsible for handling such cases.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult func save(ignoringCustomObjectIdConfig: Bool = false,\n                                 options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.save(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n\n    /**\n     Creates the `ParseInstallation` *asynchronously*.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns saved `ParseInstallation`.\n     - throws: An error of type `ParseError`.\n    */\n    @discardableResult func create(options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.create(options: options,\n                        completion: continuation.resume)\n        }\n    }\n\n    /**\n     Replaces the `ParseInstallation` *asynchronously*.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns saved `ParseInstallation`.\n     - throws: An error of type `ParseError`.\n     - important: If an object replaced has the same objectId as current, it will automatically replace the current.\n    */\n    @discardableResult func replace(options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.replace(options: options,\n                         completion: continuation.resume)\n        }\n    }\n\n    /**\n     Updates the `ParseInstallation` *asynchronously*.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns saved `ParseInstallation`.\n     - throws: An error of type `ParseError`.\n     - important: If an object updated has the same objectId as current, it will automatically update the current.\n    */\n    @discardableResult internal func update(options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.update(options: options,\n                        completion: continuation.resume)\n        }\n    }\n\n    /**\n     Deletes the `ParseInstallation` *asynchronously*.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns saved `ParseInstallation`.\n     - throws: An error of type `ParseError`.\n     - important: If an object deleted has the same objectId as current, it will automatically update the current.\n    */\n    func delete(options: API.Options = []) async throws {\n        let result = try await withCheckedThrowingContinuation { continuation in\n            self.delete(options: options, completion: continuation.resume)\n        }\n        if case let .failure(error) = result {\n            throw error\n        }\n    }\n\n    /**\n     Copy the `ParseInstallation` *asynchronously* based on the `objectId`.\n     On success, this saves the `ParseInstallation` to the keychain, so you can retrieve\n     the current installation using *current*.\n\n     - parameter objectId: The **id** of the `ParseInstallation` to become.\n     - parameter copyEntireInstallation: When **true**, copies the entire `ParseInstallation`.\n     When **false**, only the `channels` and `deviceToken` are copied; resulting in a new\n     `ParseInstallation` for original `sessionToken`. Defaults to **true**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult static func become(_ objectId: String,\n                                          copyEntireInstallation: Bool = true,\n                                          options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            Self.become(objectId,\n                        copyEntireInstallation: copyEntireInstallation,\n                        options: options,\n                        completion: continuation.resume)\n        }\n    }\n}\n\n// MARK: Batch Support\npublic extension Sequence where Element: ParseInstallation {\n    /**\n     Fetches a collection of installations *aynchronously* with the current data from the server and sets\n     an error if one occurs.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys one level deep. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns an array of Result enums with the object if a save was successful or a\n     `ParseError` if it failed.\n     - throws: An error of type `ParseError`.\n     - important: If an object fetched has the same objectId as current, it will automatically update the current.\n    */\n    @discardableResult func fetchAll(includeKeys: [String]? = nil,\n                                     options: API.Options = []) async throws -> [(Result<Self.Element, ParseError>)] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.fetchAll(includeKeys: includeKeys,\n                          options: options,\n                          completion: continuation.resume)\n        }\n    }\n\n    /**\n     Saves a collection of installations *asynchronously*.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns an array of Result enums with the object if a save was successful or a\n     `ParseError` if it failed.\n     - throws: An error of type `ParseError`.\n     - important: If an object saved has the same objectId as current, it will automatically update the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true`\n     and plan to generate all of your `objectId`'s on the client-side then you should leave\n     `ignoringCustomObjectIdConfig = false`. Setting\n     `ParseConfiguration.isRequiringCustomObjectIds = true` and\n     `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s\n     and the server will generate an `objectId` only when the client does not provide one. This can\n     increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using\n     different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the\n     client-side checks are disabled. Developers are responsible for handling such cases.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult func saveAll(batchLimit limit: Int? = nil,\n                                    transaction: Bool = configuration.isUsingTransactions,\n                                    ignoringCustomObjectIdConfig: Bool = false,\n                                    options: API.Options = []) async throws -> [(Result<Self.Element, ParseError>)] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.saveAll(batchLimit: limit,\n                         transaction: transaction,\n                         ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                         options: options,\n                         completion: continuation.resume)\n        }\n    }\n\n    /**\n     Creates a collection of installations *asynchronously*.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns an array of Result enums with the object if a save was successful or a\n     `ParseError` if it failed.\n     - throws: An error of type `ParseError`.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult func createAll(batchLimit limit: Int? = nil,\n                                      transaction: Bool = configuration.isUsingTransactions,\n                                      options: API.Options = []) async throws -> [(Result<Self.Element, ParseError>)] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.createAll(batchLimit: limit,\n                           transaction: transaction,\n                           options: options,\n                           completion: continuation.resume)\n        }\n    }\n\n    /**\n     Replaces a collection of installations *asynchronously*.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns an array of Result enums with the object if a save was successful or a\n     `ParseError` if it failed.\n     - throws: An error of type `ParseError`.\n     - important: If an object replaced has the same objectId as current, it will automatically replace the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult func replaceAll(batchLimit limit: Int? = nil,\n                                       transaction: Bool = configuration.isUsingTransactions,\n                                       options: API.Options = []) async throws -> [(Result<Self.Element, ParseError>)] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.replaceAll(batchLimit: limit,\n                            transaction: transaction,\n                            options: options,\n                            completion: continuation.resume)\n        }\n    }\n\n    /**\n     Updates a collection of installations *asynchronously*.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns an array of Result enums with the object if a save was successful or a\n     `ParseError` if it failed.\n     - throws: An error of type `ParseError`.\n     - important: If an object updated has the same objectId as current, it will automatically update the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    internal func updateAll(batchLimit limit: Int? = nil,\n                            transaction: Bool = configuration.isUsingTransactions,\n                            options: API.Options = []) async throws -> [(Result<Self.Element, ParseError>)] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.updateAll(batchLimit: limit,\n                           transaction: transaction,\n                           options: options,\n                           completion: continuation.resume)\n        }\n    }\n\n    /**\n     Deletes a collection of installations *asynchronously*.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Each element in the array is `nil` if the delete successful or a `ParseError` if it failed.\n     - throws: An error of type `ParseError`.\n     - important: If an object deleted has the same objectId as current, it will automatically update the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n    */\n    @discardableResult func deleteAll(batchLimit limit: Int? = nil,\n                                      transaction: Bool = configuration.isUsingTransactions,\n                                      options: API.Options = []) async throws -> [(Result<Void, ParseError>)] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.deleteAll(batchLimit: limit,\n                           transaction: transaction,\n                           options: options,\n                           completion: continuation.resume)\n        }\n    }\n}\n\n// MARK: Helper Methods (Internal)\ninternal extension ParseInstallation {\n\n    func command(method: Method,\n                 ignoringCustomObjectIdConfig: Bool = false,\n                 options: API.Options,\n                 callbackQueue: DispatchQueue) async throws -> Self {\n        let (savedChildObjects, savedChildFiles) = try await self.ensureDeepSave(options: options)\n        do {\n            let command: API.Command<Self, Self>!\n            switch method {\n            case .save:\n                command = try self.saveCommand(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig)\n            case .create:\n                command = self.createCommand()\n            case .replace:\n                command = try self.replaceCommand()\n            case .update:\n                command = try self.updateCommand()\n            }\n            let saved = try await command\n                .executeAsync(options: options,\n                              callbackQueue: callbackQueue,\n                              childObjects: savedChildObjects,\n                              childFiles: savedChildFiles)\n            try? Self.updateKeychainIfNeeded([saved])\n            return saved\n        } catch {\n            let defaultError = ParseError(code: .unknownError,\n                                          message: error.localizedDescription)\n            let parseError = error as? ParseError ?? defaultError\n            throw parseError\n        }\n    }\n}\n\n// MARK: Batch Support\ninternal extension Sequence where Element: ParseInstallation {\n    func batchCommand(method: Method,\n                      batchLimit limit: Int?,\n                      transaction: Bool,\n                      ignoringCustomObjectIdConfig: Bool = false,\n                      options: API.Options,\n                      callbackQueue: DispatchQueue) async throws -> [(Result<Element, ParseError>)] {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        var childObjects = [String: PointerType]()\n        var childFiles = [UUID: ParseFile]()\n        var commands = [API.Command<Self.Element, Self.Element>]()\n        let objects = map { $0 }\n        for object in objects {\n            let (savedChildObjects, savedChildFiles) = try await object\n                .ensureDeepSave(options: options,\n                                isShouldReturnIfChildObjectsFound: transaction)\n            try savedChildObjects.forEach {(key, value) in\n                guard childObjects[key] == nil else {\n                    throw ParseError(code: .unknownError, message: \"circular dependency\")\n                }\n                childObjects[key] = value\n            }\n            try savedChildFiles.forEach {(key, value) in\n                guard childFiles[key] == nil else {\n                    throw ParseError(code: .unknownError, message: \"circular dependency\")\n                }\n                childFiles[key] = value\n            }\n            do {\n                switch method {\n                case .save:\n                    commands.append(\n                        try object.saveCommand(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig)\n                    )\n                case .create:\n                    commands.append(object.createCommand())\n                case .replace:\n                    commands.append(try object.replaceCommand())\n                case .update:\n                    commands.append(try object.updateCommand())\n                }\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                throw parseError\n            }\n        }\n\n        do {\n            var returnBatch = [(Result<Self.Element, ParseError>)]()\n            let batchLimit = limit != nil ? limit! : ParseConstants.batchLimit\n            try canSendTransactions(transaction, objectCount: commands.count, batchLimit: batchLimit)\n            let batches = BatchUtils.splitArray(commands, valuesPerSegment: batchLimit)\n            for batch in batches {\n                let saved = try await API.Command<Self.Element, Self.Element>\n                        .batch(commands: batch, transaction: transaction)\n                        .executeAsync(options: options,\n                                      batching: true,\n                                      callbackQueue: callbackQueue,\n                                      childObjects: childObjects,\n                                      childFiles: childFiles)\n                returnBatch.append(contentsOf: saved)\n            }\n            try? Self.Element.updateKeychainIfNeeded(returnBatch.compactMap {try? $0.get()})\n            return returnBatch\n        } catch {\n            let defaultError = ParseError(code: .unknownError,\n                                          message: error.localizedDescription)\n            let parseError = error as? ParseError ?? defaultError\n            throw parseError\n        }\n    }\n}\n\n#if !os(Linux) && !os(Android) && !os(Windows)\n// MARK: Migrate from Objective-C SDK\npublic extension ParseInstallation {\n    /**\n     Migrates the `ParseInstallation` *asynchronously* from the Objective-C SDK Keychain.\n\n     - parameter copyEntireInstallation: When **true**, copies the\n     entire `ParseInstallation` from the Objective-C SDK Keychain to the Swift SDK. When\n     **false**, only the `channels` and `deviceToken` are copied from the Objective-C\n     SDK Keychain; resulting in a new `ParseInstallation` for original `sessionToken`.\n     Defaults to **true**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns saved `ParseInstallation`.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - warning: When initializing the Swift SDK, `migratingFromObjcSDK` should be set to **false**\n     when calling this method.\n     - warning: The latest **PFInstallation** from the Objective-C SDK should be saved to your\n     Parse Server before calling this method.\n    */\n    @available(*, deprecated, message: \"This does not work, use become() instead\")\n    @discardableResult static func migrateFromObjCKeychain(copyEntireInstallation: Bool = true,\n                                                           options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            Self.migrateFromObjCKeychain(copyEntireInstallation: copyEntireInstallation,\n                                         options: options,\n                                         completion: continuation.resume)\n        }\n    }\n\n    /**\n     Deletes the Objective-C Keychain along with the Objective-C `ParseInstallation`\n     from the Parse Server *asynchronously*.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns saved `ParseInstallation`.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - warning: When initializing the Swift SDK, `migratingFromObjcSDK` should be set to **false**\n     when calling this method.\n     - warning: It is recommended to only use this method after a succesfful migration. Calling this\n     method will destroy the entire Objective-C Keychain and `ParseInstallation` on the Parse\n     Server. This method assumes **PFInstallation.installationId** is saved to the Keychain. If the\n     **installationId** is not saved to the Keychain, this method will not work.\n    */\n    static func deleteObjCKeychain(options: API.Options = []) async throws {\n        let result = try await withCheckedThrowingContinuation { continuation in\n            Self.deleteObjCKeychain(options: options, completion: continuation.resume)\n        }\n        if case let .failure(error) = result {\n            throw error\n        }\n    }\n}\n#endif\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Objects/ParseInstallation+combine.swift",
    "content": "//\n//  ParseInstallation+combine.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/29/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\npublic extension ParseInstallation {\n\n    // MARK: Combine\n    /**\n     Fetches the `ParseInstallation` *aynchronously* with the current data from the server.\n     Publishes when complete.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys one level deep. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - important: If an object fetched has the same objectId as current, it will automatically update the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func fetchPublisher(includeKeys: [String]? = nil,\n                        options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.fetch(includeKeys: includeKeys,\n                       options: options,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Saves the `ParseInstallation` *asynchronously* and publishes when complete.\n\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - important: If an object saved has the same objectId as current, it will automatically update the current.\n     - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true`\n     and plan to generate all of your `objectId`'s on the client-side then you should leave\n     `ignoringCustomObjectIdConfig = false`. Setting\n     `ParseConfiguration.isRequiringCustomObjectIds = true` and\n     `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s\n     and the server will generate an `objectId` only when the client does not provide one. This can\n     increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using\n     different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the\n     client-side checks are disabled. Developers are responsible for handling such cases.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func savePublisher(ignoringCustomObjectIdConfig: Bool = false,\n                       options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.save(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                      options: options,\n                      completion: promise)\n        }\n    }\n\n    /**\n     Creates the `ParseInstallation` *asynchronously* and publishes when complete.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n    */\n    func createPublisher(options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.create(options: options,\n                        completion: promise)\n        }\n    }\n\n    /**\n     Replaces the `ParseInstallation` *asynchronously* and publishes when complete.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - important: If an object replaced has the same objectId as current, it will automatically replace the current.\n    */\n    func replacePublisher(options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.replace(options: options,\n                         completion: promise)\n        }\n    }\n\n    /**\n     Updates the `ParseInstallation` *asynchronously* and publishes when complete.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - important: If an object updated has the same objectId as current, it will automatically update the current.\n    */\n    internal func updatePublisher(options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.update(options: options,\n                        completion: promise)\n        }\n    }\n\n    /**\n     Deletes the `ParseInstallation` *asynchronously* and publishes when complete.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - important: If an object deleted has the same objectId as current, it will automatically update the current.\n    */\n    func deletePublisher(options: API.Options = []) -> Future<Void, ParseError> {\n        Future { promise in\n            self.delete(options: options, completion: promise)\n        }\n    }\n\n    /**\n     Copies the `ParseInstallation` *asynchronously* based on the `installationId` and publishes\n     when complete. On success, this saves the `ParseInstallation` to the keychain, so you can retrieve\n     the current installation using *current*.\n\n     - parameter installationId: The **id** of the `ParseInstallation` to become.\n     - parameter copyEntireInstallation: When **true**, copies the entire `ParseInstallation`.\n     When **false**, only the `channels` and `deviceToken` are copied; resulting in a new\n     `ParseInstallation` for original `sessionToken`. Defaults to **true**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    static func becomePublisher(_ installationId: String,\n                                copyEntireInstallation: Bool = true,\n                                options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            Self.become(installationId,\n                        copyEntireInstallation: copyEntireInstallation,\n                        options: options,\n                        completion: promise)\n        }\n    }\n}\n\n// MARK: Batch Support\npublic extension Sequence where Element: ParseInstallation {\n    /**\n     Fetches a collection of installations *aynchronously* with the current data from the server and sets\n     an error if one occurs. Publishes when complete.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys one level deep. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces an an array of Result enums with the object if a fetch was\n     successful or a `ParseError` if it failed.\n     - important: If an object fetched has the same objectId as current, it will automatically update the current.\n    */\n    func fetchAllPublisher(includeKeys: [String]? = nil,\n                           options: API.Options = []) -> Future<[(Result<Self.Element, ParseError>)], ParseError> {\n        Future { promise in\n            self.fetchAll(includeKeys: includeKeys,\n                          options: options,\n                          completion: promise)\n        }\n    }\n\n    /**\n     Saves a collection of installations *asynchronously* and publishes when complete.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces an an array of Result enums with the object if a save was\n     successful or a `ParseError` if it failed.\n     - important: If an object saved has the same objectId as current, it will automatically update the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true`\n     and plan to generate all of your `objectId`'s on the client-side then you should leave\n     `ignoringCustomObjectIdConfig = false`. Setting\n     `ParseConfiguration.isRequiringCustomObjectIds = true` and\n     `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s\n     and the server will generate an `objectId` only when the client does not provide one. This can\n     increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using\n     different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the\n     client-side checks are disabled. Developers are responsible for handling such cases.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func saveAllPublisher(batchLimit limit: Int? = nil,\n                          transaction: Bool = configuration.isUsingTransactions,\n                          ignoringCustomObjectIdConfig: Bool = false,\n                          options: API.Options = []) -> Future<[(Result<Self.Element, ParseError>)], ParseError> {\n        Future { promise in\n            self.saveAll(batchLimit: limit,\n                         transaction: transaction,\n                         ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                         options: options,\n                         completion: promise)\n        }\n    }\n\n    /**\n     Creates a collection of installations *asynchronously* and publishes when complete.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces an an array of Result enums with the object if a save was\n     successful or a `ParseError` if it failed.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func createAllPublisher(batchLimit limit: Int? = nil,\n                            transaction: Bool = configuration.isUsingTransactions,\n                            options: API.Options = []) -> Future<[(Result<Self.Element, ParseError>)], ParseError> {\n        Future { promise in\n            self.createAll(batchLimit: limit,\n                           transaction: transaction,\n                           options: options,\n                           completion: promise)\n        }\n    }\n\n    /**\n     Replaces a collection of installations *asynchronously* and publishes when complete.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces an an array of Result enums with the object if a save was\n     successful or a `ParseError` if it failed.\n     - important: If an object replaced has the same objectId as current, it will automatically replace the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func replaceAllPublisher(batchLimit limit: Int? = nil,\n                             transaction: Bool = configuration.isUsingTransactions,\n                             options: API.Options = []) -> Future<[(Result<Self.Element, ParseError>)], ParseError> {\n        Future { promise in\n            self.replaceAll(batchLimit: limit,\n                            transaction: transaction,\n                            options: options,\n                            completion: promise)\n        }\n    }\n\n    /**\n     Updates a collection of installations *asynchronously* and publishes when complete.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces an an array of Result enums with the object if a save was\n     successful or a `ParseError` if it failed.\n     - important: If an object updated has the same objectId as current, it will automatically update the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    internal func updateAllPublisher(batchLimit limit: Int? = nil,\n                                     transaction: Bool = configuration.isUsingTransactions,\n                                     options: API.Options = []) -> Future<[(Result<Self.Element, ParseError>)],\n                                                                            ParseError> {\n        Future { promise in\n            self.updateAll(batchLimit: limit,\n                           transaction: transaction,\n                           options: options,\n                           completion: promise)\n        }\n    }\n\n    /**\n     Deletes a collection of installations *asynchronously* and publishes when complete.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces an an array of Result enums with `nil` if a delete was\n     successful or a `ParseError` if it failed.\n     - important: If an object deleted has the same objectId as current, it will automatically update the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n    */\n    func deleteAllPublisher(batchLimit limit: Int? = nil,\n                            transaction: Bool = configuration.isUsingTransactions,\n                            options: API.Options = []) -> Future<[(Result<Void, ParseError>)], ParseError> {\n        Future { promise in\n            self.deleteAll(batchLimit: limit,\n                           transaction: transaction,\n                           options: options,\n                           completion: promise)\n        }\n    }\n}\n\n#if !os(Linux) && !os(Android) && !os(Windows)\n// MARK: Migrate from Objective-C SDK\npublic extension ParseInstallation {\n\n    /**\n     Migrates the `ParseInstallation` *asynchronously* from the Objective-C SDK Keychain\n     and publishes when complete.\n\n     - parameter copyEntireInstallation: When **true**, copies the\n     entire `ParseInstallation` from the Objective-C SDK Keychain to the Swift SDK. When\n     **false**, only the `channels` and `deviceToken` are copied from the Objective-C\n     SDK Keychain; resulting in a new `ParseInstallation` for original `sessionToken`.\n     Defaults to **true**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - warning: When initializing the Swift SDK, `migratingFromObjcSDK` should be set to **false**\n     when calling this method.\n     - warning: The latest **PFInstallation** from the Objective-C SDK should be saved to your\n     Parse Server before calling this method. This method assumes **PFInstallation.installationId** is saved\n     to the Keychain. If the **installationId** is not saved to the Keychain, this method will not work.\n    */\n    @available(*, deprecated, message: \"This does not work, use become() instead\")\n    static func migrateFromObjCKeychainPublisher(copyEntireInstallation: Bool = true,\n                                                 options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            Self.migrateFromObjCKeychain(copyEntireInstallation: copyEntireInstallation,\n                                         options: options,\n                                         completion: promise)\n        }\n    }\n\n    /**\n     Deletes the Objective-C Keychain along with the Objective-C `ParseInstallation`\n     from the Parse Server *asynchronously* and publishes when complete.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - warning: It is recommended to only use this method after a succesfful migration. Calling this\n     method will destroy the entire Objective-C Keychain and `ParseInstallation` on the Parse\n     Server.\n    */\n    static func deleteObjCKeychainPublisher(options: API.Options = []) -> Future<Void, ParseError> {\n        Future { promise in\n            Self.deleteObjCKeychain(options: options, completion: promise)\n        }\n    }\n}\n#endif\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Objects/ParseInstallation.swift",
    "content": "//\n//  ParseInstallation.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/6/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n Objects that conform to the `ParseInstallation` protocol have a local representation of an\n installation persisted to the Keychain and Parse Server. This protocol inherits from the\n `ParseObject` protocol, and retains the same functionality of a `ParseObject`, but also extends\n it with installation-specific fields and related immutability and validity\n checks.\n\n A valid `ParseInstallation` can only be instantiated via\n *current* because the required identifier fields\n are readonly. The `timeZone` is also a readonly property which\n is automatically updated to match the device's time zone\n when the `ParseInstallation` is saved, thus these fields might not reflect the\n latest device state if the installation has not recently been saved.\n `ParseInstallation`s which have a valid `deviceToken` and are saved to\n the Parse Server can be used to target push notifications. Use `setDeviceToken` to set the\n `deviceToken` properly.\n\n - warning: If the use of badge is desired, it should be retrieved by using UIKit, AppKit, etc. and\n stored in `ParseInstallation.badge` when saving/updating the installation.\n - warning: Linux, Android, and Windows developers should set `appName`,\n `appIdentifier`, and `appVersion` manually as `ParseSwift` does not have access\n to Bundle.main.\n*/\npublic protocol ParseInstallation: ParseObject {\n\n    /**\n     The device type for the `ParseInstallation`.\n    */\n    var deviceType: String? { get set }\n\n    /**\n     The installationId for the `ParseInstallation`.\n    */\n    var installationId: String? { get set }\n\n    /**\n     The device token for the `ParseInstallation`.\n    */\n    var deviceToken: String? { get set }\n\n    /**\n     The badge for the `ParseInstallation`.\n    */\n    var badge: Int? { get set }\n\n    /**\n     The name of the time zone for the `ParseInstallation`.\n    */\n    var timeZone: String? { get set }\n\n    /**\n     The channels for the `ParseInstallation`.\n    */\n    var channels: [String]? { get set }\n\n    /**\n     The application name  for the `ParseInstallation`.\n     */\n    var appName: String? { get set }\n\n    /**\n     The application identifier for the `ParseInstallation`.\n     */\n    var appIdentifier: String? { get set }\n\n    /**\n     The application version for the `ParseInstallation`.\n     */\n    var appVersion: String? { get set }\n\n    /**\n     The sdk version for the `ParseInstallation`.\n     */\n    var parseVersion: String? { get set }\n\n    /**\n     The locale identifier for the `ParseInstallation`.\n     */\n    var localeIdentifier: String? { get set }\n}\n\n// MARK: Default Implementations\npublic extension ParseInstallation {\n    static var className: String {\n        \"_Installation\"\n    }\n\n    func mergeParse(with object: Self) throws -> Self {\n        guard hasSameObjectId(as: object) else {\n            throw ParseError(code: .unknownError,\n                             message: \"objectId's of objects do not match\")\n        }\n        var updatedInstallation = self\n        if shouldRestoreKey(\\.ACL,\n                             original: object) {\n            updatedInstallation.ACL = object.ACL\n        }\n        if shouldRestoreKey(\\.deviceType,\n                             original: object) {\n            updatedInstallation.deviceType = object.deviceType\n        }\n        if shouldRestoreKey(\\.installationId,\n                             original: object) {\n            updatedInstallation.installationId = object.installationId\n        }\n        if shouldRestoreKey(\\.deviceToken,\n                                 original: object) {\n            updatedInstallation.deviceToken = object.deviceToken\n        }\n        if shouldRestoreKey(\\.badge,\n                             original: object) {\n            updatedInstallation.badge = object.badge\n        }\n        if shouldRestoreKey(\\.timeZone,\n                             original: object) {\n            updatedInstallation.timeZone = object.timeZone\n        }\n        if shouldRestoreKey(\\.channels,\n                             original: object) {\n            updatedInstallation.channels = object.channels\n        }\n        if shouldRestoreKey(\\.appName,\n                             original: object) {\n            updatedInstallation.appName = object.appName\n        }\n        if shouldRestoreKey(\\.appIdentifier,\n                             original: object) {\n            updatedInstallation.appIdentifier = object.appIdentifier\n        }\n        if shouldRestoreKey(\\.appVersion,\n                             original: object) {\n            updatedInstallation.appVersion = object.appVersion\n        }\n        if shouldRestoreKey(\\.parseVersion,\n                             original: object) {\n            updatedInstallation.parseVersion = object.parseVersion\n        }\n        if shouldRestoreKey(\\.localeIdentifier,\n                             original: object) {\n            updatedInstallation.localeIdentifier = object.localeIdentifier\n        }\n        return updatedInstallation\n    }\n\n    func merge(with object: Self) throws -> Self {\n        do {\n            return try mergeAutomatically(object)\n        } catch {\n            return try mergeParse(with: object)\n        }\n    }\n}\n\n// MARK: Convenience\nextension ParseInstallation {\n    var endpoint: API.Endpoint {\n        if let objectId = objectId {\n            return .installation(objectId: objectId)\n        }\n\n        return .installations\n    }\n\n    func endpoint(_ method: API.Method) -> API.Endpoint {\n        if !Parse.configuration.isRequiringCustomObjectIds || method != .POST {\n            return endpoint\n        } else {\n            return .installations\n        }\n    }\n\n    func hasSameInstallationId<T: ParseInstallation>(as other: T) -> Bool {\n        return other.className == className && other.installationId == installationId && installationId != nil\n    }\n\n    /**\n     Sets the device token string property from an `Data`-encoded token.\n     - parameter data: A token that identifies the device.\n     */\n    mutating public func setDeviceToken(_ data: Data) {\n        let deviceTokenString = data.hexEncodedString()\n        if deviceToken != deviceTokenString {\n            deviceToken = deviceTokenString\n        }\n    }\n}\n\n// MARK: CurrentInstallationContainer\nstruct CurrentInstallationContainer<T: ParseInstallation>: Codable, Hashable {\n    var currentInstallation: T?\n    var installationId: String?\n}\n\n// MARK: Current Installation Support\npublic extension ParseInstallation {\n    internal static var currentContainer: CurrentInstallationContainer<Self> {\n        get {\n            guard let installationInMemory: CurrentInstallationContainer<Self> =\n                    try? ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentInstallation) else {\n                #if !os(Linux) && !os(Android) && !os(Windows)\n                guard let installationFromKeyChain: CurrentInstallationContainer<Self> =\n                        try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation)\n                else {\n                    let newInstallationId = UUID().uuidString.lowercased()\n                    var newInstallation = BaseParseInstallation()\n                    newInstallation.installationId = newInstallationId\n                    newInstallation.createInstallationId(newId: newInstallationId)\n                    newInstallation.updateAutomaticInfo()\n                    let newBaseInstallationContainer =\n                        CurrentInstallationContainer<BaseParseInstallation>(currentInstallation: newInstallation,\n                                                                            installationId: newInstallationId)\n                    try? KeychainStore.shared.set(newBaseInstallationContainer,\n                                                  for: ParseStorage.Keys.currentInstallation)\n                    guard let installationFromKeyChain: CurrentInstallationContainer<Self> =\n                            try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation)\n                    else {\n                        // Could not create container correctly, return empty one.\n                        return CurrentInstallationContainer<Self>()\n                    }\n                    try? ParseStorage.shared.set(installationFromKeyChain, for: ParseStorage.Keys.currentInstallation)\n                    return installationFromKeyChain\n                }\n                return installationFromKeyChain\n                #else\n                let newInstallationId = UUID().uuidString.lowercased()\n                var newInstallation = BaseParseInstallation()\n                newInstallation.installationId = newInstallationId\n                newInstallation.createInstallationId(newId: newInstallationId)\n                newInstallation.updateAutomaticInfo()\n                let newBaseInstallationContainer =\n                    CurrentInstallationContainer<BaseParseInstallation>(currentInstallation: newInstallation,\n                                                                        installationId: newInstallationId)\n                try? ParseStorage.shared.set(newBaseInstallationContainer,\n                                              for: ParseStorage.Keys.currentInstallation)\n                guard let installationFromMemory: CurrentInstallationContainer<Self> =\n                        try? ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentInstallation)\n                else {\n                    // Could not create container correctly, return empty one.\n                    return CurrentInstallationContainer<Self>()\n                }\n                return installationFromMemory\n                #endif\n            }\n            return installationInMemory\n        }\n        set {\n            try? ParseStorage.shared.set(newValue, for: ParseStorage.Keys.currentInstallation)\n        }\n    }\n\n    internal static func updateInternalFieldsCorrectly() {\n\n        if let currentContainerInstallationId = Self.currentContainer.installationId,\n            Self.currentContainer.currentInstallation?.installationId !=\n            currentContainerInstallationId {\n\n            // If the user made changes, set back to the original\n            Self.currentContainer.currentInstallation?.installationId =\n            currentContainerInstallationId\n        }\n\n        // Always pull automatic info to ensure user made no changes to immutable values\n        Self.currentContainer.currentInstallation?.updateAutomaticInfo()\n    }\n\n    internal static func saveCurrentContainerToKeychain() {\n        Self.currentContainer.currentInstallation?.originalData = nil\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try? KeychainStore.shared.set(currentContainer, for: ParseStorage.Keys.currentInstallation)\n        #endif\n    }\n\n    internal static func deleteCurrentContainerFromKeychain() {\n        try? ParseStorage.shared.delete(valueFor: ParseStorage.Keys.currentInstallation)\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try? KeychainStore.shared.delete(valueFor: ParseStorage.Keys.currentInstallation)\n        #endif\n        // Prepare new installation\n        BaseParseInstallation.createNewInstallationIfNeeded()\n    }\n\n    /**\n     Gets/Sets properties of the current installation in the Keychain.\n\n     - returns: Returns a `ParseInstallation` that is the current device. If there is none, returns `nil`.\n    */\n    internal(set) static var current: Self? {\n        get {\n            return Self.currentContainer.currentInstallation\n        }\n        set {\n            Self.currentContainer.currentInstallation = newValue\n            Self.updateInternalFieldsCorrectly()\n        }\n    }\n\n    /**\n     Copy the `ParseInstallation` *asynchronously* based on the `objectId`.\n     On success, this saves the `ParseInstallation` to the keychain, so you can retrieve\n     the current installation using *current*.\n\n     - parameter objectId: The **id** of the `ParseInstallation` to become.\n     - parameter copyEntireInstallation: When **true**, copies the entire `ParseInstallation`.\n     When **false**, only the `channels` and `deviceToken` are copied; resulting in a new\n     `ParseInstallation` for original `sessionToken`. Defaults to **true**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    static func become(_ objectId: String,\n                       copyEntireInstallation: Bool = true,\n                       options: API.Options = [],\n                       callbackQueue: DispatchQueue = .main,\n                       completion: @escaping (Result<Self, ParseError>) -> Void) {\n        guard var currentInstallation = Self.current else {\n            let error = ParseError(code: .unknownError,\n                                   message: \"Current installation does not exist\")\n            callbackQueue.async {\n                completion(.failure(error))\n            }\n            return\n        }\n        guard currentInstallation.objectId != objectId else {\n            // If the installationId's are the same, assume successful replacement already occured.\n            callbackQueue.async {\n                completion(.success(currentInstallation))\n            }\n            return\n        }\n        currentInstallation.objectId = objectId\n        currentInstallation.fetch(options: options, callbackQueue: callbackQueue) { result in\n            switch result {\n            case .success(var updatedInstallation):\n                if copyEntireInstallation {\n                    updatedInstallation.updateAutomaticInfo()\n                    Self.currentContainer.installationId = updatedInstallation.installationId\n                    Self.currentContainer.currentInstallation = updatedInstallation\n                } else {\n                    Self.current?.channels = updatedInstallation.channels\n                    if Self.current?.deviceToken == nil {\n                        Self.current?.deviceToken = updatedInstallation.deviceToken\n                    }\n                }\n                Self.saveCurrentContainerToKeychain()\n                guard let latestInstallation = Self.current else {\n                    let error = ParseError(code: .unknownError,\n                                           message: \"Had trouble migrating the installation\")\n                    callbackQueue.async {\n                        completion(.failure(error))\n                    }\n                    return\n                }\n                latestInstallation.save(options: options,\n                                        callbackQueue: callbackQueue,\n                                        completion: completion)\n            case .failure(let error):\n                callbackQueue.async {\n                    completion(.failure(error))\n                }\n            }\n        }\n    }\n}\n\n// MARK: Automatic Info\nextension ParseInstallation {\n    mutating func updateAutomaticInfo() {\n        updateDeviceTypeFromDevice()\n        updateTimeZoneFromDevice()\n        updateVersionInfoFromDevice()\n        updateLocaleIdentifierFromDevice()\n    }\n\n    mutating func createInstallationId(newId: String) {\n        if installationId == nil {\n            installationId = newId\n        }\n    }\n\n    mutating func updateDeviceTypeFromDevice() {\n        if deviceType != ParseConstants.deviceType {\n            deviceType = ParseConstants.deviceType\n        }\n    }\n\n    mutating func updateTimeZoneFromDevice() {\n        let currentTimeZone = TimeZone.current.identifier\n        if timeZone != currentTimeZone {\n            timeZone = currentTimeZone\n        }\n    }\n\n    mutating func updateVersionInfoFromDevice() {\n        guard let appInfo = Bundle.main.infoDictionary else {\n            return\n        }\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        #if TARGET_OS_MACCATALYST\n        // If using an Xcode new enough to know about Mac Catalyst:\n        // Mac Catalyst Apps use a prefix to the bundle ID. This should not be transmitted\n        // to Parse Server. Catalyst apps should look like iOS apps otherwise\n        // push and other services do not work properly.\n        if let currentAppIdentifier = appInfo[String(kCFBundleIdentifierKey)] as? String {\n            let macCatalystBundleIdPrefix = \"maccatalyst.\"\n            if currentAppIdentifier.hasPrefix(macCatalystBundleIdPrefix) {\n                appIdentifier = currentAppIdentifier.replacingOccurrences(of: macCatalystBundleIdPrefix, with: \"\")\n            }\n        }\n\n        #else\n        if let currentAppIdentifier = appInfo[String(kCFBundleIdentifierKey)] as? String {\n            if appIdentifier != currentAppIdentifier {\n                appIdentifier = currentAppIdentifier\n            }\n        }\n        #endif\n\n        if let currentAppName = appInfo[String(kCFBundleNameKey)] as? String {\n            if appName != currentAppName {\n                appName = currentAppName\n            }\n        }\n\n        if let currentAppVersion = appInfo[String(kCFBundleVersionKey)] as? String {\n            if appVersion != currentAppVersion {\n                appVersion = currentAppVersion\n            }\n        }\n        #endif\n\n        if parseVersion != ParseConstants.version {\n            parseVersion = ParseConstants.version\n        }\n    }\n\n    /**\n     Save localeIdentifier in the following format: [language code]-[COUNTRY CODE].\n\n     The language codes are two-letter lowercase ISO language codes (such as \"en\") as defined by\n     <a href=\"http://en.wikipedia.org/wiki/ISO_639-1\">ISO 639-1</a>.\n     The country codes are two-letter uppercase ISO country codes (such as \"US\") as defined by\n     <a href=\"http://en.wikipedia.org/wiki/ISO_3166-1_alpha-3\">ISO 3166-1</a>.\n\n     Many iOS locale identifiers do not contain the country code -> inconsistencies with Android/Windows Phone.\n    */\n    mutating func updateLocaleIdentifierFromDevice() {\n        guard let language = Locale.current.languageCode else {\n            return\n        }\n\n        let currentLocalIdentifier: String!\n        if let regionCode = Locale.current.regionCode {\n            currentLocalIdentifier = \"\\(language)-\\(regionCode)\"\n        } else {\n            currentLocalIdentifier = language\n        }\n\n        if localeIdentifier != currentLocalIdentifier {\n            localeIdentifier = currentLocalIdentifier\n        }\n    }\n}\n\n// MARK: Fetchable\nextension ParseInstallation {\n    internal static func updateKeychainIfNeeded(_ results: [Self], deleting: Bool = false) throws {\n        guard let currentInstallation = Self.current else {\n            return\n        }\n\n        var foundCurrentInstallationObjects = results.filter { $0.hasSameInstallationId(as: currentInstallation) }\n        foundCurrentInstallationObjects = try foundCurrentInstallationObjects.sorted(by: {\n            guard let firstUpdatedAt = $0.updatedAt,\n                  let secondUpdatedAt = $1.updatedAt else {\n                throw ParseError(code: .unknownError,\n                                 message: \"Objects from the server should always have an \\\"updatedAt\\\"\")\n            }\n            return firstUpdatedAt.compare(secondUpdatedAt) == .orderedDescending\n        })\n        if let foundCurrentInstallation = foundCurrentInstallationObjects.first {\n            if !deleting {\n                Self.current = foundCurrentInstallation\n                Self.saveCurrentContainerToKeychain()\n            } else {\n                Self.deleteCurrentContainerFromKeychain()\n            }\n        }\n    }\n\n    /**\n     Fetches the `ParseInstallation` *synchronously* with the current data from the server.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys one level deep. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of `ParseError` type.\n     - important: If an object fetched has the same objectId as current, it will automatically update the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func fetch(includeKeys: [String]? = nil,\n                      options: API.Options = []) throws -> Self {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        let result: Self = try fetchCommand(include: includeKeys)\n            .execute(options: options)\n        try Self.updateKeychainIfNeeded([result])\n        return result\n    }\n\n    /**\n     Fetches the `ParseInstallation` *asynchronously* and executes the given callback block.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys one level deep. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - important: If an object fetched has the same objectId as current, it will automatically update the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func fetch(\n        includeKeys: [String]? = nil,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<Self, ParseError>) -> Void\n    ) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n         do {\n            try fetchCommand(include: includeKeys)\n                .executeAsync(options: options,\n                              callbackQueue: callbackQueue) { result in\n                    if case .success(let foundResult) = result {\n                        do {\n                            try Self.updateKeychainIfNeeded([foundResult])\n                            completion(.success(foundResult))\n                        } catch {\n                            let defaultError = ParseError(code: .unknownError,\n                                                          message: error.localizedDescription)\n                            let parseError = error as? ParseError ?? defaultError\n                            callbackQueue.async {\n                                completion(.failure(parseError))\n                            }\n                        }\n                    } else {\n                        completion(result)\n                    }\n                }\n         } catch {\n            callbackQueue.async {\n                if let error = error as? ParseError {\n                    completion(.failure(error))\n                } else {\n                    completion(.failure(ParseError(code: .unknownError,\n                                                   message: error.localizedDescription)))\n                }\n            }\n         }\n    }\n\n    func fetchCommand(include: [String]?) throws -> API.Command<Self, Self> {\n        guard objectId != nil else {\n            throw ParseError(code: .missingObjectId,\n                             message: \"objectId must not be nil\")\n        }\n\n        var params: [String: String]?\n        if let includeParams = include {\n            params = [\"include\": \"\\(Set(includeParams))\"]\n        }\n\n        return API.Command(method: .GET,\n                           path: endpoint,\n                           params: params) { (data) -> Self in\n            try ParseCoding.jsonDecoder().decode(Self.self, from: data)\n        }\n    }\n}\n\n// MARK: Savable\nextension ParseInstallation {\n\n    /**\n     Saves the `ParseInstallation` *synchronously* and throws an error if there is an issue.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n     - returns: Returns saved `ParseInstallation`.\n     - important: If an object saved has the same objectId as current, it will automatically update the current.\n    */\n    @discardableResult\n    public func save(options: API.Options = []) throws -> Self {\n        try save(ignoringCustomObjectIdConfig: false,\n                 options: options)\n    }\n\n    /**\n     Saves the `ParseInstallation` *synchronously* and throws an error if there is an issue.\n\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n     - returns: Returns saved `ParseInstallation`.\n     - important: If an object saved has the same objectId as current, it will automatically update the current.\n     - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true`\n     and plan to generate all of your `objectId`'s on the client-side then you should leave\n     `ignoringCustomObjectIdConfig = false`. Setting\n     `ParseConfiguration.isRequiringCustomObjectIds = true` and\n     `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s\n     and the server will generate an `objectId` only when the client does not provide one. This can\n     increase the probability of colliding `objectId`'s as the client and server `objectId`'s may be generated using\n     different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the\n     client-side checks are disabled. Developers are responsible for handling such cases.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult\n    public func save(ignoringCustomObjectIdConfig: Bool,\n                     options: API.Options = []) throws -> Self {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        var childObjects: [String: PointerType]?\n        var childFiles: [UUID: ParseFile]?\n        var error: ParseError?\n        let group = DispatchGroup()\n        group.enter()\n        self.ensureDeepSave(options: options) { (savedChildObjects, savedChildFiles, parseError) in\n            childObjects = savedChildObjects\n            childFiles = savedChildFiles\n            error = parseError\n            group.leave()\n        }\n        group.wait()\n\n        if let error = error {\n            throw error\n        }\n\n        let result: Self = try saveCommand(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig)\n            .execute(options: options,\n                     childObjects: childObjects,\n                     childFiles: childFiles)\n        try Self.updateKeychainIfNeeded([result])\n        return result\n    }\n\n    /**\n     Saves the `ParseInstallation` *asynchronously* and executes the given callback block.\n\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - important: If an object saved has the same objectId as current, it will automatically update the current.\n     - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true`\n     and plan to generate all of your `objectId`'s on the client-side then you should leave\n     `ignoringCustomObjectIdConfig = false`. Setting\n     `ParseConfiguration.isRequiringCustomObjectIds = true` and\n     `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s\n     and the server will generate an `objectId` only when the client does not provide one. This can\n     increase the probability of colliding `objectId`'s as the client and server `objectId`'s may be generated using\n     different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the\n     client-side checks are disabled. Developers are responsible for handling such cases.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func save(\n        ignoringCustomObjectIdConfig: Bool = false,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<Self, ParseError>) -> Void\n    ) {\n        let method = Method.save\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let object = try await command(method: method,\n                                               ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                                               options: options,\n                                               callbackQueue: callbackQueue)\n                completion(.success(object))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        command(method: method,\n                ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                options: options,\n                callbackQueue: callbackQueue,\n                completion: completion)\n        #endif\n    }\n\n    /**\n     Creates the `ParseInstallation` *asynchronously* and executes the given callback block.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func create(\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<Self, ParseError>) -> Void\n    ) {\n        let method = Method.create\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let object = try await command(method: method,\n                                               options: options,\n                                               callbackQueue: callbackQueue)\n                completion(.success(object))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        command(method: method,\n                options: options,\n                callbackQueue: callbackQueue,\n                completion: completion)\n        #endif\n    }\n\n    /**\n     Replaces the `ParseInstallation` *asynchronously* and executes the given callback block.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - important: If an object replaced has the same objectId as current, it will automatically replace the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func replace(\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<Self, ParseError>) -> Void\n    ) {\n        let method = Method.replace\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let object = try await command(method: method,\n                                               options: options,\n                                               callbackQueue: callbackQueue)\n                completion(.success(object))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        command(method: method,\n                options: options,\n                callbackQueue: callbackQueue,\n                completion: completion)\n        #endif\n    }\n\n    /**\n     Updates the `ParseInstallation` *asynchronously* and executes the given callback block.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - important: If an object updated has the same objectId as current, it will automatically update the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func update(\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<Self, ParseError>) -> Void\n    ) {\n        let method = Method.update\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let object = try await command(method: method,\n                                               options: options,\n                                               callbackQueue: callbackQueue)\n                completion(.success(object))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        command(method: method,\n                options: options,\n                callbackQueue: callbackQueue,\n                completion: completion)\n        #endif\n    }\n\n    func command(\n        method: Method,\n        ignoringCustomObjectIdConfig: Bool = false,\n        options: API.Options,\n        callbackQueue: DispatchQueue,\n        completion: @escaping (Result<Self, ParseError>) -> Void\n    ) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        self.ensureDeepSave(options: options) { (savedChildObjects, savedChildFiles, error) in\n            guard let parseError = error else {\n                do {\n                    let command: API.Command<Self, Self>!\n                    switch method {\n                    case .save:\n                        command = try self.saveCommand(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig)\n                    case .create:\n                        command = self.createCommand()\n                    case .replace:\n                        command = try self.replaceCommand()\n                    case .update:\n                        command = try self.updateCommand()\n                    }\n                    command\n                        .executeAsync(options: options,\n                                      callbackQueue: callbackQueue,\n                                      childObjects: savedChildObjects,\n                                      childFiles: savedChildFiles) { result in\n                            if case .success(let foundResult) = result {\n                                try? Self.updateKeychainIfNeeded([foundResult])\n                            }\n                            completion(result)\n                        }\n                } catch {\n                    let defaultError = ParseError(code: .unknownError,\n                                                  message: error.localizedDescription)\n                    let parseError = error as? ParseError ?? defaultError\n                    callbackQueue.async {\n                        completion(.failure(parseError))\n                    }\n                }\n                return\n            }\n            callbackQueue.async {\n                completion(.failure(parseError))\n            }\n        }\n    }\n\n    func saveCommand(ignoringCustomObjectIdConfig: Bool = false) throws -> API.Command<Self, Self> {\n        if Parse.configuration.isRequiringCustomObjectIds && objectId == nil && !ignoringCustomObjectIdConfig {\n            throw ParseError(code: .missingObjectId, message: \"objectId must not be nil\")\n        }\n        if isSaved {\n            return try replaceCommand() // MARK: Should be switched to \"updateCommand\" when server supports PATCH.\n        }\n        return createCommand()\n    }\n\n    // MARK: Saving ParseObjects - private\n    func createCommand() -> API.Command<Self, Self> {\n        var object = self\n        if object.ACL == nil,\n            let acl = try? ParseACL.defaultACL() {\n            object.ACL = acl\n        }\n        let mapper = { (data) -> Self in\n            try ParseCoding.jsonDecoder().decode(CreateResponse.self, from: data).apply(to: object)\n        }\n        return API.Command<Self, Self>(method: .POST,\n                                       path: endpoint(.POST),\n                                       body: object,\n                                       mapper: mapper)\n    }\n\n    func replaceCommand() throws -> API.Command<Self, Self> {\n        guard self.objectId != nil else {\n            throw ParseError(code: .missingObjectId,\n                             message: \"objectId must not be nil\")\n        }\n        let mapper = { (data: Data) -> Self in\n            var updatedObject = self\n            updatedObject.originalData = nil\n            updatedObject = try ParseCoding.jsonDecoder().decode(ReplaceResponse.self,\n                                                                 from: data).apply(to: updatedObject)\n            // MARK: The lines below should be removed when server supports PATCH.\n            guard let originalData = self.originalData,\n                  let original = try? ParseCoding.jsonDecoder().decode(Self.self,\n                                                                       from: originalData),\n                  original.hasSameObjectId(as: updatedObject) else {\n                      return updatedObject\n                  }\n            return try updatedObject.merge(with: original)\n        }\n        return API.Command<Self, Self>(method: .PUT,\n                                 path: endpoint,\n                                 body: self,\n                                 mapper: mapper)\n    }\n\n    func updateCommand() throws -> API.Command<Self, Self> {\n        guard self.objectId != nil else {\n            throw ParseError(code: .missingObjectId,\n                             message: \"objectId must not be nil\")\n        }\n        let mapper = { (data: Data) -> Self in\n            var updatedObject = self\n            updatedObject.originalData = nil\n            updatedObject = try ParseCoding.jsonDecoder().decode(UpdateResponse.self,\n                                                                 from: data).apply(to: updatedObject)\n            guard let originalData = self.originalData,\n                  let original = try? ParseCoding.jsonDecoder().decode(Self.self,\n                                                                       from: originalData),\n                  original.hasSameObjectId(as: updatedObject) else {\n                      return updatedObject\n                  }\n            return try updatedObject.merge(with: original)\n        }\n        return API.Command<Self, Self>(method: .PATCH,\n                                 path: endpoint,\n                                 body: self,\n                                 mapper: mapper)\n    }\n}\n\n// MARK: Deletable\nextension ParseInstallation {\n    /**\n     Deletes the `ParseInstallation` *synchronously* with the current data from the server.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of `ParseError` type.\n     - important: If an object deleted has the same objectId as current, it will automatically update the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func delete(options: API.Options = []) throws {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        _ = try deleteCommand().execute(options: options)\n        try Self.updateKeychainIfNeeded([self], deleting: true)\n    }\n\n    /**\n     Deletes the `ParseInstallation` *asynchronously* and executes the given callback block.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Void, ParseError>)`.\n     - important: If an object deleted has the same objectId as current, it will automatically update the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func delete(\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<Void, ParseError>) -> Void\n    ) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n         do {\n            try deleteCommand()\n                 .executeAsync(options: options,\n                               callbackQueue: callbackQueue) { result in\n                     switch result {\n\n                     case .success:\n                         do {\n                             try Self.updateKeychainIfNeeded([self], deleting: true)\n                             completion(.success(()))\n                         } catch {\n                             let defaultError = ParseError(code: .unknownError,\n                                                           message: error.localizedDescription)\n                             let parseError = error as? ParseError ?? defaultError\n                             callbackQueue.async {\n                                 completion(.failure(parseError))\n                             }\n                         }\n                     case .failure(let error):\n                         completion(.failure(error))\n                     }\n                }\n         } catch let error as ParseError {\n            callbackQueue.async {\n                completion(.failure(error))\n            }\n         } catch {\n            callbackQueue.async {\n                completion(.failure(ParseError(code: .unknownError, message: error.localizedDescription)))\n            }\n         }\n    }\n\n    func deleteCommand() throws -> API.NonParseBodyCommand<NoBody, NoBody> {\n        guard isSaved else {\n            throw ParseError(code: .unknownError, message: \"Cannot Delete an object without id\")\n        }\n\n        return API.NonParseBodyCommand<NoBody, NoBody>(\n            method: .DELETE,\n            path: endpoint\n        ) { (data) -> NoBody in\n            let error = try? ParseCoding.jsonDecoder().decode(ParseError.self, from: data)\n            if let error = error {\n                throw error\n            } else {\n                return NoBody()\n            }\n        }\n    }\n}\n\n// MARK: Batch Support\npublic extension Sequence where Element: ParseInstallation {\n\n    /**\n     Saves a collection of installations *synchronously* all at once and throws an error if necessary.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n\n     - returns: Returns a Result enum with the object if a save was successful or a `ParseError` if it failed.\n     - throws: An error of type `ParseError`.\n     - important: If an object saved has the same objectId as current, it will automatically update the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true`\n     and plan to generate all of your `objectId`'s on the client-side then you should leave\n     `ignoringCustomObjectIdConfig = false`. Setting\n     `ParseConfiguration.isRequiringCustomObjectIds = true` and\n     `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s\n     and the server will generate an `objectId` only when the client does not provide one. This can\n     increase the probability of colliding `objectId`'s as the client and server `objectId`'s may be generated using\n     different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the\n     client-side checks are disabled. Developers are responsible for handling such cases.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult\n    func saveAll(batchLimit limit: Int? = nil, // swiftlint:disable:this function_body_length\n                 transaction: Bool = configuration.isUsingTransactions,\n                 ignoringCustomObjectIdConfig: Bool = false,\n                 options: API.Options = []) throws -> [(Result<Self.Element, ParseError>)] {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        var childObjects = [String: PointerType]()\n        var childFiles = [UUID: ParseFile]()\n        var commands = [API.Command<Self.Element, Self.Element>]()\n        var error: ParseError?\n\n        try forEach {\n            let installation = $0\n            let group = DispatchGroup()\n            group.enter()\n            installation.ensureDeepSave(options: options,\n                                        // swiftlint:disable:next line_length\n                                        isShouldReturnIfChildObjectsFound: transaction) { (savedChildObjects, savedChildFiles, parseError) -> Void in\n                // If an error occurs, everything should be skipped\n                if parseError != nil {\n                    error = parseError\n                }\n                savedChildObjects.forEach {(key, value) in\n                    if error != nil {\n                        return\n                    }\n                    if childObjects[key] == nil {\n                        childObjects[key] = value\n                    } else {\n                        error = ParseError(code: .unknownError, message: \"circular dependency\")\n                        return\n                    }\n                }\n                savedChildFiles.forEach {(key, value) in\n                    if error != nil {\n                        return\n                    }\n                    if childFiles[key] == nil {\n                        childFiles[key] = value\n                    } else {\n                        error = ParseError(code: .unknownError, message: \"circular dependency\")\n                        return\n                    }\n                }\n                group.leave()\n            }\n            group.wait()\n            if let error = error {\n                throw error\n            }\n            commands.append(try installation.saveCommand(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig))\n        }\n\n        var returnBatch = [(Result<Self.Element, ParseError>)]()\n        let batchLimit = limit != nil ? limit! : ParseConstants.batchLimit\n        try canSendTransactions(transaction, objectCount: commands.count, batchLimit: batchLimit)\n        let batches = BatchUtils.splitArray(commands, valuesPerSegment: batchLimit)\n        try batches.forEach {\n            let currentBatch = try API.Command<Self.Element, Self.Element>\n                .batch(commands: $0, transaction: transaction)\n                .execute(options: options,\n                         batching: true,\n                         childObjects: childObjects,\n                         childFiles: childFiles)\n            returnBatch.append(contentsOf: currentBatch)\n        }\n        try Self.Element.updateKeychainIfNeeded(returnBatch.compactMap {try? $0.get()})\n        return returnBatch\n    }\n\n    /**\n     Saves a collection of installations all at once *asynchronously* and executes the completion block when done.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<[(Result<Element, ParseError>)], ParseError>)`.\n     - important: If an object saved has the same objectId as current, it will automatically update the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true`\n     and plan to generate all of your `objectId`'s on the client-side then you should leave\n     `ignoringCustomObjectIdConfig = false`. Setting\n     `ParseConfiguration.isRequiringCustomObjectIds = true` and\n     `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s\n     and the server will generate an `objectId` only when the client does not provide one. This can\n     increase the probability of colliding `objectId`'s as the client and server `objectId`'s may be generated using\n     different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the\n     client-side checks are disabled. Developers are responsible for handling such cases.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func saveAll( // swiftlint:disable:this function_body_length cyclomatic_complexity\n        batchLimit limit: Int? = nil,\n        transaction: Bool = configuration.isUsingTransactions,\n        ignoringCustomObjectIdConfig: Bool = false,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<[(Result<Element, ParseError>)], ParseError>) -> Void\n    ) {\n        let method = Method.save\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let objects = try await batchCommand(method: method,\n                                                     batchLimit: limit,\n                                                     transaction: transaction,\n                                                     ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                                                     options: options,\n                                                     callbackQueue: callbackQueue)\n                completion(.success(objects))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        batchCommand(method: method,\n                     batchLimit: limit,\n                     transaction: transaction,\n                     ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                     options: options,\n                     callbackQueue: callbackQueue,\n                     completion: completion)\n        #endif\n    }\n\n    /**\n     Creates a collection of installations all at once *asynchronously* and executes the completion block when done.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<[(Result<Element, ParseError>)], ParseError>)`.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func createAll( // swiftlint:disable:this function_body_length cyclomatic_complexity\n        batchLimit limit: Int? = nil,\n        transaction: Bool = configuration.isUsingTransactions,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<[(Result<Element, ParseError>)], ParseError>) -> Void\n    ) {\n        let method = Method.create\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let objects = try await batchCommand(method: method,\n                                                     batchLimit: limit,\n                                                     transaction: transaction,\n                                                     options: options,\n                                                     callbackQueue: callbackQueue)\n                completion(.success(objects))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        batchCommand(method: method,\n                     batchLimit: limit,\n                     transaction: transaction,\n                     options: options,\n                     callbackQueue: callbackQueue,\n                     completion: completion)\n        #endif\n    }\n\n    /**\n     Replaces a collection of installations all at once *asynchronously* and executes the completion block when done.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<[(Result<Element, ParseError>)], ParseError>)`.\n     - important: If an object replaced has the same objectId as current, it will automatically replace the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func replaceAll( // swiftlint:disable:this function_body_length cyclomatic_complexity\n        batchLimit limit: Int? = nil,\n        transaction: Bool = configuration.isUsingTransactions,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<[(Result<Element, ParseError>)], ParseError>) -> Void\n    ) {\n        let method = Method.replace\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let objects = try await batchCommand(method: method,\n                                                     batchLimit: limit,\n                                                     transaction: transaction,\n                                                     options: options,\n                                                     callbackQueue: callbackQueue)\n                completion(.success(objects))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        batchCommand(method: method,\n                     batchLimit: limit,\n                     transaction: transaction,\n                     options: options,\n                     callbackQueue: callbackQueue,\n                     completion: completion)\n        #endif\n    }\n\n    /**\n     Updates a collection of installations all at once *asynchronously* and executes the completion block when done.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<[(Result<Element, ParseError>)], ParseError>)`.\n     - important: If an object updated has the same objectId as current, it will automatically update the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    internal func updateAll( // swiftlint:disable:this function_body_length cyclomatic_complexity\n        batchLimit limit: Int? = nil,\n        transaction: Bool = configuration.isUsingTransactions,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<[(Result<Element, ParseError>)], ParseError>) -> Void\n    ) {\n        let method = Method.update\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let objects = try await batchCommand(method: method,\n                                                     batchLimit: limit,\n                                                     transaction: transaction,\n                                                     options: options,\n                                                     callbackQueue: callbackQueue)\n                completion(.success(objects))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        batchCommand(method: method,\n                     batchLimit: limit,\n                     transaction: transaction,\n                     options: options,\n                     callbackQueue: callbackQueue,\n                     completion: completion)\n        #endif\n    }\n\n    internal func batchCommand( // swiftlint:disable:this function_parameter_count\n        method: Method,\n        batchLimit limit: Int?,\n        transaction: Bool,\n        ignoringCustomObjectIdConfig: Bool = false,\n        options: API.Options,\n        callbackQueue: DispatchQueue,\n        completion: @escaping (Result<[(Result<Element, ParseError>)], ParseError>) -> Void\n    ) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        let uuid = UUID()\n        let queue = DispatchQueue(label: \"com.parse.batch.\\(uuid)\",\n                                  qos: .default,\n                                  attributes: .concurrent,\n                                  autoreleaseFrequency: .inherit,\n                                  target: nil)\n        queue.sync {\n            var childObjects = [String: PointerType]()\n            var childFiles = [UUID: ParseFile]()\n            var error: ParseError?\n            var commands = [API.Command<Self.Element, Self.Element>]()\n            let installations = map { $0 }\n\n            for installation in installations {\n                let group = DispatchGroup()\n                group.enter()\n                installation\n                    .ensureDeepSave(options: options,\n                                    // swiftlint:disable:next line_length\n                                    isShouldReturnIfChildObjectsFound: transaction) { (savedChildObjects, savedChildFiles, parseError) -> Void in\n                    // If an error occurs, everything should be skipped\n                    if let parseError = parseError {\n                        error = parseError\n                    }\n                    savedChildObjects.forEach {(key, value) in\n                        guard error == nil else {\n                            return\n                        }\n                        guard childObjects[key] == nil else {\n                            error = ParseError(code: .unknownError, message: \"circular dependency\")\n                            return\n                        }\n                        childObjects[key] = value\n                    }\n                    savedChildFiles.forEach {(key, value) in\n                        guard error == nil else {\n                            return\n                        }\n                        guard childFiles[key] == nil else {\n                            error = ParseError(code: .unknownError, message: \"circular dependency\")\n                            return\n                        }\n                        childFiles[key] = value\n                    }\n                    group.leave()\n                }\n                group.wait()\n                if let error = error {\n                    callbackQueue.async {\n                        completion(.failure(error))\n                    }\n                    return\n                }\n\n                do {\n                    switch method {\n                    case .save:\n                        commands.append(\n                            try installation.saveCommand(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig)\n                        )\n                    case .create:\n                        commands.append(installation.createCommand())\n                    case .replace:\n                        commands.append(try installation.replaceCommand())\n                    case .update:\n                        commands.append(try installation.updateCommand())\n                    }\n                } catch {\n                    let defaultError = ParseError(code: .unknownError,\n                                                  message: error.localizedDescription)\n                    let parseError = error as? ParseError ?? defaultError\n                    callbackQueue.async {\n                        completion(.failure(parseError))\n                    }\n                    return\n                }\n            }\n\n            do {\n                var returnBatch = [(Result<Self.Element, ParseError>)]()\n\n                let batchLimit = limit != nil ? limit! : ParseConstants.batchLimit\n                try canSendTransactions(transaction, objectCount: commands.count, batchLimit: batchLimit)\n                let batches = BatchUtils.splitArray(commands, valuesPerSegment: batchLimit)\n                var completed = 0\n                for batch in batches {\n                    API.Command<Self.Element, Self.Element>\n                            .batch(commands: batch, transaction: transaction)\n                            .executeAsync(options: options,\n                                          batching: true,\n                                          callbackQueue: callbackQueue,\n                                          childObjects: childObjects,\n                                          childFiles: childFiles) { results in\n                        switch results {\n\n                        case .success(let saved):\n                            returnBatch.append(contentsOf: saved)\n                            if completed == (batches.count - 1) {\n                                try? Self.Element.updateKeychainIfNeeded(returnBatch.compactMap {try? $0.get()})\n                                completion(.success(returnBatch))\n                            }\n                            completed += 1\n                        case .failure(let error):\n                            callbackQueue.async {\n                                completion(.failure(error))\n                            }\n                            return\n                        }\n                    }\n                }\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n    }\n\n    /**\n     Fetches a collection of installations *synchronously* all at once and throws an error if necessary.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys one level deep. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n\n     - returns: Returns a Result enum with the object if a fetch was successful or a `ParseError` if it failed.\n     - throws: An error of type `ParseError`.\n     - important: If an object fetched has the same objectId as current, it will automatically update the current.\n     - warning: The order in which installations are returned are not guarenteed. You should not expect results in\n     any particular order.\n    */\n    func fetchAll(includeKeys: [String]? = nil,\n                  options: API.Options = []) throws -> [(Result<Self.Element, ParseError>)] {\n\n        if (allSatisfy { $0.className == Self.Element.className}) {\n            let uniqueObjectIds = Set(compactMap { $0.objectId })\n            var query = Self.Element.query(containedIn(key: \"objectId\", array: [uniqueObjectIds]))\n                .limit(uniqueObjectIds.count)\n\n            if let include = includeKeys {\n                query = query.include(include)\n            }\n\n            let fetchedObjects = try query.find(options: options)\n            var fetchedObjectsToReturn = [(Result<Self.Element, ParseError>)]()\n\n            uniqueObjectIds.forEach {\n                let uniqueObjectId = $0\n                if let fetchedObject = fetchedObjects.first(where: {$0.objectId == uniqueObjectId}) {\n                    fetchedObjectsToReturn.append(.success(fetchedObject))\n                } else {\n                    fetchedObjectsToReturn.append(.failure(ParseError(code: .objectNotFound,\n                                                                      // swiftlint:disable:next line_length\n                                                                      message: \"objectId \\\"\\(uniqueObjectId)\\\" was not found in className \\\"\\(Self.Element.className)\\\"\")))\n                }\n            }\n            try Self.Element.updateKeychainIfNeeded(fetchedObjects)\n            return fetchedObjectsToReturn\n        } else {\n            throw ParseError(code: .unknownError, message: \"all items to fetch must be of the same class\")\n        }\n    }\n\n    /**\n     Fetches a collection of installations all at once *asynchronously* and executes the completion block when done.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys one level deep. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<[(Result<Element, ParseError>)], ParseError>)`.\n     - important: If an object fetched has the same objectId as current, it will automatically update the current.\n     - warning: The order in which installations are returned are not guarenteed. You should not expect results in\n     any particular order.\n    */\n    func fetchAll(\n        includeKeys: [String]? = nil,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<[(Result<Element, ParseError>)], ParseError>) -> Void\n    ) {\n        if (allSatisfy { $0.className == Self.Element.className}) {\n            let uniqueObjectIds = Set(compactMap { $0.objectId })\n            var query = Self.Element.query(containedIn(key: \"objectId\", array: [uniqueObjectIds]))\n            if let include = includeKeys {\n                query = query.include(include)\n            }\n            query.find(options: options, callbackQueue: callbackQueue) { result in\n                switch result {\n\n                case .success(let fetchedObjects):\n                    var fetchedObjectsToReturn = [(Result<Self.Element, ParseError>)]()\n\n                    uniqueObjectIds.forEach {\n                        let uniqueObjectId = $0\n                        if let fetchedObject = fetchedObjects.first(where: {$0.objectId == uniqueObjectId}) {\n                            fetchedObjectsToReturn.append(.success(fetchedObject))\n                        } else {\n                            fetchedObjectsToReturn.append(.failure(ParseError(code: .objectNotFound,\n                                                                              // swiftlint:disable:next line_length\n                                                                              message: \"objectId \\\"\\(uniqueObjectId)\\\" was not found in className \\\"\\(Self.Element.className)\\\"\")))\n                        }\n                    }\n                    try? Self.Element.updateKeychainIfNeeded(fetchedObjects)\n                    completion(.success(fetchedObjectsToReturn))\n                case .failure(let error):\n                    callbackQueue.async {\n                        completion(.failure(error))\n                    }\n                }\n            }\n        } else {\n            callbackQueue.async {\n                completion(.failure(ParseError(code: .unknownError,\n                                               message: \"all items to fetch must be of the same class\")))\n            }\n        }\n    }\n\n    /**\n     Deletes a collection of installations *synchronously* all at once and throws an error if necessary.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n\n     - returns: Returns `nil` if the delete successful or a `ParseError` if it failed.\n        1. A `ParseError.Code.aggregateError`. This object's \"errors\" property is an\n        array of other Parse.Error objects. Each error object in this array\n        has an \"object\" property that references the object that could not be\n        deleted (for instance, because that object could not be found).\n        2. A non-aggregate Parse.Error. This indicates a serious error that\n        caused the delete operation to be aborted partway through (for\n        instance, a connection failure in the middle of the delete).\n     - throws: An error of type `ParseError`.\n     - important: If an object deleted has the same objectId as current, it will automatically update the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func deleteAll(batchLimit limit: Int? = nil,\n                   transaction: Bool = configuration.isUsingTransactions,\n                   options: API.Options = []) throws -> [(Result<Void, ParseError>)] {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        var returnBatch = [(Result<Void, ParseError>)]()\n        let commands = try map { try $0.deleteCommand() }\n        let batchLimit = limit != nil ? limit! : ParseConstants.batchLimit\n        try canSendTransactions(transaction, objectCount: commands.count, batchLimit: batchLimit)\n        let batches = BatchUtils.splitArray(commands, valuesPerSegment: batchLimit)\n        try batches.forEach {\n            let currentBatch = try API.Command<Self.Element, (Result<Void, ParseError>)>\n                .batch(commands: $0, transaction: transaction)\n                .execute(options: options)\n            returnBatch.append(contentsOf: currentBatch)\n        }\n\n        try Self.Element.updateKeychainIfNeeded(compactMap {$0},\n                                                deleting: true)\n        return returnBatch\n    }\n\n    /**\n     Deletes a collection of installations all at once *asynchronously* and executes the completion block when done.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<[ParseError?], ParseError>)`.\n     Each element in the array is either `nil` if the delete successful or a `ParseError` if it failed.\n     1. A `ParseError.Code.aggregateError`. This object's \"errors\" property is an\n     array of other Parse.Error objects. Each error object in this array\n     has an \"object\" property that references the object that could not be\n     deleted (for instance, because that object could not be found).\n     2. A non-aggregate Parse.Error. This indicates a serious error that\n     caused the delete operation to be aborted partway through (for\n     instance, a connection failure in the middle of the delete).\n     - important: If an object deleted has the same objectId as current, it will automatically update the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func deleteAll(\n        batchLimit limit: Int? = nil,\n        transaction: Bool = configuration.isUsingTransactions,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<[(Result<Void, ParseError>)], ParseError>) -> Void\n    ) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        do {\n            var returnBatch = [(Result<Void, ParseError>)]()\n            let commands = try map({ try $0.deleteCommand() })\n            let batchLimit = limit != nil ? limit! : ParseConstants.batchLimit\n            try canSendTransactions(transaction, objectCount: commands.count, batchLimit: batchLimit)\n            let batches = BatchUtils.splitArray(commands, valuesPerSegment: batchLimit)\n            var completed = 0\n            for batch in batches {\n                API.Command<Self.Element, ParseError?>\n                        .batch(commands: batch, transaction: transaction)\n                        .executeAsync(options: options,\n                                      callbackQueue: callbackQueue) { results in\n                    switch results {\n\n                    case .success(let saved):\n                        returnBatch.append(contentsOf: saved)\n                        if completed == (batches.count - 1) {\n                            try? Self.Element.updateKeychainIfNeeded(self.compactMap {$0},\n                                                                     deleting: true)\n                            completion(.success(returnBatch))\n                        }\n                        completed += 1\n                    case .failure(let error):\n                        completion(.failure(error))\n                        return\n                    }\n                }\n            }\n        } catch {\n            let defaultError = ParseError(code: .unknownError,\n                                          message: error.localizedDescription)\n            let parseError = error as? ParseError ?? defaultError\n            callbackQueue.async {\n                completion(.failure(parseError))\n            }\n        }\n    }\n}\n\n#if !os(Linux) && !os(Android) && !os(Windows)\n// MARK: Migrate from Objective-C SDK\npublic extension ParseInstallation {\n\n    /**\n     Migrates the `ParseInstallation` *asynchronously* from the Objective-C SDK Keychain.\n\n     - parameter copyEntireInstallation: When **true**, copies the\n     entire `ParseInstallation` from the Objective-C SDK Keychain to the Swift SDK. When\n     **false**, only the `channels` and `deviceToken` are copied from the Objective-C\n     SDK Keychain; resulting in a new `ParseInstallation` for original `sessionToken`.\n     Defaults to **true**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - warning: When initializing the Swift SDK, `migratingFromObjcSDK` should be set to **false**\n     when calling this method.\n     - warning: The latest **PFInstallation** from the Objective-C SDK should be saved to your\n     Parse Server before calling this method. This method assumes **PFInstallation.installationId**\n     is saved to the Keychain. If the **installationId** is not saved to the Keychain, this method will\n     not work.\n    */\n    @available(*, deprecated, message: \"This does not work, use become() instead\")\n    static func migrateFromObjCKeychain(copyEntireInstallation: Bool = true,\n                                        options: API.Options = [],\n                                        callbackQueue: DispatchQueue = .main,\n                                        completion: @escaping (Result<Self, ParseError>) -> Void) {\n        guard let objcParseKeychain = KeychainStore.objectiveC,\n              let oldInstallationId: String = objcParseKeychain.objectObjectiveC(forKey: \"installationId\") else {\n            let error = ParseError(code: .unknownError,\n                                   message: \"Could not find Installation in the Objective-C SDK Keychain\")\n            callbackQueue.async {\n                completion(.failure(error))\n            }\n            return\n        }\n        become(oldInstallationId,\n               copyEntireInstallation: copyEntireInstallation,\n               completion: completion)\n    }\n\n    /**\n     Deletes the Objective-C Keychain along with the Objective-C `ParseInstallation`\n     from the Parse Server *asynchronously* and executes the given callback block.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Void, ParseError>)`.\n     - warning: It is recommended to only use this method after a succesfful migration. Calling this\n     method will destroy the entire Objective-C Keychain and `ParseInstallation` on the Parse\n     Server.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    static func deleteObjCKeychain(options: API.Options = [],\n                                   callbackQueue: DispatchQueue = .main,\n                                   completion: @escaping (Result<Void, ParseError>) -> Void) {\n        guard let objcParseKeychain = KeychainStore.objectiveC,\n              let oldInstallationId: String = objcParseKeychain.objectObjectiveC(forKey: \"installationId\") else {\n            let error = ParseError(code: .unknownError,\n                                   message: \"Could not find Installation in the Objective-C SDK Keychain\")\n            callbackQueue.async {\n                completion(.failure(error))\n            }\n            return\n        }\n        guard var currentInstallation = Self.current else {\n            let error = ParseError(code: .unknownError,\n                                   message: \"Current installation does not exist\")\n            callbackQueue.async {\n                completion(.failure(error))\n            }\n            return\n        }\n        currentInstallation.installationId = oldInstallationId\n        do {\n            try deleteObjectiveCKeychain()\n            // Only delete the `ParseInstallation` on Parse Server if it is not current.\n            guard Self.current?.installationId == oldInstallationId else {\n                currentInstallation.delete(options: options,\n                                           callbackQueue: callbackQueue,\n                                           completion: completion)\n                return\n            }\n            callbackQueue.async {\n                completion(.success(()))\n            }\n        } catch {\n            let parseError = ParseError(code: .unknownError,\n                                        message: error.localizedDescription)\n            callbackQueue.async {\n                completion(.failure(parseError))\n            }\n            return\n        }\n    }\n}\n#endif // swiftlint:disable:this file_length\n"
  },
  {
    "path": "Sources/ParseSwift/Objects/ParseObject+async.swift",
    "content": "//\n//  ParseObject+async.swift\n//  ParseObject+async\n//\n//  Created by Corey Baker on 8/6/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n\npublic extension ParseObject {\n\n    // MARK: Async/Await\n    /**\n     Fetches the `ParseObject` *aynchronously* with the current data from the server.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys one level deep. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the fetched `ParseObject`.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult func fetch(includeKeys: [String]? = nil,\n                                  options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.fetch(includeKeys: includeKeys,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n\n    /**\n     Saves the `ParseObject` *asynchronously*.\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the saved `ParseObject`.\n     - throws: An error of type `ParseError`.\n    */\n    @discardableResult func save(ignoringCustomObjectIdConfig: Bool = false,\n                                 options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.save(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n\n    /**\n     Creates the `ParseObject` *asynchronously*.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the saved `ParseObject`.\n     - throws: An error of type `ParseError`.\n    */\n    @discardableResult func create(options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.create(options: options,\n                        completion: continuation.resume)\n        }\n    }\n\n    /**\n     Replaces the `ParseObject` *asynchronously*.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the saved `ParseObject`.\n     - throws: An error of type `ParseError`.\n    */\n    @discardableResult func replace(options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.replace(options: options,\n                         completion: continuation.resume)\n        }\n    }\n\n    /**\n     Updates the `ParseObject` *asynchronously*.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the saved `ParseObject`.\n     - throws: An error of type `ParseError`.\n    */\n    @discardableResult internal func update(options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.update(options: options,\n                        completion: continuation.resume)\n        }\n    }\n\n    /**\n     Deletes the `ParseObject` *asynchronously*.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n    */\n    func delete(options: API.Options = []) async throws {\n        let result = try await withCheckedThrowingContinuation { continuation in\n            self.delete(options: options,\n                        completion: continuation.resume)\n        }\n        if case let .failure(error) = result {\n            throw error\n        }\n    }\n}\n\npublic extension Sequence where Element: ParseObject {\n    /**\n     Fetches a collection of objects *aynchronously* with the current data from the server and sets\n     an error if one occurs.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys one level deep. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns an array of Result enums with the object if a fetch was successful or a\n     `ParseError` if it failed.\n     - throws: An error of type `ParseError`.\n    */\n    @discardableResult func fetchAll(includeKeys: [String]? = nil,\n                                     options: API.Options = []) async throws -> [(Result<Self.Element, ParseError>)] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.fetchAll(includeKeys: includeKeys,\n                          options: options,\n                          completion: continuation.resume)\n        }\n    }\n\n    /**\n     Saves a collection of objects *asynchronously*.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns an array of Result enums with the object if a save was successful or a\n     `ParseError` if it failed.\n     - throws: An error of type `ParseError`.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true`\n     and plan to generate all of your `objectId`'s on the client-side then you should leave\n     `ignoringCustomObjectIdConfig = false`. Setting\n     `ParseConfiguration.isRequiringCustomObjectIds = true` and\n     `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s\n     and the server will generate an `objectId` only when the client does not provide one. This can\n     increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using\n     different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the\n     client-side checks are disabled. Developers are responsible for handling such cases.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult func saveAll(batchLimit limit: Int? = nil,\n                                    transaction: Bool = configuration.isUsingTransactions,\n                                    ignoringCustomObjectIdConfig: Bool = false,\n                                    options: API.Options = []) async throws -> [(Result<Self.Element, ParseError>)] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.saveAll(batchLimit: limit,\n                         transaction: transaction,\n                         ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                         options: options,\n                         completion: continuation.resume)\n        }\n    }\n\n    /**\n     Creates a collection of objects *asynchronously*.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns an array of Result enums with the object if a save was successful or a\n     `ParseError` if it failed.\n     - throws: An error of type `ParseError`.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult func createAll(batchLimit limit: Int? = nil,\n                                      transaction: Bool = configuration.isUsingTransactions,\n                                      options: API.Options = []) async throws -> [(Result<Self.Element, ParseError>)] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.createAll(batchLimit: limit,\n                           transaction: transaction,\n                           options: options,\n                           completion: continuation.resume)\n        }\n    }\n\n    /**\n     Replaces a collection of objects *asynchronously*.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns an array of Result enums with the object if a save was successful or a\n     `ParseError` if it failed.\n     - throws: An error of type `ParseError`.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult func replaceAll(batchLimit limit: Int? = nil,\n                                       transaction: Bool = configuration.isUsingTransactions,\n                                       options: API.Options = []) async throws -> [(Result<Self.Element, ParseError>)] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.replaceAll(batchLimit: limit,\n                            transaction: transaction,\n                            options: options,\n                            completion: continuation.resume)\n        }\n    }\n\n    /**\n     Updates a collection of objects *asynchronously*.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns an array of Result enums with the object if a save was successful or a\n     `ParseError` if it failed.\n     - throws: An error of type `ParseError`.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    internal func updateAll(batchLimit limit: Int? = nil,\n                            transaction: Bool = configuration.isUsingTransactions,\n                            options: API.Options = []) async throws -> [(Result<Self.Element, ParseError>)] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.updateAll(batchLimit: limit,\n                           transaction: transaction,\n                           options: options,\n                           completion: continuation.resume)\n        }\n    }\n\n    /**\n     Deletes a collection of objects *asynchronously*.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns `nil` if the delete successful or a `ParseError` if it failed.\n     - throws: An error of type `ParseError`.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n    */\n    @discardableResult func deleteAll(batchLimit limit: Int? = nil,\n                                      transaction: Bool = configuration.isUsingTransactions,\n                                      options: API.Options = []) async throws -> [(Result<Void, ParseError>)] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.deleteAll(batchLimit: limit,\n                           transaction: transaction,\n                           options: options,\n                           completion: continuation.resume)\n        }\n    }\n}\n\n// MARK: Helper Methods (Internal)\ninternal extension ParseObject {\n\n    // swiftlint:disable:next function_body_length\n    func ensureDeepSave(options: API.Options = [],\n                        isShouldReturnIfChildObjectsFound: Bool = false) async throws -> ([String: PointerType],\n                                                                                          [UUID: ParseFile]) {\n\n        var options = options\n        // Remove any caching policy added by the developer as fresh data\n        // from the server is needed.\n        options.remove(.cachePolicy(.reloadIgnoringLocalCacheData))\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        var objectsFinishedSaving = [String: PointerType]()\n        var filesFinishedSaving = [UUID: ParseFile]()\n        do {\n            let object = try ParseCoding.parseEncoder()\n                .encode(self,\n                        objectsSavedBeforeThisOne: nil,\n                        filesSavedBeforeThisOne: nil)\n            var waitingToBeSaved = object.unsavedChildren\n            if isShouldReturnIfChildObjectsFound && waitingToBeSaved.count > 0 {\n                let error = ParseError(code: .unknownError,\n                                       message: \"\"\"\nWhen using transactions, all child ParseObjects have to originally\nbe saved to the Parse Server. Either save all child objects first\nor disable transactions for this call.\n\"\"\")\n                throw error\n            }\n            while waitingToBeSaved.count > 0 {\n                var savableObjects = [ParseEncodable]()\n                var savableFiles = [ParseFile]()\n                var nextBatch = [ParseEncodable]()\n                try waitingToBeSaved.forEach { parseType in\n                    if let parseFile = parseType as? ParseFile {\n                        // ParseFiles can be saved now\n                        savableFiles.append(parseFile)\n                    } else if let parseObject = parseType as? Objectable {\n                        // This is a ParseObject\n                        let waitingObjectInfo = try ParseCoding\n                            .parseEncoder()\n                            .encode(parseObject,\n                                    collectChildren: true,\n                                    objectsSavedBeforeThisOne: objectsFinishedSaving,\n                                    filesSavedBeforeThisOne: filesFinishedSaving)\n                        if waitingObjectInfo.unsavedChildren.count == 0 {\n                            //If this ParseObject has no additional children, it can be saved now\n                            savableObjects.append(parseObject)\n                        } else {\n                            //Else this ParseObject needs to wait until it is children are saved\n                            nextBatch.append(parseObject)\n                        }\n                    }\n                }\n                waitingToBeSaved = nextBatch\n                if waitingToBeSaved.count > 0 && savableObjects.count == 0 && savableFiles.count == 0 {\n                    throw ParseError(code: .unknownError,\n                                     message: \"Found a circular dependency in ParseObject.\")\n                }\n                if savableObjects.count > 0 {\n                    let savedChildObjects = try await self.saveAll(objects: savableObjects,\n                                                                   options: options)\n                    let savedChildPointers = try savedChildObjects.compactMap { try $0.get() }\n                    for (index, object) in savableObjects.enumerated() {\n                        let hash = try BaseObjectable.createHash(object)\n                        objectsFinishedSaving[hash] = savedChildPointers[index]\n                    }\n                }\n                for savableFile in savableFiles {\n                    filesFinishedSaving[savableFile.id] = try await savableFile.save(options: options)\n                }\n            }\n            return (objectsFinishedSaving, filesFinishedSaving)\n        } catch {\n            let defaultError = ParseError(code: .unknownError,\n                                          message: error.localizedDescription)\n            let parseError = error as? ParseError ?? defaultError\n            throw parseError\n        }\n    }\n\n    func command(method: Method,\n                 ignoringCustomObjectIdConfig: Bool = false,\n                 options: API.Options,\n                 callbackQueue: DispatchQueue) async throws -> Self {\n        let (savedChildObjects, savedChildFiles) = try await self.ensureDeepSave(options: options)\n        do {\n            let command: API.Command<Self, Self>!\n            switch method {\n            case .save:\n                command = try self.saveCommand(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig)\n            case .create:\n                command = self.createCommand()\n            case .replace:\n                command = try self.replaceCommand()\n            case .update:\n                command = try self.updateCommand()\n            }\n            return try await command\n                .executeAsync(options: options,\n                              callbackQueue: callbackQueue,\n                              childObjects: savedChildObjects,\n                              childFiles: savedChildFiles)\n        } catch {\n            let defaultError = ParseError(code: .unknownError,\n                                          message: error.localizedDescription)\n            let parseError = error as? ParseError ?? defaultError\n            throw parseError\n        }\n    }\n}\n\n// MARK: Batch Support\ninternal extension Sequence where Element: ParseObject {\n    func batchCommand(method: Method,\n                      batchLimit limit: Int?,\n                      transaction: Bool,\n                      ignoringCustomObjectIdConfig: Bool = false,\n                      options: API.Options,\n                      callbackQueue: DispatchQueue) async throws -> [(Result<Element, ParseError>)] {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        var childObjects = [String: PointerType]()\n        var childFiles = [UUID: ParseFile]()\n        var commands = [API.Command<Self.Element, Self.Element>]()\n        let objects = map { $0 }\n        for object in objects {\n            let (savedChildObjects, savedChildFiles) = try await object\n                .ensureDeepSave(options: options,\n                                isShouldReturnIfChildObjectsFound: transaction)\n            try savedChildObjects.forEach {(key, value) in\n                guard childObjects[key] == nil else {\n                    throw ParseError(code: .unknownError, message: \"circular dependency\")\n                }\n                childObjects[key] = value\n            }\n            try savedChildFiles.forEach {(key, value) in\n                guard childFiles[key] == nil else {\n                    throw ParseError(code: .unknownError, message: \"circular dependency\")\n                }\n                childFiles[key] = value\n            }\n            do {\n                switch method {\n                case .save:\n                    commands.append(\n                        try object.saveCommand(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig)\n                    )\n                case .create:\n                    commands.append(object.createCommand())\n                case .replace:\n                    commands.append(try object.replaceCommand())\n                case .update:\n                    commands.append(try object.updateCommand())\n                }\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                throw parseError\n            }\n        }\n\n        do {\n            var returnBatch = [(Result<Self.Element, ParseError>)]()\n            let batchLimit = limit != nil ? limit! : ParseConstants.batchLimit\n            try canSendTransactions(transaction, objectCount: commands.count, batchLimit: batchLimit)\n            let batches = BatchUtils.splitArray(commands, valuesPerSegment: batchLimit)\n            for batch in batches {\n                let saved = try await API.Command<Self.Element, Self.Element>\n                        .batch(commands: batch, transaction: transaction)\n                        .executeAsync(options: options,\n                                      batching: true,\n                                      callbackQueue: callbackQueue,\n                                      childObjects: childObjects,\n                                      childFiles: childFiles)\n                returnBatch.append(contentsOf: saved)\n            }\n            return returnBatch\n        } catch {\n            let defaultError = ParseError(code: .unknownError,\n                                          message: error.localizedDescription)\n            let parseError = error as? ParseError ?? defaultError\n            throw parseError\n        }\n    }\n}\n\n// MARK: Savable Encodable Version\ninternal extension ParseEncodable {\n    func saveAll(objects: [ParseEncodable],\n                 transaction: Bool = configuration.isUsingTransactions,\n                 options: API.Options = [],\n                 callbackQueue: DispatchQueue = .main) async throws -> [(Result<PointerType, ParseError>)] {\n        try await API.NonParseBodyCommand<AnyCodable, PointerType>\n            .batch(objects: objects,\n                   transaction: transaction)\n            .executeAsync(options: options,\n                          callbackQueue: callbackQueue)\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Objects/ParseObject+combine.swift",
    "content": "//\n//  ParseObject+combine.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/29/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\npublic extension ParseObject {\n\n    // MARK: Combine\n    /**\n     Fetches the `ParseObject` *aynchronously* with the current data from the server.\n     Publishes when complete.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys one level deep. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func fetchPublisher(includeKeys: [String]? = nil,\n                        options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.fetch(includeKeys: includeKeys,\n                       options: options,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Saves the `ParseObject` *asynchronously* and publishes when complete.\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true`\n     and plan to generate all of your `objectId`'s on the client-side then you should leave\n     `ignoringCustomObjectIdConfig = false`. Setting\n     `ParseConfiguration.isRequiringCustomObjectIds = true` and\n     `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s\n     and the server will generate an `objectId` only when the client does not provide one. This can\n     increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using\n     different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the\n     client-side checks are disabled. Developers are responsible for handling such cases.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func savePublisher(ignoringCustomObjectIdConfig: Bool = false,\n                       options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.save(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                      options: options,\n                      completion: promise)\n        }\n    }\n\n    /**\n     Creates the `ParseObject` *asynchronously* and publishes when complete.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n    */\n    func createPublisher(options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.create(options: options,\n                        completion: promise)\n        }\n    }\n\n    /**\n     Replaces the `ParseObject` *asynchronously* and publishes when complete.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n    */\n    func replacePublisher(options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.replace(options: options,\n                         completion: promise)\n        }\n    }\n\n    /**\n     Updates the `ParseObject` *asynchronously* and publishes when complete.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n    */\n    internal func updatePublisher(options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.update(options: options,\n                        completion: promise)\n        }\n    }\n\n    /**\n     Deletes the `ParseObject` *asynchronously* and publishes when complete.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n    */\n    func deletePublisher(options: API.Options = []) -> Future<Void, ParseError> {\n        Future { promise in\n            self.delete(options: options, completion: promise)\n        }\n    }\n}\n\npublic extension Sequence where Element: ParseObject {\n    /**\n     Fetches a collection of objects *aynchronously* with the current data from the server and sets\n     an error if one occurs. Publishes when complete.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys one level deep. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces an an array of Result enums with the object if a fetch was\n     successful or a `ParseError` if it failed.\n    */\n    func fetchAllPublisher(includeKeys: [String]? = nil,\n                           options: API.Options = []) -> Future<[(Result<Self.Element, ParseError>)], ParseError> {\n        Future { promise in\n            self.fetchAll(includeKeys: includeKeys,\n                          options: options,\n                          completion: promise)\n        }\n    }\n\n    /**\n     Saves a collection of objects *asynchronously* and publishes when complete.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces an an array of Result enums with the object if a save was\n     successful or a `ParseError` if it failed.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true`\n     and plan to generate all of your `objectId`'s on the client-side then you should leave\n     `ignoringCustomObjectIdConfig = false`. Setting\n     `ParseConfiguration.isRequiringCustomObjectIds = true` and\n     `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s\n     and the server will generate an `objectId` only when the client does not provide one. This can\n     increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using\n     different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the\n     client-side checks are disabled. Developers are responsible for handling such cases.\n    */\n    func saveAllPublisher(batchLimit limit: Int? = nil,\n                          transaction: Bool = configuration.isUsingTransactions,\n                          ignoringCustomObjectIdConfig: Bool = false,\n                          options: API.Options = []) -> Future<[(Result<Self.Element, ParseError>)], ParseError> {\n        Future { promise in\n            self.saveAll(batchLimit: limit,\n                         transaction: transaction,\n                         ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                         options: options,\n                         completion: promise)\n        }\n    }\n\n    /**\n     Creates a collection of objects *asynchronously* and publishes when complete.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces an an array of Result enums with the object if a save was\n     successful or a `ParseError` if it failed.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n    */\n    func createAllPublisher(batchLimit limit: Int? = nil,\n                            transaction: Bool = configuration.isUsingTransactions,\n                            options: API.Options = []) -> Future<[(Result<Self.Element, ParseError>)], ParseError> {\n        Future { promise in\n            self.createAll(batchLimit: limit,\n                           transaction: transaction,\n                           options: options,\n                           completion: promise)\n        }\n    }\n\n    /**\n     Replaces a collection of objects *asynchronously* and publishes when complete.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces an an array of Result enums with the object if a save was\n     successful or a `ParseError` if it failed.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n    */\n    func replaceAllPublisher(batchLimit limit: Int? = nil,\n                             transaction: Bool = configuration.isUsingTransactions,\n                             options: API.Options = []) -> Future<[(Result<Self.Element, ParseError>)], ParseError> {\n        Future { promise in\n            self.replaceAll(batchLimit: limit,\n                            transaction: transaction,\n                            options: options,\n                            completion: promise)\n        }\n    }\n\n    /**\n     Updates a collection of objects *asynchronously* and publishes when complete.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces an an array of Result enums with the object if a save was\n     successful or a `ParseError` if it failed.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n    */\n    internal func updateAllPublisher(batchLimit limit: Int? = nil,\n                                     transaction: Bool = configuration.isUsingTransactions,\n                                     options: API.Options = []) -> Future<[(Result<Self.Element, ParseError>)],\n                                                                            ParseError> {\n        Future { promise in\n            self.updateAll(batchLimit: limit,\n                           transaction: transaction,\n                           options: options,\n                           completion: promise)\n        }\n    }\n\n    /**\n     Deletes a collection of objects *asynchronously* and publishes when complete.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces an an array of Result enums with `nil` if a delete was\n     successful or a `ParseError` if it failed.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n    */\n    func deleteAllPublisher(batchLimit limit: Int? = nil,\n                            transaction: Bool = configuration.isUsingTransactions,\n                            options: API.Options = []) -> Future<[(Result<Void, ParseError>)], ParseError> {\n        Future { promise in\n            self.deleteAll(batchLimit: limit,\n                           transaction: transaction,\n                           options: options,\n                           completion: promise)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Objects/ParseObject.swift",
    "content": "//\n//  ParseObject.swift\n//  ParseSwift\n//\n//  Created by Florent Vilmart on 17-07-24.\n//  Copyright © 2020 Parse. All rights reserved.\n//\n\nimport Foundation\n\n// swiftlint:disable line_length\n\n/**\n Objects that conform to the `ParseObject` protocol have a local representation of data persisted to the Parse Server.\n This is the main protocol that is used to interact with objects in your app.\n\n The Swift SDK is designed for your `ParseObject`s to be **value types (structures)**.\n Since you are using value types the compiler will assist you with conforming to the `ParseObject` protocol.\n After a `ParseObject`is saved/created to a Parse Server. It is recommended to conduct any updates on a\n `mergeable` copy of your `ParseObject`. This can be accomplished by calling the `mergeable` property\n of your `ParseObject` or by calling the `set()` method on your `ParseObject`. This allows a subset\n of the fields to be updated (PATCH) of an object as oppose to replacing all of the fields of an object (PUT).\n This reduces the amount of data sent between client and server when using `save`, `saveAll`, `update`,\n `updateAll`, `replace`, `replaceAll`, to update objects.\n \n - important: It is required that all of your `ParseObject`'s be **value types (structures)** and all added\n properties be optional so they can eventually be used as Parse `Pointer`'s. If a developer really wants to\n have a required key, they should require it on the server-side or create methods to check the respective properties\n on the client-side before saving objects. See\n [here](https://github.com/parse-community/Parse-Swift/pull/315#issuecomment-1014701003)\n for more information on the reasons why. See the [Playgrounds](https://github.com/parse-community/Parse-Swift/blob/c119033f44b91570997ad24f7b4b5af8e4d47b64/ParseSwift.playground/Pages/1%20-%20Your%20first%20Object.xcplaygroundpage/Contents.swift#L32-L66) for an example.\n - important: A developer can take advantage of `mergeable` updates in two ways: 1) By calling the `set()` method when starting\n to mutate a saved `ParseObject`, or 2) implement the `merge` method in each of your`ParseObject` models.\n - note: If you plan to use custom encoding/decoding, be sure to add `objectId`, `createdAt`, `updatedAt`, and\n `ACL` to your `ParseObject`'s `CodingKeys`.\n - warning: This SDK is not designed to use **reference types(classes)** for `ParseObject`'s. Doing so is at your\n risk and may have unexpected behavior when it comes to threading. You will also need to implement\n your own `==` method to conform to `Equatable` along with with the `hash` method to conform to `Hashable`.\n It is important to note that for unsaved `ParseObject`'s, you will not be able to rely on `objectId` for\n `Equatable` and `Hashable` as your unsaved objects will not have this value yet and is nil.\n*/\npublic protocol ParseObject: ParseTypeable,\n                             Objectable,\n                             Fetchable,\n                             Savable,\n                             Deletable,\n                             Identifiable,\n                             Hashable {\n\n    /**\n     A JSON encoded version of this `ParseObject` before `mergeable` was called and\n     properties were changed.\n     - warning: This property is not intended to be set or modified by the developer.\n    */\n    var originalData: Data? { get set }\n\n    /**\n     An empty copy of the respective object that allows you to update a\n     a subset of the fields (PATCH) of an object as oppose to replacing an object (PUT).\n     - note: It is recommended to use this to create a mergeable copy of your `ParseObject`.\n     - warning: `mergeable` should only be used on `ParseObject`'s that have already\n     been saved at least once to a Parse Server and have a valid `objectId`. In addition,\n     the developer should have implemented added all of their properties to `merge`.\n    */\n    var mergeable: Self { get }\n\n    /**\n     The default initializer to ensure all `ParseObject`'s can be encoded/decoded properly.\n     - important: The compiler will give you this initialzer for free\n     ([memberwise initializer](https://docs.swift.org/swift-book/LanguageGuide/Initialization.html))\n     as long as you declare all properties as **optional** (see **Warning** section) and you declare all other initializers in\n     an **extension**. See the [Playgrounds](https://github.com/parse-community/Parse-Swift/blob/c119033f44b91570997ad24f7b4b5af8e4d47b64/ParseSwift.playground/Pages/1%20-%20Your%20first%20Object.xcplaygroundpage/Contents.swift#L32-L66) for an example.\n     - attention: This initilizer **should remain empty and no properties should be implemented inside of it**. The SDK needs\n     this initializer to create new instances of your `ParseObject` when saving, updating, and converting to/from Parse Pointers. If you need\n     to initiaze properties, create additional initializers.\n     - warning: It is required that all added properties be optional properties so they can eventually be used as\n     Parse `Pointer`'s. If a developer really wants to have a required key, they should require it on the server-side or\n     create methods to check the respective properties on the client-side before saving objects. See\n     [here](https://github.com/parse-community/Parse-Swift/pull/315#issuecomment-1014701003)\n     for more information.\n     */\n    init()\n\n    /**\n     Determines if a `KeyPath` of the current `ParseObject` should be restored\n     by comparing it to another `ParseObject`.\n     - parameter key: The `KeyPath` to check.\n     - parameter original: The original `ParseObject`.\n     - returns: Returns a **true** if the keyPath should be restored  or **false** otherwise.\n    */\n    func shouldRestoreKey<W>(_ key: KeyPath<Self, W?>,\n                             original: Self) -> Bool where W: Equatable\n\n    /**\n     Merges two `ParseObject`'s with the resulting object consisting of all modified\n     and unchanged Parse properties.\n     - parameter with: The original object.\n     - returns: The updated installation.\n     - throws: An error of type `ParseError`.\n     - note: This is used in combination with `merge` to only send updated\n     properties to the server and then merge those changes with the original object.\n     - warning: You should only call this method and should not implement it directly\n     as it is already implemented for developers to use.\n    */\n    func mergeParse(with object: Self) throws -> Self\n\n    /**\n     Merges two `ParseObject`'s with the resulting object consisting of all modified\n     and unchanged properties.\n\n         //: Create your own value typed `ParseObject`.\n         struct GameScore: ParseObject {\n             //: These are required by ParseObject\n             var objectId: String?\n             var createdAt: Date?\n             var updatedAt: Date?\n             var ACL: ParseACL?\n\n             //: Your own properties.\n             var points: Int?\n\n             //: Implement your own version of merge\n             func merge(with object: Self) throws -> Self {\n                 var updated = try mergeParse(with: object)\n                 if updated.shouldRestoreKey(\\.points,\n                                                  original: object) {\n                     updated.points = object.points\n                 }\n                 return updated\n             }\n         }\n\n     - parameter with: The original object.\n     - returns: The merged object.\n     - throws: An error of type `ParseError`.\n     - note: Use this in combination with `ParseMutable` to only send updated\n     properties to the server and then merge those changes with the original object.\n     - important: It is recommend you provide an implementation of this method\n     for all of your `ParseObject`'s as the developer has access to all properties of a\n     `ParseObject`. You should always call `mergeParse`\n     in the beginning of your implementation to handle all default Parse properties. In addition,\n     use `shouldRestoreKey` to compare key modifications between objects.\n    */\n    func merge(with object: Self) throws -> Self\n}\n\n// MARK: Default Implementations\npublic extension ParseObject {\n\n    func hash(into hasher: inout Hasher) {\n        hasher.combine(self.id)\n    }\n\n    /**\n     A computed property that is the same value as `objectId` and makes it easy to use `ParseObject`'s\n     as models in MVVM and SwiftUI.\n     - note: `id` allows `ParseObjects`'s to be used even when they are unsaved and do not have an `objectId`.\n    */\n    var id: String {\n        objectId ?? UUID().uuidString\n    }\n\n    var mergeable: Self {\n        guard isSaved,\n            originalData == nil else {\n            return self\n        }\n        var object = Self()\n        object.objectId = objectId\n        object.createdAt = createdAt\n        object.originalData = try? ParseCoding.jsonEncoder().encode(self)\n        return object\n    }\n\n    /**\n     Determines if two objects have the same objectId.\n     - parameter as: Object to compare.\n     - returns: Returns a **true** if the other object has the same `objectId` or **false** if unsuccessful.\n    */\n    func hasSameObjectId<T: ParseObject>(as other: T) -> Bool {\n        return other.className == className && other.objectId == objectId && objectId != nil\n    }\n\n    /**\n     Converts this `ParseObject` to a Parse Pointer.\n     - returns: The pointer version of the `ParseObject`, Pointer<Self>.\n    */\n    func toPointer() throws -> Pointer<Self> {\n        return try Pointer(self)\n    }\n\n    func shouldRestoreKey<W>(_ key: KeyPath<Self, W?>,\n                             original: Self) -> Bool where W: Equatable {\n        self[keyPath: key] == nil && original[keyPath: key] != self[keyPath: key]\n    }\n\n    func mergeParse(with object: Self) throws -> Self {\n        guard hasSameObjectId(as: object) else {\n            throw ParseError(code: .unknownError,\n                             message: \"objectId's of objects do not match\")\n        }\n        var updated = self\n        if shouldRestoreKey(\\.ACL,\n                             original: object) {\n            updated.ACL = object.ACL\n        }\n        return updated\n    }\n\n    func merge(with object: Self) throws -> Self {\n        do {\n            return try mergeAutomatically(object)\n        } catch {\n            return try mergeParse(with: object)\n        }\n    }\n}\n\n// MARK: Default Implementations (Internal)\nextension ParseObject {\n    func shouldRevertKey<W>(_ key: KeyPath<Self, W?>,\n                            original: Self) -> Bool where W: Equatable {\n        original[keyPath: key] != self[keyPath: key]\n    }\n}\n\n// MARK: Helper Methods\npublic extension ParseObject {\n    /**\n     Reverts the `KeyPath` of the `ParseObject` back to  the original `KeyPath`\n     before mutations began.\n     - throws: An error of type `ParseError`.\n     - important: This reverts to the contents in `originalData`. This means `originalData` should have\n     been populated by calling `mergeable` or the `set` method.\n    */\n    @available(*, deprecated, renamed: \"revert\")\n    func revertKeyPath<W>(_ keyPath: WritableKeyPath<Self, W?>) throws -> Self where W: Equatable {\n        try revert(keyPath)\n    }\n\n    /**\n     Reverts the `ParseObject` back to the original object before mutations began.\n     - throws: An error of type `ParseError`.\n     - important: This reverts to the contents in `originalData`. This means `originalData` should have\n     been populated by calling `mergeable` or the `set` method.\n    */\n    @available(*, deprecated, renamed: \"revert\")\n    func revertObject() throws -> Self {\n        try revert()\n    }\n\n    /**\n     Reverts the `KeyPath` of the `ParseObject` back to  the original `KeyPath`\n     before mutations began.\n     - throws: An error of type `ParseError`.\n     - important: This reverts to the contents in `originalData`. This means `originalData` should have\n     been populated by calling `mergeable` or the `set` method.\n    */\n    func revert<W>(_ keyPath: WritableKeyPath<Self, W?>) throws -> Self where W: Equatable {\n        guard let originalData = originalData else {\n            throw ParseError(code: .unknownError,\n                             message: \"Missing original data to revert to\")\n        }\n        let original = try ParseCoding.jsonDecoder().decode(Self.self,\n                                                            from: originalData)\n        guard hasSameObjectId(as: original) else {\n            throw ParseError(code: .unknownError,\n                             message: \"The current object does not have the same objectId as the original\")\n        }\n        var updated = self\n        if shouldRevertKey(keyPath,\n                           original: original) {\n            updated[keyPath: keyPath] = original[keyPath: keyPath]\n        }\n        return updated\n    }\n\n    /**\n     Reverts the `ParseObject` back to the original object before mutations began.\n     - throws: An error of type `ParseError`.\n     - important: This reverts to the contents in `originalData`. This means `originalData` should have\n     been populated by calling `mergeable` or the `set` method.\n    */\n    func revert() throws -> Self {\n        guard let originalData = originalData else {\n            throw ParseError(code: .unknownError,\n                             message: \"Missing original data to revert to\")\n        }\n        let original = try ParseCoding.jsonDecoder().decode(Self.self,\n                                                            from: originalData)\n        guard hasSameObjectId(as: original) else {\n            throw ParseError(code: .unknownError,\n                             message: \"The current object does not have the same objectId as the original\")\n        }\n        return original\n    }\n\n    /**\n     Get the unwrapped property value.\n     - parameter key: The `KeyPath` of the value to get.\n     - throws: An error of type `ParseError` when the value is **nil**.\n     - returns: The unwrapped value.\n     */\n    @discardableResult\n    func get<W>(_ keyPath: KeyPath<Self, W?>) throws -> W where W: Equatable {\n        guard let value = self[keyPath: keyPath] else {\n            throw ParseError(code: .unknownError, message: \"Could not unwrap value\")\n        }\n        return value\n    }\n\n    /**\n     Set the value of a specific `KeyPath` on a `ParseObject`.\n     - parameter key: The `KeyPath` of the value to set.\n     - parameter value: The value to set the `KeyPath` to.\n     - returns: The updated `ParseObject`.\n     - important: This method should be used when updating a `ParseObject` that has already been saved to\n     a Parse Server. You can also use this method on a new `ParseObject`'s that has not been saved to a Parse Server\n     as long as the `objectId` of the respective `ParseObject` is **nil**.\n     - attention: If you are using the `set()` method, you do not need to implement `merge()`. Using `set()`\n     may perform slower than implementing `merge()` after saving the updated `ParseObject` to a Parse Server.\n     This is due to neccesary overhead required to determine what keys have been updated. If a developer finds decoding\n     updated `ParseObjects`'s to be slow, implementing `merge()` may speed up the process.\n     - warning: This method should always be used when making the very first update/mutation to your `ParseObject`.\n     Any subsequent mutations can modify the `ParseObject` property directly or use the `set()` method.\n     */\n    func set<W>(_ keyPath: WritableKeyPath<Self, W?>, to value: W) -> Self where W: Equatable {\n        var updated = self.mergeable\n        updated[keyPath: keyPath] = value\n        return updated\n    }\n}\n\n// MARK: Helper Methods (Internal)\nextension ParseObject {\n\n    func mergeAutomatically(_ originalObject: Self) throws -> Self {\n        let updatedEncoded = try ParseCoding.jsonEncoder().encode(self)\n        let originalData = try ParseCoding.jsonEncoder().encode(originalObject)\n        guard let updated = try JSONSerialization.jsonObject(with: updatedEncoded) as? [String: AnyObject],\n            var original = try JSONSerialization.jsonObject(with: originalData) as? [String: AnyObject] else {\n            throw ParseError(code: .unknownError,\n                             message: \"Could not encode/decode necessary objects\")\n        }\n        updated.forEach { (key, value) in\n            original[key] = value\n        }\n        let mergedEncoded = try JSONSerialization.data(withJSONObject: original)\n        return try ParseCoding.jsonDecoder().decode(Self.self,\n                                                    from: mergedEncoded)\n    }\n}\n\n// MARK: Batch Support\npublic extension Sequence where Element: ParseObject {\n\n    internal func canSendTransactions(_ usingTransactions: Bool,\n                                      objectCount: Int,\n                                      batchLimit: Int) throws {\n        if usingTransactions {\n            if objectCount > batchLimit {\n                let error = ParseError(code: .unknownError,\n                                       message: \"\"\"\nThe amount of objects (\\(objectCount)) cannot exceed the batch size(\\(batchLimit)).\nEither decrease the amount of objects, increase the batch size, or disable\ntransactions for this call.\n\"\"\")\n                throw error\n            }\n        }\n    }\n\n    /**\n     Saves a collection of objects *synchronously* all at once and throws an error if necessary.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns an array of Result enums with the object if a save was successful or a\n     `ParseError` if it failed.\n     - throws: An error of type `ParseError`.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true`\n     and plan to generate all of your `objectId`'s on the client-side then you should leave\n     `ignoringCustomObjectIdConfig = false`. Setting\n     `ParseConfiguration.isRequiringCustomObjectIds = true` and\n     `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s\n     and the server will generate an `objectId` only when the client does not provide one. This can\n     increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using\n     different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the\n     client-side checks are disabled. Developers are responsible for handling such cases.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func saveAll(batchLimit limit: Int? = nil, // swiftlint:disable:this function_body_length\n                 transaction: Bool = configuration.isUsingTransactions,\n                 ignoringCustomObjectIdConfig: Bool = false,\n                 options: API.Options = []) throws -> [(Result<Self.Element, ParseError>)] {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        var childObjects = [String: PointerType]()\n        var childFiles = [UUID: ParseFile]()\n        var error: ParseError?\n\n        var commands = [API.Command<Self.Element, Self.Element>]()\n        try forEach {\n            let object = $0\n            let group = DispatchGroup()\n            group.enter()\n            object.ensureDeepSave(options: options,\n                                  // swiftlint:disable:next line_length\n                                  isShouldReturnIfChildObjectsFound: transaction) { (savedChildObjects, savedChildFiles, parseError) -> Void in\n                // If an error occurs, everything should be skipped\n                if parseError != nil {\n                    error = parseError\n                }\n                savedChildObjects.forEach {(key, value) in\n                    if error != nil {\n                        return\n                    }\n                    if childObjects[key] == nil {\n                        childObjects[key] = value\n                    } else {\n                        error = ParseError(code: .unknownError, message: \"circular dependency\")\n                        return\n                    }\n                }\n                savedChildFiles.forEach {(key, value) in\n                    if error != nil {\n                        return\n                    }\n                    if childFiles[key] == nil {\n                        childFiles[key] = value\n                    } else {\n                        error = ParseError(code: .unknownError, message: \"circular dependency\")\n                        return\n                    }\n                }\n                group.leave()\n            }\n            group.wait()\n            if let error = error {\n                throw error\n            }\n            commands.append(try object.saveCommand(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig))\n        }\n\n        var returnBatch = [(Result<Self.Element, ParseError>)]()\n        let batchLimit = limit != nil ? limit! : ParseConstants.batchLimit\n        try canSendTransactions(transaction, objectCount: commands.count, batchLimit: batchLimit)\n        let batches = BatchUtils.splitArray(commands, valuesPerSegment: batchLimit)\n        try batches.forEach {\n            let currentBatch = try API.Command<Self.Element, Self.Element>\n                .batch(commands: $0, transaction: transaction)\n                .execute(options: options,\n                         batching: true,\n                         childObjects: childObjects,\n                         childFiles: childFiles)\n            returnBatch.append(contentsOf: currentBatch)\n        }\n        return returnBatch\n    }\n\n    /**\n     Saves a collection of objects all at once *asynchronously* and executes the completion block when done.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<[(Result<Element, ParseError>)], ParseError>)`.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true`\n     and plan to generate all of your `objectId`'s on the client-side then you should leave\n     `ignoringCustomObjectIdConfig = false`. Setting\n     `ParseConfiguration.isRequiringCustomObjectIds = true` and\n     `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s\n     and the server will generate an `objectId` only when the client does not provide one. This can\n     increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using\n     different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the\n     client-side checks are disabled. Developers are responsible for handling such cases.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func saveAll( // swiftlint:disable:this function_body_length cyclomatic_complexity\n        batchLimit limit: Int? = nil,\n        transaction: Bool = configuration.isUsingTransactions,\n        ignoringCustomObjectIdConfig: Bool = false,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<[(Result<Element, ParseError>)], ParseError>) -> Void\n    ) {\n        let method = Method.save\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let objects = try await batchCommand(method: method,\n                                                     batchLimit: limit,\n                                                     transaction: transaction,\n                                                     ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                                                     options: options,\n                                                     callbackQueue: callbackQueue)\n                completion(.success(objects))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        batchCommand(method: method,\n                     batchLimit: limit,\n                     transaction: transaction,\n                     ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                     options: options,\n                     callbackQueue: callbackQueue,\n                     completion: completion)\n        #endif\n    }\n\n    /**\n     Creates a collection of objects all at once *asynchronously* and executes the completion block when done.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<[(Result<Element, ParseError>)], ParseError>)`.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func createAll( // swiftlint:disable:this function_body_length cyclomatic_complexity\n        batchLimit limit: Int? = nil,\n        transaction: Bool = configuration.isUsingTransactions,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<[(Result<Element, ParseError>)], ParseError>) -> Void\n    ) {\n        let method = Method.create\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let objects = try await batchCommand(method: method,\n                                                     batchLimit: limit,\n                                                     transaction: transaction,\n                                                     options: options,\n                                                     callbackQueue: callbackQueue)\n                completion(.success(objects))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        batchCommand(method: method,\n                     batchLimit: limit,\n                     transaction: transaction,\n                     options: options,\n                     callbackQueue: callbackQueue,\n                     completion: completion)\n        #endif\n    }\n\n    /**\n     Replaces a collection of objects all at once *asynchronously* and executes the completion block when done.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<[(Result<Element, ParseError>)], ParseError>)`.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func replaceAll( // swiftlint:disable:this function_body_length cyclomatic_complexity\n        batchLimit limit: Int? = nil,\n        transaction: Bool = configuration.isUsingTransactions,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<[(Result<Element, ParseError>)], ParseError>) -> Void\n    ) {\n        let method = Method.replace\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let objects = try await batchCommand(method: method,\n                                                     batchLimit: limit,\n                                                     transaction: transaction,\n                                                     options: options,\n                                                     callbackQueue: callbackQueue)\n                completion(.success(objects))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        batchCommand(method: method,\n                     batchLimit: limit,\n                     transaction: transaction,\n                     options: options,\n                     callbackQueue: callbackQueue,\n                     completion: completion)\n        #endif\n    }\n\n    /**\n     Updates a collection of objects all at once *asynchronously* and executes the completion block when done.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<[(Result<Element, ParseError>)], ParseError>)`.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    internal func updateAll( // swiftlint:disable:this function_body_length cyclomatic_complexity\n        batchLimit limit: Int? = nil,\n        transaction: Bool = configuration.isUsingTransactions,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<[(Result<Element, ParseError>)], ParseError>) -> Void\n    ) {\n        let method = Method.update\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let objects = try await batchCommand(method: method,\n                                                     batchLimit: limit,\n                                                     transaction: transaction,\n                                                     options: options,\n                                                     callbackQueue: callbackQueue)\n                completion(.success(objects))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        batchCommand(method: method,\n                     batchLimit: limit,\n                     transaction: transaction,\n                     options: options,\n                     callbackQueue: callbackQueue,\n                     completion: completion)\n        #endif\n    }\n\n    internal func batchCommand(method: Method, // swiftlint:disable:this function_parameter_count\n                               batchLimit limit: Int?,\n                               transaction: Bool,\n                               ignoringCustomObjectIdConfig: Bool = false,\n                               options: API.Options,\n                               callbackQueue: DispatchQueue,\n                               completion: @escaping (Result<[(Result<Element, ParseError>)], ParseError>) -> Void) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        let uuid = UUID()\n        let queue = DispatchQueue(label: \"com.parse.batch.\\(uuid)\",\n                                  qos: .default,\n                                  attributes: .concurrent,\n                                  autoreleaseFrequency: .inherit,\n                                  target: nil)\n        queue.sync {\n            var childObjects = [String: PointerType]()\n            var childFiles = [UUID: ParseFile]()\n            var error: ParseError?\n            var commands = [API.Command<Self.Element, Self.Element>]()\n            let objects = map { $0 }\n            for object in objects {\n                let group = DispatchGroup()\n                group.enter()\n                object.ensureDeepSave(options: options,\n                                      // swiftlint:disable:next line_length\n                                      isShouldReturnIfChildObjectsFound: transaction) { (savedChildObjects, savedChildFiles, parseError) -> Void in\n                    // If an error occurs, everything should be skipped\n                    if let parseError = parseError {\n                        error = parseError\n                    }\n                    savedChildObjects.forEach {(key, value) in\n                        guard error == nil else {\n                            return\n                        }\n                        guard childObjects[key] == nil else {\n                            error = ParseError(code: .unknownError, message: \"circular dependency\")\n                            return\n                        }\n                        childObjects[key] = value\n                    }\n                    savedChildFiles.forEach {(key, value) in\n                        guard error == nil else {\n                            return\n                        }\n                        guard childFiles[key] == nil else {\n                            error = ParseError(code: .unknownError, message: \"circular dependency\")\n                            return\n                        }\n                        childFiles[key] = value\n                    }\n                    group.leave()\n                }\n                group.wait()\n                if let error = error {\n                    callbackQueue.async {\n                        completion(.failure(error))\n                    }\n                    return\n                }\n\n                do {\n                    switch method {\n                    case .save:\n                        commands.append(\n                            try object.saveCommand(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig)\n                        )\n                    case .create:\n                        commands.append(object.createCommand())\n                    case .replace:\n                        commands.append(try object.replaceCommand())\n                    case .update:\n                        commands.append(try object.updateCommand())\n                    }\n                } catch {\n                    let defaultError = ParseError(code: .unknownError,\n                                                  message: error.localizedDescription)\n                    let parseError = error as? ParseError ?? defaultError\n                    callbackQueue.async {\n                        completion(.failure(parseError))\n                    }\n                    return\n                }\n            }\n\n            do {\n                var returnBatch = [(Result<Self.Element, ParseError>)]()\n\n                let batchLimit = limit != nil ? limit! : ParseConstants.batchLimit\n                try canSendTransactions(transaction, objectCount: commands.count, batchLimit: batchLimit)\n                let batches = BatchUtils.splitArray(commands, valuesPerSegment: batchLimit)\n                var completed = 0\n                for batch in batches {\n                    API.Command<Self.Element, Self.Element>\n                            .batch(commands: batch, transaction: transaction)\n                            .executeAsync(options: options,\n                                          batching: true,\n                                          callbackQueue: callbackQueue,\n                                          childObjects: childObjects,\n                                          childFiles: childFiles) { results in\n                        switch results {\n\n                        case .success(let saved):\n                            returnBatch.append(contentsOf: saved)\n                            if completed == (batches.count - 1) {\n                                completion(.success(returnBatch))\n                            }\n                            completed += 1\n                        case .failure(let error):\n                            completion(.failure(error))\n                            return\n                        }\n                    }\n                }\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n    }\n\n    /**\n     Fetches a collection of objects *synchronously* all at once and throws an error if necessary.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys one level deep. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns an array of Result enums with the object if a fetch was successful or a\n     `ParseError` if it failed.\n     - throws: An error of type `ParseError`.\n     - warning: The order in which objects are returned are not guarenteed. You should not expect results in\n     any particular order.\n    */\n    func fetchAll(includeKeys: [String]? = nil,\n                  options: API.Options = []) throws -> [(Result<Self.Element, ParseError>)] {\n\n        if (allSatisfy { $0.className == Self.Element.className}) {\n            let uniqueObjectIds = Set(compactMap { $0.objectId })\n            var query = Self.Element.query(containedIn(key: \"objectId\", array: [uniqueObjectIds]))\n                .limit(uniqueObjectIds.count)\n            if let include = includeKeys {\n                query = query.include(include)\n            }\n            let fetchedObjects = try query.find(options: options)\n            var fetchedObjectsToReturn = [(Result<Self.Element, ParseError>)]()\n\n            uniqueObjectIds.forEach {\n                let uniqueObjectId = $0\n                if let fetchedObject = fetchedObjects.first(where: {$0.objectId == uniqueObjectId}) {\n                    fetchedObjectsToReturn.append(.success(fetchedObject))\n                } else {\n                    fetchedObjectsToReturn.append(.failure(ParseError(code: .objectNotFound,\n                                                                      // swiftlint:disable:next line_length\n                                                                      message: \"objectId \\\"\\(uniqueObjectId)\\\" was not found in className \\\"\\(Self.Element.className)\\\"\")))\n                }\n            }\n            return fetchedObjectsToReturn\n        } else {\n            throw ParseError(code: .unknownError, message: \"all items to fetch must be of the same class\")\n        }\n    }\n\n    /**\n     Fetches a collection of objects all at once *asynchronously* and executes the completion block when done.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys one level deep. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<[(Result<Element, ParseError>)], ParseError>)`.\n     - warning: The order in which objects are returned are not guarenteed. You should not expect results in\n     any particular order.\n    */\n    func fetchAll(\n        includeKeys: [String]? = nil,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<[(Result<Element, ParseError>)], ParseError>) -> Void\n    ) {\n        if (allSatisfy { $0.className == Self.Element.className}) {\n            let uniqueObjectIds = Set(compactMap { $0.objectId })\n            var query = Self.Element.query(containedIn(key: \"objectId\", array: [uniqueObjectIds]))\n            if let include = includeKeys {\n                query = query.include(include)\n            }\n            query.find(options: options, callbackQueue: callbackQueue) { result in\n                switch result {\n\n                case .success(let fetchedObjects):\n                    var fetchedObjectsToReturn = [(Result<Self.Element, ParseError>)]()\n\n                    uniqueObjectIds.forEach {\n                        let uniqueObjectId = $0\n                        if let fetchedObject = fetchedObjects.first(where: {$0.objectId == uniqueObjectId}) {\n                            fetchedObjectsToReturn.append(.success(fetchedObject))\n                        } else {\n                            fetchedObjectsToReturn.append(.failure(ParseError(code: .objectNotFound,\n                                                                              // swiftlint:disable:next line_length\n                                                                              message: \"objectId \\\"\\(uniqueObjectId)\\\" was not found in className \\\"\\(Self.Element.className)\\\"\")))\n                        }\n                    }\n                    completion(.success(fetchedObjectsToReturn))\n                case .failure(let error):\n                    callbackQueue.async {\n                        completion(.failure(error))\n                    }\n                }\n            }\n        } else {\n            callbackQueue.async {\n                completion(.failure(ParseError(code: .unknownError,\n                                               message: \"all items to fetch must be of the same class\")))\n            }\n        }\n    }\n\n    /**\n     Deletes a collection of objects *synchronously* all at once and throws an error if necessary.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n\n     - returns: Returns `nil` if the delete successful or a `ParseError` if it failed.\n        1. A `ParseError.Code.aggregateError`. This object's \"errors\" property is an\n        array of other Parse.Error objects. Each error object in this array\n        has an \"object\" property that references the object that could not be\n        deleted (for instance, because that object could not be found).\n        2. A non-aggregate Parse.Error. This indicates a serious error that\n        caused the delete operation to be aborted partway through (for\n        instance, a connection failure in the middle of the delete).\n     - throws: An error of type `ParseError`.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func deleteAll(batchLimit limit: Int? = nil,\n                   transaction: Bool = configuration.isUsingTransactions,\n                   options: API.Options = []) throws -> [(Result<Void, ParseError>)] {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        var returnBatch = [(Result<Void, ParseError>)]()\n        let commands = try map { try $0.deleteCommand() }\n        let batchLimit = limit != nil ? limit! : ParseConstants.batchLimit\n        try canSendTransactions(transaction, objectCount: commands.count, batchLimit: batchLimit)\n        let batches = BatchUtils.splitArray(commands, valuesPerSegment: batchLimit)\n        try batches.forEach {\n            let currentBatch = try API.Command<Self.Element, (Result<Void, ParseError>)>\n                .batch(commands: $0,\n                       transaction: transaction)\n                .execute(options: options)\n            returnBatch.append(contentsOf: currentBatch)\n        }\n        return returnBatch\n    }\n\n    /**\n     Deletes a collection of objects all at once *asynchronously* and executes the completion block when done.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<[ParseError?], ParseError>)`.\n     Each element in the array is `nil` if the delete successful or a `ParseError` if it failed.\n     1. A `ParseError.Code.aggregateError`. This object's \"errors\" property is an\n     array of other Parse.Error objects. Each error object in this array\n     has an \"object\" property that references the object that could not be\n     deleted (for instance, because that object could not be found).\n     2. A non-aggregate Parse.Error. This indicates a serious error that\n     caused the delete operation to be aborted partway through (for\n     instance, a connection failure in the middle of the delete).\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func deleteAll(\n        batchLimit limit: Int? = nil,\n        transaction: Bool = configuration.isUsingTransactions,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<[(Result<Void, ParseError>)], ParseError>) -> Void\n    ) {\n        do {\n            var options = options\n            options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n            var returnBatch = [(Result<Void, ParseError>)]()\n            let commands = try map({ try $0.deleteCommand() })\n            let batchLimit = limit != nil ? limit! : ParseConstants.batchLimit\n            try canSendTransactions(transaction, objectCount: commands.count, batchLimit: batchLimit)\n            let batches = BatchUtils.splitArray(commands, valuesPerSegment: batchLimit)\n            var completed = 0\n            for batch in batches {\n                API.Command<Self.Element, ParseError?>\n                        .batch(commands: batch, transaction: transaction)\n                        .executeAsync(options: options,\n                                      callbackQueue: callbackQueue) { results in\n                    switch results {\n\n                    case .success(let saved):\n                        returnBatch.append(contentsOf: saved)\n                        if completed == (batches.count - 1) {\n                            completion(.success(returnBatch))\n                        }\n                        completed += 1\n                    case .failure(let error):\n                        completion(.failure(error))\n                        return\n                    }\n                }\n            }\n        } catch {\n            let defaultError = ParseError(code: .unknownError,\n                                          message: error.localizedDescription)\n            let parseError = error as? ParseError ?? defaultError\n            callbackQueue.async {\n                completion(.failure(parseError))\n            }\n        }\n    }\n}\n\n// MARK: CustomDebugStringConvertible\nextension ParseObject {\n    public var debugDescription: String {\n        guard let descriptionData = try? ParseCoding.jsonEncoder().encode(self),\n            let descriptionString = String(data: descriptionData, encoding: .utf8) else {\n                return \"\\(className) ()\"\n        }\n\n        return \"\\(className) (\\(descriptionString))\"\n    }\n}\n\n// MARK: CustomStringConvertible\nextension ParseObject {\n    public var description: String {\n        debugDescription\n    }\n}\n\n// MARK: Fetchable\nextension ParseObject {\n\n    /**\n     Fetches the `ParseObject` *synchronously* with the current data from the server.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys one level deep. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of `ParseError` type.\n     - returns: Returns the fetched `ParseObject`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func fetch(includeKeys: [String]? = nil,\n                      options: API.Options = []) throws -> Self {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        return try fetchCommand(include: includeKeys).execute(options: options)\n    }\n\n    /**\n     Fetches the `ParseObject` *asynchronously* and executes the given callback block.\n     - parameter includeKeys: The name(s) of the key(s) to include. Use `[\"*\"]` to include\n     all keys one level deep.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func fetch(\n        includeKeys: [String]? = nil,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<Self, ParseError>) -> Void\n    ) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n         do {\n            try fetchCommand(include: includeKeys)\n                .executeAsync(options: options,\n                              callbackQueue: callbackQueue) { result in\n                    completion(result)\n            }\n         } catch {\n            callbackQueue.async {\n                if let error = error as? ParseError {\n                    completion(.failure(error))\n                } else {\n                    completion(.failure(ParseError(code: .unknownError,\n                                                   message: error.localizedDescription)))\n                }\n            }\n         }\n    }\n\n    internal func fetchCommand(include: [String]?) throws -> API.Command<Self, Self> {\n        try API.Command<Self, Self>.fetch(self, include: include)\n    }\n}\n\n// MARK: Savable\nextension ParseObject {\n\n    /**\n     Saves the `ParseObject` *synchronously* and throws an error if there is an issue.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n\n     - returns: Returns saved `ParseObject`.\n    */\n    @discardableResult\n    public func save(options: API.Options = []) throws -> Self {\n        try save(ignoringCustomObjectIdConfig: false, options: options)\n    }\n\n    /**\n     Saves the `ParseObject` *synchronously* and throws an error if there is an issue.\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n\n     - returns: Returns saved `ParseObject`.\n     - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true`\n     and plan to generate all of your `objectId`'s on the client-side then you should leave\n     `ignoringCustomObjectIdConfig = false`. Setting\n     `ParseConfiguration.isRequiringCustomObjectIds = true` and\n     `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s\n     and the server will generate an `objectId` only when the client does not provide one. This can\n     increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using\n     different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the\n     client-side checks are disabled. Developers are responsible for handling such cases.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult\n    public func save(ignoringCustomObjectIdConfig: Bool = false,\n                     options: API.Options = []) throws -> Self {\n        var childObjects: [String: PointerType]?\n        var childFiles: [UUID: ParseFile]?\n        var error: ParseError?\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        let group = DispatchGroup()\n        group.enter()\n        self.ensureDeepSave(options: options) { (savedChildObjects, savedChildFiles, parseError) in\n            childObjects = savedChildObjects\n            childFiles = savedChildFiles\n            error = parseError\n            group.leave()\n        }\n        group.wait()\n\n        if let error = error {\n            throw error\n        }\n\n        return try saveCommand(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig)\n            .execute(options: options,\n                     childObjects: childObjects,\n                     childFiles: childFiles)\n    }\n\n    /**\n     Saves the `ParseObject` *asynchronously* and executes the given callback block.\n\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true`\n     and plan to generate all of your `objectId`'s on the client-side then you should leave\n     `ignoringCustomObjectIdConfig = false`. Setting\n     `ParseConfiguration.isRequiringCustomObjectIds = true` and\n     `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s\n     and the server will generate an `objectId` only when the client does not provide one. This can\n     increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using\n     different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the\n     client-side checks are disabled. Developers are responsible for handling such cases.\n    */\n    public func save(\n        ignoringCustomObjectIdConfig: Bool = false,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<Self, ParseError>) -> Void\n    ) {\n        let method = Method.save\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let object = try await command(method: method,\n                                               ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                                               options: options,\n                                               callbackQueue: callbackQueue)\n                completion(.success(object))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        command(method: method,\n                ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                options: options,\n                callbackQueue: callbackQueue,\n                completion: completion)\n        #endif\n    }\n\n    /**\n     Creates the `ParseObject` *asynchronously* and executes the given callback block.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n    */\n    public func create(\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<Self, ParseError>) -> Void\n    ) {\n        let method = Method.create\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let object = try await command(method: method,\n                                               options: options,\n                                               callbackQueue: callbackQueue)\n                completion(.success(object))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        command(method: method,\n                options: options,\n                callbackQueue: callbackQueue,\n                completion: completion)\n        #endif\n    }\n\n    /**\n     Replaces the `ParseObject` *asynchronously* and executes the given callback block.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n    */\n    public func replace(\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<Self, ParseError>) -> Void\n    ) {\n        let method = Method.replace\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let object = try await command(method: method,\n                                               options: options,\n                                               callbackQueue: callbackQueue)\n                completion(.success(object))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        command(method: method,\n                options: options,\n                callbackQueue: callbackQueue,\n                completion: completion)\n        #endif\n    }\n\n    /**\n     Updates the `ParseObject` *asynchronously* and executes the given callback block.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n    */\n    func update(\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<Self, ParseError>) -> Void\n    ) {\n        let method = Method.update\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let object = try await command(method: method,\n                                               options: options,\n                                               callbackQueue: callbackQueue)\n                completion(.success(object))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        command(method: method,\n                options: options,\n                callbackQueue: callbackQueue,\n                completion: completion)\n        #endif\n    }\n\n    func command(method: Method,\n                 ignoringCustomObjectIdConfig: Bool = false,\n                 options: API.Options,\n                 callbackQueue: DispatchQueue,\n                 completion: @escaping (Result<Self, ParseError>) -> Void) {\n        self.ensureDeepSave(options: options) { (savedChildObjects, savedChildFiles, error) in\n            guard let parseError = error else {\n                do {\n                    let command: API.Command<Self, Self>!\n                    switch method {\n                    case .save:\n                        command = try self.saveCommand(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig)\n                    case .create:\n                        command = self.createCommand()\n                    case .replace:\n                        command = try self.replaceCommand()\n                    case .update:\n                        command = try self.updateCommand()\n                    }\n                    command\n                        .executeAsync(options: options,\n                                      callbackQueue: callbackQueue,\n                                      childObjects: savedChildObjects,\n                                      childFiles: savedChildFiles,\n                                      completion: completion)\n                } catch {\n                    let defaultError = ParseError(code: .unknownError,\n                                                  message: error.localizedDescription)\n                    let parseError = error as? ParseError ?? defaultError\n                    callbackQueue.async {\n                        completion(.failure(parseError))\n                    }\n                }\n                return\n            }\n            callbackQueue.async {\n                completion(.failure(parseError))\n            }\n        }\n    }\n\n    internal func saveCommand(ignoringCustomObjectIdConfig: Bool = false) throws -> API.Command<Self, Self> {\n        try API.Command<Self, Self>.save(self,\n                                         original: originalData,\n                                         ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig)\n    }\n\n    internal func createCommand() -> API.Command<Self, Self> {\n        API.Command<Self, Self>.create(self)\n    }\n\n    internal func replaceCommand() throws -> API.Command<Self, Self> {\n        try API.Command<Self, Self>.replace(self,\n                                            original: originalData)\n    }\n\n    internal func updateCommand() throws -> API.Command<Self, Self> {\n        try API.Command<Self, Self>.update(self,\n                                           original: originalData)\n    }\n\n    // swiftlint:disable:next function_body_length\n    internal func ensureDeepSave(options: API.Options = [],\n                                 isShouldReturnIfChildObjectsFound: Bool = false,\n                                 completion: @escaping ([String: PointerType],\n                                                        [UUID: ParseFile], ParseError?) -> Void) {\n        let uuid = UUID()\n        let queue = DispatchQueue(label: \"com.parse.deepSave.\\(uuid)\",\n                                  qos: .default,\n                                  attributes: .concurrent,\n                                  autoreleaseFrequency: .inherit,\n                                  target: nil)\n        var options = options\n        // Remove any caching policy added by the developer as fresh data\n        // from the server is needed.\n        options.remove(.cachePolicy(.reloadIgnoringLocalCacheData))\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n\n        queue.sync {\n            var objectsFinishedSaving = [String: PointerType]()\n            var filesFinishedSaving = [UUID: ParseFile]()\n            do {\n                let object = try ParseCoding.parseEncoder()\n                    .encode(self,\n                            objectsSavedBeforeThisOne: nil,\n                            filesSavedBeforeThisOne: nil)\n\n                var waitingToBeSaved = object.unsavedChildren\n                if isShouldReturnIfChildObjectsFound && waitingToBeSaved.count > 0 {\n                    let error = ParseError(code: .unknownError,\n                                           message: \"\"\"\n    When using transactions, all child ParseObjects have to originally\n    be saved to the Parse Server. Either save all child objects first\n    or disable transactions for this call.\n    \"\"\")\n                    completion([String: PointerType](), [UUID: ParseFile](), error)\n                    return\n                }\n                while waitingToBeSaved.count > 0 {\n                    var savableObjects = [ParseEncodable]()\n                    var savableFiles = [ParseFile]()\n                    var nextBatch = [ParseEncodable]()\n                    try waitingToBeSaved.forEach { parseType in\n\n                        if let parseFile = parseType as? ParseFile {\n                            // ParseFiles can be saved now\n                            savableFiles.append(parseFile)\n                        } else if let parseObject = parseType as? Objectable {\n                            // This is a ParseObject\n                            let waitingObjectInfo = try ParseCoding\n                                .parseEncoder()\n                                .encode(parseObject,\n                                        collectChildren: true,\n                                        objectsSavedBeforeThisOne: objectsFinishedSaving,\n                                        filesSavedBeforeThisOne: filesFinishedSaving)\n\n                            if waitingObjectInfo.unsavedChildren.count == 0 {\n                                //If this ParseObject has no additional children, it can be saved now\n                                savableObjects.append(parseObject)\n                            } else {\n                                //Else this ParseObject needs to wait until it is children are saved\n                                nextBatch.append(parseObject)\n                            }\n                        }\n                    }\n                    waitingToBeSaved = nextBatch\n\n                    if waitingToBeSaved.count > 0 && savableObjects.count == 0 && savableFiles.count == 0 {\n                        completion(objectsFinishedSaving,\n                                   filesFinishedSaving,\n                                   ParseError(code: .unknownError,\n                                              message: \"Found a circular dependency in ParseObject.\"))\n                        return\n                    }\n                    if savableObjects.count > 0 {\n                        let savedChildObjects = try self.saveAll(objects: savableObjects,\n                                                                 options: options)\n                        let savedChildPointers = try savedChildObjects.compactMap { try $0.get() }\n                        for (index, object) in savableObjects.enumerated() {\n                            let hash = try BaseObjectable.createHash(object)\n                            objectsFinishedSaving[hash] = savedChildPointers[index]\n                        }\n                    }\n\n                    try savableFiles.forEach {\n                        filesFinishedSaving[$0.id] = try $0.save(options: options)\n                    }\n                }\n                completion(objectsFinishedSaving, filesFinishedSaving, nil)\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                completion(objectsFinishedSaving, filesFinishedSaving, parseError)\n            }\n        }\n    }\n}\n\n// MARK: Savable Encodable Version\ninternal extension ParseEncodable {\n    func saveAll(objects: [ParseEncodable],\n                 transaction: Bool = configuration.isUsingTransactions,\n                 options: API.Options = []) throws -> [(Result<PointerType, ParseError>)] {\n        try API.NonParseBodyCommand<AnyCodable, PointerType>\n                .batch(objects: objects,\n                       transaction: transaction)\n                .execute(options: options)\n    }\n}\n\n// MARK: Deletable\nextension ParseObject {\n    /**\n     Deletes the `ParseObject` *synchronously* with the current data from the server.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of `ParseError` type.\n    */\n    public func delete(options: API.Options = []) throws {\n        _ = try deleteCommand().execute(options: options)\n    }\n\n    /**\n     Deletes the `ParseObject` *asynchronously* and executes the given callback block.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Void, ParseError>)`.\n    */\n    public func delete(\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<Void, ParseError>) -> Void\n    ) {\n         do {\n            try deleteCommand().executeAsync(options: options,\n                                             callbackQueue: callbackQueue) { result in\n                switch result {\n\n                case .success:\n                    completion(.success(()))\n                case .failure(let error):\n                    completion(.failure(error))\n                }\n            }\n         } catch let error as ParseError {\n            callbackQueue.async {\n                completion(.failure(error))\n            }\n         } catch {\n            callbackQueue.async {\n                completion(.failure(ParseError(code: .unknownError, message: error.localizedDescription)))\n            }\n         }\n    }\n\n    internal func deleteCommand() throws -> API.NonParseBodyCommand<NoBody, NoBody> {\n        try API.NonParseBodyCommand<NoBody, NoBody>.delete(self)\n    }\n} // swiftlint:disable:this file_length\n"
  },
  {
    "path": "Sources/ParseSwift/Objects/ParsePushStatusable.swift",
    "content": "//\n//  ParsePushStatus.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 5/30/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n Objects that conform to the `ParsePushStatusable` protocol represent\n PushStatus on the Parse Server.\n - warning: These objects are only read-only.\n - requires: `.useMasterKey` has to be available. It is recommended to only\n use the master key in server-side applications where the key is kept secure and not\n exposed to the public.\n */\npublic protocol ParsePushStatusable: ParseObject {\n    /// A type that conforms to `ParsePushPayloadable`.\n    associatedtype PushType: ParsePushPayloadable\n\n    /// The time the notification was pushed.\n    var pushTime: Date? { get }\n\n    /// The source that created the notification.\n    var source: String? { get }\n\n    /// The **where** query used to  select what installations received the notification.\n    var query: QueryWhere? { get }\n\n    /// The data sent in the notification.\n    var payload: PushType? { get }\n\n    /// The data sent in the notification.\n    var title: String? { get }\n\n    /// The date to expire the notification.\n    var expiry: Int? { get }\n\n    /// The amount of seconds until the notification expires after scheduling.\n    var expirationInterval: String? { get }\n\n    /// The status of the notification.\n    var status: String? { get }\n\n    /// The amount of notificaitons sent.\n    var numSent: Int? { get }\n\n    /// The amount of notifications that failed.\n    var numFailed: Int? { get }\n\n    /// The hash of the alert.\n    var pushHash: String? { get }\n\n    /// The associated error message.\n    var errorMessage: ParseError? { get }\n\n    /// The amount of notifications sent per type.\n    var sentPerType: [String: Int]? { get }\n\n    /// The amount of notifications failed per type.\n    var failedPerType: [String: Int]? { get }\n\n    /// The UTC offeset of notifications sent per type.\n    var sentPerUTCOffset: [String: Int]? { get }\n\n    /// The UTC offeset of notifications failed per type.\n    var failedPerUTCOffset: [String: Int]? { get }\n\n    /// The amount of batches queued.\n    var count: Int? { get }\n\n    /// Create a an empty `ParsePushStatus`.\n    init()\n}\n\n// MARK: Default Implementations\npublic extension ParsePushStatusable {\n    static var className: String {\n        \"_PushStatus\"\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Objects/ParseRole.swift",
    "content": "//\n//  ParseRole.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/17/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n Objects that conform to the `ParseRole` protocol represent a Role on the Parse Server.\n `ParseRole`'s represent groupings of `ParseUser` objects for the purposes of\n granting permissions (e.g. specifying a `ParseACL` for a `ParseObject`).\n Roles are specified by their sets of child users and child roles,\n all of which are granted any permissions that the parent role has.\n Roles must have a name (which cannot be changed after creation of the role),\n and must specify a `ParseACL`.\n */\npublic protocol ParseRole: ParseObject {\n\n    associatedtype RoleUser: ParseUser\n\n    /**\n     Gets or sets the name for a role.\n     This value must be set before the role has been saved to the server,\n     and cannot be set once the role has been saved.\n     - warning: A role's name can only contain alphanumeric characters, `_`, `-`, and spaces.\n     */\n    var name: String? { get set }\n\n    /**\n     Gets the `ParseRelation` for the `ParseUser` objects that are direct children of this role.\n     These users are granted any privileges that this role has been granted\n     (e.g. read or write access through `ParseACL`s). You can add or remove users from\n     the role through this relation.\n     */\n    var users: ParseRelation<Self>? { get }\n\n    /**\n     Gets the `ParseRelation` for the `ParseRole` objects that are direct children of this role.\n     These roles' users are granted any privileges that this role has been granted\n     (e.g. read or write access through `ParseACL`s). You can add or remove child roles\n     from this role through this relation.\n     */\n    var roles: ParseRelation<Self>? { get }\n\n    /**\n     Create a an empty `ParseRole`.\n     - warning: It's best to use the provided initializers, `init(name: String)`\n     or `init(name: String, acl: ParseACL)` instead of `init()` as they ensure the\n     `ParseRole` is setup properly.\n     */\n    init()\n\n    /**\n     Create a `ParseRole` with a name. The `ParseACL` will still need to be initialized before saving.\n     - parameter name: The name of the Role to create.\n     - throws: An error of type `ParseError` if the name has invalid characters.\n     */\n    init(name: String) throws\n\n    /**\n     Create a `ParseRole` with a name.\n     - parameter name: The name of the Role to create.\n     - parameter acl: The `ParseACL` for this role. Roles must have an ACL.\n     A `ParseRole` is a local representation of a role persisted to the Parse Server.\n     - throws: An error of type `ParseError` if the name has invalid characters.\n     */\n    init(name: String, acl: ParseACL) throws\n}\n\n// MARK: Default Implementations\npublic extension ParseRole {\n    static var className: String {\n        \"_Role\"\n    }\n\n    var users: ParseRelation<Self>? {\n        try? ParseRelation(parent: self, key: \"users\", className: RoleUser.className)\n    }\n\n    var roles: ParseRelation<Self>? {\n        try? ParseRelation(parent: self, key: \"roles\", className: Self.className)\n    }\n\n    init(name: String) throws {\n        try Self.checkName(name)\n        self.init()\n        self.name = name\n    }\n\n    init(name: String, acl: ParseACL) throws {\n        try Self.checkName(name)\n        self.init()\n        self.name = name\n        self.ACL = acl\n    }\n\n    func hash(into hasher: inout Hasher) {\n        let name = self.name ?? self.objectId\n        hasher.combine(name)\n    }\n}\n\n// MARK: Convenience\nextension ParseRole {\n    var endpoint: API.Endpoint {\n        if let objectId = objectId {\n            return .role(objectId: objectId)\n        }\n        return .roles\n    }\n\n    static func checkName(_ name: String) throws {\n        // swiftlint:disable:next line_length\n        let characterset = CharacterSet(charactersIn: \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_- \")\n        if name.rangeOfCharacter(from: characterset.inverted) != nil {\n            throw ParseError(code: .unknownError,\n                             message: \"A role's name can be only contain alphanumeric characters, _, '-, and spaces.\")\n        }\n    }\n}\n\n// MARK: ParseRelation\npublic extension ParseRole {\n\n    /**\n     Query the `ParseRelation` for the `ParseRole`'s that are direct children of this role.\n     These users are granted any privileges that this role has been granted\n     (e.g. read or write access through `ParseACL`s).\n     - throws: An error of type `ParseError`.\n     - returns: An instance of query for easy chaining.\n     */\n    func queryRoles() throws -> Query<Self> {\n        guard let roles = roles else {\n            throw ParseError(code: .unknownError,\n                             message: \"Could not create \\\"roles\\\" relation \")\n        }\n        return try roles.query()\n    }\n\n    /**\n     Query the `ParseRelation` for the `ParseUser`'s that are direct children of this role.\n     These users are granted any privileges that this role has been granted\n     (e.g. read or write access through `ParseACL`s).\n     - throws: An error of type `ParseError`.\n     - returns: An instance of query for easy chaining.\n     */\n    func queryUsers() throws -> Query<RoleUser> {\n        guard let users = users else {\n            throw ParseError(code: .unknownError,\n                             message: \"Could not create \\\"users\\\" relation \")\n        }\n        return try users.query()\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Objects/ParseSession.swift",
    "content": "//\n//  ParseSession.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/17/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n `ParseSession` is a local representation of a session.\n This protocol conforms to `ParseObject` and retains the\n same functionality.\n */\npublic protocol ParseSession: ParseObject {\n    associatedtype SessionUser: ParseUser\n\n    /// The session token for this session.\n    var sessionToken: String { get }\n\n    /// The user the session is for.\n    var user: SessionUser { get }\n\n    /// Whether the session is restricted.\n    /// - warning: This will be deprecated in newer versions of Parse Server.\n    var restricted: Bool? { get }\n\n    /// Information about how the session was created.\n    var createdWith: [String: String] { get }\n\n    /// Refers to the `ParseInstallation` where the\n    /// session logged in from.\n    var installationId: String { get }\n\n    /// Approximate date when this session will automatically\n    /// expire.\n    var expiresAt: Date { get }\n}\n\n// MARK: Default Implementations\npublic extension ParseSession {\n    static var className: String {\n        \"_Session\"\n    }\n}\n\n// MARK: Convenience\nextension ParseSession {\n    var endpoint: API.Endpoint {\n        if let objectId = objectId {\n            return .session(objectId: objectId)\n        }\n        return .sessions\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Objects/ParseUser+async.swift",
    "content": "//\n//  ParseUser+async.swift\n//  ParseUser+async\n//\n//  Created by Corey Baker on 8/6/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n\npublic extension ParseUser {\n\n    // MARK: Async/Await\n    /**\n     Signs up the user *asynchronously*.\n\n     This will also enforce that the username is not already taken.\n\n     - warning: Make sure that password and username are set before calling this method.\n     - parameter username: The username of the user.\n     - parameter password: The password of the user.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the signed in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult static func signup(username: String,\n                                          password: String,\n                                          options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            Self.signup(username: username,\n                        password: password,\n                        options: options,\n                        completion: continuation.resume)\n        }\n    }\n\n    /**\n     Signs up the user *asynchronously*.\n\n     This will also enforce that the username is not already taken.\n\n     - warning: Make sure that password and username are set before calling this method.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the signed in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult func signup(options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.signup(options: options,\n                        completion: continuation.resume)\n        }\n    }\n\n    /**\n     Makes an *asynchronous* request to log in a user with specified credentials.\n     Returns an instance of the successfully logged in `ParseUser`.\n\n     This also caches the user locally so that calls to *current* will use the latest logged in user.\n     - parameter username: The username of the user.\n     - parameter password: The password of the user.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult static func login(username: String,\n                                         password: String,\n                                         options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            Self.login(username: username,\n                       password: password,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n\n    /**\n     Logs in a `ParseUser` *asynchronously* with a session token.\n     Returns an instance of the successfully logged in `ParseUser`.\n     If successful, this saves the session to the keychain, so you can retrieve the currently logged in user\n     using *current*.\n\n     - parameter sessionToken: The sessionToken of the user to login.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the logged in `ParseUser`.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult func become(sessionToken: String,\n                                   options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.become(sessionToken: sessionToken, options: options, completion: continuation.resume)\n        }\n    }\n\n#if !os(Linux) && !os(Android) && !os(Windows)\n    /**\n     Logs in a `ParseUser` *asynchronously* using the session token from the Parse Objective-C SDK Keychain.\n     Returns an instance of the successfully logged in `ParseUser`. The Parse Objective-C SDK Keychain is not\n     modified in any way when calling this method; allowing developers to revert their applications back to the older\n     SDK if desired.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the logged in `ParseUser`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - warning: When initializing the Swift SDK, `migratingFromObjcSDK` should be set to **false**\n     when calling this method.\n     - warning: The latest **PFUser** from the Objective-C SDK should be saved to your\n     Parse Server before calling this method.\n    */\n    @discardableResult static func loginUsingObjCKeychain(options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            Self.loginUsingObjCKeychain(options: options, completion: continuation.resume)\n        }\n    }\n#endif\n\n    /**\n     Logs out the currently logged in user *asynchronously*.\n\n     This will also remove the session from the Keychain, log out of linked services\n     and all future calls to `current` will return `nil`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    static func logout(options: API.Options = []) async throws {\n        let result = try await withCheckedThrowingContinuation { continuation in\n            Self.logout(options: options, completion: continuation.resume)\n        }\n        if case let .failure(error) = result {\n            throw error\n        }\n    }\n\n    /**\n     Requests *asynchronously* a password reset email to be sent to the specified email address\n     associated with the user account. This email allows the user to securely reset their password on the web.\n     - parameter email: The email address associated with the user that forgot their password.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    static func passwordReset(email: String,\n                              options: API.Options = []) async throws {\n        let result = try await withCheckedThrowingContinuation { continuation in\n            Self.passwordReset(email: email, options: options, completion: continuation.resume)\n        }\n        if case let .failure(error) = result {\n            throw error\n        }\n    }\n\n    /**\n     Verifies *asynchronously* whether the specified password associated with the user account is valid.\n        \n     - parameter password: The password to be verified.\n     - parameter usingPost: Set to **true** to use **POST** for sending. Will use **GET**\n     otherwise. Defaults to **false**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - warning: `usingPost == true` requires the\n     [issue](https://github.com/parse-community/parse-server/issues/7784) to be addressed on\n     the Parse Server, othewise you should set `usingPost = false`.\n    */\n    @discardableResult static func verifyPassword(password: String,\n                                                  usingPost: Bool = false,\n                                                  options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            Self.verifyPassword(password: password,\n                                usingPost: usingPost,\n                                options: options, completion: continuation.resume)\n        }\n    }\n\n    /**\n     Requests *asynchronously* a verification email be sent to the specified email address\n     associated with the user account.\n     - parameter email: The email address associated with the user.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    static func verificationEmail(email: String,\n                                  options: API.Options = []) async throws {\n        let result = try await withCheckedThrowingContinuation { continuation in\n            Self.verificationEmail(email: email, options: options, completion: continuation.resume)\n        }\n        if case let .failure(error) = result {\n            throw error\n        }\n    }\n\n    /**\n     Fetches the `ParseUser` *aynchronously* with the current data from the server.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys one level deep. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the fetched `ParseUser`.\n     - throws: An error of type `ParseError`.\n     - important: If an object fetched has the same objectId as current, it will automatically update the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult func fetch(includeKeys: [String]? = nil,\n                                  options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.fetch(includeKeys: includeKeys,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n\n    /**\n     Saves the `ParseUser` *asynchronously*.\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the saved `ParseUser`.\n     - throws: An error of type `ParseError`.\n     - important: If an object saved has the same objectId as current, it will automatically update the current.\n     - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true`\n     and plan to generate all of your `objectId`'s on the client-side then you should leave\n     `ignoringCustomObjectIdConfig = false`. Setting\n     `ParseConfiguration.isRequiringCustomObjectIds = true` and\n     `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s\n     and the server will generate an `objectId` only when the client does not provide one. This can\n     increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using\n     different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the\n     client-side checks are disabled. Developers are responsible for handling such cases.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult func save(ignoringCustomObjectIdConfig: Bool = false,\n                                 options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.save(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                      options: options,\n                      completion: continuation.resume)\n        }\n    }\n\n    /**\n     Creates the `ParseUser` *asynchronously*.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the saved `ParseUser`.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult func create(options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.create(options: options,\n                        completion: continuation.resume)\n        }\n    }\n\n    /**\n     Replaces the `ParseUser` *asynchronously*.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the saved `ParseUser`.\n     - throws: An error of type `ParseError`.\n     - important: If an object replaced has the same objectId as current, it will automatically replace the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult func replace(options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.replace(options: options,\n                         completion: continuation.resume)\n        }\n    }\n\n    /**\n     Updates the `ParseUser` *asynchronously*.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the saved `ParseUser`.\n     - throws: An error of type `ParseError`.\n     - important: If an object updated has the same objectId as current, it will automatically update the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult internal func update(options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.update(options: options,\n                        completion: continuation.resume)\n        }\n    }\n\n    /**\n     Deletes the `ParseUser` *asynchronously*.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n     - important: If an object deleted has the same objectId as current, it will automatically update the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func delete(options: API.Options = []) async throws {\n        let result = try await withCheckedThrowingContinuation { continuation in\n            self.delete(options: options, completion: continuation.resume)\n        }\n        if case let .failure(error) = result {\n            throw error\n        }\n    }\n}\n\npublic extension Sequence where Element: ParseUser {\n    /**\n     Fetches a collection of users *aynchronously* with the current data from the server and sets\n     an error if one occurs.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys one level deep. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns an array of Result enums with the object if a fetch was successful or a\n     `ParseError` if it failed.\n     - throws: An error of type `ParseError`.\n     - important: If an object fetched has the same objectId as current, it will automatically update the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult func fetchAll(includeKeys: [String]? = nil,\n                                     options: API.Options = []) async throws -> [(Result<Self.Element, ParseError>)] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.fetchAll(includeKeys: includeKeys,\n                          options: options,\n                          completion: continuation.resume)\n        }\n    }\n\n    /**\n     Saves a collection of users *asynchronously*.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns an array of Result enums with the object if a save was successful or a\n     `ParseError` if it failed.\n     - throws: An error of type `ParseError`.\n     - important: If an object saved has the same objectId as current, it will automatically update the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true`\n     and plan to generate all of your `objectId`'s on the client-side then you should leave\n     `ignoringCustomObjectIdConfig = false`. Setting\n     `ParseConfiguration.isRequiringCustomObjectIds = true` and\n     `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s\n     and the server will generate an `objectId` only when the client does not provide one. This can\n     increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using\n     different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the\n     client-side checks are disabled. Developers are responsible for handling such cases.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult func saveAll(batchLimit limit: Int? = nil,\n                                    transaction: Bool = configuration.isUsingTransactions,\n                                    ignoringCustomObjectIdConfig: Bool = false,\n                                    options: API.Options = []) async throws -> [(Result<Self.Element, ParseError>)] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.saveAll(batchLimit: limit,\n                         transaction: transaction,\n                         ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                         options: options,\n                         completion: continuation.resume)\n        }\n    }\n\n    /**\n     Creates a collection of users *asynchronously*.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns an array of Result enums with the object if a save was successful or a\n     `ParseError` if it failed.\n     - throws: An error of type `ParseError`.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult func createAll(batchLimit limit: Int? = nil,\n                                      transaction: Bool = configuration.isUsingTransactions,\n                                      options: API.Options = []) async throws -> [(Result<Self.Element, ParseError>)] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.createAll(batchLimit: limit,\n                           transaction: transaction,\n                           options: options,\n                           completion: continuation.resume)\n        }\n    }\n\n    /**\n     Replaces a collection of users *asynchronously*.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns an array of Result enums with the object if a save was successful or a\n     `ParseError` if it failed.\n     - throws: An error of type `ParseError`.\n     - important: If an object replaced has the same objectId as current, it will automatically replace the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult func replaceAll(batchLimit limit: Int? = nil,\n                                       transaction: Bool = configuration.isUsingTransactions,\n                                       options: API.Options = []) async throws -> [(Result<Self.Element, ParseError>)] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.replaceAll(batchLimit: limit,\n                            transaction: transaction,\n                            options: options,\n                            completion: continuation.resume)\n        }\n    }\n\n    /**\n     Updates a collection of users *asynchronously*.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns an array of Result enums with the object if a save was successful or a\n     `ParseError` if it failed.\n     - throws: An error of type `ParseError`.\n     - important: If an object updated has the same objectId as current, it will automatically update the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    internal func updateAll(batchLimit limit: Int? = nil,\n                            transaction: Bool = configuration.isUsingTransactions,\n                            options: API.Options = []) async throws -> [(Result<Self.Element, ParseError>)] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.updateAll(batchLimit: limit,\n                           transaction: transaction,\n                           options: options,\n                           completion: continuation.resume)\n        }\n    }\n\n    /**\n     Deletes a collection of users *asynchronously*.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Each element in the array is `nil` if the delete successful or a `ParseError` if it failed.\n     - throws: An error of type `ParseError`.\n     - important: If an object deleted has the same objectId as current, it will automatically update the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult func deleteAll(batchLimit limit: Int? = nil,\n                                      transaction: Bool = configuration.isUsingTransactions,\n                                      options: API.Options = []) async throws -> [(Result<Void, ParseError>)] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.deleteAll(batchLimit: limit,\n                           transaction: transaction,\n                           options: options,\n                           completion: continuation.resume)\n        }\n    }\n}\n\n// MARK: Helper Methods (Internal)\ninternal extension ParseUser {\n\n    func command(method: Method,\n                 ignoringCustomObjectIdConfig: Bool = false,\n                 options: API.Options,\n                 callbackQueue: DispatchQueue) async throws -> Self {\n        let (savedChildObjects, savedChildFiles) = try await self.ensureDeepSave(options: options)\n        do {\n            let command: API.Command<Self, Self>!\n            switch method {\n            case .save:\n                command = try self.saveCommand(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig)\n            case .create:\n                command = self.createCommand()\n            case .replace:\n                command = try self.replaceCommand()\n            case .update:\n                command = try self.updateCommand()\n            }\n            let saved = try await command\n                .executeAsync(options: options,\n                              callbackQueue: callbackQueue,\n                              childObjects: savedChildObjects,\n                              childFiles: savedChildFiles)\n            try? Self.updateKeychainIfNeeded([saved])\n            return saved\n        } catch {\n            let defaultError = ParseError(code: .unknownError,\n                                          message: error.localizedDescription)\n            let parseError = error as? ParseError ?? defaultError\n            throw parseError\n        }\n    }\n}\n\n// MARK: Batch Support\ninternal extension Sequence where Element: ParseUser {\n    func batchCommand(method: Method,\n                      batchLimit limit: Int?,\n                      transaction: Bool,\n                      ignoringCustomObjectIdConfig: Bool = false,\n                      options: API.Options,\n                      callbackQueue: DispatchQueue) async throws -> [(Result<Element, ParseError>)] {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        var childObjects = [String: PointerType]()\n        var childFiles = [UUID: ParseFile]()\n        var commands = [API.Command<Self.Element, Self.Element>]()\n        let objects = map { $0 }\n        for object in objects {\n            let (savedChildObjects, savedChildFiles) = try await object\n                .ensureDeepSave(options: options,\n                                isShouldReturnIfChildObjectsFound: transaction)\n            try savedChildObjects.forEach {(key, value) in\n                guard childObjects[key] == nil else {\n                    throw ParseError(code: .unknownError, message: \"circular dependency\")\n                }\n                childObjects[key] = value\n            }\n            try savedChildFiles.forEach {(key, value) in\n                guard childFiles[key] == nil else {\n                    throw ParseError(code: .unknownError, message: \"circular dependency\")\n                }\n                childFiles[key] = value\n            }\n            do {\n                switch method {\n                case .save:\n                    commands.append(\n                        try object.saveCommand(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig)\n                    )\n                case .create:\n                    commands.append(object.createCommand())\n                case .replace:\n                    commands.append(try object.replaceCommand())\n                case .update:\n                    commands.append(try object.updateCommand())\n                }\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                throw parseError\n            }\n        }\n\n        do {\n            var returnBatch = [(Result<Self.Element, ParseError>)]()\n            let batchLimit = limit != nil ? limit! : ParseConstants.batchLimit\n            try canSendTransactions(transaction, objectCount: commands.count, batchLimit: batchLimit)\n            let batches = BatchUtils.splitArray(commands, valuesPerSegment: batchLimit)\n            for batch in batches {\n                let saved = try await API.Command<Self.Element, Self.Element>\n                        .batch(commands: batch, transaction: transaction)\n                        .executeAsync(options: options,\n                                      batching: true,\n                                      callbackQueue: callbackQueue,\n                                      childObjects: childObjects,\n                                      childFiles: childFiles)\n                returnBatch.append(contentsOf: saved)\n            }\n            try? Self.Element.updateKeychainIfNeeded(returnBatch.compactMap {try? $0.get()})\n            return returnBatch\n        } catch {\n            let defaultError = ParseError(code: .unknownError,\n                                          message: error.localizedDescription)\n            let parseError = error as? ParseError ?? defaultError\n            throw parseError\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Objects/ParseUser+combine.swift",
    "content": "//\n//  ParseUser+publisher.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/28/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\npublic extension ParseUser {\n\n    // MARK: Combine\n    /**\n     Signs up the user *asynchronously* and publishes value.\n\n     This will also enforce that the username is not already taken.\n\n     - warning: Make sure that password and username are set before calling this method.\n     - parameter username: The username of the user.\n     - parameter password: The password of the user.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    static func signupPublisher(username: String,\n                                password: String,\n                                options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            Self.signup(username: username,\n                        password: password,\n                        options: options,\n                        completion: promise)\n        }\n    }\n\n    /**\n     Signs up the user *asynchronously* and publishes value.\n\n     This will also enforce that the username is not already taken.\n\n     - warning: Make sure that password and username are set before calling this method.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func signupPublisher(options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.signup(options: options,\n                        completion: promise)\n        }\n    }\n\n    /**\n     Makes an *asynchronous* request to log in a user with specified credentials.\n     Publishes an instance of the successfully logged in `ParseUser`.\n\n     This also caches the user locally so that calls to *current* will use the latest logged in user.\n     - parameter username: The username of the user.\n     - parameter password: The password of the user.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    static func loginPublisher(username: String,\n                               password: String,\n                               options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            Self.login(username: username,\n                       password: password,\n                       options: options,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Logs in a `ParseUser` *asynchronously* with a session token.\n     Publishes an instance of the successfully logged in `ParseUser`.\n     If successful, this saves the session to the keychain, so you can retrieve the currently logged in user\n     using *current*.\n\n     - parameter sessionToken: The sessionToken of the user to login.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func becomePublisher(sessionToken: String, options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.become(sessionToken: sessionToken, options: options, completion: promise)\n        }\n    }\n\n#if !os(Linux) && !os(Android) && !os(Windows)\n    /**\n     Logs in a `ParseUser` *asynchronously* using the session token from the Parse Objective-C SDK Keychain.\n     Publishes an instance of the successfully logged in `ParseUser`. The Parse Objective-C SDK Keychain is not\n     modified in any way when calling this method; allowing developers to revert their applications back to the older\n     SDK if desired.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - warning: When initializing the Swift SDK, `migratingFromObjcSDK` should be set to **false**\n     when calling this method.\n     - warning: The latest **PFUser** from the Objective-C SDK should be saved to your\n     Parse Server before calling this method.\n    */\n    static func loginUsingObjCKeychainPublisher(options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            Self.loginUsingObjCKeychain(options: options, completion: promise)\n        }\n    }\n#endif\n\n    /**\n     Logs out the currently logged in user *asynchronously*. Publishes when complete.\n\n     This will also remove the session from the Keychain, log out of linked services\n     and all future calls to `current` will return `nil`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    static func logoutPublisher(options: API.Options = []) -> Future<Void, ParseError> {\n        Future { promise in\n            Self.logout(options: options, completion: promise)\n        }\n    }\n\n    /**\n     Requests *asynchronously* a password reset email to be sent to the specified email address\n     associated with the user account. This email allows the user to securely reset their password on the web.\n     Publishes when complete.\n     - parameter email: The email address associated with the user that forgot their password.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    static func passwordResetPublisher(email: String,\n                                       options: API.Options = []) -> Future<Void, ParseError> {\n        Future { promise in\n            Self.passwordReset(email: email, options: options, completion: promise)\n        }\n    }\n\n    /**\n     Verifies *asynchronously* whether the specified password associated with the user account is valid.\n     Publishes when complete.\n     - parameter password: The password to be verified.\n     - parameter usingPost: Set to **true** to use **POST** for sending. Will use **GET**\n     otherwise. Defaults to **false**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - warning: `usingPost == true` requires the\n     [issue](https://github.com/parse-community/parse-server/issues/7784) to be addressed on\n     the Parse Server, othewise you should set `usingPost = false`.\n    */\n    static func verifyPasswordPublisher(password: String,\n                                        usingPost: Bool = false,\n                                        options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            Self.verifyPassword(password: password,\n                                usingPost: usingPost,\n                                options: options,\n                                completion: promise)\n        }\n    }\n\n    /**\n     Requests *asynchronously* a verification email be sent to the specified email address\n     associated with the user account. Publishes when complete.\n     - parameter email: The email address associated with the user.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    static func verificationEmailPublisher(email: String,\n                                           options: API.Options = []) -> Future<Void, ParseError> {\n        Future { promise in\n            Self.verificationEmail(email: email, options: options, completion: promise)\n        }\n    }\n\n    /**\n     Fetches the `ParseUser` *aynchronously* with the current data from the server.\n     Publishes when complete.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys one level deep. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - important: If an object fetched has the same objectId as current, it will automatically update the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func fetchPublisher(includeKeys: [String]? = nil,\n                        options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.fetch(includeKeys: includeKeys,\n                       options: options,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Saves the `ParseUser` *asynchronously* and publishes when complete.\n\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - important: If an object saved has the same objectId as current, it will automatically update the current.\n     - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true`\n     and plan to generate all of your `objectId`'s on the client-side then you should leave\n     `ignoringCustomObjectIdConfig = false`. Setting\n     `ParseConfiguration.isRequiringCustomObjectIds = true` and\n     `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s\n     and the server will generate an `objectId` only when the client does not provide one. This can\n     increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using\n     different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the\n     client-side checks are disabled. Developers are responsible for handling such cases.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func savePublisher(options: API.Options = [],\n                       ignoringCustomObjectIdConfig: Bool = false) -> Future<Self, ParseError> {\n        Future { promise in\n            self.save(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                      options: options,\n                      completion: promise)\n        }\n    }\n\n    /**\n     Creates the `ParseUser` *asynchronously* and publishes when complete.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func createPublisher(options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.create(options: options,\n                        completion: promise)\n        }\n    }\n\n    /**\n     Replaces the `ParseUser` *asynchronously* and publishes when complete.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - important: If an object replaced has the same objectId as current, it will automatically replace the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func replacePublisher(options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.replace(options: options,\n                         completion: promise)\n        }\n    }\n\n    /**\n     Updates the `ParseUser` *asynchronously* and publishes when complete.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - important: If an object updated has the same objectId as current, it will automatically update the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    internal func updatePublisher(options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.update(options: options,\n                        completion: promise)\n        }\n    }\n\n    /**\n     Deletes the `ParseUser` *asynchronously* and publishes when complete.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - important: If an object deleted has the same objectId as current, it will automatically update the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func deletePublisher(options: API.Options = []) -> Future<Void, ParseError> {\n        Future { promise in\n            self.delete(options: options, completion: promise)\n        }\n    }\n}\n\npublic extension Sequence where Element: ParseUser {\n    /**\n     Fetches a collection of users *aynchronously* with the current data from the server and sets\n     an error if one occurs. Publishes when complete.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys one level deep. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces an an array of Result enums with the object if a fetch was\n     successful or a `ParseError` if it failed.\n     - important: If an object fetched has the same objectId as current, it will automatically update the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func fetchAllPublisher(includeKeys: [String]? = nil,\n                           options: API.Options = []) -> Future<[(Result<Self.Element, ParseError>)], ParseError> {\n        Future { promise in\n            self.fetchAll(includeKeys: includeKeys,\n                          options: options,\n                          completion: promise)\n        }\n    }\n\n    /**\n     Saves a collection of users *asynchronously* and publishes when complete.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces an an array of Result enums with the object if a save was\n     successful or a `ParseError` if it failed.\n     - important: If an object saved has the same objectId as current, it will automatically update the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true`\n     and plan to generate all of your `objectId`'s on the client-side then you should leave\n     `ignoringCustomObjectIdConfig = false`. Setting\n     `ParseConfiguration.isRequiringCustomObjectIds = true` and\n     `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s\n     and the server will generate an `objectId` only when the client does not provide one. This can\n     increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using\n     different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the\n     client-side checks are disabled. Developers are responsible for handling such cases.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func saveAllPublisher(batchLimit limit: Int? = nil,\n                          transaction: Bool = configuration.isUsingTransactions,\n                          ignoringCustomObjectIdConfig: Bool = false,\n                          options: API.Options = []) -> Future<[(Result<Self.Element, ParseError>)], ParseError> {\n        Future { promise in\n            self.saveAll(batchLimit: limit,\n                         transaction: transaction,\n                         ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                         options: options,\n                         completion: promise)\n        }\n    }\n\n    /**\n     Creates a collection of users *asynchronously* and publishes when complete.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces an an array of Result enums with the object if a save was\n     successful or a `ParseError` if it failed.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func createAllPublisher(batchLimit limit: Int? = nil,\n                            transaction: Bool = configuration.isUsingTransactions,\n                            options: API.Options = []) -> Future<[(Result<Self.Element, ParseError>)], ParseError> {\n        Future { promise in\n            self.createAll(batchLimit: limit,\n                           transaction: transaction,\n                           options: options,\n                           completion: promise)\n        }\n    }\n\n    /**\n     Replaces a collection of users *asynchronously* and publishes when complete.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces an an array of Result enums with the object if a save was\n     successful or a `ParseError` if it failed.\n     - important: If an object replaced has the same objectId as current, it will automatically replace the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func replaceAllPublisher(batchLimit limit: Int? = nil,\n                             transaction: Bool = configuration.isUsingTransactions,\n                             options: API.Options = []) -> Future<[(Result<Self.Element, ParseError>)],\n                                                                    ParseError> {\n        Future { promise in\n            self.replaceAll(batchLimit: limit,\n                           transaction: transaction,\n                           options: options,\n                           completion: promise)\n        }\n    }\n\n    /**\n     Updates a collection of users *asynchronously* and publishes when complete.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces an an array of Result enums with the object if a save was\n     successful or a `ParseError` if it failed.\n     - important: If an object updated has the same objectId as current, it will automatically update the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    internal func updateAllPublisher(batchLimit limit: Int? = nil,\n                                     transaction: Bool = configuration.isUsingTransactions,\n                                     options: API.Options = []) -> Future<[(Result<Self.Element, ParseError>)],\n                                                                            ParseError> {\n        Future { promise in\n            self.updateAll(batchLimit: limit,\n                           transaction: transaction,\n                           options: options,\n                           completion: promise)\n        }\n    }\n\n    /**\n     Deletes a collection of users *asynchronously* and publishes when complete.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces an an array of Result enums with `nil` if a delete was\n     successful or a `ParseError` if it failed.\n     - important: If an object deleted has the same objectId as current, it will automatically update the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func deleteAllPublisher(batchLimit limit: Int? = nil,\n                            transaction: Bool = configuration.isUsingTransactions,\n                            options: API.Options = []) -> Future<[(Result<Void, ParseError>)], ParseError> {\n        Future { promise in\n            self.deleteAll(batchLimit: limit,\n                           transaction: transaction,\n                           options: options,\n                           completion: promise)\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Objects/ParseUser.swift",
    "content": "import Foundation\n\n/**\n Objects that conform to the `ParseUser` protocol have a local representation of a user persisted to the\n Keychain and Parse Server. This protocol inherits from the `ParseObject` protocol, and retains the same\n functionality of a `ParseObject`, but also extends it with various user specific methods, like\n authentication, signing up, and validation uniqueness.\n*/\npublic protocol ParseUser: ParseObject {\n    /**\n    The username for the `ParseUser`.\n    */\n    var username: String? { get set }\n\n    /**\n    The email for the `ParseUser`.\n    */\n    var email: String? { get set }\n\n    /**\n    Determines if the email is verified for the `ParseUser`.\n     - note: This value can only be changed on the Parse Server.\n    */\n    var emailVerified: Bool? { get }\n\n    /**\n     The password for the `ParseUser`.\n\n     This will not be filled in from the server with the password.\n     It is only meant to be set.\n    */\n    var password: String? { get set }\n\n    /**\n     The authentication data for the `ParseUser`. Used by `ParseAnonymous`\n     or any authentication type that conforms to `ParseAuthentication`.\n    */\n    var authData: [String: [String: String]?]? { get set }\n}\n\n// MARK: Default Implementations\npublic extension ParseUser {\n    static var className: String {\n        \"_User\"\n    }\n\n    func mergeParse(with object: Self) throws -> Self {\n        guard hasSameObjectId(as: object) else {\n            throw ParseError(code: .unknownError,\n                             message: \"objectId's of objects do not match\")\n        }\n        var updatedUser = self\n        if shouldRestoreKey(\\.ACL,\n                             original: object) {\n            updatedUser.ACL = object.ACL\n        }\n        if shouldRestoreKey(\\.username,\n                             original: object) {\n            updatedUser.username = object.username\n        }\n        if shouldRestoreKey(\\.email,\n                             original: object) {\n            updatedUser.email = object.email\n        }\n        if shouldRestoreKey(\\.authData,\n                             original: object) {\n            updatedUser.authData = object.authData\n        }\n        return updatedUser\n    }\n\n    func merge(with object: Self) throws -> Self {\n        do {\n            return try mergeAutomatically(object)\n        } catch {\n            return try mergeParse(with: object)\n        }\n    }\n}\n\n// MARK: Convenience\nextension ParseUser {\n    var endpoint: API.Endpoint {\n        if let objectId = objectId {\n            return .user(objectId: objectId)\n        }\n\n        return .users\n    }\n\n    func endpoint(_ method: API.Method) -> API.Endpoint {\n        if !Parse.configuration.isRequiringCustomObjectIds || method != .POST {\n            return endpoint\n        } else {\n            return .users\n        }\n    }\n\n    static func deleteCurrentKeychain() {\n        deleteCurrentContainerFromKeychain()\n        BaseParseInstallation.deleteCurrentContainerFromKeychain()\n        ParseACL.deleteDefaultFromKeychain()\n        BaseConfig.deleteCurrentContainerFromKeychain()\n        clearCache()\n    }\n}\n\n// MARK: CurrentUserContainer\nstruct CurrentUserContainer<T: ParseUser>: Codable, Hashable {\n    var currentUser: T?\n    var sessionToken: String?\n}\n\n// MARK: Current User Support\npublic extension ParseUser {\n    internal static var currentContainer: CurrentUserContainer<Self>? {\n        get {\n            guard let currentUserInMemory: CurrentUserContainer<Self>\n                = try? ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentUser) else {\n                #if !os(Linux) && !os(Android) && !os(Windows)\n                return try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser)\n                #else\n                return nil\n                #endif\n            }\n            return currentUserInMemory\n        }\n        set { try? ParseStorage.shared.set(newValue, for: ParseStorage.Keys.currentUser) }\n    }\n\n    internal static func saveCurrentContainerToKeychain() {\n        Self.currentContainer?.currentUser?.originalData = nil\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try? KeychainStore.shared.set(currentContainer, for: ParseStorage.Keys.currentUser)\n        #endif\n    }\n\n    internal static func deleteCurrentContainerFromKeychain() {\n        try? ParseStorage.shared.delete(valueFor: ParseStorage.Keys.currentUser)\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        URLSession.liveQuery.closeAll()\n        try? KeychainStore.shared.delete(valueFor: ParseStorage.Keys.currentUser)\n        #endif\n        Self.currentContainer = nil\n    }\n\n    /**\n     Gets the currently logged in user from the Keychain and returns an instance of it.\n\n     - returns: Returns a `ParseUser` that is the currently logged in user. If there is none, returns `nil`.\n     - warning: Only use `current` users on the main thread as as modifications to `current` have to be unique.\n    */\n    internal(set) static var current: Self? {\n        get { Self.currentContainer?.currentUser }\n        set {\n            Self.currentContainer?.currentUser = newValue\n        }\n    }\n\n    /**\n     The session token for the `ParseUser`.\n\n     This is set by the server upon successful authentication.\n    */\n    var sessionToken: String? {\n        Self.currentContainer?.sessionToken\n    }\n}\n\n// MARK: SignupLoginBody\nstruct SignupLoginBody: ParseEncodable {\n    var username: String?\n    var password: String?\n    var authData: [String: [String: String]?]?\n\n    init(username: String, password: String) {\n        self.username = username\n        self.password = password\n    }\n\n    init(authData: [String: [String: String]?]) {\n        self.authData = authData\n    }\n}\n\n// MARK: EmailBody\nstruct EmailBody: ParseEncodable {\n    let email: String\n}\n\n// MARK: Logging In\nextension ParseUser {\n\n    /**\n     Makes a *synchronous* request to login a user with specified credentials.\n\n     Returns an instance of the successfully logged in `ParseUser`.\n     This also caches the user locally so that calls to *current* will use the latest logged in user.\n\n     - parameter username: The username of the user.\n     - parameter password: The password of the user.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n     - returns: An instance of the logged in `ParseUser`.\n     If login failed due to either an incorrect password or incorrect username, it throws a `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public static func login(username: String,\n                             password: String, options: API.Options = []) throws -> Self {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        return try loginCommand(username: username, password: password).execute(options: options)\n    }\n\n    /**\n     Makes an *asynchronous* request to log in a user with specified credentials.\n     Returns an instance of the successfully logged in `ParseUser`.\n\n     This also caches the user locally so that calls to *current* will use the latest logged in user.\n     - parameter username: The username of the user.\n     - parameter password: The password of the user.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public static func login(\n        username: String,\n        password: String,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<Self, ParseError>) -> Void\n    ) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        loginCommand(username: username, password: password)\n            .executeAsync(options: options,\n                          callbackQueue: callbackQueue) { result in\n                completion(result)\n            }\n    }\n\n    internal static func loginCommand(username: String,\n                                      password: String) -> API.Command<SignupLoginBody, Self> {\n\n        let body = SignupLoginBody(username: username, password: password)\n        return API.Command<SignupLoginBody, Self>(method: .POST,\n                                                  path: .login,\n                                                  body: body) { (data) -> Self in\n            let sessionToken = try ParseCoding.jsonDecoder().decode(LoginSignupResponse.self, from: data).sessionToken\n            let user = try ParseCoding.jsonDecoder().decode(Self.self, from: data)\n\n            Self.currentContainer = .init(\n                currentUser: user,\n                sessionToken: sessionToken\n            )\n            Self.saveCurrentContainerToKeychain()\n            return user\n        }\n    }\n\n    /**\n     Logs in a `ParseUser` *synchronously* with a session token. On success, this saves the logged in\n     `ParseUser`with this session to the keychain, so you can retrieve the currently logged in user using\n     *current*.\n\n     - parameter sessionToken: The sessionToken of the user to login.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An Error of `ParseError` type.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func become(sessionToken: String, options: API.Options = []) throws -> Self {\n        var newUser = self\n        newUser.objectId = \"me\"\n        var options = options\n        options.insert(.sessionToken(sessionToken))\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        return try newUser.meCommand(sessionToken: sessionToken)\n            .execute(options: options)\n    }\n\n    /**\n     Logs in a `ParseUser` *asynchronously* with a session token. On success, this saves the logged in\n     `ParseUser`with this session to the keychain, so you can retrieve the currently logged in user using\n     *current*.\n\n     - parameter sessionToken: The sessionToken of the user to login.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func become(sessionToken: String,\n                       options: API.Options = [],\n                       callbackQueue: DispatchQueue = .main,\n                       completion: @escaping (Result<Self, ParseError>) -> Void) {\n        Self.become(sessionToken: sessionToken,\n                    options: options,\n                    callbackQueue: callbackQueue,\n                    completion: completion)\n    }\n\n    /**\n     Logs in a `ParseUser` *asynchronously* with a session token. On success, this saves the logged in\n     `ParseUser`with this session to the keychain, so you can retrieve the currently logged in user using\n     *current*.\n\n     - parameter sessionToken: The sessionToken of the user to login.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public static func become(sessionToken: String,\n                              options: API.Options = [],\n                              callbackQueue: DispatchQueue = .main,\n                              completion: @escaping (Result<Self, ParseError>) -> Void) {\n        var newUser = Self()\n        newUser.objectId = \"me\"\n        var options = options\n        options.insert(.sessionToken(sessionToken))\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        do {\n            try newUser.meCommand(sessionToken: sessionToken)\n                .executeAsync(options: options,\n                              callbackQueue: callbackQueue) { result in\n                if case .success(let foundResult) = result {\n                    completion(.success(foundResult))\n                } else {\n                    completion(result)\n                }\n            }\n        } catch let error as ParseError {\n            callbackQueue.async {\n                completion(.failure(error))\n            }\n        } catch {\n            callbackQueue.async {\n                completion(.failure(ParseError(code: .unknownError, message: error.localizedDescription)))\n            }\n        }\n    }\n\n#if !os(Linux) && !os(Android) && !os(Windows)\n    /**\n     Logs in a `ParseUser` *asynchronously* using the session token from the Parse Objective-C SDK Keychain.\n     Returns an instance of the successfully logged in `ParseUser`. The Parse Objective-C SDK Keychain is not\n     modified in any way when calling this method; allowing developers to revert their applications back to the older\n     SDK if desired.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - warning: When initializing the Swift SDK, `migratingFromObjcSDK` should be set to **false**\n     when calling this method.\n     - warning: The latest **PFUser** from the Objective-C SDK should be saved to your\n     Parse Server before calling this method.\n    */\n    public static func loginUsingObjCKeychain(options: API.Options = [],\n                                              callbackQueue: DispatchQueue = .main,\n                                              completion: @escaping (Result<Self, ParseError>) -> Void) {\n\n        let objcParseKeychain = KeychainStore.objectiveC\n\n        guard let objcParseUser: [String: String] = objcParseKeychain?.objectObjectiveC(forKey: \"currentUser\"),\n            let sessionToken: String = objcParseUser[\"sessionToken\"] ??\n                objcParseUser[\"session_token\"] else {\n            let error = ParseError(code: .unknownError,\n                                   message: \"Could not find a session token in the Parse Objective-C SDK Keychain.\")\n            callbackQueue.async {\n                completion(.failure(error))\n            }\n            return\n        }\n\n        guard let currentUser = Self.current else {\n            become(sessionToken: sessionToken,\n                   options: options,\n                   callbackQueue: callbackQueue,\n                   completion: completion)\n            return\n        }\n\n        guard currentUser.sessionToken == sessionToken else {\n            let error = ParseError(code: .unknownError,\n                                   message: \"\"\"\n                                   Currently logged in as a ParseUser who has a different\n                                   session token than the Objective-C Parse SDK session token. Please log out before\n                                   calling this method.\n            \"\"\")\n            callbackQueue.async {\n                completion(.failure(error))\n            }\n            return\n        }\n        callbackQueue.async {\n            completion(.success(currentUser))\n        }\n    }\n#endif\n\n    internal func meCommand(sessionToken: String) throws -> API.Command<Self, Self> {\n\n        return API.Command(method: .GET,\n                           path: endpoint) { (data) -> Self in\n            let user = try ParseCoding.jsonDecoder().decode(Self.self, from: data)\n\n            if let current = Self.current {\n                if !current.hasSameObjectId(as: user) && self.anonymous.isLinked {\n                    Self.deleteCurrentContainerFromKeychain()\n                }\n            }\n\n            Self.currentContainer = .init(\n                currentUser: user,\n                sessionToken: sessionToken\n            )\n            Self.saveCurrentContainerToKeychain()\n            return user\n        }\n    }\n}\n\n// MARK: Logging Out\nextension ParseUser {\n\n    /**\n    Logs out the currently logged in user in Keychain *synchronously*.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of `ParseError` type.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public static func logout(options: API.Options = []) throws {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        let error = try? logoutCommand().execute(options: options)\n        // Always let user logout locally, no matter the error.\n        deleteCurrentKeychain()\n        // Wait to throw error\n        if let parseError = error {\n            throw parseError\n        }\n    }\n\n    /**\n     Logs out the currently logged in user *asynchronously*.\n\n     This will also remove the session from the Keychain, log out of linked services\n     and all future calls to `current` will return `nil`. This is preferable to using `logout`,\n     unless your code is already running from a background thread.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: A block that will be called when logging out completes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public static func logout(options: API.Options = [], callbackQueue: DispatchQueue = .main,\n                              completion: @escaping (Result<Void, ParseError>) -> Void) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        logoutCommand().executeAsync(options: options,\n                                     callbackQueue: callbackQueue) { result in\n            // Always let user logout locally, no matter the error.\n            deleteCurrentKeychain()\n\n            switch result {\n\n            case .success(let error):\n                if let error = error {\n                    completion(.failure(error))\n                } else {\n                    completion(.success(()))\n                }\n            case .failure(let error):\n                completion(.failure(error))\n            }\n        }\n    }\n\n    internal static func logoutCommand() -> API.Command<NoBody, ParseError?> {\n        return API.Command(method: .POST, path: .logout) { (data) -> ParseError? in\n            do {\n                let parseError = try ParseCoding.jsonDecoder().decode(ParseError.self, from: data)\n                return parseError\n            } catch {\n                return nil\n            }\n       }\n    }\n}\n\n// MARK: Password Reset\nextension ParseUser {\n\n    /**\n     Requests *synchronously* a password reset email to be sent to the specified email address\n     associated with the user account. This email allows the user to securely reset their password on the web.\n        - parameter email: The email address associated with the user that forgot their password.\n        - parameter options: A set of header options sent to the server. Defaults to an empty set.\n        - throws: An error of `ParseError` type.\n        - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n        desires a different policy, it should be inserted in `options`.\n    */\n    public static func passwordReset(email: String, options: API.Options = []) throws {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        if let error = try passwordResetCommand(email: email).execute(options: options) {\n            throw error\n        }\n    }\n\n    /**\n     Requests *asynchronously* a password reset email to be sent to the specified email address\n     associated with the user account. This email allows the user to securely reset their password on the web.\n        - parameter email: The email address associated with the user that forgot their password.\n        - parameter options: A set of header options sent to the server. Defaults to an empty set.\n        - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n        - parameter completion: A block that will be called when the password reset completes or fails.\n        - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n        desires a different policy, it should be inserted in `options`.\n    */\n    public static func passwordReset(email: String, options: API.Options = [],\n                                     callbackQueue: DispatchQueue = .main,\n                                     completion: @escaping (Result<Void, ParseError>) -> Void) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        passwordResetCommand(email: email).executeAsync(options: options,\n                                                        callbackQueue: callbackQueue) { result in\n            switch result {\n\n            case .success(let error):\n                if let error = error {\n                    completion(.failure(error))\n                } else {\n                    completion(.success(()))\n                }\n            case .failure(let error):\n                completion(.failure(error))\n            }\n        }\n    }\n\n    internal static func passwordResetCommand(email: String) -> API.Command<EmailBody, ParseError?> {\n        let emailBody = EmailBody(email: email)\n        return API.Command(method: .POST,\n                           path: .passwordReset, body: emailBody) { (data) -> ParseError? in\n            try? ParseCoding.jsonDecoder().decode(ParseError.self, from: data)\n        }\n    }\n}\n\n// MARK: Verify Password\nextension ParseUser {\n\n    /**\n     Verifies *asynchronously* whether the specified password associated with the user account is valid.\n        - parameter password: The password to be verified.\n        - parameter usingPost: Set to **true** to use **POST** for sending. Will use **GET**\n        otherwise. Defaults to **false**.\n        - parameter options: A set of header options sent to the server. Defaults to an empty set.\n        - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n        - parameter completion: A block that will be called when the verification request completes or fails.\n        - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n        desires a different policy, it should be inserted in `options`.\n        - warning: `usingPost == true` requires the\n        [issue](https://github.com/parse-community/parse-server/issues/7784) to be addressed on\n        the Parse Server, othewise you should set `usingPost = false`.\n    */\n    public static func verifyPassword(password: String,\n                                      usingPost: Bool = false,\n                                      options: API.Options = [],\n                                      callbackQueue: DispatchQueue = .main,\n                                      completion: @escaping (Result<Self, ParseError>) -> Void) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        let username = BaseParseUser.current?.username ?? \"\"\n        let method: API.Method = usingPost ? .POST : .GET\n        verifyPasswordCommand(username: username,\n                              password: password,\n                              method: method)\n            .executeAsync(options: options,\n                          callbackQueue: callbackQueue,\n                          completion: completion)\n    }\n\n    internal static func verifyPasswordCommand(username: String,\n                                               password: String,\n                                               method: API.Method) -> API.Command<SignupLoginBody, Self> {\n        let loginBody: SignupLoginBody?\n        let params: [String: String]?\n\n        switch method {\n        case .GET:\n            loginBody = nil\n            params = [\"username\": username, \"password\": password ]\n        default:\n            loginBody = SignupLoginBody(username: username, password: password)\n            params = nil\n        }\n\n        return API.Command(method: method,\n                           path: .verifyPassword,\n                           params: params,\n                           body: loginBody) { (data) -> Self in\n            var sessionToken = BaseParseUser.current?.sessionToken ?? \"\"\n            if let decodedSessionToken = try? ParseCoding.jsonDecoder()\n                .decode(LoginSignupResponse.self, from: data).sessionToken {\n                sessionToken = decodedSessionToken\n            }\n            let user = try ParseCoding.jsonDecoder().decode(Self.self, from: data)\n            Self.currentContainer = .init(currentUser: user,\n                                          sessionToken: sessionToken)\n            Self.saveCurrentContainerToKeychain()\n            return user\n        }\n    }\n}\n\n// MARK: Verification Email Request\nextension ParseUser {\n\n    /**\n     Requests *synchronously* a verification email be sent to the specified email address\n     associated with the user account.\n        - parameter email: The email address associated with the user.\n        - parameter options: A set of header options sent to the server. Defaults to an empty set.\n        - throws: An error of `ParseError` type.\n        - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n        desires a different policy, it should be inserted in `options`.\n    */\n    public static func verificationEmail(email: String,\n                                         options: API.Options = []) throws {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        if let error = try verificationEmailCommand(email: email).execute(options: options) {\n            throw error\n        }\n    }\n\n    /**\n     Requests *asynchronously* a verification email be sent to the specified email address\n     associated with the user account.\n        - parameter email: The email address associated with the user.\n        - parameter options: A set of header options sent to the server. Defaults to an empty set.\n        - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n        - parameter completion: A block that will be called when the verification request completes or fails.\n        - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n        desires a different policy, it should be inserted in `options`.\n    */\n    public static func verificationEmail(email: String,\n                                         options: API.Options = [],\n                                         callbackQueue: DispatchQueue = .main,\n                                         completion: @escaping (Result<Void, ParseError>) -> Void) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        verificationEmailCommand(email: email)\n            .executeAsync(options: options, callbackQueue: callbackQueue) { result in\n                switch result {\n\n                case .success(let error):\n                    if let error = error {\n                        completion(.failure(error))\n                    } else {\n                        completion(.success(()))\n                    }\n                case .failure(let error):\n                    completion(.failure(error))\n                }\n        }\n    }\n\n    internal static func verificationEmailCommand(email: String) -> API.Command<EmailBody, ParseError?> {\n        let emailBody = EmailBody(email: email)\n        return API.Command(method: .POST,\n                           path: .verificationEmail,\n                           body: emailBody) { (data) -> ParseError? in\n            try? ParseCoding.jsonDecoder().decode(ParseError.self, from: data)\n        }\n    }\n}\n\n// MARK: Signing Up\nextension ParseUser {\n    /**\n     Signs up the user *synchronously*.\n\n     This will also enforce that the username is not already taken.\n\n     - warning: Make sure that password and username are set before calling this method.\n     - parameter username: The username of the user.\n     - parameter password: The password of the user.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns whether the sign up was successful.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public static func signup(username: String,\n                              password: String,\n                              options: API.Options = []) throws -> Self {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        let body = SignupLoginBody(username: username,\n                                   password: password)\n        if let current = Self.current {\n            return try current.linkCommand(body: body)\n                .execute(options: options)\n        } else {\n            return try signupCommand(body: body)\n                .execute(options: options)\n        }\n    }\n\n    /**\n     Signs up the user *synchronously*.\n\n     This will also enforce that the username is not already taken.\n\n     - warning: Make sure that password and username are set before calling this method.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns whether the sign up was successful.\n     - throws: An error of `ParseError` type.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func signup(options: API.Options = []) throws -> Self {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        if Self.current != nil {\n            return try self.linkCommand()\n                .execute(options: options)\n        } else {\n            return try signupCommand().execute(options: options)\n        }\n    }\n\n    /**\n     Signs up the user *asynchronously*.\n\n     This will also enforce that the username is not already taken.\n\n     - warning: Make sure that password and username are set before calling this method.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func signup(options: API.Options = [], callbackQueue: DispatchQueue = .main,\n                       completion: @escaping (Result<Self, ParseError>) -> Void) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        if Self.current != nil {\n            do {\n                try self.linkCommand()\n                    .executeAsync(options: options,\n                                  callbackQueue: callbackQueue) { result in\n                        completion(result)\n                    }\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        } else {\n            do {\n                try signupCommand()\n                    .executeAsync(options: options,\n                                  callbackQueue: callbackQueue) { result in\n                        completion(result)\n                }\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n    }\n\n    /**\n     Signs up the user *asynchronously*.\n\n     This will also enforce that the username is not already taken.\n\n     - warning: Make sure that password and username are set before calling this method.\n     - parameter username: The username of the user.\n     - parameter password: The password of the user.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public static func signup(\n        username: String,\n        password: String,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<Self, ParseError>) -> Void) {\n\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        let body = SignupLoginBody(username: username, password: password)\n        if let current = Self.current {\n            current.linkCommand(body: body)\n                .executeAsync(options: options,\n                              callbackQueue: callbackQueue) { result in\n                    completion(result)\n                }\n        } else {\n            do {\n                try signupCommand(body: body)\n                    .executeAsync(options: options,\n                                  callbackQueue: callbackQueue) { result in\n                        completion(result)\n                }\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n    }\n\n    internal static func signupCommand(body: SignupLoginBody) throws -> API.Command<SignupLoginBody, Self> {\n        API.Command(method: .POST,\n                    path: .users,\n                    body: body) { (data) -> Self in\n\n            let sessionToken = try ParseCoding.jsonDecoder()\n                .decode(LoginSignupResponse.self, from: data).sessionToken\n            var user = try ParseCoding.jsonDecoder().decode(Self.self, from: data)\n\n            if user.username == nil {\n                if let username = body.username {\n                    user.username = username\n                }\n            }\n            if user.authData == nil {\n                if let authData = body.authData {\n                    user.authData = authData\n                }\n            }\n            Self.currentContainer = .init(currentUser: user,\n                                              sessionToken: sessionToken)\n            Self.saveCurrentContainerToKeychain()\n            return user\n        }\n    }\n\n    internal func signupCommand() throws -> API.Command<Self, Self> {\n\n        API.Command(method: .POST,\n                    path: endpoint,\n                    body: self) { (data) -> Self in\n\n            let response = try ParseCoding.jsonDecoder()\n                .decode(LoginSignupResponse.self, from: data)\n            let user = response.applySignup(to: self)\n            Self.currentContainer = .init(\n                currentUser: user,\n                sessionToken: response.sessionToken\n            )\n            Self.saveCurrentContainerToKeychain()\n            return user\n        }\n    }\n}\n\n// MARK: Fetchable\nextension ParseUser {\n    internal static func updateKeychainIfNeeded(_ results: [Self], deleting: Bool = false) throws {\n        guard let currentUser = Self.current else {\n            return\n        }\n\n        var foundCurrentUserObjects = results.filter { $0.hasSameObjectId(as: currentUser) }\n        foundCurrentUserObjects = try foundCurrentUserObjects.sorted(by: {\n            guard let firstUpdatedAt = $0.updatedAt,\n                  let secondUpdatedAt = $1.updatedAt else {\n                throw ParseError(code: .unknownError,\n                                 message: \"Objects from the server should always have an \\\"updatedAt\\\"\")\n            }\n            return firstUpdatedAt.compare(secondUpdatedAt) == .orderedDescending\n        })\n        if let foundCurrentUser = foundCurrentUserObjects.first {\n            if !deleting {\n                Self.current = foundCurrentUser\n                Self.saveCurrentContainerToKeychain()\n            } else {\n                Self.deleteCurrentContainerFromKeychain()\n            }\n        }\n    }\n\n    /**\n     Fetches the `ParseUser` *synchronously* with the current data from the server.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys one level deep. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of `ParseError` type.\n     - important: If an object fetched has the same objectId as current, it will automatically update the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func fetch(includeKeys: [String]? = nil,\n                      options: API.Options = []) throws -> Self {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        let result: Self = try fetchCommand(include: includeKeys)\n            .execute(options: options)\n        try Self.updateKeychainIfNeeded([result])\n        return result\n    }\n\n    /**\n     Fetches the `ParseUser` *asynchronously* and executes the given callback block.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys one level deep. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - important: If an object fetched has the same objectId as current, it will automatically update the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func fetch(\n        includeKeys: [String]? = nil,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<Self, ParseError>) -> Void\n    ) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        do {\n            try fetchCommand(include: includeKeys)\n                .executeAsync(options: options,\n                              callbackQueue: callbackQueue) { result in\n                    if case .success(let foundResult) = result {\n                        do {\n                            try Self.updateKeychainIfNeeded([foundResult])\n                            completion(.success(foundResult))\n                        } catch {\n                            let defaultError = ParseError(code: .unknownError,\n                                                          message: error.localizedDescription)\n                            let parseError = error as? ParseError ?? defaultError\n                            completion(.failure(parseError))\n                        }\n                    } else {\n                        completion(result)\n                    }\n                }\n         } catch {\n            callbackQueue.async {\n                if let error = error as? ParseError {\n                    completion(.failure(error))\n                } else {\n                    completion(.failure(ParseError(code: .unknownError,\n                                                   message: error.localizedDescription)))\n                }\n            }\n         }\n    }\n\n    func fetchCommand(include: [String]?) throws -> API.Command<Self, Self> {\n        guard objectId != nil else {\n            throw ParseError(code: .missingObjectId,\n                             message: \"objectId must not be nil\")\n        }\n\n        var params: [String: String]?\n        if let includeParams = include {\n            params = [\"include\": \"\\(Set(includeParams))\"]\n        }\n\n        return API.Command(method: .GET,\n                           path: endpoint,\n                           params: params) { (data) -> Self in\n            try ParseCoding.jsonDecoder().decode(Self.self, from: data)\n        }\n    }\n}\n\n// MARK: Savable\nextension ParseUser {\n\n    /**\n     Saves the `ParseUser` *synchronously* and throws an error if there is an issue.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n     - returns: Returns saved `ParseUser`.\n     - important: If an object saved has the same objectId as current, it will automatically update the current.\n    */\n    @discardableResult\n    public func save(options: API.Options = []) throws -> Self {\n        try save(ignoringCustomObjectIdConfig: false, options: options)\n    }\n\n    /**\n     Saves the `ParseUser` *synchronously* and throws an error if there is an issue.\n\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n     - returns: Returns saved `ParseUser`.\n     - important: If an object saved has the same objectId as current, it will automatically update the current.\n     - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true`\n     and plan to generate all of your `objectId`'s on the client-side then you should leave\n     `ignoringCustomObjectIdConfig = false`. Setting\n     `ParseConfiguration.isRequiringCustomObjectIds = true` and\n     `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s\n     and the server will generate an `objectId` only when the client does not provide one. This can\n     increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using\n     different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the\n     client-side checks are disabled. Developers are responsible for handling such cases.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    @discardableResult\n    public func save(ignoringCustomObjectIdConfig: Bool,\n                     options: API.Options = []) throws -> Self {\n        var childObjects: [String: PointerType]?\n        var childFiles: [UUID: ParseFile]?\n        var error: ParseError?\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        let group = DispatchGroup()\n        group.enter()\n        self.ensureDeepSave(options: options) { (savedChildObjects, savedChildFiles, parseError) in\n            childObjects = savedChildObjects\n            childFiles = savedChildFiles\n            error = parseError\n            group.leave()\n        }\n        group.wait()\n\n        if let error = error {\n            throw error\n        }\n\n        let result: Self = try saveCommand(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig)\n            .execute(options: options,\n                     childObjects: childObjects,\n                     childFiles: childFiles)\n        try Self.updateKeychainIfNeeded([result])\n        return result\n    }\n\n    /**\n     Saves the `ParseUser` *asynchronously* and executes the given callback block.\n\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - important: If an object saved has the same objectId as current, it will automatically update the current.\n     - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true`\n     and plan to generate all of your `objectId`'s on the client-side then you should leave\n     `ignoringCustomObjectIdConfig = false`. Setting\n     `ParseConfiguration.isRequiringCustomObjectIds = true` and\n     `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s\n     and the server will generate an `objectId` only when the client does not provide one. This can\n     increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using\n     different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the\n     client-side checks are disabled. Developers are responsible for handling such cases.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func save(\n        ignoringCustomObjectIdConfig: Bool = false,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<Self, ParseError>) -> Void\n    ) {\n        let method = Method.save\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let object = try await command(method: method,\n                                               ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                                               options: options,\n                                               callbackQueue: callbackQueue)\n                completion(.success(object))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        command(method: method,\n                ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                options: options,\n                callbackQueue: callbackQueue,\n                completion: completion)\n        #endif\n    }\n\n    /**\n     Creates the `ParseUser` *asynchronously* and executes the given callback block.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n    */\n    public func create(\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<Self, ParseError>) -> Void\n    ) {\n        let method = Method.create\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let object = try await command(method: method,\n                                               options: options,\n                                               callbackQueue: callbackQueue)\n                completion(.success(object))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        command(method: method,\n                options: options,\n                callbackQueue: callbackQueue,\n                completion: completion)\n        #endif\n    }\n\n    /**\n     Replaces the `ParseUser` *asynchronously* and executes the given callback block.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - important: If an object replaced has the same objectId as current, it will automatically replace the current.\n    */\n    public func replace(\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<Self, ParseError>) -> Void\n    ) {\n        let method = Method.replace\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let object = try await command(method: method,\n                                               options: options,\n                                               callbackQueue: callbackQueue)\n                completion(.success(object))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        command(method: method,\n                options: options,\n                callbackQueue: callbackQueue,\n                completion: completion)\n        #endif\n    }\n\n    /**\n     Updates the `ParseUser` *asynchronously* and executes the given callback block.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - important: If an object updated has the same objectId as current, it will automatically update the current.\n    */\n    internal func update(\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<Self, ParseError>) -> Void\n    ) {\n        let method = Method.update\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let object = try await command(method: method,\n                                               options: options,\n                                               callbackQueue: callbackQueue)\n                completion(.success(object))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        command(method: method,\n                options: options,\n                callbackQueue: callbackQueue,\n                completion: completion)\n        #endif\n    }\n\n    func command(\n        method: Method,\n        ignoringCustomObjectIdConfig: Bool = false,\n        options: API.Options,\n        callbackQueue: DispatchQueue,\n        completion: @escaping (Result<Self, ParseError>) -> Void\n    ) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        self.ensureDeepSave(options: options) { (savedChildObjects, savedChildFiles, error) in\n            guard let parseError = error else {\n                do {\n                    let command: API.Command<Self, Self>!\n                    switch method {\n                    case .save:\n                        command = try self.saveCommand(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig)\n                    case .create:\n                        command = self.createCommand()\n                    case .replace:\n                        command = try self.replaceCommand()\n                    case .update:\n                        command = try self.updateCommand()\n                    }\n                    command\n                        .executeAsync(options: options,\n                                      callbackQueue: callbackQueue,\n                                      childObjects: savedChildObjects,\n                                      childFiles: savedChildFiles) { result in\n                            if case .success(let foundResult) = result {\n                                try? Self.updateKeychainIfNeeded([foundResult])\n                            }\n                            completion(result)\n                    }\n                } catch {\n                    let defaultError = ParseError(code: .unknownError,\n                                                  message: error.localizedDescription)\n                    let parseError = error as? ParseError ?? defaultError\n                    callbackQueue.async {\n                        completion(.failure(parseError))\n                    }\n                }\n                return\n            }\n            callbackQueue.async {\n                completion(.failure(parseError))\n            }\n        }\n    }\n\n    func saveCommand(ignoringCustomObjectIdConfig: Bool = false) throws -> API.Command<Self, Self> {\n        if Parse.configuration.isRequiringCustomObjectIds && objectId == nil && !ignoringCustomObjectIdConfig {\n            throw ParseError(code: .missingObjectId, message: \"objectId must not be nil\")\n        }\n        if isSaved {\n            return try replaceCommand() // MARK: Should be switched to \"updateCommand\" when server supports PATCH.\n        }\n        return createCommand()\n    }\n\n    // MARK: Saving ParseObjects - private\n    func createCommand() -> API.Command<Self, Self> {\n        var object = self\n        if object.ACL == nil,\n            let acl = try? ParseACL.defaultACL() {\n            object.ACL = acl\n        }\n        let mapper = { (data) -> Self in\n            try ParseCoding.jsonDecoder().decode(CreateResponse.self, from: data).apply(to: object)\n        }\n        return API.Command<Self, Self>(method: .POST,\n                                       path: endpoint(.POST),\n                                       body: object,\n                                       mapper: mapper)\n    }\n\n    func replaceCommand() throws -> API.Command<Self, Self> {\n        guard self.objectId != nil else {\n            throw ParseError(code: .missingObjectId,\n                             message: \"objectId must not be nil\")\n        }\n        var mutableSelf = self\n        if let currentUser = Self.current,\n           currentUser.hasSameObjectId(as: mutableSelf) {\n            #if !os(Linux) && !os(Android) && !os(Windows)\n            // swiftlint:disable:next line_length\n            if let currentUserContainerInKeychain: CurrentUserContainer<BaseParseUser> = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser),\n               currentUserContainerInKeychain.currentUser?.email == mutableSelf.email {\n                mutableSelf.email = nil\n            }\n            #else\n            if currentUser.email == mutableSelf.email {\n                mutableSelf.email = nil\n            }\n            #endif\n        }\n        let mapper = { (data: Data) -> Self in\n            var updatedObject = self\n            updatedObject.originalData = nil\n            updatedObject = try ParseCoding.jsonDecoder().decode(ReplaceResponse.self,\n                                                                 from: data).apply(to: updatedObject)\n            // MARK: The lines below should be removed when server supports PATCH.\n            guard let originalData = self.originalData,\n                  let original = try? ParseCoding.jsonDecoder().decode(Self.self,\n                                                                       from: originalData),\n                  original.hasSameObjectId(as: updatedObject) else {\n                      return updatedObject\n                  }\n            return try updatedObject.merge(with: original)\n        }\n        return API.Command<Self, Self>(method: .PUT,\n                                 path: endpoint,\n                                 body: mutableSelf,\n                                 mapper: mapper)\n    }\n\n    func updateCommand() throws -> API.Command<Self, Self> {\n        guard self.objectId != nil else {\n            throw ParseError(code: .missingObjectId,\n                             message: \"objectId must not be nil\")\n        }\n        var mutableSelf = self\n        if let currentUser = Self.current,\n           currentUser.hasSameObjectId(as: mutableSelf) {\n            #if !os(Linux) && !os(Android) && !os(Windows)\n            // swiftlint:disable:next line_length\n            if let currentUserContainerInKeychain: CurrentUserContainer<BaseParseUser> = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser),\n               currentUserContainerInKeychain.currentUser?.email == mutableSelf.email {\n                mutableSelf.email = nil\n            }\n            #else\n            if currentUser.email == mutableSelf.email {\n                mutableSelf.email = nil\n            }\n            #endif\n        }\n        let mapper = { (data: Data) -> Self in\n            var updatedObject = self\n            updatedObject.originalData = nil\n            updatedObject = try ParseCoding.jsonDecoder().decode(UpdateResponse.self,\n                                                                 from: data).apply(to: updatedObject)\n            guard let originalData = self.originalData,\n                  let original = try? ParseCoding.jsonDecoder().decode(Self.self,\n                                                                       from: originalData),\n                  original.hasSameObjectId(as: updatedObject) else {\n                      return updatedObject\n                  }\n            return try updatedObject.merge(with: original)\n        }\n        return API.Command<Self, Self>(method: .PATCH,\n                                 path: endpoint,\n                                 body: mutableSelf,\n                                 mapper: mapper)\n    }\n}\n\n// MARK: Deletable\nextension ParseUser {\n    /**\n     Deletes the `ParseUser` *synchronously* with the current data from the server.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of `ParseError` type.\n     - important: If an object deleted has the same objectId as current, it will automatically update the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func delete(options: API.Options = []) throws {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        _ = try deleteCommand().execute(options: options)\n        try Self.updateKeychainIfNeeded([self], deleting: true)\n    }\n\n    /**\n     Deletes the `ParseUser` *asynchronously* and executes the given callback block.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Void, ParseError>)`.\n     - important: If an object deleted has the same objectId as current, it will automatically update the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func delete(\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<Void, ParseError>) -> Void\n    ) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n         do {\n            try deleteCommand().executeAsync(options: options,\n                                             callbackQueue: callbackQueue) { result in\n                switch result {\n\n                case .success:\n                    try? Self.updateKeychainIfNeeded([self], deleting: true)\n                    completion(.success(()))\n                case .failure(let error):\n                    callbackQueue.async {\n                        completion(.failure(error))\n                    }\n                }\n            }\n         } catch let error as ParseError {\n            callbackQueue.async {\n                completion(.failure(error))\n            }\n         } catch {\n            callbackQueue.async {\n                completion(.failure(ParseError(code: .unknownError, message: error.localizedDescription)))\n            }\n         }\n    }\n\n    func deleteCommand() throws -> API.NonParseBodyCommand<NoBody, NoBody> {\n        guard isSaved else {\n            throw ParseError(code: .unknownError, message: \"Cannot Delete an object without id\")\n        }\n\n        return API.NonParseBodyCommand<NoBody, NoBody>(\n            method: .DELETE,\n            path: endpoint\n        ) { (data) -> NoBody in\n            let error = try? ParseCoding.jsonDecoder().decode(ParseError.self, from: data)\n            if let error = error {\n                throw error\n            } else {\n                return NoBody()\n            }\n        }\n    }\n}\n\n// MARK: Batch Support\npublic extension Sequence where Element: ParseUser {\n\n    /**\n     Saves a collection of users *synchronously* all at once and throws an error if necessary.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n\n     - returns: Returns a Result enum with the object if a save was successful or a `ParseError` if it failed.\n     - throws: An error of type `ParseError`.\n     - important: If an object saved has the same objectId as current, it will automatically update the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true`\n     and plan to generate all of your `objectId`'s on the client-side then you should leave\n     `ignoringCustomObjectIdConfig = false`. Setting\n     `ParseConfiguration.isRequiringCustomObjectIds = true` and\n     `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s\n     and the server will generate an `objectId` only when the client does not provide one. This can\n     increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using\n     different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the\n     client-side checks are disabled. Developers are responsible for handling such cases.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func saveAll(batchLimit limit: Int? = nil, // swiftlint:disable:this function_body_length\n                 transaction: Bool = configuration.isUsingTransactions,\n                 ignoringCustomObjectIdConfig: Bool = false,\n                 options: API.Options = []) throws -> [(Result<Self.Element, ParseError>)] {\n        var childObjects = [String: PointerType]()\n        var childFiles = [UUID: ParseFile]()\n        var error: ParseError?\n        var commands = [API.Command<Self.Element, Self.Element>]()\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n\n        try forEach {\n            let user = $0\n            let group = DispatchGroup()\n            group.enter()\n            user.ensureDeepSave(options: options,\n                                // swiftlint:disable:next line_length\n                                isShouldReturnIfChildObjectsFound: transaction) { (savedChildObjects, savedChildFiles, parseError) -> Void in\n                //If an error occurs, everything should be skipped\n                if parseError != nil {\n                    error = parseError\n                }\n                savedChildObjects.forEach {(key, value) in\n                    if error != nil {\n                        return\n                    }\n                    if childObjects[key] == nil {\n                        childObjects[key] = value\n                    } else {\n                        error = ParseError(code: .unknownError, message: \"circular dependency\")\n                        return\n                    }\n                }\n                savedChildFiles.forEach {(key, value) in\n                    if error != nil {\n                        return\n                    }\n                    if childFiles[key] == nil {\n                        childFiles[key] = value\n                    } else {\n                        error = ParseError(code: .unknownError, message: \"circular dependency\")\n                        return\n                    }\n                }\n                group.leave()\n            }\n            group.wait()\n            if let error = error {\n                throw error\n            }\n            commands.append(try user.saveCommand(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig))\n        }\n\n        var returnBatch = [(Result<Self.Element, ParseError>)]()\n        let batchLimit = limit != nil ? limit! : ParseConstants.batchLimit\n        try canSendTransactions(transaction, objectCount: commands.count, batchLimit: batchLimit)\n        let batches = BatchUtils.splitArray(commands, valuesPerSegment: batchLimit)\n        try batches.forEach {\n            let currentBatch = try API.Command<Self.Element, Self.Element>\n                .batch(commands: $0, transaction: transaction)\n                .execute(options: options,\n                         batching: true,\n                         childObjects: childObjects,\n                         childFiles: childFiles)\n            returnBatch.append(contentsOf: currentBatch)\n        }\n        try Self.Element.updateKeychainIfNeeded(returnBatch.compactMap {try? $0.get()})\n        return returnBatch\n    }\n\n    /**\n     Saves a collection of users all at once *asynchronously* and executes the completion block when done.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter ignoringCustomObjectIdConfig: Ignore checking for `objectId`\n     when `ParseConfiguration.isRequiringCustomObjectIds = true` to allow for mixed\n     `objectId` environments. Defaults to false.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<[(Result<Element, ParseError>)], ParseError>)`.\n     - important: If an object saved has the same objectId as current, it will automatically update the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - warning: If you are using `ParseConfiguration.isRequiringCustomObjectIds = true`\n     and plan to generate all of your `objectId`'s on the client-side then you should leave\n     `ignoringCustomObjectIdConfig = false`. Setting\n     `ParseConfiguration.isRequiringCustomObjectIds = true` and\n     `ignoringCustomObjectIdConfig = true` means the client will generate `objectId`'s\n     and the server will generate an `objectId` only when the client does not provide one. This can\n     increase the probability of colliiding `objectId`'s as the client and server `objectId`'s may be generated using\n     different algorithms. This can also lead to overwriting of `ParseObject`'s by accident as the\n     client-side checks are disabled. Developers are responsible for handling such cases.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func saveAll( // swiftlint:disable:this function_body_length cyclomatic_complexity\n        batchLimit limit: Int? = nil,\n        transaction: Bool = configuration.isUsingTransactions,\n        ignoringCustomObjectIdConfig: Bool = false,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<[(Result<Element, ParseError>)], ParseError>) -> Void\n    ) {\n        let method = Method.save\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let objects = try await batchCommand(method: method,\n                                                     batchLimit: limit,\n                                                     transaction: transaction,\n                                                     ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                                                     options: options,\n                                                     callbackQueue: callbackQueue)\n                completion(.success(objects))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        batchCommand(method: method,\n                     batchLimit: limit,\n                     transaction: transaction,\n                     ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                     options: options,\n                     callbackQueue: callbackQueue,\n                     completion: completion)\n        #endif\n    }\n\n    /**\n     Creates a collection of users all at once *asynchronously* and executes the completion block when done.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<[(Result<Element, ParseError>)], ParseError>)`.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func createAll( // swiftlint:disable:this function_body_length cyclomatic_complexity\n        batchLimit limit: Int? = nil,\n        transaction: Bool = configuration.isUsingTransactions,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<[(Result<Element, ParseError>)], ParseError>) -> Void\n    ) {\n        let method = Method.create\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let objects = try await batchCommand(method: method,\n                                                     batchLimit: limit,\n                                                     transaction: transaction,\n                                                     options: options,\n                                                     callbackQueue: callbackQueue)\n                completion(.success(objects))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        batchCommand(method: method,\n                     batchLimit: limit,\n                     transaction: transaction,\n                     options: options,\n                     callbackQueue: callbackQueue,\n                     completion: completion)\n        #endif\n    }\n\n    /**\n     Replaces a collection of users all at once *asynchronously* and executes the completion block when done.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<[(Result<Element, ParseError>)], ParseError>)`.\n     - important: If an object replaced has the same objectId as current, it will automatically replace the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func replaceAll( // swiftlint:disable:this function_body_length cyclomatic_complexity\n        batchLimit limit: Int? = nil,\n        transaction: Bool = configuration.isUsingTransactions,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<[(Result<Element, ParseError>)], ParseError>) -> Void\n    ) {\n        let method = Method.replace\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let objects = try await batchCommand(method: method,\n                                                     batchLimit: limit,\n                                                     transaction: transaction,\n                                                     options: options,\n                                                     callbackQueue: callbackQueue)\n                completion(.success(objects))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        batchCommand(method: method,\n                     batchLimit: limit,\n                     transaction: transaction,\n                     options: options,\n                     callbackQueue: callbackQueue,\n                     completion: completion)\n        #endif\n    }\n\n    /**\n     Updates a collection of users all at once *asynchronously* and executes the completion block when done.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<[(Result<Element, ParseError>)], ParseError>)`.\n     - important: If an object updated has the same objectId as current, it will automatically update the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    internal func updateAll( // swiftlint:disable:this function_body_length cyclomatic_complexity\n        batchLimit limit: Int? = nil,\n        transaction: Bool = configuration.isUsingTransactions,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<[(Result<Element, ParseError>)], ParseError>) -> Void\n    ) {\n        let method = Method.update\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        Task {\n            do {\n                let objects = try await batchCommand(method: method,\n                                                     batchLimit: limit,\n                                                     transaction: transaction,\n                                                     options: options,\n                                                     callbackQueue: callbackQueue)\n                completion(.success(objects))\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n        #else\n        batchCommand(method: method,\n                     batchLimit: limit,\n                     transaction: transaction,\n                     options: options,\n                     callbackQueue: callbackQueue,\n                     completion: completion)\n        #endif\n    }\n\n    internal func batchCommand( // swiftlint:disable:this function_parameter_count\n        method: Method,\n        batchLimit limit: Int?,\n        transaction: Bool,\n        ignoringCustomObjectIdConfig: Bool = false,\n        options: API.Options,\n        callbackQueue: DispatchQueue,\n        completion: @escaping (Result<[(Result<Element, ParseError>)], ParseError>) -> Void\n    ) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        let uuid = UUID()\n        let queue = DispatchQueue(label: \"com.parse.batch.\\(uuid)\",\n                                  qos: .default,\n                                  attributes: .concurrent,\n                                  autoreleaseFrequency: .inherit,\n                                  target: nil)\n        let users = map { $0 }\n        queue.sync {\n            var childObjects = [String: PointerType]()\n            var childFiles = [UUID: ParseFile]()\n            var error: ParseError?\n            var commands = [API.Command<Self.Element, Self.Element>]()\n\n            for user in users {\n                let group = DispatchGroup()\n                group.enter()\n                user.ensureDeepSave(options: options,\n                                    // swiftlint:disable:next line_length\n                                    isShouldReturnIfChildObjectsFound: transaction) { (savedChildObjects, savedChildFiles, parseError) -> Void in\n                    // If an error occurs, everything should be skipped\n                    if let parseError = parseError {\n                        error = parseError\n                    }\n                    savedChildObjects.forEach {(key, value) in\n                        guard error == nil else {\n                            return\n                        }\n                        guard childObjects[key] == nil else {\n                            error = ParseError(code: .unknownError, message: \"circular dependency\")\n                            return\n                        }\n                        childObjects[key] = value\n                    }\n                    savedChildFiles.forEach {(key, value) in\n                        guard error == nil else {\n                            return\n                        }\n                        guard childFiles[key] == nil else {\n                            error = ParseError(code: .unknownError, message: \"circular dependency\")\n                            return\n                        }\n                        childFiles[key] = value\n                    }\n                    group.leave()\n                }\n                group.wait()\n                if let error = error {\n                    callbackQueue.async {\n                        completion(.failure(error))\n                    }\n                    return\n                }\n                do {\n                    switch method {\n                    case .save:\n                        commands.append(\n                            try user.saveCommand(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig)\n                        )\n                    case .create:\n                        commands.append(user.createCommand())\n                    case .replace:\n                        commands.append(try user.replaceCommand())\n                    case .update:\n                        commands.append(try user.updateCommand())\n                    }\n                } catch {\n                    let defaultError = ParseError(code: .unknownError,\n                                                  message: error.localizedDescription)\n                    let parseError = error as? ParseError ?? defaultError\n                    callbackQueue.async {\n                        completion(.failure(parseError))\n                    }\n                    return\n                }\n            }\n\n            do {\n                var returnBatch = [(Result<Self.Element, ParseError>)]()\n                let batchLimit = limit != nil ? limit! : ParseConstants.batchLimit\n                try canSendTransactions(transaction, objectCount: commands.count, batchLimit: batchLimit)\n                let batches = BatchUtils.splitArray(commands, valuesPerSegment: batchLimit)\n                var completed = 0\n                for batch in batches {\n                    API.Command<Self.Element, Self.Element>\n                            .batch(commands: batch, transaction: transaction)\n                            .executeAsync(options: options,\n                                          batching: true,\n                                          callbackQueue: callbackQueue,\n                                          childObjects: childObjects,\n                                          childFiles: childFiles) { results in\n                        switch results {\n\n                        case .success(let saved):\n                            returnBatch.append(contentsOf: saved)\n                            if completed == (batches.count - 1) {\n                                try? Self.Element.updateKeychainIfNeeded(returnBatch.compactMap {try? $0.get()})\n                                completion(.success(returnBatch))\n                            }\n                            completed += 1\n                        case .failure(let error):\n                            completion(.failure(error))\n                            return\n                        }\n                    }\n                }\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n    }\n    /**\n     Fetches a collection of users *synchronously* all at once and throws an error if necessary.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys one level deep. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n\n     - returns: Returns a Result enum with the object if a fetch was successful or a `ParseError` if it failed.\n     - throws: An error of `ParseError` type.\n     - important: If an object fetched has the same objectId as current, it will automatically update the current.\n     - warning: The order in which users are returned are not guarenteed. You should not expect results in\n     any particular order.\n    */\n    func fetchAll(includeKeys: [String]? = nil,\n                  options: API.Options = []) throws -> [(Result<Self.Element, ParseError>)] {\n\n        if (allSatisfy { $0.className == Self.Element.className}) {\n            let uniqueObjectIds = Set(self.compactMap { $0.objectId })\n            var query = Self.Element.query(containedIn(key: \"objectId\", array: [uniqueObjectIds]))\n                .limit(uniqueObjectIds.count)\n            if let include = includeKeys {\n                query = query.include(include)\n            }\n            let fetchedObjects = try query.find(options: options)\n            var fetchedObjectsToReturn = [(Result<Self.Element, ParseError>)]()\n\n            uniqueObjectIds.forEach {\n                let uniqueObjectId = $0\n                if let fetchedObject = fetchedObjects.first(where: {$0.objectId == uniqueObjectId}) {\n                    fetchedObjectsToReturn.append(.success(fetchedObject))\n                } else {\n                    fetchedObjectsToReturn.append(.failure(ParseError(code: .objectNotFound,\n                                                                      // swiftlint:disable:next line_length\n                                                                      message: \"objectId \\\"\\(uniqueObjectId)\\\" was not found in className \\\"\\(Self.Element.className)\\\"\")))\n                }\n            }\n            try Self.Element.updateKeychainIfNeeded(fetchedObjects)\n            return fetchedObjectsToReturn\n        } else {\n            throw ParseError(code: .unknownError, message: \"all items to fetch must be of the same class\")\n        }\n    }\n\n    /**\n     Fetches a collection of users all at once *asynchronously* and executes the completion block when done.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys one level deep. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<[(Result<Element, ParseError>)], ParseError>)`.\n     - important: If an object fetched has the same objectId as current, it will automatically update the current.\n     - warning: The order in which users are returned are not guarenteed. You should not expect results in\n     any particular order.\n    */\n    func fetchAll(\n        includeKeys: [String]? = nil,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<[(Result<Element, ParseError>)], ParseError>) -> Void\n    ) {\n        if (allSatisfy { $0.className == Self.Element.className}) {\n            let uniqueObjectIds = Set(compactMap { $0.objectId })\n            var query = Self.Element.query(containedIn(key: \"objectId\", array: [uniqueObjectIds]))\n            if let include = includeKeys {\n                query = query.include(include)\n            }\n            query.find(options: options, callbackQueue: callbackQueue) { result in\n                switch result {\n\n                case .success(let fetchedObjects):\n                    var fetchedObjectsToReturn = [(Result<Self.Element, ParseError>)]()\n\n                    uniqueObjectIds.forEach {\n                        let uniqueObjectId = $0\n                        if let fetchedObject = fetchedObjects.first(where: {$0.objectId == uniqueObjectId}) {\n                            fetchedObjectsToReturn.append(.success(fetchedObject))\n                        } else {\n                            fetchedObjectsToReturn.append(.failure(ParseError(code: .objectNotFound,\n                                                                              // swiftlint:disable:next line_length\n                                                                              message: \"objectId \\\"\\(uniqueObjectId)\\\" was not found in className \\\"\\(Self.Element.className)\\\"\")))\n                        }\n                    }\n                    try? Self.Element.updateKeychainIfNeeded(fetchedObjects)\n                    completion(.success(fetchedObjectsToReturn))\n                case .failure(let error):\n                    callbackQueue.async {\n                        completion(.failure(error))\n                    }\n                }\n            }\n        } else {\n            callbackQueue.async {\n                completion(.failure(ParseError(code: .unknownError,\n                                               message: \"all items to fetch must be of the same class\")))\n            }\n        }\n    }\n\n    /**\n     Deletes a collection of users *synchronously* all at once and throws an error if necessary.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n\n     - returns: Returns `nil` if the delete successful or a `ParseError` if it failed.\n        1. A `ParseError.Code.aggregateError`. This object's \"errors\" property is an\n        array of other Parse.Error objects. Each error object in this array\n        has an \"object\" property that references the object that could not be\n        deleted (for instance, because that object could not be found).\n        2. A non-aggregate Parse.Error. This indicates a serious error that\n        caused the delete operation to be aborted partway through (for\n        instance, a connection failure in the middle of the delete).\n     - throws: An error of `ParseError` type.\n     - important: If an object deleted has the same objectId as current, it will automatically update the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func deleteAll(batchLimit limit: Int? = nil,\n                   transaction: Bool = configuration.isUsingTransactions,\n                   options: API.Options = []) throws -> [(Result<Void, ParseError>)] {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        var returnBatch = [(Result<Void, ParseError>)]()\n        let commands = try map { try $0.deleteCommand() }\n        let batchLimit = limit != nil ? limit! : ParseConstants.batchLimit\n        try canSendTransactions(transaction, objectCount: commands.count, batchLimit: batchLimit)\n        let batches = BatchUtils.splitArray(commands, valuesPerSegment: batchLimit)\n        try batches.forEach {\n            let currentBatch = try API.Command<Self.Element, ParseError?>\n                .batch(commands: $0, transaction: transaction)\n                .execute(options: options)\n            returnBatch.append(contentsOf: currentBatch)\n        }\n        try Self.Element.updateKeychainIfNeeded(compactMap {$0},\n                                                deleting: true)\n        return returnBatch\n    }\n\n    /**\n     Deletes a collection of users all at once *asynchronously* and executes the completion block when done.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n     Defaults to 50.\n     - parameter transaction: Treat as an all-or-nothing operation. If some operation failure occurs that\n     prevents the transaction from completing, then none of the objects are committed to the Parse Server database.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<[ParseError?], ParseError>)`.\n     Each element in the array is `nil` if the delete successful or a `ParseError` if it failed.\n     1. A `ParseError.Code.aggregateError`. This object's \"errors\" property is an\n     array of other Parse.Error objects. Each error object in this array\n     has an \"object\" property that references the object that could not be\n     deleted (for instance, because that object could not be found).\n     2. A non-aggregate Parse.Error. This indicates a serious error that\n     caused the delete operation to be aborted partway through (for\n     instance, a connection failure in the middle of the delete).\n     - important: If an object deleted has the same objectId as current, it will automatically update the current.\n     - warning: If `transaction = true`, then `batchLimit` will be automatically be set to the amount of the\n     objects in the transaction. The developer should ensure their respective Parse Servers can handle the limit or else\n     the transactions can fail.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func deleteAll(\n        batchLimit limit: Int? = nil,\n        transaction: Bool = configuration.isUsingTransactions,\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<[(Result<Void, ParseError>)], ParseError>) -> Void\n    ) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        do {\n            var returnBatch = [(Result<Void, ParseError>)]()\n            let commands = try map({ try $0.deleteCommand() })\n            let batchLimit = limit != nil ? limit! : ParseConstants.batchLimit\n            try canSendTransactions(transaction, objectCount: commands.count, batchLimit: batchLimit)\n            let batches = BatchUtils.splitArray(commands, valuesPerSegment: batchLimit)\n            var completed = 0\n            for batch in batches {\n                API.Command<Self.Element, ParseError?>\n                        .batch(commands: batch, transaction: transaction)\n                        .executeAsync(options: options,\n                                      callbackQueue: callbackQueue) { results in\n                    switch results {\n\n                    case .success(let saved):\n                        returnBatch.append(contentsOf: saved)\n                        if completed == (batches.count - 1) {\n                            try? Self.Element.updateKeychainIfNeeded(self.compactMap {$0},\n                                                                     deleting: true)\n                            completion(.success(returnBatch))\n                        }\n                        completed += 1\n                    case .failure(let error):\n                        completion(.failure(error))\n                        return\n                    }\n                }\n            }\n        } catch {\n            let defaultError = ParseError(code: .unknownError,\n                                          message: error.localizedDescription)\n            let parseError = error as? ParseError ?? defaultError\n            callbackQueue.async {\n                completion(.failure(parseError))\n            }\n        }\n    }\n} // swiftlint:disable:this file_length\n"
  },
  {
    "path": "Sources/ParseSwift/Operations/Add.swift",
    "content": "//\n//  Add.swift\n//  Parse\n//\n//  Created by Florent Vilmart on 17-07-24.\n//  Copyright © 2017 Parse. All rights reserved.\n//\n\nimport Foundation\n\ninternal struct Add<T>: Encodable where T: Encodable {\n    let __op: Operation = .add // swiftlint:disable:this identifier_name\n    let objects: [T]\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Operations/AddRelation.swift",
    "content": "//\n//  AddRelation.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/17/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\ninternal struct AddRelation<T>: Encodable where T: ParseObject {\n    let __op: Operation = .addRelation // swiftlint:disable:this identifier_name\n    let objects: [Pointer<T>]\n\n    init(objects: [T]) throws {\n        self.objects = try objects.compactMap { try $0.toPointer() }\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Operations/AddUnique.swift",
    "content": "//\n//  AddUnique.swift\n//  Parse\n//\n//  Created by Florent Vilmart on 17-07-24.\n//  Copyright © 2017 Parse. All rights reserved.\n//\n\nimport Foundation\n\ninternal struct AddUnique<T>: Encodable where T: Encodable {\n    let __op: Operation = .addUnique // swiftlint:disable:this identifier_name\n    let objects: [T]\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Operations/Delete.swift",
    "content": "//\n//  Delete.swift\n//  Parse\n//\n//  Created by Florent Vilmart on 17-07-24.\n//  Copyright © 2017 Parse. All rights reserved.\n//\n\nimport Foundation\n\ninternal struct Delete: Encodable {\n    let __op: Operation = .delete // swiftlint:disable:this identifier_name\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Operations/Increment.swift",
    "content": "//\n//  IncrementOperation.swift\n//  Parse\n//\n//  Created by Florent Vilmart on 17-07-24.\n//  Copyright © 2017 Parse. All rights reserved.\n//\n\nimport Foundation\n\ninternal struct Increment: Encodable {\n    let __op: Operation = .increment // swiftlint:disable:this identifier_name\n    let amount: Int\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Operations/Operation.swift",
    "content": "//\n//  Operation.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 5/21/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\nenum Operation: String, Codable {\n    case add = \"Add\"\n    case addRelation = \"AddRelation\"\n    case addUnique = \"AddUnique\"\n    case delete = \"Delete\"\n    case increment = \"Increment\"\n    case remove = \"Remove\"\n    case removeRelation = \"RemoveRelation\"\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Operations/Remove.swift",
    "content": "//\n//  Remove.swift\n//  Parse\n//\n//  Created by Florent Vilmart on 17-07-24.\n//  Copyright © 2017 Parse. All rights reserved.\n//\n\nimport Foundation\n\ninternal struct Remove<T>: Encodable where T: Encodable {\n    let __op: Operation = .remove // swiftlint:disable:this identifier_name\n    let objects: [T]\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Operations/RemoveRelation.swift",
    "content": "//\n//  RemoveRelation.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/17/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\ninternal struct RemoveRelation<T>: Encodable where T: ParseObject {\n    let __op: Operation = .removeRelation // swiftlint:disable:this identifier_name\n    let objects: [Pointer<T>]\n\n    init(objects: [T]) throws {\n        self.objects = try objects.compactMap { try $0.toPointer() }\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Parse.h",
    "content": "//\n//  Parse.h\n//  Parse\n//\n//  Created by Florent Vilmart on 17-07-23.\n//  Copyright © 2017 Parse. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n//! Project version number for Parse.\nFOUNDATION_EXPORT double ParseVersionNumber;\n\n//! Project version string for Parse.\nFOUNDATION_EXPORT const unsigned char ParseVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <Parse/PublicHeader.h>\n"
  },
  {
    "path": "Sources/ParseSwift/Parse.swift",
    "content": "import Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\n\n// swiftlint:disable line_length\n\n// MARK: Internal\n\ninternal struct Parse {\n    static var configuration: ParseConfiguration!\n    static var sessionDelegate: ParseURLSessionDelegate!\n}\n\ninternal func initialize(applicationId: String,\n                         clientKey: String? = nil,\n                         masterKey: String? = nil,\n                         serverURL: URL,\n                         liveQueryServerURL: URL? = nil,\n                         requiringCustomObjectIds: Bool = false,\n                         usingTransactions: Bool = false,\n                         usingEqualQueryConstraint: Bool = false,\n                         usingPostForQuery: Bool = false,\n                         primitiveStore: ParsePrimitiveStorable? = nil,\n                         requestCachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy,\n                         cacheMemoryCapacity: Int = 512_000,\n                         cacheDiskCapacity: Int = 10_000_000,\n                         migratingFromObjcSDK: Bool = false,\n                         usingDataProtectionKeychain: Bool = false,\n                         deletingKeychainIfNeeded: Bool = false,\n                         httpAdditionalHeaders: [AnyHashable: Any]? = nil,\n                         maxConnectionAttempts: Int = 5,\n                         testing: Bool = false,\n                         authentication: ((URLAuthenticationChallenge,\n                                          (URLSession.AuthChallengeDisposition,\n                                           URLCredential?) -> Void) -> Void)? = nil) {\n    var configuration = ParseConfiguration(applicationId: applicationId,\n                                           clientKey: clientKey,\n                                           masterKey: masterKey,\n                                           serverURL: serverURL,\n                                           liveQueryServerURL: liveQueryServerURL,\n                                           requiringCustomObjectIds: requiringCustomObjectIds,\n                                           usingTransactions: usingTransactions,\n                                           usingEqualQueryConstraint: usingEqualQueryConstraint,\n                                           usingPostForQuery: usingPostForQuery,\n                                           primitiveStore: primitiveStore,\n                                           requestCachePolicy: requestCachePolicy,\n                                           cacheMemoryCapacity: cacheMemoryCapacity,\n                                           cacheDiskCapacity: cacheDiskCapacity,\n                                           usingDataProtectionKeychain: usingDataProtectionKeychain,\n                                           deletingKeychainIfNeeded: deletingKeychainIfNeeded,\n                                           httpAdditionalHeaders: httpAdditionalHeaders,\n                                           maxConnectionAttempts: maxConnectionAttempts,\n                                           authentication: authentication)\n    configuration.isMigratingFromObjcSDK = migratingFromObjcSDK\n    configuration.isTestingSDK = testing\n    initialize(configuration: configuration)\n}\n\ninternal func deleteKeychainIfNeeded() {\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    // Clear items out of the Keychain on app first run.\n    if UserDefaults.standard.object(forKey: ParseConstants.bundlePrefix) == nil {\n        if Parse.configuration.isDeletingKeychainIfNeeded {\n            try? KeychainStore.old.deleteAll()\n            try? KeychainStore.shared.deleteAll()\n        }\n        Parse.configuration.keychainAccessGroup = .init()\n        clearCache()\n        // This is no longer the first run\n        UserDefaults.standard.setValue(String(ParseConstants.bundlePrefix),\n                                       forKey: ParseConstants.bundlePrefix)\n        UserDefaults.standard.synchronize()\n    }\n    #endif\n}\n\n// MARK: Public - All Platforms\n\n/// The current `ParseConfiguration` for the ParseSwift client.\npublic var configuration: ParseConfiguration {\n    Parse.configuration\n}\n\n/**\n Configure the Parse Swift client. This should only be used when starting your app. Typically in the\n `application(... didFinishLaunchingWithOptions launchOptions...)`.\n - parameter configuration: The Parse configuration.\n - important: It is recomended to only specify `masterKey` when using the SDK on a server. Do not use this key on the client.\n - note: Setting `usingPostForQuery` to **true**  will require all queries to access the server instead of following the `requestCachePolicy`.\n - warning: `usingTransactions` is experimental.\n - warning: Setting `usingDataProtectionKeychain` to **true** is known to cause issues in Playgrounds or in\n situtations when apps do not have credentials to setup a Keychain.\n */\npublic func initialize(configuration: ParseConfiguration) {\n    Parse.configuration = configuration\n    Parse.sessionDelegate = ParseURLSessionDelegate(callbackQueue: .main,\n                                                    authentication: configuration.authentication)\n    URLSession.updateParseURLSession()\n    deleteKeychainIfNeeded()\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    if let keychainAccessGroup = ParseKeychainAccessGroup.current {\n        Parse.configuration.keychainAccessGroup = keychainAccessGroup\n    } else {\n        ParseKeychainAccessGroup.current = ParseKeychainAccessGroup()\n    }\n    #endif\n\n    do {\n        let previousSDKVersion = try ParseVersion(ParseVersion.current)\n        let currentSDKVersion = try ParseVersion(ParseConstants.version)\n        let oneNineEightSDKVersion = try ParseVersion(\"1.9.8\")\n\n        // All migrations from previous versions to current should occur here:\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        if previousSDKVersion < oneNineEightSDKVersion {\n            // Old macOS Keychain cannot be used because it is global to all apps.\n            _ = KeychainStore.old\n            try? KeychainStore.shared.copy(KeychainStore.old,\n                                           oldAccessGroup: configuration.keychainAccessGroup,\n                                           newAccessGroup: configuration.keychainAccessGroup)\n            // Need to delete the old Keychain because a new one is created with bundleId.\n            try? KeychainStore.old.deleteAll()\n        }\n        #endif\n        if currentSDKVersion > previousSDKVersion {\n            ParseVersion.current = currentSDKVersion.string\n        }\n    } catch {\n        // Migrate old installations made with ParseSwift < 1.3.0\n        if let currentInstallation = BaseParseInstallation.current {\n            if currentInstallation.objectId == nil {\n                BaseParseInstallation.deleteCurrentContainerFromKeychain()\n                // Prepare installation\n                BaseParseInstallation.createNewInstallationIfNeeded()\n            }\n        } else {\n            // Prepare installation\n            BaseParseInstallation.createNewInstallationIfNeeded()\n        }\n        ParseVersion.current = ParseConstants.version\n    }\n\n    // Migrate installations with installationId, but missing\n    // currentInstallation, ParseSwift < 1.9.10\n    if let installationId = BaseParseInstallation.currentContainer.installationId,\n       BaseParseInstallation.currentContainer.currentInstallation == nil {\n        if let foundInstallation = try? BaseParseInstallation\n            .query(\"installationId\" == installationId)\n            .first(options: [.cachePolicy(.reloadIgnoringLocalCacheData)]) {\n            let newContainer = CurrentInstallationContainer<BaseParseInstallation>(currentInstallation: foundInstallation,\n                                                                                   installationId: installationId)\n            BaseParseInstallation.currentContainer = newContainer\n            BaseParseInstallation.saveCurrentContainerToKeychain()\n        }\n    }\n    BaseParseInstallation.createNewInstallationIfNeeded()\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    if configuration.isMigratingFromObjcSDK {\n        if let objcParseKeychain = KeychainStore.objectiveC {\n            guard let installationId: String = objcParseKeychain.objectObjectiveC(forKey: \"installationId\"),\n                  BaseParseInstallation.current?.installationId != installationId else {\n                return\n            }\n            var updatedInstallation = BaseParseInstallation.current\n            updatedInstallation?.installationId = installationId\n            BaseParseInstallation.currentContainer.installationId = installationId\n            BaseParseInstallation.currentContainer.currentInstallation = updatedInstallation\n            BaseParseInstallation.saveCurrentContainerToKeychain()\n        }\n    }\n    #endif\n}\n\n/**\n Configure the Parse Swift client. This should only be used when starting your app. Typically in the\n `application(... didFinishLaunchingWithOptions launchOptions...)`.\n - parameter applicationId: The application id for your Parse application.\n - parameter clientKey: The client key for your Parse application.\n - parameter masterKey: The master key for your Parse application. This key should only be\n specified when using the SDK on a server.\n - parameter serverURL: The server URL to connect to Parse Server.\n - parameter liveQueryServerURL: The live query server URL to connect to Parse Server.\n - parameter requiringCustomObjectIds: Requires `objectId`'s to be created on the client\n side for each object. Must be enabled on the server to work.\n - parameter usingTransactions: Use transactions when saving/updating multiple objects.\n - parameter usingEqualQueryConstraint: Use the **$eq** query constraint when querying.\n - parameter usingPostForQuery: Use **POST** instead of **GET** when making query calls.\n Defaults to **false**.\n - parameter primitiveStore: A key/value store that conforms to the `ParseKeyValueStore`\n protocol. Defaults to `nil` in which one will be created an memory, but never persisted. For Linux, this\n this is the only store available since there is no Keychain. Linux, Android, and Windows users should\n replace this store with an encrypted one.\n - parameter requestCachePolicy: The default caching policy for all http requests that determines\n when to return a response from the cache. Defaults to `useProtocolCachePolicy`. See Apple's [documentation](https://developer.apple.com/documentation/foundation/url_loading_system/accessing_cached_data)\n for more info.\n - parameter cacheMemoryCapacity: The memory capacity of the cache, in bytes. Defaults to 512KB.\n - parameter cacheDiskCapacity: The disk capacity of the cache, in bytes. Defaults to 10MB.\n - parameter usingDataProtectionKeychain: Sets `kSecUseDataProtectionKeychain` to **true**. See Apple's [documentation](https://developer.apple.com/documentation/security/ksecusedataprotectionkeychain)\n for more info. Defaults to **false**.\n - parameter deletingKeychainIfNeeded: Deletes the Parse Keychain when the app is running for the first time.\n Defaults to **false**.\n - parameter httpAdditionalHeaders: A dictionary of additional headers to send with requests. See Apple's\n [documentation](https://developer.apple.com/documentation/foundation/urlsessionconfiguration/1411532-httpadditionalheaders)\n for more info.\n - parameter maxConnectionAttempts: Maximum number of times to try to connect to Parse Server.\n Defaults to 5.\n - parameter parseFileTransfer: Override the default transfer behavior for `ParseFile`'s.\n Allows for direct uploads to other file storage providers.\n - parameter authentication: A callback block that will be used to receive/accept/decline network challenges.\n Defaults to `nil` in which the SDK will use the default OS authentication methods for challenges.\n It should have the following argument signature: `(challenge: URLAuthenticationChallenge,\n completionHandler: (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) -> Void`.\n See Apple's [documentation](https://developer.apple.com/documentation/foundation/urlsessiontaskdelegate/1411595-urlsession) for more for details.\n - important: It is recomended to only specify `masterKey` when using the SDK on a server. Do not use this key on the client.\n - note: Setting `usingPostForQuery` to **true**  will require all queries to access the server instead of following the `requestCachePolicy`.\n - warning: `usingTransactions` is experimental.\n - warning: Setting `usingDataProtectionKeychain` to **true** is known to cause issues in Playgrounds or in\n situtations when apps do not have credentials to setup a Keychain.\n */\npublic func initialize(\n    applicationId: String,\n    clientKey: String? = nil,\n    masterKey: String? = nil,\n    serverURL: URL,\n    liveQueryServerURL: URL? = nil,\n    requiringCustomObjectIds: Bool = false,\n    usingTransactions: Bool = false,\n    usingEqualQueryConstraint: Bool = false,\n    usingPostForQuery: Bool = false,\n    primitiveStore: ParsePrimitiveStorable? = nil,\n    requestCachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy,\n    cacheMemoryCapacity: Int = 512_000,\n    cacheDiskCapacity: Int = 10_000_000,\n    usingDataProtectionKeychain: Bool = false,\n    deletingKeychainIfNeeded: Bool = false,\n    httpAdditionalHeaders: [AnyHashable: Any]? = nil,\n    maxConnectionAttempts: Int = 5,\n    parseFileTransfer: ParseFileTransferable? = nil,\n    authentication: ((URLAuthenticationChallenge,\n                      (URLSession.AuthChallengeDisposition,\n                       URLCredential?) -> Void) -> Void)? = nil\n) {\n    let configuration = ParseConfiguration(applicationId: applicationId,\n                                           clientKey: clientKey,\n                                           masterKey: masterKey,\n                                           serverURL: serverURL,\n                                           liveQueryServerURL: liveQueryServerURL,\n                                           requiringCustomObjectIds: requiringCustomObjectIds,\n                                           usingTransactions: usingTransactions,\n                                           usingEqualQueryConstraint: usingEqualQueryConstraint,\n                                           usingPostForQuery: usingPostForQuery,\n                                           primitiveStore: primitiveStore,\n                                           requestCachePolicy: requestCachePolicy,\n                                           cacheMemoryCapacity: cacheMemoryCapacity,\n                                           cacheDiskCapacity: cacheDiskCapacity,\n                                           usingDataProtectionKeychain: usingDataProtectionKeychain,\n                                           deletingKeychainIfNeeded: deletingKeychainIfNeeded,\n                                           httpAdditionalHeaders: httpAdditionalHeaders,\n                                           maxConnectionAttempts: maxConnectionAttempts,\n                                           parseFileTransfer: parseFileTransfer,\n                                           authentication: authentication)\n    initialize(configuration: configuration)\n}\n\n/**\n Configure the Parse Swift client. This should only be used when starting your app. Typically in the\n `application(... didFinishLaunchingWithOptions launchOptions...)`.\n - parameter applicationId: The application id for your Parse application.\n - parameter clientKey: The client key for your Parse application.\n - parameter masterKey: The master key for your Parse application. This key should only be\n specified when using the SDK on a server.\n - parameter serverURL: The server URL to connect to Parse Server.\n - parameter liveQueryServerURL: The live query server URL to connect to Parse Server.\n - parameter allowingCustomObjectIds: Requires `objectId`'s to be created on the client\n side for each object. Must be enabled on the server to work.\n - parameter usingTransactions: Use transactions when saving/updating multiple objects.\n - parameter usingEqualQueryConstraint: Use the **$eq** query constraint when querying.\n - parameter usingPostForQuery: Use **POST** instead of **GET** when making query calls.\n Defaults to **false**.\n - parameter keyValueStore: A key/value store that conforms to the `ParseKeyValueStore`\n protocol. Defaults to `nil` in which one will be created an memory, but never persisted. For Linux, this\n this is the only store available since there is no Keychain. Linux, Android, and Windows users should\n replace this store with an encrypted one.\n - parameter requestCachePolicy: The default caching policy for all http requests that determines\n when to return a response from the cache. Defaults to `useProtocolCachePolicy`. See Apple's [documentation](https://developer.apple.com/documentation/foundation/url_loading_system/accessing_cached_data)\n for more info.\n - parameter cacheMemoryCapacity: The memory capacity of the cache, in bytes. Defaults to 512KB.\n - parameter cacheDiskCapacity: The disk capacity of the cache, in bytes. Defaults to 10MB.\n - parameter usingDataProtectionKeychain: Sets `kSecUseDataProtectionKeychain` to **true**. See Apple's [documentation](https://developer.apple.com/documentation/security/ksecusedataprotectionkeychain)\n for more info. Defaults to **false**.\n - parameter deletingKeychainIfNeeded: Deletes the Parse Keychain when the app is running for the first time.\n Defaults to **false**.\n - parameter httpAdditionalHeaders: A dictionary of additional headers to send with requests. See Apple's\n [documentation](https://developer.apple.com/documentation/foundation/urlsessionconfiguration/1411532-httpadditionalheaders)\n for more info.\n - parameter maxConnectionAttempts: Maximum number of times to try to connect to Parse Server.\n Defaults to 5.\n - parameter parseFileTransfer: Override the default transfer behavior for `ParseFile`'s.\n Allows for direct uploads to other file storage providers.\n - parameter authentication: A callback block that will be used to receive/accept/decline network challenges.\n Defaults to `nil` in which the SDK will use the default OS authentication methods for challenges.\n It should have the following argument signature: `(challenge: URLAuthenticationChallenge,\n completionHandler: (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) -> Void`.\n See Apple's [documentation](https://developer.apple.com/documentation/foundation/urlsessiontaskdelegate/1411595-urlsession) for more for details.\n - important: It is recomended to only specify `masterKey` when using the SDK on a server. Do not use this key on the client.\n - note: Setting `usingPostForQuery` to **true**  will require all queries to access the server instead of following the `requestCachePolicy`.\n - warning: `usingTransactions` is experimental.\n - warning: Setting `usingDataProtectionKeychain` to **true** is known to cause issues in Playgrounds or in\n situtations when apps do not have credentials to setup a Keychain.\n */\n@available(*, deprecated, message: \"Change: allowingCustomObjectIds->requiringCustomObjectIds and keyValueStore->primitiveStore\")\npublic func initialize(\n    applicationId: String,\n    clientKey: String? = nil,\n    masterKey: String? = nil,\n    serverURL: URL,\n    liveQueryServerURL: URL? = nil,\n    allowingCustomObjectIds: Bool,\n    usingTransactions: Bool = false,\n    usingEqualQueryConstraint: Bool = false,\n    usingPostForQuery: Bool = false,\n    keyValueStore: ParsePrimitiveStorable? = nil,\n    requestCachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy,\n    cacheMemoryCapacity: Int = 512_000,\n    cacheDiskCapacity: Int = 10_000_000,\n    usingDataProtectionKeychain: Bool = false,\n    deletingKeychainIfNeeded: Bool = false,\n    httpAdditionalHeaders: [AnyHashable: Any]? = nil,\n    maxConnectionAttempts: Int = 5,\n    parseFileTransfer: ParseFileTransferable? = nil,\n    authentication: ((URLAuthenticationChallenge,\n                      (URLSession.AuthChallengeDisposition,\n                       URLCredential?) -> Void) -> Void)? = nil\n) {\n    initialize(applicationId: applicationId,\n               clientKey: clientKey,\n               masterKey: masterKey,\n               serverURL: serverURL,\n               liveQueryServerURL: liveQueryServerURL,\n               requiringCustomObjectIds: allowingCustomObjectIds,\n               usingTransactions: usingTransactions,\n               usingEqualQueryConstraint: usingEqualQueryConstraint,\n               usingPostForQuery: usingPostForQuery,\n               primitiveStore: keyValueStore,\n               requestCachePolicy: requestCachePolicy,\n               cacheMemoryCapacity: cacheMemoryCapacity,\n               cacheDiskCapacity: cacheDiskCapacity,\n               usingDataProtectionKeychain: usingDataProtectionKeychain,\n               deletingKeychainIfNeeded: deletingKeychainIfNeeded,\n               httpAdditionalHeaders: httpAdditionalHeaders,\n               maxConnectionAttempts: maxConnectionAttempts,\n               parseFileTransfer: parseFileTransfer,\n               authentication: authentication)\n}\n\n/**\n Configure the Parse Swift client. This should only be used when starting your app. Typically in the\n `application(... didFinishLaunchingWithOptions launchOptions...)`.\n - parameter applicationId: The application id for your Parse application.\n - parameter clientKey: The client key for your Parse application.\n - parameter masterKey: The master key for your Parse application. This key should only be\n specified when using the SDK on a server.\n - parameter serverURL: The server URL to connect to Parse Server.\n - parameter liveQueryServerURL: The live query server URL to connect to Parse Server.\n - parameter allowingCustomObjectIds: Requires `objectId`'s to be created on the client\n side for each object. Must be enabled on the server to work.\n - parameter usingTransactions: Use transactions when saving/updating multiple objects.\n - parameter usingEqualQueryConstraint: Use the **$eq** query constraint when querying.\n - parameter usingPostForQuery: Use **POST** instead of **GET** when making query calls.\n Defaults to **false**.\n - parameter keyValueStore: A key/value store that conforms to the `ParseKeyValueStore`\n protocol. Defaults to `nil` in which one will be created an memory, but never persisted. For Linux, this\n this is the only store available since there is no Keychain. Linux, Android, and Windows users should\n replace this store with an encrypted one.\n - parameter requestCachePolicy: The default caching policy for all http requests that determines\n when to return a response from the cache. Defaults to `useProtocolCachePolicy`. See Apple's [documentation](https://developer.apple.com/documentation/foundation/url_loading_system/accessing_cached_data)\n for more info.\n - parameter cacheMemoryCapacity: The memory capacity of the cache, in bytes. Defaults to 512KB.\n - parameter cacheDiskCapacity: The disk capacity of the cache, in bytes. Defaults to 10MB.\n - parameter migratingFromObjcSDK: If your app previously used the iOS Objective-C SDK, setting this value\n to **true** will attempt to migrate relevant data stored in the Keychain to ParseSwift. Defaults to **false**.\n - parameter usingDataProtectionKeychain: Sets `kSecUseDataProtectionKeychain` to **true**. See Apple's [documentation](https://developer.apple.com/documentation/security/ksecusedataprotectionkeychain)\n for more info. Defaults to **false**.\n - parameter deletingKeychainIfNeeded: Deletes the Parse Keychain when the app is running for the first time.\n Defaults to **false**.\n - parameter httpAdditionalHeaders: A dictionary of additional headers to send with requests. See Apple's\n [documentation](https://developer.apple.com/documentation/foundation/urlsessionconfiguration/1411532-httpadditionalheaders)\n for more info.\n - parameter maxConnectionAttempts: Maximum number of times to try to connect to Parse Server.\n Defaults to 5.\n - parameter parseFileTransfer: Override the default transfer behavior for `ParseFile`'s.\n Allows for direct uploads to other file storage providers.\n - parameter authentication: A callback block that will be used to receive/accept/decline network challenges.\n Defaults to `nil` in which the SDK will use the default OS authentication methods for challenges.\n It should have the following argument signature: `(challenge: URLAuthenticationChallenge,\n completionHandler: (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) -> Void`.\n See Apple's [documentation](https://developer.apple.com/documentation/foundation/urlsessiontaskdelegate/1411595-urlsession) for more for details.\n - important: It is recomended to only specify `masterKey` when using the SDK on a server. Do not use this key on the client.\n - note: Setting `usingPostForQuery` to **true**  will require all queries to access the server instead of following the `requestCachePolicy`.\n - warning: `usingTransactions` is experimental.\n - warning: Setting `usingDataProtectionKeychain` to **true** is known to cause issues in Playgrounds or in\n situtations when apps do not have credentials to setup a Keychain.\n */\n@available(*, deprecated, message: \"Remove the migratingFromObjcSDK argument\")\npublic func initialize(\n    applicationId: String,\n    clientKey: String? = nil,\n    masterKey: String? = nil,\n    serverURL: URL,\n    liveQueryServerURL: URL? = nil,\n    allowingCustomObjectIds: Bool = false,\n    usingTransactions: Bool = false,\n    usingEqualQueryConstraint: Bool = false,\n    usingPostForQuery: Bool = false,\n    keyValueStore: ParseKeyValueStore? = nil,\n    requestCachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy,\n    cacheMemoryCapacity: Int = 512_000,\n    cacheDiskCapacity: Int = 10_000_000,\n    migratingFromObjcSDK: Bool,\n    usingDataProtectionKeychain: Bool = false,\n    deletingKeychainIfNeeded: Bool = false,\n    httpAdditionalHeaders: [AnyHashable: Any]? = nil,\n    maxConnectionAttempts: Int = 5,\n    parseFileTransfer: ParseFileTransferable? = nil,\n    authentication: ((URLAuthenticationChallenge,\n                      (URLSession.AuthChallengeDisposition,\n                       URLCredential?) -> Void) -> Void)? = nil\n) {\n    var configuration = ParseConfiguration(applicationId: applicationId,\n                                           clientKey: clientKey,\n                                           masterKey: masterKey,\n                                           serverURL: serverURL,\n                                           liveQueryServerURL: liveQueryServerURL,\n                                           requiringCustomObjectIds: allowingCustomObjectIds,\n                                           usingTransactions: usingTransactions,\n                                           usingEqualQueryConstraint: usingEqualQueryConstraint,\n                                           usingPostForQuery: usingPostForQuery,\n                                           primitiveStore: keyValueStore,\n                                           requestCachePolicy: requestCachePolicy,\n                                           cacheMemoryCapacity: cacheMemoryCapacity,\n                                           cacheDiskCapacity: cacheDiskCapacity,\n                                           usingDataProtectionKeychain: usingDataProtectionKeychain,\n                                           deletingKeychainIfNeeded: deletingKeychainIfNeeded,\n                                           httpAdditionalHeaders: httpAdditionalHeaders,\n                                           maxConnectionAttempts: maxConnectionAttempts,\n                                           parseFileTransfer: parseFileTransfer,\n                                           authentication: authentication)\n    configuration.isMigratingFromObjcSDK = migratingFromObjcSDK\n    initialize(configuration: configuration)\n}\n\n/**\n Update the authentication callback.\n - parameter authentication: A callback block that will be used to receive/accept/decline network challenges.\n Defaults to `nil` in which the SDK will use the default OS authentication methods for challenges.\n It should have the following argument signature: `(challenge: URLAuthenticationChallenge,\n completionHandler: (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) -> Void`.\n See Apple's [documentation](https://developer.apple.com/documentation/foundation/urlsessiontaskdelegate/1411595-urlsession) for more for details.\n */\npublic func updateAuthentication(_ authentication: ((URLAuthenticationChallenge,\n                                                     (URLSession.AuthChallengeDisposition,\n                                                      URLCredential?) -> Void) -> Void)?) {\n    Parse.sessionDelegate = ParseURLSessionDelegate(callbackQueue: .main,\n                                                    authentication: authentication)\n    URLSession.updateParseURLSession()\n}\n\n/**\n Manually remove all stored cache.\n - note: The OS typically handles this automatically.\n */\npublic func clearCache() {\n    URLSession.parse.configuration.urlCache?.removeAllCachedResponses()\n}\n\n// MARK: Public - Apple Platforms\n\n#if !os(Linux) && !os(Android) && !os(Windows)\n\n/**\n Delete the Parse iOS Objective-C SDK Keychain from the device.\n - note: ParseSwift uses a different Keychain. After migration, the iOS Objective-C SDK Keychain is no longer needed.\n - warning: The keychain cannot be recovered after deletion.\n */\npublic func deleteObjectiveCKeychain() throws {\n    try KeychainStore.objectiveC?.deleteAllObjectiveC()\n}\n\n/**\n Sets all of the items in the Parse Keychain to a specific access group.\n Apps in the same access group can share Keychain items. See Apple's\n  [documentation](https://developer.apple.com/documentation/security/ksecattraccessgroup)\n  for more information.\n - parameter accessGroup: The name of the access group.\n - parameter synchronizeAcrossDevices: **true** to synchronize all necessary Parse Keychain items to\n other devices using iCloud. See Apple's [documentation](https://developer.apple.com/documentation/security/ksecattrsynchronizable)\n for more information. **false** to disable synchronization.\n - throws: An error of type `ParseError`.\n - returns: **true** if the Keychain was moved to the new `accessGroup`, **false** otherwise.\n - important: Setting `synchronizeAcrossDevices == true` requires `accessGroup` to be\n set to a valid [keychain group](https://developer.apple.com/documentation/security/ksecattraccessgroup).\n */\n@discardableResult public func setAccessGroup(_ accessGroup: String?,\n                                              synchronizeAcrossDevices: Bool) throws -> Bool {\n    if synchronizeAcrossDevices && accessGroup == nil {\n        throw ParseError(code: .unknownError,\n                         message: \"\\\"accessGroup\\\" must be set to a valid string when \\\"synchronizeAcrossDevices == true\\\"\")\n    }\n    guard let currentAccessGroup = ParseKeychainAccessGroup.current else {\n        throw ParseError(code: .unknownError,\n                         message: \"Problem unwrapping the current access group. Did you initialize the SDK before calling this method?\")\n    }\n    let newKeychainAccessGroup = ParseKeychainAccessGroup(accessGroup: accessGroup,\n                                                          isSyncingKeychainAcrossDevices: synchronizeAcrossDevices)\n    guard newKeychainAccessGroup != currentAccessGroup else {\n        ParseKeychainAccessGroup.current = newKeychainAccessGroup\n        return true\n    }\n    do {\n        try KeychainStore.shared.copy(KeychainStore.shared,\n                                      oldAccessGroup: currentAccessGroup,\n                                      newAccessGroup: newKeychainAccessGroup)\n        ParseKeychainAccessGroup.current = newKeychainAccessGroup\n    } catch {\n        ParseKeychainAccessGroup.current = currentAccessGroup\n        throw error\n    }\n    return true\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/ParseConstants.swift",
    "content": "//\n//  ParseConstants.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/7/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\nenum ParseConstants {\n    static let sdk = \"swift\"\n    static let version = \"4.14.2\"\n    static let fileManagementDirectory = \"parse/\"\n    static let fileManagementPrivateDocumentsDirectory = \"Private Documents/\"\n    static let fileManagementLibraryDirectory = \"Library/\"\n    static let fileDownloadsDirectory = \"Downloads\"\n    static let bundlePrefix = \"com.parse.ParseSwift\"\n    static let batchLimit = 50\n    static let includeAllKey = \"*\"\n    #if os(iOS)\n    static let deviceType = \"ios\"\n    #elseif os(macOS)\n    static let deviceType = \"osx\"\n    #elseif os(tvOS)\n    static let deviceType = \"tvos\"\n    #elseif os(watchOS)\n    static let deviceType = \"applewatch\"\n    #elseif os(Linux)\n    static let deviceType = \"linux\"\n    #elseif os(Android)\n    static let deviceType = \"android\"\n    #elseif os(Windows)\n    static let deviceType = \"windows\"\n    #endif\n}\n\nenum Method: String {\n    case save, create, replace, update\n}\n\n/**\n The types of Parse Hook Triggers available.\n */\npublic enum ParseHookTriggerType: String, Codable {\n    /// Occurs before login of a `ParseUser`.\n    case beforeLogin\n    /// Occurs after login of a `ParseUser`.\n    case afterLogin\n    /// Occurs after logout of a `ParseUser`.\n    case afterLogout\n    /// Occurs before saving a `ParseObject` or `ParseFile`.\n    case beforeSave\n    /// Occurs after saving a `ParseObject` or `ParseFile`.\n    case afterSave\n    /// Occurs before deleting a `ParseObject` or `ParseFile`.\n    case beforeDelete\n    /// Occurs after deleting a `ParseObject` or `ParseFile`.\n    case afterDelete\n    /// Occurs before finding a `ParseObject`.\n    case beforeFind\n    /// Occurs after finding a `ParseObject`.\n    case afterFind\n    /// Occurs before a `ParseLiveQuery` connection is made.\n    case beforeConnect\n    /// Occurs before a `ParseLiveQuery` subscription is made.\n    case beforeSubscribe\n    /// Occurs after a `ParseLiveQuery` event.\n    case afterEvent\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/CloudObservable.swift",
    "content": "//\n//  CloudObservable.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 7/11/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n#if canImport(SwiftUI)\nimport Foundation\n\n/**\n This protocol describes the interface for creating a view model for `ParseCloud` functions and jobs.\n You can use this protocol on any custom class of yours, instead of `CloudViewModel`, if it fits your use case better.\n */\npublic protocol CloudObservable: ObservableObject {\n\n    /// The `ParseObject` associated with this view model.\n    associatedtype CloudCodeType: ParseCloudable\n\n    /**\n     Creates a new view model that can be used to handle updates.\n     */\n    init(cloudCode: CloudCodeType)\n\n    /**\n     Calls a Cloud Code function *asynchronously* and updates the view model\n     when the result of it is execution.\n        - parameter options: A set of header options sent to the server. Defaults to an empty set.\n    */\n    func runFunction(options: API.Options)\n\n    /**\n     Starts a Cloud Code Job *asynchronously* and updates the view model with the result and jobStatusId of the job.\n        - parameter options: A set of header options sent to the server. Defaults to an empty set.\n    */\n    func startJob(options: API.Options)\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/Deletable.swift",
    "content": "//\n//  Deletable.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/27/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\npublic protocol Deletable: Codable {\n    associatedtype DeletingType\n\n    func delete(options: API.Options) throws -> DeletingType\n    func delete() throws -> DeletingType\n}\n\nextension Deletable {\n    public func delete() throws -> DeletingType {\n        try delete(options: [])\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/Fetchable.swift",
    "content": "//\n//  Fetchable.swift\n//  ParseSwift\n//\n//  Created by Florent Vilmart on 17-07-24.\n//  Copyright © 2020 Parse. All rights reserved.\n//\n\nimport Foundation\n#if canImport(Combine)\nimport Combine\n#endif\n\npublic protocol Fetchable: Decodable {\n    associatedtype FetchingType\n\n    func fetch(includeKeys: [String]?, options: API.Options) throws -> FetchingType\n    func fetch() throws -> FetchingType\n}\n\npublic extension Fetchable {\n    func fetch() throws -> FetchingType {\n        try fetch(includeKeys: nil, options: [])\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/Fileable.swift",
    "content": "//\n//  Fileable.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 12/27/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\nprotocol Fileable: ParseEncodable, ParseTypeable, Identifiable {\n    var type: String { get }\n    var name: String { get set }\n    var url: URL? { get set }\n}\n\nextension Fileable {\n    var isSaved: Bool {\n        return url != nil\n    }\n\n    mutating func hash(into hasher: inout Hasher) {\n        if let url = url {\n            hasher.combine(url)\n        } else {\n            hasher.combine(self.id)\n        }\n    }\n\n    public static func == (lhs: Self, rhs: Self) -> Bool {\n        guard let lURL = lhs.url,\n              let rURL = rhs.url else {\n            return lhs.id == rhs.id\n        }\n        return lURL == rURL\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/Objectable.swift",
    "content": "//\n//  Objectable.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 10/4/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/// The base protocol for a `ParseObject`.\n/// - note: You should not use this directly and instead use `ParseObject`.\npublic protocol Objectable: ParseEncodable, Decodable {\n    /**\n    The class name of the object.\n    */\n    static var className: String { get }\n\n    /**\n    The id of the object.\n    */\n    var objectId: String? { get set }\n\n    /**\n    When the object was created.\n    */\n    var createdAt: Date? { get set }\n\n    /**\n    When the object was last updated.\n    */\n    var updatedAt: Date? { get set }\n\n    /**\n    The ACL for this object.\n    */\n    var ACL: ParseACL? { get set }\n}\n\nextension Objectable {\n    /**\n    The class name of the object.\n    */\n    public static var className: String {\n        let classType = \"\\(type(of: self))\"\n        return classType.components(separatedBy: \".\").first ?? \"\" // strip .Type\n    }\n\n    /**\n    The class name of the object.\n    */\n    public var className: String {\n        return Self.className\n    }\n\n    static func createHash(_ object: Encodable) throws -> String {\n        let encoded = try ParseCoding.parseEncoder().encode(object)\n        guard let hashString = String(data: encoded, encoding: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Could not create hash\")\n        }\n        return hashString\n    }\n}\n\n// MARK: Convenience\nextension Objectable {\n    var endpoint: API.Endpoint {\n        if let objectId = objectId {\n            return .object(className: className, objectId: objectId)\n        }\n\n        return .objects(className: className)\n    }\n\n    /// Specifies if a `ParseObject` has been saved.\n    public var isSaved: Bool {\n        if !Parse.configuration.isRequiringCustomObjectIds {\n            return objectId != nil\n        } else {\n            return objectId != nil && createdAt != nil\n        }\n    }\n\n    func toPointer() throws -> PointerType {\n        return try PointerType(self)\n    }\n\n    func endpoint(_ method: API.Method) -> API.Endpoint {\n        if !Parse.configuration.isRequiringCustomObjectIds || method != .POST {\n            return endpoint\n        } else {\n            return .objects(className: className)\n        }\n    }\n}\n\ninternal struct BaseObjectable: Objectable {\n    var objectId: String?\n\n    var createdAt: Date?\n\n    var updatedAt: Date?\n\n    var ACL: ParseACL?\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/ParseCloudable+async.swift",
    "content": "//\n//  ParseCloudable+async.swift\n//  ParseCloudable+async\n//\n//  Created by Corey Baker on 8/6/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n\npublic extension ParseCloudable {\n\n    // MARK: Aysnc/Await\n\n    /**\n     Calls a Cloud Code function *asynchronously* and returns a result of it is execution.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: The return type.\n     - throws: An error of type `ParseError`.\n    */\n    func runFunction(options: API.Options = []) async throws -> ReturnType {\n        try await withCheckedThrowingContinuation { continuation in\n            self.runFunction(options: options,\n                             completion: continuation.resume)\n        }\n    }\n\n    /**\n     Starts a Cloud Code Job *asynchronously* and returns a result with the jobStatusId of the job.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: The return type.\n     - throws: An error of type `ParseError`.\n    */\n    func startJob(options: API.Options = []) async throws -> ReturnType {\n        try await withCheckedThrowingContinuation { continuation in\n            self.startJob(options: options,\n                          completion: continuation.resume)\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/ParseCloudable+combine.swift",
    "content": "//\n//  ParseCloudable+combine.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/29/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\npublic extension ParseCloudable {\n\n    // MARK: Combine\n\n    /**\n     Calls a Cloud Code function *asynchronously* and returns a result of it is execution.\n     Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n    */\n    func runFunctionPublisher(options: API.Options = []) -> Future<ReturnType, ParseError> {\n        Future { promise in\n            self.runFunction(options: options,\n                             completion: promise)\n        }\n    }\n\n    /**\n     Starts a Cloud Code Job *asynchronously* and returns a result with the jobStatusId of the job.\n     Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n    */\n    func startJobPublisher(options: API.Options = []) -> Future<ReturnType, ParseError> {\n        Future { promise in\n            self.startJob(options: options,\n                          completion: promise)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/ParseCloudable.swift",
    "content": "//\n//  ParseCloudable.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 12/29/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\npublic protocol ParseCloudTypeable: ParseEncodable {}\n\n/**\n Objects that conform to the `ParseCloud` protocol are able to call Parse Cloud Functions and Jobs.\n An object should be instantiated for each function and job type. When conforming to\n `ParseCloud`, any properties added will be passed as parameters to your Cloud Function or Job.\n*/\n@available(*, deprecated, renamed: \"ParseCloudable\")\npublic typealias ParseCloud = ParseCloudable\n\n/**\n Objects that conform to the `ParseCloudable` protocol are able to call Parse Cloud Functions and Jobs.\n An object should be instantiated for each function and job type. When conforming to\n `ParseCloudable`, any properties added will be passed as parameters to your Cloud Function or Job.\n*/\npublic protocol ParseCloudable: ParseCloudTypeable, Hashable {\n\n    associatedtype ReturnType: Decodable\n    /**\n     The name of the function or job.\n    */\n    var functionJobName: String { get set }\n\n}\n\n// MARK: Functions\nextension ParseCloudable {\n\n    /**\n     Calls a Cloud Code function *synchronously* and returns a result of it is execution.\n        - parameter options: A set of header options sent to the server. Defaults to an empty set.\n        - returns: Returns a `Decodable` type.\n        - throws: An error of type `ParseError`.\n    */\n    public func runFunction(options: API.Options = []) throws -> ReturnType {\n        try runFunctionCommand().execute(options: options)\n    }\n\n    /**\n     Calls a Cloud Code function *asynchronously* and returns a result of it is execution.\n        - parameter options: A set of header options sent to the server. Defaults to an empty set.\n        - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n        - parameter completion: A block that will be called when the Cloud Code completes or fails.\n        It should have the following argument signature: `(Result<ReturnType, ParseError>)`.\n    */\n    public func runFunction(options: API.Options = [],\n                            callbackQueue: DispatchQueue = .main,\n                            completion: @escaping (Result<ReturnType, ParseError>) -> Void) {\n        runFunctionCommand()\n            .executeAsync(options: options, callbackQueue: callbackQueue) { result in\n                completion(result)\n            }\n    }\n\n    internal func runFunctionCommand() -> API.Command<Self, ReturnType> {\n        API.Command(method: .POST,\n                    path: .functions(name: functionJobName),\n                    body: self) { (data) -> ReturnType in\n            let response = try ParseCoding.jsonDecoder().decode(AnyResultResponse<ReturnType>.self, from: data)\n            return response.result\n        }\n    }\n}\n\n// MARK: Jobs\nextension ParseCloudable {\n    /**\n     Starts a Cloud Code Job *synchronously* and returns a result with the jobStatusId of the job.\n          - parameter options: A set of header options sent to the server. Defaults to an empty set.\n          - returns: Returns a `Decodable` type.\n    */\n    public func startJob(options: API.Options = []) throws -> ReturnType {\n        try startJobCommand().execute(options: options)\n    }\n\n    /**\n     Starts a Cloud Code Job *asynchronously* and returns a result with the jobStatusId of the job.\n        - parameter options: A set of header options sent to the server. Defaults to an empty set.\n        - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n        - parameter completion: A block that will be called when the Cloud Code Job completes or fails.\n        It should have the following argument signature: `(Result<ReturnType, ParseError>)`.\n    */\n    public func startJob(options: API.Options = [],\n                         callbackQueue: DispatchQueue = .main,\n                         completion: @escaping (Result<ReturnType, ParseError>) -> Void) {\n        startJobCommand()\n            .executeAsync(options: options, callbackQueue: callbackQueue) { result in\n                completion(result)\n            }\n    }\n\n    internal func startJobCommand() -> API.Command<Self, ReturnType> {\n        API.Command(method: .POST,\n                    path: .jobs(name: functionJobName),\n                    body: self) { (data) -> ReturnType in\n            let response = try ParseCoding.jsonDecoder().decode(AnyResultResponse<ReturnType>.self, from: data)\n            return response.result\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/ParseEncodable.swift",
    "content": "//\n//  ParseEncodable.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 12/31/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n Types that conform to **ParseEncodable** should be encoded by the\n `ParseEncoder` when necessary.\n */\npublic protocol ParseEncodable: Encodable {}\n\n// MARK: CustomDebugStringConvertible\nextension ParseEncodable {\n    public var debugDescription: String {\n        guard let descriptionData = try? ParseCoding.jsonEncoder().encode(self),\n            let descriptionString = String(data: descriptionData, encoding: .utf8) else {\n                return \"()\"\n        }\n\n        return \"\\(descriptionString)\"\n    }\n}\n\n// MARK: CustomStringConvertible\nextension ParseEncodable {\n    public var description: String {\n        debugDescription\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/ParseFileTransferable.swift",
    "content": "//\n//  ParseFileAdaptable.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/12/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\n\n/**\n A protocol for overriding the default transfer behavior for `ParseFile`'s.\n Allows for direct uploads to other file storage providers.\n */\npublic protocol ParseFileTransferable: AnyObject {\n    /**\n     Creates a task that performs an HTTP request for uploading the specified file,\n     then calls a handler upon completion.\n     - parameter request: The Parse URL request object that provides the URL, cache policy,\n     request type, and so on.\n     - parameter fileURL: The URL of the file to upload.\n     - parameter completion: The completion handler to call when the load request\n     is complete. Should be in the form `(Data?, URLResponse?, URLRequest?, Error?)`.\n    `Data` and `URLResponse` should be created using `makeSuccessfulUploadResponse()`.\n    `URLRequest` is the request used to upload the file if available. `Error` is any error that occured\n     that prevented the file upload.\n     */\n    func upload(with request: URLRequest,\n                fromFile fileURL: URL,\n                completion: @escaping (Data?, URLResponse?, URLRequest?, Error?) -> Void) throws -> URLSessionUploadTask\n\n    /**\n     Creates a task that performs an HTTP request for the specified URL request\n     object, uploads the provided data, and calls a handler upon completion.\n     - parameter request: The Parse URL request object that provides the URL, cache policy,\n     request type, and so on.\n     - parameter bodyData: The body data for the request.\n     - parameter completion: The completion handler to call when the load request\n     is complete. Should be in the form `(Data?, URLResponse?, URLRequest?, Error?)`.\n    `Data` and `URLResponse` should be created using `makeSuccessfulUploadResponse()`.\n    `URLRequest` is the request used to upload the file if available. `Error` is any error that occured\n     that prevented the file upload.\n     */\n    func upload(with request: URLRequest,\n                from bodyData: Data?,\n                completion: @escaping (Data?, URLResponse?, URLRequest?, Error?) -> Void) throws -> URLSessionUploadTask\n\n    /**\n     Compose a valid file upload response with a name and url.\n     \n     Use this method after uploading a file to any file storage to\n     respond to the Swift SDK upload request.\n     - parameter name: The name of the file.\n     - parameter url: The url of the file that was stored.\n     - returns: A tuple of `(Data, HTTPURLResponse?)` where `Data` is the\n     JSON encoded file upload response and `HTTPURLResponse` is the metadata\n     associated with the response to the load request.\n     */\n    func makeSuccessfulUploadResponse(_ name: String, url: URL) throws -> (Data, HTTPURLResponse?)\n\n    /**\n     Compose a dummy upload task.\n     \n     Use this method if you do not need the Parse Swift SDK to start\n     your upload task for you.\n     - returns: A dummy upload task that starts an upload of zero bytes\n     to localhost.\n     - throws: An error of type `ParseError`.\n     */\n    func makeDummyUploadTask() throws -> URLSessionUploadTask\n}\n\n// MARK: Default Implementation - Internal\nextension ParseFileTransferable {\n    func upload(with request: URLRequest,\n                fromFile fileURL: URL,\n                // swiftlint:disable:next line_length\n                completion: @escaping (Data?, URLResponse?, URLRequest?, Error?) -> Void) throws -> URLSessionUploadTask {\n        URLSession.parse.uploadTask(with: request, fromFile: fileURL) { (data, response, error) in\n            completion(data, response, request, error)\n        }\n    }\n\n    func upload(with request: URLRequest,\n                from bodyData: Data?,\n                // swiftlint:disable:next line_length\n                completion: @escaping (Data?, URLResponse?, URLRequest?, Error?) -> Void) throws -> URLSessionUploadTask {\n        URLSession.parse.uploadTask(with: request, from: bodyData) { (data, response, error) in\n            completion(data, response, request, error)\n        }\n    }\n}\n\n// MARK: Default Implementation - Public\npublic extension ParseFileTransferable {\n    func makeSuccessfulUploadResponse(_ name: String, url: URL) throws -> (Data, HTTPURLResponse?) {\n        let responseData = FileUploadResponse(name: name, url: url)\n        let response = HTTPURLResponse(url: url,\n                                       statusCode: 200,\n                                       httpVersion: nil,\n                                       headerFields: nil)\n        let encodedResponseData = try ParseCoding.jsonEncoder().encode(responseData)\n        return (encodedResponseData, response)\n    }\n\n    func makeDummyUploadTask() throws -> URLSessionUploadTask {\n        guard let url = URL(string: \"http://localhost\") else {\n            throw ParseError(code: .unknownError, message: \"Could not create URL\")\n        }\n        return URLSession.shared.uploadTask(with: .init(url: url), from: Data())\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/ParseHookFunctionable+async.swift",
    "content": "//\n//  ParseHookFunctionable+async.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/19/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\n\n// MARK: Fetch\npublic extension ParseHookFunctionable {\n    /**\n     Fetches the Parse hook function *asynchronously*  from the server.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the fetched `ParseHookFunctionable`.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     */\n     func fetch(options: API.Options = []) async throws -> Self {\n         try await withCheckedThrowingContinuation { continuation in\n             self.fetch(options: options,\n                        completion: continuation.resume)\n         }\n     }\n\n    /**\n     Fetches all of the Parse hook functions *asynchronously*  from the server.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An array of fetched `ParseHookFunctionable`'s.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     */\n     func fetchAll(options: API.Options = []) async throws -> [Self] {\n         try await withCheckedThrowingContinuation { continuation in\n             self.fetchAll(options: options,\n                           completion: continuation.resume)\n         }\n     }\n}\n\n// MARK: Create\npublic extension ParseHookFunctionable {\n    /**\n     Creates the Parse hook function *asynchronously*  from the server.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the created `ParseHookFunctionable`.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     */\n     func create(options: API.Options = []) async throws -> Self {\n         try await withCheckedThrowingContinuation { continuation in\n             self.create(options: options,\n                         completion: continuation.resume)\n         }\n     }\n}\n\n// MARK: Update\npublic extension ParseHookFunctionable {\n    /**\n     Updates the Parse hook function *asynchronously*  from the server.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the updated `ParseHookFunctionable`.\n     - throws: An error of type `ParseError`.\n     - warning: Do not use on Parse Server 5.3.0 and below. Instead, delete and create.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     */\n     func update(options: API.Options = []) async throws -> Self {\n         try await withCheckedThrowingContinuation { continuation in\n             self.update(options: options,\n                         completion: continuation.resume)\n         }\n     }\n}\n\n// MARK: Delete\npublic extension ParseHookFunctionable {\n    /**\n     Deletes the Parse hook function *asynchronously*  from the server.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     */\n     func delete(options: API.Options = []) async throws {\n         let result = try await withCheckedThrowingContinuation { continuation in\n             self.delete(options: options,\n                         completion: continuation.resume)\n         }\n         if case let .failure(error) = result {\n             throw error\n         }\n     }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/ParseHookFunctionable+combine.swift",
    "content": "//\n//  ParseHookFunctionable+combine.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/19/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\n// MARK: Fetch\npublic extension ParseHookFunctionable {\n    /**\n     Fetches the Parse hook function *asynchronously*. Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func fetchPublisher(options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.fetch(options: options, completion: promise)\n        }\n    }\n\n    /**\n     Fetches all of the Parse hook functions *asynchronously*. Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func fetchAllPublisher(options: API.Options = []) -> Future<[Self], ParseError> {\n        Future { promise in\n            self.fetchAll(options: options, completion: promise)\n        }\n    }\n}\n\n// MARK: Create\npublic extension ParseHookFunctionable {\n    /**\n     Creates the Parse hook function *asynchronously*. Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func createPublisher(options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.create(options: options, completion: promise)\n        }\n    }\n}\n\n// MARK: Update\npublic extension ParseHookFunctionable {\n    /**\n     Updates the Parse hook function *asynchronously*. Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - warning: Do not use on Parse Server 5.3.0 and below. Instead, delete and create.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func updatePublisher(options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.update(options: options, completion: promise)\n        }\n    }\n}\n\n// MARK: Delete\npublic extension ParseHookFunctionable {\n    /**\n     Deletes the Parse hook function *asynchronously*. Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func deletePublisher(options: API.Options = []) -> Future<Void, ParseError> {\n        Future { promise in\n            self.delete(options: options, completion: promise)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/ParseHookFunctionable.swift",
    "content": "//\n//  ParseHookFunction.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/14/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n Conforming to `ParseHookFunctionable` allows the creation of hooks\n which are Cloud Code functions.\n - requires: `.useMasterKey` has to be available. It is recommended to only\n use the master key in server-side applications where the key is kept secure and not\n exposed to the public.\n */\npublic protocol ParseHookFunctionable: ParseHookable {\n    /**\n     The name of the function.\n    */\n    var functionName: String? { get set }\n}\n\n// MARK: Default Implementation\npublic extension ParseHookFunctionable {\n    /**\n     Creates a new Parse hook function.\n     - parameter name: The name of the function.\n     - parameter url: The endpoint of the hook.\n     */\n    init(name: String, url: URL?) {\n        self.init()\n        functionName = name\n        self.url = url\n    }\n}\n\ninternal struct FunctionRequest: Encodable {\n    let functionName: String\n    let url: URL?\n\n    init<F>(hookFunction: F) throws where F: ParseHookFunctionable {\n        guard let functionName = hookFunction.functionName else {\n            throw ParseError(code: .unknownError,\n                             message: \"The \\\"functionName\\\" needs to be set: \\(hookFunction)\")\n        }\n        self.functionName = functionName\n        self.url = hookFunction.url\n    }\n}\n\n// MARK: Fetch\nextension ParseHookFunctionable {\n    /**\n     Fetches the Parse hook function *asynchronously* and executes the given callback block.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func fetch(options: API.Options = [],\n                      callbackQueue: DispatchQueue = .main,\n                      completion: @escaping (Result<Self, ParseError>) -> Void) {\n        var options = options\n        options.insert(.useMasterKey)\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        do {\n            try fetchCommand().executeAsync(options: options,\n                                            callbackQueue: callbackQueue) { result in\n                completion(result)\n            }\n        } catch {\n            let defaultError = ParseError(code: .unknownError,\n                                          message: error.localizedDescription)\n            let parseError = error as? ParseError ?? defaultError\n            completion(.failure(parseError))\n        }\n    }\n\n    func fetchCommand() throws -> API.NonParseBodyCommand<Self, Self> {\n        let request = try FunctionRequest(hookFunction: self)\n        return API.NonParseBodyCommand(method: .GET,\n                                       path: .hookFunction(request: request)) { (data) -> Self in\n            try ParseCoding.jsonDecoder().decode(Self.self, from: data)\n        }\n    }\n\n    /**\n     Fetches all of the Parse hook functions *asynchronously* and executes the given callback block.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func fetchAll(options: API.Options = [],\n                         callbackQueue: DispatchQueue = .main,\n                         completion: @escaping (Result<[Self], ParseError>) -> Void) {\n        Self.fetchAll(options: options,\n                      callbackQueue: callbackQueue,\n                      completion: completion)\n    }\n\n    /**\n     Fetches all of the Parse hook functions *asynchronously* and executes the given callback block.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public static func fetchAll(options: API.Options = [],\n                                callbackQueue: DispatchQueue = .main,\n                                completion: @escaping (Result<[Self], ParseError>) -> Void) {\n        var options = options\n        options.insert(.useMasterKey)\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        fetchAllCommand().executeAsync(options: options,\n                                       callbackQueue: callbackQueue) { result in\n            completion(result)\n        }\n    }\n\n    static func fetchAllCommand() -> API.NonParseBodyCommand<Self, [Self]> {\n        API.NonParseBodyCommand(method: .GET,\n                                path: .hookFunctions) { (data) -> [Self] in\n            try ParseCoding.jsonDecoder().decode([Self].self, from: data)\n        }\n    }\n}\n\n// MARK: Create\nextension ParseHookFunctionable {\n    /**\n     Creates the Parse hook function *asynchronously* and executes the given callback block.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func create(options: API.Options = [],\n                       callbackQueue: DispatchQueue = .main,\n                       completion: @escaping (Result<Self, ParseError>) -> Void) {\n        var options = options\n        options.insert(.useMasterKey)\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        do {\n            try createCommand().executeAsync(options: options,\n                                             callbackQueue: callbackQueue) { result in\n                completion(result)\n            }\n        } catch {\n            let defaultError = ParseError(code: .unknownError,\n                                          message: error.localizedDescription)\n            let parseError = error as? ParseError ?? defaultError\n            completion(.failure(parseError))\n        }\n    }\n\n    func createCommand() throws -> API.NonParseBodyCommand<FunctionRequest, Self> {\n        let request = try FunctionRequest(hookFunction: self)\n        return API.NonParseBodyCommand(method: .POST,\n                                       path: .hookFunctions,\n                                       body: request) { (data) -> Self in\n            try ParseCoding.jsonDecoder().decode(Self.self, from: data)\n        }\n    }\n}\n\n// MARK: Update\nextension ParseHookFunctionable {\n    /**\n     Fetches the Parse hook function *asynchronously* and executes the given callback block.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - warning: Do not use on Parse Server 5.3.0 and below. Instead, delete and create.\n    */\n    public func update(options: API.Options = [],\n                       callbackQueue: DispatchQueue = .main,\n                       completion: @escaping (Result<Self, ParseError>) -> Void) {\n        var options = options\n        options.insert(.useMasterKey)\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        do {\n            try updateCommand().executeAsync(options: options,\n                                             callbackQueue: callbackQueue) { result in\n                completion(result)\n            }\n        } catch {\n            let defaultError = ParseError(code: .unknownError,\n                                          message: error.localizedDescription)\n            let parseError = error as? ParseError ?? defaultError\n            completion(.failure(parseError))\n        }\n    }\n\n    func updateCommand() throws -> API.NonParseBodyCommand<FunctionRequest, Self> {\n        let request = try FunctionRequest(hookFunction: self)\n        return API.NonParseBodyCommand(method: .PUT,\n                                       path: .hookFunction(request: request),\n                                       body: request) { (data) -> Self in\n            try ParseCoding.jsonDecoder().decode(Self.self, from: data)\n        }\n    }\n}\n\n// MARK: Delete\nextension ParseHookFunctionable {\n    /**\n     Deletes the Parse hook function *asynchronously* and executes the given callback block.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Void, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func delete(options: API.Options = [],\n                       callbackQueue: DispatchQueue = .main,\n                       completion: @escaping (Result<Void, ParseError>) -> Void) {\n        var options = options\n        options.insert(.useMasterKey)\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        do {\n            try deleteCommand().executeAsync(options: options,\n                                             callbackQueue: callbackQueue) { result in\n                switch result {\n\n                case .success:\n                    completion(.success(()))\n                case .failure(let error):\n                    completion(.failure(error))\n                }\n            }\n        } catch {\n            let defaultError = ParseError(code: .unknownError,\n                                          message: error.localizedDescription)\n            let parseError = error as? ParseError ?? defaultError\n            completion(.failure(parseError))\n        }\n    }\n\n    func deleteCommand() throws -> API.NonParseBodyCommand<Delete, NoBody> {\n        let request = try FunctionRequest(hookFunction: self)\n        return API.NonParseBodyCommand(method: .PUT,\n                                       path: .hookFunction(request: request),\n                                       body: Delete()) { (data) -> NoBody in\n            try ParseCoding.jsonDecoder().decode(NoBody.self, from: data)\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/ParseHookParametable.swift",
    "content": "//\n//  ParseHookParametable.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/14/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n Conforming to `ParseHookParametable` allows types that can be created\n to decode parameters in `ParseHookFunctionRequest`'s.\n */\npublic protocol ParseHookParametable: Codable, Equatable {}\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/ParseHookRequestable+async.swift",
    "content": "//\n//  ParseHookRequestable+async.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/14/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\npublic extension ParseHookRequestable {\n   /**\n    Fetches the complete `ParseUser` *aynchronously*  from the server.\n    - parameter options: A set of header options sent to the server. Defaults to an empty set.\n    - returns: Returns the `ParseHookRequestable` with the hydrated `ParseCloudUser`.\n    - throws: An error of type `ParseError`.\n    - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n    desires a different policy, it should be inserted in `options`.\n    */\n    func hydrateUser(options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.hydrateUser(options: options,\n                             completion: continuation.resume)\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/ParseHookRequestable+combine.swift",
    "content": "//\n//  ParseHookRequestable+combine.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/14/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\npublic extension ParseHookRequestable {\n    /**\n     Fetches the complete `ParseUser`. Publishes when complete.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func hydrateUserPublisher(options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.hydrateUser(options: options, completion: promise)\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/ParseHookRequestable.swift",
    "content": "//\n//  ParseHookRequestable.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/14/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n Conforming to `ParseHookRequestable` allows you to create types that\n can decode requests when `ParseHookFunctionable` functions are called.\n - requires: `.useMasterKey` has to be available. It is recommended to only\n use the master key in server-side applications where the key is kept secure and not\n exposed to the public.\n */\npublic protocol ParseHookRequestable: ParseTypeable {\n    associatedtype UserType: ParseCloudUser\n    /**\n     Specifies if the **masterKey** was used in the\n     Parse hook call.\n     */\n    var masterKey: Bool? { get }\n    /**\n     A `ParseUser` that contains additional attributes\n     needed for Parse hook calls. If **nil** a user with\n     a valid session did not make the call.\n     */\n    var user: UserType? { get set }\n    /**\n     If set, the installationId triggering the request.\n     */\n    var installationId: String? { get }\n    /**\n     The IP address of the client making the request.\n     */\n    var ipAddress: String? { get }\n    /**\n     The original HTTP headers for the request.\n     */\n    var headers: [String: String]? { get }\n}\n\nextension ParseHookRequestable {\n    /**\n     Produce the set of options that should be used for subsequent `ParseHook` requests.\n     - returns: The set of options produced by the current request.\n     */\n    public func options() -> API.Options {\n        var options = API.Options()\n        if let masterKey = masterKey,\n            masterKey {\n            options.insert(.useMasterKey)\n        } else if let sessionToken = user?.sessionToken {\n            options.insert(.sessionToken(sessionToken))\n            if let installationId = installationId {\n                options.insert(.installationId(installationId))\n            }\n        } else if let installationId = installationId {\n            options.insert(.installationId(installationId))\n        }\n        return options\n    }\n\n    /**\n     Fetches the complete `ParseUser`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: A block that will be called when the Cloud Code completes or fails.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     */\n    public func hydrateUser(options: API.Options = [],\n                            callbackQueue: DispatchQueue = .main,\n                            completion: @escaping (Result<Self, ParseError>) -> Void) {\n        guard let user = user else {\n            let error = ParseError(code: .unknownError,\n                                   message: \"Resquest does not contain a user.\")\n            completion(.failure(error))\n            return\n        }\n        let request = self\n        var updatedOptions = self.options()\n        updatedOptions.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        options.forEach { updatedOptions.insert($0) }\n        user.fetch(options: updatedOptions,\n                   callbackQueue: callbackQueue) { result in\n            switch result {\n            case .success(let fetchedUser):\n                let updatedRequest = request.applyUser(fetchedUser)\n                completion(.success(updatedRequest))\n            case .failure(let error):\n                completion(.failure(error))\n            }\n        }\n    }\n\n    func applyUser(_ updatedUser: UserType) -> Self {\n        var mutableRequest = self\n        mutableRequest.user = updatedUser\n        mutableRequest.user?.sessionToken = self.user?.sessionToken\n        return mutableRequest\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/ParseHookTriggerable+async.swift",
    "content": "//\n//  ParseHookTriggerable+async.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/19/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\n// MARK: Fetch\npublic extension ParseHookTriggerable {\n    /**\n     Fetches the Parse hook trigger *asynchronously*  from the server.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the fetched `ParseHookTriggerable`.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     */\n     func fetch(options: API.Options = []) async throws -> Self {\n         try await withCheckedThrowingContinuation { continuation in\n             self.fetch(options: options,\n                        completion: continuation.resume)\n         }\n     }\n\n    /**\n     Fetches all of the Parse hook triggers *asynchronously*  from the server.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An array of fetched `ParseHookTriggerable`'s.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     */\n     func fetchAll(options: API.Options = []) async throws -> [Self] {\n         try await withCheckedThrowingContinuation { continuation in\n             self.fetchAll(options: options,\n                           completion: continuation.resume)\n         }\n     }\n}\n\n// MARK: Create\npublic extension ParseHookTriggerable {\n    /**\n     Creates the Parse hook trigger *asynchronously*  from the server.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the created `ParseHookTriggerable`.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     */\n     func create(options: API.Options = []) async throws -> Self {\n         try await withCheckedThrowingContinuation { continuation in\n             self.create(options: options,\n                         completion: continuation.resume)\n         }\n     }\n}\n\n// MARK: Update\npublic extension ParseHookTriggerable {\n    /**\n     Updates the Parse hook trigger *asynchronously*  from the server.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the updated `ParseHookTriggerable`.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     */\n     func update(options: API.Options = []) async throws -> Self {\n         try await withCheckedThrowingContinuation { continuation in\n             self.update(options: options,\n                         completion: continuation.resume)\n         }\n     }\n}\n\n// MARK: Delete\npublic extension ParseHookTriggerable {\n    /**\n     Deletes the Parse hook trigger *asynchronously*  from the server.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     */\n     func delete(options: API.Options = []) async throws {\n         let result = try await withCheckedThrowingContinuation { continuation in\n             self.delete(options: options,\n                         completion: continuation.resume)\n         }\n         if case let .failure(error) = result {\n             throw error\n         }\n     }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/ParseHookTriggerable+combine.swift",
    "content": "//\n//  ParseHookTriggerable+combine.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/19/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\n// MARK: Fetch\npublic extension ParseHookTriggerable {\n    /**\n     Fetches the Parse hook trigger *asynchronously*. Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func fetchPublisher(options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.fetch(options: options, completion: promise)\n        }\n    }\n\n    /**\n     Fetches the Parse hook triggers *asynchronously*. Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func fetchAllPublisher(options: API.Options = []) -> Future<[Self], ParseError> {\n        Future { promise in\n            self.fetchAll(options: options, completion: promise)\n        }\n    }\n}\n\n// MARK: Create\npublic extension ParseHookTriggerable {\n    /**\n     Creates the Parse hook trigger *asynchronously*. Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func createPublisher(options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.create(options: options, completion: promise)\n        }\n    }\n}\n\n// MARK: Update\npublic extension ParseHookTriggerable {\n    /**\n     Updates the Parse hook trigger *asynchronously*. Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func updatePublisher(options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.update(options: options, completion: promise)\n        }\n    }\n}\n\n// MARK: Delete\npublic extension ParseHookTriggerable {\n    /**\n     Deletes the Parse hook trigger *asynchronously*. Publishes when complete.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func deletePublisher(options: API.Options = []) -> Future<Void, ParseError> {\n        Future { promise in\n            self.delete(options: options, completion: promise)\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/ParseHookTriggerable.swift",
    "content": "//\n//  ParseHookTriggerable.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/14/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n Conforming to `ParseHookFunctionable` allows the creation of hooks which\n are Cloud Code triggers.\n - requires: `.useMasterKey` has to be available. It is recommended to only\n use the master key in server-side applications where the key is kept secure and not\n exposed to the public.\n */\npublic protocol ParseHookTriggerable: ParseHookable {\n    /// The name of the `ParseObject` the trigger should act on.\n    var className: String? { get set }\n    /// The `ParseHookTriggerType` type.\n    var triggerName: ParseHookTriggerType? { get set }\n}\n\n// MARK: Default Implementation\npublic extension ParseHookTriggerable {\n    /**\n     Creates a new Parse hook trigger.\n     - parameter className: The name of the `ParseObject` the trigger should act on.\n     - parameter triggerName: The `ParseHookTriggerType` type.\n     - parameter url: The endpoint of the hook.\n     */\n    init(className: String, triggerName: ParseHookTriggerType, url: URL) {\n        self.init()\n        self.className = className\n        self.triggerName = triggerName\n        self.url = url\n    }\n\n    /**\n     Creates a new Parse hook trigger.\n     - parameter object: The `ParseObject` the trigger should act on.\n     - parameter triggerName: The `ParseHookTriggerType` type.\n     - parameter url: The endpoint of the hook.\n     */\n    init<T>(object: T, triggerName: ParseHookTriggerType, url: URL) where T: ParseObject {\n        self.init(className: T.className, triggerName: triggerName, url: url)\n    }\n\n    /**\n     Creates a new `ParseFile` or `ParseHookTriggerType.beforeConnect` hook trigger.\n     - parameter triggerName: The `ParseHookTriggerType` type.\n     - parameter url: The endpoint of the hook.\n     */\n    init(triggerName: ParseHookTriggerType, url: URL) throws {\n        self.init()\n        self.triggerName = triggerName\n        self.url = url\n        switch triggerName {\n        case .beforeSave, .afterSave, .beforeDelete, .afterDelete:\n            self.className = \"@File\"\n        case .beforeConnect:\n            self.className = \"@Connect\"\n        default:\n            throw ParseError(code: .unknownError,\n                             message: \"This initializer should only be used for \\\"ParseFile\\\" and \\\"beforeConnect\\\"\")\n        }\n    }\n}\n\ninternal struct TriggerRequest: Encodable {\n    let className: String\n    let triggerName: ParseHookTriggerType\n    let url: URL?\n\n    init<T>(trigger: T) throws where T: ParseHookTriggerable {\n        guard let className = trigger.className,\n              let triggerName = trigger.triggerName else {\n            throw ParseError(code: .unknownError,\n                             message: \"The \\\"className\\\" and \\\"triggerName\\\" needs to be set: \\(trigger)\")\n        }\n        self.className = className\n        self.triggerName = triggerName\n        self.url = trigger.url\n    }\n}\n\n// MARK: Fetch\nextension ParseHookTriggerable {\n    /**\n     Fetches the Parse hook trigger *asynchronously* and executes the given callback block.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func fetch(options: API.Options = [],\n                      callbackQueue: DispatchQueue = .main,\n                      completion: @escaping (Result<Self, ParseError>) -> Void) {\n        var options = options\n        options.insert(.useMasterKey)\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        do {\n            try fetchCommand().executeAsync(options: options,\n                                            callbackQueue: callbackQueue) { result in\n                completion(result)\n            }\n        } catch {\n            let defaultError = ParseError(code: .unknownError,\n                                          message: error.localizedDescription)\n            let parseError = error as? ParseError ?? defaultError\n            completion(.failure(parseError))\n        }\n    }\n\n    func fetchCommand() throws -> API.NonParseBodyCommand<Self, Self> {\n        let request = try TriggerRequest(trigger: self)\n        return API.NonParseBodyCommand(method: .GET,\n                                       path: .hookTrigger(request: request)) { (data) -> Self in\n            try ParseCoding.jsonDecoder().decode(Self.self, from: data)\n        }\n    }\n\n    /**\n     Fetches all of the Parse hook triggers *asynchronously* and executes the given callback block.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - important: If an object fetched has the same objectId as current, it will automatically update the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func fetchAll(options: API.Options = [],\n                         callbackQueue: DispatchQueue = .main,\n                         completion: @escaping (Result<[Self], ParseError>) -> Void) {\n        Self.fetchAll(options: options,\n                      callbackQueue: callbackQueue,\n                      completion: completion)\n    }\n\n    /**\n     Fetches all of the Parse hook triggers *asynchronously* and executes the given callback block.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - important: If an object fetched has the same objectId as current, it will automatically update the current.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public static func fetchAll(options: API.Options = [],\n                                callbackQueue: DispatchQueue = .main,\n                                completion: @escaping (Result<[Self], ParseError>) -> Void) {\n        var options = options\n        options.insert(.useMasterKey)\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        fetchAllCommand().executeAsync(options: options,\n                                       callbackQueue: callbackQueue) { result in\n            completion(result)\n        }\n    }\n\n    static func fetchAllCommand() -> API.NonParseBodyCommand<Self, [Self]> {\n        API.NonParseBodyCommand(method: .GET,\n                                path: .hookTriggers) { (data) -> [Self] in\n            try ParseCoding.jsonDecoder().decode([Self].self, from: data)\n        }\n    }\n}\n\n// MARK: Create\nextension ParseHookTriggerable {\n    /**\n     Creates the Parse hook trigger *asynchronously* and executes the given callback block.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func create(options: API.Options = [],\n                       callbackQueue: DispatchQueue = .main,\n                       completion: @escaping (Result<Self, ParseError>) -> Void) {\n        var options = options\n        options.insert(.useMasterKey)\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        do {\n            try createCommand().executeAsync(options: options,\n                                             callbackQueue: callbackQueue) { result in\n                completion(result)\n            }\n        } catch {\n            let defaultError = ParseError(code: .unknownError,\n                                          message: error.localizedDescription)\n            let parseError = error as? ParseError ?? defaultError\n            completion(.failure(parseError))\n        }\n    }\n\n    func createCommand() throws -> API.NonParseBodyCommand<TriggerRequest, Self> {\n        let request = try TriggerRequest(trigger: self)\n        return API.NonParseBodyCommand(method: .POST,\n                                       path: .hookTriggers,\n                                       body: request) { (data) -> Self in\n            try ParseCoding.jsonDecoder().decode(Self.self, from: data)\n        }\n    }\n}\n\n// MARK: Update\nextension ParseHookTriggerable {\n    /**\n     Fetches the Parse hook trigger *asynchronously* and executes the given callback block.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func update(options: API.Options = [],\n                       callbackQueue: DispatchQueue = .main,\n                       completion: @escaping (Result<Self, ParseError>) -> Void) {\n        var options = options\n        options.insert(.useMasterKey)\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        do {\n            try updateCommand().executeAsync(options: options,\n                                             callbackQueue: callbackQueue) { result in\n                completion(result)\n            }\n        } catch {\n            let defaultError = ParseError(code: .unknownError,\n                                          message: error.localizedDescription)\n            let parseError = error as? ParseError ?? defaultError\n            completion(.failure(parseError))\n        }\n    }\n\n    func updateCommand() throws -> API.NonParseBodyCommand<TriggerRequest, Self> {\n        let request = try TriggerRequest(trigger: self)\n        return API.NonParseBodyCommand(method: .PUT,\n                                       path: .hookTrigger(request: request),\n                                       body: request) { (data) -> Self in\n            try ParseCoding.jsonDecoder().decode(Self.self, from: data)\n        }\n    }\n}\n\n// MARK: Delete\nextension ParseHookTriggerable {\n    /**\n     Deletes the Parse hook trigger *asynchronously* and executes the given callback block.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Void, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func delete(options: API.Options = [],\n                       callbackQueue: DispatchQueue = .main,\n                       completion: @escaping (Result<Void, ParseError>) -> Void) {\n        var options = options\n        options.insert(.useMasterKey)\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        do {\n            try deleteCommand().executeAsync(options: options,\n                                             callbackQueue: callbackQueue) { result in\n                switch result {\n\n                case .success:\n                    completion(.success(()))\n                case .failure(let error):\n                    completion(.failure(error))\n                }\n            }\n        } catch {\n            let defaultError = ParseError(code: .unknownError,\n                                          message: error.localizedDescription)\n            let parseError = error as? ParseError ?? defaultError\n            completion(.failure(parseError))\n        }\n    }\n\n    func deleteCommand() throws -> API.NonParseBodyCommand<Delete, NoBody> {\n        let request = try TriggerRequest(trigger: self)\n        return API.NonParseBodyCommand(method: .PUT,\n                                       path: .hookTrigger(request: request),\n                                       body: Delete()) { (data) -> NoBody in\n            try ParseCoding.jsonDecoder().decode(NoBody.self, from: data)\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/ParseHookable.swift",
    "content": "//\n//  ParseHookable.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/15/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n Hooks and Triggers should conform to `ParseHookable`.\n */\npublic protocol ParseHookable: ParseTypeable {\n    /// The endpoint of the hook.\n    var url: URL? { get set }\n\n    /// Create an empty initializer.\n    init()\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/ParsePushApplePayloadable.swift",
    "content": "//\n//  ParsePushApplePayloadable.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/8/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n// swiftlint:disable line_length\n\n/**\n A protocol for adding the standard properties for Apple push notifications.\n - warning: You should add `alert`, `badge`, and `sound` properties to your type.\n They are not provided by default as they need to be type erased. You will also\n need to implement `CodingKeys`, see `ParsePushPayloadApple` for an example.\n */\npublic protocol ParsePushApplePayloadable: ParsePushPayloadable {\n    /**\n     The payload for displaying an alert.\n     */\n    var alert: ParsePushAppleAlert? { get set }\n    /**\n     The destination topic for the notification.\n     */\n    var topic: String? { get set }\n    /**\n     Multiple notifications with same collapse identifier are displayed to the user as a single\n     notification. The value should not exceed 64 bytes.\n     */\n    var collapseId: String? { get set }\n    /**\n     The type of the notification. The value is alert or background. Specify alert when the\n     delivery of your notification displays an alert, plays a sound, or badges your app’s icon.\n     Specify background for silent notifications that do not interact with the user.\n     Defaults to alert if no value is set.\n     - warning: Required when delivering notifications to\n     devices running iOS 13 and later, or watchOS 6 and later. Ignored on earlier OS versions.\n     */\n    var pushType: ParsePushPayloadApple.PushType? { get set }\n    /**\n     The identifier of the `UNNotification​Category` for this push notification.\n     See Apple's\n     [documentation](https://developer.apple.com/documentation/usernotifications/unnotificationcategory)\n     for more information.\n     */\n    var category: String? { get set }\n    /**\n     Used for Safari Push Notifications and should be an array of values. See the\n     [Notification Programming Guide for Websites](https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/NotificationProgrammingGuideForWebsites/PushNotifications/PushNotifications.html#//apple_ref/doc/uid/TP40013225-CH3-SW12).\n     */\n    var urlArgs: [String]? { get set }\n    /**\n     The identifier of the window brought forward. The value of this key will be populated\n     on the [UNNotificationContent](https://developer.apple.com/documentation/usernotifications/unnotificationcontent)\n     object created from the push payload. Access the value\n     using the UNNotificationContent object’s [targetContentIdentifier](https://developer.apple.com/documentation/usernotifications/unnotificationcontent/3235764-targetcontentidentifier)\n     property.\n     */\n    var targetContentId: String? { get set }\n    /**\n     An app-specific identifier for grouping related notifications. This value corresponds\n     to the [threadIdentifier](https://developer.apple.com/documentation/usernotifications/unmutablenotificationcontent/1649872-threadidentifier)\n     property in the UNNotificationContent object.\n     */\n    var threadId: String? { get set }\n    /**\n     A string that indicates the importance and delivery timing of a notification.\n     The string values “passive”, “active”, “time-sensitive”, or “critical” correspond\n     to the [UNNotificationInterruptionLevel](https://developer.apple.com/documentation/usernotifications/unnotificationinterruptionlevel)\n     enumeration cases.\n     */\n    var interruptionLevel: String? { get set }\n    /**\n     The relevance score, a number between 0 and 1, that the system uses to\n     sort the notifications from your app. The highest score gets featured in the\n     notification summary. See [relevanceScore](https://developer.apple.com/documentation/usernotifications/unnotificationcontent/3821031-relevancescore).\n     */\n    var relevanceScore: Double? { get set }\n    /**\n     Specify for the `mdm` field where applicable.\n     */\n    var mdm: String? { get set }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/ParsePushFirebasePayloadable.swift",
    "content": "//\n//  ParsePushFirebasePayloadable.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/8/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n A protocol for adding the standard properties for Firebase Cloud Messaging (FCM) push notifications.\n - warning: You will also need to implement `CodingKeys`, see `ParsePushPayloadFirebase` for an example.\n */\npublic protocol ParsePushFirebasePayloadable: ParsePushPayloadable {\n    /**\n     An optional field that contains a URI. When the notification is opened, an\n     Activity associated with opening the URI is launched.\n     */\n    var uri: URL? { get set }\n    /**\n     The value displayed in the Android system tray notification.\n     */\n    var title: String? { get set }\n    /**\n     When there is a newer message that renders an older,\n     related message irrelevant to the client app, FCM\n     replaces the older message.\n     */\n    var collapseKey: String? { get set }\n    /**\n     If the device is connected but idle, the message will\n     still be delivered right away unless the `delayWhileIdle`\n     flag is set to **true**. Otherwise, it will be stored in the\n     FCM servers until the device is awake. And that's where\n     the `collapseKey` flag plays a role: if there is already a\n     message with the same collapse key (and registration ID)\n     stored and waiting for delivery, the old message will be\n     discarded and the new message will take its place\n     (that is, the old message will be collapsed by the new one).\n     */\n    var delayWhileIdle: Bool? { get set }\n    /**\n     This parameter specifies the package name of the application where\n     the registration tokens must match in order to receive the message.\n     */\n    var restrictedPackageName: String? { get set }\n    /**\n     This parameter, when set to **true**, allows developers to test a request\n     without actually sending a message.\n     */\n    var dryRun: Bool? { get set }\n    /**\n     This parameter specifies the custom key-value pairs of the\n     message's payload.\n     */\n    var data: [String: String]? { get set }\n    /**\n     The predefined, user-visible notification payload.\n     */\n    var notification: ParsePushFirebaseNotification? { get set }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/ParsePushPayloadable.swift",
    "content": "//\n//  ParsePushPayloadDatable.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/5/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n A protocol for making push notification payloads.\n See `ParsePushPayloadApple` or `ParsePushPayloadFirebase` for examples.\n */\npublic protocol ParsePushPayloadable: ParseTypeable {\n\n    /// Creates an empty payload.\n    init()\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/ParseQueryScorable.swift",
    "content": "//\n//  ParseQueryScorable.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/16/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n Conform to this protocol to add the required properties to your `ParseObject`\n for using `QueryConstraint.matchesText()` and `Query.sortByTextScore()`.\n - note: In order to sort you must use `Query.sortByTextScore()`.\n   To retrieve the weight/rank, access the \"score\" property of your `ParseObject`.\n */\npublic protocol ParseQueryScorable {\n    /**\n     The weight/rank of a `QueryConstraint.matchesText()`.\n    */\n    var score: Double? { get }\n}\n\n// MARK: ParseQueryScorable\nextension Query where T: ParseObject & ParseQueryScorable {\n    /**\n      Method to sort the full text search by text score.\n      - parameter value: String or Object of index that should be used when executing query.\n      - note: Your `ParseObject` should conform to `ParseQueryScorable` to retrieve\n      the weight/rank via  the \"score\" property of your `ParseObject`.\n    */\n    public func sortByTextScore() -> Query<T> {\n        var mutableQuery = self\n        let ascendingScore = Order.ascending(QueryConstraint.Comparator.score.rawValue)\n        if mutableQuery.order != nil {\n            mutableQuery.order?.append(ascendingScore)\n        } else {\n            mutableQuery.order = [ascendingScore]\n        }\n        return mutableQuery.select(QueryConstraint.Comparator.score.rawValue)\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/ParseTypeable.swift",
    "content": "//\n//  ParseTypeable.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/19/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n A special type that is considered a Parse type.\n */\npublic protocol ParseTypeable: Codable,\n                               Equatable,\n                               CustomDebugStringConvertible,\n                               CustomStringConvertible {}\n\n// MARK: CustomDebugStringConvertible\nextension ParseTypeable {\n    public var debugDescription: String {\n        guard let descriptionData = try? ParseCoding.jsonEncoder().encode(self),\n            let descriptionString = String(data: descriptionData, encoding: .utf8) else {\n                return \"()\"\n        }\n\n        return \"\\(descriptionString)\"\n    }\n}\n\n// MARK: CustomStringConvertible\nextension ParseTypeable {\n    public var description: String {\n        debugDescription\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/QueryObservable.swift",
    "content": "//\n//  QueryObservable.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 7/3/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(SwiftUI)\nimport Foundation\n\n/**\n This protocol describes the interface for creating a view model for a `Query`.\n You can use this protocol on any custom class of yours, instead of `QueryViewModel`, if it fits your use case better.\n */\npublic protocol QueryObservable: ObservableObject {\n\n    /// The `ParseObject` associated with this view model.\n    associatedtype Object: ParseObject\n\n    /// The query associated with this view model.\n    var query: Query<Object> { get set }\n\n    /**\n     Creates a new view model that can be used to handle updates.\n     */\n    init(query: Query<Object>)\n\n    /**\n      Finds objects *asynchronously* based on the constructed query and updates the view model\n     when complete.\n\n      - parameter options: A set of header options sent to the server. Defaults to an empty set.\n    */\n    func find(options: API.Options)\n\n    /**\n     Retrieves *asynchronously* a complete list of `ParseObject`'s  that satisfy this query\n     and updates the view model when complete.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - warning: The items are processed in an unspecified order. The query may not have any sort\n     order, and may not use limit or skip.\n    */\n    func findAll(batchLimit: Int?,\n                 options: API.Options)\n\n    /**\n      Gets an object *asynchronously* and updates the view model when complete.\n\n      - warning: This method mutates the query. It will reset the limit to `1`.\n      - parameter options: A set of header options sent to the server. Defaults to an empty set.\n    */\n    func first(options: API.Options)\n\n    /**\n      Counts objects *synchronously* based on the constructed query and updates the view model\n     when complete.\n\n      - parameter options: A set of header options sent to the server. Defaults to an empty set.\n    */\n    func count(options: API.Options)\n\n    /**\n      Executes an aggregate query *asynchronously* and updates the view model when complete.\n        - requires: `.useMasterKey` has to be available. It is recommended to only\n        use the master key in server-side applications where the key is kept secure and not\n        exposed to the public.\n        - parameter pipeline: A pipeline of stages to process query.\n        - parameter options: A set of header options sent to the server. Defaults to an empty set.\n        - warning: This has not been tested thoroughly.\n    */\n    func aggregate(_ pipeline: [[String: Encodable]],\n                   options: API.Options)\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/Queryable.swift",
    "content": "//\n//  Queryable.swift\n//  ParseSwift\n//\n//  Created by Florent Vilmart on 17-07-24.\n//  Copyright © 2020 Parse. All rights reserved.\n//\nimport Foundation\n\npublic protocol Queryable {\n    associatedtype ResultType\n\n    func find(options: API.Options) throws -> [ResultType]\n    func first(options: API.Options) throws -> ResultType\n    func count(options: API.Options) throws -> Int\n    func find(options: API.Options, callbackQueue: DispatchQueue,\n              completion: @escaping (Result<[ResultType], ParseError>) -> Void)\n    func first(options: API.Options, callbackQueue: DispatchQueue,\n               completion: @escaping (Result<ResultType, ParseError>) -> Void)\n    func count(options: API.Options, callbackQueue: DispatchQueue,\n               completion: @escaping (Result<Int, ParseError>) -> Void)\n}\n\nextension Queryable {\n    /**\n      Finds objects *synchronously* based on the constructed query and sets an error if there was one.\n\n      - throws: An error of type `ParseError`.\n\n      - returns: Returns an array of `ParseObject`s that were found.\n    */\n    func find() throws -> [ResultType] {\n        try find(options: [])\n    }\n\n    /**\n       Gets an object *synchronously* based on the constructed query and sets an error if any occurred.\n\n       - warning: This method mutates the query. It will reset the limit to `1`.\n\n       - throws: An error of type `ParseError`.\n\n       - returns: Returns a `ParseObject`, or `nil` if none was found.\n     */\n    func first() throws -> ResultType? {\n        try first(options: [])\n    }\n\n    /**\n      Counts objects *synchronously* based on the constructed query and sets an error if there was one.\n\n      - throws: An error of type `ParseError`.\n\n      - returns: Returns the number of `ParseObject`s that match the query, or `-1` if there is an error.\n    */\n    func count() throws -> Int {\n        try count(options: [])\n    }\n\n    /**\n      Finds objects *asynchronously* and returns a completion block with the results.\n\n      - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n      - parameter completion: The block to execute.\n      It should have the following argument signature: `(Result<[ResultType], ParseError>)`\n    */\n    func find(callbackQueue: DispatchQueue = .main, completion: @escaping (Result<[ResultType], ParseError>) -> Void) {\n        find(options: [], callbackQueue: callbackQueue, completion: completion)\n    }\n\n    /**\n      Gets an object *asynchronously* and returns a completion block with the result.\n\n      - warning: This method mutates the query. It will reset the limit to `1`.\n\n      - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n      - parameter completion: The block to execute.\n      It should have the following argument signature: `^(ParseObject *object, ParseError *error)`.\n      `result` will be `nil` if `error` is set OR no object was found matching the query.\n      `error` will be `nil` if `result` is set OR if the query succeeded, but found no results.\n    */\n    func first(callbackQueue: DispatchQueue = .main, completion: @escaping (Result<ResultType, ParseError>) -> Void) {\n        first(options: [], callbackQueue: callbackQueue, completion: completion)\n    }\n\n    /**\n      Counts objects *asynchronously* and returns a completion block with the count.\n\n      - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n      - parameter completion: The block to execute.\n      It should have the following argument signature: `^(int count, ParseError *error)`\n    */\n    func count(callbackQueue: DispatchQueue = .main, completion: @escaping (Result<Int, ParseError>) -> Void) {\n        count(options: [], callbackQueue: callbackQueue, completion: completion)\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Protocols/Savable.swift",
    "content": "//\n//  Savable.swift\n//  ParseSwift\n//\n//  Created by Florent Vilmart on 17-07-24.\n//  Copyright © 2020 Parse. All rights reserved.\n//\n\npublic protocol Savable: Encodable {\n    associatedtype SavingType\n\n    func save(options: API.Options) throws -> SavingType\n    func save() throws -> SavingType\n}\n\nextension Savable {\n    public func save() throws -> SavingType {\n        try save(options: [])\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Storage/KeychainStore.swift",
    "content": "//\n//  KeychainStore.swift\n//  ParseSwift\n//\n//  Created by Florent Vilmart on 17-09-25.\n//  Copyright © 2017 Parse. All rights reserved.\n//\n\nimport Foundation\n#if canImport(Security)\nimport Security\n#endif\n\n#if !os(Linux) && !os(Android) && !os(Windows)\n\n/**\n KeychainStore is UserDefaults-like wrapper on top of Keychain.\n It supports any object, with Coding support. All objects are available after the\n first device unlock and are not backed up.\n */\nstruct KeychainStore: SecureStorage {\n\n    let synchronizationQueue: DispatchQueue\n    let service: String\n    static var objectiveCService: String {\n        guard let identifier = Bundle.main.bundleIdentifier else {\n            return \"\"\n        }\n        return \"\\(identifier).com.parse.sdk\"\n    }\n    static var shared = KeychainStore()\n    static var objectiveC: KeychainStore? {\n        KeychainStore(service: objectiveCService)\n    }\n    // This Keychain was used by SDK <= 1.9.7\n    static var old = KeychainStore(service: \"shared\")\n\n    init(service: String? = nil) {\n        var keychainService = \".parseSwift.sdk\"\n        if let service = service {\n            keychainService = service\n        } else if let identifier = Bundle.main.bundleIdentifier {\n            keychainService = \"\\(identifier)\\(keychainService)\"\n        } else {\n            keychainService = \"com\\(keychainService)\"\n        }\n        self.service = keychainService\n        synchronizationQueue = DispatchQueue(label: \"\\(keychainService).keychain\",\n                                             qos: .default,\n                                             attributes: .concurrent,\n                                             autoreleaseFrequency: .inherit,\n                                             target: nil)\n    }\n\n    func getKeychainQueryTemplate() -> [String: Any] {\n        var query = [String: Any]()\n        if !service.isEmpty {\n            query[kSecAttrService as String] = service\n        }\n        query[kSecClass as String] = kSecClassGenericPassword as String\n        return query\n    }\n\n    func getObjectiveCKeychainQueryTemplate() -> [String: Any] {\n        var query = [String: Any]()\n        if !Self.objectiveCService.isEmpty {\n            query[kSecAttrService as String] = Self.objectiveCService\n        }\n        query[kSecClass as String] = kSecClassGenericPassword as String\n        return query\n    }\n\n    func copy(_ keychain: KeychainStore,\n              oldAccessGroup: ParseKeychainAccessGroup,\n              newAccessGroup: ParseKeychainAccessGroup) throws {\n        if let user = keychain.data(forKey: ParseStorage.Keys.currentUser,\n                                    accessGroup: oldAccessGroup) {\n            try set(user,\n                    forKey: ParseStorage.Keys.currentUser,\n                    oldAccessGroup: oldAccessGroup,\n                    newAccessGroup: newAccessGroup)\n        }\n        if let installation = keychain.data(forKey: ParseStorage.Keys.currentInstallation,\n                                            accessGroup: oldAccessGroup) {\n            try set(installation,\n                    forKey: ParseStorage.Keys.currentInstallation,\n                    oldAccessGroup: oldAccessGroup,\n                    newAccessGroup: newAccessGroup)\n        }\n        if let version = keychain.data(forKey: ParseStorage.Keys.currentVersion,\n                                       accessGroup: oldAccessGroup) {\n            try set(version,\n                    forKey: ParseStorage.Keys.currentVersion,\n                    oldAccessGroup: oldAccessGroup,\n                    newAccessGroup: newAccessGroup)\n        }\n        if let config = keychain.data(forKey: ParseStorage.Keys.currentConfig,\n                                      accessGroup: oldAccessGroup) {\n            try set(config,\n                    forKey: ParseStorage.Keys.currentConfig,\n                    oldAccessGroup: oldAccessGroup,\n                    newAccessGroup: newAccessGroup)\n        }\n        if let acl = keychain.data(forKey: ParseStorage.Keys.defaultACL,\n                                   accessGroup: oldAccessGroup) {\n            try set(acl,\n                    forKey: ParseStorage.Keys.defaultACL,\n                    oldAccessGroup: oldAccessGroup,\n                    newAccessGroup: newAccessGroup)\n        }\n        if let keychainAccessGroup = keychain.data(forKey: ParseStorage.Keys.currentAccessGroup,\n                                                   accessGroup: oldAccessGroup) {\n            try set(keychainAccessGroup,\n                    forKey: ParseStorage.Keys.currentAccessGroup,\n                    oldAccessGroup: oldAccessGroup,\n                    newAccessGroup: newAccessGroup)\n        }\n    }\n\n    func isSyncableKey(_ key: String) -> Bool {\n        key != ParseStorage.Keys.currentInstallation &&\n        key != ParseStorage.Keys.currentVersion &&\n        key != ParseStorage.Keys.currentAccessGroup\n    }\n\n    func keychainQuery(forKey key: String,\n                       useObjectiveCKeychain: Bool = false,\n                       accessGroup: ParseKeychainAccessGroup) -> [String: Any] {\n        if !useObjectiveCKeychain {\n            var query: [String: Any] = getKeychainQueryTemplate()\n            query[kSecAttrAccount as String] = key\n            if let keychainAccessGroup = accessGroup.accessGroup {\n                query[kSecAttrAccessGroup as String] = keychainAccessGroup\n                if accessGroup.isSyncingKeychainAcrossDevices && isSyncableKey(key) {\n                    query[kSecAttrSynchronizable as String] = kCFBooleanTrue\n                    query[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlock as String\n                } else {\n                    query[kSecAttrSynchronizable as String] = kCFBooleanFalse\n                    query[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly as String\n                }\n            } else {\n                query[kSecAttrSynchronizable as String] = kCFBooleanFalse\n                query[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly as String\n            }\n            #if os(macOS)\n            if Parse.configuration.isUsingDataProtectionKeychain {\n                query[kSecUseDataProtectionKeychain as String] = kCFBooleanTrue\n            }\n            #endif\n            return query\n        } else {\n            var query: [String: Any] = getKeychainQueryTemplate()\n            query[kSecAttrAccount as String] = key\n            query[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlock as String\n            return query\n        }\n    }\n\n    func data(forKey key: String,\n              useObjectiveCKeychain: Bool = false,\n              accessGroup: ParseKeychainAccessGroup) -> Data? {\n        var query: [String: Any] = keychainQuery(forKey: key,\n                                                 useObjectiveCKeychain: useObjectiveCKeychain,\n                                                 accessGroup: accessGroup)\n        query[kSecMatchLimit as String] = kSecMatchLimitOne\n        query[kSecReturnData as String] = kCFBooleanTrue\n\n        var result: AnyObject?\n        let status = withUnsafeMutablePointer(to: &result) {\n            SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0))\n        }\n\n        guard status == errSecSuccess,\n            let data = result as? Data else {\n            return nil\n        }\n\n        return data\n    }\n\n    private func set(_ data: Data,\n                     forKey key: String,\n                     useObjectiveCKeychain: Bool = false,\n                     oldAccessGroup: ParseKeychainAccessGroup,\n                     newAccessGroup: ParseKeychainAccessGroup) throws {\n        var query = keychainQuery(forKey: key,\n                                  accessGroup: oldAccessGroup)\n        var update: [String: Any] = [\n            kSecValueData as String: data\n        ]\n\n        if !useObjectiveCKeychain {\n            if let newKeychainAccessGroup = newAccessGroup.accessGroup {\n                update[kSecAttrAccessGroup as String] = newKeychainAccessGroup\n                if newAccessGroup.isSyncingKeychainAcrossDevices && isSyncableKey(key) {\n                    update[kSecAttrSynchronizable as String] = kCFBooleanTrue\n                    update[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlock as String\n                } else {\n                    update[kSecAttrSynchronizable as String] = kCFBooleanFalse\n                    update[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly as String\n                }\n            } else {\n                query.removeValue(forKey: kSecAttrAccessGroup as String)\n                update[kSecAttrSynchronizable as String] = kCFBooleanFalse\n                update[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly as String\n            }\n        } else {\n            update[kSecAttrAccessible as String] = kSecAttrAccessibleAfterFirstUnlock as String\n        }\n\n        let status = synchronizationQueue.sync(flags: .barrier) { () -> OSStatus in\n            let mergedQuery = query.merging(update) { (_, otherValue) -> Any in otherValue }\n            if self.data(forKey: key,\n                         accessGroup: newAccessGroup) != nil {\n                let updateStatus = SecItemUpdate(query as CFDictionary, update as CFDictionary)\n                guard updateStatus == errSecDuplicateItem,\n                      SecItemDelete(mergedQuery as CFDictionary) == errSecSuccess else {\n                    return updateStatus\n                }\n            }\n            return SecItemAdd(mergedQuery as CFDictionary, nil)\n        }\n\n        guard status == errSecSuccess else {\n            throw ParseError(code: .unknownError,\n                             message: \"Could not save to Keychain, OSStatus: \\(status)\")\n        }\n    }\n\n    private func removeObject(forKey key: String,\n                              useObjectiveCKeychain: Bool = false,\n                              accessGroup: ParseKeychainAccessGroup) -> Bool {\n        dispatchPrecondition(condition: .onQueue(synchronizationQueue))\n        let query = keychainQuery(forKey: key,\n                                  useObjectiveCKeychain: useObjectiveCKeychain,\n                                  accessGroup: accessGroup) as CFDictionary\n        return SecItemDelete(query) == errSecSuccess\n    }\n\n    func removeOldObjects(accessGroup: ParseKeychainAccessGroup) -> Bool {\n        var query = getKeychainQueryTemplate()\n        query[kSecReturnAttributes as String] = kCFBooleanTrue\n        query[kSecMatchLimit as String] = kSecMatchLimitAll\n\n        return synchronizationQueue.sync(flags: .barrier) { () -> Bool in\n            var result: AnyObject?\n            let status = withUnsafeMutablePointer(to: &result) {\n                SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0))\n            }\n            if status != errSecSuccess { return true }\n\n            guard let results = result as? [[String: Any]] else { return false }\n\n            for item in results {\n                guard let key = item[kSecAttrAccount as String] as? String,\n                      isSyncableKey(key) else {\n                    continue\n                }\n                guard self.removeObject(forKey: key,\n                                        accessGroup: accessGroup) else {\n                    return false\n                }\n            }\n            return true\n        }\n    }\n\n    func removeAllObjects(useObjectiveCKeychain: Bool) -> Bool {\n        var query = useObjectiveCKeychain ? getObjectiveCKeychainQueryTemplate() : getKeychainQueryTemplate()\n        query[kSecReturnAttributes as String] = kCFBooleanTrue\n        query[kSecMatchLimit as String] = kSecMatchLimitAll\n\n        return synchronizationQueue.sync(flags: .barrier) { () -> Bool in\n            var result: AnyObject?\n            let status = withUnsafeMutablePointer(to: &result) {\n                SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0))\n            }\n            if status != errSecSuccess { return true }\n\n            guard let results = result as? [[String: Any]] else { return false }\n\n            for item in results {\n                guard let key = item[kSecAttrAccount as String] as? String else {\n                    continue\n                }\n                let removedDefaultObject = self.removeObject(forKey: key,\n                                                             useObjectiveCKeychain: useObjectiveCKeychain,\n                                                             accessGroup: Parse.configuration.keychainAccessGroup)\n                if !useObjectiveCKeychain {\n                    var mutatedKeychainAccessGroup = Parse.configuration.keychainAccessGroup\n                    mutatedKeychainAccessGroup.isSyncingKeychainAcrossDevices.toggle()\n                    let removedToggledObject = self.removeObject(forKey: key,\n                                                                 accessGroup: mutatedKeychainAccessGroup)\n                    mutatedKeychainAccessGroup.accessGroup = nil\n                    let removedNoAccessGroupObject = self.removeObject(forKey: key,\n                                                                       accessGroup: mutatedKeychainAccessGroup)\n                    if !(removedDefaultObject || removedToggledObject || removedNoAccessGroupObject) {\n                        return false\n                    }\n                }\n            }\n            return true\n        }\n    }\n}\n\n// MARK: SecureStorage\nextension KeychainStore {\n    func object<T>(forKey key: String) -> T? where T: Decodable {\n        guard let data = synchronizationQueue.sync(execute: { () -> Data? in\n            return self.data(forKey: key,\n                             accessGroup: Parse.configuration.keychainAccessGroup)\n        }) else {\n            return nil\n        }\n        do {\n            return try ParseCoding.jsonDecoder().decode(T.self, from: data)\n        } catch {\n            return nil\n        }\n    }\n\n    func set<T>(object: T?, forKey key: String) -> Bool where T: Encodable {\n        guard let object = object else {\n            return removeObject(forKey: key)\n        }\n        do {\n            let data = try ParseCoding.jsonEncoder().encode(object)\n            try set(data,\n                    forKey: key,\n                    oldAccessGroup: Parse.configuration.keychainAccessGroup,\n                    newAccessGroup: Parse.configuration.keychainAccessGroup)\n            return true\n        } catch {\n            return false\n        }\n    }\n\n    subscript<T>(key: String) -> T? where T: Codable {\n        get {\n            object(forKey: key)\n        }\n        set (object) {\n            _ = set(object: object, forKey: key)\n        }\n    }\n\n    func removeObject(forKey key: String) -> Bool {\n        return synchronizationQueue.sync {\n            return removeObject(forKey: key,\n                                accessGroup: Parse.configuration.keychainAccessGroup)\n        }\n    }\n\n    func removeAllObjects() -> Bool {\n        removeAllObjects(useObjectiveCKeychain: false)\n    }\n}\n\n// MARK: TypedSubscript\nextension KeychainStore {\n    subscript(string key: String) -> String? {\n        get {\n            object(forKey: key)\n        }\n        set (object) {\n            _ = set(object: object, forKey: key)\n        }\n    }\n\n    subscript(bool key: String) -> Bool? {\n        get {\n            object(forKey: key)\n        }\n        set (object) {\n            _ = set(object: object, forKey: key)\n        }\n    }\n}\n\n// MARK: Objective-C SDK Keychain\nextension KeychainStore {\n    func objectObjectiveC<T>(forKey key: String) -> T? where T: Decodable {\n        guard let data = synchronizationQueue.sync(execute: { () -> Data? in\n            return self.data(forKey: key,\n                             useObjectiveCKeychain: true,\n                             accessGroup: Parse.configuration.keychainAccessGroup)\n        }) else {\n            return nil\n        }\n        do {\n            return try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? T\n        } catch {\n            return nil\n        }\n    }\n\n    func removeObjectObjectiveC(forKey key: String) -> Bool {\n        return synchronizationQueue.sync {\n            return removeObject(forKey: key,\n                                useObjectiveCKeychain: true,\n                                accessGroup: Parse.configuration.keychainAccessGroup)\n        }\n    }\n\n    func setObjectiveC<T>(object: T?, forKey key: String) -> Bool where T: Encodable {\n        guard let object = object else {\n            return removeObjectObjectiveC(forKey: key)\n        }\n        do {\n            let data = try NSKeyedArchiver.archivedData(withRootObject: object, requiringSecureCoding: false)\n            try set(data,\n                    forKey: key,\n                    useObjectiveCKeychain: true,\n                    oldAccessGroup: Parse.configuration.keychainAccessGroup,\n                    newAccessGroup: Parse.configuration.keychainAccessGroup)\n            return true\n        } catch {\n            return false\n        }\n    }\n\n    func deleteAllObjectiveC() throws {\n        if !removeAllObjects(useObjectiveCKeychain: true) {\n            throw ParseError(code: .objectNotFound, message: \"Could not delete all objects in Keychain\")\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Storage/ParseFileManager.swift",
    "content": "//\n//  ParseFileManager.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 12/20/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/// Manages Parse files and directories.\npublic struct ParseFileManager {\n\n    private var defaultDirectoryAttributes: [FileAttributeKey: Any]? {\n        #if os(macOS) || os(Linux) || os(Android) || os(Windows)\n        return nil\n        #else\n        return [.protectionKey: FileProtectionType.completeUntilFirstUserAuthentication]\n        #endif\n    }\n\n    private var defaultDataWritingOptions: Data.WritingOptions {\n        var options = Data.WritingOptions.atomic\n        #if !os(macOS) && !os(Linux) && !os(Android) && !os(Windows)\n            options.insert(.completeFileProtectionUntilFirstUserAuthentication)\n        #endif\n        return options\n    }\n\n    private var localSandBoxDataDirectoryPath: URL? {\n        #if os(macOS) || os(Linux) || os(Android) || os(Windows)\n        return self.defaultDataDirectoryPath\n        #else\n        // swiftlint:disable:next line_length\n        let directoryPath = \"\\(NSHomeDirectory())/\\(ParseConstants.fileManagementLibraryDirectory)\\(ParseConstants.fileManagementPrivateDocumentsDirectory)\\(ParseConstants.fileManagementDirectory)\"\n        guard (try? createDirectoryIfNeeded(directoryPath)) != nil else {\n            return nil\n        }\n        return URL(fileURLWithPath: directoryPath, isDirectory: true)\n        #endif\n    }\n\n    private let synchronizationQueue = DispatchQueue(label: \"com.parse.file\",\n                                                     qos: .default,\n                                                     attributes: .concurrent,\n                                                     autoreleaseFrequency: .inherit,\n                                                     target: nil)\n\n    private let applicationIdentifier: String\n    private let applicationGroupIdentifer: String?\n\n    /// The default directory for storing Parse files.\n    public var defaultDataDirectoryPath: URL? {\n        #if os(macOS) || os(Linux) || os(Android) || os(Windows)\n        var directoryPath: String!\n        let paths = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true)\n        guard let directory = paths.first else {\n            return nil\n        }\n        directoryPath = directory\n        directoryPath += \"/\\(ParseConstants.fileManagementDirectory)\\(applicationIdentifier)\"\n        return URL(fileURLWithPath: directoryPath, isDirectory: true)\n        #else\n        if let groupIdentifier = applicationGroupIdentifer {\n            guard var directory = FileManager\n                    .default\n                    .containerURL(forSecurityApplicationGroupIdentifier: groupIdentifier) else {\n                return nil\n            }\n            directory.appendPathComponent(ParseConstants.fileManagementDirectory)\n            directory.appendPathComponent(applicationIdentifier)\n            return directory\n        } else {\n            return self.localSandBoxDataDirectoryPath\n        }\n        #endif\n    }\n\n    /// Creates an instance of `ParseFileManager`.\n    /// - returns: If an instance cannot be created, nil is returned.\n    public init?() {\n        #if os(Linux) || os(Android) || os(Windows)\n        let applicationId = Parse.configuration.applicationId\n        applicationIdentifier = \"\\(ParseConstants.bundlePrefix).\\(applicationId)\"\n        #else\n        if let identifier = Bundle.main.bundleIdentifier {\n            applicationIdentifier = identifier\n        } else {\n            return nil\n        }\n        #endif\n\n        applicationGroupIdentifer = nil\n    }\n}\n\n// MARK: Helper Methods (Internal)\nextension ParseFileManager {\n    func dataItemPathForPathComponent(_ component: String) -> URL? {\n        guard var path = self.defaultDataDirectoryPath else {\n            return nil\n        }\n        path.appendPathComponent(component)\n        return path\n    }\n\n    func createDirectoryIfNeeded(_ path: String) throws {\n        if !FileManager.default.fileExists(atPath: path) {\n            try FileManager.default.createDirectory(atPath: path,\n                                                    withIntermediateDirectories: true,\n                                                    attributes: defaultDirectoryAttributes)\n        }\n    }\n\n    func writeString(_ string: String, filePath: URL, completion: @escaping(Error?) -> Void) {\n        synchronizationQueue.async {\n            do {\n                guard let data = string.data(using: .utf8) else {\n                    completion(ParseError(code: .unknownError, message: \"Could not convert string to utf8\"))\n                    return\n                }\n                try data.write(to: filePath, options: self.defaultDataWritingOptions)\n                completion(nil)\n            } catch {\n                completion(error)\n            }\n        }\n    }\n\n    func writeData(_ data: Data, filePath: URL, completion: @escaping(Error?) -> Void) {\n        synchronizationQueue.async {\n            do {\n                try data.write(to: filePath, options: self.defaultDataWritingOptions)\n                completion(nil)\n            } catch {\n                completion(error)\n            }\n        }\n    }\n\n    func copyItem(_ fromPath: URL, toPath: URL, completion: @escaping(Error?) -> Void) {\n        synchronizationQueue.async {\n            do {\n                try FileManager.default.copyItem(at: fromPath, to: toPath)\n                completion(nil)\n            } catch {\n                completion(error)\n            }\n        }\n    }\n\n    func moveItem(_ fromPath: URL, toPath: URL, completion: @escaping(Error?) -> Void) {\n        synchronizationQueue.async {\n            if fromPath != toPath {\n                do {\n                    try FileManager.default.moveItem(at: fromPath, to: toPath)\n                    completion(nil)\n                } catch {\n                    completion(error)\n                }\n            } else {\n                completion(nil)\n            }\n        }\n    }\n\n    func moveContentsOfDirectory(_ fromPath: URL, toPath: URL, completion: @escaping(Error?) -> Void) {\n        synchronizationQueue.async {\n            do {\n                if fromPath == toPath {\n                    completion(nil)\n                    return\n                }\n\n                try self.createDirectoryIfNeeded(toPath.path)\n                let contents = try FileManager.default.contentsOfDirectory(atPath: fromPath.path)\n                if contents.count == 0 {\n                    completion(nil)\n                    return\n                }\n                try contents.forEach {\n                    let fromFilePath = fromPath.appendingPathComponent($0)\n                    let toFilePath = toPath.appendingPathComponent($0)\n                    try FileManager.default.moveItem(at: fromFilePath, to: toFilePath)\n                }\n                completion(nil)\n            } catch {\n                completion(error)\n            }\n        }\n    }\n\n    func removeDirectoryContents(_ path: URL, completion: @escaping(Error?) -> Void) {\n        synchronizationQueue.async {\n            do {\n                let contents = try FileManager.default.contentsOfDirectory(atPath: path.path)\n                if contents.count == 0 {\n                    completion(nil)\n                    return\n                }\n                try contents.forEach {\n                    let filePath = path.appendingPathComponent($0)\n                    try FileManager.default.removeItem(at: filePath)\n                }\n                completion(nil)\n            } catch {\n                completion(error)\n            }\n        }\n    }\n}\n\n// MARK: Helper Methods (External)\npublic extension ParseFileManager {\n\n    /**\n     The download directory for all `ParseFile`'s.\n     - returns: The download directory.\n     - throws: An error of type `ParseError`.\n     */\n    static func downloadDirectory() throws -> URL {\n        guard let fileManager = ParseFileManager(),\n              let defaultDirectoryPath = fileManager.defaultDataDirectoryPath else {\n            throw ParseError(code: .unknownError, message: \"Cannot create ParseFileManager\")\n        }\n        return defaultDirectoryPath\n            .appendingPathComponent(ParseConstants.fileDownloadsDirectory,\n                                    isDirectory: true)\n    }\n\n    /**\n     Check if a file exists in the Swift SDK download directory.\n     - parameter name: The name of the file to check.\n     - returns: The location of the file.\n     - throws: An error of type `ParseError`.\n     */\n    static func fileExists(_ name: String) throws -> URL {\n        let fileName = URL(fileURLWithPath: name).lastPathComponent\n        let fileLocation = try downloadDirectory().appendingPathComponent(fileName).relativePath\n        guard FileManager.default.fileExists(atPath: fileLocation) else {\n            throw ParseError(code: .unknownError, message: \"File does not exist\")\n        }\n        return URL(fileURLWithPath: fileLocation, isDirectory: false)\n    }\n\n    /**\n     Check if a `ParseFile` exists in the Swift SDK download directory.\n     - parameter file: The `ParseFile` to check.\n     - returns: The location of the file.\n     - throws: An error of type `ParseError`.\n     */\n    static func fileExists(_ file: ParseFile) throws -> URL {\n        try fileExists(file.name)\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Storage/ParseKeyValueStore.swift",
    "content": "//\n//  ParsePrimitiveStorable.swift\n//  \n//\n//  Created by Pranjal Satija on 7/19/20.\n//\n\nimport Foundation\n\n/**\n A store that supports key/value storage. It should be able\n to handle any object that conforms to encodable and decodable.\n */\n@available(*, deprecated, renamed: \"ParsePrimitiveStorable\")\npublic typealias ParseKeyValueStore = ParsePrimitiveStorable\n\n/**\n A store that supports key/value storage. It should be able\n to handle any object that conforms to encodable and decodable.\n */\npublic protocol ParsePrimitiveStorable {\n    /// Delete an object from the store.\n    /// - parameter key: The unique key value of the object.\n    mutating func delete(valueFor key: String) throws\n    /// Delete all objects from the store.\n    mutating func deleteAll() throws\n    /// Gets an object from the store based on its `key`.\n    /// - parameter key: The unique key value of the object.\n    mutating func get<T: Decodable>(valueFor key: String) throws -> T?\n    /// Stores an object in the store with a given `key`.\n    /// - parameter object: The object to store.\n    /// - parameter key: The unique key value of the object.\n    mutating func set<T: Encodable>(_ object: T, for key: String) throws\n}\n\n// MARK: InMemoryKeyValueStore\n\n/// A `ParseKeyValueStore` that lives in memory for unit testing purposes.\n/// It works by encoding / decoding all values just like a real `Codable` store would\n/// but it stores all values as `Data` blobs in memory.\nstruct InMemoryKeyValueStore: ParsePrimitiveStorable {\n    var decoder = ParseCoding.jsonDecoder()\n    var encoder = ParseCoding.jsonEncoder()\n    var storage = [String: Data]()\n\n    mutating func delete(valueFor key: String) throws {\n        storage[key] = nil\n    }\n\n    mutating func deleteAll() throws {\n        storage.removeAll()\n    }\n\n    mutating func get<T>(valueFor key: String) throws -> T? where T: Decodable {\n        guard let data = storage[key] else { return nil }\n        return try decoder.decode(T.self, from: data)\n    }\n\n    mutating func set<T>(_ object: T, for key: String) throws where T: Encodable {\n        let data = try encoder.encode(object)\n        storage[key] = data\n    }\n}\n\n#if !os(Linux) && !os(Android) && !os(Windows)\n\n// MARK: KeychainStore + ParseKeyValueStore\nextension KeychainStore: ParsePrimitiveStorable {\n\n    func delete(valueFor key: String) throws {\n        if !removeObject(forKey: key) {\n            throw ParseError(code: .objectNotFound, message: \"Object for key \\\"\\(key)\\\" not found in Keychain\")\n        }\n    }\n\n    func deleteAll() throws {\n        if !removeAllObjects() {\n            throw ParseError(code: .objectNotFound, message: \"Could not delete all objects in Keychain\")\n        }\n    }\n\n    func get<T>(valueFor key: String) throws -> T? where T: Decodable {\n        object(forKey: key)\n    }\n\n    func set<T>(_ object: T, for key: String) throws where T: Encodable {\n        if !set(object: object, forKey: key) {\n            throw ParseError(code: .unknownError,\n                             message: \"Could not save object: \\(object) key \\\"\\(key)\\\" in Keychain\")\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Storage/ParseStorage.swift",
    "content": "//\n//  ParseStorage.swift\n//  \n//\n//  Created by Pranjal Satija on 7/19/20.\n//\n\n// MARK: ParseStorage\nstruct ParseStorage {\n    public static var shared = ParseStorage()\n\n    private var backingStore: ParsePrimitiveStorable!\n\n    mutating func use(_ store: ParsePrimitiveStorable) {\n        self.backingStore = store\n    }\n\n    private mutating func requireBackingStore() {\n        guard backingStore != nil else {\n            print(\"\"\"\n                You cannot use ParseStorage without a backing store.\n                An in-memory store is being used as a fallback.\n            \"\"\")\n            return\n        }\n    }\n\n    enum Keys {\n        static let currentUser = \"_currentUser\"\n        static let currentInstallation = \"_currentInstallation\"\n        static let currentConfig = \"_currentConfig\"\n        static let defaultACL = \"_defaultACL\"\n        static let currentVersion = \"_currentVersion\"\n        static let currentAccessGroup = \"_currentAccessGroup\"\n    }\n}\n\n// MARK: ParseKeyValueStore\nextension ParseStorage: ParsePrimitiveStorable {\n    public mutating func delete(valueFor key: String) throws {\n        requireBackingStore()\n        return try backingStore.delete(valueFor: key)\n    }\n\n    public mutating func deleteAll() throws {\n        requireBackingStore()\n        return try backingStore.deleteAll()\n    }\n    public mutating func get<T>(valueFor key: String) throws -> T? where T: Decodable {\n        requireBackingStore()\n        return try backingStore.get(valueFor: key)\n    }\n\n    public mutating func set<T>(_ object: T, for key: String) throws where T: Encodable {\n        requireBackingStore()\n        return try backingStore.set(object, for: key)\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Storage/SecureStorage.swift",
    "content": "//\n//  SecureStorage.swift\n//  ParseSwift\n//\n//  Created by Florent Vilmart on 17-09-25.\n//  Copyright © 2017 Parse. All rights reserved.\n//\n\nimport Foundation\n\nprotocol SecureStorage {\n    init(service: String?)\n    func object<T>(forKey key: String) -> T? where T: Decodable\n    func set<T>(object: T?, forKey: String) -> Bool where T: Encodable\n    subscript <T>(key: String) -> T? where T: Codable { get }\n    func removeObject(forKey: String) -> Bool\n    func removeAllObjects() -> Bool\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/CloudViewModel.swift",
    "content": "//\n//  CloudViewModel.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 7/11/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n#if canImport(SwiftUI)\nimport Foundation\n\n/**\n A default implementation of the `CloudCodeObservable` protocol. Suitable for `ObjectObserved`\n and can be used as a SwiftUI view model. Also can be used as a Combine publisher. See Apple's\n [documentation](https://developer.apple.com/documentation/combine/observableobject)\n for more details.\n */\nopen class CloudViewModel<T: ParseCloudable>: CloudObservable {\n\n    public typealias CloudCodeType = T\n    public var cloudCode: T\n\n    /// Updates and notifies when the new results have been retrieved.\n    open var results: T.ReturnType? {\n        willSet {\n            if newValue != nil {\n                self.error = nil\n                DispatchQueue.main.async {\n                    self.objectWillChange.send()\n                }\n            }\n        }\n    }\n\n    /// Updates and notifies when there is an error retrieving the results.\n    open var error: ParseError? {\n        willSet {\n            if newValue != nil {\n                self.results = nil\n                DispatchQueue.main.async {\n                    self.objectWillChange.send()\n                }\n            }\n        }\n    }\n\n    required public init(cloudCode: T) {\n        self.cloudCode = cloudCode\n    }\n\n    public func runFunction(options: API.Options = []) {\n        cloudCode.runFunction(options: options) { results in\n            switch results {\n\n            case .success(let results):\n                self.results = results\n            case .failure(let error):\n                self.error = error\n            }\n        }\n    }\n\n    public func startJob(options: API.Options = []) {\n        cloudCode.startJob(options: options) { results in\n            switch results {\n\n            case .success(let results):\n                self.results = results\n            case .failure(let error):\n                self.error = error\n            }\n        }\n    }\n}\n\n// MARK: CloudCodeViewModel\npublic extension ParseCloudable {\n\n    /**\n     Creates a view model for this CloudCode. Suitable for `ObjectObserved`\n     as the view model can be used as a SwiftUI publisher. Meaning it can serve\n     indepedently as a ViewModel in MVVM.\n     */\n    var viewModel: CloudViewModel<Self> {\n        CloudViewModel(cloudCode: self)\n    }\n\n    /**\n     Creates a view model for this CloudCode. Suitable for `ObjectObserved`\n     as the view model can be used as a SwiftUI publisher. Meaning it can serve\n     indepedently as a ViewModel in MVVM.\n     - parameter query: Any query.\n     - returns: The view model for this query.\n     */\n    static func viewModel(_ cloudCode: Self) -> CloudViewModel<Self> {\n        CloudViewModel(cloudCode: cloudCode)\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Types/Parse.h",
    "content": "//\n//  Parse.h\n//  Parse\n//\n//  Created by Florent Vilmart on 17-07-23.\n//  Copyright © 2017 Parse. All rights reserved.\n//\n\n#import <Foundation/Foundation.h>\n\n//! Project version number for Parse.\nFOUNDATION_EXPORT double ParseVersionNumber;\n\n//! Project version string for Parse.\nFOUNDATION_EXPORT const unsigned char ParseVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <Parse/PublicHeader.h>\n\n\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseACL.swift",
    "content": "//\n//  ParseACL.swift\n//  ParseSwift\n//\n//  Created by Florent Vilmart on 17-08-19.\n//  Copyright © 2017 Parse. All rights reserved.\n//\n\nimport Foundation\n\n/**\n `ParseACL` is used to control which users can access or modify a particular `ParseObject`.\n Each `ParseObject` has its own ACL. You can grant read and write permissions separately \n to specific users, to groups of users that belong to roles, or you can grant permissions to\n **the public** so that, for example, any user could read a particular object but only a \n particular set of users could write to that object.\n*/\npublic struct ParseACL: ParseTypeable,\n                        Hashable {\n    private static let publicScope = \"*\"\n    private var acl: [String: [Access: Bool]]?\n\n    /**\n     An enum specifying read and write access controls.\n    */\n    public enum Access: String, Codable, CodingKey {\n        /// Read access control.\n        case read\n        /// Write access control.\n        case write\n\n        public init(from decoder: Decoder) throws {\n            guard let decoded = Access(rawValue: try decoder.singleValueContainer().decode(String.self)) else {\n                throw ParseError(code: .unknownError, message: \"Not able to decode ParseACL Access\")\n            }\n            self = decoded\n        }\n\n        public func encode(to encoder: Encoder) throws {\n            var container = encoder.singleValueContainer()\n            try container.encode(rawValue)\n        }\n    }\n\n    /// The default initializer.\n    public init() { }\n\n    static func getRoleAccessName<R>(_ role: R) throws -> String where R: ParseRole {\n        guard let name = role.name else {\n            throw ParseError(code: .unknownError, message: \"Name of ParseRole cannot be nil\")\n        }\n        return getRoleAccessName(name)\n    }\n\n    static func getRoleAccessName(_ name: String) -> String {\n        return \"role:\\(name)\"\n    }\n\n    /**\n     Controls whether the public is allowed to read this object.\n    */\n    public var publicRead: Bool {\n        get {\n            return get(ParseACL.publicScope, access: .read)\n        }\n        set {\n            set(ParseACL.publicScope, access: .read, value: newValue)\n        }\n    }\n\n    /**\n     Controls whether the public is allowed to write this object.\n    */\n    public var publicWrite: Bool {\n        get {\n            return get(ParseACL.publicScope, access: .write)\n        }\n        set {\n            set(ParseACL.publicScope, access: .write, value: newValue)\n        }\n    }\n\n    /**\n     Returns true if a particular key has a specific access level.\n     - parameter key: The key of the `ParseUser` or `ParseRole` for which to retrieve access.\n     - parameter access: The type of access.\n     - returns: **true** if the `key` has *explicit* access, otherwise **false**.\n    */\n    func get(_ key: String, access: Access) -> Bool {\n        guard let acl = acl else { // no acl, all open!\n            return false\n        }\n        return acl[key]?[access] ?? false\n    }\n\n    // MARK: ParseUser\n    /**\n     Gets whether the given `objectId` is *explicitly* allowed to read this object.\n     Even if this returns **false**, the user may still be able to access it if `publicReadAccess` returns **true**\n     or if the user belongs to a role that has access.\n\n     - parameter objectId: The `ParseUser.objectId` of the user for which to retrieve access.\n     - returns: **true** if the user with this `objectId` has *explicit* read access, otherwise **false**.\n    */\n    public func getReadAccess(objectId: String) -> Bool {\n        get(objectId, access: .read)\n    }\n\n    /**\n     Gets whether the given `ParseUser` is *explicitly* allowed to read this object.\n     Even if this returns **false**, the user may still be able to access it if `publicReadAccess` returns **true**\n     or if the user belongs to a role that has access.\n\n     - parameter user: The `ParseUser` for which to retrieve access.\n     - returns: **true** if the user with this `ParseUser` has *explicit* read access, otherwise **false**.\n    */\n    public func getReadAccess<T>(user: T) -> Bool where T: ParseUser {\n        if let objectId = user.objectId {\n            return get(objectId, access: .read)\n        } else {\n            return false\n        }\n    }\n\n    /**\n     Gets whether the given `objectId` is *explicitly* allowed to write this object.\n     Even if this returns false, the user may still be able to write it if `publicWriteAccess` returns **true**\n     or if the user belongs to a role that has access.\n\n     - parameter objectId: The `ParseUser.objectId` of the user for which to retrieve access.\n     - returns: **true** if the user with this `ParseUser.objectId` has *explicit* write access, otherwise **false**.\n    */\n    public func getWriteAccess(objectId: String) -> Bool {\n        return get(objectId, access: .write)\n    }\n\n    /**\n     Gets whether the given `ParseUser` is *explicitly* allowed to write this object.\n     Even if this returns false, the user may still be able to write it if `publicWriteAccess` returns **true**\n     or if the user belongs to a role that has access.\n\n     - parameter user: The `ParseUser` of the user for which to retrieve access.\n     - returns: **true** if the `ParseUser` has *explicit* write access, otherwise **false**.\n    */\n    public func getWriteAccess<T>(user: T) -> Bool where T: ParseUser {\n        if let objectId = user.objectId {\n            return get(objectId, access: .write)\n        } else {\n            return false\n        }\n    }\n\n    /**\n     Set whether the given `objectId` is allowed to read this object.\n\n     - parameter value: Whether the given user can read this object.\n     - parameter objectId: The `ParseUser.objectId` of the user to assign access.\n    */\n    public mutating func setReadAccess(objectId: String, value: Bool) {\n        set(objectId, access: .read, value: value)\n    }\n\n    /**\n     Set whether the given `ParseUser` is allowed to read this object.\n\n     - parameter value: Whether the given user can read this object.\n     - parameter user: The `ParseUser` to assign access.\n    */\n    public mutating func setReadAccess<T>(user: T, value: Bool) where T: ParseUser {\n        if let objectId = user.objectId {\n            set(objectId, access: .read, value: value)\n        }\n    }\n\n    /**\n     Set whether the given `objectId` is allowed to write this object.\n\n     - parameter value: Whether the given user can write this object.\n     - parameter objectId: The `ParseUser.objectId` of the user to assign access.\n    */\n    public mutating func setWriteAccess(objectId: String, value: Bool) {\n        set(objectId, access: .write, value: value)\n    }\n\n    /**\n     Set whether the given `ParseUser` is allowed to write this object.\n\n     - parameter value: Whether the given user can write this object.\n     - parameter user: The `ParseUser` to assign access.\n    */\n    public mutating func setWriteAccess<T>(user: T, value: Bool) where T: ParseUser {\n        if let objectId = user.objectId {\n            set(objectId, access: .write, value: value)\n        }\n    }\n\n    // MARK: ParseRole\n\n    /**\n     Get whether users belonging to the role with the given name are allowed to read this object.\n     Even if this returns **false**, the role may still be able to read it if a parent role has read access.\n\n     - parameter roleName: The name of the role.\n     - returns: **true** if the role has read access, otherwise **false**.\n    */\n    public func getReadAccess(roleName: String) -> Bool {\n        get(Self.getRoleAccessName(roleName), access: .read)\n    }\n\n    /**\n     Get whether users belonging to the role are allowed to read this object.\n     Even if this returns **false**, the role may still be able to read it if a parent role has read access.\n\n     - parameter role: The `ParseRole` to get access for.\n     - returns: **true** if the `ParseRole` has read access, otherwise **false**.\n    */\n    public func getReadAccess<T>(role: T) -> Bool where T: ParseRole {\n        guard let name = role.name else { return false }\n        return get(Self.getRoleAccessName(name), access: .read)\n    }\n\n    /**\n     Get whether users belonging to the role with the given name are allowed to write this object.\n     Even if this returns **false**, the role may still be able to write it if a parent role has write access.\n\n     - parameter roleName: The name of the role.\n     - returns: **true** if the role has read access, otherwise **false**.\n    */\n    public func getWriteAccess(roleName: String) -> Bool {\n        get(Self.getRoleAccessName(roleName), access: .write)\n    }\n\n    /**\n     Get whether users belonging to the role are allowed to write this object.\n     Even if this returns **false**, the role may still be able to write it if a parent role has write access.\n\n     - parameter role: The `ParseRole` to get access for.\n     - returns: **true** if the role has read access, otherwise **false**.\n    */\n    public func getWriteAccess<T>(role: T) -> Bool where T: ParseRole {\n        guard let name = role.name else { return false }\n        return get(Self.getRoleAccessName(name), access: .write)\n    }\n\n    /**\n     Set whether users belonging to the role with the given name are allowed to read this object.\n\n     - parameter value: Whether the given role can read this object.\n     - parameter roleName: The name of the role.\n    */\n    public mutating func setReadAccess(roleName: String, value: Bool) {\n        set(Self.getRoleAccessName(roleName), access: .read, value: value)\n    }\n\n    /**\n     Set whether users belonging to the role are allowed to read this object.\n\n     - parameter value: Whether the given role can read this object.\n     - parameter role: The `ParseRole` to set access for.\n    */\n    public mutating func setReadAccess<T>(role: T, value: Bool) where T: ParseRole {\n        guard let name = role.name else { return }\n        set(Self.getRoleAccessName(name), access: .read, value: value)\n    }\n\n    /**\n     Set whether users belonging to the role with the given name are allowed to write this object.\n\n     - parameter allowed: Whether the given role can write this object.\n     - parameter roleName: The name of the role.\n    */\n    public mutating func setWriteAccess(roleName: String, value: Bool) {\n        set(Self.getRoleAccessName(roleName), access: .write, value: value)\n    }\n\n    /**\n     Set whether users belonging to the role are allowed to write this object.\n\n     - parameter allowed: Whether the given role can write this object.\n     - parameter role: The `ParseRole` to set access for.\n    */\n    public mutating func setWriteAccess<T>(role: T, value: Bool) where T: ParseRole {\n        guard let name = role.name else { return }\n        set(Self.getRoleAccessName(name), access: .write, value: value)\n    }\n\n    private mutating func set(_ key: String, access: Access, value: Bool) {\n        // initialized the backing dictionary if needed\n        if acl == nil && value { // do not create if value is false (no-op)\n            acl = [:]\n        }\n        // initialize the scope dictionary\n        if acl?[key] == nil && value { // do not create if value is false (no-op)\n            acl?[key] = [:]\n        }\n        if value {\n            acl?[key]?[access] = value\n        } else {\n            acl?[key]?.removeValue(forKey: access)\n            if acl?[key]?.isEmpty == true {\n                acl?.removeValue(forKey: key)\n            }\n            if acl?.isEmpty == true {\n                acl = nil // cleanup\n            }\n        }\n    }\n}\n\n// Default ACL\nextension ParseACL {\n    /**\n     Get the default ACL from the Keychain.\n     - returns: Returns the default ACL.\n     - throws: An error of type `ParseError`.\n    */\n    public static func defaultACL() throws -> Self {\n\n        let aclController: DefaultACL!\n\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        if let controller: DefaultACL = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.defaultACL) {\n            aclController = controller\n        } else {\n            throw ParseError(code: .unknownError,\n                             message: \"Default ACL cannot be found in Keychain. You should `setDefaultACL` first\")\n        }\n        #else\n        if let controller: DefaultACL = try? ParseStorage.shared.get(valueFor: ParseStorage.Keys.defaultACL) {\n            aclController = controller\n        } else {\n            throw ParseError(code: .unknownError,\n                             message: \"Default ACL cannot be found in Keychain. You should `setDefaultACL` first\")\n        }\n        #endif\n\n        if !aclController.useCurrentUser {\n            return aclController.defaultACL\n        } else {\n            guard let userObjectId = BaseParseUser.current?.objectId else {\n                return aclController.defaultACL\n            }\n\n            guard let lastCurrentUserObjectId = aclController.lastCurrentUserObjectId,\n                userObjectId == lastCurrentUserObjectId else {\n                return try setDefaultACL(ParseACL(), withAccessForCurrentUser: true)\n            }\n\n            return aclController.defaultACL\n        }\n    }\n\n    /**\n     Sets a default ACL that can later be used by `ParseObjects`. The default ACL\n     is persisted to the Keychain. This value will be copied and used as a template when\n     new `ParseObject`'s are created locally. Any changes to the default ACL will not\n     have effect on already saved `ParseObject`'s.\n\n     - parameter acl: The ACL to use as a template for instances of `ParseObject`.\n     - parameter withAccessForCurrentUser: If **true**, the `ACL` that is applied to\n     newly-created instance of `ParseObject` will provide read and write access to the\n     `ParseUser.currentUser` at the time of creation. If **false**, the provided `acl`\n     will be used without modification. If `acl` is `nil`, this value is ignored.\n     - returns: Updated default ACL.\n     - throws: An error of type `ParseError`.\n    */\n    public static func setDefaultACL(_ acl: ParseACL, withAccessForCurrentUser: Bool) throws -> ParseACL {\n\n        guard let currentUser = BaseParseUser.current,\n            let currentUserObjectId = currentUser.objectId else {\n            throw ParseError(code: .missingObjectId, message: \"Cannot set defaultACL with no current user\")\n        }\n\n        let modifiedACL: ParseACL?\n        if withAccessForCurrentUser {\n            modifiedACL = setDefaultAccess(acl, user: currentUser)\n        } else {\n            modifiedACL = acl\n        }\n\n        let aclController: DefaultACL!\n        if let modified = modifiedACL {\n            aclController = DefaultACL(defaultACL: modified,\n                                       lastCurrentUserObjectId: currentUserObjectId,\n                                       useCurrentUser: withAccessForCurrentUser)\n        } else {\n            aclController =\n                DefaultACL(defaultACL: acl,\n                           lastCurrentUserObjectId: currentUserObjectId,\n                           useCurrentUser: withAccessForCurrentUser)\n        }\n\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.set(aclController, for: ParseStorage.Keys.defaultACL)\n        #else\n        try ParseStorage.shared.set(aclController, for: ParseStorage.Keys.defaultACL)\n        #endif\n        return aclController.defaultACL\n    }\n\n    private static func setDefaultAccess<T>(_ acl: ParseACL, user: T) -> ParseACL? where T: ParseUser {\n        var modifiedACL = acl\n        modifiedACL.setReadAccess(user: user, value: true)\n        modifiedACL.setWriteAccess(user: user, value: true)\n\n        return modifiedACL\n    }\n\n    internal static func deleteDefaultFromKeychain() {\n        try? ParseStorage.shared.delete(valueFor: ParseStorage.Keys.defaultACL)\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try? KeychainStore.shared.delete(valueFor: ParseStorage.Keys.defaultACL)\n        #endif\n    }\n}\n\n// Encoding and decoding\nextension ParseACL {\n    public init(from decoder: Decoder) throws {\n        let container = try decoder.container(keyedBy: RawCodingKey.self)\n        try container.allKeys.lazy.map { (scope) -> (String, KeyedDecodingContainer<ParseACL.Access>) in\n            return (scope.stringValue,\n                    try container.nestedContainer(keyedBy: Access.self, forKey: scope))\n            }.flatMap { pair -> [(String, Access, Bool)] in\n                let (scope, accessValues) = pair\n                return try accessValues.allKeys.compactMap { (access) -> (String, Access, Bool)? in\n                    guard let value = try accessValues.decodeIfPresent(Bool.self, forKey: access) else {\n                        return nil\n                    }\n                    return (scope, access, value)\n                }\n            }.forEach {\n                set($0, access: $1, value: $2)\n            }\n    }\n\n    public func encode(to encoder: Encoder) throws {\n        guard let acl = acl else { return } // only encode if acl is present\n        var container = encoder.container(keyedBy: RawCodingKey.self)\n        try acl.forEach { pair in\n            let (scope, values) = pair\n            var nestedContainer = container.nestedContainer(keyedBy: Access.self,\n                                                            forKey: .key(scope))\n            try values.forEach { (pair) in\n                let (access, value) = pair\n                try nestedContainer.encode(value, forKey: access)\n            }\n        }\n    }\n\n}\n\nstruct DefaultACL: Codable, Hashable {\n    var defaultACL: ParseACL\n    var lastCurrentUserObjectId: String?\n    var useCurrentUser: Bool\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseAnalytics+async.swift",
    "content": "//\n//  ParseAnalytics+async.swift\n//  ParseAnalytics+async\n//\n//  Created by Corey Baker on 8/6/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n\n#if os(iOS)\nimport UIKit\n#endif\n\npublic extension ParseAnalytics {\n\n    // MARK: Aysnc/Await\n\n    #if os(iOS)\n    /**\n     Tracks *asynchronously* this application being launched. If this happened as the result of the\n     user opening a push notification, this method sends along information to\n     correlate this open with that push.\n     \n     - parameter launchOptions: The dictionary indicating the reason the application was\n     launched, if any. This value can be found as a parameter to various\n     `UIApplicationDelegate` methods, and can be empty or `nil`.\n     - parameter at: Explicitly set the time associated with a given event. If not provided the\n     server time will be used.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n    */\n    static func trackAppOpened(launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil,\n                               at date: Date? = nil,\n                               options: API.Options = []) async throws {\n        let result = try await withCheckedThrowingContinuation { continuation in\n            Self.trackAppOpened(launchOptions: launchOptions,\n                                at: date,\n                                options: options,\n                                completion: continuation.resume)\n        }\n        if case let .failure(error) = result {\n            throw error\n        }\n    }\n    #endif\n\n    /**\n     Tracks *asynchronously* this application being launched. If this happened as the result of the\n     user opening a push notification, this method sends along information to\n     correlate this open with that push.\n     \n     - parameter dimensions: The dictionary of information by which to segment this\n     event and can be empty or `nil`.\n     - parameter at: Explicitly set the time associated with a given event. If not provided the\n     server time will be used.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n    */\n    static func trackAppOpened(dimensions: [String: String]? = nil,\n                               at date: Date? = nil,\n                               options: API.Options = []) async throws {\n        let result = try await withCheckedThrowingContinuation { continuation in\n            Self.trackAppOpened(dimensions: dimensions,\n                                at: date,\n                                options: options,\n                                completion: continuation.resume)\n        }\n        if case let .failure(error) = result {\n            throw error\n        }\n    }\n\n    /**\n     Tracks *asynchronously* the occurrence of a custom event.\n  \n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n    */\n    func track(options: API.Options = []) async throws {\n        let result = try await withCheckedThrowingContinuation { continuation in\n            self.track(options: options,\n                       completion: continuation.resume)\n        }\n        if case let .failure(error) = result {\n            throw error\n        }\n    }\n\n    /**\n     Tracks *asynchronously* the occurrence of a custom event with additional dimensions.\n  \n     - parameter dimensions: The dictionary of information by which to segment this\n     event and can be empty or `nil`.\n     - parameter at: Explicitly set the time associated with a given event. If not provided the\n     server time will be used.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n    */\n    mutating func track(dimensions: [String: String]?,\n                        at date: Date? = nil,\n                        options: API.Options = []) async throws {\n        let result = try await withCheckedThrowingContinuation { continuation in\n            self.track(dimensions: dimensions,\n                       at: date,\n                       options: options,\n                       completion: continuation.resume)\n        }\n        if case let .failure(error) = result {\n            throw error\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseAnalytics+combine.swift",
    "content": "//\n//  ParseAnalytics+combine.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 5/20/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\n#if os(iOS)\nimport UIKit\n#endif\n\npublic extension ParseAnalytics {\n\n    // MARK: Combine\n\n    #if os(iOS)\n    /**\n     Tracks *asynchronously* this application being launched. If this happened as the result of the\n     user opening a push notification, this method sends along information to\n     correlate this open with that push. Publishes when complete.\n     \n     - parameter launchOptions: The dictionary indicating the reason the application was\n     launched, if any. This value can be found as a parameter to various\n     `UIApplicationDelegate` methods, and can be empty or `nil`.\n     - parameter at: Explicitly set the time associated with a given event. If not provided the\n     server time will be used.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n    */\n    static func trackAppOpenedPublisher(launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil,\n                                        at date: Date? = nil,\n                                        options: API.Options = []) -> Future<Void, ParseError> {\n        Future { promise in\n            Self.trackAppOpened(launchOptions: launchOptions,\n                                at: date,\n                                options: options,\n                                completion: promise)\n        }\n    }\n    #endif\n\n    /**\n     Tracks *asynchronously* this application being launched. If this happened as the result of the\n     user opening a push notification, this method sends along information to\n     correlate this open with that push. Publishes when complete.\n     \n     - parameter dimensions: The dictionary of information by which to segment this\n     event and can be empty or `nil`.\n     - parameter at: Explicitly set the time associated with a given event. If not provided the\n     server time will be used.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n    */\n    static func trackAppOpenedPublisher(dimensions: [String: String]? = nil,\n                                        at date: Date? = nil,\n                                        options: API.Options = []) -> Future<Void, ParseError> {\n        Future { promise in\n            Self.trackAppOpened(dimensions: dimensions,\n                                at: date,\n                                options: options,\n                                completion: promise)\n        }\n    }\n\n    /**\n     Tracks *asynchronously* the occurrence of a custom event. Publishes when complete.\n  \n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n    */\n    func trackPublisher(options: API.Options = []) -> Future<Void, ParseError> {\n        Future { promise in\n            self.track(options: options,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Tracks *asynchronously* the occurrence of a custom event with additional dimensions.\n     Publishes when complete.\n  \n     - parameter dimensions: The dictionary of information by which to segment this\n     event and can be empty or `nil`.\n     - parameter at: Explicitly set the time associated with a given event. If not provided the\n     server time will be used.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - warning: This method makes a copy of the current `ParseAnalytics` and then mutates\n     it. You will not have access to the mutated analytic after calling this method.\n    */\n    func trackPublisher(dimensions: [String: String]?,\n                        at date: Date? = nil,\n                        options: API.Options = []) -> Future<Void, ParseError> {\n        Future { promise in\n            var analytic = self\n            analytic.track(dimensions: dimensions,\n                           at: date,\n                           options: options,\n                           completion: promise)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseAnalytics.swift",
    "content": "//\n//  ParseAnalytics.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 5/20/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n#if os(iOS)\nimport UIKit\n#endif\n\n/**\n `ParseAnalytics` provides an interface to Parse's logging and analytics backend.\n */\npublic struct ParseAnalytics: ParseTypeable, Hashable {\n\n    /// The name of the custom event to report to Parse as having happened.\n    public var name: String\n\n    /// Explicitly set the time associated with a given event. If not provided the server\n    /// time will be used.\n    /// - warning: This will be removed in ParseSwift 5.0.0 in favor of `date`.\n    @available(*, deprecated, renamed: \"date\")\n    public var at: Date? { // swiftlint:disable:this identifier_name\n        get {\n            date\n        }\n        set {\n            date = newValue\n        }\n    }\n\n    /// Explicitly set the time associated with a given event. If not provided the server\n    /// time will be used.\n    public var date: Date?\n\n    /// The dictionary of information by which to segment this event.\n    public var dimensions: [String: Codable]? {\n        get {\n            convertToString(dimensionsAnyCodable)\n        }\n        set {\n            dimensionsAnyCodable = convertToAnyCodable(newValue)\n        }\n    }\n\n    var dimensionsAnyCodable: [String: AnyCodable]?\n\n    enum CodingKeys: String, CodingKey {\n        case date = \"at\"\n        case dimensions\n        case name\n    }\n\n    /**\n     Create an instance of ParseAnalytics for tracking.\n     - parameter name: The name of the custom event to report to Parse as having happened.\n     - parameter dimensions: The dictionary of information by which to segment this event. Defaults to `nil`.\n     - parameter at: Explicitly set the time associated with a given event. If not provided the server\n     time will be used. Defaults to `nil`.\n     */\n    public init (name: String,\n                 dimensions: [String: Codable]? = nil,\n                 at date: Date? = nil) {\n        self.name = name\n        self.dimensionsAnyCodable = convertToAnyCodable(dimensions)\n        self.date = date\n    }\n\n    // MARK: Helpers\n    func convertToAnyCodable(_ dimensions: [String: Codable]?) -> [String: AnyCodable]? {\n        guard let dimensions = dimensions else {\n            return nil\n        }\n        var convertedDimensions = [String: AnyCodable]()\n        for (key, value) in dimensions {\n            convertedDimensions[key] = AnyCodable(value)\n        }\n        return convertedDimensions\n    }\n\n    func convertToString(_ dimensions: [String: AnyCodable]?) -> [String: String]? {\n        guard let dimensions = dimensions else {\n            return nil\n        }\n        var convertedDimensions = [String: String]()\n        for (key, value) in dimensions {\n            convertedDimensions[key] = \"\\(value.value)\"\n        }\n        return convertedDimensions\n    }\n\n    // MARK: Intents\n\n    #if os(iOS)\n    /**\n     Tracks *asynchronously* this application being launched. If this happened as the result of the\n     user opening a push notification, this method sends along information to\n     correlate this open with that push.\n     \n     - parameter launchOptions: The dictionary indicating the reason the application was\n     launched, if any. This value can be found as a parameter to various\n     `UIApplicationDelegate` methods, and can be empty or `nil`.\n     - parameter at: Explicitly set the time associated with a given event. If not provided the\n     server time will be used.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: A block that will be called when file deletes or fails.\n     It should have the following argument signature: `(Result<Void, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    static public func trackAppOpened(launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil,\n                                      at date: Date? = nil,\n                                      options: API.Options = [],\n                                      callbackQueue: DispatchQueue = .main,\n                                      completion: @escaping (Result<Void, ParseError>) -> Void) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        var userInfo: [String: String]?\n        if let remoteOptions = launchOptions?[.remoteNotification] as? [String: String] {\n            userInfo = remoteOptions\n        }\n        let appOppened = ParseAnalytics(name: \"AppOpened\",\n                                        dimensions: userInfo,\n                                        at: date)\n        appOppened.saveCommand().executeAsync(options: options,\n                                              callbackQueue: callbackQueue) { result in\n            switch result {\n            case .success:\n                completion(.success(()))\n            case .failure(let error):\n                completion(.failure(error))\n            }\n        }\n    }\n    #endif\n\n    /**\n     Tracks *asynchronously* this application being launched with additional dimensions.\n     \n     - parameter dimensions: The dictionary of information by which to segment this\n     event. Can be empty or `nil`.\n     - parameter at: Explicitly set the time associated with a given event. If not provided the\n     server time will be used.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: A block that will be called when file deletes or fails.\n     It should have the following argument signature: `(Result<Void, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    static public func trackAppOpened(dimensions: [String: String]? = nil,\n                                      at date: Date? = nil,\n                                      options: API.Options = [],\n                                      callbackQueue: DispatchQueue = .main,\n                                      completion: @escaping (Result<Void, ParseError>) -> Void) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        let appOppened = ParseAnalytics(name: \"AppOpened\",\n                                        dimensions: dimensions,\n                                        at: date)\n        appOppened.saveCommand().executeAsync(options: options,\n                                              callbackQueue: callbackQueue) { result in\n            switch result {\n            case .success:\n                completion(.success(()))\n            case .failure(let error):\n                completion(.failure(error))\n            }\n        }\n    }\n\n    /**\n     Tracks *asynchronously* the occurrence of a custom event.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: A block that will be called when file deletes or fails.\n     It should have the following argument signature: `(Result<Void, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func track(options: API.Options = [],\n                      callbackQueue: DispatchQueue = .main,\n                      completion: @escaping (Result<Void, ParseError>) -> Void) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        self.saveCommand().executeAsync(options: options,\n                                        callbackQueue: callbackQueue) { result in\n            switch result {\n            case .success:\n                completion(.success(()))\n            case .failure(let error):\n                completion(.failure(error))\n            }\n        }\n    }\n\n    /**\n     Tracks *asynchronously* the occurrence of a custom event with additional dimensions.\n     \n     - parameter dimensions: The dictionary of information by which to segment this\n     event. Can be empty or `nil`.\n     - parameter at: Explicitly set the time associated with a given event. If not provided the\n     server time will be used.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: A block that will be called when file deletes or fails.\n     It should have the following argument signature: `(Result<Void, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public mutating func track(dimensions: [String: String]?,\n                               at date: Date? = nil,\n                               options: API.Options = [],\n                               callbackQueue: DispatchQueue = .main,\n                               completion: @escaping (Result<Void, ParseError>) -> Void) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        self.dimensionsAnyCodable = convertToAnyCodable(dimensions)\n        self.date = date\n        self.saveCommand().executeAsync(options: options,\n                                        callbackQueue: callbackQueue) { result in\n            switch result {\n            case .success:\n                completion(.success(()))\n            case .failure(let error):\n                completion(.failure(error))\n            }\n        }\n    }\n\n    internal func saveCommand() -> API.NonParseBodyCommand<Self, NoBody> {\n        return API.NonParseBodyCommand(method: .POST,\n                                       path: .event(event: name),\n                                       body: self) { (data) -> NoBody in\n            let parseError: ParseError!\n            do {\n                parseError = try ParseCoding.jsonDecoder().decode(ParseError.self, from: data)\n            } catch {\n                return try ParseCoding.jsonDecoder().decode(NoBody.self, from: data)\n            }\n            throw parseError\n        }\n    }\n}\n\n// MARK: Codable\npublic extension ParseAnalytics {\n    init(from decoder: Decoder) throws {\n        let values = try decoder.container(keyedBy: CodingKeys.self)\n        name = try values.decode(String.self, forKey: .name)\n        date = try values.decodeIfPresent(Date.self, forKey: .date)\n        dimensionsAnyCodable = try values.decodeIfPresent([String: AnyCodable].self, forKey: .dimensions)\n    }\n\n    func encode(to encoder: Encoder) throws {\n        var container = encoder.container(keyedBy: CodingKeys.self)\n        try container.encodeIfPresent(date, forKey: .date)\n        try container.encodeIfPresent(dimensionsAnyCodable, forKey: .dimensions)\n        if !(encoder is _ParseEncoder) {\n            try container.encode(name, forKey: .name)\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseBytes.swift",
    "content": "//\n//  ParseBytes.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 7/9/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n  `ParseBytes` is used to store base 64 data.\n*/\npublic struct ParseBytes: ParseTypeable, Hashable {\n    private let __type: String = \"Bytes\" // swiftlint:disable:this identifier_name\n    public let base64: String\n\n    enum CodingKeys: String, CodingKey {\n        case __type // swiftlint:disable:this identifier_name\n        case base64\n    }\n\n    /**\n      Create new `ParseBytes` instance with the specified base64 string.\n       - parameter base64: A base64 string.\n     */\n    public init(base64: String) {\n        self.base64 = base64\n    }\n\n    /**\n      Create new `ParseBytes` instance with the specified data.\n       - parameter data: The data to encode to a base64 string.\n     */\n    public init(data: Data) {\n        self.base64 = data.base64EncodedString()\n    }\n}\n\nextension ParseBytes {\n    public init(from decoder: Decoder) throws {\n        let values = try decoder.container(keyedBy: CodingKeys.self)\n        base64 = try values.decode(String.self, forKey: .base64)\n    }\n\n    public func encode(to encoder: Encoder) throws {\n        var container = encoder.container(keyedBy: CodingKeys.self)\n        try container.encode(__type, forKey: .__type)\n        try container.encode(base64, forKey: .base64)\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseCLP.swift",
    "content": "//\n//  ParseCLP.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 5/21/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/// Class Level Permissions for `ParseSchema`.\npublic struct ParseCLP: ParseTypeable {\n\n    var get: [String: AnyCodable]?\n    var find: [String: AnyCodable]?\n    var count: [String: AnyCodable]?\n    var create: [String: AnyCodable]?\n    var update: [String: AnyCodable]?\n    var delete: [String: AnyCodable]?\n    var addField: [String: AnyCodable]?\n    /**\n     The users, roles, and access level restrictions who cannot access particular\n     fields in a Parse class.\n     */\n    public internal(set) var protectedFields: [String: Set<String>]?\n    /**\n     Fields of `ParseUser` type or an array of `ParseUser`'s that\n     can perform get/count/find actions on a Parse class.\n     */\n    public var readUserFields: Set<String>?\n    /**\n     Fields of `ParseUser` type or an array of `ParseUser`'s that\n     can perform create/delete/update/addField actions on a Parse class.\n     */\n    public var writeUserFields: Set<String>?\n\n    /// The avialable actions to perform on a Parse class.\n    public enum Action {\n        /// Fetch `ParseObject`'s.\n        case get\n        /// Query for `ParseObject`'s.\n        case find\n        /// Count `ParseObject`'s.\n        case count\n        /// Create new `ParseObject`'s.\n        case create\n        /// Update `ParseObject`'s.\n        case update\n        /// Delete `ParseObject`'s.\n        case delete\n        /// Add fields to the Parse class.\n        case addField\n\n        internal func keyPath() -> KeyPath<ParseCLP, [String: AnyCodable]?> {\n            let keyPath: KeyPath<ParseCLP, [String: AnyCodable]?>\n            switch self {\n            case .get:\n                keyPath = \\.get\n            case .find:\n                keyPath = \\.find\n            case .count:\n                keyPath = \\.count\n            case .create:\n                keyPath = \\.create\n            case .update:\n                keyPath = \\.update\n            case .delete:\n                keyPath = \\.delete\n            case .addField:\n                keyPath = \\.addField\n            }\n            return keyPath\n        }\n\n        internal func writableKeyPath() -> WritableKeyPath<ParseCLP, [String: AnyCodable]?> {\n            let keyPath: WritableKeyPath<ParseCLP, [String: AnyCodable]?>\n            switch self {\n            case .get:\n                keyPath = \\.get\n            case .find:\n                keyPath = \\.find\n            case .count:\n                keyPath = \\.count\n            case .create:\n                keyPath = \\.create\n            case .update:\n                keyPath = \\.update\n            case .delete:\n                keyPath = \\.delete\n            case .addField:\n                keyPath = \\.addField\n            }\n            return keyPath\n        }\n    }\n\n    enum Access: String {\n        case requiresAuthentication\n        case publicScope = \"*\"\n        case pointerFields\n    }\n\n    /// Creates an empty instance of CLP.\n    public init() { }\n\n    /**\n     Creates an instance of CLP with particular access.\n     - parameter requiresAuthentication: Read/Write to a Parse class requires users to be authenticated.\n     - parameter publicAccess:Read/Write to a Parse class can be done by the public.\n     - warning: Setting `requiresAuthentication` and `publicAccess` does not give **addField**\n     access. You can set **addField** access after creating an instance of CLP.\n     - warning: Use of `requiresAuthentication == true` requires Parse Server 2.3.0+.\n     */\n    public init(requiresAuthentication: Bool, publicAccess: Bool) {\n        let clp = setWriteAccessRequiresAuthentication(requiresAuthentication)\n            .setReadAccessRequiresAuthentication(requiresAuthentication)\n            .setWriteAccessPublic(publicAccess)\n            .setReadAccessPublic(publicAccess)\n        self = clp\n    }\n}\n\n// MARK: Default Implementation\nextension ParseCLP {\n    static func getUserFieldAccess(_ field: String) -> String {\n        \"userField:\\(field)\"\n    }\n\n    func hasAccess(_ keyPath: KeyPath<Self, [String: AnyCodable]?>,\n                   for entity: String) -> Bool {\n        self[keyPath: keyPath]?[entity]?.value as? Bool ?? false\n    }\n\n    func setAccess(_ allow: Bool,\n                   on keyPath: WritableKeyPath<Self, [String: AnyCodable]?>,\n                   for entity: String) -> Self {\n        let allowed: Bool? = allow ? allow : nil\n        var mutableCLP = self\n        if let allowed = allowed {\n            let value = AnyCodable(allowed)\n            if mutableCLP[keyPath: keyPath] != nil {\n                mutableCLP[keyPath: keyPath]?[entity] = value\n            } else {\n                mutableCLP[keyPath: keyPath] = [entity: value]\n            }\n        } else {\n            mutableCLP[keyPath: keyPath]?[entity] = nil\n        }\n        return mutableCLP\n    }\n\n    func getPointerFields(_ keyPath: KeyPath<Self, [String: AnyCodable]?>) -> Set<String> {\n        self[keyPath: keyPath]?[Access.pointerFields.rawValue]?.value as? Set<String> ?? []\n    }\n\n    func setPointer(_ fields: Set<String>,\n                    on keyPath: WritableKeyPath<Self, [String: AnyCodable]?>) -> Self {\n        var mutableCLP = self\n        let value = AnyCodable(fields)\n        if mutableCLP[keyPath: keyPath] != nil {\n            mutableCLP[keyPath: keyPath]?[Access.pointerFields.rawValue] = value\n        } else {\n            mutableCLP[keyPath: keyPath] = [Access.pointerFields.rawValue: value]\n        }\n        return mutableCLP\n    }\n\n    func addPointer(_ fields: Set<String>,\n                    on keyPath: WritableKeyPath<Self, [String: AnyCodable]?>) -> Self {\n\n        if let currentSet = self[keyPath: keyPath]?[Access.pointerFields.rawValue]?.value as? Set<String> {\n            var mutableCLP = self\n            mutableCLP[keyPath: keyPath]?[Access.pointerFields.rawValue] = AnyCodable(currentSet.union(fields))\n            return mutableCLP\n        } else {\n            return setPointer(fields, on: keyPath)\n        }\n    }\n\n    func removePointer(_ fields: Set<String>,\n                       on keyPath: WritableKeyPath<Self, [String: AnyCodable]?>) -> Self {\n        var mutableCLP = self\n        if var currentSet = self[keyPath: keyPath]?[Access.pointerFields.rawValue]?.value as? Set<String> {\n            fields.forEach { currentSet.remove($0) }\n            mutableCLP[keyPath: keyPath]?[Access.pointerFields.rawValue] = AnyCodable(currentSet)\n        }\n        return mutableCLP\n    }\n}\n\n// MARK: Standard Access\npublic extension ParseCLP {\n    /**\n     Checks if an `Action` on a Parse class has public access.\n     - parameter action: An enum value of one of the following actions:\n     get/find/count/create/update/delete/addField.\n     - returns: **true** if access is allowed, **false** otherwise.\n    */\n    func hasAccessPublic(_ action: Action) -> Bool {\n        hasAccess(action.keyPath(), for: Access.publicScope.rawValue)\n    }\n\n    /**\n     Checks if an `Action` on a Parse class requires users to be authenticated to access.\n     - parameter action: An enum value of one of the following actions:\n     get/find/count/create/update/delete/addField.\n     - returns: **true** if access is allowed, **false** otherwise.\n     - warning: Requires Parse Server 2.3.0+.\n    */\n    func hasAccessRequiresAuthentication(_ action: Action) -> Bool {\n        hasAccess(action.keyPath(), for: Access.requiresAuthentication.rawValue)\n    }\n\n    /**\n     Checks if an `Action` on a Parse class provides access to a specific `objectId`.\n     - parameter action: An enum value of one of the following actions:\n     get/find/count/create/update/delete/addField.\n     - parameter objectId: The `ParseUser` objectId to check.\n     - returns: **true** if access is allowed, **false** otherwise.\n    */\n    func hasAccess(_ action: Action,\n                   for objectId: String) -> Bool {\n        return hasAccess(action.keyPath(), for: objectId)\n    }\n\n    /**\n     Checks if an `Action` on a Parse class provides access to a specific `ParseUser`.\n     - parameter action: An enum value of one of the following actions:\n     get/find/count/create/update/delete/addField.\n     - parameter user: The `ParseUser` to check.\n     - returns: **true** if access is allowed, **false** otherwise.\n     - throws: An error of type `ParseError`.\n    */\n    func hasAccess<U>(_ action: Action,\n                      for user: U) throws -> Bool where U: ParseUser {\n        let objectId = try user.toPointer().objectId\n        return hasAccess(action.keyPath(), for: objectId)\n    }\n\n    /**\n     Checks if an `Action` on a Parse class provides access to a specific `ParseUser` pointer.\n     - parameter action: An enum value of one of the following actions:\n     get/find/count/create/update/delete/addField.\n     - parameter user: The `ParseUser` pointer to check.\n     - returns: **true** if access is allowed, **false** otherwise.\n    */\n    func hasAccess<U>(_ action: Action,\n                      for user: Pointer<U>) -> Bool where U: ParseUser {\n        hasAccess(action.keyPath(), for: user.objectId)\n    }\n\n    /**\n     Checks if an `Action` on a Parse class provides access to a specific `ParseRole`.\n     - parameter action: An enum value of one of the following actions:\n     get/find/count/create/update/delete/addField.\n     - parameter role: The `ParseRole` to check.\n     - returns: **true** if access is allowed, **false** otherwise.\n     - throws: An error of type `ParseError`.\n    */\n    func hasAccess<R>(_ action: Action,\n                      for role: R) throws -> Bool where R: ParseRole {\n        let roleNameAccess = try ParseACL.getRoleAccessName(role)\n        return hasAccess(action.keyPath(), for: roleNameAccess)\n    }\n\n    /**\n     Set/remove public access to an `Action` on a Parse class.\n     - parameter allow: **true** to allow access , **false** to remove access.\n     - parameter action: An enum value of one of the following actions:\n     get/find/count/create/update/delete/addField.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n    */\n    func setAccessPublic(_ allow: Bool,\n                         on action: Action) -> Self {\n        setAccess(allow, on: action.writableKeyPath(), for: Access.publicScope.rawValue)\n    }\n\n    /**\n     Set/remove require user authentication to access an `Action` on a Parse class.\n     - parameter allow: **true** to allow access , **false** to remove access.\n     - parameter action: An enum value of one of the following actions:\n     get/find/count/create/update/delete/addField.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - warning: Requires Parse Server 2.3.0+.\n     */\n    func setAccessRequiresAuthentication(_ allow: Bool,\n                                         on action: Action) -> Self {\n        setAccess(allow, on: action.writableKeyPath(), for: Access.requiresAuthentication.rawValue)\n    }\n\n    /**\n     Set/remove access to an `Action` for a specific user objectId on a Parse class.\n     - parameter action: An enum value of one of the following actions:\n     get/find/count/create/update/delete/addField.\n     - parameter allow: **true** to allow access , **false** to remove access.\n     - parameter objectId: The `ParseUser` objectId to add/remove access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     */\n    func setAccess(_ allow: Bool,\n                   on action: Action,\n                   for objectId: String) -> Self {\n        setAccess(allow, on: action.writableKeyPath(), for: objectId)\n    }\n\n    /**\n     Set/remove access to an `Action` for a specific user `ParseUser` on a Parse class.\n     - parameter action: An enum value of one of the following actions:\n     get/find/count/create/update/delete/addField.\n     - parameter allow: **true** to allow access , **false** to remove access.\n     - parameter objectId: The `ParseUser` to add/remove access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n     */\n    func setAccess<U>(_ allow: Bool,\n                      on action: Action,\n                      for user: U) throws -> Self where U: ParseUser {\n        let objectId = try user.toPointer().objectId\n        return setAccess(allow, on: action.writableKeyPath(), for: objectId)\n    }\n\n    /**\n     Set/remove access to an `Action` for a specific user `ParseUser` pointer on a Parse class.\n     - parameter action: An enum value of one of the following actions:\n     get/find/count/create/update/delete/addField.\n     - parameter allow: **true** to allow access , **false** to remove access.\n     - parameter user: The `ParseUser` pointer to add/remove access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     */\n    func setAccess<U>(_ allow: Bool,\n                      on action: Action,\n                      for user: Pointer<U>) -> Self where U: ParseUser {\n        setAccess(allow, on: action.writableKeyPath(), for: user.objectId)\n    }\n\n    /**\n     Set/remove access to an `Action` for a specific `ParseRole` on a Parse class.\n     - parameter action: An enum value of one of the following actions:\n     get/find/count/create/update/delete/addField.\n     - parameter allow: **true** to allow access , **false** to remove access.\n     - parameter objectId: The `ParseRole` to add/remove access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n     */\n    func setAccess<R>(_ allow: Bool,\n                      on action: Action,\n                      for role: R) throws -> Self where R: ParseRole {\n        let roleNameAccess = try ParseACL.getRoleAccessName(role)\n        return setAccess(allow, on: action.writableKeyPath(), for: roleNameAccess)\n    }\n}\n\n// MARK: WriteAccess\npublic extension ParseCLP {\n    internal func hasWriteAccess(_ entity: String,\n                                 check addField: Bool) -> Bool {\n        let access = hasAccess(.create, for: entity)\n            && hasAccess(.update, for: entity)\n            && hasAccess(.delete, for: entity)\n        if addField {\n            return access && hasAccess(.addField, for: entity)\n        }\n        return access\n    }\n\n    /**\n     Check whether user authentication is required to perform create/update/delete/addField actions on a Parse class.\n     - parameter checkAddField: **true** if `addField` should be part of the check, **false** otherwise.\n     Defaults to **false**.\n     - returns: **true** if has access, **false** otherwise.\n     - warning: Requires Parse Server 2.3.0+.\n    */\n    func hasWriteAccessRequiresAuthentication(_ checkAddField: Bool = false) -> Bool {\n        hasWriteAccess(Access.requiresAuthentication.rawValue, check: checkAddField)\n    }\n\n    /**\n     Check whether the public has access to perform create/update/delete/addField actions on a Parse class.\n     - parameter checkAddField: **true** if `addField` should be part of the check, **false** otherwise.\n     Defaults to **false**.\n     - returns: **true** if has access, **false** otherwise.\n    */\n    func hasWriteAccessPublic(_ checkAddField: Bool = false) -> Bool {\n        hasWriteAccess(Access.publicScope.rawValue, check: checkAddField)\n    }\n\n    /**\n     Check whether a `ParseUser` objectId has access to perform create/update/delete/addField actions on a Parse class.\n     - parameter objectId: The `ParseUser` objectId to check.\n     - parameter checkAddField: **true** if `addField` should be part of the check, **false** otherwise.\n     Defaults to **false**.\n     - returns: **true** if has access, **false** otherwise.\n     - warning: Even if **false** is returned, the `ParseUser`/`ParseRole` may still\n     have access if they are apart of a `ParseRole` that has access.\n     - throws: An error of type `ParseError`.\n    */\n    func hasWriteAccess(_ objectId: String,\n                        checkAddField: Bool = false) -> Bool {\n        hasWriteAccess(objectId, check: checkAddField)\n    }\n\n    /**\n     Check whether the `ParseUser` pointer has access to perform create/update/delete/addField actions on a Parse class.\n     - parameter user: The `ParseUser` pointer to check.\n     - parameter checkAddField: **true** if `addField` should be part of the check, **false** otherwise.\n     Defaults to **false**.\n     - returns: **true** if has access, **false** otherwise.\n     - warning: Even if **false** is returned, the `ParseUser`/`ParseRole` may still\n     have access if they are apart of a `ParseRole` that has access.\n    */\n    func hasWriteAccess<U>(_ user: Pointer<U>,\n                           checkAddField: Bool = false) -> Bool where U: ParseUser {\n        hasWriteAccess(user.objectId, checkAddField: checkAddField)\n    }\n\n    /**\n     Check whether the `ParseUser` has access to perform create/update/delete/addField actions on a Parse class.\n     - parameter user: The `ParseUser` to check.\n     - parameter checkAddField: **true** if `addField` should be part of the check, **false** otherwise.\n     Defaults to **false**.\n     - returns: **true** if has access, **false** otherwise.\n     - warning: Even if **false** is returned, the `ParseUser`/`ParseRole` may still\n     have access if they are apart of a `ParseRole` that has access.\n     - throws: An error of type `ParseError`.\n    */\n    func hasWriteAccess<U>(_ user: U,\n                           checkAddField: Bool = false) throws -> Bool where U: ParseUser {\n        let objectId = try user.toPointer().objectId\n        return hasWriteAccess(objectId, checkAddField: checkAddField)\n    }\n\n    /**\n     Check whether the `ParseRole` has access to perform create/update/delete/addField actions on a Parse class.\n     - parameter role: The `ParseRole` to check.\n     - parameter checkAddField: **true** if `addField` should be part of the check, **false** otherwise.\n     Defaults to **false**.\n     - returns: **true** if has access, **false** otherwise.\n     - warning: Even if **false** is returned, the `ParseUser`/`ParseRole` may still\n     have access if they are apart of a `ParseRole` that has access.\n     - throws: An error of type `ParseError`.\n    */\n    func hasWriteAccess<R>(_ role: R,\n                           checkAddField: Bool = false) throws -> Bool where R: ParseRole {\n        let roleNameAccess = try ParseACL.getRoleAccessName(role)\n        return hasWriteAccess(roleNameAccess, checkAddField: checkAddField)\n    }\n\n    /**\n     Sets whether user authentication is required to perform create/update/delete/addField actions on a Parse class.\n     - parameter allow: **true** if access should be allowed, **false** otherwise.\n     - parameter canAddField: **true** if access should be allowed to `addField`,\n     **false** otherwise. Defaults to **false**.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - warning: Requires Parse Server 2.3.0+.\n    */\n    func setWriteAccessRequiresAuthentication(_ allow: Bool,\n                                              canAddField addField: Bool = false) -> Self {\n        setWriteAccess(allow, for: Access.requiresAuthentication.rawValue, canAddField: addField)\n    }\n\n    /**\n     Sets whether the public has access to perform create/update/delete/addField actions on a Parse class.\n     - parameter allow: **true** if access should be allowed, **false** otherwise.\n     - parameter canAddField: **true** if access should be allowed to `addField`,\n     **false** otherwise. Defaults to **false**.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n    */\n    func setWriteAccessPublic(_ allow: Bool,\n                              canAddField addField: Bool = false) -> Self {\n        setWriteAccess(allow, for: Access.publicScope.rawValue, canAddField: addField)\n    }\n\n    /**\n     Sets whether the given `ParseUser` objectId  has access to perform\n     create/update/delete/addField actions on a Parse class.\n     - parameter allow: **true** if access should be allowed, **false** otherwise.\n     - parameter objectId: The `ParseUser` objectId to provide/restrict access to.\n     - parameter canAddField: **true** if access should be allowed to `addField`,\n     **false** otherwise. Defaults to **false**.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n    */\n    func setWriteAccess(_ allow: Bool,\n                        for objectId: String,\n                        canAddField addField: Bool = false) -> Self {\n        var updatedCLP = self\n            .setAccess(allow, on: .create, for: objectId)\n            .setAccess(allow, on: .update, for: objectId)\n            .setAccess(allow, on: .delete, for: objectId)\n        if addField {\n            updatedCLP = updatedCLP.setAccess(allow, on: .addField, for: objectId)\n        } else {\n            updatedCLP = updatedCLP.setAccess(false, on: .addField, for: objectId)\n        }\n        return updatedCLP\n    }\n\n    /**\n     Sets whether the given `ParseUser` has access to perform create/update/delete/addField actions on a Parse class.\n     - parameter allow: **true** if access should be allowed, **false** otherwise.\n     - parameter user: The `ParseUser` to provide/restrict access to.\n     - parameter canAddField: **true** if access should be allowed to `addField`,\n     **false** otherwise. Defaults to **false**.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n    */\n    func setWriteAccess<U>(_ allow: Bool,\n                           for user: U,\n                           canAddField addField: Bool = false) throws -> Self where U: ParseUser {\n        let objectId = try user.toPointer().objectId\n        return setWriteAccess(allow, for: objectId, canAddField: addField)\n    }\n\n    /**\n     Sets whether the given `ParseUser`pointer  has access to perform\n     create/update/delete/addField actions on a Parse class.\n     - parameter allow: **true** if access should be allowed, **false** otherwise.\n     - parameter user: The `ParseUser` to provide/restrict access to.\n     - parameter canAddField: **true** if access should be allowed to `addField`,\n     **false** otherwise. Defaults to **false**.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n    */\n    func setWriteAccess<U>(_ allow: Bool,\n                           for user: Pointer<U>,\n                           canAddField addField: Bool = false) -> Self where U: ParseUser {\n        setWriteAccess(allow, for: user.objectId, canAddField: addField)\n    }\n\n    /**\n     Sets whether the given `ParseRole` has access to perform create/update/delete/addField actions on a Parse class.\n     - parameter allow: **true** if access should be allowed, **false** otherwise.\n     - parameter role: The `ParseRole` to provide/restrict access to.\n     - parameter canAddField: **true** if access should be allowed to `addField`,\n     **false** otherwise. Defaults to **false**.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n    */\n    func setWriteAccess<R>(_ allow: Bool,\n                           for role: R,\n                           canAddField addField: Bool = false) throws -> Self where R: ParseRole {\n        let roleNameAccess = try ParseACL.getRoleAccessName(role)\n        return setWriteAccess(allow, for: roleNameAccess, canAddField: addField)\n    }\n}\n\n// MARK: ReadAccess\npublic extension ParseCLP {\n    /**\n     Check whether user authentication is required to perform get/find/count actions on a Parse class.\n     - returns: **true** if has access, **false** otherwise.\n     - warning: Requires Parse Server 2.3.0+.\n    */\n    func hasReadAccessRequiresAuthentication() -> Bool {\n        hasReadAccess(Access.requiresAuthentication.rawValue)\n    }\n\n    /**\n     Check whether the public has access to perform get/find/count actions on a Parse class.\n     - returns: **true** if has access, **false** otherwise.\n    */\n    func hasReadAccessPublic() -> Bool {\n        hasReadAccess(Access.publicScope.rawValue)\n    }\n\n    /**\n     Check whether the `ParseUser` objectId has access to perform get/find/count actions on a Parse class.\n     - parameter objectId: The `ParseUser` objectId to check.\n     - returns: **true** if has access, **false** otherwise.\n     - warning: Even if **false** is returned, the `ParseUser`/`ParseRole` may still\n     have access if they are apart of a `ParseRole` that has access.\n    */\n    func hasReadAccess(_ objectId: String) -> Bool {\n        hasAccess(.get, for: objectId)\n            && hasAccess(.find, for: objectId)\n            && hasAccess(.count, for: objectId)\n    }\n\n    /**\n     Check whether the `ParseUser` pointer has access to perform get/find/count actions on a Parse class.\n     - parameter user: The `ParseUser` pointer to check.\n     - returns: **true** if has access, **false** otherwise.\n     - warning: Even if **false** is returned, the `ParseUser`/`ParseRole` may still\n     have access if they are apart of a `ParseRole` that has access.\n    */\n    func hasReadAccess<U>(_ user: Pointer<U>) -> Bool where U: ParseUser {\n        hasReadAccess(user.objectId)\n    }\n\n    /**\n     Check whether the `ParseUser` has access to perform get/find/count actions on a Parse class.\n     - parameter user: The `ParseUser` to check.\n     - returns: **true** if has access, **false** otherwise.\n     - throws: An error of type `ParseError`.\n     - warning: Even if **false** is returned, the `ParseUser`/`ParseRole` may still\n     have access if they are apart of a `ParseRole` that has access.\n    */\n    func hasReadAccess<U>(_ user: U) throws -> Bool where U: ParseUser {\n        let objectId = try user.toPointer().objectId\n        return hasReadAccess(objectId)\n    }\n\n    /**\n     Check whether the `ParseRole` has access to perform get/find/count actions on a Parse class.\n     - parameter role: The `ParseRole` to check.\n     - returns: **true** if has access, **false** otherwise.\n     - throws: An error of type `ParseError`.\n     - warning: Even if **false** is returned, the `ParseUser`/`ParseRole` may still\n     have access if they are apart of a `ParseRole` that has access.\n    */\n    func hasReadAccess<R>(_ role: R) throws -> Bool where R: ParseRole {\n        let roleNameAccess = try ParseACL.getRoleAccessName(role)\n        return hasReadAccess(roleNameAccess)\n    }\n\n    /**\n     Sets whether authentication is required to perform get/find/count actions on a Parse class.\n     - parameter allow: **true** if access should be allowed, **false** otherwise.\n     - parameter canAddField: **true** if access should be allowed to `addField`,\n     **false** otherwise. Defaults to **false**.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - warning: Requires Parse Server 2.3.0+.\n    */\n    func setReadAccessRequiresAuthentication(_ allow: Bool,\n                                             canAddField addField: Bool = false) -> Self {\n        setReadAccess(allow, for: Access.requiresAuthentication.rawValue)\n    }\n\n    /**\n     Sets whether the public has access to perform get/find/count actions on a Parse class.\n     - parameter allow: **true** if access should be allowed, **false** otherwise.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n    */\n    func setReadAccessPublic(_ allow: Bool) -> Self {\n        setReadAccess(allow, for: Access.publicScope.rawValue)\n    }\n\n    /**\n     Sets whether the given `ParseUser` has access to perform get/find/count actions on a Parse class.\n     - parameter allow: **true** if access should be allowed, **false** otherwise.\n     - parameter objectId: The `ParseUser` pointer to provide/restrict access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n    */\n    func setReadAccess(_ allow: Bool,\n                       for objectId: String) -> Self {\n        let updatedCLP = self\n            .setAccess(allow, on: .get, for: objectId)\n            .setAccess(allow, on: .find, for: objectId)\n            .setAccess(allow, on: .count, for: objectId)\n        return updatedCLP\n    }\n\n    /**\n     Sets whether the given `ParseUser` has access to perform get/find/count actions on a Parse class.\n     - parameter allow: **true** if access should be allowed, **false** otherwise.\n     - parameter user: The `ParseUser` to provide/restrict access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n    */\n    func setReadAccess<U>(_ allow: Bool,\n                          for user: U) throws -> Self where U: ParseUser {\n        let objectId = try user.toPointer().objectId\n        return setReadAccess(allow, for: objectId)\n    }\n\n    /**\n     Sets whether the given `ParseUser` has access to perform get/find/count actions on a Parse class.\n     - parameter allow: **true** if access should be allowed, **false** otherwise.\n     - parameter user: The `ParseUser` pointer to provide/restrict access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n    */\n    func setReadAccess<U>(_ allow: Bool,\n                          for user: Pointer<U>) -> Self where U: ParseUser {\n        return setReadAccess(allow, for: user.objectId)\n    }\n\n    /**\n     Sets whether the given `ParseRole` has access to perform get/find/count actions on a Parse class.\n     - parameter allow: **true** if access should be allowed, **false** otherwise.\n     - parameter role: The `ParseRole` to provide/restrict access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n    */\n    func setReadAccess<R>(_ allow: Bool,\n                          for role: R) throws -> Self where R: ParseRole {\n        let roleNameAccess = try ParseACL.getRoleAccessName(role)\n        return setReadAccess(allow, for: roleNameAccess)\n    }\n}\n\n// MARK: Pointer Access\npublic extension ParseCLP {\n    /**\n     Retreive the fields in a Parse class that determine access for a specific `Action`.\n     - parameter action: An enum value of one of the following actions:\n     get/find/count/create/update/delete/addField.\n     - returns: The set of fields that are either of`ParseUser` type or\n     an array of `ParseUser`'s.\n    */\n    func getPointerFields(_ action: Action) -> Set<String> {\n        getPointerFields(action.keyPath())\n    }\n\n    /**\n     Give access to a set of fields that are either of `ParseUser` type or an array\n     `ParseUser`'s for a specific `Action` on a Parse class.\n     - parameter action: An enum value of one of the following actions:\n     get/find/count/create/update/delete/addField.\n     - parameter fields: The set of fields that are either of`ParseUser` type or\n     an array of `ParseUser`'s.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - note: This method replaces the current set of `fields` in the CLP.\n     - warning: Requires Parse Server 3.1.1+.\n     */\n    func setPointerFields(_ fields: Set<String>,\n                          on action: Action) -> Self {\n        setPointer(fields, on: action.writableKeyPath())\n    }\n\n    /**\n     Add access to an additional set of fields that are either of `ParseUser` type or an array\n     `ParseUser`'s for a specific `Action` on a Parse class.\n     - parameter action: An enum value of one of the following actions:\n     get/find/count/create/update/delete/addField.\n     - parameter fields: The set of fields that are either of`ParseUser` type or\n     an array of `ParseUser`'s.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - note: This method adds on to the current set of `fields` in the CLP.\n     - warning: Requires Parse Server 3.1.1+.\n     */\n    func addPointerFields(_ fields: Set<String>,\n                          on action: Action) -> Self {\n        addPointer(fields, on: action.writableKeyPath())\n    }\n\n    /**\n     Remove access for the set of fields that are either of `ParseUser` type or an array\n     `ParseUser`'s for a specific `Action` on a Parse class.\n     - parameter action: An enum value of one of the following actions:\n     get/find/count/create/update/delete/addField.\n     - parameter fields: The set of fields that are either of`ParseUser` type or\n     an array of `ParseUser`'s.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - note: This method removes from the current set of `fields` in the CLP.\n     - warning: Requires Parse Server 3.1.1+.\n     */\n    func removePointerFields(_ fields: Set<String>,\n                             on action: Action) -> Self {\n        removePointer(fields, on: action.writableKeyPath())\n    }\n}\n\n// MARK: Protected Fields\npublic extension ParseCLP {\n    internal func getProtected(_ keyPath: KeyPath<Self, [String: Set<String>]?>,\n                               for entity: String) -> Set<String> {\n        self[keyPath: keyPath]?[entity] ?? []\n    }\n\n    internal func setProtected(_ fields: Set<String>,\n                               on keyPath: WritableKeyPath<Self, [String: Set<String>]?>,\n                               for entity: String) -> Self {\n        var mutableCLP = self\n        if mutableCLP[keyPath: keyPath] != nil {\n            mutableCLP[keyPath: keyPath]?[entity] = fields\n        } else {\n            mutableCLP[keyPath: keyPath] = [entity: fields]\n        }\n        return mutableCLP\n    }\n\n    internal func addProtected(_ fields: Set<String>,\n                               on keyPath: WritableKeyPath<Self, [String: Set<String>]?>,\n                               for entity: String) -> Self {\n        if let currentSet = self[keyPath: keyPath]?[entity] {\n            var mutableCLP = self\n            mutableCLP[keyPath: keyPath]?[entity] = currentSet.union(fields)\n            return mutableCLP\n        } else {\n            return setProtected(fields, on: keyPath, for: entity)\n        }\n    }\n\n    internal func removeProtected(_ fields: Set<String>,\n                                  on keyPath: WritableKeyPath<Self, [String: Set<String>]?>,\n                                  for entity: String) -> Self {\n        var mutableCLP = self\n        fields.forEach {\n            mutableCLP[keyPath: keyPath]?[entity]?.remove($0)\n        }\n        return mutableCLP\n    }\n\n    /**\n     Get the fields the publc cannot access.\n     - returns: The set protected fields that cannot be accessed.\n    */\n    func getProtectedFieldsPublic() -> Set<String> {\n        getProtectedFields(Access.publicScope.rawValue)\n    }\n\n    /**\n     Get the fields the users with authentication cannot access.\n     - returns: The set protected fields that cannot be accessed.\n     - warning: Requires Parse Server 2.3.0+.\n    */\n    func getProtectedFieldsRequiresAuthentication() -> Set<String> {\n        getProtectedFields(Access.requiresAuthentication.rawValue)\n    }\n\n    /**\n     Get the protected fields either a field of `ParseUser` type or\n     an array of `ParseUser`'s in a Parse class cannot access.\n     - parameter field: A field in a Parse class that is either of `ParseUser` type or\n     an array of `ParseUser`'s.\n     - returns: The set protected fields that cannot be accessed.\n    */\n    func getProtectedFieldsUser(_ field: String) -> Set<String> {\n        getProtectedFields(Self.getUserFieldAccess(field))\n    }\n\n    /**\n     Get the protected fields the given `ParseUser` objectId cannot access.\n     - parameter objectId: The `ParseUser` objectId access to check.\n     - returns: The set protected fields that cannot be accessed.\n    */\n    func getProtectedFields(_ objectId: String) -> Set<String> {\n        getProtected(\\.protectedFields, for: objectId)\n    }\n\n    /**\n     Get the protected fields the given `ParseUser` cannot access.\n     - parameter user: The `ParseUser` access to check.\n     - returns: The set protected fields that cannot be accessed.\n     - throws: An error of type `ParseError`.\n    */\n    func getProtectedFields<U>(_ user: U) throws -> Set<String> where U: ParseUser {\n        let objectId = try user.toPointer().objectId\n        return getProtectedFields(objectId)\n    }\n\n    /**\n     Get the protected fields for the given `ParseUser` pointer cannot access.\n     - parameter user: The `ParseUser` access to check.\n     - returns: The set protected fields that cannot be accessed.\n    */\n    func getProtectedFields<U>(_ user: Pointer<U>) -> Set<String> where U: ParseUser {\n        getProtectedFields(user.objectId)\n    }\n\n    /**\n     Get the protected fields the given `ParseRole` cannot access.\n     - parameter role: The `ParseRole` access to check.\n     - returns: The set protected fields that cannot be accessed.\n     - throws: An error of type `ParseError`.\n    */\n    func getProtectedFields<R>(_ role: R) throws -> Set<String> where R: ParseRole {\n        let roleNameAccess = try ParseACL.getRoleAccessName(role)\n        return getProtectedFields(roleNameAccess)\n    }\n\n    /**\n     Set whether the public should not have access to specific fields of a Parse class.\n     - parameter fields: The set of fields that should be protected from access.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n    */\n    func setProtectedFieldsPublic(_ fields: Set<String>) -> Self {\n        setProtected(fields, on: \\.protectedFields, for: Access.publicScope.rawValue)\n    }\n\n    /**\n     Set whether authenticated users should not have access to specific fields of a Parse class.\n     - parameter fields: The set of fields that should be protected from access.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n     - warning: Requires Parse Server 2.3.0+.\n    */\n    func setProtectedFieldsRequiresAuthentication(_ fields: Set<String>) -> Self {\n        setProtected(fields, on: \\.protectedFields, for: Access.requiresAuthentication.rawValue)\n    }\n\n    /**\n     Set whether the given field that is either of `ParseUser` type or an array of `ParseUser`'s\n     should not have access to specific fields of a Parse class.\n     - parameter fields: The set of fields that should be protected from access.\n     - parameter userField: A field in a Parse class that is either of `ParseUser` type or\n     an array of `ParseUser`'s to restrict access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n    */\n    func setProtectedFields(_ fields: Set<String>, userField: String) -> Self {\n        setProtected(fields,\n                     on: \\.protectedFields,\n                     for: Self.getUserFieldAccess(userField))\n    }\n\n    /**\n     Set whether the given `ParseUser` objectId should not have access to specific fields of a Parse class.\n     - parameter fields: The set of fields that should be protected from access.\n     - parameter objectId: The `ParseUser` objectId to restrict access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n    */\n    func setProtectedFields(_ fields: Set<String>, for objectId: String) -> Self {\n        setProtected(fields, on: \\.protectedFields, for: objectId)\n    }\n\n    /**\n     Set whether the given `ParseUser` should not have access to specific fields of a Parse class.\n     - parameter fields: The set of fields that should be protected from access.\n     - parameter user: The `ParseUser` to restrict access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n    */\n    func setProtectedFields<U>(_ fields: Set<String>, for user: U) throws -> Self where U: ParseUser {\n        let objectId = try user.toPointer().objectId\n        return setProtectedFields(fields, for: objectId)\n    }\n\n    /**\n     Set whether the given `ParseUser` should not have access to specific fields of a Parse class.\n     - parameter fields: The set of fields that should be protected from access.\n     - parameter user: The `ParseUser` to restrict access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n    */\n    func setProtectedFields<U>(_ fields: Set<String>, for user: Pointer<U>) -> Self where U: ParseUser {\n        setProtectedFields(fields, for: user.objectId)\n    }\n\n    /**\n     Set whether the given `ParseRole` should not have access to specific fields of a Parse class.\n     - parameter fields: The set of fields that should be protected from access.\n     - parameter role: The `ParseRole` to restrict access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n    */\n    func setProtectedFields<R>(_ fields: Set<String>, for role: R) throws -> Self where R: ParseRole {\n        let roleNameAccess = try ParseACL.getRoleAccessName(role)\n        return setProtectedFields(fields, for: roleNameAccess)\n    }\n\n    /**\n     Add to the set of specific fields the public should not have access to on a Parse class.\n     - parameter fields: The set of fields that should be protected from access.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n     - note: This method adds on to the current set of `fields` in the CLP.\n    */\n    func addProtectedFieldsPublic(_ fields: Set<String>) -> Self {\n        addProtected(fields, on: \\.protectedFields, for: Access.publicScope.rawValue)\n    }\n\n    /**\n     Add to the set of specific fields authenticated users should not have access to on a Parse class.\n     - parameter fields: The set of fields that should be protected from access.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n     - note: This method adds on to the current set of `fields` in the CLP.\n     - warning: Requires Parse Server 2.3.0+.\n    */\n    func addProtectedFieldsRequiresAuthentication(_ fields: Set<String>) -> Self {\n        addProtected(fields, on: \\.protectedFields, for: Access.requiresAuthentication.rawValue)\n    }\n\n    /**\n     Add to the set of specific fields the given field that is either of `ParseUser` type or an array of `ParseUser`'s\n     should not have access to on a Parse class.\n     - parameter fields: The set of fields that should be protected from access.\n     - parameter userField: A field in a Parse class that is either of `ParseUser` type or\n     an array of `ParseUser`'s to restrict access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n     - note: This method adds on to the current set of `fields` in the CLP.\n    */\n    func addProtectedFieldsUser(_ fields: Set<String>, userField: String) -> Self {\n        addProtected(fields, on: \\.protectedFields, for: Self.getUserFieldAccess(userField))\n    }\n\n    /**\n     Add to the set of specific fields the given `ParseUser` objectId should not have access to on a Parse class.\n     - parameter fields: The set of fields that should be protected from access.\n     - parameter objectId: The `ParseUser` objectId to restrict access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n     - note: This method adds on to the current set of `fields` in the CLP.\n    */\n    func addProtectedFields(_ fields: Set<String>, for objectId: String) -> Self {\n        addProtected(fields, on: \\.protectedFields, for: objectId)\n    }\n\n    /**\n     Add to the set of specific fields the given `ParseUser` should not have access to on a Parse class.\n     - parameter fields: The set of fields that should be protected from access.\n     - parameter user: The `ParseUser` to restrict access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n     - note: This method adds on to the current set of `fields` in the CLP.\n    */\n    func addProtectedFields<U>(_ fields: Set<String>, for user: U) throws -> Self where U: ParseUser {\n        let objectId = try user.toPointer().objectId\n        return addProtectedFields(fields, for: objectId)\n    }\n\n    /**\n     Add to the set of specific fields the given `ParseUser` pointer should not have access to on a Parse class.\n     - parameter fields: The set of fields that should be protected from access.\n     - parameter user: The `ParseUser` to restrict access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - note: This method adds on to the current set of `fields` in the CLP.\n    */\n    func addProtectedFields<U>(_ fields: Set<String>, for user: Pointer<U>) -> Self where U: ParseUser {\n        addProtectedFields(fields, for: user.objectId)\n    }\n\n    /**\n     Add to the set of specific fields the given `ParseRole` should not have access to on a Parse class.\n     - parameter fields: The set of fields that should be protected from access.\n     - parameter role: The `ParseRole` to restrict access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n     - note: This method adds on to the current set of `fields` in the CLP.\n    */\n    func addProtectedFields<R>(_ fields: Set<String>, for role: R) throws -> Self where R: ParseRole {\n        let roleNameAccess = try ParseACL.getRoleAccessName(role)\n        return addProtectedFields(fields, for: roleNameAccess)\n    }\n\n    /**\n     Remove the set of specific fields the public should not have access to on a Parse class.\n     - parameter fields: The set of fields that should be removed from protected access.\n     - parameter objectId: The `ParseUser` objectId to restrict access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n     - note: This method removes from the current set of `fields` in the CLP.\n    */\n    func removeProtectedFieldsPublic(_ fields: Set<String>) -> Self {\n        removeProtected(fields, on: \\.protectedFields, for: Access.publicScope.rawValue)\n    }\n\n    /**\n     Remove the set of specific fields authenticated users should not have access to\n     on a Parse class.\n     - parameter fields: The set of fields that should be removed from protected access.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n     - note: This method removes from the current set of `fields` in the CLP.\n    */\n    func removeProtectedFieldsRequiresAuthentication(_ fields: Set<String>) -> Self {\n        removeProtected(fields, on: \\.protectedFields, for: Access.requiresAuthentication.rawValue)\n    }\n\n    /**\n     Remove fields from the set of specific fields the given field that is either of `ParseUser` type\n     or an array of `ParseUser`'s should not have access to on a Parse class.\n     - parameter fields: The set of fields that should be removed from protected access.\n     - parameter userField: A field in a Parse class that is either of `ParseUser` type or\n     an array of `ParseUser`'s to restrict access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n     - note: This method removes from the current set of `fields` in the CLP.\n    */\n    func removeProtectedFieldsUser(_ fields: Set<String>, userField: String) -> Self {\n        removeProtected(fields, on: \\.protectedFields, for: Self.getUserFieldAccess(userField))\n    }\n\n    /**\n     Remove fields from the set of specific fields the given `ParseUser` objectId\n     should not have access to on a Parse class.\n     - parameter fields: The set of fields that should be removed from protected access.\n     - parameter objectId: The `ParseUser` objectId to restrict access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n     - note: This method removes from the current set of `fields` in the CLP.\n    */\n    func removeProtectedFields(_ fields: Set<String>, for objectId: String) -> Self {\n        removeProtected(fields, on: \\.protectedFields, for: objectId)\n    }\n\n    /**\n     Remove fields from the set of specific fields the given `ParseUser` should not have access to on a Parse class.\n     - parameter fields: The set of fields that should be removed from protected access.\n     - parameter user: The `ParseUser` to restrict access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n     - note: This method removes from the current set of `fields` in the CLP.\n    */\n    func removeProtectedFields<U>(_ fields: Set<String>, for user: U) throws -> Self where U: ParseUser {\n        let objectId = try user.toPointer().objectId\n        return removeProtectedFields(fields, for: objectId)\n    }\n\n    /**\n     Remove fields from the set of specific fields the given `ParseUser` pointer\n     should not have access to on a Parse class.\n     - parameter fields: The set of fields that should be removed from protected access.\n     - parameter user: The `ParseUser` to restrict access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - note: This method removes from the current set of `fields` in the CLP.\n    */\n    func removeProtectedFields<U>(_ fields: Set<String>, for user: Pointer<U>) -> Self where U: ParseUser {\n        removeProtectedFields(fields, for: user.objectId)\n    }\n\n    /**\n     Remove fields from the set of specific fields the given `ParseRole` should not have access to on a Parse class.\n     - parameter fields: The set of fields that should be removed from protected access.\n     - parameter role: The `ParseRole` to restrict access to.\n     - returns: A mutated instance of `ParseCLP` for easy chaining.\n     - throws: An error of type `ParseError`.\n     - note: This method removes from the current set of `fields` in the CLP.\n    */\n    func removeProtectedFields<R>(_ fields: Set<String>, for role: R) throws -> Self where R: ParseRole {\n        let roleNameAccess = try ParseACL.getRoleAccessName(role)\n        return removeProtectedFields(fields, for: roleNameAccess)\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseConfig+async.swift",
    "content": "//\n//  ParseConfig+async.swift\n//  ParseConfig+async\n//\n//  Created by Corey Baker on 8/6/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n\npublic extension ParseConfig {\n\n    // MARK: Fetchable - Async/Await\n\n    /**\n     Fetch the Config *asynchronously*.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: The return type of self.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func fetch(options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.fetch(options: options,\n                       completion: continuation.resume)\n        }\n    }\n\n    // MARK: Savable - Async/Await\n\n    /**\n     Update the Config *asynchronously*.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: **true** if saved, **false** if save is unsuccessful.\n     - throws: An error of type `ParseError`.\n    */\n    func save(options: API.Options = []) async throws -> Bool {\n        try await withCheckedThrowingContinuation { continuation in\n            self.save(options: options,\n                      completion: continuation.resume)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseConfig+combine.swift",
    "content": "//\n//  ParseConfig+combine.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/29/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\npublic extension ParseConfig {\n\n    // MARK: Combine\n\n    /**\n     Fetch the Config *asynchronously*. Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func fetchPublisher(options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.fetch(options: options,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Update the Config *asynchronously*. Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n    */\n    func savePublisher(options: API.Options = []) -> Future<Bool, ParseError> {\n        Future { promise in\n            self.save(options: options,\n                      completion: promise)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseConfig.swift",
    "content": "//\n//  ParseConfig.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/22/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n Objects that conform to the `ParseConfig` protocol are able to access the Config on the Parse Server.\n When conforming to `ParseConfig`, any properties added can be retrieved by the client or updated on\n the server. The current `ParseConfig` is persisted to the Keychain and Parse Server.\n*/\npublic protocol ParseConfig: ParseTypeable {}\n\n// MARK: Update\nextension ParseConfig {\n\n    /**\n     Fetch the Config *synchronously*.\n        - parameter options: A set of header options sent to the server. Defaults to an empty set.\n        - returns: Returns `Self`.\n        - throws: An error of type `ParseError`.\n        - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n        desires a different policy, it should be inserted in `options`.\n    */\n    public func fetch(options: API.Options = []) throws -> Self {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        return try fetchCommand().execute(options: options)\n    }\n\n    /**\n     Fetch the Config *asynchronously*.\n        - parameter options: A set of header options sent to the server. Defaults to an empty set.\n        - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n        - parameter completion: A block that will be called when retrieving the config completes or fails.\n        It should have the following argument signature: `(Result<Self, ParseError>)`.\n        - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n        desires a different policy, it should be inserted in `options`.\n    */\n    public func fetch(options: API.Options = [],\n                      callbackQueue: DispatchQueue = .main,\n                      completion: @escaping (Result<Self, ParseError>) -> Void) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        fetchCommand()\n            .executeAsync(options: options, callbackQueue: callbackQueue) { result in\n                completion(result)\n            }\n    }\n\n    internal func fetchCommand() -> API.NonParseBodyCommand<Self, Self> {\n\n        return API.NonParseBodyCommand(method: .GET,\n                                       path: .config) { (data) -> Self in\n            let fetched = try ParseCoding.jsonDecoder().decode(ConfigFetchResponse<Self>.self, from: data).params\n            Self.updateKeychainIfNeeded(fetched)\n            return fetched\n        }\n    }\n}\n\n// MARK: Update\nextension ParseConfig {\n\n    /**\n     Update the Config *synchronously*.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns **true** if updated, **false** otherwise.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func save(options: API.Options = []) throws -> Bool {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        return try updateCommand().execute(options: options)\n    }\n\n    /**\n     Update the Config *asynchronously*.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: A block that will be called when retrieving the config completes or fails.\n     It should have the following argument signature: `(Result<Bool, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    public func save(options: API.Options = [],\n                     callbackQueue: DispatchQueue = .main,\n                     completion: @escaping (Result<Bool, ParseError>) -> Void) {\n        var options = options\n        options.insert(.useMasterKey)\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        updateCommand()\n            .executeAsync(options: options, callbackQueue: callbackQueue) { result in\n                completion(result)\n            }\n    }\n\n    internal func updateCommand() -> API.NonParseBodyCommand<ConfigUpdateBody<Self>, Bool> {\n        let body = ConfigUpdateBody(params: self)\n        return API.NonParseBodyCommand(method: .PUT, // MARK: Should be switched to \".PATCH\" when server supports PATCH.\n                                       path: .config,\n                                       body: body) { (data) -> Bool in\n            let updated = try ParseCoding.jsonDecoder().decode(BooleanResponse.self, from: data).result\n\n            if updated {\n                Self.updateKeychainIfNeeded(self)\n            }\n            return updated\n        }\n    }\n}\n\ninternal struct ConfigUpdateBody<T>: ParseTypeable, Decodable where T: ParseConfig {\n    let params: T\n}\n\n// MARK: Current\nstruct CurrentConfigContainer<T: ParseConfig>: Codable, Equatable {\n    var currentConfig: T?\n}\n\npublic extension ParseConfig {\n\n    internal static var currentContainer: CurrentConfigContainer<Self>? {\n        get {\n            guard let configInMemory: CurrentConfigContainer<Self> =\n                try? ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentConfig) else {\n                #if !os(Linux) && !os(Android) && !os(Windows)\n                    return try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentConfig)\n                #else\n                    return nil\n                #endif\n            }\n            return configInMemory\n        }\n        set {\n            try? ParseStorage.shared.set(newValue, for: ParseStorage.Keys.currentConfig)\n            #if !os(Linux) && !os(Android) && !os(Windows)\n            try? KeychainStore.shared.set(newValue, for: ParseStorage.Keys.currentConfig)\n            #endif\n        }\n    }\n\n    internal static func updateKeychainIfNeeded(_ result: Self, deleting: Bool = false) {\n        if !deleting {\n            Self.current = result\n        } else {\n            Self.deleteCurrentContainerFromKeychain()\n        }\n    }\n\n    internal static func deleteCurrentContainerFromKeychain() {\n        try? ParseStorage.shared.delete(valueFor: ParseStorage.Keys.currentConfig)\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try? KeychainStore.shared.delete(valueFor: ParseStorage.Keys.currentConfig)\n        #endif\n    }\n\n    /**\n     Gets/Sets properties of the current config in the Keychain.\n\n     - returns: Returns the latest `ParseConfig` on this device. If there is none, returns `nil`.\n    */\n    internal(set) static var current: Self? {\n        get {\n            return Self.currentContainer?.currentConfig\n        }\n        set {\n            if Self.currentContainer == nil {\n                Self.currentContainer = CurrentConfigContainer<Self>()\n            }\n            Self.currentContainer?.currentConfig = newValue\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseConfiguration.swift",
    "content": "//\n//  ParseConfiguration.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 8/30/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\n\n// swiftlint:disable line_length\n\n/**\n The Configuration for a Parse client.\n\n - important: It is recomended to only specify `masterKey` when using the SDK on a server. Do not use this key on the client.\n - note: Setting `usingPostForQuery` to **true**  will require all queries to access the server instead of following the `requestCachePolicy`.\n - warning: `usingTransactions` is experimental.\n - warning: Setting `usingDataProtectionKeychain` to **true** is known to cause issues in Playgrounds or in\n situtations when apps do not have credentials to setup a Keychain.\n */\npublic struct ParseConfiguration {\n\n    /// The application id for your Parse application.\n    public internal(set) var applicationId: String\n\n    /// The master key for your Parse application. This key should only\n    /// be specified when using the SDK on a server.\n    public internal(set) var masterKey: String? // swiftlint:disable:this inclusive_language\n\n    /// The client key for your Parse application.\n    public internal(set) var clientKey: String?\n\n    /// The server URL to connect to Parse Server.\n    public internal(set) var serverURL: URL\n\n    /// The live query server URL to connect to Parse Server.\n    public internal(set) var liveQuerysServerURL: URL?\n\n    /// Requires `objectId`'s to be created on the client.\n    public internal(set) var isRequiringCustomObjectIds = false\n\n    /// Requires `objectId`'s to be created on the client.\n    @available(*, deprecated, renamed: \"isRequiringCustomObjectIds\")\n    public var isAllowingCustomObjectIds: Bool {\n        isRequiringCustomObjectIds\n    }\n\n    /// Use transactions when saving/updating multiple objects.\n    /// - warning: This is experimental.\n    public internal(set) var isUsingTransactions = false\n\n    /// Use the **$eq** query constraint when querying.\n    /// - warning: This is known not to work for LiveQuery on Parse Servers <= 5.0.0.\n    public internal(set) var isUsingEqualQueryConstraint = false\n\n    /// Use **POST** instead of **GET** when making query calls.\n    /// Defaults to **false**.\n    /// - warning: **POST** calls are not cached and will require all queries to access the\n    /// server instead of following the `requestCachePolicy`.\n    public internal(set) var isUsingPostForQuery = false\n\n    /// The default caching policy for all http requests that determines when to\n    /// return a response from the cache. Defaults to `useProtocolCachePolicy`.\n    /// See Apple's [documentation](https://developer.apple.com/documentation/foundation/url_loading_system/accessing_cached_data)\n    /// for more info.\n    public internal(set) var requestCachePolicy = URLRequest.CachePolicy.useProtocolCachePolicy\n\n    /// A dictionary of additional headers to send with requests. See Apple's\n    /// [documentation](https://developer.apple.com/documentation/foundation/urlsessionconfiguration/1411532-httpadditionalheaders)\n    /// for more info.\n    public internal(set) var httpAdditionalHeaders: [AnyHashable: Any]?\n\n    /// The memory capacity of the cache, in bytes. Defaults to 512KB.\n    public internal(set) var cacheMemoryCapacity = 512_000\n\n    /// The disk capacity of the cache, in bytes. Defaults to 10MB.\n    public internal(set) var cacheDiskCapacity = 10_000_000\n\n    /// If your app previously used the iOS Objective-C SDK, setting this value\n    /// to **true** will attempt to migrate relevant data stored in the Keychain to\n    /// ParseSwift. Defaults to **false**.\n    public internal(set) var isMigratingFromObjcSDK: Bool = false\n\n    /// Deletes the Parse Keychain when the app is running for the first time.\n    /// Defaults to **false**.\n    public internal(set) var isDeletingKeychainIfNeeded: Bool = false\n\n    /// Sets `kSecUseDataProtectionKeychain` to **true**. See Apple's [documentation](https://developer.apple.com/documentation/security/ksecusedataprotectionkeychain)\n    /// for more info.\n    /// Defaults to **false**.\n    ///  - warning: This is known to cause issues in Playgrounds or in situtations when\n    ///  apps do not have credentials to setup a Keychain.\n    public internal(set) var isUsingDataProtectionKeychain: Bool = false\n\n    /// Maximum number of times to try to connect to Parse Server.\n    /// Defaults to 5.\n    public internal(set) var maxConnectionAttempts: Int = 5\n\n    /**\n     Override the default transfer behavior for `ParseFile`'s.\n     Allows for direct uploads to other file storage providers.\n     */\n    public internal(set) var parseFileTransfer: ParseFileTransferable\n\n    internal var authentication: ((URLAuthenticationChallenge,\n                                   (URLSession.AuthChallengeDisposition,\n                                    URLCredential?) -> Void) -> Void)?\n    internal var mountPath: String\n    internal var isTestingSDK = false // Enable this only for certain tests like ParseFile\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    internal var keychainAccessGroup = ParseKeychainAccessGroup()\n    #endif\n\n    /**\n     Create a Parse Swift configuration.\n     - parameter applicationId: The application id for your Parse application.\n     - parameter clientKey: The client key for your Parse application.\n     - parameter masterKey: The master key for your Parse application. This key should only be\n     specified when using the SDK on a server.\n     - parameter serverURL: The server URL to connect to Parse Server.\n     - parameter liveQueryServerURL: The live query server URL to connect to Parse Server.\n     - parameter requiringCustomObjectIds: Requires `objectId`'s to be created on the client\n     side for each object. Must be enabled on the server to work.\n     - parameter usingTransactions: Use transactions when saving/updating multiple objects.\n     - parameter usingEqualQueryConstraint: Use the **$eq** query constraint when querying.\n     - parameter usingPostForQuery: Use **POST** instead of **GET** when making query calls.\n     Defaults to **false**.\n     - parameter primitiveStore: A key/value store that conforms to the `ParsePrimitiveStorable`\n     protocol. Defaults to `nil` in which one will be created an memory, but never persisted. For Linux, this\n     this is the only store available since there is no Keychain. Linux, Android, and Windows users should\n     replace this store with an encrypted one.\n     - parameter requestCachePolicy: The default caching policy for all http requests that determines\n     when to return a response from the cache. Defaults to `useProtocolCachePolicy`. See Apple's [documentation](https://developer.apple.com/documentation/foundation/url_loading_system/accessing_cached_data)\n     for more info.\n     - parameter cacheMemoryCapacity: The memory capacity of the cache, in bytes. Defaults to 512KB.\n     - parameter cacheDiskCapacity: The disk capacity of the cache, in bytes. Defaults to 10MB.\n     - parameter usingDataProtectionKeychain: Sets `kSecUseDataProtectionKeychain` to **true**. See Apple's [documentation](https://developer.apple.com/documentation/security/ksecusedataprotectionkeychain)\n     for more info. Defaults to **false**.\n     - parameter deletingKeychainIfNeeded: Deletes the Parse Keychain when the app is running for the first time.\n     Defaults to **false**.\n     - parameter httpAdditionalHeaders: A dictionary of additional headers to send with requests. See Apple's\n     [documentation](https://developer.apple.com/documentation/foundation/urlsessionconfiguration/1411532-httpadditionalheaders)\n     for more info.\n     - parameter maxConnectionAttempts: Maximum number of times to try to connect to Parse Server.\n     Defaults to 5.\n     - parameter parseFileTransfer: Override the default transfer behavior for `ParseFile`'s.\n     Allows for direct uploads to other file storage providers.\n     - parameter authentication: A callback block that will be used to receive/accept/decline network challenges.\n     Defaults to `nil` in which the SDK will use the default OS authentication methods for challenges.\n     It should have the following argument signature: `(challenge: URLAuthenticationChallenge,\n     completionHandler: (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) -> Void`.\n     See Apple's [documentation](https://developer.apple.com/documentation/foundation/urlsessiontaskdelegate/1411595-urlsession) for more for details.\n     - important: It is recomended to only specify `masterKey` when using the SDK on a server. Do not use this key on the client.\n     - note: Setting `usingPostForQuery` to **true**  will require all queries to access the server instead of following the `requestCachePolicy`.\n     - warning: `usingTransactions` is experimental.\n     - warning: Setting `usingDataProtectionKeychain` to **true** is known to cause issues in Playgrounds or in\n     situtations when apps do not have credentials to setup a Keychain.\n     */\n    public init(applicationId: String,\n                clientKey: String? = nil,\n                masterKey: String? = nil,\n                webhookKey: String? = nil,\n                serverURL: URL,\n                liveQueryServerURL: URL? = nil,\n                requiringCustomObjectIds: Bool = false,\n                usingTransactions: Bool = false,\n                usingEqualQueryConstraint: Bool = false,\n                usingPostForQuery: Bool = false,\n                primitiveStore: ParsePrimitiveStorable? = nil,\n                requestCachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy,\n                cacheMemoryCapacity: Int = 512_000,\n                cacheDiskCapacity: Int = 10_000_000,\n                usingDataProtectionKeychain: Bool = false,\n                deletingKeychainIfNeeded: Bool = false,\n                httpAdditionalHeaders: [AnyHashable: Any]? = nil,\n                maxConnectionAttempts: Int = 5,\n                parseFileTransfer: ParseFileTransferable? = nil,\n                authentication: ((URLAuthenticationChallenge,\n                                  (URLSession.AuthChallengeDisposition,\n                                   URLCredential?) -> Void) -> Void)? = nil) {\n        self.applicationId = applicationId\n        self.clientKey = clientKey\n        self.masterKey = masterKey\n        self.serverURL = serverURL\n        self.liveQuerysServerURL = liveQueryServerURL\n        self.isRequiringCustomObjectIds = requiringCustomObjectIds\n        self.isUsingTransactions = usingTransactions\n        self.isUsingEqualQueryConstraint = usingEqualQueryConstraint\n        self.isUsingPostForQuery = usingPostForQuery\n        self.mountPath = \"/\" + serverURL.pathComponents\n            .filter { $0 != \"/\" }\n            .joined(separator: \"/\")\n        self.authentication = authentication\n        self.requestCachePolicy = requestCachePolicy\n        self.cacheMemoryCapacity = cacheMemoryCapacity\n        self.cacheDiskCapacity = cacheDiskCapacity\n        self.isUsingDataProtectionKeychain = usingDataProtectionKeychain\n        self.isDeletingKeychainIfNeeded = deletingKeychainIfNeeded\n        self.httpAdditionalHeaders = httpAdditionalHeaders\n        self.maxConnectionAttempts = maxConnectionAttempts\n        self.parseFileTransfer = parseFileTransfer ?? ParseFileDefaultTransfer()\n        ParseStorage.shared.use(primitiveStore ?? InMemoryKeyValueStore())\n    }\n\n    /**\n     Create a Parse Swift configuration.\n     - parameter applicationId: The application id for your Parse application.\n     - parameter clientKey: The client key for your Parse application.\n     - parameter masterKey: The master key for your Parse application. This key should only be\n     specified when using the SDK on a server.\n     - parameter serverURL: The server URL to connect to Parse Server.\n     - parameter liveQueryServerURL: The live query server URL to connect to Parse Server.\n     - parameter allowingCustomObjectIds: Requires `objectId`'s to be created on the client\n     side for each object. Must be enabled on the server to work.\n     - parameter usingTransactions: Use transactions when saving/updating multiple objects.\n     - parameter usingEqualQueryConstraint: Use the **$eq** query constraint when querying.\n     - parameter usingPostForQuery: Use **POST** instead of **GET** when making query calls.\n     Defaults to **false**.\n     - parameter keyValueStore: A key/value store that conforms to the `ParseKeyValueStore`\n     protocol. Defaults to `nil` in which one will be created an memory, but never persisted. For Linux, this\n     this is the only store available since there is no Keychain. Linux, Android, and Windows users should\n     replace this store with an encrypted one.\n     - parameter requestCachePolicy: The default caching policy for all http requests that determines\n     when to return a response from the cache. Defaults to `useProtocolCachePolicy`. See Apple's [documentation](https://developer.apple.com/documentation/foundation/url_loading_system/accessing_cached_data)\n     for more info.\n     - parameter cacheMemoryCapacity: The memory capacity of the cache, in bytes. Defaults to 512KB.\n     - parameter cacheDiskCapacity: The disk capacity of the cache, in bytes. Defaults to 10MB.\n     - parameter usingDataProtectionKeychain: Sets `kSecUseDataProtectionKeychain` to **true**. See Apple's [documentation](https://developer.apple.com/documentation/security/ksecusedataprotectionkeychain)\n     for more info. Defaults to **false**.\n     - parameter deletingKeychainIfNeeded: Deletes the Parse Keychain when the app is running for the first time.\n     Defaults to **false**.\n     - parameter httpAdditionalHeaders: A dictionary of additional headers to send with requests. See Apple's\n     [documentation](https://developer.apple.com/documentation/foundation/urlsessionconfiguration/1411532-httpadditionalheaders)\n     for more info.\n     - parameter maxConnectionAttempts: Maximum number of times to try to connect to Parse Server.\n     Defaults to 5.\n     - parameter parseFileTransfer: Override the default transfer behavior for `ParseFile`'s.\n     Allows for direct uploads to other file storage providers.\n     - parameter authentication: A callback block that will be used to receive/accept/decline network challenges.\n     Defaults to `nil` in which the SDK will use the default OS authentication methods for challenges.\n     It should have the following argument signature: `(challenge: URLAuthenticationChallenge,\n     completionHandler: (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) -> Void`.\n     See Apple's [documentation](https://developer.apple.com/documentation/foundation/urlsessiontaskdelegate/1411595-urlsession) for more for details.\n     - important: It is recomended to only specify `masterKey` when using the SDK on a server. Do not use this key on the client.\n     - note: Setting `usingPostForQuery` to **true**  will require all queries to access the server instead of following the `requestCachePolicy`.\n     - warning: `usingTransactions` is experimental.\n     - warning: Setting `usingDataProtectionKeychain` to **true** is known to cause issues in Playgrounds or in\n     situtations when apps do not have credentials to setup a Keychain.\n     */\n    @available(*, deprecated, message: \"Change: allowingCustomObjectIds->requiringCustomObjectIds and keyValueStore->primitiveStore\")\n    public init(applicationId: String,\n                clientKey: String? = nil,\n                masterKey: String? = nil,\n                webhookKey: String? = nil,\n                serverURL: URL,\n                liveQueryServerURL: URL? = nil,\n                allowingCustomObjectIds: Bool,\n                usingTransactions: Bool = false,\n                usingEqualQueryConstraint: Bool = false,\n                usingPostForQuery: Bool = false,\n                keyValueStore: ParseKeyValueStore? = nil,\n                requestCachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy,\n                cacheMemoryCapacity: Int = 512_000,\n                cacheDiskCapacity: Int = 10_000_000,\n                usingDataProtectionKeychain: Bool = false,\n                deletingKeychainIfNeeded: Bool = false,\n                httpAdditionalHeaders: [AnyHashable: Any]? = nil,\n                maxConnectionAttempts: Int = 5,\n                parseFileTransfer: ParseFileTransferable? = nil,\n                authentication: ((URLAuthenticationChallenge,\n                                  (URLSession.AuthChallengeDisposition,\n                                   URLCredential?) -> Void) -> Void)? = nil) {\n        self.init(applicationId: applicationId,\n                  clientKey: clientKey,\n                  masterKey: masterKey,\n                  webhookKey: webhookKey,\n                  serverURL: serverURL,\n                  liveQueryServerURL: liveQueryServerURL,\n                  requiringCustomObjectIds: allowingCustomObjectIds,\n                  usingTransactions: usingTransactions,\n                  usingEqualQueryConstraint: usingEqualQueryConstraint,\n                  usingPostForQuery: usingPostForQuery,\n                  primitiveStore: keyValueStore,\n                  requestCachePolicy: requestCachePolicy,\n                  cacheMemoryCapacity: cacheMemoryCapacity,\n                  cacheDiskCapacity: cacheDiskCapacity,\n                  usingDataProtectionKeychain: usingDataProtectionKeychain,\n                  deletingKeychainIfNeeded: deletingKeychainIfNeeded,\n                  httpAdditionalHeaders: httpAdditionalHeaders,\n                  maxConnectionAttempts: maxConnectionAttempts,\n                  parseFileTransfer: parseFileTransfer ?? ParseFileDefaultTransfer(),\n                  authentication: authentication)\n    }\n\n    /**\n     Create a Parse Swift configuration.\n     - parameter applicationId: The application id for your Parse application.\n     - parameter clientKey: The client key for your Parse application.\n     - parameter masterKey: The master key for your Parse application. This key should only be\n     specified when using the SDK on a server.\n     - parameter serverURL: The server URL to connect to Parse Server.\n     - parameter liveQueryServerURL: The live query server URL to connect to Parse Server.\n     - parameter allowingCustomObjectIds: Requires `objectId`'s to be created on the client\n     side for each object. Must be enabled on the server to work.\n     - parameter usingTransactions: Use transactions when saving/updating multiple objects.\n     - parameter usingEqualQueryConstraint: Use the **$eq** query constraint when querying.\n     - parameter usingPostForQuery: Use **POST** instead of **GET** when making query calls.\n     Defaults to **false**.\n     - parameter keyValueStore: A key/value store that conforms to the `ParseKeyValueStore`\n     protocol. Defaults to `nil` in which one will be created an memory, but never persisted. For Linux, this\n     this is the only store available since there is no Keychain. Linux, Android, and Windows users should\n     replace this store with an encrypted one.\n     - parameter requestCachePolicy: The default caching policy for all http requests that determines\n     when to return a response from the cache. Defaults to `useProtocolCachePolicy`. See Apple's [documentation](https://developer.apple.com/documentation/foundation/url_loading_system/accessing_cached_data)\n     for more info.\n     - parameter cacheMemoryCapacity: The memory capacity of the cache, in bytes. Defaults to 512KB.\n     - parameter cacheDiskCapacity: The disk capacity of the cache, in bytes. Defaults to 10MB.\n     - parameter migratingFromObjcSDK: If your app previously used the iOS Objective-C SDK, setting this value\n     to **true** will attempt to migrate relevant data stored in the Keychain to ParseSwift. Defaults to **false**.\n     - parameter usingDataProtectionKeychain: Sets `kSecUseDataProtectionKeychain` to **true**. See Apple's [documentation](https://developer.apple.com/documentation/security/ksecusedataprotectionkeychain)\n     for more info. Defaults to **false**.\n     - parameter deletingKeychainIfNeeded: Deletes the Parse Keychain when the app is running for the first time.\n     Defaults to **false**.\n     - parameter httpAdditionalHeaders: A dictionary of additional headers to send with requests. See Apple's\n     [documentation](https://developer.apple.com/documentation/foundation/urlsessionconfiguration/1411532-httpadditionalheaders)\n     for more info.\n     - parameter maxConnectionAttempts: Maximum number of times to try to connect to Parse Server.\n     Defaults to 5.\n     - parameter parseFileTransfer: Override the default transfer behavior for `ParseFile`'s.\n     Allows for direct uploads to other file storage providers.\n     - parameter authentication: A callback block that will be used to receive/accept/decline network challenges.\n     Defaults to `nil` in which the SDK will use the default OS authentication methods for challenges.\n     It should have the following argument signature: `(challenge: URLAuthenticationChallenge,\n     completionHandler: (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) -> Void`.\n     See Apple's [documentation](https://developer.apple.com/documentation/foundation/urlsessiontaskdelegate/1411595-urlsession) for more for details.\n     - important: It is recomended to only specify `masterKey` when using the SDK on a server. Do not use this key on the client.\n     - note: Setting `usingPostForQuery` to **true**  will require all queries to access the server instead of following the `requestCachePolicy`.\n     - warning: `usingTransactions` is experimental.\n     - warning: Setting `usingDataProtectionKeychain` to **true** is known to cause issues in Playgrounds or in\n     situtations when apps do not have credentials to setup a Keychain.\n     */\n    @available(*, deprecated, message: \"Remove the migratingFromObjcSDK argument\")\n    public init(applicationId: String,\n                clientKey: String? = nil,\n                masterKey: String? = nil,\n                webhookKey: String? = nil,\n                serverURL: URL,\n                liveQueryServerURL: URL? = nil,\n                allowingCustomObjectIds: Bool = false,\n                usingTransactions: Bool = false,\n                usingEqualQueryConstraint: Bool = false,\n                usingPostForQuery: Bool = false,\n                keyValueStore: ParseKeyValueStore? = nil,\n                requestCachePolicy: URLRequest.CachePolicy = .useProtocolCachePolicy,\n                cacheMemoryCapacity: Int = 512_000,\n                cacheDiskCapacity: Int = 10_000_000,\n                migratingFromObjcSDK: Bool,\n                usingDataProtectionKeychain: Bool = false,\n                deletingKeychainIfNeeded: Bool = false,\n                httpAdditionalHeaders: [AnyHashable: Any]? = nil,\n                maxConnectionAttempts: Int = 5,\n                parseFileTransfer: ParseFileTransferable? = nil,\n                authentication: ((URLAuthenticationChallenge,\n                                  (URLSession.AuthChallengeDisposition,\n                                   URLCredential?) -> Void) -> Void)? = nil) {\n        self.init(applicationId: applicationId,\n                  clientKey: clientKey,\n                  masterKey: masterKey,\n                  webhookKey: webhookKey,\n                  serverURL: serverURL,\n                  liveQueryServerURL: liveQueryServerURL,\n                  requiringCustomObjectIds: allowingCustomObjectIds,\n                  usingTransactions: usingTransactions,\n                  usingEqualQueryConstraint: usingEqualQueryConstraint,\n                  usingPostForQuery: usingPostForQuery,\n                  primitiveStore: keyValueStore,\n                  requestCachePolicy: requestCachePolicy,\n                  cacheMemoryCapacity: cacheMemoryCapacity,\n                  cacheDiskCapacity: cacheDiskCapacity,\n                  usingDataProtectionKeychain: usingDataProtectionKeychain,\n                  deletingKeychainIfNeeded: deletingKeychainIfNeeded,\n                  httpAdditionalHeaders: httpAdditionalHeaders,\n                  maxConnectionAttempts: maxConnectionAttempts,\n                  parseFileTransfer: parseFileTransfer ?? ParseFileDefaultTransfer(),\n                  authentication: authentication)\n        self.isMigratingFromObjcSDK = migratingFromObjcSDK\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseError.swift",
    "content": "//\n//  ParseError.swift\n//  ParseSwift\n//\n//  Created by Florent Vilmart on 17-09-24.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n An object with a Parse code and message.\n */\npublic struct ParseError: ParseTypeable, Swift.Error {\n    /// The value representing the error from the Parse Server.\n    public let code: Code\n    /// The text representing the error from the Parse Server.\n    public let message: String\n    /// An error value representing a custom error from the Parse Server.\n    public let otherCode: Int?\n    let error: String?\n\n    enum CodingKeys: String, CodingKey {\n        case code\n        case message = \"error\"\n        case error = \"message\"\n    }\n\n    /**\n    `ParseError.Code` enum contains all custom error codes that are used\n         as `code` for `Error` for callbacks on all classes.\n    */\n    public enum Code: Int, Swift.Error, Codable {\n\n        /**\n         Internal SDK Error. No information available\n         */\n        case unknownError = -1\n\n        /**\n         Internal server error. No information available.\n         */\n        case internalServer = 1\n\n        /**\n         The connection to the Parse servers failed.\n         */\n        case connectionFailed = 100\n\n        /**\n         Object does not exist, or has an incorrect password.\n         */\n        case objectNotFound = 101\n\n        /**\n         You tried to find values matching a datatype that does not\n         support exact database matching, like an array or a dictionary.\n         */\n        case invalidQuery = 102\n\n        /**\n         Missing or invalid classname. Classnames are case-sensitive.\n         They must start with a letter, and `a-zA-Z0-9_` are the only valid characters.\n         */\n        case invalidClassName = 103\n\n        /**\n         Missing object id.\n         */\n        case missingObjectId = 104\n\n        /**\n         Invalid key name. Keys are case-sensitive.\n         They must start with a letter, and `a-zA-Z0-9_` are the only valid characters.\n         */\n        case invalidKeyName = 105\n\n        /**\n         Malformed pointer. Pointers must be arrays of a classname and an object id.\n         */\n        case invalidPointer = 106\n\n        /**\n         Malformed json object. A json dictionary is expected.\n         */\n        case invalidJSON = 107\n\n        /**\n         Tried to access a feature only available internally.\n         */\n        case commandUnavailable = 108\n\n        /**\n         Field set to incorrect type.\n         */\n        case incorrectType = 111\n\n        /**\n         Invalid channel name. A channel name is either an empty string (the broadcast channel)\n         or contains only `a-zA-Z0-9_` characters and starts with a letter.\n         */\n        case invalidChannelName = 112\n\n        /**\n         Invalid device token.\n         */\n        case invalidDeviceToken = 114\n\n        /**\n         Push is misconfigured. See details to find out how.\n         */\n        case pushMisconfigured = 115\n\n        /**\n         The object is too large.\n         */\n        case objectTooLarge = 116\n\n        /**\n         That operation is not allowed for clients.\n         */\n        case operationForbidden = 119\n\n        /**\n         The results were not found in the cache.\n         */\n        case cacheMiss = 120\n\n        /**\n         Keys in `NSDictionary` values may not include `$` or `.`.\n         */\n        case invalidNestedKey = 121\n\n        /**\n         Invalid file name.\n         A file name can contain only `a-zA-Z0-9_.` characters and should be between 1 and 36 characters.\n         */\n        case invalidFileName = 122\n\n        /**\n         Invalid ACL. An ACL with an invalid format was saved. This should not happen if you use `ACL`.\n         */\n        case invalidACL = 123\n\n        /**\n         The request timed out on the server. Typically this indicates the request is too expensive.\n         */\n        case timeout = 124\n\n        /**\n         The email address was invalid.\n         */\n        case invalidEmailAddress = 125\n\n        /**\n         Missing content type.\n         */\n        case missingContentType = 126\n\n        /**\n         Missing content length.\n         */\n        case missingContentLength = 127\n\n        /**\n         Invalid content length.\n         */\n        case invalidContentLength = 128\n\n        /**\n         File was too large.\n         */\n        case fileTooLarge = 129\n\n        /**\n         Failure saving a file.\n         */\n        case fileSaveFailure = 130\n\n        /**\n         A unique field was given a value that is already taken.\n         */\n        case duplicateValue = 137\n\n        /**\n         Role's name is invalid.\n         */\n        case invalidRoleName = 139\n\n        /**\n         Exceeded an application quota. Upgrade to resolve.\n         */\n        case exceededQuota = 140\n\n        /**\n         Cloud Code script had an error.\n         */\n        case scriptFailed = 141\n\n        /**\n         Cloud Code validation failed.\n         */\n        case validationFailed = 142\n\n        /**\n         Fail to convert data to image.\n         */\n        case invalidImageData = 143\n\n        /**\n         Unsaved file failure.\n         */\n        case unsavedFileFailure = 151\n\n        /**\n         An invalid push time.\n         */\n        case invalidPushTime = 152\n\n        /**\n         Fail to delete file.\n         */\n        case fileDeleteFailure = 153\n\n        /**\n         Fail to delete an unnamed file.\n         */\n        case fileDeleteUnnamedFailure = 161\n\n        /**\n         Application has exceeded its request limit.\n         */\n        case requestLimitExceeded = 155\n\n        /**\n         The request was a duplicate and has been discarded\n         due to idempotency rules.\n         */\n        case duplicateRequest = 159\n\n        /**\n         Invalid event name.\n         */\n        case invalidEventName = 160\n\n        /**\n         Invalid value.\n         */\n        case invalidValue = 162\n\n        /**\n         Username is missing or empty.\n         */\n        case usernameMissing = 200\n\n        /**\n         Password is missing or empty.\n         */\n        case userPasswordMissing = 201\n\n        /**\n         Username has already been taken.\n         */\n        case usernameTaken = 202\n\n        /**\n         Email has already been taken.\n         */\n        case userEmailTaken = 203\n\n        /**\n         The email is missing, and must be specified.\n         */\n        case userEmailMissing = 204\n\n        /**\n         A user with the specified email was not found.\n         */\n        case userWithEmailNotFound = 205\n\n        /**\n         The user cannot be altered by a client without the session.\n         */\n        case userCannotBeAlteredWithoutSession = 206\n\n        /**\n         Users can only be created through sign up.\n         */\n        case userCanOnlyBeCreatedThroughSignUp = 207\n\n        /**\n         An existing account already linked to another user.\n         */\n        case accountAlreadyLinked = 208\n\n        /**\n         The current session token is invalid.\n         */\n        case invalidSessionToken = 209\n\n        /**\n         Error enabling or verifying MFA.\n         */\n        case mfaError = 210\n\n        /**\n         A valid MFA token must be provided.\n         */\n        case mfaTokenRequired = 211\n\n        /**\n         Linked id missing from request.\n         */\n        case linkedIdMissing = 250\n\n        /**\n         Invalid linked session.\n         */\n        case invalidLinkedSession = 251\n\n        /**\n         Error code indicating that a service being linked (e.g. Facebook or\n         Twitter) is unsupported.\n         */\n        case unsupportedService = 252\n\n        /**\n         Error code indicating an invalid operation occured on schema\n         */\n        case invalidSchemaOperation = 255\n\n        /**\n         Error code indicating that there were multiple errors. Aggregate errors\n         have an \"errors\" property, which is an array of error objects with more\n         detail about each error that occurred.\n         */\n        case aggregateError = 600\n\n        /**\n         Error code indicating the client was unable to read an input file.\n         */\n        case fileReadError = 601\n\n        /**\n         Error code indicating a real error code is unavailable because\n         we had to use an XDomainRequest object to allow CORS requests in\n         Internet Explorer, which strips the body from HTTP responses that have\n         a non-2XX status code.\n         */\n        case xDomainRequest = 602\n\n        /**\n         Error code indicating any other custom error sent from the Parse Server.\n         */\n        case other\n    }\n}\n\n// MARK: Encodable\nextension ParseError {\n\n    public func encode(to encoder: Encoder) throws {\n        var container = encoder.container(keyedBy: CodingKeys.self)\n        try container.encode(code, forKey: .code)\n        try container.encode(message, forKey: .message)\n    }\n}\n\n// MARK: Convenience Implementations\npublic extension ParseError {\n\n    /**\n     Create an error with a known code and custom message.\n     - parameter code: The known Parse code.\n     - parameter message: The custom message.\n     */\n    init(code: Code, message: String) {\n        self.code = code\n        self.message = message\n        self.otherCode = nil\n        self.error = nil\n    }\n\n    /**\n     Create an error with a custom code and custom message.\n     - parameter otherCode: The custom code.\n     - parameter message: The custom message.\n     */\n    init(otherCode: Int, message: String) {\n        self.code = .other\n        self.message = message\n        self.otherCode = otherCode\n        self.error = nil\n    }\n}\n\n// MARK: Decodable\nextension ParseError {\n\n    public init(from decoder: Decoder) throws {\n        let values = try decoder.container(keyedBy: CodingKeys.self)\n        do {\n            code = try values.decode(Code.self, forKey: .code)\n            otherCode = nil\n        } catch {\n            do {\n                otherCode = try values.decode(Int.self, forKey: .code)\n                code = .other\n            } catch {\n                code = .unknownError\n                otherCode = nil\n            }\n        }\n        // Handle when Parse Server sends \"message\" instead of \"error\".\n        do {\n            // Attempt the common case first.\n            message = try values.decode(String.self, forKey: .message)\n        } catch {\n            message = try values.decode(String.self, forKey: .error)\n        }\n        self.error = nil\n    }\n}\n\n// MARK: CustomDebugStringConvertible\nextension ParseError: CustomDebugStringConvertible {\n    public var debugDescription: String {\n        guard let otherCode = otherCode else {\n            return \"ParseError code=\\(code.rawValue) error=\\(message)\"\n        }\n        return \"ParseError code=\\(code.rawValue) error=\\(message) otherCode=\\(otherCode)\"\n    }\n}\n\n// MARK: LocalizedError\nextension ParseError: LocalizedError {\n    public var errorDescription: String? {\n        debugDescription\n    }\n}\n\n// MARK: Compare Errors\npublic extension Error {\n\n    /**\n     Returns the respective `ParseError` if the given `ParseError` code is equal to the error.\n     \n    **Example use case:**\n    ````\n    if let parseError = error.equalsTo(.objectNotFound)  {\n        print(parseError.description)\n    }\n    ````\n     - parameter errorCode: A `ParseError` code to compare to.\n     \n     - returns: Returns the `ParseError` with respect to the `Error`. If the error is not a `ParseError`, returns nil.\n     */\n    func equalsTo(_ errorCode: ParseError.Code) -> ParseError? {\n        guard let error = self as? ParseError,\n                error.code == errorCode else {\n            return nil\n        }\n        return error\n    }\n\n    /**\n     Validates if the given `ParseError` code is equal to the error.\n     \n    **Example use case:**\n    ````\n    if error.equalsTo(.objectNotFound)  {\n        //Do stuff\n    }\n    ````\n     - parameter errorCode: A `ParseError` code to compare to.\n     \n     - returns: A boolean indicating whether or not the `Error` is the `errorCode`.\n     */\n    func equalsTo(_ errorCode: ParseError.Code) -> Bool {\n        guard equalsTo(errorCode) != nil else {\n            return false\n        }\n        return true\n    }\n\n    /**\n     Returns the respective `ParseError` if the `Error` is contained in the array of `ParseError` codes.\n     \n    **Example use case:**\n    ````\n    if let parseError = error.containedIn([.objectNotFound, .invalidQuery])  {\n        print(parseError.description)\n    }\n    ````\n     - parameter errorCodes: An array of zero or more of `ParseError` codes to compare to.\n     \n     - returns: Returns the `ParseError` with respect to the `Error`. If the error is not a `ParseError`, returns nil.\n     */\n    func containedIn(_ errorCodes: [ParseError.Code]) -> ParseError? {\n        guard let error = self as? ParseError,\n              errorCodes.contains(error.code) else {\n            return nil\n        }\n        return error\n    }\n\n    /**\n     Returns the respective `ParseError` if the `Error` is contained in the list of `ParseError` codes.\n     \n    **Example use case:**\n    ````\n    if let parseError = error.containedIn(.objectNotFound, .invalidQuery)  {\n        print(parseError.description)\n    }\n    ````\n     - parameter errorCodes: A variadic amount of zero or more of `ParseError` codes to compare to.\n     \n     - returns: Returns the `ParseError` with respect to the `Error`. If the error is not a `ParseError`, returns nil.\n     */\n    func containedIn(_ errorCodes: ParseError.Code...) -> ParseError? {\n        containedIn(errorCodes)\n    }\n\n    /**\n     Validates if the given `ParseError` codes contains the error.\n     \n    **Example use case:**\n    ````\n    if error.containedIn([.objectNotFound, .invalidQuery])  {\n        //Do stuff\n    }\n    ````\n     - parameter errorCodes: An array of zero or more of `ParseError` codes to compare to.\n     \n     - returns: A boolean indicating whether or not the `Error` is contained in the `errorCodes`.\n     */\n    func containedIn(_ errorCodes: [ParseError.Code]) -> Bool {\n        guard containedIn(errorCodes) != nil else {\n            return false\n        }\n        return true\n    }\n\n    /**\n     Validates if the given `ParseError` codes contains the error.\n     \n    **Example use case:**\n    ````\n    if error.containedIn(.objectNotFound, .invalidQuery)  {\n        //Do stuff\n    }\n    ````\n     - parameter errorCodes: A variadic amount of zero or more of `ParseError` codes to compare to.\n     \n     - returns: A boolean indicating whether or not the `Error` is contained in the `errorCodes`.\n     */\n    func containedIn(_ errorCodes: ParseError.Code...) -> Bool {\n        containedIn(errorCodes)\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseField.swift",
    "content": "//\n//  ParseField.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 5/21/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/// A type used to create internal fields for `ParseSchema`.\npublic struct ParseField: ParseTypeable {\n    var __op: Operation? // swiftlint:disable:this identifier_name\n    var type: FieldType?\n    var required: Bool?\n    var defaultValue: AnyCodable?\n    var targetClass: String?\n\n    /// Field types available in `ParseSchema`.\n    public enum FieldType: String, Codable {\n        /// A string type.\n        case string = \"String\"\n        /// A number type.\n        case number = \"Number\"\n        /// A boolean type.\n        case boolean = \"Boolean\"\n        /// A date type.\n        case date = \"Date\"\n        /// A file type.\n        case file = \"File\"\n        /// A geoPoint type.\n        case geoPoint = \"GeoPoint\"\n        /// A polygon type.\n        case polygon = \"Polygon\"\n        /// An array type.\n        case array = \"Array\"\n        /// An object type.\n        case object = \"Object\"\n        /// A pointer type.\n        case pointer = \"Pointer\"\n        /// A relation type.\n        case relation = \"Relation\"\n        /// A bytes type.\n        case bytes = \"Bytes\"\n        /// A acl type.\n        case acl = \"ACL\"\n    }\n\n    init(operation: Operation) {\n        __op = operation\n    }\n\n    init<V>(type: FieldType, options: ParseFieldOptions<V>) where V: Codable {\n        self.type = type\n        self.required = options.required\n        if let defaultValue = options.defaultValue {\n            self.defaultValue = AnyCodable(defaultValue)\n        }\n    }\n\n    init<T>(type: FieldType,\n            options: ParseFieldOptions<T>) where T: ParseObject {\n        self.type = type\n        self.targetClass = T.className\n        self.required = options.required\n        if let defaultValue = options.defaultValue {\n            self.defaultValue = AnyCodable(defaultValue)\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseFieldOptions.swift",
    "content": "//\n//  ParseFieldOptions.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 5/29/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/// The options for a field in `ParseSchema`\npublic struct ParseFieldOptions<V: Codable>: Codable {\n    /// Specifies if a field is required.\n    public var required: Bool = false\n\n    /// The default value for a field.\n    public var defaultValue: V?\n\n    /**\n     Create new options for a `ParseSchema` field.\n     - parameter required: Specify if the field is required. Defaults to **false**.\n     - parameter defauleValue: The default value for the field. Defaults to **nil**.\n     */\n    public init(required: Bool = false, defauleValue: V? = nil) {\n        self.required = required\n        self.defaultValue = defauleValue\n    }\n}\n\nextension ParseFieldOptions where V: ParseObject {\n    /**\n     Create new options for a `ParseSchema` field.\n     - parameter required: Specify if the field is required. Defaults to **false**.\n     - parameter defauleValue: The default value for the field. Defaults to **nil**.\n     - throws: An error of `ParseError` type.\n     */\n    public init(required: Bool = false, defauleValue: V? = nil) throws {\n        self.required = required\n        self.defaultValue = try defauleValue?.toPointer().toObject()\n    }\n}\n\n// MARK: CustomDebugStringConvertible\nextension ParseFieldOptions {\n    public var debugDescription: String {\n        guard let descriptionData = try? ParseCoding.jsonEncoder().encode(self),\n            let descriptionString = String(data: descriptionData, encoding: .utf8) else {\n                return \"()\"\n        }\n\n        return \"\\(descriptionString)\"\n    }\n}\n\n// MARK: CustomStringConvertible\nextension ParseFieldOptions {\n    public var description: String {\n        debugDescription\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseFile+async.swift",
    "content": "//\n//  ParseFile+async.swift\n//  ParseFile+async\n//\n//  Created by Corey Baker on 8/6/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\n\npublic extension ParseFile {\n\n    // MARK: Async/Await\n    /**\n     Fetches a file with given url *asynchronously*.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A fetched `ParseFile`.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func fetch(options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.fetch(options: options,\n                       completion: continuation.resume)\n        }\n    }\n\n    /**\n     Fetches a file with given url *asynchronously*.\n     Fetches a file with given url *asynchronously*.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter progress: A block that will be called when file updates it is progress.\n     It should have the following argument signature: `(task: URLSessionDownloadTask,\n     bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)`.\n     - returns: A fetched `ParseFile`.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func fetch(options: API.Options = [],\n               progress: @escaping ((URLSessionDownloadTask,\n                                     Int64, Int64, Int64) -> Void)) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.fetch(options: options,\n                       progress: progress,\n                       completion: continuation.resume)\n        }\n    }\n\n    /**\n     Creates a file with given data *asynchronously* and executes the given callback block.\n     A name will be assigned to it by the server. If the file has not been downloaded, it will automatically\n     be downloaded before saved.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A saved `ParseFile`.\n     - throws: An error of type `ParseError`.\n    */\n    func save(options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.save(options: options,\n                      completion: continuation.resume)\n        }\n    }\n\n    /**\n     Creates a file with given data *asynchronously* and executes the given callback block.\n     A name will be assigned to it by the server. If the file has not been downloaded, it will automatically\n     be downloaded before saved.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter progress: A block that will be called when file updates it is progress.\n     It should have the following argument signature: `(task: URLSessionDownloadTask,\n     bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)`.\n     - returns: A ParsFile.\n     - throws: An error of type `ParseError`.\n     */\n    func save(options: API.Options = [],\n              progress: ((URLSessionTask,\n                          Int64,\n                          Int64,\n                          Int64) -> Void)? = nil) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.save(options: options,\n                      progress: progress,\n                      completion: continuation.resume)\n        }\n    }\n\n    /**\n     Deletes the file from the Parse Server.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n     */\n    func delete(options: API.Options = []) async throws {\n        let result = try await withCheckedThrowingContinuation { continuation in\n            self.delete(options: options, completion: continuation.resume)\n        }\n        if case let .failure(error) = result {\n            throw error\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseFile+combine.swift",
    "content": "//\n//  ParseFile+combine.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/29/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport Combine\n\npublic extension ParseFile {\n\n    // MARK: Combine\n    /**\n     Fetches a file with given url *synchronously*. Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func fetchPublisher(options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.fetch(options: options,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Fetches a file with given url *synchronously*. Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter progress: A block that will be called when file updates it is progress.\n     It should have the following argument signature: `(task: URLSessionDownloadTask,\n     bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)`.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func fetchPublisher(options: API.Options = [],\n                        progress: @escaping ((URLSessionDownloadTask,\n                                              Int64, Int64, Int64) -> Void)) -> Future<Self, ParseError> {\n        Future { promise in\n            self.fetch(options: options,\n                       progress: progress,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Creates a file with given data *asynchronously* and executes the given callback block.\n     Publishes when complete.\n     A name will be assigned to it by the server. If the file has not been downloaded, it will automatically\n     be downloaded before saved.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n    */\n    func savePublisher(options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.save(options: options,\n                      completion: promise)\n        }\n    }\n\n    /**\n     Creates a file with given data *asynchronously* and executes the given callback block.\n     A name will be assigned to it by the server. If the file has not been downloaded, it will automatically\n     be downloaded before saved. Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter progress: A block that will be called when file updates it is progress.\n     It should have the following argument signature: `(task: URLSessionDownloadTask,\n     bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)`.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func savePublisher(options: API.Options = [],\n                       progress: ((URLSessionTask, Int64, Int64, Int64) -> Void)? = nil) -> Future<Self, ParseError> {\n        Future { promise in\n            self.save(options: options,\n                      progress: progress,\n                      completion: promise)\n        }\n    }\n\n    /**\n     Deletes the file from the Parse Server. Publishes when complete.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     */\n    func deletePublisher(options: API.Options = []) -> Future<Void, ParseError> {\n        Future { promise in\n            self.delete(options: options, completion: promise)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseFile.swift",
    "content": "import Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\n\n/**\n  A `ParseFile` object representes a file of binary data stored on the Parse server.\n  This can be a image, video, or anything else that an application needs to reference in a non-relational way.\n */\npublic struct ParseFile: Fileable, Savable, Fetchable, Deletable, Hashable {\n\n    internal static var type: String {\n        \"File\"\n    }\n\n    internal let type: String = Self.type\n\n    internal var isDownloadNeeded: Bool {\n        return cloudURL != nil\n            && url == nil\n            && localURL == nil\n            && data == nil\n    }\n\n    public var id: UUID\n\n    /**\n      The name of the file.\n      Before the file is saved, this is the filename given by the user.\n      After the file is saved, that name gets prefixed with a unique identifier.\n     */\n    public internal(set) var name: String\n\n    /**\n     The Parse Server url of the file.\n     */\n    public internal(set) var url: URL?\n\n    /**\n     The local file path.\n     */\n    public var localURL: URL?\n\n    /**\n     The link to the file online that should be fetched before uploading to the Parse Server.\n     */\n    public var cloudURL: URL?\n\n    /**\n     The contents of the file.\n     */\n    public var data: Data?\n\n    /// The Content-Type header to use for the file.\n    public var mimeType: String?\n\n    /// Key value pairs to be stored with the file object.\n    public var metadata: [String: String]?\n\n    /// Key value pairs to be stored with the file object.\n    public var tags: [String: String]?\n\n    /// A set of header options sent to the server.\n    public var options: API.Options = []\n\n    /**\n     Creates a file with given data and name.\n     - parameter name: The name of the new `ParseFile`. The file name must begin with and\n     alphanumeric character, and consist of alphanumeric characters, periods, spaces, underscores,\n     or dashes. The default value is **file**.\n     - parameter data: The contents of the new `ParseFile`.\n     - parameter mimeType: Specify the Content-Type header to use for the file,  for example\n     **application/pdf**. The default is nil. If no value is specified the file type will be inferred from the file\n     extention of `name`.\n     - parameter metadata: Optional key value pairs to be stored with file object\n     - parameter tags: Optional key value pairs to be stored with file object\n     - note: `metadata` and `tags` are file adapter specific and not supported by all file adapters.\n     For more, see details on the\n     [S3 adapter](https://github.com/parse-community/parse-server-s3-adapter#adding-metadata-and-tags)\n     */\n    public init(name: String = \"file\", data: Data, mimeType: String? = nil,\n                metadata: [String: String]? = nil, tags: [String: String]? = nil,\n                options: API.Options = []) {\n        self.name = name\n        self.data = data\n        self.mimeType = mimeType\n        self.metadata = metadata\n        self.tags = tags\n        self.options = options\n        self.id = UUID()\n    }\n\n    /**\n     Creates a file from a local file path and name.\n     - parameter name: The name of the new `ParseFile`. The file name must begin with and\n     alphanumeric character, and consist of alphanumeric characters, periods, spaces, underscores,\n     or dashes. The default value is **file**.\n     - parameter localURL: The local file path of the`ParseFile`.\n     - parameter mimeType: Specify the Content-Type header to use for the file,  for example\n     **application/pdf**. The default is nil. If no value is specified the file type will be inferred from the file\n     extention of `name`.\n     - parameter metadata: Optional key value pairs to be stored with file object.\n     - parameter tags: Optional key value pairs to be stored with file object.\n     - note: `metadata` and `tags` are file adapter specific and not supported by all file adapters.\n     For more, see details on the\n     [S3 adapter](https://github.com/parse-community/parse-server-s3-adapter#adding-metadata-and-tags).\n     */\n    public init(name: String = \"file\", localURL: URL,\n                metadata: [String: String]? = nil, tags: [String: String]? = nil,\n                options: API.Options = []) {\n        self.name = name\n        self.localURL = localURL\n        self.metadata = metadata\n        self.tags = tags\n        self.options = options\n        self.id = UUID()\n    }\n\n    /**\n     Creates a file from a link online and name.\n     - parameter name: The name of the new `ParseFile`. The file name must begin with and\n     alphanumeric character, and consist of alphanumeric characters, periods, spaces, underscores,\n     or dashes. The default value is **file**.\n     - parameter cloudURL: The online link of the`ParseFile`.\n     - parameter mimeType: Specify the Content-Type header to use for the file,  for example\n     **application/pdf**. The default is nil. If no value is specified the file type will be inferred from the file\n     extention of `name`.\n     - parameter metadata: Optional key value pairs to be stored with file object.\n     - parameter tags: Optional key value pairs to be stored with file object.\n     - note: `metadata` and `tags` are file adapter specific and not supported by all file adapters.\n     For more, see details on the\n     [S3 adapter](https://github.com/parse-community/parse-server-s3-adapter#adding-metadata-and-tags).\n     */\n    public init(name: String = \"file\", cloudURL: URL,\n                metadata: [String: String]? = nil, tags: [String: String]? = nil,\n                options: API.Options = []) {\n        self.name = name\n        self.cloudURL = cloudURL\n        self.metadata = metadata\n        self.tags = tags\n        self.options = options\n        self.id = UUID()\n    }\n\n    enum CodingKeys: String, CodingKey {\n        case url\n        case name\n        case type = \"__type\"\n    }\n}\n\n// MARK: Helper Methods (internal)\nextension ParseFile {\n    func setDefaultOptions(_ options: API.Options) -> API.Options {\n        var options = options\n        if let mimeType = mimeType {\n            options.insert(.mimeType(mimeType))\n        } else {\n            options.insert(.removeMimeType)\n        }\n        if let metadata = metadata {\n            options.insert(.metadata(metadata))\n        }\n        if let tags = tags {\n            options.insert(.tags(tags))\n        }\n        options = options.union(self.options)\n        return options\n    }\n\n    func checkDownloadsForFile(options: API.Options) throws -> ParseFile? {\n        var cachePolicy: URLRequest.CachePolicy = ParseSwift.configuration.requestCachePolicy\n        var shouldBreak = false\n        for option in options {\n            switch option {\n            case .cachePolicy(let policy):\n                cachePolicy = policy\n                shouldBreak = true\n            default:\n                continue\n            }\n            if shouldBreak {\n                break\n            }\n        }\n        switch cachePolicy {\n        case .useProtocolCachePolicy, .returnCacheDataElseLoad:\n            return try createLocalParseFileIfExists()\n        case .returnCacheDataDontLoad:\n            return try? createLocalParseFileIfExists()\n        default:\n            throw ParseError(code: .unknownError,\n                             message: \"Policy defines to load from remote\")\n        }\n    }\n\n    func createLocalParseFileIfExists() throws -> Self {\n        let fileLocation = try ParseFileManager.fileExists(self)\n        var mutableFile = self\n        mutableFile.localURL = fileLocation\n        return mutableFile\n    }\n}\n\n// MARK: Coding\nextension ParseFile {\n    public init(from decoder: Decoder) throws {\n        let values = try decoder.container(keyedBy: CodingKeys.self)\n        url = try values.decode(URL.self, forKey: .url)\n        name = try values.decode(String.self, forKey: .name)\n        id = UUID()\n    }\n}\n\n// MARK: Deleting\nextension ParseFile {\n    /**\n     Deletes the file from the Parse cloud.\n     - requires: `.useMasterKey` has to be available.  It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after synchronous completion.\n     - throws: A `ParseError` if there was an issue deleting the file. Otherwise it was successful.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     */\n    public func delete(options: API.Options,\n                       callbackQueue: DispatchQueue) throws {\n        var options = options\n        options.insert(.useMasterKey)\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        options = options.union(self.options)\n\n        _ = try deleteFileCommand().execute(options: options)\n    }\n\n    /**\n     Deletes the file from the Parse cloud.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: A `ParseError` if there was an issue deleting the file. Otherwise it was successful.\n     */\n    public func delete(options: API.Options) throws {\n        try delete(options: options, callbackQueue: .main)\n    }\n\n    /**\n     Deletes the file from the Parse cloud. Completes with `nil` if successful.\n     - requires: `.useMasterKey` has to be available.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: A block that will be called when file deletes or fails.\n     It should have the following argument signature: `(Result<Void, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     */\n    public func delete(options: API.Options,\n                       callbackQueue: DispatchQueue = .main,\n                       completion: @escaping (Result<Void, ParseError>) -> Void) {\n        var options = options\n        options.insert(.useMasterKey)\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        options = options.union(self.options)\n\n        deleteFileCommand().executeAsync(options: options, callbackQueue: callbackQueue) { result in\n            switch result {\n            case .success:\n                completion(.success(()))\n            case .failure(let error):\n                completion(.failure(error))\n            }\n        }\n    }\n\n    internal func deleteFileCommand() -> API.Command<Self, NoBody> {\n        return API.Command<Self, NoBody>.deleteFile(self)\n    }\n}\n\n// MARK: Saving\nextension ParseFile {\n    /**\n     Creates a file with given stream *synchronously*. A name will be assigned to it by the server.\n     \n    **Checking progress**\n             \n          guard let parseFileURL = URL(string: \"https://parseplatform.org/img/logo.svg\") else {\n            return\n          }\n\n          let parseFile = ParseFile(name: \"logo.svg\", cloudURL: parseFileURL)\n          let fetchedFile = try parseFile.fetch(stream: InputStream(fileAtPath: URL(\"parse.org\")!) {\n          (_, _, totalWritten, totalExpected) in\n            let currentProgess = Double(totalWritten)/Double(totalExpected) * 100\n            print(currentProgess)\n          }\n     \n    **Cancelling**\n              \n           guard let parseFileURL = URL(string: \"https://parseplatform.org/img/logo.svg\") else {\n             return\n           }\n\n           let parseFile = ParseFile(name: \"logo.svg\", cloudURL: parseFileURL)\n           let fetchedFile = try parseFile.fetch(stream: InputStream(fileAtPath: URL(\"parse.org\")!){\n           (task, _, totalWritten, totalExpected) in\n             let currentProgess = Double(totalWritten)/Double(totalExpected) * 100\n             //Cancel when data exceeds 10%\n             if currentProgess > 10 {\n               task.cancel()\n               print(\"task has been cancelled\")\n             }\n             print(currentProgess)\n           }\n      \n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter progress: A block that will be called when file updates it is progress.\n     It should have the following argument signature: `(task: URLSessionDownloadTask,\n     bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)`.\n     - parameter stream: An input file stream.\n     - parameter callbackQueue: The queue to return to after synchronous completion.\n     Default value of .main.\n     - returns: A saved `ParseFile`.\n     */\n    public func save(options: API.Options = [],\n                     stream: InputStream,\n                     callbackQueue: DispatchQueue = .main,\n                     progress: ((URLSessionTask, Int64, Int64, Int64) -> Void)? = nil) throws {\n        try uploadFileCommand()\n            .executeStream(options: setDefaultOptions(options),\n                           callbackQueue: callbackQueue,\n                           uploadProgress: progress,\n                           stream: stream)\n    }\n\n    /**\n     Creates a file with given data *synchronously*. A name will be assigned to it by the server.\n     If the file has not been downloaded, it will automatically be downloaded before saved.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A saved `ParseFile`.\n     */\n    public func save(options: API.Options = []) throws -> ParseFile {\n        let options = setDefaultOptions(options)\n        if isDownloadNeeded {\n            let fetched = try fetch(options: options)\n            return try fetched.uploadFileCommand().execute(options: options)\n        }\n        return try uploadFileCommand().execute(options: options)\n    }\n\n    /**\n     Creates a file with given data *synchronously*. A name will be assigned to it by the server.\n     If the file has not been downloaded, it will automatically be downloaded before saved.\n     \n    **Checking progress**\n             \n          guard let parseFileURL = URL(string: \"https://parseplatform.org/img/logo.svg\") else {\n            return\n          }\n\n          let parseFile = ParseFile(name: \"logo.svg\", cloudURL: parseFileURL)\n          let fetchedFile = try parseFile.save { (_, _, totalWritten, totalExpected) in\n            let currentProgess = Double(totalWritten)/Double(totalExpected) * 100\n            print(currentProgess)\n          }\n     \n    **Cancelling**\n              \n           guard let parseFileURL = URL(string: \"https://parseplatform.org/img/logo.svg\") else {\n             return\n           }\n\n           let parseFile = ParseFile(name: \"logo.svg\", cloudURL: parseFileURL)\n           let fetchedFile = try parseFile.save { (task, _, totalWritten, totalExpected) in\n             let currentProgess = Double(totalWritten)/Double(totalExpected) * 100\n             //Cancel when data exceeds 10%\n             if currentProgess > 10 {\n               task.cancel()\n               print(\"task has been cancelled\")\n             }\n             print(currentProgess)\n           }\n      \n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after synchronous completion.\n     Defailts to .main.\n     - parameter progress: A block that will be called when file updates it is progress.\n     It should have the following argument signature: `(task: URLSessionDownloadTask,\n     bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)`.\n     - returns: A saved `ParseFile`.\n     */\n    public func save(options: API.Options = [],\n                     callbackQueue: DispatchQueue = .main,\n                     progress: ((URLSessionTask, Int64, Int64, Int64) -> Void)?) throws -> ParseFile {\n        let options = setDefaultOptions(options)\n        if isDownloadNeeded {\n            let fetched = try fetch(options: options)\n            return try fetched\n                .uploadFileCommand()\n                .execute(options: options,\n                         notificationQueue: callbackQueue,\n                         uploadProgress: progress)\n        }\n        return try uploadFileCommand().execute(options: options,\n                                               notificationQueue: callbackQueue,\n                                               uploadProgress: progress)\n    }\n\n    /**\n     Creates a file with given data *asynchronously* and executes the given callback block.\n     A name will be assigned to it by the server. If the file has not been downloaded, it will automatically\n     be downloaded before saved.\n    \n    **Checking progress**\n             \n          guard let parseFileURL = URL(string: \"https://parseplatform.org/img/logo.svg\") else {\n            return\n          }\n\n          let parseFile = ParseFile(name: \"logo.svg\", cloudURL: parseFileURL)\n          let fetchedFile = try parseFile.save { (_, _, totalWritten, totalExpected) in\n            let currentProgess = Double(totalWritten)/Double(totalExpected) * 100\n            print(currentProgess)\n          }\n     \n    **Cancelling**\n              \n           guard let parseFileURL = URL(string: \"https://parseplatform.org/img/logo.svg\") else {\n             return\n           }\n\n           let parseFile = ParseFile(name: \"logo.svg\", cloudURL: parseFileURL)\n           let fetchedFile = try parseFile.save(progress: {(task, _, totalWritten, totalExpected)-> Void in\n               let currentProgess = Double(totalWritten)/Double(totalExpected) * 100\n                 //Cancel when data exceeds 10%\n                 if currentProgess > 10 {\n                   task.cancel()\n                   print(\"task has been cancelled\")\n                 }\n                 print(currentProgess)\n               }) { result in\n                 ...\n           })\n      \n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter progress: A block that will be called when file updates it is progress.\n     It should have the following argument signature: `(task: URLSessionDownloadTask,\n     bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)`.\n     - parameter completion: A block that will be called when file saves or fails.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n    */\n    public func save(options: API.Options = [],\n                     callbackQueue: DispatchQueue = .main,\n                     progress: ((URLSessionTask, Int64, Int64, Int64) -> Void)? = nil,\n                     completion: @escaping (Result<Self, ParseError>) -> Void) {\n        let options = setDefaultOptions(options)\n        if isDownloadNeeded {\n            fetch(options: options) { result in\n                switch result {\n\n                case .success(let fetched):\n                    do {\n                        try fetched.uploadFileCommand()\n                            .executeAsync(options: options,\n                                      callbackQueue: callbackQueue,\n                                      uploadProgress: progress) { result in\n                                completion(result)\n                            }\n                    } catch {\n                        let defaultError = ParseError(code: .unknownError,\n                                                      message: error.localizedDescription)\n                        let parseError = error as? ParseError ?? defaultError\n                        callbackQueue.async {\n                            completion(.failure(parseError))\n                        }\n                    }\n                case .failure(let error):\n                    callbackQueue.async {\n                        completion(.failure(error))\n                    }\n                }\n            }\n        } else {\n            do {\n                try uploadFileCommand()\n                    .executeAsync(options: options,\n                                  callbackQueue: callbackQueue,\n                                  uploadProgress: progress) { result in\n                        completion(result)\n                    }\n            } catch {\n                let defaultError = ParseError(code: .unknownError,\n                                              message: error.localizedDescription)\n                let parseError = error as? ParseError ?? defaultError\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n\n    }\n\n    internal func uploadFileCommand() throws -> API.Command<Self, Self> {\n        try API.Command<Self, Self>.uploadFile(self)\n    }\n}\n\n// MARK: Fetching\nextension ParseFile {\n\n    /**\n     Fetches a file with given url *synchronously*.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter stream: An input file stream.\n     - parameter callbackQueue: The queue to return to after synchronous completion.\n     Default value of .main.\n     - returns: A saved `ParseFile`.\n     */\n    public func fetch(options: API.Options = [],\n                      stream: InputStream,\n                      callbackQueue: DispatchQueue = .main) throws {\n        try downloadFileCommand()\n            .executeStream(options: setDefaultOptions(options),\n                           callbackQueue: callbackQueue,\n                           stream: stream)\n    }\n\n    /**\n     Fetches a file with given url *synchronously*.\n     - parameter includeKeys: Currently not used for `ParseFile`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after synchronous completion.\n     - returns: A saved `ParseFile`.\n     */\n    public func fetch(includeKeys: [String]? = nil,\n                      options: API.Options = [],\n                      callbackQueue: DispatchQueue) throws -> ParseFile {\n        let options = setDefaultOptions(options)\n        do {\n            guard let file = try checkDownloadsForFile(options: options) else {\n                throw ParseError(code: .unsavedFileFailure,\n                                 message: \"File not downloaded\")\n            }\n            return file\n        } catch {\n            let defaultError = ParseError(code: .unknownError,\n                                          message: error.localizedDescription)\n            let parseError = error as? ParseError ?? defaultError\n            guard parseError.code != .unsavedFileFailure else {\n                throw parseError\n            }\n            return try downloadFileCommand()\n                .execute(options: options)\n        }\n    }\n\n    /**\n     Fetches a file with given url *synchronously*.\n     - parameter includeKeys: Currently not used for `ParseFile`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A saved `ParseFile`.\n     */\n    public func fetch(includeKeys: [String]? = nil,\n                      options: API.Options = []) throws -> ParseFile {\n        try fetch(includeKeys: includeKeys,\n                  options: options,\n                  callbackQueue: .main)\n    }\n\n    /**\n     Fetches a file with given url *synchronously*.\n     \n    **Checking progress**\n            \n         guard let parseFileURL = URL(string: \"https://parseplatform.org/img/logo.svg\") else {\n           return\n         }\n\n         let parseFile = ParseFile(name: \"logo.svg\", cloudURL: parseFileURL)\n         let fetchedFile = try parseFile.fetch { (_, _, totalDownloaded, totalExpected) in\n           let currentProgess = Double(totalWritten)/Double(totalExpected) * 100\n           print(currentProgess)\n         }\n    \n    **Cancelling**\n             \n          guard let parseFileURL = URL(string: \"https://parseplatform.org/img/logo.svg\") else {\n            return\n          }\n\n          let parseFile = ParseFile(name: \"logo.svg\", cloudURL: parseFileURL)\n          let fetchedFile = try parseFile.fetch { (task, _, totalDownloaded, totalExpected) in\n            let currentProgess = Double(totalDownloaded)/Double(totalExpected) * 100\n            //Cancel when data exceeds 10%\n            if currentProgess > 10 {\n              task.cancel()\n              print(\"task has been cancelled\")\n            }\n            print(currentProgess)\n          }\n     \n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after synchronous completion.\n     Defaults to .main.\n     - parameter progress: A block that will be called when file updates it is progress.\n     It should have the following argument signature: `(task: URLSessionDownloadTask,\n     bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)`.\n     - returns: A saved `ParseFile`.\n     */\n    public func fetch(options: API.Options = [],\n                      callbackQueue: DispatchQueue = .main,\n                      progress: @escaping ((URLSessionDownloadTask, Int64, Int64, Int64) -> Void)) throws -> ParseFile {\n        let options = setDefaultOptions(options)\n        do {\n            guard let file = try checkDownloadsForFile(options: options) else {\n                throw ParseError(code: .unsavedFileFailure,\n                                 message: \"File not downloaded\")\n            }\n            return file\n        } catch {\n            let defaultError = ParseError(code: .unknownError,\n                                          message: error.localizedDescription)\n            let parseError = error as? ParseError ?? defaultError\n            guard parseError.code != .unsavedFileFailure else {\n                throw parseError\n            }\n            return try downloadFileCommand()\n                .execute(options: options,\n                         notificationQueue: callbackQueue,\n                         downloadProgress: progress)\n        }\n    }\n\n    /**\n     Fetches a file with given url *asynchronously*.\n     \n    **Checking progress**\n             \n          guard let parseFileURL = URL(string: \"https://parseplatform.org/img/logo.svg\") else {\n            return\n          }\n\n          let parseFile = ParseFile(name: \"logo.svg\", cloudURL: parseFileURL)\n          let fetchedFile = try parseFile.fetch { (_, _, totalDownloaded, totalExpected) in\n            let currentProgess = Double(totalDownloaded)/Double(totalExpected) * 100\n            print(currentProgess)\n          }\n     \n    **Cancelling**\n              \n           guard let parseFileURL = URL(string: \"https://parseplatform.org/img/logo.svg\") else {\n             return\n           }\n\n           let parseFile = ParseFile(name: \"logo.svg\", cloudURL: parseFileURL)\n           let fetchedFile = try parseFile.fetch(progress: {(task, _, totalDownloaded, totalExpected)-> Void in\n             let currentProgess = Double(totalDownloaded)/Double(totalExpected) * 100\n             //Cancel when data exceeds 10%\n             if currentProgess > 10 {\n               task.cancel()\n               print(\"task has been cancelled\")\n             }\n             print(currentProgess)\n           }) { result in\n             ...\n           }\n      \n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter progress: A block that will be called when file updates it is progress.\n     It should have the following argument signature: `(task: URLSessionDownloadTask,\n     bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)`.\n     - parameter completion: A block that will be called when file fetches or fails.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n    */\n    public func fetch(options: API.Options = [],\n                      callbackQueue: DispatchQueue = .main,\n                      progress: ((URLSessionDownloadTask, Int64, Int64, Int64) -> Void)? = nil,\n                      completion: @escaping (Result<Self, ParseError>) -> Void) {\n        let options = setDefaultOptions(options)\n        do {\n            guard let file = try checkDownloadsForFile(options: options) else {\n                throw ParseError(code: .unsavedFileFailure,\n                                 message: \"File not downloaded\")\n            }\n            callbackQueue.async {\n                completion(.success(file))\n            }\n        } catch {\n            let defaultError = ParseError(code: .unknownError,\n                                          message: error.localizedDescription)\n            let parseError = error as? ParseError ?? defaultError\n            guard parseError.code != .unsavedFileFailure else {\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n                return\n            }\n            downloadFileCommand()\n                .executeAsync(options: options,\n                              callbackQueue: callbackQueue,\n                              downloadProgress: progress) { result in\n                    completion(result)\n                }\n        }\n    }\n\n    internal func downloadFileCommand() -> API.Command<Self, Self> {\n        return API.Command<Self, Self>.downloadFile(self)\n    }\n}\n\n// MARK: CustomDebugStringConvertible\nextension ParseFile: CustomDebugStringConvertible {\n    public var debugDescription: String {\n        guard let descriptionData = try? ParseCoding.jsonEncoder().encode(self),\n            let descriptionString = String(data: descriptionData, encoding: .utf8) else {\n            return \"()\"\n        }\n        return \"\\(descriptionString)\"\n    }\n}\n\n// MARK: CustomStringConvertible\nextension ParseFile: CustomStringConvertible {\n    public var description: String {\n        debugDescription\n    }\n} // swiftlint:disable:this file_length\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseFileDefaultTransfer.swift",
    "content": "//\n//  ParseFileDefaultTransfer.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/12/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\nfinal class ParseFileDefaultTransfer: ParseFileTransferable {}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseGeoPoint.swift",
    "content": "import Foundation\n#if canImport(CoreLocation)\nimport CoreLocation\n#endif\n\n/**\n  `ParseGeoPoint` is used to embed a latitude / longitude point as the value for a key in a `ParseObject`.\n   It could be used to perform queries in a geospatial manner using `ParseQuery.whereKey:nearGeoPoint:`.\n\n - warning:Currently, instances of `ParseObject` may only have one key associated with a `ParseGeoPoint` type.\n*/\npublic struct ParseGeoPoint: ParseTypeable, Hashable {\n    private let __type: String = \"GeoPoint\" // swiftlint:disable:this identifier_name\n    static let earthRadiusMiles = 3958.8\n    static let earthRadiusKilometers = 6371.0\n\n    enum CodingKeys: String, CodingKey {\n        case __type, latitude, longitude // swiftlint:disable:this identifier_name\n    }\n\n    /**\n      Latitude of point in degrees. Valid range is from `-90.0` to `90.0`.\n    */\n    public var latitude: Double\n\n    /**\n      Longitude of point in degrees. Valid range is from `-180.0` to `180.0`.\n    */\n    public var longitude: Double\n\n    /**\n     Create a `ParseGeoPoint` instance. Latitude and longitude are set to `0.0`.\n     */\n    public init() {\n        latitude = 0.0\n        longitude = 0.0\n    }\n\n    /**\n      Create a new `ParseGeoPoint` instance with the specified latitude and longitude.\n       - parameter latitude: Latitude of point in degrees.\n       - parameter longitude: Longitude of point in degrees.\n       - throws: An error of type `ParseError`.\n     */\n    public init(latitude: Double, longitude: Double) throws {\n        self.latitude = latitude\n        self.longitude = longitude\n        try validate()\n    }\n\n    func validate() throws {\n        if longitude < -180 {\n            throw ParseError(code: .unknownError,\n                             message: \"longitude should be > -180\")\n        } else if longitude > 180 {\n            throw ParseError(code: .unknownError,\n                             message: \"longitude should be < 180\")\n        } else if latitude < -90 {\n            throw ParseError(code: .unknownError,\n                             message: \"latitude should be > -90\")\n        } else if latitude > 90 {\n            throw ParseError(code: .unknownError,\n                             message: \"latitude should be < 90\")\n        }\n    }\n\n    /**\n     Get distance in radians from this point to specified point.\n\n     - parameter point: `ParseGeoPoint` that represents the location of other point.\n     - returns: Distance in radians between the receiver and `point`.\n    */\n    public func distanceInRadians(_ point: ParseGeoPoint) -> Double {\n        let d2r: Double = .pi / 180.0 // radian conversion factor\n        let lat1rad = self.latitude * d2r\n        let long1rad = self.longitude * d2r\n        let lat2rad = point.latitude * d2r\n        let long2rad = point.longitude * d2r\n        let deltaLat = lat1rad - lat2rad\n        let deltaLong = long1rad - long2rad\n        let sinDeltaLatDiv2 = sin(deltaLat / 2.0)\n        let sinDeltaLongDiv2 = sin(deltaLong / 2.0)\n        // Square of half the straight line chord distance between both points. [0.0, 1.0]\n        var partialDistance = sinDeltaLatDiv2 * sinDeltaLatDiv2 +\n            cos(lat1rad) * cos(lat2rad) * sinDeltaLongDiv2 * sinDeltaLongDiv2\n        partialDistance = fmin(1.0, partialDistance)\n        return 2.0 * asin(sqrt(partialDistance))\n    }\n\n    /**\n     Get distance in miles from this point to specified point.\n     - parameter point: `ParseGeoPoint` that represents the location of other point.\n     - returns: Distance in miles between the receiver and `point`.\n    */\n    public func distanceInMiles(_ point: ParseGeoPoint) -> Double {\n        return distanceInRadians(point) * Self.earthRadiusMiles\n    }\n\n    /**\n     Get distance in kilometers from this point to specified point.\n     - parameter point: `ParseGeoPoint` that represents the location of other point.\n     - returns: Distance in kilometers between the receiver and `point`.\n    */\n    public func distanceInKilometers(_ point: ParseGeoPoint) -> Double {\n        return distanceInRadians(point) * Self.earthRadiusKilometers\n    }\n}\n\nextension ParseGeoPoint {\n    public init(from decoder: Decoder) throws {\n        let values = try decoder.container(keyedBy: CodingKeys.self)\n        longitude = try values.decode(Double.self, forKey: .longitude)\n        latitude = try values.decode(Double.self, forKey: .latitude)\n        try validate()\n    }\n\n    public func encode(to encoder: Encoder) throws {\n        var container = encoder.container(keyedBy: CodingKeys.self)\n        try container.encode(__type, forKey: .__type)\n        try container.encode(longitude, forKey: .longitude)\n        try container.encode(latitude, forKey: .latitude)\n        try validate()\n    }\n}\n\n#if canImport(CoreLocation)\n// MARK: CoreLocation\npublic extension ParseGeoPoint {\n\n    /**\n     A `CLLocation` instance created from the current `ParseGeoPoint`.\n     */\n    var toCLLocation: CLLocation {\n        CLLocation(latitude: latitude, longitude: longitude)\n    }\n\n    /**\n     A `CLLocationCoordinate2D` instance created from the current `ParseGeoPoint`.\n     */\n    var toCLLocationCoordinate2D: CLLocationCoordinate2D {\n        CLLocationCoordinate2D(latitude: latitude, longitude: longitude)\n    }\n\n    /**\n     Creates a new `ParseGeoPoint` instance for the given `CLLocation`, set to the location's coordinates.\n     - parameter location: Instance of `CLLocation`, with set latitude and longitude.\n     - throws: An error of `ParseError` type.\n     */\n    init(location: CLLocation) throws {\n        self.longitude = location.coordinate.longitude\n        self.latitude = location.coordinate.latitude\n        try validate()\n    }\n\n    /**\n     Creates a new `ParseGeoPoint` instance for the given `CLLocationCoordinate2D`, set to the location's coordinates.\n     - parameter location: Instance of `CLLocationCoordinate2D`, with set latitude and longitude.\n     - throws: An error of `ParseError` type.\n     */\n    init(coordinate: CLLocationCoordinate2D) throws {\n        self.longitude = coordinate.longitude\n        self.latitude = coordinate.latitude\n        try validate()\n    }\n\n    /**\n     A `CLLocation` instance created from the current `ParseGeoPoint`.\n     - returns: Returns a `CLLocation`.\n     */\n    @available(*, deprecated, message: \"Use the computed property instead by removing \\\"()\\\"\")\n    func toCLLocation(_ geoPoint: ParseGeoPoint? = nil) -> CLLocation {\n        toCLLocation\n    }\n\n    /**\n     A `CLLocationCoordinate2D` instance created from the current `ParseGeoPoint`.\n     - returns: Returns a `CLLocationCoordinate2D`.\n     */\n    @available(*, deprecated, message: \"Use the computed property instead by removing \\\"()\\\"\")\n    func toCLLocationCoordinate2D(_ geoPoint: ParseGeoPoint? = nil) -> CLLocationCoordinate2D {\n        toCLLocationCoordinate2D\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseHealth+async.swift",
    "content": "//\n//  ParseHealth+async.swift\n//  ParseHealth+async\n//\n//  Created by Corey Baker on 8/6/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n\npublic extension ParseHealth {\n\n    // MARK: Async/Await\n\n    /**\n     Calls the health check function *asynchronously*.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Status of ParseServer.\n     - throws: An error of type `ParseError`.\n    */\n    static func check(options: API.Options = []) async throws -> String {\n        try await withCheckedThrowingContinuation { continuation in\n            Self.check(options: options,\n                       completion: continuation.resume)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseHealth+combine.swift",
    "content": "//\n//  ParseHealth+combine.swift\n//  ParseHealth+combine\n//\n//  Created by Corey Baker on 4/28/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\npublic extension ParseHealth {\n\n    // MARK: Combine\n\n    /**\n     Calls the health check function *asynchronously*. Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n    */\n    static func checkPublisher(options: API.Options = []) -> Future<String, ParseError> {\n        Future { promise in\n            Self.check(options: options,\n                       completion: promise)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseHealth.swift",
    "content": "//\n//  ParseHealth.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 4/28/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n  `ParseHealth` allows you to check the health of a Parse Server.\n */\npublic struct ParseHealth: ParseTypeable {\n\n    /**\n     Calls the health check function *synchronously* and returns a result of it is execution.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the status of the server.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    static public func check(options: API.Options = []) throws -> String {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        return try healthCommand().execute(options: options)\n    }\n\n    /**\n     Calls the health check function *asynchronously* and returns a result of it is execution.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: A block that will be called when the health check completes or fails.\n     It should have the following argument signature: `(Result<String, ParseError>)`.\n    */\n    static public func check(options: API.Options = [],\n                             callbackQueue: DispatchQueue = .main,\n                             completion: @escaping (Result<String, ParseError>) -> Void) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        healthCommand()\n            .executeAsync(options: options,\n                          callbackQueue: callbackQueue) { result in\n                completion(result)\n            }\n    }\n\n    internal static func healthCommand() -> API.Command<NoBody, String> {\n        return API.Command(method: .POST,\n                           path: .health) { (data) -> String in\n            return try ParseCoding.jsonDecoder().decode(HealthResponse.self, from: data).status\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseHookFunctionRequest.swift",
    "content": "//\n//  ParseHookRequest.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/14/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n A type that can decode requests when `ParseHookFunctionable` functions are called.\n - requires: `.useMasterKey` has to be available. It is recommended to only\n use the master key in server-side applications where the key is kept secure and not\n exposed to the public.\n */\npublic struct ParseHookFunctionRequest<U: ParseCloudUser, P: ParseHookParametable>: ParseHookRequestable {\n    public typealias UsertType = U\n    public var masterKey: Bool?\n    public var user: U?\n    public var installationId: String?\n    public var ipAddress: String?\n    public var headers: [String: String]?\n    /**\n     The `ParseHookParametable` object containing the parameters passed\n     to the function.\n     */\n    public var parameters: P\n    var log: AnyCodable?\n    var context: AnyCodable?\n\n    enum CodingKeys: String, CodingKey {\n        case masterKey = \"master\"\n        case parameters = \"params\"\n        case ipAddress = \"ip\"\n        case user, installationId,\n             headers, log, context\n    }\n}\n\nextension ParseHookFunctionRequest {\n\n    /**\n     Get the log using any type that conforms to `Codable`.\n     - returns: The sound casted to the inferred type.\n     - throws: An error of type `ParseError`.\n     */\n    public func getLog<V>() throws -> V where V: Codable {\n        guard let log = log?.value as? V else {\n            throw ParseError(code: .unknownError,\n                             message: \"Cannot be casted to the inferred type\")\n        }\n        return log\n    }\n\n    /**\n     Get the context using any type that conforms to `Codable`.\n     - returns: The sound casted to the inferred type.\n     - throws: An error of type `ParseError`.\n     */\n    public func getContext<V>() throws -> V where V: Codable {\n        guard let context = context?.value as? V else {\n            throw ParseError(code: .unknownError,\n                             message: \"Cannot be casted to the inferred type\")\n        }\n        return context\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseHookResponse.swift",
    "content": "//\n//  ParseHookResponseSuccess.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/14/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n Build a response after processing a `ParseHookFunctionRequest`\n or `ParseHookTriggerRequest`.\n */\npublic struct ParseHookResponse<R: Codable & Equatable>: ParseTypeable {\n    /// The data to return in the response.\n    public var success: R?\n    /// An object with a Parse code and message.\n    public var error: ParseError?\n/*\n    /// The text representing the error from the Parse Server.\n    public var message: String?\n    /// The value representing the error from the Parse Server.\n    public var code: ParseError.Code?\n    /// An error value representing a custom error from the Parse Server.\n    public var otherCode: Int? */\n    // var error: String?\n\n    enum CodingKeys: String, CodingKey {\n        case success, error\n    }\n}\n\n// MARK: Default Implementation\npublic extension ParseHookResponse {\n    /**\n     Create a successful response after processing a `ParseHookFunctionRequest`\n     or `ParseHookTriggerRequest`.\n     - parameter success: The data to return in the response.\n     */\n    init(success: R) {\n        self.success = success\n    }\n\n    /**\n     Create an error reponse to a `ParseHookFunctionRequest` or\n     `ParseHookTriggerRequest`  with a `ParseError`.\n     - parameter error: The `ParseError`.\n     */\n    init(error: ParseError) {\n        self.error = error\n        /* self.message = error.message\n        self.otherCode = error.otherCode */\n    }\n/*\n    /**\n     Create an error with a known code and custom message.\n     - parameter code: The known Parse code.\n     - parameter message: The custom message.\n     */\n    init(code: ParseError.Code, message: String) {\n        self.code = code\n        self.message = message\n    }\n\n    /**\n     Create an error with a custom code and custom message.\n     - parameter otherCode: The custom code.\n     - parameter message: The custom message.\n     */\n    init(otherCode: Int, message: String) {\n        self.code = .other\n        self.message = message\n        self.otherCode = otherCode\n    }\n\n    /**\n     Convert to `ParseError`.\n     - parameter otherCode: The custom code.\n     - returns: A `ParseError`.\n     - throws: An error of type `ParseError`.\n     */\n     func convertToParseError() throws -> ParseError {\n        guard let code = code,\n              let message = message else {\n            throw ParseError(code: .unknownError,\n                             message: \"Unable to convert to error; missing valid fields\")\n        }\n        return ParseError(code: code,\n                          message: message,\n                          otherCode: otherCode,\n                          error: error)\n    } */\n}\n\n// MARK: Encodable\npublic extension ParseHookResponse {\n    func encode(to encoder: Encoder) throws {\n        guard let success = success else {\n            var container = encoder.singleValueContainer()\n            try container.encode(error)\n            return\n        }\n        var container = encoder.container(keyedBy: CodingKeys.self)\n        try container.encode(success, forKey: .success)\n    }\n}\n\n// MARK: Decodable\npublic extension ParseHookResponse {\n\n    init(from decoder: Decoder) throws {\n        let values = try decoder.container(keyedBy: CodingKeys.self)\n        do {\n            self.success = try values.decode(R.self, forKey: .success)\n        } catch {\n            let errorValue = try decoder.singleValueContainer()\n            self.error = try errorValue.decode(ParseError.self)\n        }\n    }\n}\n\n// MARK: LocalizedError\nextension ParseHookResponse: LocalizedError {\n    public var errorDescription: String? {\n        debugDescription\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseHookTriggerRequest.swift",
    "content": "//\n//  ParseHookTriggerRequest.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/14/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n A type that can decode requests when `ParseHookTriggerable` triggers are called.\n - requires: `.useMasterKey` has to be available. It is recommended to only\n use the master key in server-side applications where the key is kept secure and not\n exposed to the public.\n */\npublic struct ParseHookTriggerRequest<U: ParseCloudUser, T: ParseObject>: ParseHookRequestable {\n    public typealias UserType = U\n    public var masterKey: Bool?\n    public var user: U?\n    public var installationId: String?\n    public var ipAddress: String?\n    public var headers: [String: String]?\n    /// An object from the hook call.\n    public var object: T?\n    /// The results the query yielded..\n    public var objects: [T]?\n    /// If set, the object, as currently stored.\n    public var original: T?\n    /// The query from the hook call.\n    public var query: Query<T>?\n    /// Whether the query a **get** or a **find**.\n    public var isGet: Bool?\n    /// The  from the hook call.\n    public var file: ParseFile?\n    /// The size of the file in bytes.\n    public var fileSize: Int?\n    /// The value from Content-Length header.\n    public var contentLength: Int?\n    /// The number of clients connected.\n    public var clients: Int?\n    /// The number of subscriptions connected.\n    public var subscriptions: Int?\n    /**\n     If the LiveQuery event should be sent to the client. Set to false to prevent\n     LiveQuery from pushing to the client.\n     */\n    public var sendEvent: Bool?\n    /// The live query event that triggered the request.\n    public var event: String?\n    var log: AnyCodable?\n    var context: AnyCodable?\n\n    enum CodingKeys: String, CodingKey {\n        case masterKey = \"master\"\n        case ipAddress = \"ip\"\n        case user, installationId, headers,\n             log, context, object, objects,\n             original, query, file, fileSize,\n             isGet, contentLength, clients,\n             subscriptions, sendEvent\n    }\n}\n\nextension ParseHookTriggerRequest {\n\n    /**\n     Get the Parse Server logger using any type that conforms to `Codable`.\n     - returns: The sound casted to the inferred type.\n     - throws: An error of type `ParseError`.\n     */\n    public func getLog<V>() throws -> V where V: Codable {\n        guard let log = log?.value as? V else {\n            throw ParseError(code: .unknownError,\n                             message: \"Cannot be casted to the inferred type\")\n        }\n        return log\n    }\n\n    /**\n     Get the context using any type that conforms to `Codable`.\n     - returns: The sound casted to the inferred type.\n     - throws: An error of type `ParseError`.\n     */\n    public func getContext<V>() throws -> V where V: Codable {\n        guard let context = context?.value as? V else {\n            throw ParseError(code: .unknownError,\n                             message: \"Cannot be casted to the inferred type\")\n        }\n        return context\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseKeychainAccessGroup.swift",
    "content": "//\n//  ParseKeychainAccessGroup.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 8/23/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if !os(Linux) && !os(Android) && !os(Windows)\nimport Foundation\n\nstruct ParseKeychainAccessGroup: ParseTypeable, Hashable {\n\n    var accessGroup: String?\n    var isSyncingKeychainAcrossDevices = false\n\n    static var current: Self? {\n        get {\n            guard let versionInMemory: Self =\n                try? ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentAccessGroup) else {\n                    guard let versionFromKeyChain: Self =\n                        try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentAccessGroup)\n                         else {\n                        return nil\n                    }\n                    return versionFromKeyChain\n            }\n            return versionInMemory\n        }\n        set {\n            guard let updatedKeychainAccessGroup = newValue else {\n                let defaultKeychainAccessGroup = Self()\n                try? ParseStorage.shared.set(defaultKeychainAccessGroup, for: ParseStorage.Keys.currentAccessGroup)\n                try? KeychainStore.shared.set(defaultKeychainAccessGroup, for: ParseStorage.Keys.currentAccessGroup)\n                Parse.configuration.keychainAccessGroup = defaultKeychainAccessGroup\n                return\n            }\n            try? ParseStorage.shared.set(updatedKeychainAccessGroup, for: ParseStorage.Keys.currentAccessGroup)\n            try? KeychainStore.shared.set(updatedKeychainAccessGroup, for: ParseStorage.Keys.currentAccessGroup)\n            Parse.configuration.keychainAccessGroup = updatedKeychainAccessGroup\n        }\n    }\n\n    static func deleteCurrentContainerFromKeychain() {\n        try? ParseStorage.shared.delete(valueFor: ParseStorage.Keys.currentAccessGroup)\n        try? KeychainStore.shared.delete(valueFor: ParseStorage.Keys.currentAccessGroup)\n        Parse.configuration.keychainAccessGroup = Self()\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseOperation+async.swift",
    "content": "//\n//  ParseOperation+async.swift\n//  ParseOperation+async\n//\n//  Created by Corey Baker on 8/6/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n\npublic extension ParseOperation {\n\n    // MARK: Async/Await\n\n    /**\n     Saves the operations on the `ParseObject` *asynchronously* and executes the given callback block.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A saved `ParseFile`.\n     - throws: An error of type `ParseError`.\n    */\n    @discardableResult func save(options: API.Options = []) async throws -> T {\n        try await withCheckedThrowingContinuation { continuation in\n            self.save(options: options,\n                      completion: continuation.resume)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseOperation+combine.swift",
    "content": "//\n//  ParseOperation+combine.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/29/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\npublic extension ParseOperation {\n\n    // MARK: Combine\n\n    /**\n     Saves the operations on the `ParseObject` *asynchronously*. Publishes when complete.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n    */\n    func savePublisher(options: API.Options = []) -> Future<T, ParseError> {\n        Future { promise in\n            self.save(options: options,\n                      completion: promise)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseOperation.swift",
    "content": "//\n//  ParseOperation.swift\n//  Parse\n//\n//  Created by Florent Vilmart on 17-07-24.\n//  Copyright © 2017 Parse. All rights reserved.\n//\n\nimport Foundation\n\n/**\n A `ParseOperation` represents a modification to a value in a `ParseObject`.\n For example, setting, deleting, or incrementing a value are all `ParseOperation`'s.\n `ParseOperation` themselves can be considered to be immutable.\n \n In most cases, you do not need to create an instance of `ParseOperation` directly as it can be\n indirectly created from any `ParseObject` by using the respective `operation` property.\n */\npublic struct ParseOperation<T>: Savable where T: ParseObject {\n\n    var target: T\n    var operations = [String: Encodable]()\n    var keysToNull = Set<String>()\n\n    public init(target: T) {\n        self.target = target\n    }\n\n    /**\n     An operation that sets a field's value.\n     - Parameters:\n        - keyPath: The respective `KeyPath` of the object.\n        - value: The value to set the `KeyPath` to.\n        - returns: The updated operations.\n     - warning: Do not combine operations using this method with other operations that\n     do not use this method to **set** all operations. If you need to combine multiple types\n     of operations such as: add, increment, forceSet, etc., use\n     `func set<W>(_ key: (String, WritableKeyPath<T, W?>), value: W?)`\n     instead.\n     */\n    @available(*, deprecated, message: \"Replace \\\"value\\\" with \\\"to\\\"\")\n    public func set<W>(_ keyPath: WritableKeyPath<T, W?>,\n                       value: W) throws -> Self where W: Encodable & Equatable {\n        try set(keyPath, to: value)\n    }\n\n    /**\n     An operation that sets a field's value.\n     - Parameters:\n        - keyPath: The respective `KeyPath` of the object.\n        - value: The value to set the `KeyPath` to.\n        - returns: The updated operations.\n     - warning: Do not combine operations using this method with other operations that\n     do not use this method to **set** all operations. If you need to combine multiple types\n     of operations such as: add, increment, forceSet, etc., use\n     `func set<W>(_ key: (String, WritableKeyPath<T, W?>), value: W?)`\n     instead.\n     */\n    public func set<W>(_ keyPath: WritableKeyPath<T, W?>,\n                       to value: W) throws -> Self where W: Encodable & Equatable {\n        guard operations.isEmpty,\n              keysToNull.isEmpty else {\n            throw ParseError(code: .unknownError,\n                             message: \"\"\"\n                                Cannot combine other operations such as: add, increment,\n                                forceSet, etc., with this method. Use the \\\"set\\\" method that takes\n                                the (String, WritableKeyPath) tuple as an argument instead to\n                                combine multiple types of operations.\n                                \"\"\")\n        }\n        var mutableOperation = self\n        mutableOperation.target = mutableOperation.target.set(keyPath, to: value)\n        return mutableOperation\n    }\n\n    /**\n     An operation that sets a field's value if it has changed from its previous value.\n     - Parameters:\n        - key: A tuple consisting of the key and the respective `KeyPath` of the object.\n        - value: The value to set the `KeyPath` to.\n        - returns: The updated operations.\n     - Note: Set the value to \"nil\" if you want it to be \"null\" on the Parse Server.\n     */\n    @available(*, deprecated, message: \"Replace \\\"value\\\" with \\\"to\\\"\")\n    public func set<W>(_ key: (String, WritableKeyPath<T, W?>),\n                       value: W?) -> Self where W: Encodable & Equatable {\n        set(key, to: value)\n    }\n\n    /**\n     An operation that sets a field's value if it has changed from its previous value.\n     - Parameters:\n        - key: A tuple consisting of the key and the respective `KeyPath` of the object.\n        - value: The value to set the `KeyPath` to.\n        - returns: The updated operations.\n     - Note: Set the value to \"nil\" if you want it to be \"null\" on the Parse Server.\n     */\n    public func set<W>(_ key: (String, WritableKeyPath<T, W?>),\n                       to value: W?) -> Self where W: Encodable & Equatable {\n        var mutableOperation = self\n        if value == nil && target[keyPath: key.1] != nil {\n            mutableOperation.keysToNull.insert(key.0)\n            mutableOperation.target[keyPath: key.1] = value\n        } else if target[keyPath: key.1] != value {\n            mutableOperation.operations[key.0] = value\n            mutableOperation.target[keyPath: key.1] = value\n        }\n        return mutableOperation\n    }\n\n    /**\n     An operation that force sets a field's value.\n     - Parameters:\n        - key: A tuple consisting of the key and the respective `KeyPath` of the object.\n        - value: The value to set the `KeyPath` to.\n        - returns: The updated operations.\n     - Note: Set the value to \"nil\" if you want it to be \"null\" on the Parse Server.\n     */\n    public func forceSet<W>(_ key: (String, WritableKeyPath<T, W?>),\n                            value: W?) -> Self where W: Encodable {\n        forceSet(key, to: value)\n    }\n\n    /**\n     An operation that force sets a field's value.\n     - Parameters:\n        - key: A tuple consisting of the key and the respective `KeyPath` of the object.\n        - value: The value to set the `KeyPath` to.\n        - returns: The updated operations.\n     - Note: Set the value to \"nil\" if you want it to be \"null\" on the Parse Server.\n     */\n    public func forceSet<W>(_ key: (String, WritableKeyPath<T, W?>),\n                            to value: W?) -> Self where W: Encodable {\n        var mutableOperation = self\n        if value != nil {\n            mutableOperation.operations[key.0] = value\n        } else {\n            mutableOperation.keysToNull.insert(key.0)\n        }\n        mutableOperation.target[keyPath: key.1] = value\n        return mutableOperation\n    }\n\n    /**\n     An operation that increases a numeric field's value by a given amount.\n     - Parameters:\n        - key: The key of the object.\n        - amount: How much to increment by.\n        - returns: The updated operations.\n     */\n    public func increment(_ key: String, by amount: Int) -> Self {\n        var mutableOperation = self\n        mutableOperation.operations[key] = Increment(amount: amount)\n        return mutableOperation\n    }\n\n    /**\n     An operation that adds a new element to an array field,\n     only if it was not already present.\n     - Parameters:\n        - key: The key of the object.\n        - objects: The field of objects.\n        - returns: The updated operations.\n     */\n    public func addUnique<W>(_ key: String, objects: [W]) -> Self where W: Encodable, W: Hashable {\n        var mutableOperation = self\n        mutableOperation.operations[key] = AddUnique(objects: objects)\n        return mutableOperation\n    }\n\n    /**\n     An operation that adds a new element to an array field,\n     only if it was not already present.\n     - Parameters:\n        - key: A tuple consisting of the key and the respective `KeyPath` of the object.\n        - objects: The field of objects.\n        - returns: The updated operations.\n     */\n    @available(*, deprecated,\n                message: \"\"\"\n                    The KeyPath of a ParseObject should always point to an optional value.\n                    This means that all properties of your ParseObject's should be optional.\n                    Please read the important notes and warnings in the documentation for\n                    details.\n                \"\"\")\n    public func addUnique<V>(_ key: (String, WritableKeyPath<T, [V]>),\n                             objects: [V]) -> Self where V: Encodable, V: Hashable {\n        var mutableOperation = self\n        mutableOperation.operations[key.0] = AddUnique(objects: objects)\n        var values = target[keyPath: key.1]\n        values.append(contentsOf: objects)\n        mutableOperation.target[keyPath: key.1] = Array(Set<V>(values))\n        return mutableOperation\n    }\n\n    /**\n     An operation that adds a new element to an array field,\n     only if it was not already present.\n     - Parameters:\n        - key: A tuple consisting of the key and the respective `KeyPath` of the object.\n        - objects: The field of objects.\n        - returns: The updated operations.\n     */\n    public func addUnique<V>(_ key: (String, WritableKeyPath<T, [V]?>),\n                             objects: [V]) -> Self where V: Encodable, V: Hashable {\n        var mutableOperation = self\n        mutableOperation.operations[key.0] = AddUnique(objects: objects)\n        var values = target[keyPath: key.1] ?? []\n        values.append(contentsOf: objects)\n        mutableOperation.target[keyPath: key.1] = Array(Set<V>(values))\n        return mutableOperation\n    }\n\n    /**\n     An operation that adds a new element to an array field.\n     - Parameters:\n        - key: The key of the object.\n        - objects: The field of objects.\n        - returns: The updated operations.\n     */\n    public func add<W>(_ key: String, objects: [W]) -> Self where W: Encodable {\n        var mutableOperation = self\n        mutableOperation.operations[key] = Add(objects: objects)\n        return mutableOperation\n    }\n\n    /**\n     An operation that adds a new element to an array field.\n     - Parameters:\n        - key: A tuple consisting of the key and the respective `KeyPath` of the object.\n        - objects: The field of objects.\n        - returns: The updated operations.\n     */\n    @available(*, deprecated,\n                message: \"\"\"\n                    The KeyPath of a ParseObject should always point to an optional value.\n                    This means that all properties of your ParseObject's should be optional.\n                    Please read the important notes and warnings in the documentation for\n                    details.\n                \"\"\")\n    public func add<V>(_ key: (String, WritableKeyPath<T, [V]>),\n                       objects: [V]) -> Self where V: Encodable {\n        var mutableOperation = self\n        mutableOperation.operations[key.0] = Add(objects: objects)\n        var values = target[keyPath: key.1]\n        values.append(contentsOf: objects)\n        mutableOperation.target[keyPath: key.1] = values\n        return mutableOperation\n    }\n\n    /**\n     An operation that adds a new element to an array field.\n     - Parameters:\n        - key: A tuple consisting of the key and the respective `KeyPath` of the object.\n        - objects: The field of objects.\n        - returns: The updated operations.\n     */\n    public func add<V>(_ key: (String, WritableKeyPath<T, [V]?>),\n                       objects: [V]) -> Self where V: Encodable {\n        var mutableOperation = self\n        mutableOperation.operations[key.0] = Add(objects: objects)\n        var values = target[keyPath: key.1] ?? []\n        values.append(contentsOf: objects)\n        mutableOperation.target[keyPath: key.1] = values\n        return mutableOperation\n    }\n\n    /**\n     An operation that adds a new relation to an array field.\n     - Parameters:\n        - key: The key of the object.\n        - objects: The field of objects.\n        - returns: The updated operations.\n     */\n    public func addRelation<W>(_ key: String, objects: [W]) throws -> Self where W: ParseObject {\n        var mutableOperation = self\n        mutableOperation.operations[key] = try AddRelation(objects: objects)\n        return mutableOperation\n    }\n\n    /**\n     An operation that adds a new relation to an array field.\n     - Parameters:\n        - key: A tuple consisting of the key and the respective `KeyPath` of the object.\n        - objects: The field of objects.\n        - returns: The updated operations.\n     */\n    @available(*, deprecated,\n                message: \"\"\"\n                    The KeyPath of a ParseObject should always point to an optional value.\n                    This means that all properties of your ParseObject's should be optional.\n                    Please read the important notes and warnings in the documentation for\n                    details.\n                \"\"\")\n    public func addRelation<V>(_ key: (String, WritableKeyPath<T, [V]>),\n                               objects: [V]) throws -> Self where V: ParseObject {\n        var mutableOperation = self\n        mutableOperation.operations[key.0] = try AddRelation(objects: objects)\n        var values = target[keyPath: key.1]\n        values.append(contentsOf: objects)\n        mutableOperation.target[keyPath: key.1] = values\n        return mutableOperation\n    }\n\n    /**\n     An operation that adds a new relation to an array field.\n     - Parameters:\n        - key: A tuple consisting of the key and the respective `KeyPath` of the object.\n        - objects: The field of objects.\n        - returns: The updated operations.\n     */\n    public func addRelation<V>(_ key: (String, WritableKeyPath<T, [V]?>),\n                               objects: [V]) throws -> Self where V: ParseObject {\n        var mutableOperation = self\n        mutableOperation.operations[key.0] = try AddRelation(objects: objects)\n        var values = target[keyPath: key.1] ?? []\n        values.append(contentsOf: objects)\n        mutableOperation.target[keyPath: key.1] = values\n        return mutableOperation\n    }\n\n    /**\n     An operation that removes every instance of an element from\n     an array field.\n     - Parameters:\n        - key: The key of the object.\n        - objects: The field of objects.\n        - returns: The updated operations.\n     */\n    public func remove<W>(_ key: String, objects: [W]) -> Self where W: Encodable {\n        var mutableOperation = self\n        mutableOperation.operations[key] = Remove(objects: objects)\n        return mutableOperation\n    }\n\n    /**\n     An operation that removes every instance of an element from\n     an array field.\n     - Parameters:\n        - key: A tuple consisting of the key and the respective `KeyPath` of the object.\n        - objects: The field of objects.\n        - returns: The updated operations.\n     */\n    @available(*, deprecated,\n                message: \"\"\"\n                    The KeyPath of a ParseObject should always point to an optional value.\n                    This means that all properties of your ParseObject's should be optional.\n                    Please read the important notes and warnings in the documentation for\n                    details.\n                \"\"\")\n    public func remove<V>(_ key: (String, WritableKeyPath<T, [V]>),\n                          objects: [V]) -> Self where V: Encodable, V: Hashable {\n        var mutableOperation = self\n        mutableOperation.operations[key.0] = Remove(objects: objects)\n        let values = target[keyPath: key.1]\n        var set = Set<V>(values)\n        objects.forEach {\n            set.remove($0)\n        }\n        mutableOperation.target[keyPath: key.1] = Array(set)\n        return mutableOperation\n    }\n\n    /**\n     An operation that removes every instance of an element from\n     an array field.\n     - Parameters:\n        - key: A tuple consisting of the key and the respective `KeyPath` of the object.\n        - objects: The field of objects.\n        - returns: The updated operations.\n     */\n    public func remove<V>(_ key: (String, WritableKeyPath<T, [V]?>),\n                          objects: [V]) -> Self where V: Encodable, V: Hashable {\n        var mutableOperation = self\n        mutableOperation.operations[key.0] = Remove(objects: objects)\n        let values = target[keyPath: key.1]\n        var set = Set<V>(values ?? [])\n        objects.forEach {\n            set.remove($0)\n        }\n        mutableOperation.target[keyPath: key.1] = Array(set)\n        return mutableOperation\n    }\n\n    /**\n     An operation that removes every instance of a relation from\n     an array field.\n     - Parameters:\n        - key: The key of the object.\n        - objects: The field of objects.\n        - returns: The updated operations.\n     */\n    public func removeRelation<W>(_ key: String, objects: [W]) throws -> Self where W: ParseObject {\n        var mutableOperation = self\n        mutableOperation.operations[key] = try RemoveRelation(objects: objects)\n        return mutableOperation\n    }\n\n    /**\n     An operation that removes every instance of a relation from\n     an array field.\n     - Parameters:\n        - key: A tuple consisting of the key and the respective `KeyPath` of the object.\n        - objects: The field of objects.\n        - returns: The updated operations.\n     */\n    @available(*, deprecated,\n                message: \"\"\"\n                    The KeyPath of a ParseObject should always point to an optional value.\n                    This means that all properties of your ParseObject's should be optional.\n                    Please read the important notes and warnings in the documentation for\n                    details.\n                \"\"\")\n    public func removeRelation<V>(_ key: (String, WritableKeyPath<T, [V]>),\n                                  objects: [V]) throws -> Self where V: ParseObject {\n        var mutableOperation = self\n        mutableOperation.operations[key.0] = try RemoveRelation(objects: objects)\n        let values = target[keyPath: key.1]\n        var set = Set<V>(values)\n        objects.forEach {\n            set.remove($0)\n        }\n        mutableOperation.target[keyPath: key.1] = Array(set)\n        return mutableOperation\n    }\n\n    /**\n     An operation that removes every instance of a relation from\n     an array field.\n     - Parameters:\n        - key: A tuple consisting of the key and the respective `KeyPath` of the object.\n        - objects: The field of objects.\n        - returns: The updated operations.\n     */\n    public func removeRelation<V>(_ key: (String, WritableKeyPath<T, [V]?>),\n                                  objects: [V]) throws -> Self where V: ParseObject {\n        var mutableOperation = self\n        mutableOperation.operations[key.0] = try RemoveRelation(objects: objects)\n        let values = target[keyPath: key.1]\n        var set = Set<V>(values ?? [])\n        objects.forEach {\n            set.remove($0)\n        }\n        mutableOperation.target[keyPath: key.1] = Array(set)\n        return mutableOperation\n    }\n\n    /**\n     An operation where a field is deleted from the object.\n     - parameter key: The key of the object.\n     - returns: The updated operations.\n     */\n    public func unset(_ key: String) -> Self {\n        var mutableOperation = self\n        mutableOperation.operations[key] = Delete()\n        return mutableOperation\n    }\n\n    /**\n     An operation where a field is deleted from the object.\n     - Parameters:\n        - key: A tuple consisting of the key and the respective `KeyPath` of the object.\n        - returns: The updated operations.\n     */\n    public func unset<V>(_ key: (String, WritableKeyPath<T, V?>)) -> Self where V: Encodable {\n        var mutableOperation = self\n        mutableOperation.operations[key.0] = Delete()\n        mutableOperation.target[keyPath: key.1] = nil\n        return mutableOperation\n    }\n\n    public func encode(to encoder: Encoder) throws {\n        var container = encoder.container(keyedBy: RawCodingKey.self)\n        try operations.forEach { key, value in\n            let encoder = container.superEncoder(forKey: .key(key))\n            try value.encode(to: encoder)\n        }\n        try keysToNull.forEach { key in\n            let encoder = container.superEncoder(forKey: .key(key))\n            var container = encoder.singleValueContainer()\n            try container.encodeNil()\n        }\n    }\n}\n\n// MARK: Savable\nextension ParseOperation {\n    /**\n     Saves the operations on the `ParseObject` *synchronously* and throws an error if there is an issue.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - throws: An error of type `ParseError`.\n     - returns: Returns saved `ParseObject`.\n    */\n    @discardableResult public func save(options: API.Options = []) throws -> T {\n        guard target.objectId != nil else {\n            throw ParseError(code: .missingObjectId,\n                             message: \"ParseObject is not saved.\")\n        }\n        guard target.originalData == nil else {\n            guard operations.isEmpty,\n                  keysToNull.isEmpty else {\n                throw ParseError(code: .unknownError,\n                                 message: \"\"\"\n                                    Cannot combine operations with the \\\"set\\\" method that uses\n                                    just the KeyPath with other operations such as: add, increment,\n                                    forceSet, etc., that use the KeyPath and/or key String. Use the\n                                    \\\"set\\\" method that takes the (String, WritableKeyPath) tuple\n                                    as an argument instead to combine multiple types of operations.\n                                    \"\"\")\n            }\n            return try target.save(options: options)\n        }\n        return try saveCommand()\n            .execute(options: options)\n    }\n\n    /**\n     Saves the operations on the `ParseObject` *asynchronously* and executes the given callback block.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n     - parameter completion: The block to execute.\n     It should have the following argument signature: `(Result<T, ParseError>)`.\n    */\n    public func save(\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<T, ParseError>) -> Void\n    ) {\n        guard target.objectId != nil else {\n            let error = ParseError(code: .missingObjectId,\n                                   message: \"ParseObject is not saved.\")\n            callbackQueue.async {\n                completion(.failure(error))\n            }\n            return\n        }\n        guard target.originalData == nil else {\n            guard operations.isEmpty,\n                  keysToNull.isEmpty else {\n                let error = ParseError(code: .unknownError,\n                                       message: \"\"\"\n                                            Cannot combine operations with the \\\"set\\\" method that uses\n                                            just the KeyPath with other operations such as: add, increment,\n                                            forceSet, etc., that use the KeyPath and/or key String. Use the\n                                            \\\"set\\\" method that takes the (String, WritableKeyPath) tuple\n                                            as an argument instead to combine multiple types of operations.\n                                        \"\"\")\n                callbackQueue.async {\n                    completion(.failure(error))\n                }\n                return\n            }\n            target.save(options: options,\n                        callbackQueue: callbackQueue,\n                        completion: completion)\n            return\n        }\n        self.saveCommand().executeAsync(options: options,\n                                        callbackQueue: callbackQueue,\n                                        completion: completion)\n    }\n\n    func saveCommand() -> API.NonParseBodyCommand<ParseOperation<T>, T> {\n        // MARK: Should be switched to \".PATCH\" when server supports PATCH.\n        API.NonParseBodyCommand(method: .PUT, path: target.endpoint, body: self) {\n            try ParseCoding.jsonDecoder().decode(UpdateResponse.self, from: $0).apply(to: self.target)\n        }\n    }\n}\n\n// MARK: ParseOperation\npublic extension ParseObject {\n\n    /// Create a new operation.\n    var operation: ParseOperation<Self> {\n        return ParseOperation(target: self)\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParsePolygon.swift",
    "content": "//\n//  ParsePolygon.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 7/9/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n/**\n `ParsePolygon` is used to create a polygon that represents the coordinates\n that may be associated with a key in a ParseObject or used as a reference point\n for geo queries. This allows proximity-based queries on the key.\n*/\npublic struct ParsePolygon: ParseTypeable, Hashable {\n    private let __type: String = \"Polygon\" // swiftlint:disable:this identifier_name\n    public let coordinates: [ParseGeoPoint]\n\n    enum CodingKeys: String, CodingKey {\n        case __type // swiftlint:disable:this identifier_name\n        case coordinates\n    }\n\n    /**\n      Create new `ParsePolygon` instance with coordinates.\n       - parameter coordinates: An array of geopoints that make the polygon.\n       - throws: An error of type `ParseError`.\n     */\n    public init(_ coordinates: [ParseGeoPoint]) throws {\n        self.coordinates = coordinates\n        try validate()\n    }\n\n    /**\n      Create new `ParsePolygon` instance with a variadic amount of coordinates.\n       - parameter coordinates: variadic amount of zero or more `ParseGeoPoint`'s.\n       - throws: An error of type `ParseError`.\n     */\n    public init(_ coordinates: ParseGeoPoint...) throws {\n        try self.init(coordinates)\n    }\n\n    func validate() throws {\n        if coordinates.count < 3 {\n            throw ParseError(code: .unknownError,\n                             message: \"Polygon must have at least 3 ParseGeoPoint's or Points\")\n        }\n    }\n\n    /**\n      Determines if a `ParsePolygon` containes a point.\n       - parameter point: The point to check.\n     */\n    public func containsPoint(_ point: ParseGeoPoint) -> Bool {\n        var minX = coordinates[0].latitude\n        var maxX = coordinates[0].latitude\n        var minY = coordinates[0].longitude\n        var maxY = coordinates[0].longitude\n\n        var modifiedCoordinates = coordinates\n        modifiedCoordinates.removeFirst()\n        for coordinate in modifiedCoordinates {\n            minX = Swift.min(coordinate.latitude, minX)\n            maxX = Swift.max(coordinate.latitude, maxX)\n            minY = Swift.min(coordinate.longitude, minY)\n            maxY = Swift.max(coordinate.longitude, maxY)\n        }\n\n        // Check if outside of the polygon\n        if point.latitude < minX ||\n            point.latitude > maxX ||\n            point.longitude < minY ||\n            point.longitude > maxY {\n            return false\n        }\n\n        modifiedCoordinates = coordinates\n\n        // Check if intersects polygon\n        var otherIndex = coordinates.count - 1\n        for (index, coordinate) in coordinates.enumerated() {\n            let startX = coordinate.latitude\n            let startY = coordinate.longitude\n            let endX = coordinates[otherIndex].latitude\n            let endY = coordinates[otherIndex].longitude\n            let startYComparison = startY > point.longitude\n            let endYComparison = endY > point.longitude\n            if startYComparison != endYComparison &&\n                point.latitude < ((endX - startX) * (point.longitude - startY)) / (endY - startY) + startX {\n                return true\n            }\n            if index == 0 {\n                otherIndex = index\n            } else {\n                otherIndex += 1\n            }\n        }\n        return false\n    }\n}\n\nextension ParsePolygon {\n    public init(from decoder: Decoder) throws {\n        let values = try decoder.container(keyedBy: CodingKeys.self)\n        var decodedCoordinates = [ParseGeoPoint]()\n        let points = try values.decode([[Double]].self, forKey: .coordinates)\n        try points.forEach {\n            if $0.count == 2 {\n                guard let latitude = $0.last,\n                      let longitude = $0.first else {\n                    throw ParseError(code: .unknownError, message: \"Could not decode ParsePolygon: \\(points)\")\n                }\n                decodedCoordinates.append(try ParseGeoPoint(latitude: latitude,\n                                                 longitude: longitude))\n            } else {\n                throw ParseError(code: .unknownError, message: \"Could not decode ParsePolygon: \\(points)\")\n            }\n        }\n        coordinates = decodedCoordinates\n        try validate()\n    }\n\n    public func encode(to encoder: Encoder) throws {\n        try validate()\n        var container = encoder.container(keyedBy: CodingKeys.self)\n        try container.encode(__type, forKey: .__type)\n        var nestedUnkeyedContainer = container.nestedUnkeyedContainer(forKey: .coordinates)\n        try coordinates.forEach {\n            try nestedUnkeyedContainer.encode([$0.longitude, $0.latitude])\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParsePush+async.swift",
    "content": "//\n//  ParsePush+async.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/5/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n\npublic extension ParsePush {\n    /**\n     Sends the `ParsePush` *aynchronously* to the server.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the `ParsePushStatus` `objectId`.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n    */\n    func send(options: API.Options = []) async throws -> String {\n        try await withCheckedThrowingContinuation { continuation in\n            self.send(options: options,\n                      completion: continuation.resume)\n        }\n    }\n\n    /**\n     Fetches the `ParsePushStatus` *aynchronously* from the server.\n     - parameter statusId: The `objectId` of the `ParsePushStatus`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the fetched `ParsePushStatus`.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n    */\n    func fetchStatus(_ statusId: String,\n                     options: API.Options = []) async throws -> ParsePushStatus<V> {\n        try await withCheckedThrowingContinuation { continuation in\n            self.fetchStatus(statusId,\n                             options: options,\n                             completion: continuation.resume)\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParsePush+combine.swift",
    "content": "//\n//  ParsePush+combine.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/5/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\npublic extension ParsePush {\n    /**\n     Sends a Parse push notification *aynchronously*. Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n    */\n    func sendPublisher(options: API.Options = []) -> Future<String, ParseError> {\n        Future { promise in\n            self.send(options: options,\n                      completion: promise)\n        }\n    }\n\n    /**\n     Fetches the `ParsePushStatus` *aynchronously* from the server. Publishes when complete.\n     - parameter statusId: The `objectId` of the `ParsePushStatus`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n    */\n    func fetchStatusPublisher(_ statusId: String,\n                              options: API.Options = []) -> Future<ParsePushStatus<V>, ParseError> {\n        Future { promise in\n            self.fetchStatus(statusId,\n                             options: options,\n                             completion: promise)\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParsePush.swift",
    "content": "//\n//  ParsePush.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/4/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n Send and check the status of push notificaitons.\n - requires: `.useMasterKey` has to be available. It is recommended to only\n use the master key in server-side applications where the key is kept secure and not\n exposed to the public.\n */\npublic struct ParsePush<V: ParsePushPayloadable>: ParseTypeable {\n    /**\n     The query that determines what installations should receive the notification.\n     - warning: Cannot send a notification with this valuel and `channels` both set.\n     */\n    public var `where`: QueryWhere?\n    /**\n     An Array of channels to push to.\n     - warning: Cannot send a notification with this valuel and `where` both set.\n     */\n    public var channels: Set<String>?\n    /// The payload to send.\n    public var payload: V?\n    /// When to send the notification.\n    public var pushTime: Date?\n    /**\n     The UNIX timestamp when the notification should expire.\n     If the notification cannot be delivered to the device, will retry until it expires.\n     An expiry of **0** indicates that the notification expires immediately, therefore\n     no retries will be attempted.\n     - note: This should not be set directly using a **Date** type. Instead it should\n     be set using `expirationDate`.\n     - warning: Cannot send a notification with this valuel and `expirationInterval` both set.\n     */\n    var expirationTime: TimeInterval?\n\n    /**\n     The date when the notification should expire.\n     If the notification cannot be delivered to the device, will retry until it expires.\n     - note: This takes any date and turns it into a UNIX timestamp and sets the\n     value of `expirationTime`.\n     - warning: Cannot send a notification with this valuel and `expirationInterval` both set.\n     */\n    var expirationDate: Date? {\n        get {\n            guard let interval = expirationTime else {\n                return nil\n            }\n            return Date(timeIntervalSince1970: interval)\n        }\n        set {\n            expirationTime = newValue?.timeIntervalSince1970\n        }\n    }\n    /**\n     The seconds from now to expire the notification.\n     - warning: Cannot send a notification with this valuel and `expirationTime` both set.\n     */\n    public var expirationInterval: Int?\n\n    enum CodingKeys: String, CodingKey {\n        case pushTime = \"push_time\"\n        case expirationTime = \"expiration_time\"\n        case expirationInterval = \"expiration_interval\"\n        case payload = \"data\"\n        case `where`, channels\n    }\n\n    /**\n     Create an instance of  `ParsePush` with a given expiration date.\n     - parameter payload: The payload information to send.\n     - parameter pushTime: When to send the notification.  Defaults to **nil**.\n     - parameter expirationDate: The date to expire the notification. Defaults to **nil**.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n     - warning: `expirationTime` and `expirationInterval` cannot be set at the same time.\n    */\n    public init(payload: V,\n                pushTime: Date? = nil,\n                expirationDate: Date? = nil) {\n        self.payload = payload\n        self.pushTime = pushTime\n        self.expirationDate = expirationDate\n    }\n\n    /**\n     Create an instance of  `ParsePush` that expires after a given amount of seconds.\n     - parameter payload: The payload information to send.\n     - parameter pushTime: When to send the notification.  Defaults to **nil**.\n     - parameter expirationInterval: How many seconds to expire the notification after now.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n     - warning: `expirationTime` and `expirationInterval` cannot be set at the same time.\n    */\n    public init(payload: V,\n                pushTime: Date? = nil,\n                expirationInterval: Int?) {\n        self.payload = payload\n        self.pushTime = pushTime\n        self.expirationInterval = expirationInterval\n    }\n\n    /**\n     Create an instance of  `ParsePush` with a given expiration date.\n     - parameter payload: The payload information to send.\n     - parameter query: The query that determines what installations should receive the notification.\n     Defaults to **nil**.\n     - parameter pushTime: When to send the notification.  Defaults to **nil**.\n     - parameter expirationDate: The date to expire the notification. Defaults to **nil**.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n     - warning: `expirationTime` and `expirationInterval` cannot be set at the same time.\n    */\n    public init<U>(payload: V,\n                   query: Query<U>,\n                   pushTime: Date? = nil,\n                   expirationDate: Date? = nil) where U: ParseInstallation {\n        self.payload = payload\n        self.`where` = query.`where`\n        self.pushTime = pushTime\n        self.expirationDate = expirationDate\n    }\n\n    /**\n     Create an instance of  `ParsePush` that expires after a given amount of seconds.\n     - parameter payload: The payload information to send.\n     - parameter query: The query that determines what installations should receive the notification.\n     Defaults to **nil**.\n     - parameter pushTime: When to send the notification.  Defaults to **nil**.\n     - parameter expirationInterval: How many seconds to expire the notification after now.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n     - warning: `expirationTime` and `expirationInterval` cannot be set at the same time.\n    */\n    public init<U>(payload: V,\n                   query: Query<U>,\n                   pushTime: Date? = nil,\n                   expirationInterval: Int?) where U: ParseInstallation {\n        self.payload = payload\n        self.`where` = query.`where`\n        self.pushTime = pushTime\n        self.expirationInterval = expirationInterval\n    }\n}\n\n// MARK: Sendable\nextension ParsePush {\n\n    /**\n     Sends the  `ParsePush` *asynchronously* from the server and executes the given callback block.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n     - warning: expirationTime and expirationInterval cannot be set at the same time.\n    */\n    public func send(options: API.Options = [],\n                     callbackQueue: DispatchQueue = .main,\n                     completion: @escaping (Result<String, ParseError>) -> Void) {\n        if expirationTime != nil && expirationInterval != nil {\n            let error =  ParseError(code: .unknownError,\n                                    message: \"expirationTime and expirationInterval cannot both be set.\")\n            completion(.failure(error))\n            return\n        }\n        if `where` != nil && channels != nil {\n            let error =  ParseError(code: .unknownError,\n                                    message: \"query and channels cannot both be set.\")\n            completion(.failure(error))\n            return\n        }\n        var options = options\n        options.insert(.useMasterKey)\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        sendCommand()\n            .executeAsync(options: options,\n                          callbackQueue: callbackQueue,\n                          completion: completion)\n    }\n\n    func sendCommand() -> API.NonParseBodyCommand<Self, String> {\n\n        return API.NonParseBodyCommand(method: .POST,\n                                       path: .push,\n                                       body: self) { (data) -> String in\n            guard let response = try? ParseCoding.jsonDecoder().decode(PushResponse.self, from: data) else {\n                throw ParseError(code: .unknownError,\n                                 message: \"The server is missing \\\"X-Parse-Push-Status-Id\\\" in its header response\")\n            }\n            guard let success = try? ParseCoding.jsonDecoder().decode(BooleanResponse.self,\n                                                                      from: response.data).result else {\n                throw ParseError(code: .unknownError, message: \"The server did not resturn a Boolean response\")\n            }\n            if success {\n                return response.statusId\n            } else {\n                throw ParseError(code: .unknownError, message: \"Push was unsuccessful\")\n            }\n        }\n    }\n}\n\n// MARK: Fetchable\npublic extension ParsePush {\n    /**\n     Fetches the  `ParsePushStatus` by `objectId` *asynchronously* from the server and\n     executes the given callback block.\n     - parameter statusId: The `objectId` of the `ParsePushStatus`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n    */\n    func fetchStatus(_ statusId: String,\n                     options: API.Options = [],\n                     callbackQueue: DispatchQueue = .main,\n                     completion: @escaping (Result<ParsePushStatus<V>, ParseError>) -> Void) {\n        var options = options\n        options.insert(.useMasterKey)\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        let query = ParsePushStatus<V>.query(\"objectId\" == statusId)\n        query.first(options: options, completion: completion)\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParsePushPayload/Apple/ParsePushAppleAlert.swift",
    "content": "//\n//  ParsePushAppleAlert.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/5/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n// swiftlint:disable line_length\n\n/**\n An alert payload for Apple push notifications. See Apple's [documentation](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification#2943365)\n for more information.\n */\npublic struct ParsePushAppleAlert: ParseTypeable {\n    /**\n     The content of the alert message.\n     */\n    public var body: String?\n    /**\n     The name of the launch image file to display. If the user chooses to\n     launch your app, the contents of the specified image or storyboard file\n     are displayed instead of your app’s normal launch image.\n     */\n    public var launchImage: String?\n    /**\n     The key for a localized message string. Use this key, instead of the body\n     key, to retrieve the message text from your app’s Localizable.strings file.\n     The value must contain the name of a key in your strings file.\n     */\n    public var locKey: String?\n    /**\n     An array of strings containing replacement values for variables in your\n     message text. Each %@ character in the string specified by loc-key is\n     replaced by a value from this array. The first item in the array replaces\n     the first instance of the %@ character in the string, the second item\n     replaces the second instance, and so on.\n     */\n    public var locArgs: [String]?\n    /**\n     The title of the notification. Apple Watch displays this string in the short\n     look notification interface. Specify a string that’s quickly understood by the user.\n     */\n    public var title: String?\n    /**\n     The key for a localized title string. Specify this key instead of the title key to\n     retrieve the title from your app’s Localizable.strings files. The value must\n     contain the name of a key in your strings file.\n     */\n    public var titleLocKey: String?\n    /**\n     An array of strings containing replacement values for variables in your title string.\n     Each %@ character in the string specified by the title-loc-key is replaced by a\n     value from this array. The first item in the array replaces the first instance of the\n     %@ character in the string, the second item replaces the second instance, and so on.\n     */\n    public var titleLocArgs: [String]?\n    /**\n     Additional information that explains the purpose of the notification.\n     */\n    public var subtitle: String?\n    /**\n     The key for a localized subtitle string. Use this key, instead of the subtitle key, to\n     retrieve the subtitle from your app’s Localizable.strings file. The value must contain\n     the name of a key in your strings file.\n     */\n    public var subtitleLocKey: String?\n    /**\n     An array of strings containing replacement values for variables in your title string.\n     Each %@ character in the string specified by subtitle-loc-key is replaced by a value\n     from this array. The first item in the array replaces the first instance of the %@\n     character in the string, the second item replaces the second instance, and so on.\n     */\n    public var subtitleLocArgs: [String]?\n    public var action: String?\n    /**\n     If a string is specified, the system displays an alert that includes the Close and\n     View buttons. The string is used as a key to get a localized string in the current\n     localization to use for the right button’s title instead of “View”. See [Localizing the\n     Content of Your Remote Notifications](https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html#//apple_ref/doc/uid/TP40008194-CH10-SW9) for more information.\n     */\n    public var actionLocKey: String?\n\n    /// Create an empty alert.\n    public init() { }\n\n    /// Create an alert with a body message.\n    /// - parameter body: The message to send in the alert.\n    public init(body: String) {\n        self.body = body\n    }\n\n    enum CodingKeys: String, CodingKey {\n        case launchImage = \"launch-image\"\n        case titleLocKey = \"title-loc-key\"\n        case titleLocArgs = \"title-loc-args\"\n        case subtitleLocKey = \"subtitle-loc-key\"\n        case subtitleLocArgs = \"subtitle-loc-args\"\n        case locKey = \"loc-key\"\n        case locArgs = \"loc-args\"\n        case actionLocKey = \"action-loc-key\"\n        case title, subtitle, body, action\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParsePushPayload/Apple/ParsePushAppleSound.swift",
    "content": "//\n//  ParsePushAppleSound.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/5/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n// swiftlint:disable line_length\n\n/**\n Use these keys to configure the sound for a critical alert.\n - warning: For Apple OS's only.\n */\npublic struct ParsePushAppleSound: ParseTypeable {\n    /**\n     The critical alert flag. Set to **true** to enable the critical alert.\n     */\n    var critical: Bool?\n    /**\n     The name of a sound file in your app’s main bundle or in the\n     Library/Sounds folder of your app’s container directory. Specify the\n     string “default” to play the system sound. For information about how\n     to prepare sounds, see [UNNotificationSound](https://developer.apple.com/documentation/usernotifications/unnotificationsound).\n     */\n    var name: String?\n    /**\n     The volume for the critical alert’s sound. Set this to a value\n     between 0 (silent) and 1 (full volume).\n     */\n    var volume: Double?\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParsePushPayload/Apple/ParsePushPayloadApple.swift",
    "content": "//\n//  ParsePushPayload.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/5/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n// swiftlint:disable line_length\n\n/// The payload data for an Apple push notification.\npublic struct ParsePushPayloadApple: ParsePushApplePayloadable {\n    /**\n     If you are a writing an app using the Remote Notification\n     Background Mode introduced in iOS7 (a.k.a. “Background Push”), set this value to\n     1 to trigger a background download.\n     - warning: For Apple OS's only. You also have to set `pushType` starting iOS 13\n     and watchOS 6.\n     */\n    public var contentAvailable: Int?\n    /**\n     If you are a writing an app using the Remote Notification Background Mode introduced\n     in iOS7 (a.k.a. “Background Push”), set this value to 1 to trigger a background download.\n     - warning: You also have to set `pushType` starting iOS 13\n     and watchOS 6.\n     */\n    public var mutableContent: Int?\n    /**\n     The priority of the notification. Specify 10 to send the notification immediately.\n     Specify 5 to send the notification based on power considerations on the user’s device.\n     See Apple's [documentation](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns)\n     for more information.\n     - warning: For Apple OS's only.\n     */\n    public var priority: Int?\n\n    public var topic: String?\n\n    public var collapseId: String?\n\n    public var relevanceScore: Double?\n\n    public var targetContentId: String?\n\n    public var interruptionLevel: String?\n\n    public var pushType: PushType? = .alert\n\n    public var category: String?\n\n    public var urlArgs: [String]?\n\n    public var threadId: String?\n\n    public var mdm: String?\n\n    public var alert: ParsePushAppleAlert?\n\n    /**\n     The content of the alert message.\n     */\n    public var body: String? {\n        get {\n            alert?.body\n        }\n        set {\n            if alert != nil {\n                alert?.body = newValue\n            } else if let newBody = newValue {\n                alert = .init(body: newBody)\n            }\n        }\n    }\n    var badge: AnyCodable?\n    var sound: AnyCodable?\n\n    /// The type of notification.\n    public enum PushType: String, Codable {\n        /// Send as an alert.\n        case alert\n        /// Send as a background notification.\n        case background\n    }\n\n    enum CodingKeys: String, CodingKey {\n        case relevanceScore = \"relevance-score\"\n        case targetContentId = \"targetContentIdentifier\"\n        case mutableContent = \"mutable-content\"\n        case contentAvailable = \"content-available\"\n        case pushType = \"push_type\"\n        case collapseId = \"collapse_id\"\n        case category, sound, badge, alert, threadId,\n             mdm, priority, topic, interruptionLevel,\n             urlArgs\n    }\n\n    public init() { }\n\n    /**\n     Create an instance of `ParsePushPayloadApple` .\n     - parameter alert: The alert payload for the Apple push notification.\n     */\n    public init(alert: ParsePushAppleAlert) {\n        self.alert = alert\n    }\n\n    /**\n     Create an instance of `ParsePushPayloadApple` .\n     - parameter body: The body message to display for the Apple push notification.\n     */\n    public init(body: String) {\n        self.body = body\n    }\n\n    public init(from decoder: Decoder) throws {\n        let values = try decoder.container(keyedBy: CodingKeys.self)\n        do {\n            alert = try values.decode(ParsePushAppleAlert.self, forKey: .alert)\n        } catch {\n            if let alertBody = try values.decodeIfPresent(String.self, forKey: .alert) {\n                alert = ParsePushAppleAlert(body: alertBody)\n            }\n        }\n        relevanceScore = try values.decodeIfPresent(Double.self, forKey: .relevanceScore)\n        targetContentId = try values.decodeIfPresent(String.self, forKey: .targetContentId)\n        mutableContent = try values.decodeIfPresent(Int.self, forKey: .mutableContent)\n        contentAvailable = try values.decodeIfPresent(Int.self, forKey: .contentAvailable)\n        priority = try values.decodeIfPresent(Int.self, forKey: .priority)\n        pushType = try values.decodeIfPresent(Self.PushType.self, forKey: .pushType)\n        collapseId = try values.decodeIfPresent(String.self, forKey: .collapseId)\n        category = try values.decodeIfPresent(String.self, forKey: .category)\n        sound = try values.decodeIfPresent(AnyCodable.self, forKey: .sound)\n        badge = try values.decodeIfPresent(AnyCodable.self, forKey: .badge)\n        threadId = try values.decodeIfPresent(String.self, forKey: .threadId)\n        mdm = try values.decodeIfPresent(String.self, forKey: .mdm)\n        topic = try values.decodeIfPresent(String.self, forKey: .topic)\n        interruptionLevel = try values.decodeIfPresent(String.self, forKey: .interruptionLevel)\n        urlArgs = try values.decodeIfPresent([String].self, forKey: .urlArgs)\n    }\n\n    /**\n     Set the name of a sound file in your app’s main bundle or in the Library/Sounds folder\n     of your app’s container directory. For information about how to prepare sounds, see\n     [UNNotificationSound](https://developer.apple.com/documentation/usernotifications/unnotificationsound).\n     - parameter sound: An instance of `ParsePushAppleSound`.\n     - returns: A mutated instance of `ParsePushPayloadApple` for easy chaining.\n     - warning: For Apple OS's only.\n     */\n    public func setSound(_ sound: ParsePushAppleSound) -> Self {\n        var mutablePayload = self\n        mutablePayload.sound = AnyCodable(sound)\n        return mutablePayload\n    }\n\n    /**\n     Set the name of a sound file in your app’s main bundle or in the Library/Sounds folder\n     of your app’s container directory. Specify the string “default” to play the system\n     sound. Pass a string for **regular** notifications. For critical alerts, pass the sound\n     `ParsePushAppleSound` instead. For information about how to prepare sounds, see\n     [UNNotificationSound](https://developer.apple.com/documentation/usernotifications/unnotificationsound).\n     - parameter sound: A `String` or any `Codable` object that can be sent to APN.\n     - returns: A mutated instance of `ParsePushPayloadApple` for easy chaining.\n     - warning: For Apple OS's only.\n     */\n    public func setSound<V>(_ sound: V) -> Self where V: Codable {\n        var mutablePayload = self\n        mutablePayload.sound = AnyCodable(sound)\n        return mutablePayload\n    }\n\n    /**\n     Get the sound using any type that conforms to `Codable`.\n     - returns: The sound casted to the inferred type.\n     - throws: An error of type `ParseError`.\n     */\n    public func getSound<V>() throws -> V where V: Codable {\n        guard let sound = sound?.value as? V else {\n            throw ParseError(code: .unknownError,\n                             message: \"Cannot be casted to the inferred type\")\n        }\n        return sound\n    }\n\n    /**\n     Set the badge to a specific value to display on your app's icon.\n     - parameter badge: The number to display in a badge on your app’s icon.\n     Specify 0 to remove the current badge, if any.\n     - returns: A mutated instance of `ParsePushPayloadApple` for easy chaining.\n     - warning: For Apple OS's only.\n     */\n    public func setBadge(_ number: Int) -> Self {\n        var mutablePayload = self\n        mutablePayload.badge = AnyCodable(number)\n        return mutablePayload\n    }\n\n    /**\n     Increment the badge value by 1 to display on your app's icon.\n     - warning: For Apple OS's only.\n     - returns: A mutated instance of `ParsePushPayloadApple` for easy chaining.\n     */\n    public func incrementBadge() -> Self {\n        var mutablePayload = self\n        mutablePayload.badge = AnyCodable(Increment(amount: 1))\n        return mutablePayload\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParsePushPayload/Firebase/ParsePushFirebaseNotification.swift",
    "content": "//\n//  ParsePushFirebaseNotification.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/11/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n// swiftlint:disable line_length\n\n/**\n The Firebase Cloud Messaging (FCM) notification payload. For more information, see\n [Firebase Cloud Messaging](https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages#Notification)\n and [Firebase Cloud Messaging (legacy)](https://firebase.google.com/docs/cloud-messaging/http-server-ref#notification-payload-support).\n */\npublic struct ParsePushFirebaseNotification: ParseTypeable {\n    /**\n     Indicates notification icon. On Android: sets value to myicon for\n     drawable resource **myicon.png**.\n     - note: Android: Required, Apple: Not Avialable.\n     - warning: Only valid for FCM legacy HTTP API.\n     */\n    public var icon: String?\n\n    /**\n     Contains the URL of an image that is going to be downloaded on\n     the device and displayed in a notification. JPEG, PNG, BMP have\n     full support across platforms. Animated GIF and video only work on\n     iOS. WebP and HEIF have varying levels of support across platforms\n     and platform versions. Android has 1MB image size limit.\n     - note: Android: Optional, Apple: Optional.\n     - warning: Only valid for FCM HTTP v1 API.\n     */\n    public var image: String?\n\n    /**\n     Indicates notification body text.\n     - note: Android: Optional, Apple: Optional.\n     - warning: Only valid for FCM legacy HTTP API.\n     */\n    public var body: String?\n    /**\n     Indicates notification title. This field is not visible on iOS phones and tablets.\n     - note: Android: Required, Apple: Optional.\n     - warning: Only valid for FCM legacy HTTP API.\n     */\n    public var title: String?\n    /**\n     The notification's subtitle.\n     - note: Android: Required, Apple-watchOS: Optional.\n     - warning: Only valid for FCM legacy HTTP API.\n     */\n    public var subtitle: String?\n    /**\n     Indicates sound to be played. Supports only default currently.\n     - note: Android: Optional, Apple: Optional.\n     - warning: Only valid for FCM legacy HTTP API.\n     */\n    public var sound: String?\n    /**\n     Indicates the badge on client app home icon.\n     - note: Android: Not Available, Apple: Optional.\n     - warning: Only valid for FCM legacy HTTP API.\n     */\n    public var badge: String?\n    /**\n     Indicates whether each notification message results in a new\n     entry on the notification center on Android. If not set, each request\n     creates a new notification. If set, and a notification with the same\n     tag is already being shown, the new notification replaces the\n     existing one in notification center.\n     - note: Android: Optional, Apple: Not Available.\n     - warning: Only valid for FCM legacy HTTP API.\n     */\n    public var tag: String?\n    /**\n     Indicates color of the icon, expressed in #rrggbb format.\n     - note: Android: Optional, Apple: Not Available.\n     - warning: Only valid for FCM legacy HTTP API.\n     */\n    public var color: String?\n    /**\n     The action associated with a user click on the notification. On Android,\n     if this is set, an activity with a matching intent filter is launched when\n     user clicks the notification.\n     - note: Android: Optional, Apple: Optional.\n     - warning: Only valid for FCM legacy HTTP API.\n     */\n    public var clickAction: String?\n    /**\n     Indicates the key to the body string for localization. On iOS, this\n     corresponds to \"loc-key\" in APNS payload.\n     - note: Android: Not Available, Apple: Optional.\n     - warning: Only valid for FCM legacy HTTP API.\n     */\n    public var bodyLocKey: String?\n    /**\n     Indicates the string value to replace format specifiers in body string\n     for localization. On iOS, this corresponds to \"loc-args\" in APNS payload.\n     - note: Android: Not Available, Apple: Optional.\n     - warning: Only valid for FCM legacy HTTP API.\n     */\n    public var bodyLocArgs: [String]?\n    /**\n     Indicates the string value to replace format specifiers in title string for l\n     ocalization. On iOS, this corresponds to \"title-loc-args\" in APNS payload.\n     - note: Android: Not Available, Apple: Optional.\n     - warning: Only valid for FCM legacy HTTP API.\n     */\n    public var titleLocKey: String?\n    /**\n     Indicates the key to the title string for localization. On iOS, this\n     corresponds to \"title-loc-key\" in APNS payload.\n     - note: Android: Not Available, Apple: Optional.\n     - warning: Only valid for FCM legacy HTTP API.\n     */\n    public var titleLocArgs: [String]?\n    /**\n     The app must create a channel with this channel ID before any\n     notification with this channel ID is received.\n     - note: Android: Optional, Apple: Not Available.\n     - warning: Only valid for FCM legacy HTTP API.\n     */\n    public var androidChannelId: String?\n\n    enum CodingKeys: String, CodingKey {\n        case titleLocKey = \"title_loc_key\"\n        case titleLocArgs = \"title_loc_args\"\n        case bodyLocKey = \"body_loc-key\"\n        case bodyLocArgs = \"body-loc-args\"\n        case clickAction = \"click_action\"\n        case androidChannelId = \"android_channel_id\"\n        case title, icon, body, sound, badge, tag,\n            color, subtitle, image\n    }\n\n    /**\n     Creates a new instance of `ParsePushFirebaseNotification`.\n     - parameter title: Indicates notification body text.\n     - parameter body: Indicates notification body text.\n     - parameter icon: Indicates notification icon. On Android: sets\n     value to myicon for drawable resource **myicon.png**. Only valid\n     for FCM legacy HTTP API.\n     */\n    public init(title: String? = nil,\n                body: String? = nil,\n                icon: String? = nil) {\n        self.title = title\n        self.body = body\n        self.icon = icon\n    }\n\n    /**\n     Creates a new instance of `ParsePushFirebaseNotification`.\n     - parameter title: Indicates notification body text.\n     - parameter body: Indicates notification body text.\n     - parameter image: Contains the URL of an image that is going\n     to be downloaded on the device and displayed in a notification. JPEG,\n     PNG, BMP have full support across platforms. Animated GIF and\n     video only work on iOS. WebP and HEIF have varying levels of support\n     across platforms and platform versions. Android has 1MB image size\n     limit. Only valid for FCM HTTP v1 API.\n     */\n    public init(title: String? = nil,\n                body: String? = nil,\n                image: String?) {\n        self.title = title\n        self.body = body\n        self.image = image\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParsePushPayload/Firebase/ParsePushPayloadFirebase.swift",
    "content": "//\n//  ParsePushPayloadFirebase.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/8/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n The payload data for an Firebase Cloud Messaging (FCM) push notification.\n See [Firebase Cloud Messaging](https://firebase.google.com/docs/cloud-messaging/http-server-ref)\n documentation for more information.\n */\npublic struct ParsePushPayloadFirebase: ParsePushFirebasePayloadable {\n    /**\n     The delivery priority to downstream messages. Can be either\n     **normal** or **high** priority. On Apple platforms,\n     these correspond to APNs priorities 5 and 10.\n     */\n    public var priority: Self.PushPriority?\n    /**\n     On Apple platforms, use this field to represent content-available\n     in the APNs payload. When a notification or message is sent and\n     this is set to true, an inactive client app is awoken, and the message\n     is sent through APNs as a silent notification and not through FCM.\n     - note: Silent notifications in APNs are not guaranteed to be\n     delivered, and can depend on factors such as the user turning on\n     Low Power Mode, force quitting the app, etc. On Android, data\n     messages wake the app by default. On Chrome, currently not supported.\n     */\n    public var contentAvailable: Bool?\n    /**\n     On Apple platforms, use this field to represent mutable-content in\n     the APNs payload.\n     */\n    public var mutableContent: Bool?\n    public var uri: URL?\n    public var title: String?\n    public var collapseKey: String?\n    public var delayWhileIdle: Bool?\n    public var restrictedPackageName: String?\n    public var dryRun: Bool?\n    public var data: [String: String]?\n    public var notification: ParsePushFirebaseNotification?\n\n    /// The priority type of a notification.\n    public enum PushPriority: String, Codable {\n        /// Sets the priority to **5**.\n        case normal\n        /// Sets the priority to **10**.\n        case high\n    }\n\n    public init() { }\n\n    /**\n     Create a new instance of `ParsePushPayloadFirebase`.\n     - parameter notification: The predefined, user-visible notification payload.\n     */\n    public init(notification: ParsePushFirebaseNotification) {\n        self.notification = notification\n    }\n\n    enum CodingKeys: String, CodingKey {\n        case priority, contentAvailable, title, uri,\n             collapseKey, delayWhileIdle, restrictedPackageName,\n             dryRun, data, notification, mutableContent\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParsePushPayload/ParsePushPayloadAny.swift",
    "content": "//\n//  ParsePushPayloadAny.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/8/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n The payload data for both a `ParsePushPayloadApple` and\n `ParsePushPayloadFirebase` push notification.\n */\npublic struct ParsePushPayloadAny: ParsePushApplePayloadable, ParsePushFirebasePayloadable {\n    public var topic: String?\n    public var collapseId: String?\n    public var pushType: ParsePushPayloadApple.PushType?\n    public var category: String?\n    public var urlArgs: [String]?\n    public var targetContentId: String?\n    public var threadId: String?\n    public var interruptionLevel: String?\n    public var relevanceScore: Double?\n    public var mdm: String?\n    public var uri: URL?\n    public var title: String?\n    public var collapseKey: String?\n    public var delayWhileIdle: Bool?\n    public var restrictedPackageName: String?\n    public var dryRun: Bool?\n    public var data: [String: String]?\n    public var notification: ParsePushFirebaseNotification?\n    public var alert: ParsePushAppleAlert?\n    var badge: AnyCodable?\n    var sound: AnyCodable?\n    var priority: AnyCodable?\n    var contentAvailable: AnyCodable?\n    var mutableContent: AnyCodable?\n\n    public init(from decoder: Decoder) throws {\n        let values = try decoder.container(keyedBy: RawCodingKey.self)\n        relevanceScore = try values.decodeIfPresent(Double.self, forKey: .key(\"relevance-score\"))\n        targetContentId = try values.decodeIfPresent(String.self, forKey: .key(\"targetContentIdentifier\"))\n        do {\n            mutableContent = try values.decode(AnyCodable.self, forKey: .key(\"mutable-content\"))\n        } catch {\n            mutableContent = try values.decodeIfPresent(AnyCodable.self, forKey: .key(\"mutableContent\"))\n        }\n        do {\n            contentAvailable = try values.decode(AnyCodable.self, forKey: .key(\"content-available\"))\n        } catch {\n            contentAvailable = try values.decodeIfPresent(AnyCodable.self, forKey: .key(\"contentAvailable\"))\n        }\n        do {\n            let priorityInt = try values.decode(Int.self, forKey: .key(\"priority\"))\n            priority = AnyCodable(priorityInt)\n        } catch {\n            if let priorityString = try values.decodeIfPresent(String.self, forKey: .key(\"priority\")),\n               let priorityEnum = ParsePushPayloadFirebase.PushPriority(rawValue: priorityString) {\n                priority = AnyCodable(priorityEnum)\n            }\n        }\n        pushType = try values.decodeIfPresent(ParsePushPayloadApple.PushType.self, forKey: .key(\"push_type\"))\n        collapseId = try values.decodeIfPresent(String.self, forKey: .key(\"collapse_id\"))\n        category = try values.decodeIfPresent(String.self, forKey: .key(\"category\"))\n        sound = try values.decodeIfPresent(AnyCodable.self, forKey: .key(\"sound\"))\n        badge = try values.decodeIfPresent(AnyCodable.self, forKey: .key(\"badge\"))\n        do {\n            alert = try values.decode(ParsePushAppleAlert.self, forKey: .key(\"alert\"))\n        } catch {\n            if let alertBody = try? values.decode(String.self, forKey: .key(\"alert\")) {\n                alert = ParsePushAppleAlert(body: alertBody)\n            }\n        }\n        threadId = try values.decodeIfPresent(String.self, forKey: .key(\"threadId\"))\n        mdm = try values.decodeIfPresent(String.self, forKey: .key(\"mdm\"))\n        topic = try values.decodeIfPresent(String.self, forKey: .key(\"topic\"))\n        interruptionLevel = try values.decodeIfPresent(String.self, forKey: .key(\"interruptionLevel\"))\n        urlArgs = try values.decodeIfPresent([String].self, forKey: .key(\"urlArgs\"))\n        title = try values.decodeIfPresent(String.self, forKey: .key(\"title\"))\n        uri = try values.decodeIfPresent(URL.self, forKey: .key(\"uri\"))\n        collapseKey = try values.decodeIfPresent(String.self, forKey: .key(\"collapseKey\"))\n        delayWhileIdle = try values.decodeIfPresent(Bool.self, forKey: .key(\"delayWhileIdle\"))\n        restrictedPackageName = try values.decodeIfPresent(String.self, forKey: .key(\"restrictedPackageName\"))\n        dryRun = try values.decodeIfPresent(Bool.self, forKey: .key(\"dryRun\"))\n        data = try values.decodeIfPresent([String: String].self, forKey: .key(\"data\"))\n        notification = try values.decodeIfPresent(ParsePushFirebaseNotification.self, forKey: .key(\"notification\"))\n    }\n\n    public init() { }\n\n    /**\n     Convert the current `ParsePushPayloadAny` to `ParsePushPayloadApple`.\n     - returns: A `ParsePushPayloadApple` instance.\n     */\n    public func convertToApple() -> ParsePushPayloadApple {\n        var payload = ParsePushPayloadApple()\n        payload.topic = topic\n        payload.collapseId = collapseId\n        payload.pushType = pushType\n        payload.category = category\n        payload.urlArgs = urlArgs\n        payload.targetContentId = targetContentId\n        payload.threadId = threadId\n        payload.interruptionLevel = interruptionLevel\n        payload.relevanceScore = relevanceScore\n        payload.mdm = mdm\n        payload.alert = alert\n        payload.badge = badge\n        payload.sound = sound\n        if let priority = priority?.value as? Int {\n            payload.priority = priority\n        }\n        if let contentAvailable = contentAvailable?.value as? Int {\n            payload.contentAvailable = contentAvailable\n        }\n        if let mutableContent = mutableContent?.value as? Int {\n            payload.mutableContent = mutableContent\n        }\n        return payload\n    }\n\n    /**\n     Convert the current `ParsePushPayloadAny` to `ParsePushPayloadFirebase`.\n     - returns: A `ParsePushPayloadFirebase` instance.\n     */\n    public func convertToFirebase() -> ParsePushPayloadFirebase {\n        var payload = ParsePushPayloadFirebase()\n        payload.uri = uri\n        payload.title = title\n        payload.collapseKey = collapseKey\n        payload.delayWhileIdle = delayWhileIdle\n        payload.restrictedPackageName = restrictedPackageName\n        payload.dryRun = dryRun\n        payload.data = data\n        payload.notification = notification\n        if let priority = priority?.value as? ParsePushPayloadFirebase.PushPriority {\n            payload.priority = priority\n        }\n        if let contentAvailable = contentAvailable?.value as? Bool {\n            payload.contentAvailable = contentAvailable\n        }\n        if let mutableContent = mutableContent?.value as? Bool {\n            payload.mutableContent = mutableContent\n        }\n        return payload\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParsePushStatus.swift",
    "content": "//\n//  ParsePushStatus.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 5/30/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n The PushStatus on the Parse Server.\n - warning: These objects are only read-only.\n - requires: `.useMasterKey` has to be available. It is recommended to only\n use the master key in server-side applications where the key is kept secure and not\n exposed to the public.\n */\npublic struct ParsePushStatus<V: ParsePushPayloadable>: ParsePushStatusable {\n    public typealias PayloadType = V\n\n    public var originalData: Data?\n\n    public var objectId: String?\n\n    public var createdAt: Date?\n\n    public var updatedAt: Date?\n\n    public var ACL: ParseACL?\n\n    public var query: QueryWhere?\n\n    public var pushTime: Date?\n\n    public var source: String?\n\n    public var payload: PayloadType?\n\n    public var title: String?\n\n    public var expiry: Int?\n\n    public var expirationInterval: String?\n\n    public var status: String?\n\n    public var numSent: Int?\n\n    public var numFailed: Int?\n\n    public var pushHash: String?\n\n    public var errorMessage: ParseError?\n\n    public var sentPerType: [String: Int]?\n\n    public var failedPerType: [String: Int]?\n\n    public var sentPerUTCOffset: [String: Int]?\n\n    public var failedPerUTCOffset: [String: Int]?\n\n    public var count: Int?\n\n    public init() { }\n\n    enum CodingKeys: String, CodingKey {\n        case expirationInterval = \"expiration_interval\"\n        case objectId, createdAt, updatedAt, ACL\n        case count, failedPerUTCOffset, sentPerUTCOffset,\n             sentPerType, failedPerType, errorMessage, pushHash,\n             numFailed, numSent, status, expiry, title, source,\n             pushTime, query, payload\n    }\n\n    public init(from decoder: Decoder) throws {\n        let values = try decoder.container(keyedBy: CodingKeys.self)\n        objectId = try values.decodeIfPresent(String.self, forKey: .objectId)\n        createdAt = try values.decodeIfPresent(Date.self, forKey: .createdAt)\n        updatedAt = try values.decodeIfPresent(Date.self, forKey: .updatedAt)\n        ACL = try values.decodeIfPresent(ParseACL.self, forKey: .ACL)\n        count = try values.decodeIfPresent(Int.self, forKey: .count)\n        failedPerUTCOffset = try values.decodeIfPresent([String: Int].self, forKey: .failedPerUTCOffset)\n        sentPerUTCOffset = try values.decodeIfPresent([String: Int].self, forKey: .sentPerType)\n        sentPerType = try values.decodeIfPresent([String: Int].self, forKey: .sentPerType)\n        failedPerType = try values.decodeIfPresent([String: Int].self, forKey: .failedPerType)\n        errorMessage = try values.decodeIfPresent(ParseError.self, forKey: .errorMessage)\n        pushHash = try values.decodeIfPresent(String.self, forKey: .pushHash)\n        numFailed = try values.decodeIfPresent(Int.self, forKey: .numFailed)\n        numSent = try values.decodeIfPresent(Int.self, forKey: .numSent)\n        status = try values.decodeIfPresent(String.self, forKey: .status)\n        expiry = try values.decodeIfPresent(Int.self, forKey: .expiry)\n        title = try values.decodeIfPresent(String.self, forKey: .title)\n        source = try values.decodeIfPresent(String.self, forKey: .source)\n        pushTime = try values.decodeIfPresent(Date.self, forKey: .pushTime)\n        expirationInterval = try values.decodeIfPresent(String.self, forKey: .expirationInterval)\n        // Handle when Parse Server sends doubly encoded fields.\n        do {\n            // Attempt the correct decoding first.\n            payload = try values.decodeIfPresent(PayloadType.self, forKey: .payload)\n        } catch {\n            let payloadString = try values.decode(String.self, forKey: .payload)\n            guard let payloadData = payloadString.data(using: .utf8) else {\n                throw ParseError(code: .unknownError, message: \"Could not decode payload\")\n            }\n            payload = try ParseCoding.jsonDecoder().decode(PayloadType.self, from: payloadData)\n        }\n        do {\n            // Attempt the correct decoding first.\n            query = try values.decodeIfPresent(QueryWhere.self, forKey: .query)\n        } catch {\n            let queryString = try values.decode(String.self, forKey: .query)\n            guard let queryData = queryString.data(using: .utf8) else {\n                throw ParseError(code: .unknownError, message: \"Could not decode query\")\n            }\n            query = try ParseCoding.jsonDecoder().decode(QueryWhere.self, from: queryData)\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseRelation.swift",
    "content": "//\n//  ParseRelation.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/18/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n The `ParseRelation` object that is used to access all of the children of a many-to-many relationship.\n Each instance of `ParseRelation` is associated with a particular parent object and key.\n \n In most cases, you do not need to create an instance of `ParseRelation` directly as it can be\n indirectly created from any `ParseObject` by using the respective `relation` property.\n */\npublic struct ParseRelation<T>: ParseTypeable, Hashable where T: ParseObject {\n    internal let __type: String = \"Relation\" // swiftlint:disable:this identifier_name\n\n    /// The parent `ParseObject`\n    public var parent: Pointer<T>?\n\n    /// The name of the class of the target child objects.\n    public var className: String?\n\n    var key: String?\n\n    /**\n     Create a `ParseRelation` with a specific parent and key.\n     - parameters:\n        - parent: The parent `ParseObject` Pointer.\n        - key: The key for the relation.\n     */\n    public init(parent: Pointer<T>, key: String? = nil) {\n        self.parent = parent\n        self.key = key\n    }\n\n    /**\n     Create a `ParseRelation` with a specific parent, key, and className.\n     - parameters:\n        - parent: The parent `ParseObject` Pointer.\n        - key: The key for the relation.\n        - className: The name of the child class for the relation.\n     */\n    public init(parent: Pointer<T>, key: String? = nil, className: String) {\n        self.init(parent: parent, key: key)\n        self.className = className\n    }\n\n    /**\n     Create a `ParseRelation` with a specific parent, key, and child object.\n     - parameters:\n        - parent: The parent `ParseObject` Pointer.\n        - key: The key for the relation.\n        - child: The child `ParseObject`.\n     */\n    public init<U>(parent: Pointer<T>, key: String? = nil, child: U) where U: ParseObject {\n        self.init(parent: parent, key: key)\n        self.className = child.className\n    }\n\n    /**\n     Create a `ParseRelation` with a specific parent, key, and child object.\n     - parameters:\n        - parent: The parent `ParseObject` Pointer.\n        - key: The key for the relation.\n        - child: The child `ParseObject` Pointer.\n     */\n    public init<U>(parent: Pointer<T>, key: String? = nil, child: Pointer<U>) where U: ParseObject {\n        self.init(parent: parent, key: key)\n        self.className = child.className\n    }\n\n    /**\n     Create a `ParseRelation` with a specific parent and key.\n     - parameters:\n        - parent: The parent `ParseObject`.\n        - key: The key for the relation.\n     */\n    public init(parent: T, key: String? = nil) throws {\n        self.init(parent: try parent.toPointer(), key: key)\n    }\n\n    /**\n     Create a `ParseRelation` with a specific parent, key, and className.\n     - parameters:\n        - parent: The parent `ParseObject`.\n        - key: The key for the relation.\n        - className: The name of the child class for the relation.\n     */\n    public init(parent: T, key: String? = nil, className: String) throws {\n        self.init(parent: try parent.toPointer(), key: key, className: className)\n    }\n\n    /**\n     Create a `ParseRelation` with a specific parent, key, and child object.\n     - parameters:\n        - parent: The parent `ParseObject`.\n        - key: The key for the relation.\n        - child: The child `ParseObject`.\n     */\n    public init<U>(parent: T, key: String? = nil, child: U) throws where U: ParseObject {\n        self.init(parent: try parent.toPointer(), key: key, child: child)\n    }\n\n    /**\n     Create a `ParseRelation` with a specific parent, key, and child object.\n     - parameters:\n        - parent: The parent `ParseObject`.\n        - key: The key for the relation.\n        - child: The child `ParseObject` Pointer.\n     */\n    public init<U>(parent: T, key: String? = nil, child: Pointer<U>) throws where U: ParseObject {\n        self.init(parent: try parent.toPointer(), key: key, child: child)\n    }\n\n    enum CodingKeys: String, CodingKey {\n        case className\n        case __type // swiftlint:disable:this identifier_name\n    }\n\n    // MARK: Helpers\n    func isSameClass(_ objectClassNames: [String]) -> Bool {\n        guard let first = objectClassNames.first else {\n            return false\n        }\n        if className != nil {\n            if className != first {\n                return false\n            }\n        }\n        let sameClassObjects = objectClassNames.filter({ $0 == first })\n        return sameClassObjects.count == objectClassNames.count\n    }\n\n    func isSameClass<U>(_ objects: [U]) -> Bool where U: ParseObject {\n        isSameClass(objects.map { $0.className })\n    }\n\n    // MARK: Intents\n    /**\n     Adds a relation to the respective objects.\n     - parameters:\n        - key: The key for the relation.\n        - objects: An array of `ParseObject`'s to add relation to.\n     - throws: An error of type `ParseError`.\n     */\n    public func add<U>(_ key: String, objects: [U]) throws -> ParseOperation<T> where U: ParseObject {\n        guard let parent = parent else {\n            throw ParseError(code: .unknownError,\n                             message: \"ParseRelation must have the parent set.\")\n        }\n        if let currentKey = self.key {\n            if currentKey != key {\n                throw ParseError(code: .unknownError, message: \"All objects have be related to the same key.\")\n            }\n        }\n        if !isSameClass(objects) {\n            throw ParseError(code: .unknownError, message: \"All objects have to have the same className.\")\n        }\n\n        return try parent.toObject().operation.addRelation(key, objects: objects)\n    }\n\n    /**\n     Adds a relation to the respective `ParseObject`'s with using the `key` for this `ParseRelation`.\n     - parameters:\n        - objects: An array of `ParseObject`'s to add relation to.\n     - throws: An error of type `ParseError`.\n     */\n    public func add<U>(_ objects: [U]) throws -> ParseOperation<T> where U: ParseObject {\n        guard let key = self.key else {\n            throw ParseError(code: .unknownError,\n                             message: \"ParseRelation must have the key set.\")\n        }\n        return try add(key, objects: objects)\n    }\n\n    /**\n     Removes a relation to the respective objects.\n     - parameters:\n        - key: The key for the relation.\n        - objects: An array of `ParseObject`'s to remove relation to.\n     - throws: An error of type `ParseError`.\n     */\n    public func remove<U>(_ key: String, objects: [U]) throws -> ParseOperation<T> where U: ParseObject {\n        guard let parent = parent else {\n            throw ParseError(code: .unknownError,\n                             message: \"ParseRelation must have the parent set.\")\n        }\n        if let currentKey = self.key {\n            if currentKey != key {\n                throw ParseError(code: .unknownError, message: \"All objects have be related to the same key.\")\n            }\n        }\n        if !isSameClass(objects) {\n            throw ParseError(code: .unknownError, message: \"All objects have to have the same className.\")\n        }\n        return try parent.toObject().operation.removeRelation(key, objects: objects)\n    }\n\n    /**\n     Removes a relation to the respective objects using the `key` for this `ParseRelation`.\n     - parameters:\n        - objects: An array of `ParseObject`'s to add relation to.\n     - throws: An error of type `ParseError`.\n     */\n    public func remove<U>(_ objects: [U]) throws -> ParseOperation<T> where U: ParseObject {\n        guard let key = self.key else {\n            throw ParseError(code: .unknownError,\n                             message: \"ParseRelation must have the key set.\")\n        }\n        return try remove(key, objects: objects)\n    }\n\n    /**\n     Returns a `Query` that is limited to objects for a specific `key` and `parent` in this relation.\n     - parameter key: The key for the relation.\n     - parameter parent: The parent pointer object for the relation.\n     - returns: A relation query.\n    */\n    public static func query<U>(_ key: String, parent: Pointer<U>) -> Query<T> where U: ParseObject {\n        Query<T>(related(key: key, object: parent))\n    }\n\n    /**\n     Returns a `Query` that is limited to objects for a specific `key` and `parent` in this relation.\n     - parameter key: The key for the relation.\n     - parameter parent: The parent object for the relation.\n     - throws: An error of type `ParseError`.\n     - returns: A relation query.\n    */\n    public static func query<U>(_ key: String, parent: U) throws -> Query<T> where U: ParseObject {\n        Self.query(key, parent: try parent.toPointer())\n    }\n\n    /**\n     Returns a `Query` that is limited to objects for a specific `key` and `parent` in this relation.\n     - parameter key: The key for the relation.\n     - parameter parent: The parent object for the relation.\n     - throws: An error of type `ParseError`.\n     - returns: A relation query.\n    */\n    public func query<U>(_ key: String, parent: U) throws -> Query<T> where U: ParseObject {\n        try Self.query(key, parent: parent)\n    }\n\n    /**\n     Returns a `Query` that is limited to objects for a specific `key` and `parent` in this relation.\n     - parameter key: The key for the relation.\n     - parameter parent: The parent pointer object for the relation.\n     - returns: A relation query.\n    */\n    public func query<U>(_ key: String, parent: Pointer<U>) -> Query<T> where U: ParseObject {\n        Self.query(key, parent: parent)\n    }\n\n    /**\n     Returns a `Query` that is limited to the key and objects in this relation.\n        - throws: An error of type `ParseError`.\n        - returns: A relation query.\n    */\n    public func query<U>() throws -> Query<U> where U: ParseObject {\n        guard let parent = parent else {\n            throw ParseError(code: .unknownError,\n                             message: \"ParseRelation must have the parent set.\")\n        }\n        guard let key = self.key else {\n            throw ParseError(code: .unknownError,\n                             message: \"ParseRelation must have the key set.\")\n        }\n        if !isSameClass([U.className]) {\n            throw ParseError(code: .unknownError,\n                             message: \"ParseRelation must have the same child className as the original relation.\")\n        }\n        return Query<U>(related(key: key, object: parent))\n    }\n\n    /**\n     Returns a `Query` that is limited to objects for a specific `key` and `child` in this relation.\n     - parameter key: The key for the relation.\n     - throws: An error of type `ParseError`.\n     - returns: A relation query.\n    */\n    public func query<U>(_ key: String) throws -> Query<U> where U: ParseObject {\n        guard let parent = parent else {\n            throw ParseError(code: .unknownError,\n                             message: \"ParseRelation must have the parent set.\")\n        }\n        return try Self(parent: parent, key: key).query()\n    }\n}\n\n// MARK: Convenience\npublic extension ParseRelation {\n\n    /**\n     Adds a relation to the respective `ParseUser`'s with `key = \"users\"`.\n     - parameters:\n        - users: An array of `ParseUser`'s to add relation to.\n     - throws: An error of type `ParseError`.\n     */\n    func add<U>(_ users: [U]) throws -> ParseOperation<T> where U: ParseUser {\n        guard let key = self.key else {\n            return try add(\"users\", objects: users)\n        }\n        return try add(key, objects: users)\n    }\n\n    /**\n     Adds a relation to the respective `ParseRole`'s with `key = \"roles\"`.\n     - parameters:\n        - roles: An array of `ParseRole`'s to add relation to.\n     - throws: An error of type `ParseError`.\n     */\n    func add<U>(_ roles: [U]) throws -> ParseOperation<T> where U: ParseRole {\n        guard let key = self.key else {\n            return try add(\"roles\", objects: roles)\n        }\n        return try add(key, objects: roles)\n    }\n\n    /**\n     Removes a relation to the respective `ParseUser`'s with `key = \"users\"`.\n     - parameters:\n        - users: An array of `ParseUser`'s to add relation to.\n     - throws: An error of type `ParseError`.\n     */\n    func remove<U>(_ users: [U]) throws -> ParseOperation<T> where U: ParseUser {\n        guard let key = self.key else {\n            return try remove(\"users\", objects: users)\n        }\n        return try remove(key, objects: users)\n    }\n\n    /**\n     Removes a relation to the respective `ParseRole`'s with `key = \"roles\"`.\n     - parameters:\n        - roles: An array of `ParseRole`'s to add relation to.\n     - throws: An error of type `ParseError`.\n     */\n    func remove<U>(_ roles: [U]) throws -> ParseOperation<T> where U: ParseRole {\n        guard let key = self.key else {\n            return try remove(\"roles\", objects: roles)\n        }\n        return try remove(key, objects: roles)\n    }\n}\n\n// MARK: ParseRelation\npublic extension ParseObject {\n\n    /// Create a new relation with this `ParseObject` as the parent.\n    var relation: ParseRelation<Self>? {\n        try? ParseRelation(parent: self)\n    }\n\n    /**\n     Establish a relation based on a stored relation.\n     - parameter relation: The stored relation property.\n     - parameter key: The key for the relation.\n     - parameter with: The parent `ParseObject` Pointer of the `ParseRelation`.\n     - returns: A usable `ParseRelation` based on the stored relation property.\n     */\n    static func relation<T: ParseObject>(_ relation: ParseRelation<T>?,\n                                         key: String,\n                                         with parent: Pointer<T>) throws -> ParseRelation<T> {\n        guard var relation = relation,\n              relation.className != nil else {\n            throw ParseError(code: .unknownError,\n                             message: \"ParseRelation is either nil or missing \\\"className\\\"\")\n        }\n        relation.parent = parent\n        relation.key = key\n        return relation\n    }\n\n    /**\n     Establish a relation based on a stored relation.\n     - parameter relation: The stored relation property.\n     - parameter key: The key for the relation.\n     - parameter with: The parent `ParseObject` of the `ParseRelation`.\n     - returns: A usable `ParseRelation` based on the stored relation property.\n     */\n    static func relation<T: ParseObject>(_ relation: ParseRelation<T>?,\n                                         key: String,\n                                         with parent: T) throws -> ParseRelation<T> {\n        try Self.relation(relation, key: key, with: try parent.toPointer())\n    }\n\n    /**\n     Returns a `Query` for child objects that is limited to objects for a specific `key` and `parent` in this relation.\n     - parameter key: The key for the relation.\n     - parameter parent: The parent object for the relation.\n     - throws: An error of type `ParseError`.\n     - returns: A relation query for child objects related to a `parent` object with a specific `key`.\n    */\n    static func queryRelations<U: ParseObject>(_ key: String, parent: U) throws -> Query<Self> {\n        try ParseRelation<Self>.query(key, parent: parent)\n    }\n\n    /**\n     Returns a `Query` for child objects that is limited to objects for a specific `key` and `parent` in this relation.\n     - parameter key: The key for the relation.\n     - parameter parent: The parent pointer object for the relation.\n     - throws: An error of type `ParseError`.\n     - returns: A relation query for child objects related to a `parent` object with a specific `key`.\n    */\n    static func queryRelations<U: ParseObject>(_ key: String, parent: Pointer<U>) -> Query<Self> {\n        ParseRelation<Self>.query(key, parent: parent)\n    }\n\n    /**\n     Create a new relation with a specific key.\n     - parameter key: The key for the relation.\n     - parameter className: The name of the child class for the relation.\n     - returns: A new `ParseRelation`.\n     */\n    func relation(_ key: String, className: String) throws -> ParseRelation<Self> {\n        try ParseRelation(parent: self, key: key, className: className)\n    }\n\n    /**\n     Create a new relation to a specific child.\n     - parameter key: The key for the relation.\n     - parameter child: The child `ParseObject`.\n     - returns: A new `ParseRelation`.\n     */\n    func relation<U>(_ key: String, child: U) throws -> ParseRelation<Self> where U: ParseObject {\n        try ParseRelation(parent: self, key: key, child: child)\n    }\n\n    /**\n     Establish a relation based on a stored relation with this `ParseObject` as the parent.\n     - parameter relation: The stored relation property.\n     - parameter key: The key for the relation.\n     - returns: A usable `ParseRelation` based on the stored relation property.\n     */\n    func relation(_ relation: ParseRelation<Self>?,\n                  key: String) throws -> ParseRelation<Self> {\n        try Self.relation(relation, key: key, with: self)\n    }\n\n    /**\n     Establish a relation based on a stored relation.\n     - parameter relation: The stored relation property.\n     - parameter key: The key for the relation.\n     - parameter with: The parent `ParseObject` Pointer of the `ParseRelation`.\n     - returns: A usable `ParseRelation` based on the stored relation property.\n     */\n    func relation<T: ParseObject>(_ relation: ParseRelation<T>?,\n                                  key: String,\n                                  with parent: Pointer<T>) throws -> ParseRelation<T> {\n        try Self.relation(relation, key: key, with: parent)\n    }\n\n    /**\n     Establish a relation based on a stored relation.\n     - parameter relation: The stored relation property.\n     - parameter key: The key for the relation.\n     - parameter with: The parent `ParseObject` of the `ParseRelation`.\n     - returns: A usable `ParseRelation` based on the stored relation property.\n     */\n    func relation<T: ParseObject>(_ relation: ParseRelation<T>?,\n                                  key: String,\n                                  with parent: T) throws -> ParseRelation<T> {\n        try self.relation(relation, key: key, with: try parent.toPointer())\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseSchema+async.swift",
    "content": "//\n//  ParseSchema+async.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 5/21/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n\npublic extension ParseSchema {\n    /**\n     Fetches the `ParseSchema` *aynchronously* from the server.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the fetched `ParseSchema`.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n    */\n    func fetch(options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.fetch(options: options,\n                       completion: continuation.resume)\n        }\n    }\n\n    /**\n     Creates the `ParseSchema` *aynchronously* on the server.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the fetched `ParseSchema`.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n    */\n    func create(options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.create(options: options,\n                        completion: continuation.resume)\n        }\n    }\n\n    /**\n     Updates the `ParseSchema` *aynchronously* on the server.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the fetched `ParseSchema`.\n     - throws: An error of type `ParseError`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n    */\n    func update(options: API.Options = []) async throws -> Self {\n        try await withCheckedThrowingContinuation { continuation in\n            self.update(options: options,\n                        completion: continuation.resume)\n        }\n    }\n\n    /**\n     Deletes all objects in the `ParseSchema` *aynchronously* from the server.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the fetched `ParseSchema`.\n     - throws: An error of type `ParseError`.\n     - warning: This will delete all objects for this `ParseSchema` and cannot be reversed.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n    */\n    func purge(options: API.Options = []) async throws {\n        let result = try await withCheckedThrowingContinuation { continuation in\n            self.purge(options: options,\n                        completion: continuation.resume)\n        }\n        if case let .failure(error) = result {\n            throw error\n        }\n    }\n\n    /**\n     Deletes the `ParseSchema` *aynchronously*  from the server.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: Returns the fetched `ParseSchema`.\n     - throws: An error of type `ParseError`.\n     - warning: This can only be used on a `ParseSchema` without objects. If the `ParseSchema`\n     currently contains objects, run `purge()` first.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n    */\n    func delete(options: API.Options = []) async throws {\n        let result = try await withCheckedThrowingContinuation { continuation in\n            self.delete(options: options,\n                        completion: continuation.resume)\n        }\n        if case let .failure(error) = result {\n            throw error\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseSchema+combine.swift",
    "content": "//\n//  ParseSchema+combine.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 5/22/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\npublic extension ParseSchema {\n    /**\n     Fetches the `ParseSchema` *aynchronously* from the server. Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n    */\n    func fetchPublisher(includeKeys: [String]? = nil,\n                        options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.fetch(options: options,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Creates the `ParseSchema` *aynchronously* on the server. Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n    */\n    func createPublisher(includeKeys: [String]? = nil,\n                         options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.create(options: options,\n                        completion: promise)\n        }\n    }\n\n    /**\n     Updates the `ParseSchema` *aynchronously* on the server. Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n    */\n    func updatePublisher(includeKeys: [String]? = nil,\n                         options: API.Options = []) -> Future<Self, ParseError> {\n        Future { promise in\n            self.update(options: options,\n                        completion: promise)\n        }\n    }\n\n    /**\n     Deletes all objects in the `ParseSchema` *aynchronously* from the server. Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - warning: This will delete all objects for this `ParseSchema` and cannot be reversed.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n    */\n    func purgePublisher(includeKeys: [String]? = nil,\n                        options: API.Options = []) -> Future<Void, ParseError> {\n        Future { promise in\n            self.purge(options: options,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Deletes the `ParseSchema` *aynchronously* from the server. Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - warning: This can only be used on a `ParseSchema` without objects. If the `ParseSchema`\n     currently contains objects, run `purge()` first.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n    */\n    func deletePublisher(includeKeys: [String]? = nil,\n                         options: API.Options = []) -> Future<Void, ParseError> {\n        Future { promise in\n            self.delete(options: options,\n                        completion: promise)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseSchema.swift",
    "content": "//\n//  ParseSchema.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 5/21/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/**\n `ParseSchema` is used for handeling your schemas.\n - requires: `.useMasterKey` has to be available. It is recommended to only\n use the master key in server-side applications where the key is kept secure and not\n exposed to the public.\n */\npublic struct ParseSchema<SchemaObject: ParseObject>: ParseTypeable, Decodable, Equatable {\n\n    /// The class name of the `ParseSchema`.\n    public var className: String\n    /// The CLPs of this `ParseSchema`.\n    public var classLevelPermissions: ParseCLP?\n    internal var fields: [String: ParseField]?\n    internal var indexes: [String: [String: AnyCodable]]?\n    internal var pendingIndexes = [String: [String: AnyCodable]]()\n\n    enum CodingKeys: String, CodingKey {\n        case className, classLevelPermissions, fields, indexes\n    }\n\n    /**\n     Get the current fields for this `ParseSchema`.\n     - returns: The current fields.\n     */\n    public func getFields() -> [String: String] {\n        var currentFields = [String: String]()\n        fields?.forEach { (key, value) in\n            currentFields[key] = value.description\n        }\n        return currentFields\n    }\n\n    /**\n     Get the current indexes for this `ParseSchema`.\n     - returns: The current indexes.\n     */\n    public func getIndexes() -> [String: [String: String]] {\n        var currentIndexes = [String: [String: String]]()\n        indexes?.forEach { (name, value) in\n            value.forEach { (field, index) in\n                currentIndexes[name] = [field: index.description]\n            }\n        }\n        pendingIndexes.forEach { (name, value) in\n            value.forEach { (field, index) in\n                currentIndexes[name] = [field: index.description]\n            }\n        }\n        return currentIndexes\n    }\n}\n\n// MARK: Default Implementations\npublic extension ParseSchema {\n    static var className: String {\n        SchemaObject.className\n    }\n\n    /// Create an empty instance of `ParseSchema` type.\n    init() {\n        self.init(className: SchemaObject.className)\n    }\n\n    /**\n     Create an empty instance of ParseSchema type with a specific CLP.\n     - parameter classLevelPermissions: The CLP access for this `ParseSchema`.\n    */\n    init(classLevelPermissions: ParseCLP) {\n        self.init(className: SchemaObject.className)\n        self.classLevelPermissions = classLevelPermissions\n    }\n\n    /**\n     Add a Field to create/update a `ParseSchema`.\n     \n     - parameter name: Name of the field that will be created/updated in the schema on Parse Server.\n     - parameter type: The `ParseField.FieldType` of the field that will be created/updated\n     in the schema on Parse Server.\n     - parameter target: The  target `ParseObject` of the field that will be created/updated in\n     the schema on Parse Server.\n     - parameter options: The `ParseFieldOptions` of the field that will be created/updated in\n     the schema on Parse Server.\n     - returns: A mutated instance of `ParseSchema` for easy chaining.\n     - throws: An error of type `ParseError`.\n     - warning: The use of `options` requires Parse Server 3.7.0+.\n    */\n    func addField<T>(_ name: String,\n                     type: ParseField.FieldType,\n                     options: ParseFieldOptions<T>) throws -> Self where T: ParseObject {\n        switch type {\n        case .pointer:\n            return addPointer(name, options: options)\n        case .relation:\n            return addRelation(name, options: options)\n        default:\n            throw ParseError(code: .unknownError,\n                             message: \"The type \\\"\\(type)\\\" is not supported by this method\")\n        }\n    }\n\n    /**\n     Add a Field to create/update a `ParseSchema`.\n     \n     - parameter name: Name of the field that will be created/updated in the schema on Parse Server.\n     - parameter type: The `ParseField.FieldType` of the field that will be created/updated\n     in the schema on Parse Server.\n     - parameter options: The `ParseFieldOptions` of the field that will be created/updated in\n     the schema on Parse Server.\n     - returns: A mutated instance of `ParseSchema` for easy chaining.\n     - warning: The use of `options` requires Parse Server 3.7.0+.\n    */\n    func addField<V>(_ name: String,\n                     type: ParseField.FieldType,\n                     options: ParseFieldOptions<V>) -> Self {\n        var mutableSchema = self\n        let field = ParseField(type: type, options: options)\n        if mutableSchema.fields != nil {\n            mutableSchema.fields?[name] = field\n        } else {\n            mutableSchema.fields = [name: field]\n        }\n\n        return mutableSchema\n    }\n\n    /**\n     Add a Pointer field to create/update a `ParseSchema`.\n     \n     - parameter name: Name of the field that will be created/updated in the schema on Parse Server.\n     - parameter target: The  target `ParseObject` of the field that will be created/updated in\n     the schema on Parse Server.\n     Defaults to **nil**.\n     - parameter options: The `ParseFieldOptions` of the field that will be created/updated in\n     the schema on Parse Server.\n     - returns: A mutated instance of `ParseSchema` for easy chaining.\n     - throws: An error of type `ParseError`.\n     - warning: The use of `options` requires Parse Server 3.7.0+.\n    */\n    func addPointer<T>(_ name: String,\n                       options: ParseFieldOptions<T>) -> Self where T: ParseObject {\n\n        let field = ParseField(type: .pointer, options: options)\n        var mutableSchema = self\n        if mutableSchema.fields != nil {\n            mutableSchema.fields?[name] = field\n        } else {\n            mutableSchema.fields = [name: field]\n        }\n\n        return mutableSchema\n    }\n\n    /**\n     Add a Relation field to create/update a `ParseSchema`.\n     \n     - parameter name: Name of the field that will be created/updated in the schema on Parse Server.\n     - parameter options: The `ParseFieldOptions` of the field that will be created/updated in\n     the schema on Parse Server.\n     Defaults to **nil**.\n     - returns: A mutated instance of `ParseSchema` for easy chaining.\n     - throws: An error of type `ParseError`.\n    */\n    func addRelation<T>(_ name: String,\n                        options: ParseFieldOptions<T>) -> Self where T: ParseObject {\n\n        let field = ParseField(type: .relation, options: options)\n        var mutableSchema = self\n        if mutableSchema.fields != nil {\n            mutableSchema.fields?[name] = field\n        } else {\n            mutableSchema.fields = [name: field]\n        }\n\n        return mutableSchema\n    }\n\n    /**\n     Delete a field in the `ParseSchema`.\n     \n     - parameter name: Name of the field that will be deleted in the schema on Parse Server.\n     - returns: A mutated instance of `ParseSchema` for easy chaining.\n    */\n    func deleteField(_ name: String) -> Self {\n        let field = ParseField(operation: .delete)\n        var mutableSchema = self\n        if mutableSchema.fields != nil {\n            mutableSchema.fields?[name] = field\n        } else {\n            mutableSchema.fields = [name: field]\n        }\n\n        return mutableSchema\n    }\n\n    /**\n     Add an index to create/update a `ParseSchema`.\n     \n     - parameter name: Name of the index that will be created/updated in the schema on Parse Server.\n     - parameter field: The **field** the index should be added to.\n     - parameter index: The **index** to create.\n     - returns: A mutated instance of `ParseSchema` for easy chaining.\n    */\n    func addIndex(_ name: String,\n                  field: String,\n                  index: Encodable) -> Self {\n        var mutableSchema = self\n        mutableSchema.pendingIndexes[name] = [field: AnyCodable(index)]\n        return mutableSchema\n    }\n\n    /**\n     Delete an index in the `ParseSchema`.\n     \n     - parameter name: Name of the index that will be deleted in the schema on Parse Server.\n     - returns: A mutated instance of `ParseSchema` for easy chaining.\n    */\n    func deleteIndex(_ name: String) -> Self {\n        let index = [\"__op\": AnyCodable(Operation.delete.rawValue)]\n        var mutableSchema = self\n        mutableSchema.pendingIndexes[name] = index\n        return mutableSchema\n    }\n}\n\n// MARK: Convenience\nextension ParseSchema {\n    var endpoint: API.Endpoint {\n        .schema(className: className)\n    }\n\n    var endpointPurge: API.Endpoint {\n        .purge(className: className)\n    }\n}\n\n// MARK: Fetchable\nextension ParseSchema {\n\n    /**\n     Fetches the `ParseSchema` *asynchronously* from the server and executes the given callback block.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n    */\n    public func fetch(options: API.Options = [],\n                      callbackQueue: DispatchQueue = .main,\n                      completion: @escaping (Result<Self, ParseError>) -> Void) {\n        var options = options\n        options.insert(.useMasterKey)\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        fetchCommand()\n            .executeAsync(options: options,\n                          callbackQueue: callbackQueue,\n                          completion: completion)\n    }\n\n    func fetchCommand() -> API.NonParseBodyCommand<Self, Self> {\n\n        return API.NonParseBodyCommand(method: .GET,\n                                       path: endpoint) { (data) -> Self in\n            try ParseCoding.jsonDecoder().decode(Self.self, from: data)\n        }\n    }\n}\n\n// MARK: Savable\nextension ParseSchema {\n\n    /**\n     Creates the `ParseSchema` *asynchronously* on the server and executes the given callback block.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n    */\n    public func create(options: API.Options = [],\n                       callbackQueue: DispatchQueue = .main,\n                       completion: @escaping (Result<Self, ParseError>) -> Void) {\n        var options = options\n        options.insert(.useMasterKey)\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        createCommand()\n            .executeAsync(options: options,\n                          callbackQueue: callbackQueue,\n                          completion: completion)\n    }\n\n    /**\n     Updates the `ParseSchema` *asynchronously* on the server and executes the given callback block.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Self, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n    */\n    public func update(options: API.Options = [],\n                       callbackQueue: DispatchQueue = .main,\n                       completion: @escaping (Result<Self, ParseError>) -> Void) {\n        var mutableSchema = self\n        if !mutableSchema.pendingIndexes.isEmpty {\n            mutableSchema.indexes = pendingIndexes\n        } else {\n            mutableSchema.indexes = nil\n        }\n        var options = options\n        options.insert(.useMasterKey)\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        mutableSchema.updateCommand()\n            .executeAsync(options: options,\n                          callbackQueue: callbackQueue,\n                          completion: completion)\n    }\n\n    func createCommand() -> API.NonParseBodyCommand<Self, Self> {\n        API.NonParseBodyCommand(method: .POST,\n                                       path: endpoint,\n                                       body: self) { (data) -> Self in\n            try ParseCoding.jsonDecoder().decode(Self.self, from: data)\n        }\n    }\n\n    func updateCommand() -> API.NonParseBodyCommand<Self, Self> {\n        API.NonParseBodyCommand(method: .PUT,\n                    path: endpoint,\n                    body: self) { (data) -> Self in\n            try ParseCoding.jsonDecoder().decode(Self.self, from: data)\n        }\n    }\n}\n\n// MARK: Deletable\nextension ParseSchema {\n\n    /**\n     Deletes all objects in the `ParseSchema` *asynchronously* from the server and executes the given callback block.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Void, ParseError>)`.\n     - warning: This will delete all objects for this `ParseSchema` and cannot be reversed.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n    */\n    public func purge(\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<Void, ParseError>) -> Void\n    ) {\n        var options = options\n        options.insert(.useMasterKey)\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        purgeCommand().executeAsync(options: options,\n                                        callbackQueue: callbackQueue) { result in\n            switch result {\n\n            case .success:\n                completion(.success(()))\n            case .failure(let error):\n                callbackQueue.async {\n                    completion(.failure(error))\n                }\n            }\n        }\n    }\n\n    /**\n     Deletes the `ParseSchema` *asynchronously* from the server and executes the given callback block.\n\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<Void, ParseError>)`.\n     - warning: This can only be used on a `ParseSchema` without objects. If the `ParseSchema`\n     currently contains objects, run `purge()` first.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n    */\n    public func delete(\n        options: API.Options = [],\n        callbackQueue: DispatchQueue = .main,\n        completion: @escaping (Result<Void, ParseError>) -> Void\n    ) {\n        var options = options\n        options.insert(.useMasterKey)\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        deleteCommand().executeAsync(options: options,\n                                         callbackQueue: callbackQueue) { result in\n            switch result {\n\n            case .success:\n                completion(.success(()))\n            case .failure(let error):\n                callbackQueue.async {\n                    completion(.failure(error))\n                }\n            }\n        }\n    }\n\n    func purgeCommand() -> API.NonParseBodyCommand<Self, NoBody> {\n        API.NonParseBodyCommand(method: .DELETE,\n                                path: endpointPurge) { (data) -> NoBody in\n            let error = try? ParseCoding.jsonDecoder().decode(ParseError.self, from: data)\n            if let error = error {\n                throw error\n            } else {\n                return NoBody()\n            }\n        }\n    }\n\n    func deleteCommand() -> API.NonParseBodyCommand<Self, NoBody> {\n        API.NonParseBodyCommand(method: .DELETE,\n                                path: endpoint,\n                                body: self) { (data) -> NoBody in\n            let error = try? ParseCoding.jsonDecoder().decode(ParseError.self, from: data)\n            if let error = error {\n                throw error\n            } else {\n                return NoBody()\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/ParseVersion.swift",
    "content": "//\n//  ParseVersion.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 7/1/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/// `ParseVersion` is used to determine the version of the SDK. The current\n/// version of the SDK is persisted to the Keychain.\npublic struct ParseVersion: ParseTypeable, Comparable {\n\n    var string: String\n\n    /// Current version of the SDK.\n    public internal(set) static var current: String? {\n        get {\n            guard let versionInMemory: String =\n                try? ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentVersion) else {\n                #if !os(Linux) && !os(Android) && !os(Windows)\n                    guard let versionFromKeyChain: String =\n                        try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentVersion)\n                         else {\n                        guard let versionFromKeyChain: String =\n                            try? KeychainStore.old.get(valueFor: ParseStorage.Keys.currentVersion)\n                             else {\n                            return nil\n                        }\n                        try? KeychainStore.shared.set(versionFromKeyChain, for: ParseStorage.Keys.currentVersion)\n                        return versionFromKeyChain\n                    }\n                    return versionFromKeyChain\n                #else\n                    return nil\n                #endif\n            }\n            return versionInMemory\n        }\n        set {\n            try? ParseStorage.shared.set(newValue, for: ParseStorage.Keys.currentVersion)\n            #if !os(Linux) && !os(Android) && !os(Windows)\n            try? KeychainStore.shared.set(newValue, for: ParseStorage.Keys.currentVersion)\n            #endif\n        }\n    }\n\n    init(_ string: String?) throws {\n        guard let newString = string else {\n            throw ParseError(code: .unknownError,\n                             message: \"Cannot initialize with nil value.\")\n        }\n        self.string = newString\n    }\n\n    static func deleteCurrentContainerFromKeychain() {\n        try? ParseStorage.shared.delete(valueFor: ParseStorage.Keys.currentVersion)\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try? KeychainStore.shared.delete(valueFor: ParseStorage.Keys.currentVersion)\n        #endif\n    }\n}\n\npublic extension ParseVersion {\n\n    static func > (left: ParseVersion, right: ParseVersion) -> Bool {\n        let left = left.string.split(separator: \".\").compactMap { Int($0) }\n        assert(left.count == 3, \"Left version must have 3 values, \\\"1.1.1\\\".\")\n        let right = right.string.split(separator: \".\").compactMap { Int($0) }\n        assert(right.count == 3, \"Right version must have 3 values, \\\"1.1.1\\\".\")\n        if left[0] > right[0] {\n            return true\n        } else if left[0] < right[0] {\n            return false\n        } else if left[1] > right[1] {\n            return true\n        } else if left[1] < right[1] {\n            return false\n        } else if left[2] > right[2] {\n            return true\n        } else {\n            return false\n        }\n    }\n\n    static func >= (left: ParseVersion, right: ParseVersion) -> Bool {\n        if left == right || left > right {\n            return true\n        } else {\n            return false\n        }\n    }\n\n    static func < (left: ParseVersion, right: ParseVersion) -> Bool {\n        let left = left.string.split(separator: \".\").compactMap { Int($0) }\n        assert(left.count == 3, \"Left version must have 3 values, \\\"1.1.1\\\".\")\n        let right = right.string.split(separator: \".\").compactMap { Int($0) }\n        assert(right.count == 3, \"Right version must have 3 values, \\\"1.1.1\\\".\")\n        if left[0] < right[0] {\n            return true\n        } else if left[0] > right[0] {\n            return false\n        } else if left[1] < right[1] {\n            return true\n        } else if left[1] > right[1] {\n            return false\n        } else if left[2] < right[2] {\n            return true\n        } else {\n            return false\n        }\n    }\n\n    static func <= (left: ParseVersion, right: ParseVersion) -> Bool {\n        if left == right || left < right {\n            return true\n        } else {\n            return false\n        }\n    }\n\n    static func == (left: ParseVersion, right: ParseVersion) -> Bool {\n        left.string == right.string\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/Pointer+async.swift",
    "content": "//\n//  Pointer+async.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 11/1/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n\n// MARK: Async/Await\npublic extension Pointer {\n    /**\n     Fetches the `ParseObject` *aynchronously* with the current data from the server.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: The `ParseObject` with respect to the `Pointer`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func fetch(includeKeys: [String]? = nil,\n               options: API.Options = []) async throws -> T {\n        try await withCheckedThrowingContinuation { continuation in\n            self.fetch(includeKeys: includeKeys,\n                       options: options,\n                       completion: continuation.resume)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Types/Pointer+combine.swift",
    "content": "//\n//  Pointer+combine.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 11/1/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\n// MARK: Combine\npublic extension Pointer {\n    /**\n     Fetches the `ParseObject` *aynchronously* with the current data from the server.\n     Publishes when complete.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func fetchPublisher(includeKeys: [String]? = nil,\n                        options: API.Options = []) -> Future<T, ParseError> {\n        Future { promise in\n            self.fetch(includeKeys: includeKeys,\n                       options: options,\n                       completion: promise)\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Types/Pointer.swift",
    "content": "import Foundation\n\nprotocol ParsePointer: Encodable {\n\n    var __type: String { get } // swiftlint:disable:this identifier_name\n\n    var className: String { get }\n\n    var objectId: String { get set }\n}\n\nextension ParsePointer {\n    /**\n     Determines if two objects have the same objectId.\n     - parameter as: Object to compare.\n     - returns: Returns a **true** if the other object has the same `objectId` or **false** if unsuccessful.\n    */\n    func hasSameObjectId(as other: ParsePointer) -> Bool {\n        return other.className == className && other.objectId == objectId\n    }\n}\n\nprivate func getObjectId(target: Objectable) throws -> String {\n    guard let objectId = target.objectId else {\n        throw ParseError(code: .missingObjectId, message: \"Cannot set a pointer to an unsaved object\")\n    }\n    return objectId\n}\n\n/// A Pointer referencing a ParseObject.\npublic struct Pointer<T: ParseObject>: ParsePointer, ParseTypeable, Fetchable, Hashable {\n\n    internal let __type: String = \"Pointer\" // swiftlint:disable:this identifier_name\n\n    /**\n     The class name of the object.\n    */\n    public var className: String\n\n    /**\n     The id of the object.\n    */\n    public var objectId: String\n\n    /**\n     Create a Pointer type.\n     - parameter target: Object to point to.\n     - throws: An error of type `ParseError`.\n     */\n    public init(_ target: T) throws {\n        self.objectId = try getObjectId(target: target)\n        self.className = target.className\n    }\n\n    /**\n     Create a Pointer type.\n     - parameter objectId: The id of the object.\n     */\n    public init(objectId: String) {\n        self.className = T.className\n        self.objectId = objectId\n    }\n\n    /**\n     Convert a Pointer to its respective `ParseObject`.\n     - returns: A `ParseObject` created from this Pointer.\n     */\n    public func toObject() -> T {\n        var object = T()\n        object.objectId = self.objectId\n        return object\n    }\n\n    private enum CodingKeys: String, CodingKey {\n        case __type, objectId, className // swiftlint:disable:this identifier_name\n    }\n}\n\npublic extension Pointer {\n\n    /**\n     Determines if a `ParseObject` and `Pointer`have the same `objectId`.\n     - parameter as: `ParseObject` to compare.\n     - returns: Returns a **true** if the other object has the same `objectId` or **false** if unsuccessful.\n    */\n    func hasSameObjectId(as other: T) -> Bool {\n        return other.className == className && other.objectId == objectId\n    }\n\n    /**\n     Determines if two `Pointer`'s have the same `objectId`.\n     - parameter as: `Pointer` to compare.\n     - returns: Returns a **true** if the other object has the same `objectId` or **false** if unsuccessful.\n    */\n    func hasSameObjectId(as other: Self) -> Bool {\n        return other.className == className && other.objectId == objectId\n    }\n\n    /**\n     Fetches the `ParseObject` *synchronously* with the current data from the server.\n     - parameter includeKeys: The name(s) of the key(s) to include that are\n     `ParseObject`s. Use `[\"*\"]` to include all keys. This is similar to `include` and\n     `includeAll` for `Query`.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: The `ParseObject` with respect to the `Pointer`.\n     - throws: An error of `ParseError` type.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func fetch(includeKeys: [String]? = nil,\n               options: API.Options = []) throws -> T {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        let path = API.Endpoint.object(className: className, objectId: objectId)\n        return try API.NonParseBodyCommand<NoBody, T>(method: .GET,\n                                      path: path) { (data) -> T in\n                    try ParseCoding.jsonDecoder().decode(T.self, from: data)\n        }.execute(options: options)\n    }\n\n    /**\n     Fetches the `ParseObject` *asynchronously* and executes the given callback block.\n     - parameter includeKeys: The name(s) of the key(s) to include. Use `[\"*\"]` to include\n     all keys.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - parameter callbackQueue: The queue to return to after completion. Default\n     value of .main.\n     - parameter completion: The block to execute when completed.\n     It should have the following argument signature: `(Result<T, ParseError>)`.\n     - note: The default cache policy for this method is `.reloadIgnoringLocalCacheData`. If a developer\n     desires a different policy, it should be inserted in `options`.\n    */\n    func fetch(includeKeys: [String]? = nil,\n               options: API.Options = [],\n               callbackQueue: DispatchQueue = .main,\n               completion: @escaping (Result<T, ParseError>) -> Void) {\n        var options = options\n        options.insert(.cachePolicy(.reloadIgnoringLocalCacheData))\n        let path = API.Endpoint.object(className: className, objectId: objectId)\n        API.NonParseBodyCommand<NoBody, T>(method: .GET,\n                                      path: path) { (data) -> T in\n                    try ParseCoding.jsonDecoder().decode(T.self, from: data)\n        }.executeAsync(options: options,\n                       callbackQueue: callbackQueue) { result in\n            completion(result)\n        }\n    }\n}\n\ninternal struct PointerType: ParsePointer, Codable {\n    var __type: String = \"Pointer\" // swiftlint:disable:this identifier_name\n    var className: String\n    var objectId: String\n\n    init(_ target: Objectable) throws {\n        self.objectId = try getObjectId(target: target)\n        self.className = target.className\n    }\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/Query+async.swift",
    "content": "//\n//  Query+async.swift\n//  Query+async\n//\n//  Created by Corey Baker on 8/6/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n\npublic extension Query {\n\n    // MARK: Async/Await\n\n    /**\n     Finds objects *asynchronously*.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An array of ParseObjects.\n     - throws: An error of type `ParseError`.\n    */\n    func find(options: API.Options = []) async throws -> [ResultType] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.find(options: options,\n                      completion: continuation.resume)\n        }\n    }\n\n    /**\n     Query plan information for finding objects *asynchronously*.\n     - parameter usingMongoDB: Set to **true** if your Parse Server uses MongoDB. Defaults to **false**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - note: An explain query will have many different underlying types. Since Swift is a strongly\n     typed language, a developer should specify the type expected to be decoded which will be\n     different for MongoDB and PostgreSQL. One way around this is to use a type-erased wrapper\n     such as the [AnyCodable](https://github.com/Flight-School/AnyCodable) package.\n     - returns: An array of ParseObjects.\n     - throws: An error of type `ParseError`.\n     - warning: MongoDB's **explain** does not conform to the traditional Parse Server response, so the\n     `usingMongoDB` flag needs to be set for MongoDB users. See more\n     [here](https://github.com/parse-community/parse-server/pull/7440).\n    */\n    func findExplain<U: Decodable>(usingMongoDB: Bool = false,\n                                   options: API.Options = []) async throws -> [U] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.findExplain(usingMongoDB: usingMongoDB,\n                             options: options,\n                             completion: continuation.resume)\n        }\n    }\n\n    /**\n     Retrieves *asynchronously* a complete list of `ParseObject`'s  that satisfy this query.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An array of ParseObjects.\n     - throws: An error of type `ParseError`.\n     - warning: The items are processed in an unspecified order. The query may not have any sort\n     order, and may not use limit or skip.\n    */\n    func findAll(batchLimit: Int? = nil,\n                 options: API.Options = []) async throws -> [ResultType] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.findAll(batchLimit: batchLimit,\n                         options: options,\n                         completion: continuation.resume)\n        }\n    }\n\n    /**\n     Gets an object *asynchronously*.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: The first `ParseObject`.\n     - throws: An error of type `ParseError`.\n    */\n    func first(options: API.Options = []) async throws -> ResultType {\n        try await withCheckedThrowingContinuation { continuation in\n            self.first(options: options,\n                       completion: continuation.resume)\n        }\n    }\n\n    /**\n     Query plan information for getting an object *asynchronously*.\n     - note: An explain query will have many different underlying types. Since Swift is a strongly\n     typed language, a developer should specify the type expected to be decoded which will be\n     different for MongoDB and PostgreSQL. One way around this is to use a type-erased wrapper\n     such as the [AnyCodable](https://github.com/Flight-School/AnyCodable) package.\n     - parameter usingMongoDB: Set to **true** if your Parse Server uses MongoDB. Defaults to **false**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An array of ParseObjects.\n     - throws: An error of type `ParseError`.\n     - warning: MongoDB's **explain** does not conform to the traditional Parse Server response, so the\n     `usingMongoDB` flag needs to be set for MongoDB users. See more\n     [here](https://github.com/parse-community/parse-server/pull/7440).\n    */\n    func firstExplain<U: Decodable>(usingMongoDB: Bool = false,\n                                    options: API.Options = []) async throws -> U {\n        try await withCheckedThrowingContinuation { continuation in\n            self.firstExplain(usingMongoDB: usingMongoDB,\n                              options: options,\n                              completion: continuation.resume)\n        }\n    }\n\n    /**\n     Count objects *asynchronously*.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: The count of `ParseObject`'s.\n     - throws: An error of type `ParseError`.\n    */\n    func count(options: API.Options = []) async throws -> Int {\n        try await withCheckedThrowingContinuation { continuation in\n            self.count(options: options,\n                       completion: continuation.resume)\n        }\n    }\n\n    /**\n     Query plan information for counting objects *asynchronously*.\n     - note: An explain query will have many different underlying types. Since Swift is a strongly\n     typed language, a developer should specify the type expected to be decoded which will be\n     different for MongoDB and PostgreSQL. One way around this is to use a type-erased wrapper\n     such as the [AnyCodable](https://github.com/Flight-School/AnyCodable) package.\n     - parameter usingMongoDB: Set to **true** if your Parse Server uses MongoDB. Defaults to **false**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An array of ParseObjects.\n     - throws: An error of type `ParseError`.\n     - warning: MongoDB's **explain** does not conform to the traditional Parse Server response, so the\n     `usingMongoDB` flag needs to be set for MongoDB users. See more\n     [here](https://github.com/parse-community/parse-server/pull/7440).\n    */\n    func countExplain<U: Decodable>(usingMongoDB: Bool = false,\n                                    options: API.Options = []) async throws -> [U] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.countExplain(usingMongoDB: usingMongoDB,\n                              options: options,\n                              completion: continuation.resume)\n        }\n    }\n\n    /**\n     Finds objects *asynchronously* and returns a tuple of the results which include\n     the total number of objects satisfying this query, despite limits/skip. Might be useful for pagination.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: The count of `ParseObject`'s.\n     - throws: An error of type `ParseError`.\n    */\n    func withCount(options: API.Options = []) async throws -> ([ResultType], Int) {\n        try await withCheckedThrowingContinuation { continuation in\n            self.withCount(options: options,\n                           completion: continuation.resume)\n        }\n    }\n\n    /**\n     Query plan information for withCount objects *asynchronously*.\n     - note: An explain query will have many different underlying types. Since Swift is a strongly\n     typed language, a developer should specify the type expected to be decoded which will be\n     different for mongoDB and PostgreSQL. One way around this is to use a type-erased wrapper\n     such as the [AnyCodable](https://github.com/Flight-School/AnyCodable) package.\n     - parameter usingMongoDB: Set to **true** if your Parse Server uses MongoDB. Defaults to **false**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An array of ParseObjects.\n     - throws: An error of type `ParseError`.\n     - warning: MongoDB's **explain** does not conform to the traditional Parse Server response, so the\n     `usingMongoDB` flag needs to be set for MongoDB users. See more\n     [here](https://github.com/parse-community/parse-server/pull/7440).\n    */\n    func withCountExplain<U: Decodable>(usingMongoDB: Bool = false,\n                                        options: API.Options = []) async throws -> [U] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.withCountExplain(usingMongoDB: usingMongoDB,\n                                  options: options,\n                                  completion: continuation.resume)\n        }\n    }\n\n    /**\n     Executes an aggregate query *asynchronously*.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n     - parameter pipeline: A pipeline of stages to process query.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An array of ParseObjects.\n     - throws: An error of type `ParseError`.\n    */\n    func aggregate(_ pipeline: [[String: Encodable]],\n                   options: API.Options = []) async throws -> [ResultType] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.aggregate(pipeline,\n                           options: options,\n                           completion: continuation.resume)\n        }\n    }\n\n    /**\n     Query plan information for executing an aggregate query *asynchronously*.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n     - note: An explain query will have many different underlying types. Since Swift is a strongly\n     typed language, a developer should specify the type expected to be decoded which will be\n     different for MongoDB and PostgreSQL. One way around this is to use a type-erased wrapper\n     such as the [AnyCodable](https://github.com/Flight-School/AnyCodable) package.\n     - parameter pipeline: A pipeline of stages to process query.\n     - parameter usingMongoDB: Set to **true** if your Parse Server uses MongoDB. Defaults to **false**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An array of ParseObjects.\n     - throws: An error of type `ParseError`.\n     - warning: MongoDB's **explain** does not conform to the traditional Parse Server response, so the\n     `usingMongoDB` flag needs to be set for MongoDB users. See more\n     [here](https://github.com/parse-community/parse-server/pull/7440).\n    */\n    func aggregateExplain<U: Decodable>(_ pipeline: [[String: Encodable]],\n                                        usingMongoDB: Bool = false,\n                                        options: API.Options = []) async throws -> [U] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.aggregateExplain(pipeline,\n                                  usingMongoDB: usingMongoDB,\n                                  options: options,\n                                  completion: continuation.resume)\n        }\n    }\n\n    /**\n     Executes a distinct query *asynchronously* and returns unique values when complete.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n     - parameter key: A field to find distinct values.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An array of ParseObjects.\n     - throws: An error of type `ParseError`.\n    */\n    func distinct(_ key: String,\n                  options: API.Options = []) async throws -> [ResultType] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.distinct(key,\n                          options: options,\n                          completion: continuation.resume)\n        }\n    }\n\n    /**\n     Query plan information for executing a distinct query *asynchronously* and returns unique values when complete.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n     - note: An explain query will have many different underlying types. Since Swift is a strongly\n     typed language, a developer should specify the type expected to be decoded which will be\n     different for MongoDB and PostgreSQL. One way around this is to use a type-erased wrapper\n     such as the [AnyCodable](https://github.com/Flight-School/AnyCodable) package.\n     - parameter key: A field to find distinct values.\n     - parameter usingMongoDB: Set to **true** if your Parse Server uses MongoDB. Defaults to **false**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: An array of ParseObjects.\n     - throws: An error of type `ParseError`.\n     - warning: MongoDB's **explain** does not conform to the traditional Parse Server response, so the\n     `usingMongoDB` flag needs to be set for MongoDB users. See more\n     [here](https://github.com/parse-community/parse-server/pull/7440).\n    */\n    func distinctExplain<U: Decodable>(_ key: String,\n                                       usingMongoDB: Bool = false,\n                                       options: API.Options = []) async throws -> [U] {\n        try await withCheckedThrowingContinuation { continuation in\n            self.distinctExplain(key,\n                                 usingMongoDB: usingMongoDB,\n                                 options: options,\n                                 completion: continuation.resume)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Types/Query+combine.swift",
    "content": "//\n//  Query+combine.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/29/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\nimport Foundation\nimport Combine\n\npublic extension Query {\n\n    // MARK: Combine\n\n    /**\n     Finds objects *asynchronously* and publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n    */\n    func findPublisher(options: API.Options = []) -> Future<[ResultType], ParseError> {\n        Future { promise in\n            self.find(options: options,\n                      completion: promise)\n        }\n    }\n\n    /**\n     Query plan information for finding objects *asynchronously* and publishes when complete.\n     - parameter usingMongoDB: Set to **true** if your Parse Server uses MongoDB. Defaults to **false**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - note: An explain query will have many different underlying types. Since Swift is a strongly\n     typed language, a developer should specify the type expected to be decoded which will be\n     different for MongoDB and PostgreSQL. One way around this is to use a type-erased wrapper\n     such as the [AnyCodable](https://github.com/Flight-School/AnyCodable) package.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - warning: MongoDB's **explain** does not conform to the traditional Parse Server response, so the\n     `usingMongoDB` flag needs to be set for MongoDB users. See more\n     [here](https://github.com/parse-community/parse-server/pull/7440).\n    */\n    func findExplainPublisher<U: Decodable>(usingMongoDB: Bool = false,\n                                            options: API.Options = []) -> Future<[U], ParseError> {\n        Future { promise in\n            self.findExplain(usingMongoDB: usingMongoDB,\n                             options: options,\n                             completion: promise)\n        }\n    }\n\n    /**\n     Retrieves *asynchronously* a complete list of `ParseObject`'s  that satisfy this query\n     and publishes when complete.\n     - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - warning: The items are processed in an unspecified order. The query may not have any sort\n     order, and may not use limit or skip.\n    */\n    func findAllPublisher(batchLimit: Int? = nil,\n                          options: API.Options = []) -> Future<[ResultType], ParseError> {\n        Future { promise in\n            self.findAll(batchLimit: batchLimit,\n                         options: options,\n                         completion: promise)\n        }\n    }\n\n    /**\n     Gets an object *asynchronously* and publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n    */\n    func firstPublisher(options: API.Options = []) -> Future<ResultType, ParseError> {\n        Future { promise in\n            self.first(options: options,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Query plan information for getting an object *asynchronously* and publishes when complete.\n     - note: An explain query will have many different underlying types. Since Swift is a strongly\n     typed language, a developer should specify the type expected to be decoded which will be\n     different for MongoDB and PostgreSQL. One way around this is to use a type-erased wrapper\n     such as the [AnyCodable](https://github.com/Flight-School/AnyCodable) package.\n     - parameter usingMongoDB: Set to **true** if your Parse Server uses MongoDB. Defaults to **false**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - warning: MongoDB's **explain** does not conform to the traditional Parse Server response, so the\n     `usingMongoDB` flag needs to be set for MongoDB users. See more\n     [here](https://github.com/parse-community/parse-server/pull/7440).\n    */\n    func firstExplainPublisher<U: Decodable>(usingMongoDB: Bool = false,\n                                             options: API.Options = []) -> Future<U, ParseError> {\n        Future { promise in\n            self.firstExplain(usingMongoDB: usingMongoDB,\n                              options: options,\n                              completion: promise)\n        }\n    }\n\n    /**\n     Count objects *asynchronously* and publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n    */\n    func countPublisher(options: API.Options = []) -> Future<Int, ParseError> {\n        Future { promise in\n            self.count(options: options,\n                       completion: promise)\n        }\n    }\n\n    /**\n     Query plan information for counting objects *asynchronously* and publishes when complete.\n     - note: An explain query will have many different underlying types. Since Swift is a strongly\n     typed language, a developer should specify the type expected to be decoded which will be\n     different for MongoDB and PostgreSQL. One way around this is to use a type-erased wrapper\n     such as the [AnyCodable](https://github.com/Flight-School/AnyCodable) package.\n     - parameter usingMongoDB: Set to **true** if your Parse Server uses MongoDB. Defaults to **false**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - warning: MongoDB's **explain** does not conform to the traditional Parse Server response, so the\n     `usingMongoDB` flag needs to be set for MongoDB users. See more\n     [here](https://github.com/parse-community/parse-server/pull/7440).\n    */\n    func countExplainPublisher<U: Decodable>(usingMongoDB: Bool = false,\n                                             options: API.Options = []) -> Future<[U], ParseError> {\n        Future { promise in\n            self.countExplain(usingMongoDB: usingMongoDB,\n                              options: options,\n                              completion: promise)\n        }\n    }\n\n    /**\n     Finds objects *asynchronously* and returns a tuple of the results which include\n     the total number of objects satisfying this query, despite limits/skip. Might be useful for pagination.\n     Publishes when complete.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n    */\n    func withCountPublisher(options: API.Options = []) -> Future<([ResultType], Int), ParseError> {\n        Future { promise in\n            self.withCount(options: options,\n                           completion: promise)\n        }\n    }\n\n    /**\n     Query plan information for counting objects *asynchronously* and publishes when complete.\n     - note: An explain query will have many different underlying types. Since Swift is a strongly\n     typed language, a developer should specify the type expected to be decoded which will be\n     different for mongoDB and PostgreSQL. One way around this is to use a type-erased wrapper\n     such as the [AnyCodable](https://github.com/Flight-School/AnyCodable) package.\n     - parameter usingMongoDB: Set to **true** if your Parse Server uses MongoDB. Defaults to **false**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - warning: MongoDB's **explain** does not conform to the traditional Parse Server response, so the\n     `usingMongoDB` flag needs to be set for MongoDB users. See more\n     [here](https://github.com/parse-community/parse-server/pull/7440).\n    */\n    func withCountExplainPublisher<U: Decodable>(usingMongoDB: Bool = false,\n                                                 options: API.Options = []) -> Future<[U], ParseError> {\n        Future { promise in\n            self.withCountExplain(usingMongoDB: usingMongoDB,\n                                  options: options,\n                                  completion: promise)\n        }\n    }\n\n    /**\n     Executes an aggregate query *asynchronously* and publishes when complete.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n     - parameter pipeline: A pipeline of stages to process query.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n    */\n    func aggregatePublisher(_ pipeline: [[String: Encodable]],\n                            options: API.Options = []) -> Future<[ResultType], ParseError> {\n        Future { promise in\n            self.aggregate(pipeline,\n                           options: options,\n                           completion: promise)\n        }\n    }\n\n    /**\n     Query plan information for executing an aggregate query *asynchronously* and publishes when complete.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n     - note: An explain query will have many different underlying types. Since Swift is a strongly\n     typed language, a developer should specify the type expected to be decoded which will be\n     different for MongoDB and PostgreSQL. One way around this is to use a type-erased wrapper\n     such as the [AnyCodable](https://github.com/Flight-School/AnyCodable) package.\n     - parameter pipeline: A pipeline of stages to process query.\n     - parameter usingMongoDB: Set to **true** if your Parse Server uses MongoDB. Defaults to **false**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - warning: MongoDB's **explain** does not conform to the traditional Parse Server response, so the\n     `usingMongoDB` flag needs to be set for MongoDB users. See more\n     [here](https://github.com/parse-community/parse-server/pull/7440).\n    */\n    func aggregateExplainPublisher<U: Decodable>(_ pipeline: [[String: Encodable]],\n                                                 usingMongoDB: Bool = false,\n                                                 options: API.Options = []) -> Future<[U], ParseError> {\n        Future { promise in\n            self.aggregateExplain(pipeline,\n                                  usingMongoDB: usingMongoDB,\n                                  options: options,\n                                  completion: promise)\n        }\n    }\n\n    /**\n     Executes a distinct query *asynchronously* and publishes unique values when complete.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n     - parameter key: A field to find distinct values.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n    */\n    func distinctPublisher(_ key: String,\n                           options: API.Options = []) -> Future<[ResultType], ParseError> {\n        Future { promise in\n            self.distinct(key,\n                          options: options,\n                          completion: promise)\n        }\n    }\n\n    /**\n     Query plan information for executing a distinct query *asynchronously* and publishes unique values when complete.\n     - requires: `.useMasterKey` has to be available. It is recommended to only\n     use the master key in server-side applications where the key is kept secure and not\n     exposed to the public.\n     - note: An explain query will have many different underlying types. Since Swift is a strongly\n     typed language, a developer should specify the type expected to be decoded which will be\n     different for MongoDB and PostgreSQL. One way around this is to use a type-erased wrapper\n     such as the [AnyCodable](https://github.com/Flight-School/AnyCodable) package.\n     - parameter key: A field to find distinct values.\n     - parameter usingMongoDB: Set to **true** if your Parse Server uses MongoDB. Defaults to **false**.\n     - parameter options: A set of header options sent to the server. Defaults to an empty set.\n     - returns: A publisher that eventually produces a single value and then finishes or fails.\n     - warning: MongoDB's **explain** does not conform to the traditional Parse Server response, so the\n     `usingMongoDB` flag needs to be set for MongoDB users. See more\n     [here](https://github.com/parse-community/parse-server/pull/7440).\n    */\n    func distinctExplainPublisher<U: Decodable>(_ key: String,\n                                                usingMongoDB: Bool = false,\n                                                options: API.Options = []) -> Future<[U], ParseError> {\n        Future { promise in\n            self.distinctExplain(key,\n                                 usingMongoDB: usingMongoDB,\n                                 options: options,\n                                 completion: promise)\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Types/Query.swift",
    "content": "//\n//  Query.swift\n//  Parse\n//\n//  Created by Florent Vilmart on 17-07-23.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n// MARK: Query\n/**\n  The `Query` class defines a query that is used to query for `ParseObject`s.\n*/\npublic struct Query<T>: ParseTypeable where T: ParseObject {\n    // interpolate as GET\n    private let method: String = \"GET\"\n    internal var limit: Int = 100\n    internal var skip: Int = 0\n    internal var keys: Set<String>?\n    internal var include: Set<String>?\n    internal var order: [Order]?\n    internal var isCount: Bool?\n    internal var explain: Bool?\n    internal var hint: AnyCodable?\n    internal var `where` = QueryWhere()\n    internal var excludeKeys: Set<String>?\n    internal var readPreference: String?\n    internal var includeReadPreference: String?\n    internal var subqueryReadPreference: String?\n    internal var distinct: String?\n    internal var pipeline: [[String: AnyCodable]]?\n    internal var fields: Set<String>?\n    var endpoint: API.Endpoint {\n        .objects(className: T.className)\n    }\n\n    /// The className of the `ParseObject` to query.\n    public static var className: String {\n        T.className\n    }\n\n    /// The className of the `ParseObject` to query.\n    public var className: String {\n        Self.className\n    }\n\n    struct AggregateBody<T>: Codable where T: ParseObject {\n        let pipeline: [[String: AnyCodable]]?\n        let hint: AnyCodable?\n        let explain: Bool?\n        let includeReadPreference: String?\n\n        init(query: Query<T>) {\n            pipeline = query.pipeline\n            hint = query.hint\n            explain = query.explain\n            includeReadPreference = query.includeReadPreference\n        }\n\n        func getQueryParameters() throws -> [String: String] {\n            var dictionary = [String: String]()\n            dictionary[\"explain\"] = try encodeAsString(\\.explain)\n            dictionary[\"hint\"] = try encodeAsString(\\.hint)\n            dictionary[\"includeReadPreference\"] = try encodeAsString(\\.includeReadPreference)\n            dictionary[\"pipeline\"] = try encodeAsString(\\.pipeline)\n            return dictionary\n        }\n\n        func encodeAsString<W>(_ key: KeyPath<Self, W?>) throws -> String? where W: Encodable {\n            guard let value = self[keyPath: key] else {\n                return nil\n            }\n            let encoded = try ParseCoding.jsonEncoder().encode(value)\n            return String(data: encoded, encoding: .utf8)\n        }\n    }\n\n    struct DistinctBody<T>: Codable where T: ParseObject {\n        let hint: AnyCodable?\n        let explain: Bool?\n        let includeReadPreference: String?\n        let distinct: String?\n\n        init(query: Query<T>) {\n            distinct = query.distinct\n            hint = query.hint\n            explain = query.explain\n            includeReadPreference = query.includeReadPreference\n        }\n\n        func getQueryParameters() throws -> [String: String] {\n            var dictionary = [String: String]()\n            dictionary[\"explain\"] = try encodeAsString(\\.explain)\n            dictionary[\"hint\"] = try encodeAsString(\\.hint)\n            dictionary[\"includeReadPreference\"] = try encodeAsString(\\.includeReadPreference)\n            dictionary[\"distinct\"] = try encodeAsString(\\.distinct)\n            return dictionary\n        }\n\n        func encodeAsString<W>(_ key: KeyPath<Self, W?>) throws -> String? where W: Encodable {\n            guard let value = self[keyPath: key] else {\n                return nil\n            }\n            let encoded = try ParseCoding.jsonEncoder().encode(value)\n            return String(data: encoded, encoding: .utf8)\n        }\n    }\n\n    enum CodingKeys: String, CodingKey {\n        case `where`\n        case method = \"_method\"\n        case limit\n        case skip\n        case include\n        case isCount = \"count\"\n        case keys\n        case order\n        case explain\n        case hint\n        case excludeKeys\n        case readPreference\n        case includeReadPreference\n        case subqueryReadPreference\n        case distinct\n        case pipeline\n    }\n\n    public init(from decoder: Decoder) throws {\n        let values = try decoder.container(keyedBy: CodingKeys.self)\n        `where` = try values.decode(QueryWhere.self, forKey: .`where`)\n        if let limit = try values.decodeIfPresent(Int.self, forKey: .limit) {\n            self.limit = limit\n        }\n        if let skip = try values.decodeIfPresent(Int.self, forKey: .skip) {\n            self.skip = skip\n        }\n        do {\n            keys = try values.decodeIfPresent(Set<String>.self, forKey: .keys)\n        } catch {\n            if let commaString = try values.decodeIfPresent(String.self, forKey: .keys) {\n                let commaArray = commaString\n                    .split(separator: \",\")\n                    .compactMap { String($0) }\n                keys = Set(commaArray)\n            }\n        }\n        do {\n            include = try values.decodeIfPresent(Set<String>.self, forKey: .include)\n        } catch {\n            if let commaString = try values.decodeIfPresent(String.self, forKey: .include) {\n                let commaArray = commaString\n                    .split(separator: \",\")\n                    .compactMap { String($0) }\n                include = Set(commaArray)\n            }\n        }\n        do {\n            order = try values.decodeIfPresent([Order].self, forKey: .order)\n        } catch {\n            let orderString = try values\n                .decodeIfPresent(String.self, forKey: .order)?\n                .split(separator: \",\")\n                .compactMap { String($0) }\n            order = orderString?.map {\n                var value = $0\n                if value.hasPrefix(\"-\") {\n                    value.removeFirst()\n                    return Order.descending(value)\n                } else {\n                    return Order.ascending(value)\n                }\n            }\n        }\n        do {\n            excludeKeys = try values.decodeIfPresent(Set<String>.self, forKey: .excludeKeys)\n        } catch {\n            if let commaString = try values.decodeIfPresent(String.self, forKey: .excludeKeys) {\n                let commaArray = commaString\n                    .split(separator: \",\")\n                    .compactMap { String($0) }\n                excludeKeys = Set(commaArray)\n            }\n        }\n        isCount = try values.decodeIfPresent(Bool.self, forKey: .isCount)\n        explain = try values.decodeIfPresent(Bool.self, forKey: .explain)\n        hint = try values.decodeIfPresent(AnyCodable.self, forKey: .hint)\n        readPreference = try values.decodeIfPresent(String.self, forKey: .readPreference)\n        includeReadPreference = try values.decodeIfPresent(String.self, forKey: .includeReadPreference)\n        subqueryReadPreference = try values.decodeIfPresent(String.self, forKey: .subqueryReadPreference)\n        distinct = try values.decodeIfPresent(String.self, forKey: .distinct)\n        pipeline = try values.decodeIfPresent([[String: AnyCodable]].self, forKey: .pipeline)\n    }\n\n    /**\n      An enum that determines the order to sort the results based on a given key.\n\n      - parameter key: The key to order by.\n    */\n    public enum Order: Codable, Equatable {\n        /// Sort in ascending order based on `key`.\n        case ascending(String)\n        /// Sort in descending order based on `key`.\n        case descending(String)\n\n        public func encode(to encoder: Encoder) throws {\n            var container = encoder.singleValueContainer()\n            switch self {\n            case .ascending(let value):\n                try container.encode(value)\n            case .descending(let value):\n                try container.encode(\"-\\(value)\")\n            }\n        }\n\n        public init(from decoder: Decoder) throws {\n            let values = try decoder.singleValueContainer()\n            var value = try values.decode(String.self)\n            if value.hasPrefix(\"-\") {\n                value.removeFirst()\n                self = .descending(value)\n            } else {\n                self = .ascending(value)\n            }\n        }\n    }\n\n    /**\n      Create an instance with a variadic amount constraints.\n     - parameter constraints: A variadic amount of zero or more `QueryConstraint`'s.\n     */\n    public init(_ constraints: QueryConstraint...) {\n        self.init(constraints)\n    }\n\n    /**\n      Create an instance with an array of constraints.\n     - parameter constraints: An array of `QueryConstraint`'s.\n     */\n    public init(_ constraints: [QueryConstraint]) {\n        constraints.forEach({ self.where.add($0) })\n    }\n\n    /**\n      Add any amount of variadic constraints.\n     - parameter constraints: A variadic amount of zero or more `QueryConstraint`'s.\n     - returns: The current instance of query for easy chaining.\n     */\n    public func `where`(_ constraints: QueryConstraint...) -> Query<T> {\n        self.`where`(constraints)\n    }\n\n    /**\n      Add an array of variadic constraints.\n     - parameter constraints: An array of zero or more `QueryConstraint`'s.\n     - returns: The current instance of query for easy chaining.\n     */\n    public func `where`(_ constraints: [QueryConstraint]) -> Query<T> {\n        var mutableQuery = self\n        constraints.forEach({ mutableQuery.where.add($0) })\n        return mutableQuery\n    }\n\n    /**\n     A limit on the number of objects to return. The default limit is `100`, with a\n     maximum of 1000 results being returned at a time.\n\n     - parameter value: `n` number of results to limit to.\n     - returns: The mutated instance of query for easy chaining.\n     - note: If you are calling `find` with `limit = 1`, you may find it easier to use `first` instead.\n    */\n    public func limit(_ value: Int) -> Query<T> {\n        var mutableQuery = self\n        mutableQuery.limit = value\n        return mutableQuery\n    }\n\n    /**\n     The number of objects to skip before returning any.\n     This is useful for pagination. Default is to skip zero results.\n     - parameter value: `n` number of results to skip.\n     - returns: The mutated instance of query for easy chaining.\n    */\n    public func skip(_ value: Int) -> Query<T> {\n        var mutableQuery = self\n        mutableQuery.skip = value\n        return mutableQuery\n    }\n\n    /**\n      Adds a hint to force index selection.\n      - parameter value: String or Object of index that should be used when executing query.\n      - returns: The mutated instance of query for easy chaining.\n    */\n    public func hint<U: Encodable>(_ value: U) -> Query<T> {\n        var mutableQuery = self\n        mutableQuery.hint = AnyCodable(value)\n        return mutableQuery\n    }\n\n    /**\n      Changes the read preference that the backend will use when performing the query to the database.\n      - parameter readPreference: The read preference for the main query.\n      - parameter includeReadPreference: The read preference for the queries to include pointers.\n      - parameter subqueryReadPreference: The read preference for the sub queries.\n      - returns: The mutated instance of query for easy chaining.\n    */\n    public func readPreference(_ readPreference: String?,\n                               includeReadPreference: String? = nil,\n                               subqueryReadPreference: String? = nil) -> Query<T> {\n        var mutableQuery = self\n        mutableQuery.readPreference = readPreference\n        mutableQuery.includeReadPreference = includeReadPreference\n        mutableQuery.subqueryReadPreference = subqueryReadPreference\n        return mutableQuery\n    }\n\n    /**\n     Make the query include `ParseObject`s that have a reference stored at the provided keys.\n     If this is called multiple times, then all of the keys specified in each of the calls will be included.\n     - parameter keys: A variadic list of keys to load child `ParseObject`s for.\n     - returns: The mutated instance of query for easy chaining.\n     */\n    public func include(_ keys: String...) -> Query<T> {\n        self.include(keys)\n    }\n\n    /**\n     Make the query include `ParseObject`s that have a reference stored at the provided keys.\n     If this is called multiple times, then all of the keys specified in each of the calls will be included.\n     - parameter keys: An array of keys to load child `ParseObject`s for.\n     - returns: The mutated instance of query for easy chaining.\n     */\n    public func include(_ keys: [String]) -> Query<T> {\n        var mutableQuery = self\n        if mutableQuery.include != nil {\n            mutableQuery.include = mutableQuery.include?.union(keys)\n        } else {\n            mutableQuery.include = Set(keys)\n        }\n        return mutableQuery\n    }\n\n    /**\n     Includes all nested `ParseObject`s one level deep.\n     - warning: Requires Parse Server 3.0.0+.\n     - returns: The mutated instance of query for easy chaining.\n     */\n    public func includeAll() -> Query<T> {\n        var mutableQuery = self\n        if mutableQuery.include != nil {\n            mutableQuery.include?.insert(ParseConstants.includeAllKey)\n        } else {\n            mutableQuery.include = [ParseConstants.includeAllKey]\n        }\n        return mutableQuery\n    }\n\n    /**\n     Exclude specific keys for a `ParseObject`.\n     If this is called multiple times, then all of the keys specified in each of the calls will be excluded.\n     - parameter keys: A variadic list of keys include in the result.\n     - returns: The mutated instance of query for easy chaining.\n     - warning: Requires Parse Server 5.0.0+.\n     */\n    public func exclude(_ keys: String...) -> Query<T> {\n        self.exclude(keys)\n    }\n\n    /**\n     Exclude specific keys for a `ParseObject`.\n     If this is called multiple times, then all of the keys specified in each of the calls will be excluded.\n     - parameter keys: An array of keys to exclude in the result.\n     - returns: The mutated instance of query for easy chaining.\n     - warning: Requires Parse Server 5.0.0+.\n    */\n    public func exclude(_ keys: [String]) -> Query<T> {\n        var mutableQuery = self\n        if mutableQuery.excludeKeys != nil {\n            mutableQuery.excludeKeys = mutableQuery.excludeKeys?.union(keys)\n        } else {\n            mutableQuery.excludeKeys = Set(keys)\n        }\n        return mutableQuery\n    }\n\n    /**\n     Make the query restrict the fields of the returned `ParseObject`s to include only the provided keys.\n     If this is called multiple times, then all of the keys specified in each of the calls will be included.\n     - parameter keys: A variadic list of keys to include in the result.\n     - returns: The mutated instance of query for easy chaining.\n     - warning: Requires Parse Server 5.0.0+.\n     - note: When using the `Query` for `ParseLiveQuery`, setting `fields` will take precedence\n     over `select`. If `fields` are not set, the `select` keys will be used.\n     */\n    public func select(_ keys: String...) -> Query<T> {\n        self.select(keys)\n    }\n\n    /**\n     Make the query restrict the fields of the returned `ParseObject`s to include only the provided keys.\n     If this is called multiple times, then all of the keys specified in each of the calls will be included.\n     - parameter keys: An array of keys to include in the result.\n     - returns: The mutated instance of query for easy chaining.\n     - warning: Requires Parse Server 5.0.0+.\n     - note: When using the `Query` for `ParseLiveQuery`, setting `fields` will take precedence\n     over `select`. If `fields` are not set, the `select` keys will be used.\n     */\n    public func select(_ keys: [String]) -> Query<T> {\n        var mutableQuery = self\n        if mutableQuery.keys != nil {\n            mutableQuery.keys = mutableQuery.keys?.union(keys)\n        } else {\n            mutableQuery.keys = Set(keys)\n        }\n        return mutableQuery\n    }\n\n    /**\n     Sort the results of the query based on the `Order` enum.\n      - parameter keys: A variadic list of keys to order by.\n      - returns: The mutated instance of query for easy chaining.\n    */\n    public func order(_ keys: Order...) -> Query<T> {\n        self.order(keys)\n    }\n\n    /**\n     Sort the results of the query based on the `Order` enum.\n      - parameter keys: An array of keys to order by.\n      - returns: The mutated instance of query for easy chaining.\n    */\n    public func order(_ keys: [Order]?) -> Query<T> {\n        var mutableQuery = self\n        mutableQuery.order = keys\n        return mutableQuery\n    }\n\n    /**\n     A variadic list of selected fields to receive updates on when the `Query` is used as a\n     `ParseLiveQuery`.\n     \n     Suppose the `ParseObject` Player contains three fields name, id and age.\n     If you are only interested in the change of the name field, you can set `query.fields` to \"name\".\n     In this situation, when the change of a Player `ParseObject` fulfills the subscription, only the\n     name field will be sent to the clients instead of the full Player `ParseObject`.\n     If this is called multiple times, then all of the keys specified in each of the calls will be received.\n     - note: Setting `fields` will take precedence over `select`. If `fields` are not set, the\n     `select` keys will be used.\n     - warning: This is only for `ParseLiveQuery`.\n     - parameter keys: A variadic list of fields to receive back instead of the whole `ParseObject`.\n     - returns: The mutated instance of query for easy chaining.\n     */\n    public func fields(_ keys: String...) -> Query<T> {\n        self.fields(keys)\n    }\n\n    /**\n     A list of fields to receive updates on when the `Query` is used as a\n     `ParseLiveQuery`.\n     \n     Suppose the `ParseObject` Player contains three fields name, id and age.\n     If you are only interested in the change of the name field, you can set `query.fields` to \"name\".\n     In this situation, when the change of a Player `ParseObject` fulfills the subscription, only the\n     name field will be sent to the clients instead of the full Player `ParseObject`.\n     If this is called multiple times, then all of the keys specified in each of the calls will be received.\n     - note: Setting `fields` will take precedence over `select`. If `fields` are not set, the\n     `select` keys will be used.\n     - warning: This is only for `ParseLiveQuery`.\n     - parameter keys: An array of fields to receive back instead of the whole `ParseObject`.\n     - returns: The mutated instance of query for easy chaining.\n     */\n    public func fields(_ keys: [String]) -> Query<T> {\n        var mutableQuery = self\n        if mutableQuery.fields != nil {\n            mutableQuery.fields = mutableQuery.fields?.union(keys)\n        } else {\n            mutableQuery.fields = Set(keys)\n        }\n        return mutableQuery\n    }\n}\n\n// MARK: Queryable\nextension Query: Queryable {\n\n    public typealias ResultType = T\n\n    /**\n      Finds objects *synchronously* based on the constructed query and sets an error if there was one.\n\n      - parameter options: A set of header options sent to the server. Defaults to an empty set.\n      - throws: An error of type `ParseError`.\n\n      - returns: Returns an array of `ParseObject`s that were found.\n    */\n    public func find(options: API.Options = []) throws -> [ResultType] {\n        if limit == 0 {\n            return [ResultType]()\n        }\n        return try findCommand().execute(options: options)\n    }\n\n    /**\n      Query plan information for finding objects *synchronously* based on the constructed query and\n        sets an error if there was one.\n      - note: An explain query will have many different underlying types. Since Swift is a strongly\n      typed language, a developer should specify the type expected to be decoded which will be\n      different for MongoDB and PostgreSQL. One way around this is to use a type-erased wrapper\n      such as the [AnyCodable](https://github.com/Flight-School/AnyCodable) package.\n      - parameter usingMongoDB: Set to **true** if your Parse Server uses MongoDB. Defaults to **false**.\n      - parameter options: A set of header options sent to the server. Defaults to an empty set.\n      - throws: An error of type `ParseError`.\n      - returns: Returns a response of `Decodable` type.\n      - warning: MongoDB's **explain** does not conform to the traditional Parse Server response, so the\n      `usingMongoDB` flag needs to be set for MongoDB users. See more\n      [here](https://github.com/parse-community/parse-server/pull/7440).\n    */\n    public func findExplain<U: Decodable>(usingMongoDB: Bool = false,\n                                          options: API.Options = []) throws -> [U] {\n        if limit == 0 {\n            return [U]()\n        }\n        if !usingMongoDB {\n            return try findExplainCommand().execute(options: options)\n        } else {\n            return try findExplainMongoCommand().execute(options: options)\n        }\n    }\n\n    /**\n      Finds objects *asynchronously* and returns a completion block with the results.\n\n      - parameter options: A set of header options sent to the server. Defaults to an empty set.\n      - parameter callbackQueue: The queue to return to after completion. Default value of `.main`.\n      - parameter completion: The block to execute.\n      It should have the following argument signature: `(Result<[ResultType], ParseError>)`.\n    */\n    public func find(options: API.Options = [],\n                     callbackQueue: DispatchQueue = .main,\n                     completion: @escaping (Result<[ResultType], ParseError>) -> Void) {\n        if limit == 0 {\n            callbackQueue.async {\n                completion(.success([ResultType]()))\n            }\n            return\n        }\n        do {\n            try findCommand().executeAsync(options: options,\n                                           callbackQueue: callbackQueue) { result in\n                completion(result)\n            }\n        } catch {\n            let parseError = ParseError(code: .unknownError,\n                                        message: error.localizedDescription)\n            callbackQueue.async {\n                completion(.failure(parseError))\n            }\n        }\n    }\n\n    /**\n     Query plan information for finding objects *asynchronously* and returns a completion block with the results.\n      - note: An explain query will have many different underlying types. Since Swift is a strongly\n      typed language, a developer should specify the type expected to be decoded which will be\n      different for MongoDB and PostgreSQL. One way around this is to use a type-erased wrapper\n      such as the [AnyCodable](https://github.com/Flight-School/AnyCodable) package.\n      - parameter usingMongoDB: Set to **true** if your Parse Server uses MongoDB. Defaults to **false**.\n      - parameter options: A set of header options sent to the server. Defaults to an empty set.\n      - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n      - parameter completion: The block to execute.\n      It should have the following argument signature: `(Result<[Decodable], ParseError>)`.\n      - warning: MongoDB's **explain** does not conform to the traditional Parse Server response, so the\n      `usingMongoDB` flag needs to be set for MongoDB users. See more\n      [here](https://github.com/parse-community/parse-server/pull/7440).\n    */\n    public func findExplain<U: Decodable>(usingMongoDB: Bool = false,\n                                          options: API.Options = [],\n                                          callbackQueue: DispatchQueue = .main,\n                                          completion: @escaping (Result<[U], ParseError>) -> Void) {\n        if limit == 0 {\n            callbackQueue.async {\n                completion(.success([U]()))\n            }\n            return\n        }\n        if !usingMongoDB {\n            do {\n                try findExplainCommand().executeAsync(options: options,\n                                                      callbackQueue: callbackQueue) { result in\n                    completion(result)\n                }\n            } catch {\n                let parseError = ParseError(code: .unknownError,\n                                            message: error.localizedDescription)\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        } else {\n            do {\n                try findExplainMongoCommand().executeAsync(options: options,\n                                                           callbackQueue: callbackQueue) { result in\n                    completion(result)\n                }\n            } catch {\n                let parseError = ParseError(code: .unknownError,\n                                            message: error.localizedDescription)\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n    }\n\n    /**\n     Retrieves *asynchronously* a complete list of `ParseObject`'s  that satisfy this query.\n        \n      - parameter batchLimit: The maximum number of objects to send in each batch. If the items to be batched.\n         is greater than the `batchLimit`, the objects will be sent to the server in waves up to the `batchLimit`.\n         Defaults to 50.\n      - parameter options: A set of header options sent to the server. Defaults to an empty set.\n      - parameter callbackQueue: The queue to return to after completion. Default value of .main.\n      - parameter completion: The block to execute.\n      It should have the following argument signature: `(Result<[Decodable], ParseError>)`.\n     - warning: The items are processed in an unspecified order. The query may not have any sort\n     order, and may not use limit or skip.\n    */\n    public func findAll(batchLimit limit: Int? = nil,\n                        options: API.Options = [],\n                        callbackQueue: DispatchQueue = .main,\n                        completion: @escaping (Result<[ResultType], ParseError>) -> Void) {\n        if self.limit == 0 {\n            callbackQueue.async {\n                completion(.success([ResultType]()))\n            }\n            return\n        }\n        if order != nil || skip > 0 || self.limit != 100 {\n            let error = ParseError(code: .unknownError,\n                             message: \"Cannot iterate on a query with sort, skip, or limit.\")\n            completion(.failure(error))\n            return\n        }\n        let uuid = UUID()\n        let queue = DispatchQueue(label: \"com.parse.findAll.\\(uuid)\",\n                                  qos: .default,\n                                  attributes: .concurrent,\n                                  autoreleaseFrequency: .inherit,\n                                  target: nil)\n        queue.sync {\n\n            var query = self\n                .order([.ascending(\"objectId\")])\n            query.limit = limit ?? ParseConstants.batchLimit\n            var results = [ResultType]()\n            var finished = false\n\n            while !finished {\n                do {\n                    let currentResults = try query.findCommand().execute(options: options)\n                    results.append(contentsOf: currentResults)\n                    if currentResults.count >= query.limit {\n                        guard let lastObjectId = results[results.count - 1].objectId else {\n                            throw ParseError(code: .unknownError, message: \"Last object should have an id.\")\n                        }\n                        query.where.add(\"objectId\" > lastObjectId)\n                    } else {\n                        finished = true\n                    }\n                } catch {\n                    let defaultError = ParseError(code: .unknownError,\n                                                  message: error.localizedDescription)\n                    let parseError = error as? ParseError ?? defaultError\n                    callbackQueue.async {\n                        completion(.failure(parseError))\n                    }\n                    return\n                }\n            }\n\n            callbackQueue.async {\n                completion(.success(results))\n            }\n        }\n    }\n\n    /**\n      Gets an object *synchronously* based on the constructed query and sets an error if any occurred.\n\n      - warning: This method mutates the query. It will reset the limit to `1`.\n      - parameter options: A set of header options sent to the server. Defaults to an empty set.\n      - throws: An error of type `ParseError`.\n\n      - returns: Returns a `ParseObject`.\n    */\n    public func first(options: API.Options = []) throws -> ResultType {\n        if limit == 0 {\n            throw ParseError(code: .objectNotFound,\n                             message: \"Object not found on the server.\")\n        }\n        return try firstCommand().execute(options: options)\n    }\n\n    /**\n     Query plan information for getting an object *synchronously* based on the\n     constructed query and sets an error if any occurred.\n\n      - warning: This method mutates the query. It will reset the limit to `1`.\n      - note: An explain query will have many different underlying types. Since Swift is a strongly\n      typed language, a developer should specify the type expected to be decoded which will be\n      different for MongoDB and PostgreSQL. One way around this is to use a type-erased wrapper\n      such as the [AnyCodable](https://github.com/Flight-School/AnyCodable) package.\n      - parameter usingMongoDB: Set to **true** if your Parse Server uses MongoDB. Defaults to **false**.\n      - parameter options: A set of header options sent to the server. Defaults to an empty set.\n      - throws: An error of type `ParseError`.\n      - returns: Returns a response of `Decodable` type.\n      - warning: MongoDB's **explain** does not conform to the traditional Parse Server response, so the\n      `usingMongoDB` flag needs to be set for MongoDB users. See more\n      [here](https://github.com/parse-community/parse-server/pull/7440).\n    */\n    public func firstExplain<U: Decodable>(usingMongoDB: Bool = false,\n                                           options: API.Options = []) throws -> U {\n        if limit == 0 {\n            throw ParseError(code: .objectNotFound,\n                             message: \"Object not found on the server.\")\n        }\n        if !usingMongoDB {\n            return try firstExplainCommand().execute(options: options)\n        } else {\n            return try firstExplainMongoCommand().execute(options: options)\n        }\n    }\n\n    /**\n      Gets an object *asynchronously* and calls the given block with the result.\n\n      - warning: This method mutates the query. It will reset the limit to `1`.\n      - parameter options: A set of header options sent to the server. Defaults to an empty set.\n      - parameter callbackQueue: The queue to return to after completion. Default value of `.main`.\n      - parameter completion: The block to execute.\n      It should have the following argument signature: `(Result<ParseObject, ParseError>)`.\n    */\n    public func first(options: API.Options = [],\n                      callbackQueue: DispatchQueue = .main,\n                      completion: @escaping (Result<ResultType, ParseError>) -> Void) {\n        if limit == 0 {\n            let error = ParseError(code: .objectNotFound,\n                                   message: \"Object not found on the server.\")\n            callbackQueue.async {\n                completion(.failure(error))\n            }\n            return\n        }\n        do {\n            try firstCommand().executeAsync(options: options,\n                                            callbackQueue: callbackQueue) { result in\n                completion(result)\n            }\n        } catch {\n            let parseError = ParseError(code: .unknownError,\n                                        message: error.localizedDescription)\n            callbackQueue.async {\n                completion(.failure(parseError))\n            }\n        }\n    }\n\n    /**\n     Query plan information for getting an object *asynchronously* and returns a completion block with the result.\n\n      - warning: This method mutates the query. It will reset the limit to `1`.\n      - note: An explain query will have many different underlying types. Since Swift is a strongly\n      typed language, a developer should specify the type expected to be decoded which will be\n      different for MongoDB and PostgreSQL. One way around this is to use a type-erased wrapper\n      such as the [AnyCodable](https://github.com/Flight-School/AnyCodable) package.\n      - parameter usingMongoDB: Set to **true** if your Parse Server uses MongoDB. Defaults to **false**.\n      - parameter options: A set of header options sent to the server. Defaults to an empty set.\n      - parameter callbackQueue: The queue to return to after completion. Default value of `.main`.\n      - parameter completion: The block to execute.\n      It should have the following argument signature: `(Result<Decodable, ParseError>)`.\n      - warning: MongoDB's **explain** does not conform to the traditional Parse Server response, so the\n      `usingMongoDB` flag needs to be set for MongoDB users. See more\n      [here](https://github.com/parse-community/parse-server/pull/7440).\n    */\n    public func firstExplain<U: Decodable>(usingMongoDB: Bool = false,\n                                           options: API.Options = [],\n                                           callbackQueue: DispatchQueue = .main,\n                                           completion: @escaping (Result<U, ParseError>) -> Void) {\n        if limit == 0 {\n            let error = ParseError(code: .objectNotFound,\n                                   message: \"Object not found on the server.\")\n            callbackQueue.async {\n                completion(.failure(error))\n            }\n            return\n        }\n        if !usingMongoDB {\n            do {\n                try firstExplainCommand().executeAsync(options: options,\n                                                       callbackQueue: callbackQueue) { result in\n                    completion(result)\n                }\n            } catch {\n                let parseError = ParseError(code: .unknownError,\n                                            message: error.localizedDescription)\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        } else {\n            do {\n                try firstExplainMongoCommand().executeAsync(options: options,\n                                                            callbackQueue: callbackQueue) { result in\n                    completion(result)\n                }\n            } catch {\n                let parseError = ParseError(code: .unknownError,\n                                            message: error.localizedDescription)\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n    }\n\n    /**\n      Counts objects *synchronously* based on the constructed query and sets an error if there was one.\n\n      - parameter options: A set of header options sent to the server. Defaults to an empty set.\n      - throws: An error of type `ParseError`.\n      - returns: Returns the number of `ParseObject`s that match the query, or `-1` if there is an error.\n    */\n    public func count(options: API.Options = []) throws -> Int {\n        if limit == 0 {\n            return 0\n        }\n        return try countCommand().execute(options: options)\n    }\n\n    /**\n     Query plan information for counting objects *synchronously* based on the\n     constructed query and sets an error if there was one.\n      - note: An explain query will have many different underlying types. Since Swift is a strongly\n      typed language, a developer should specify the type expected to be decoded which will be\n      different for MongoDB and PostgreSQL. One way around this is to use a type-erased wrapper\n      such as the [AnyCodable](https://github.com/Flight-School/AnyCodable) package.\n      - parameter usingMongoDB: Set to **true** if your Parse Server uses MongoDB. Defaults to **false**.\n      - parameter options: A set of header options sent to the server. Defaults to an empty set.\n      - throws: An error of type `ParseError`.\n      - returns: Returns a response of `Decodable` type.\n      - warning: MongoDB's **explain** does not conform to the traditional Parse Server response, so the\n      `usingMongoDB` flag needs to be set for MongoDB users. See more\n      [here](https://github.com/parse-community/parse-server/pull/7440).\n    */\n    public func countExplain<U: Decodable>(usingMongoDB: Bool = false,\n                                           options: API.Options = []) throws -> [U] {\n        if limit == 0 {\n            return [U]()\n        }\n        if !usingMongoDB {\n            return try countExplainCommand().execute(options: options)\n        } else {\n            return try countExplainMongoCommand().execute(options: options)\n        }\n    }\n\n    /**\n      Counts objects *asynchronously* and returns a completion block with the count.\n\n      - parameter options: A set of header options sent to the server. Defaults to an empty set.\n      - parameter callbackQueue: The queue to return to after completion. Default value of `.main`.\n      - parameter completion: The block to execute.\n      It should have the following argument signature: `(Result<Int, ParseError>)`\n    */\n    public func count(options: API.Options = [],\n                      callbackQueue: DispatchQueue = .main,\n                      completion: @escaping (Result<Int, ParseError>) -> Void) {\n        if limit == 0 {\n            callbackQueue.async {\n                completion(.success(0))\n            }\n            return\n        }\n        do {\n            try countCommand().executeAsync(options: options,\n                                            callbackQueue: callbackQueue) { result in\n                completion(result)\n            }\n        } catch {\n            let parseError = ParseError(code: .unknownError,\n                                        message: error.localizedDescription)\n            callbackQueue.async {\n                completion(.failure(parseError))\n            }\n        }\n    }\n\n    /**\n     Query plan information for counting objects *asynchronously* and returns a completion block with the count.\n      - note: An explain query will have many different underlying types. Since Swift is a strongly\n      typed language, a developer should specify the type expected to be decoded which will be\n      different for MongoDB and PostgreSQL. One way around this is to use a type-erased wrapper\n      such as the [AnyCodable](https://github.com/Flight-School/AnyCodable) package.\n      - parameter usingMongoDB: Set to **true** if your Parse Server uses MongoDB. Defaults to **false**.\n      - parameter options: A set of header options sent to the server. Defaults to an empty set.\n      - parameter callbackQueue: The queue to return to after completion. Default value of `.main`.\n      - parameter completion: The block to execute.\n      It should have the following argument signature: `(Result<Decodable, ParseError>)`.\n      - warning: MongoDB's **explain** does not conform to the traditional Parse Server response, so the\n      `usingMongoDB` flag needs to be set for MongoDB users. See more\n      [here](https://github.com/parse-community/parse-server/pull/7440).\n    */\n    public func countExplain<U: Decodable>(usingMongoDB: Bool = false,\n                                           options: API.Options = [],\n                                           callbackQueue: DispatchQueue = .main,\n                                           completion: @escaping (Result<[U], ParseError>) -> Void) {\n        if limit == 0 {\n            callbackQueue.async {\n                completion(.success([U]()))\n            }\n            return\n        }\n        if !usingMongoDB {\n            do {\n                try countExplainCommand().executeAsync(options: options,\n                                                       callbackQueue: callbackQueue) { result in\n                    completion(result)\n                }\n            } catch {\n                let parseError = ParseError(code: .unknownError,\n                                            message: error.localizedDescription)\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        } else {\n            do {\n                try countExplainMongoCommand().executeAsync(options: options,\n                                                            callbackQueue: callbackQueue) { result in\n                    completion(result)\n                }\n            } catch {\n                let parseError = ParseError(code: .unknownError,\n                                            message: error.localizedDescription)\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n    }\n\n    /**\n     Finds objects *asynchronously* and returns a completion block with the results which include\n     the total number of objects satisfying this query, despite limits/skip. Might be useful for pagination.\n\n      - parameter options: A set of header options sent to the server. Defaults to an empty set.\n      - parameter callbackQueue: The queue to return to after completion. Default value of `.main`.\n      - parameter completion: The block to execute.\n      It should have the following argument signature: `(Result<([ResultType], Int), ParseError>)`\n    */\n    public func withCount(options: API.Options = [],\n                          callbackQueue: DispatchQueue = .main,\n                          completion: @escaping (Result<([ResultType], Int), ParseError>) -> Void) {\n        if limit == 0 {\n            callbackQueue.async {\n                completion(.success(([], 0)))\n            }\n            return\n        }\n        do {\n            try withCountCommand().executeAsync(options: options,\n                                                callbackQueue: callbackQueue) { result in\n                completion(result)\n            }\n        } catch {\n            let parseError = ParseError(code: .unknownError,\n                                        message: error.localizedDescription)\n            callbackQueue.async {\n                completion(.failure(parseError))\n            }\n        }\n    }\n\n    /**\n     Query plan information for withCount objects *asynchronously* and a completion block with the results.\n      - note: An explain query will have many different underlying types. Since Swift is a strongly\n      typed language, a developer should specify the type expected to be decoded which will be\n      different for mongoDB and PostgreSQL. One way around this is to use a type-erased wrapper\n      such as the [AnyCodable](https://github.com/Flight-School/AnyCodable) package.\n      - parameter usingMongoDB: Set to **true** if your Parse Server uses MongoDB. Defaults to **false**.\n      - parameter options: A set of header options sent to the server. Defaults to an empty set.\n      - parameter callbackQueue: The queue to return to after completion. Default value of `.main`.\n      - parameter completion: The block to execute.\n      It should have the following argument signature: `(Result<Decodable, ParseError>)`.\n      - warning: MongoDB's **explain** does not conform to the traditional Parse Server response, so the\n      `usingMongoDB` flag needs to be set for MongoDB users. See more\n      [here](https://github.com/parse-community/parse-server/pull/7440).\n    */\n    public func withCountExplain<U: Decodable>(usingMongoDB: Bool = false,\n                                               options: API.Options = [],\n                                               callbackQueue: DispatchQueue = .main,\n                                               completion: @escaping (Result<[U], ParseError>) -> Void) {\n        if limit == 0 {\n            callbackQueue.async {\n                completion(.success([U]()))\n            }\n            return\n        }\n        if !usingMongoDB {\n            do {\n                try withCountExplainCommand().executeAsync(options: options,\n                                                           callbackQueue: callbackQueue) { result in\n                    completion(result)\n                }\n            } catch {\n                let parseError = ParseError(code: .unknownError,\n                                            message: error.localizedDescription)\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        } else {\n            do {\n                try withCountExplainMongoCommand().executeAsync(options: options,\n                                                            callbackQueue: callbackQueue) { result in\n                    completion(result)\n                }\n            } catch {\n                let parseError = ParseError(code: .unknownError,\n                                            message: error.localizedDescription)\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n    }\n\n    /**\n     Executes an aggregate query *synchronously*.\n      - requires: `.useMasterKey` has to be available. It is recommended to only\n        use the master key in server-side applications where the key is kept secure and not\n        exposed to the public.\n      - parameter pipeline: A pipeline of stages to process query.\n      - parameter options: A set of header options sent to the server. Defaults to an empty set.\n      - throws: An error of type `ParseError`.\n      - warning: This has not been tested thoroughly.\n      - returns: Returns the `ParseObject`s that match the query.\n    */\n    public func aggregate(_ pipeline: [[String: Encodable]],\n                          options: API.Options = []) throws -> [ResultType] {\n        if limit == 0 {\n            return [ResultType]()\n        }\n        var options = options\n        options.insert(.useMasterKey)\n\n        var updatedPipeline = [[String: AnyCodable]]()\n        pipeline.forEach { updatedPipeline = $0.map { [$0.key: AnyCodable($0.value)] } }\n\n        guard let encoded = try? ParseCoding.jsonEncoder()\n                .encode(self.`where`),\n            let whereString = String(data: encoded, encoding: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Cannot decode where to String.\")\n        }\n        var query = self\n        query.`where` = QueryWhere()\n\n        if whereString != \"{}\" {\n            var finishedPipeline = [[\"match\": AnyCodable(whereString)]]\n            finishedPipeline.append(contentsOf: updatedPipeline)\n            query.pipeline = finishedPipeline\n        } else {\n            query.pipeline = updatedPipeline\n        }\n\n        return try query.aggregateCommand()\n            .execute(options: options)\n    }\n\n    /**\n      Executes an aggregate query *asynchronously*.\n        - requires: `.useMasterKey` has to be available. It is recommended to only\n        use the master key in server-side applications where the key is kept secure and not\n        exposed to the public.\n        - parameter pipeline: A pipeline of stages to process query.\n        - parameter options: A set of header options sent to the server. Defaults to an empty set.\n        - parameter callbackQueue: The queue to return to after completion. Default value of `.main`.\n        - parameter completion: The block to execute.\n      It should have the following argument signature: `(Result<[ParseObject], ParseError>)`.\n        - warning: This has not been tested thoroughly.\n    */\n    public func aggregate(_ pipeline: [[String: Encodable]],\n                          options: API.Options = [],\n                          callbackQueue: DispatchQueue = .main,\n                          completion: @escaping (Result<[ResultType], ParseError>) -> Void) {\n        if limit == 0 {\n            callbackQueue.async {\n                completion(.success([ResultType]()))\n            }\n            return\n        }\n        var options = options\n        options.insert(.useMasterKey)\n\n        var updatedPipeline = [[String: AnyCodable]]()\n        pipeline.forEach { updatedPipeline = $0.map { [$0.key: AnyCodable($0.value)] } }\n\n        guard let encoded = try? ParseCoding.jsonEncoder()\n                .encode(self.`where`),\n            let whereString = String(data: encoded, encoding: .utf8) else {\n            let error = ParseError(code: .unknownError, message: \"Cannot decode where to String.\")\n            callbackQueue.async {\n                completion(.failure(error))\n            }\n            return\n        }\n\n        var query = self\n        query.`where` = QueryWhere()\n\n        if whereString != \"{}\" {\n            var finishedPipeline = [[\"match\": AnyCodable(whereString)]]\n            finishedPipeline.append(contentsOf: updatedPipeline)\n            query.pipeline = finishedPipeline\n        } else {\n            query.pipeline = updatedPipeline\n        }\n        do {\n            try query.aggregateCommand()\n                .executeAsync(options: options,\n                              callbackQueue: callbackQueue) { result in\n                    completion(result)\n            }\n        } catch {\n            let parseError = ParseError(code: .unknownError,\n                                        message: error.localizedDescription)\n            callbackQueue.async {\n                completion(.failure(parseError))\n            }\n        }\n    }\n\n    /**\n     Query plan information for  executing an aggregate query *synchronously*.\n      - requires: `.useMasterKey` has to be available. It is recommended to only\n      use the master key in server-side applications where the key is kept secure and not\n      exposed to the public.\n      - note: An explain query will have many different underlying types. Since Swift is a strongly\n      typed language, a developer should specify the type expected to be decoded which will be\n      different for MongoDB and PostgreSQL. One way around this is to use a type-erased wrapper\n      such as the [AnyCodable](https://github.com/Flight-School/AnyCodable) package.\n      - parameter pipeline: A pipeline of stages to process query.\n      - parameter usingMongoDB: Set to **true** if your Parse Server uses MongoDB. Defaults to **false**.\n      - parameter options: A set of header options sent to the server. Defaults to an empty set.\n      - throws: An error of type `ParseError`.\n      - returns: Returns the `ParseObject`s that match the query.\n      - warning: MongoDB's **explain** does not conform to the traditional Parse Server response, so the\n      `usingMongoDB` flag needs to be set for MongoDB users. See more\n      [here](https://github.com/parse-community/parse-server/pull/7440).\n    */\n    public func aggregateExplain<U: Decodable>(_ pipeline: [[String: Encodable]],\n                                               usingMongoDB: Bool = false,\n                                               options: API.Options = []) throws -> [U] {\n        if limit == 0 {\n            return [U]()\n        }\n        var options = options\n        options.insert(.useMasterKey)\n\n        var updatedPipeline = [[String: AnyCodable]]()\n        pipeline.forEach { updatedPipeline = $0.map { [$0.key: AnyCodable($0.value)] } }\n\n        guard let encoded = try? ParseCoding.jsonEncoder()\n                .encode(self.`where`),\n            let whereString = String(data: encoded, encoding: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Cannot decode where to String.\")\n        }\n        var query = self\n        query.`where` = QueryWhere()\n\n        if whereString != \"{}\" {\n            var finishedPipeline = [[\"match\": AnyCodable(whereString)]]\n            finishedPipeline.append(contentsOf: updatedPipeline)\n            query.pipeline = finishedPipeline\n        } else {\n            query.pipeline = updatedPipeline\n        }\n        if !usingMongoDB {\n            return try query.aggregateExplainCommand()\n                .execute(options: options)\n        } else {\n            return try query.aggregateExplainMongoCommand()\n                .execute(options: options)\n        }\n    }\n\n    /**\n     Query plan information for executing an aggregate query *asynchronously*.\n        - requires: `.useMasterKey` has to be available. It is recommended to only\n        use the master key in server-side applications where the key is kept secure and not\n        exposed to the public.\n        - note: An explain query will have many different underlying types. Since Swift is a strongly\n        typed language, a developer should specify the type expected to be decoded which will be\n        different for MongoDB and PostgreSQL. One way around this is to use a type-erased wrapper\n        such as the [AnyCodable](https://github.com/Flight-School/AnyCodable) package.\n        - parameter pipeline: A pipeline of stages to process query.\n        - parameter usingMongoDB: Set to **true** if your Parse Server uses MongoDB. Defaults to **false**.\n        - parameter options: A set of header options sent to the server. Defaults to an empty set.\n        - parameter callbackQueue: The queue to return to after completion. Default value of `.main`.\n        - parameter completion: The block to execute.\n      It should have the following argument signature: `(Result<[ParseObject], ParseError>)`.\n        - warning: MongoDB's **explain** does not conform to the traditional Parse Server response, so the\n        `usingMongoDB` flag needs to be set for MongoDB users. See more\n        [here](https://github.com/parse-community/parse-server/pull/7440).\n    */\n    public func aggregateExplain<U: Decodable>(_ pipeline: [[String: Encodable]],\n                                               usingMongoDB: Bool = false,\n                                               options: API.Options = [],\n                                               callbackQueue: DispatchQueue = .main,\n                                               completion: @escaping (Result<[U], ParseError>) -> Void) {\n        if limit == 0 {\n            callbackQueue.async {\n                completion(.success([U]()))\n            }\n            return\n        }\n        var options = options\n        options.insert(.useMasterKey)\n\n        var updatedPipeline = [[String: AnyCodable]]()\n        pipeline.forEach { updatedPipeline = $0.map { [$0.key: AnyCodable($0.value)] } }\n\n        guard let encoded = try? ParseCoding.jsonEncoder()\n                .encode(self.`where`),\n            let whereString = String(data: encoded, encoding: .utf8) else {\n            let error = ParseError(code: .unknownError, message: \"Cannot decode where to String.\")\n            callbackQueue.async {\n                completion(.failure(error))\n            }\n            return\n        }\n\n        var query = self\n        query.`where` = QueryWhere()\n\n        if whereString != \"{}\" {\n            var finishedPipeline = [[\"match\": AnyCodable(whereString)]]\n            finishedPipeline.append(contentsOf: updatedPipeline)\n            query.pipeline = finishedPipeline\n        } else {\n            query.pipeline = updatedPipeline\n        }\n        if !usingMongoDB {\n            do {\n                try query.aggregateExplainCommand()\n                    .executeAsync(options: options, callbackQueue: callbackQueue) { result in\n                        completion(result)\n                }\n            } catch {\n                let parseError = ParseError(code: .unknownError,\n                                            message: error.localizedDescription)\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        } else {\n            do {\n                try query.aggregateExplainMongoCommand()\n                    .executeAsync(options: options, callbackQueue: callbackQueue) { result in\n                        completion(result)\n                }\n            } catch {\n                let parseError = ParseError(code: .unknownError,\n                                            message: error.localizedDescription)\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n    }\n\n    /**\n     Executes an aggregate query *synchronously* and calls the given.\n      - requires: `.useMasterKey` has to be available. It is recommended to only\n      use the master key in server-side applications where the key is kept secure and not\n      exposed to the public.\n      - parameter key: A field to find distinct values.\n      - parameter options: A set of header options sent to the server. Defaults to an empty set.\n      - throws: An error of type `ParseError`.\n      - warning: This has not been tested thoroughly.\n      - returns: Returns the `ParseObject`s that match the query.\n    */\n    public func distinct(_ key: String,\n                         options: API.Options = []) throws -> [ResultType] {\n        if limit == 0 {\n            return [ResultType]()\n        }\n        var options = options\n        options.insert(.useMasterKey)\n        return try distinctCommand(key: key)\n            .execute(options: options)\n    }\n\n    /**\n     Executes a distinct query *asynchronously* and returns unique values.\n        - requires: `.useMasterKey` has to be available. It is recommended to only\n        use the master key in server-side applications where the key is kept secure and not\n        exposed to the public.\n        - parameter key: A field to find distinct values.\n        - parameter options: A set of header options sent to the server. Defaults to an empty set.\n        - parameter callbackQueue: The queue to return to after completion. Default value of `.main`.\n        - parameter completion: The block to execute.\n      It should have the following argument signature: `(Result<[ParseObject], ParseError>)`.\n        - warning: This has not been tested thoroughly.\n    */\n    public func distinct(_ key: String,\n                         options: API.Options = [],\n                         callbackQueue: DispatchQueue = .main,\n                         completion: @escaping (Result<[ResultType], ParseError>) -> Void) {\n        if limit == 0 {\n            callbackQueue.async {\n                completion(.success([ResultType]()))\n            }\n            return\n        }\n        var options = options\n        options.insert(.useMasterKey)\n        do {\n            try distinctCommand(key: key)\n                .executeAsync(options: options,\n                              callbackQueue: callbackQueue) { result in\n                    completion(result)\n            }\n        } catch {\n            let parseError = ParseError(code: .unknownError,\n                                        message: error.localizedDescription)\n            callbackQueue.async {\n                completion(.failure(parseError))\n            }\n        }\n    }\n\n    /**\n     Query plan information for executing an aggregate query *synchronously* and calls the given.\n      - requires: `.useMasterKey` has to be available. It is recommended to only\n      use the master key in server-side applications where the key is kept secure and not\n      exposed to the public.\n      - note: An explain query will have many different underlying types. Since Swift is a strongly\n      typed language, a developer should specify the type expected to be decoded which will be\n      different for MongoDB and PostgreSQL. One way around this is to use a type-erased wrapper\n      such as the [AnyCodable](https://github.com/Flight-School/AnyCodable) package.\n      - parameter key: A field to find distinct values.\n      - parameter usingMongoDB: Set to **true** if your Parse Server uses MongoDB. Defaults to **false**.\n      - parameter options: A set of header options sent to the server. Defaults to an empty set.\n      - throws: An error of type `ParseError`.\n      - warning: This has not been tested thoroughly.\n      - returns: Returns the `ParseObject`s that match the query.\n      - warning: MongoDB's **explain** does not conform to the traditional Parse Server response, so the\n      `usingMongoDB` flag needs to be set for MongoDB users. See more\n       [here](https://github.com/parse-community/parse-server/pull/7440).\n    */\n    public func distinctExplain<U: Decodable>(_ key: String,\n                                              usingMongoDB: Bool = false,\n                                              options: API.Options = []) throws -> [U] {\n        if limit == 0 {\n            return [U]()\n        }\n        var options = options\n        options.insert(.useMasterKey)\n        if !usingMongoDB {\n            return try distinctExplainCommand(key: key)\n                .execute(options: options)\n        } else {\n            return try distinctExplainMongoCommand(key: key)\n                .execute(options: options)\n        }\n    }\n\n    /**\n     Query plan information for executing a distinct query *asynchronously* and returns unique values.\n        - requires: `.useMasterKey` has to be available. It is recommended to only\n        use the master key in server-side applications where the key is kept secure and not\n        exposed to the public.\n        - note: An explain query will have many different underlying types. Since Swift is a strongly\n        typed language, a developer should specify the type expected to be decoded which will be\n        different for MongoDB and PostgreSQL. One way around this is to use a type-erased wrapper\n        such as the [AnyCodable](https://github.com/Flight-School/AnyCodable) package.\n        - parameter key: A field to find distinct values.\n        - parameter usingMongoDB: Set to **true** if your Parse Server uses MongoDB. Defaults to **false**.\n        - parameter options: A set of header options sent to the server. Defaults to an empty set.\n        - parameter callbackQueue: The queue to return to after completion. Default value of `.main`.\n        - parameter completion: The block to execute.\n      It should have the following argument signature: `(Result<[Decodable], ParseError>)`.\n        - warning: MongoDB's **explain** does not conform to the traditional Parse Server response, so the\n        `usingMongoDB` flag needs to be set for MongoDB users. See more\n        [here](https://github.com/parse-community/parse-server/pull/7440).\n    */\n    public func distinctExplain<U: Decodable>(_ key: String,\n                                              usingMongoDB: Bool = false,\n                                              options: API.Options = [],\n                                              callbackQueue: DispatchQueue = .main,\n                                              completion: @escaping (Result<[U], ParseError>) -> Void) {\n        if limit == 0 {\n            callbackQueue.async {\n                completion(.success([U]()))\n            }\n            return\n        }\n        var options = options\n        options.insert(.useMasterKey)\n        if !usingMongoDB {\n            do {\n                try distinctExplainCommand(key: key)\n                    .executeAsync(options: options,\n                                  callbackQueue: callbackQueue) { result in\n                        completion(result)\n                }\n            } catch {\n                let parseError = ParseError(code: .unknownError,\n                                            message: error.localizedDescription)\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        } else {\n            do {\n                try distinctExplainMongoCommand(key: key)\n                    .executeAsync(options: options,\n                                  callbackQueue: callbackQueue) { result in\n                        completion(result)\n                }\n            } catch {\n                let parseError = ParseError(code: .unknownError,\n                                            message: error.localizedDescription)\n                callbackQueue.async {\n                    completion(.failure(parseError))\n                }\n            }\n        }\n    }\n}\n\nextension Query {\n\n    func findCommand() throws -> API.NonParseBodyCommand<Query<ResultType>, [ResultType]> {\n        if !Parse.configuration.isUsingPostForQuery {\n            return API.NonParseBodyCommand(method: .GET,\n                                           path: endpoint,\n                                           params: try getQueryParameters()) {\n                try ParseCoding.jsonDecoder().decode(QueryResponse<T>.self, from: $0).results\n            }\n        } else {\n            return API.NonParseBodyCommand(method: .POST,\n                                           path: endpoint,\n                                           body: self) {\n                try ParseCoding.jsonDecoder().decode(QueryResponse<T>.self, from: $0).results\n            }\n        }\n    }\n\n    func firstCommand() throws -> API.NonParseBodyCommand<Query<ResultType>, ResultType> {\n        var query = self\n        query.limit = 1\n        if !Parse.configuration.isUsingPostForQuery {\n            return API.NonParseBodyCommand(method: .GET,\n                                           path: query.endpoint,\n                                           params: try getQueryParameters()) {\n                if let decoded = try ParseCoding.jsonDecoder().decode(QueryResponse<T>.self, from: $0).results.first {\n                    return decoded\n                }\n                throw ParseError(code: .objectNotFound,\n                                 message: \"Object not found on the server.\")\n            }\n        } else {\n            return API.NonParseBodyCommand(method: .POST, path: query.endpoint, body: query) {\n                if let decoded = try ParseCoding.jsonDecoder().decode(QueryResponse<T>.self, from: $0).results.first {\n                    return decoded\n                }\n                throw ParseError(code: .objectNotFound,\n                                 message: \"Object not found on the server.\")\n            }\n        }\n    }\n\n    func countCommand() throws -> API.NonParseBodyCommand<Query<ResultType>, Int> {\n        var query = self\n        query.limit = 1\n        query.isCount = true\n        if !Parse.configuration.isUsingPostForQuery {\n            return API.NonParseBodyCommand(method: .GET,\n                                           path: query.endpoint,\n                                           params: try getQueryParameters()) {\n                try ParseCoding.jsonDecoder().decode(QueryResponse<T>.self, from: $0).count ?? 0\n            }\n        } else {\n            return API.NonParseBodyCommand(method: .POST,\n                                           path: query.endpoint,\n                                           body: query) {\n                try ParseCoding.jsonDecoder().decode(QueryResponse<T>.self, from: $0).count ?? 0\n            }\n        }\n    }\n\n    func withCountCommand() throws -> API.NonParseBodyCommand<Query<ResultType>, ([ResultType], Int)> {\n        var query = self\n        query.isCount = true\n        if !Parse.configuration.isUsingPostForQuery {\n            return API.NonParseBodyCommand(method: .GET,\n                                           path: query.endpoint,\n                                           params: try getQueryParameters()) {\n                let decoded = try ParseCoding.jsonDecoder().decode(QueryResponse<T>.self, from: $0)\n                return (decoded.results, decoded.count ?? 0)\n            }\n        } else {\n            return API.NonParseBodyCommand(method: .POST,\n                                           path: query.endpoint,\n                                           body: query) {\n                let decoded = try ParseCoding.jsonDecoder().decode(QueryResponse<T>.self, from: $0)\n                return (decoded.results, decoded.count ?? 0)\n            }\n        }\n    }\n\n    func aggregateCommand() throws -> API.NonParseBodyCommand<AggregateBody<ResultType>, [ResultType]> {\n        let body = AggregateBody(query: self)\n        if !Parse.configuration.isUsingPostForQuery {\n            return API.NonParseBodyCommand(method: .GET,\n                                           path: .aggregate(className: T.className),\n                                           params: try body.getQueryParameters()) {\n                try ParseCoding.jsonDecoder().decode(QueryResponse<T>.self, from: $0).results\n            }\n        } else {\n            return API.NonParseBodyCommand(method: .POST,\n                                           path: .aggregate(className: T.className),\n                                           body: body) {\n                try ParseCoding.jsonDecoder().decode(QueryResponse<T>.self, from: $0).results\n            }\n        }\n    }\n\n    func distinctCommand(key: String) throws -> API.NonParseBodyCommand<DistinctBody<ResultType>, [ResultType]> {\n        var query = self\n        query.distinct = key\n        let body = DistinctBody(query: query)\n        if !Parse.configuration.isUsingPostForQuery {\n            return API.NonParseBodyCommand(method: .GET,\n                                           path: .aggregate(className: T.className),\n                                           params: try body.getQueryParameters()) {\n                try ParseCoding.jsonDecoder().decode(QueryResponse<T>.self, from: $0).results\n            }\n        } else {\n            return API.NonParseBodyCommand(method: .POST,\n                                           path: .aggregate(className: T.className),\n                                           body: body) {\n                try ParseCoding.jsonDecoder().decode(QueryResponse<T>.self, from: $0).results\n            }\n        }\n    }\n\n    func findExplainCommand<U: Decodable>() throws -> API.NonParseBodyCommand<Query<ResultType>, [U]> {\n        var query = self\n        query.explain = true\n        if !Parse.configuration.isUsingPostForQuery {\n            return API.NonParseBodyCommand(method: .GET,\n                                           path: query.endpoint,\n                                           params: try query.getQueryParameters()) {\n                try ParseCoding.jsonDecoder().decode(AnyResultsResponse<U>.self, from: $0).results\n            }\n        } else {\n            return API.NonParseBodyCommand(method: .POST,\n                                           path: query.endpoint,\n                                           body: query) {\n                try ParseCoding.jsonDecoder().decode(AnyResultsResponse<U>.self, from: $0).results\n            }\n        }\n    }\n\n    func firstExplainCommand<U: Decodable>() throws -> API.NonParseBodyCommand<Query<ResultType>, U> {\n        var query = self\n        query.limit = 1\n        query.explain = true\n        if !Parse.configuration.isUsingPostForQuery {\n            return API.NonParseBodyCommand(method: .GET,\n                                           path: query.endpoint,\n                                           params: try query.getQueryParameters()) {\n                if let decoded = try ParseCoding\n                    .jsonDecoder()\n                    .decode(AnyResultsResponse<U>.self, from: $0)\n                    .results.first {\n                    return decoded\n                }\n                throw ParseError(code: .objectNotFound,\n                                 message: \"Object not found on the server.\")\n            }\n        } else {\n            return API.NonParseBodyCommand(method: .POST,\n                                           path: query.endpoint,\n                                           body: query) {\n                if let decoded = try ParseCoding\n                    .jsonDecoder()\n                    .decode(AnyResultsResponse<U>.self, from: $0)\n                    .results.first {\n                    return decoded\n                }\n                throw ParseError(code: .objectNotFound,\n                                 message: \"Object not found on the server.\")\n            }\n        }\n    }\n\n    func countExplainCommand<U: Decodable>() throws -> API.NonParseBodyCommand<Query<ResultType>, [U]> {\n        var query = self\n        query.limit = 1\n        query.isCount = true\n        query.explain = true\n        if !Parse.configuration.isUsingPostForQuery {\n            return API.NonParseBodyCommand(method: .GET,\n                                           path: query.endpoint,\n                                           params: try query.getQueryParameters()) {\n                try ParseCoding.jsonDecoder().decode(AnyResultsResponse<U>.self, from: $0).results\n            }\n        } else {\n            return API.NonParseBodyCommand(method: .POST,\n                                           path: query.endpoint,\n                                           body: query) {\n                try ParseCoding.jsonDecoder().decode(AnyResultsResponse<U>.self, from: $0).results\n            }\n        }\n    }\n\n    func withCountExplainCommand<U: Decodable>() throws -> API.NonParseBodyCommand<Query<ResultType>, [U]> {\n        var query = self\n        query.isCount = true\n        query.explain = true\n        if !Parse.configuration.isUsingPostForQuery {\n            return API.NonParseBodyCommand(method: .GET,\n                                           path: query.endpoint,\n                                           params: try query.getQueryParameters()) {\n                try ParseCoding.jsonDecoder().decode(AnyResultsResponse<U>.self, from: $0).results\n            }\n        } else {\n            return API.NonParseBodyCommand(method: .POST,\n                                           path: query.endpoint,\n                                           body: query) {\n                try ParseCoding.jsonDecoder().decode(AnyResultsResponse<U>.self, from: $0).results\n            }\n        }\n    }\n\n    func aggregateExplainCommand<U: Decodable>() throws -> API.NonParseBodyCommand<AggregateBody<ResultType>, [U]> {\n        var query = self\n        query.explain = true\n        let body = AggregateBody(query: query)\n        if !Parse.configuration.isUsingPostForQuery {\n            return API.NonParseBodyCommand(method: .GET,\n                                           path: .aggregate(className: T.className),\n                                           params: try body.getQueryParameters()) {\n                try ParseCoding.jsonDecoder().decode(AnyResultsResponse<U>.self, from: $0).results\n            }\n        } else {\n            return API.NonParseBodyCommand(method: .POST,\n                                           path: .aggregate(className: T.className),\n                                           body: body) {\n                try ParseCoding.jsonDecoder().decode(AnyResultsResponse<U>.self, from: $0).results\n            }\n        }\n    }\n\n    // swiftlint:disable:next line_length\n    func distinctExplainCommand<U: Decodable>(key: String) throws -> API.NonParseBodyCommand<DistinctBody<ResultType>, [U]> {\n        var query = self\n        query.explain = true\n        query.distinct = key\n        let body = DistinctBody(query: query)\n        if !Parse.configuration.isUsingPostForQuery {\n            return API.NonParseBodyCommand(method: .GET,\n                                           path: .aggregate(className: T.className),\n                                           params: try body.getQueryParameters()) {\n                try ParseCoding.jsonDecoder().decode(AnyResultsResponse<U>.self, from: $0).results\n            }\n        } else {\n            return API.NonParseBodyCommand(method: .POST, path: .aggregate(className: T.className), body: body) {\n                try ParseCoding.jsonDecoder().decode(AnyResultsResponse<U>.self, from: $0).results\n            }\n        }\n    }\n\n    func findExplainMongoCommand<U: Decodable>() throws -> API.NonParseBodyCommand<Query<ResultType>, [U]> {\n        var query = self\n        query.explain = true\n        if !Parse.configuration.isUsingPostForQuery {\n            return API.NonParseBodyCommand(method: .GET,\n                                           path: query.endpoint,\n                                           params: try query.getQueryParameters()) {\n                try [ParseCoding.jsonDecoder().decode(AnyResultsMongoResponse<U>.self, from: $0).results]\n            }\n        } else {\n            return API.NonParseBodyCommand(method: .POST,\n                                           path: query.endpoint,\n                                           body: query) {\n                try [ParseCoding.jsonDecoder().decode(AnyResultsMongoResponse<U>.self, from: $0).results]\n            }\n        }\n    }\n\n    func firstExplainMongoCommand<U: Decodable>() throws -> API.NonParseBodyCommand<Query<ResultType>, U> {\n        var query = self\n        query.limit = 1\n        query.explain = true\n        if !Parse.configuration.isUsingPostForQuery {\n            return API.NonParseBodyCommand(method: .GET,\n                                           path: query.endpoint,\n                                           params: try query.getQueryParameters()) {\n                do {\n                    return try ParseCoding.jsonDecoder().decode(AnyResultsMongoResponse<U>.self, from: $0).results\n                } catch {\n                    throw ParseError(code: .objectNotFound,\n                                     message: \"Object not found on the server. Error: \\(error)\")\n                }\n            }\n        } else {\n            return API.NonParseBodyCommand(method: .POST,\n                                           path: query.endpoint,\n                                           body: query) {\n                do {\n                    return try ParseCoding.jsonDecoder().decode(AnyResultsMongoResponse<U>.self, from: $0).results\n                } catch {\n                    throw ParseError(code: .objectNotFound,\n                                     message: \"Object not found on the server. Error: \\(error)\")\n                }\n            }\n        }\n    }\n\n    func countExplainMongoCommand<U: Decodable>() throws -> API.NonParseBodyCommand<Query<ResultType>, [U]> {\n        var query = self\n        query.limit = 1\n        query.isCount = true\n        query.explain = true\n        if !Parse.configuration.isUsingPostForQuery {\n            return API.NonParseBodyCommand(method: .GET,\n                                           path: query.endpoint,\n                                           params: try query.getQueryParameters()) {\n                try [ParseCoding.jsonDecoder().decode(AnyResultsMongoResponse<U>.self, from: $0).results]\n            }\n        } else {\n            return API.NonParseBodyCommand(method: .POST,\n                                           path: query.endpoint,\n                                           body: query) {\n                try [ParseCoding.jsonDecoder().decode(AnyResultsMongoResponse<U>.self, from: $0).results]\n            }\n        }\n    }\n\n    func withCountExplainMongoCommand<U: Decodable>() throws -> API.NonParseBodyCommand<Query<ResultType>, [U]> {\n        var query = self\n        query.isCount = true\n        query.explain = true\n        if !Parse.configuration.isUsingPostForQuery {\n            return API.NonParseBodyCommand(method: .GET,\n                                           path: query.endpoint,\n                                           params: try query.getQueryParameters()) {\n                try [ParseCoding.jsonDecoder().decode(AnyResultsMongoResponse<U>.self, from: $0).results]\n            }\n        } else {\n            return API.NonParseBodyCommand(method: .POST,\n                                           path: query.endpoint,\n                                           body: query) {\n                try [ParseCoding.jsonDecoder().decode(AnyResultsMongoResponse<U>.self, from: $0).results]\n            }\n        }\n    }\n\n    // swiftlint:disable:next line_length\n    func aggregateExplainMongoCommand<U: Decodable>() throws -> API.NonParseBodyCommand<AggregateBody<ResultType>, [U]> {\n        var query = self\n        query.explain = true\n        let body = AggregateBody(query: query)\n        if !Parse.configuration.isUsingPostForQuery {\n            return API.NonParseBodyCommand(method: .GET,\n                                           path: .aggregate(className: T.className),\n                                           params: try body.getQueryParameters()) {\n                try [ParseCoding.jsonDecoder().decode(AnyResultsMongoResponse<U>.self, from: $0).results]\n            }\n        } else {\n            return API.NonParseBodyCommand(method: .POST,\n                                           path: .aggregate(className: T.className),\n                                           body: body) {\n                try [ParseCoding.jsonDecoder().decode(AnyResultsMongoResponse<U>.self, from: $0).results]\n            }\n        }\n    }\n\n    // swiftlint:disable:next line_length\n    func distinctExplainMongoCommand<U: Decodable>(key: String) throws -> API.NonParseBodyCommand<DistinctBody<ResultType>, [U]> {\n        var query = self\n        query.explain = true\n        query.distinct = key\n        let body = DistinctBody(query: query)\n        if !Parse.configuration.isUsingPostForQuery {\n            return API.NonParseBodyCommand(method: .GET,\n                                           path: .aggregate(className: T.className),\n                                           params: try body.getQueryParameters()) {\n                try [ParseCoding.jsonDecoder().decode(AnyResultsMongoResponse<U>.self, from: $0).results]\n            }\n        } else {\n            return API.NonParseBodyCommand(method: .POST,\n                                           path: .aggregate(className: T.className),\n                                           body: body) {\n                try [ParseCoding.jsonDecoder().decode(AnyResultsMongoResponse<U>.self, from: $0).results]\n            }\n        }\n    }\n}\n\n// MARK: Query\npublic extension ParseObject {\n\n    /**\n      Create a query with no constraints.\n     */\n    static var query: Query<Self> {\n        Query<Self>()\n    }\n\n    /**\n      Create a query with a variadic amount constraints.\n     - parameter constraints: A variadic amount of zero or more `QueryConstraint`'s.\n     - returns: An instance of query for easy chaining.\n     */\n    static func query(_ constraints: QueryConstraint...) -> Query<Self> {\n        Self.query(constraints)\n    }\n\n    /**\n      Create a query with an array of constraints.\n     - parameter constraints: An array of `QueryConstraint`'s.\n     - returns: An instance of query for easy chaining.\n     */\n    static func query(_ constraints: [QueryConstraint] = []) -> Query<Self> {\n        Query<Self>(constraints)\n    }\n}\n\n// MARK: ParseUser\nextension Query where T: ParseUser {\n    var endpoint: API.Endpoint {\n        return .users\n    }\n}\n\n// MARK: ParseInstallation\nextension Query where T: ParseInstallation {\n    var endpoint: API.Endpoint {\n        return .installations\n    }\n}\n\n// MARK: ParseSession\nextension Query where T: ParseSession {\n    var endpoint: API.Endpoint {\n        return .sessions\n    }\n}\n\n// MARK: ParseRole\nextension Query where T: ParseRole {\n    var endpoint: API.Endpoint {\n        return .roles\n    }\n}\n\nenum RawCodingKey: CodingKey {\n    case key(String)\n    var stringValue: String {\n        switch self {\n        case .key(let str):\n            return str\n        }\n    }\n    var intValue: Int? {\n        nil\n    }\n    init?(stringValue: String) {\n        self = .key(stringValue)\n    }\n    init?(intValue: Int) {\n        fatalError()\n    }\n}\n\ninternal extension Query {\n    func getQueryParameters() throws -> [String: String] {\n        var dictionary = [String: String]()\n        dictionary[\"limit\"] = try encodeAsString(\\.limit)\n        dictionary[\"skip\"] = try encodeAsString(\\.skip)\n        dictionary[\"keys\"] = try encodeAsString(\\.keys)\n        dictionary[\"include\"] = try encodeAsString(\\.include)\n        dictionary[\"order\"] = try encodeAsString(\\.order)\n        dictionary[\"count\"] = try encodeAsString(\\.isCount)\n        dictionary[\"explain\"] = try encodeAsString(\\.explain)\n        dictionary[\"hint\"] = try encodeAsString(\\.hint)\n        dictionary[\"where\"] = try encodeAsString(\\.`where`)\n        dictionary[\"excludeKeys\"] = try encodeAsString(\\.excludeKeys)\n        dictionary[\"readPreference\"] = try encodeAsString(\\.readPreference)\n        dictionary[\"includeReadPreference\"] = try encodeAsString(\\.includeReadPreference)\n        dictionary[\"subqueryReadPreference\"] = try encodeAsString(\\.subqueryReadPreference)\n        dictionary[\"distinct\"] = try encodeAsString(\\.distinct)\n        dictionary[\"pipeline\"] = try encodeAsString(\\.pipeline)\n        return dictionary\n    }\n\n    func encodeAsString<W>(_ key: KeyPath<Self, W?>) throws -> String? where W: Encodable {\n        guard let value = self[keyPath: key] else {\n            return nil\n        }\n        let encoded = try ParseCoding.jsonEncoder().encode(value)\n        return String(data: encoded, encoding: .utf8)\n    }\n\n    func encodeAsString<W>(_ key: KeyPath<Self, W>) throws -> String? where W: Encodable {\n        let encoded = try ParseCoding.jsonEncoder().encode(self[keyPath: key])\n        return String(data: encoded, encoding: .utf8)\n    }\n}\n// swiftlint:disable:this file_length\n"
  },
  {
    "path": "Sources/ParseSwift/Types/QueryConstraint.swift",
    "content": "//\n//  QueryConstraint.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 12/9/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/// Used to constrain a query.\npublic struct QueryConstraint: ParseTypeable, Hashable {\n    enum Comparator: String, CodingKey, Codable, CaseIterable {\n        case lessThan = \"$lt\"\n        case lessThanOrEqualTo = \"$lte\"\n        case greaterThan = \"$gt\"\n        case greaterThanOrEqualTo = \"$gte\"\n        case equalTo = \"$eq\"\n        case notEqualTo = \"$ne\"\n        case containedIn = \"$in\"\n        case notContainedIn = \"$nin\"\n        case containedBy = \"$containedBy\"\n        case exists = \"$exists\"\n        case select = \"$select\"\n        case dontSelect = \"$dontSelect\"\n        case all = \"$all\"\n        case regex = \"$regex\"\n        case inQuery = \"$inQuery\"\n        case notInQuery = \"$notInQuery\"\n        case nearSphere = \"$nearSphere\"\n        case or = \"$or\" //swiftlint:disable:this identifier_name\n        case and = \"$and\"\n        case nor = \"$nor\"\n        case relatedTo = \"$relatedTo\"\n        case within = \"$within\"\n        case geoWithin = \"$geoWithin\"\n        case geoIntersects = \"$geoIntersects\"\n        case maxDistance = \"$maxDistance\"\n        case centerSphere = \"$centerSphere\"\n        case box = \"$box\"\n        case polygon = \"$polygon\"\n        case point = \"$point\"\n        case text = \"$text\"\n        case search = \"$search\"\n        case term = \"$term\"\n        case regexOptions = \"$options\"\n        case relativeTime = \"$relativeTime\"\n        case score = \"$score\"\n    }\n\n    var key: String\n    var value: AnyCodable?\n    var comparator: Comparator?\n    var isNull: Bool = false\n\n    init(key: String, value: Codable? = nil, comparator: Comparator? = nil, isNull: Bool = false) {\n        self.key = key\n        self.value = AnyCodable(value)\n        self.comparator = comparator\n        self.isNull = isNull\n    }\n\n    public func encode(to encoder: Encoder) throws {\n        if isNull {\n            var container = encoder.singleValueContainer()\n            try container.encodeNil()\n        } else if let value = value?.value as? Date {\n            // Parse uses special case for date\n            try value.parseRepresentation.encode(to: encoder)\n        } else {\n            try value?.encode(to: encoder)\n        }\n    }\n\n    public init(from decoder: Decoder) throws {\n        key = \"\" // Dummy string that needs to be set to the correct value\n        if let comparatorString = decoder.codingPath.last?.stringValue {\n            comparator = Comparator(rawValue: comparatorString)\n        }\n        let container = try decoder.singleValueContainer()\n        if container.decodeNil() {\n            isNull = true\n            value = AnyCodable(nil)\n        } else {\n            value = try container.decode(AnyCodable.self)\n        }\n    }\n}\n\n/**\n Add a constraint that requires that a key is greater than a value.\n - parameter key: The key that the value is stored in.\n - parameter value: The value to compare.\n - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func > <T>(key: String, value: T) -> QueryConstraint where T: Codable {\n    QueryConstraint(key: key, value: value, comparator: .greaterThan)\n}\n\n/**\n Add a constraint that requires that a key is greater than or equal to a value.\n - parameter key: The key that the value is stored in.\n - parameter value: The value to compare.\n - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func >= <T>(key: String, value: T) -> QueryConstraint where T: Codable {\n    QueryConstraint(key: key, value: value, comparator: .greaterThanOrEqualTo)\n}\n\n/**\n Add a constraint that requires that a key is less than a value.\n - parameter key: The key that the value is stored in.\n - parameter value: The value to compare.\n - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func < <T>(key: String, value: T) -> QueryConstraint where T: Codable {\n    QueryConstraint(key: key, value: value, comparator: .lessThan)\n}\n\n/**\n Add a constraint that requires that a key is less than or equal to a value.\n - parameter key: The key that the value is stored in.\n - parameter value: The value to compare.\n - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func <= <T>(key: String, value: T) -> QueryConstraint where T: Codable {\n    QueryConstraint(key: key, value: value, comparator: .lessThanOrEqualTo)\n}\n\n/**\n Add a constraint that requires that a key is equal to a value.\n - parameter key: The key that the value is stored in.\n - parameter value: The value to compare.\n - returns: The same instance of `QueryConstraint` as the receiver.\n - warning: See `equalTo` for more information.\n Behavior changes based on `ParseSwift.configuration.isUsingEqualQueryConstraint`\n where isUsingEqualQueryConstraint == true is known not to work for LiveQuery on\n Parse Servers  <= 5.0.0.\n */\npublic func == <T>(key: String, value: T) -> QueryConstraint where T: Codable {\n    equalTo(key: key, value: value)\n}\n\n/**\n Add a constraint that requires that a key is equal to a value.\n - parameter key: The key that the value is stored in.\n - parameter value: The value to compare.\n - parameter usingEqComparator: Set to **true** to use **$eq** comparater,\n allowing for multiple `QueryConstraint`'s to be used on a single **key**.\n Setting to *false* may override any `QueryConstraint`'s on the same **key**.\n Defaults to `ParseSwift.configuration.isUsingEqualQueryConstraint`.\n - returns: The same instance of `QueryConstraint` as the receiver.\n - warning: `usingEqComparator == true` is known not to work for LiveQueries\n on Parse Servers <= 5.0.0.\n */\npublic func equalTo <T>(key: String,\n                        value: T,\n                        //swiftlint:disable:next line_length\n                        usingEqComparator: Bool = configuration.isUsingEqualQueryConstraint) -> QueryConstraint where T: Codable {\n    if !usingEqComparator {\n        return QueryConstraint(key: key, value: value)\n    } else {\n        return QueryConstraint(key: key, value: value, comparator: .equalTo)\n    }\n}\n\n/**\n Add a constraint that requires that a key is equal to a `ParseObject`.\n - parameter key: The key that the value is stored in.\n - parameter object: The `ParseObject` to compare.\n - returns: The same instance of `QueryConstraint` as the receiver.\n - throws: An error of type `ParseError`.\n - warning: See `equalTo` for more information.\n Behavior changes based on `ParseSwift.configuration.isUsingEqualQueryConstraint`\n where isUsingEqualQueryConstraint == true is known not to work for LiveQuery on\n Parse Servers  <= 5.0.0.\n */\npublic func == <T>(key: String, object: T) throws -> QueryConstraint where T: ParseObject {\n    try equalTo(key: key, object: object)\n}\n\n/**\n Add a constraint that requires that a key is equal to a `ParseObject`.\n - parameter key: The key that the value is stored in.\n - parameter value: The `ParseObject` to compare.\n - parameter usingEqComparator: Set to **true** to use **$eq** comparater,\n allowing for multiple `QueryConstraint`'s to be used on a single **key**.\n Setting to *false* may override any `QueryConstraint`'s on the same **key**.\n Defaults to `ParseSwift.configuration.isUsingEqualQueryConstraint`.\n - returns: The same instance of `QueryConstraint` as the receiver.\n - throws: An error of type `ParseError`.\n - warning: `usingEqComparator == true` is known not to work for LiveQueries\n on Parse Servers <= 5.0.0.\n */\n@available(*, deprecated, message: \"Replace \\\"value\\\" with \\\"object\\\"\")\npublic func equalTo <T>(key: String,\n                        value: T,\n                        //swiftlint:disable:next line_length\n                        usingEqComparator: Bool = configuration.isUsingEqualQueryConstraint) throws -> QueryConstraint where T: ParseObject {\n    try equalTo(key: key, object: value, usingEqComparator: usingEqComparator)\n}\n\n/**\n Add a constraint that requires that a key is equal to a `ParseObject`.\n - parameter key: The key that the value is stored in.\n - parameter object: The `ParseObject` to compare.\n - parameter usingEqComparator: Set to **true** to use **$eq** comparater,\n allowing for multiple `QueryConstraint`'s to be used on a single **key**.\n Setting to *false* may override any `QueryConstraint`'s on the same **key**.\n Defaults to `ParseSwift.configuration.isUsingEqualQueryConstraint`.\n - returns: The same instance of `QueryConstraint` as the receiver.\n - throws: An error of type `ParseError`.\n - warning: `usingEqComparator == true` is known not to work for LiveQueries\n on Parse Servers <= 5.0.0.\n */\npublic func equalTo <T>(key: String,\n                        object: T,\n                        //swiftlint:disable:next line_length\n                        usingEqComparator: Bool = configuration.isUsingEqualQueryConstraint) throws -> QueryConstraint where T: ParseObject {\n    if !usingEqComparator {\n        return try QueryConstraint(key: key, value: object.toPointer())\n    } else {\n        return try QueryConstraint(key: key, value: object.toPointer(), comparator: .equalTo)\n    }\n}\n\n/**\n Add a constraint that requires that a key is not equal to a value.\n - parameter key: The key that the value is stored in.\n - parameter value: The value to compare.\n - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func != <T>(key: String, value: T) -> QueryConstraint where T: Codable {\n    QueryConstraint(key: key, value: value, comparator: .notEqualTo)\n}\n\n/**\n Add a constraint that requires that a key is not equal to a `ParseObject`.\n - parameter key: The key that the value is stored in.\n - parameter object: The `ParseObject` to compare.\n - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func != <T>(key: String, object: T) throws -> QueryConstraint where T: ParseObject {\n    try QueryConstraint(key: key, value: object.toPointer(), comparator: .notEqualTo)\n}\n\ninternal struct InQuery<T>: Codable where T: ParseObject {\n    let `where`: QueryWhere\n    let className: String\n\n    init(query: Query<T>) {\n        self.`where` = query.`where`\n        self.className = query.className\n    }\n}\n\ninternal struct OrAndQuery<T>: Codable where T: ParseObject {\n    let `where`: QueryWhere\n\n    init(query: Query<T>) {\n        self.`where` = query.`where`\n    }\n\n    func encode(to encoder: Encoder) throws {\n        var container = encoder.singleValueContainer()\n        try container.encode(self.`where`)\n    }\n}\n\ninternal struct QuerySelect<T>: Codable where T: ParseObject {\n    let query: InQuery<T>\n    let key: String\n}\n\n/**\n  Returns a `Query` that is the `or` of the passed in queries.\n  - parameter queries: The list of queries to `or` together.\n  - returns: An instance of `QueryConstraint`'s that are the `or` of the passed in queries.\n */\npublic func or <T>(queries: [Query<T>]) -> QueryConstraint where T: ParseObject {\n    let orQueries = queries.map { OrAndQuery(query: $0) }\n    return QueryConstraint(key: QueryConstraint.Comparator.or.rawValue, value: orQueries)\n}\n\n/**\n  Returns a `Query` that is the `or` of the passed in queries.\n  - parameter queries: The variadic amount of queries to `or` together.\n  - returns: An instance of `QueryConstraint`'s that are the `or` of the passed in queries.\n */\npublic func or <T>(queries: Query<T>...) -> QueryConstraint where T: ParseObject {\n    or(queries: queries)\n}\n\n/**\n  Returns a `Query` that is the `nor` of the passed in queries.\n  - parameter queries: The list of queries to `nor` together.\n  - returns: An instance of `QueryConstraint`'s that are the `nor` of the passed in queries.\n */\npublic func nor <T>(queries: [Query<T>]) -> QueryConstraint where T: ParseObject {\n    let orQueries = queries.map { OrAndQuery(query: $0) }\n    return QueryConstraint(key: QueryConstraint.Comparator.nor.rawValue, value: orQueries)\n}\n\n/**\n  Returns a `Query` that is the `nor` of the passed in queries.\n  - parameter queries: The variadic amount of queries to `nor` together.\n  - returns: An instance of `QueryConstraint`'s that are the `nor` of the passed in queries.\n */\npublic func nor <T>(queries: Query<T>...) -> QueryConstraint where T: ParseObject {\n    nor(queries: queries)\n}\n\n/**\n Constructs a Query that is the `and` of the passed in queries.\n \n For example:\n    \n     var compoundQueryConstraints = and(queries: [query1, query2, query3])\n    \n will create a compoundQuery that is an and of the query1, query2, and query3.\n    - parameter queries: The list of queries to `and` together.\n    - returns: An instance of `QueryConstraint`'s that are the `and` of the passed in queries.\n*/\npublic func and <T>(queries: [Query<T>]) -> QueryConstraint where T: ParseObject {\n    let andQueries = queries.map { OrAndQuery(query: $0) }\n    return QueryConstraint(key: QueryConstraint.Comparator.and.rawValue, value: andQueries)\n}\n\n/**\n Constructs a Query that is the `and` of the passed in queries.\n \n For example:\n    \n     var compoundQueryConstraints = and(queries: query1, query2, query3)\n    \n will create a compoundQuery that is an and of the query1, query2, and query3.\n    - parameter queries: The variadic amount of queries to `and` together.\n    - returns: An instance of `QueryConstraint`'s that are the `and` of the passed in queries.\n*/\npublic func and <T>(queries: Query<T>...) -> QueryConstraint where T: ParseObject {\n    and(queries: queries)\n}\n\n/**\n Add a constraint that requires that a key's value matches a `Query`.\n - warning: This only works when the key's values are `ParseObject`s or arrays of `ParseObject`s.\n - parameter key: The key that the value is stored in.\n - parameter query: The query the value should match.\n - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func == <T>(key: String, query: Query<T>) -> QueryConstraint {\n    QueryConstraint(key: key, value: InQuery(query: query), comparator: .inQuery)\n}\n\n/**\n Add a constraint that requires that a key's value do not match a `Query`.\n - warning: This only works when the key's values are `ParseObject`s or arrays of `ParseObject`s.\n - parameter key: The key that the value is stored in.\n - parameter query: The query the value should not match.\n - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func != <T>(key: String, query: Query<T>) -> QueryConstraint {\n    QueryConstraint(key: key, value: InQuery(query: query), comparator: .notInQuery)\n}\n\n/**\n Adds a constraint that requires that a key's value matches a value in another key\n in objects returned by a sub query.\n - parameter key: The key that contains the value that is being matched.\n - parameter queryKey: The key in objects in the returned by the sub query whose value should match.\n - parameter query: The query to run.\n - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func matchesKeyInQuery <T>(key: String, queryKey: String, query: Query<T>) -> QueryConstraint {\n    let select = QuerySelect(query: InQuery(query: query), key: queryKey)\n    return QueryConstraint(key: key, value: select, comparator: .select)\n}\n\n/**\n Adds a constraint that requires that a key's value *not* match a value in another key\n in objects returned by a sub query.\n - parameter key: The key that contains the value that is being excluded.\n - parameter queryKey: The key in objects returned by the sub query whose value should match.\n - parameter query: The query to run.\n - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func doesNotMatchKeyInQuery <T>(key: String, queryKey: String, query: Query<T>) -> QueryConstraint {\n    let select = QuerySelect(query: InQuery(query: query), key: queryKey)\n    return QueryConstraint(key: key, value: select, comparator: .dontSelect)\n}\n\n/**\n  Add a constraint to the query that requires a particular key's object\n  to be contained in the provided array.\n  - parameter key: The key to be constrained.\n  - parameter array: The possible values for the key's object.\n  - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func containedIn <T>(key: String, array: [T]) -> QueryConstraint where T: Codable {\n    QueryConstraint(key: key, value: array, comparator: .containedIn)\n}\n\n/**\n  Add a constraint to the query that requires a particular key's object\n  to be contained in the provided array of `ParseObjects`.\n  - parameter key: The key to be constrained.\n  - parameter array: The possible values for the key's object.\n  - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func containedIn <T>(key: String, array: [T]) throws -> QueryConstraint where T: ParseObject {\n    let pointers = try array.map { try $0.toPointer() }\n    return containedIn(key: key, array: pointers)\n}\n\n/**\n  Add a constraint to the query that requires a particular key's object\n  not be contained in the provided array.\n  - parameter key: The key to be constrained.\n  - parameter array: The list of values the key's object should not be.\n  - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func notContainedIn <T>(key: String, array: [T]) -> QueryConstraint where T: Codable {\n    QueryConstraint(key: key, value: array, comparator: .notContainedIn)\n}\n\n/**\n  Add a constraint to the query that requires a particular key's object\n  not be contained in the provided array of `ParseObject` pointers.\n  - parameter key: The key to be constrained.\n  - parameter array: The list of values the key's object should not be.\n  - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func notContainedIn <T>(key: String, array: [T]) throws -> QueryConstraint where T: ParseObject {\n    let pointers = try array.map { try $0.toPointer() }\n    return notContainedIn(key: key, array: pointers)\n}\n\n/**\n  Add a constraint to the query that requires a particular key's array\n  contains every element of the provided array.\n  - parameter key: The key to be constrained.\n  - parameter array: The possible values for the key's object.\n  - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func containsAll <T>(key: String, array: [T]) -> QueryConstraint where T: Codable {\n    QueryConstraint(key: key, value: array, comparator: .all)\n}\n\n/**\n  Add a constraint to the query that requires a particular key's array\n  contains every element of the provided array of `ParseObject's.\n  - parameter key: The key to be constrained.\n  - parameter array: The possible values for the key's object.\n  - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func containsAll <T>(key: String, array: [T]) throws -> QueryConstraint where T: ParseObject {\n    let pointers = try array.map { try $0.toPointer() }\n    return containsAll(key: key, array: pointers)\n}\n\n/**\n  Add a constraint to the query that requires a particular key's object\n  to be contained by the provided array. Get objects where all array elements match.\n  - parameter key: The key to be constrained.\n  - parameter array: The possible values for the key's object.\n  - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func containedBy <T>(key: String, array: [T]) -> QueryConstraint where T: Codable {\n    QueryConstraint(key: key, value: array, comparator: .containedBy)\n}\n\n/**\n Add a constraint to the query that requires a particular key's object\n to be contained by the provided array of `ParseObject`'s.\n Get objects where all array elements match.\n  - parameter key: The key to be constrained.\n  - parameter array: The possible values for the key's object.\n  - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func containedBy <T>(key: String, array: [T]) throws -> QueryConstraint where T: ParseObject {\n    let pointers = try array.map { try $0.toPointer() }\n    return containedBy(key: key, array: pointers)\n}\n\n/**\n Add a constraint to the query that requires a particular key's time is related to a specified time.\n \n For example:\n\n     let queryRelative = GameScore.query(relative(\"createdAt\" < \"12 days ago\"))\n\n will create a relative query where `createdAt` is less than 12 days ago.\n - parameter constraint: The key to be constrained. Should be a Date field. The value is a\n reference time, e.g. \"12 days ago\". Currently only comparators supported are: <, <=, >, and >=.\n - returns: The same instance of `QueryConstraint` as the receiver.\n - warning: Requires Parse Server 2.6.5+ for MongoDB and Parse Server 5.1.0+ for PostgreSQL.\n */\npublic func relative(_ constraint: QueryConstraint) -> QueryConstraint {\n    QueryConstraint(key: constraint.key,\n                    value: [QueryConstraint.Comparator.relativeTime.rawValue: AnyCodable(constraint.value)],\n                    comparator: constraint.comparator)\n}\n\n/**\n Add a constraint to the query that requires a particular key's coordinates (specified via `ParseGeoPoint`)\n be near a reference point. Distance is calculated based on angular distance on a sphere. Results will be sorted\n by distance from reference point.\n - parameter key: The key to be constrained.\n - parameter geoPoint: The reference point represented as a `ParseGeoPoint`.\n - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func near(key: String, geoPoint: ParseGeoPoint) -> QueryConstraint {\n    QueryConstraint(key: key, value: geoPoint, comparator: .nearSphere)\n}\n\n/**\n Add a constraint to the query that requires a particular key's coordinates (specified via `ParseGeoPoint`) be near\n a reference point and within the maximum distance specified (in radians). Distance is calculated based on\n angular distance on a sphere. Results will be sorted by distance (nearest to farthest) from the reference point.\n - parameter key: The key to be constrained.\n - parameter geoPoint: The reference point as a `ParseGeoPoint`.\n - parameter distance: Maximum distance in radians.\n - parameter sorted: **true** if results should be sorted by distance ascending, **false** is no sorting is required.\n Defaults to true.\n - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func withinRadians(key: String,\n                          geoPoint: ParseGeoPoint,\n                          distance: Double,\n                          sorted: Bool = true) -> [QueryConstraint] {\n    if sorted {\n        var constraints = [QueryConstraint(key: key, value: geoPoint, comparator: .nearSphere)]\n        constraints.append(.init(key: key, value: distance, comparator: .maxDistance))\n        return constraints\n    } else {\n        var constraints = [QueryConstraint(key: key, value: geoPoint, comparator: .centerSphere)]\n        constraints.append(.init(key: key, value: distance, comparator: .geoWithin))\n        return constraints\n    }\n}\n\n/**\n Add a constraint to the query that requires a particular key's coordinates (specified via `ParseGeoPoint`)\n be near a reference point and within the maximum distance specified (in miles). Distance is calculated based\n on a spherical coordinate system. Results will be sorted by distance (nearest to farthest) from the reference point.\n - parameter key: The key to be constrained.\n - parameter geoPoint: The reference point represented as a `ParseGeoPoint`.\n - parameter distance: Maximum distance in miles.\n - parameter sorted: **true** if results should be sorted by distance ascending, **false** is no sorting is required.\n Defaults to true.\n - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func withinMiles(key: String,\n                        geoPoint: ParseGeoPoint,\n                        distance: Double,\n                        sorted: Bool = true) -> [QueryConstraint] {\n    withinRadians(key: key,\n                  geoPoint: geoPoint,\n                  distance: (distance / ParseGeoPoint.earthRadiusMiles),\n                  sorted: sorted)\n}\n\n/**\n Add a constraint to the query that requires a particular key's coordinates (specified via `ParseGeoPoint`)\n be near a reference point and within the maximum distance specified (in kilometers). Distance is calculated based\n on a spherical coordinate system. Results will be sorted by distance (nearest to farthest) from the reference point.\n - parameter key: The key to be constrained.\n - parameter geoPoint: The reference point represented as a `ParseGeoPoint`.\n - parameter distance: Maximum distance in kilometers.\n - parameter sorted: **true** if results should be sorted by distance ascending, **false** is no sorting is required.\n Defaults to true.\n - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func withinKilometers(key: String,\n                             geoPoint: ParseGeoPoint,\n                             distance: Double,\n                             sorted: Bool = true) -> [QueryConstraint] {\n    withinRadians(key: key,\n                  geoPoint: geoPoint,\n                  distance: (distance / ParseGeoPoint.earthRadiusKilometers),\n                  sorted: sorted)\n}\n\n/**\n Add a constraint to the query that requires a particular key's coordinates (specified via `ParseGeoPoint`) be\n contained within a given rectangular geographic bounding box.\n - parameter key: The key to be constrained.\n - parameter fromSouthWest: The lower-left inclusive corner of the box.\n - parameter toNortheast: The upper-right inclusive corner of the box.\n - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func withinGeoBox(key: String, fromSouthWest southwest: ParseGeoPoint,\n                         toNortheast northeast: ParseGeoPoint) -> QueryConstraint {\n    let array = [southwest, northeast]\n    let dictionary = [QueryConstraint.Comparator.box.rawValue: array]\n    return .init(key: key, value: dictionary, comparator: .within)\n}\n\n/**\n Add a constraint to the query that requires a particular key's\n coordinates be contained within and on the bounds of a given polygon\n Supports closed and open (last point is connected to first) paths.\n\n Polygon must have at least 3 points.\n\n - parameter key: The key to be constrained.\n - parameter points: The polygon points as an Array of `ParseGeoPoint`'s.\n - warning: Requires Parse Server 2.5.0+.\n - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func withinPolygon(key: String, points: [ParseGeoPoint]) -> QueryConstraint {\n    let dictionary = [QueryConstraint.Comparator.polygon.rawValue: points]\n    return .init(key: key, value: dictionary, comparator: .geoWithin)\n}\n\n/**\n Add a constraint to the query that requires a particular key's\n coordinates be contained within and on the bounds of a given polygon\n Supports closed and open (last point is connected to first) paths.\n\n - parameter key: The key to be constrained.\n - parameter polygon: The `ParsePolygon`.\n - warning: Requires Parse Server 2.5.0+.\n - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func withinPolygon(key: String, polygon: ParsePolygon) -> QueryConstraint {\n    let dictionary = [QueryConstraint.Comparator.polygon.rawValue: polygon]\n    return .init(key: key, value: dictionary, comparator: .geoWithin)\n}\n\n/**\n Add a constraint to the query that requires a particular key's\n coordinates contains a `ParseGeoPoint`.\n\n - parameter key: The key of the `ParsePolygon`.\n - parameter point: The `ParseGeoPoint` to check for containment.\n - warning: Requires Parse Server 2.6.0+.\n - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func polygonContains(key: String, point: ParseGeoPoint) -> QueryConstraint {\n    let dictionary = [QueryConstraint.Comparator.point.rawValue: point]\n    return .init(key: key, value: dictionary, comparator: .geoIntersects)\n}\n\n/**\n  Add a constraint for finding string values that contain a provided\n  string using Full Text Search.\n  - parameter key: The key to be constrained.\n  - parameter text: The substring that the value must contain.\n  - returns: The resulting `QueryConstraint`.\n  - note: In order to sort you must use `Query.sortByTextScore()`.\n  Your `ParseObject` should conform to `ParseQueryScorable` to retrieve\n  the weight/rank via  the \"score\" property of your `ParseObject`.\n  - warning: This may be slow for large datasets. Requires Parse Server > 2.5.0.\n */\npublic func matchesText(key: String, text: String) -> QueryConstraint {\n    let dictionary = [QueryConstraint.Comparator.search.rawValue: [QueryConstraint.Comparator.term.rawValue: text]]\n    return .init(key: key, value: dictionary, comparator: .text)\n}\n\n/**\n  Options used to constrain a text search.\n */\npublic enum ParseTextOption: String {\n    /// The language that determines the list of stop words for the search and the rules for the stemmer and tokenizer.\n    /// Must be of type `String`.\n    case language = \"$language\"\n    /// A boolean flag to enable or disable case sensitive search.\n    case caseSensitive = \"$caseSensitive\"\n    /// A boolean flag to enable or disable diacritic sensitive search.\n    case diacriticSensitive = \"$diacriticSensitive\"\n\n    internal func buildSearch(_ text: String,\n                              options: [Self: Encodable]) throws -> [String: Encodable] {\n        var dictionary: [String: Encodable] = [QueryConstraint.Comparator.term.rawValue: text]\n        for (key, value) in options {\n            switch key {\n            case .language:\n                guard (value as? String) != nil else {\n                    throw ParseError(code: .unknownError,\n                                     message: \"Text option \\(key) has to be a String\")\n                }\n                dictionary[key.rawValue] = value\n            case .caseSensitive, .diacriticSensitive:\n                guard (value as? Bool) != nil else {\n                    throw ParseError(code: .unknownError,\n                                     message: \"Text option \\(key) has to be a Bool\")\n                }\n                dictionary[key.rawValue] = value\n            }\n        }\n        return dictionary\n    }\n}\n\n/**\n  Add a constraint for finding string values that contain a provided\n  string using Full Text Search.\n  - parameter key: The key to be constrained.\n  - parameter text: The substring that the value must contain.\n  - parameter options: The dictionary of options to constrain the search.\n     The key is of type `TextOption` and must have a respective value.\n  - returns: The resulting `QueryConstraint`.\n  - note: In order to sort you must use `Query.sortByTextScore()`.\n  Your `ParseObject` should conform to `ParseQueryScorable` to retrieve\n  the weight/rank via  the \"score\" property of your `ParseObject`.\n  - warning: This may be slow for large datasets. Requires Parse Server > 2.5.0.\n */\npublic func matchesText(key: String,\n                        text: String,\n                        options: [ParseTextOption: Encodable]) throws -> QueryConstraint {\n    let search = try ParseTextOption.language.buildSearch(text, options: options)\n    let dictionary = [QueryConstraint.Comparator.search.rawValue: search]\n    return .init(key: key, value: AnyCodable(dictionary), comparator: .text)\n}\n\n/**\n  Add a regular expression constraint for finding string values that match the provided regular expression.\n  - warning: This may be slow for large datasets.\n  - parameter key: The key that the string to match is stored in.\n  - parameter regex: The regular expression pattern to match.\n  - parameter modifiers: Any of the following supported PCRE modifiers (defaults to nil):\n  - `i` - Case insensitive search\n  - `m` - Search across multiple lines of input\n  - returns: The resulting `QueryConstraint`.\n */\npublic func matchesRegex(key: String, regex: String, modifiers: String? = nil) -> QueryConstraint {\n\n    if let modifiers = modifiers {\n        let dictionary = [\n            QueryConstraint.Comparator.regex.rawValue: regex,\n            QueryConstraint.Comparator.regexOptions.rawValue: modifiers\n        ]\n        return .init(key: key, value: dictionary)\n    } else {\n        return .init(key: key, value: regex, comparator: .regex)\n    }\n}\n\nprivate func regexStringForString(_ inputString: String) -> String {\n    let escapedString = inputString.replacingOccurrences(of: \"\\\\E\", with: \"\\\\E\\\\\\\\E\\\\Q\")\n    return \"\\\\Q\\(escapedString)\\\\E\"\n}\n\n/**\n  Add a constraint for finding string values that contain a provided substring.\n  - warning: This will be slow for large datasets.\n  - parameter key: The key that the string to match is stored in.\n  - parameter substring: The substring that the value must contain.\n  - parameter modifiers: Any of the following supported PCRE modifiers (defaults to nil):\n    - `i` - Case insensitive search\n    - `m` - Search across multiple lines of input\n  - returns: The resulting `QueryConstraint`.\n */\npublic func containsString(key: String, substring: String, modifiers: String? = nil) -> QueryConstraint {\n    let regex = regexStringForString(substring)\n    return matchesRegex(key: key, regex: regex, modifiers: modifiers)\n}\n\n/**\n  Add a constraint for finding string values that start with a provided prefix.\n  This will use smart indexing, so it will be fast for large datasets.\n  - parameter key: The key that the string to match is stored in.\n  - parameter prefix: The substring that the value must start with.\n  - parameter modifiers: Any of the following supported PCRE modifiers (defaults to nil):\n    - `i` - Case insensitive search\n    - `m` - Search across multiple lines of input\n  - returns: The resulting `QueryConstraint`.\n */\npublic func hasPrefix(key: String, prefix: String, modifiers: String? = nil) -> QueryConstraint {\n    let regex = \"^\\(regexStringForString(prefix))\"\n    return matchesRegex(key: key, regex: regex, modifiers: modifiers)\n}\n\n/**\n  Add a constraint for finding string values that end with a provided suffix.\n  - warning: This will be slow for large datasets.\n  - parameter key: The key that the string to match is stored in.\n  - parameter suffix: The substring that the value must end with.\n  - parameter modifiers: Any of the following supported PCRE modifiers (defaults to nil):\n    - `i` - Case insensitive search\n    - `m` - Search across multiple lines of input\n  - returns: The resulting `QueryConstraint`.\n */\npublic func hasSuffix(key: String, suffix: String, modifiers: String? = nil) -> QueryConstraint {\n    let regex = \"\\(regexStringForString(suffix))$\"\n    return matchesRegex(key: key, regex: regex, modifiers: modifiers)\n}\n\n/**\n Add a constraint that requires that a key is equal to **null** or **undefined**.\n - parameter key: The key that the value is stored in.\n - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func isNull (key: String) -> QueryConstraint {\n    QueryConstraint(key: key, isNull: true)\n}\n\n/**\n Add a constraint that requires that a key is not equal to **null** or **undefined**.\n - parameter key: The key that the value is stored in.\n - returns: The same instance of `QueryConstraint` as the receiver.\n */\npublic func isNotNull (key: String) -> QueryConstraint {\n    QueryConstraint(key: key, comparator: .notEqualTo, isNull: true)\n}\n\n/**\n  Add a constraint that requires a particular key to not be equal to **undefined**.\n  - parameter key: The key that should exist.\n  - returns: The resulting `QueryConstraint`.\n */\npublic func exists(key: String) -> QueryConstraint {\n    .init(key: key, value: true, comparator: .exists)\n}\n\n/**\n  Add a constraint that requires a key to be equal to **undefined**.\n  - parameter key: The key that should not exist.\n  - returns: The resulting `QueryConstraint`.\n */\npublic func doesNotExist(key: String) -> QueryConstraint {\n    .init(key: key, value: false, comparator: .exists)\n}\n\ninternal struct RelatedKeyCondition: Codable {\n    let key: String\n}\n\ninternal struct RelatedObjectCondition <T>: Codable where T: ParseObject {\n    let object: Pointer<T>\n}\n\ninternal struct RelatedCondition <T>: Codable where T: ParseObject {\n    let object: Pointer<T>\n    let key: String\n}\n\n/**\n  Add a constraint that requires a key is related.\n  - parameter key: The key that should be related.\n  - parameter object: The object that should be related.\n  - returns: The resulting `QueryConstraint`.\n  - throws: An error of type `ParseError`.\n */\npublic func related <T>(key: String, object: T) throws -> QueryConstraint where T: ParseObject {\n    let pointer = try object.toPointer()\n    let condition = RelatedCondition(object: pointer, key: key)\n    return .init(key: QueryConstraint.Comparator.relatedTo.rawValue, value: condition)\n}\n\n/**\n  Add a constraint that requires a key is related.\n  - parameter key: The key that should be related.\n  - parameter object: The pointer object that should be related.\n  - returns: The resulting `QueryConstraint`.\n */\npublic func related <T>(key: String, object: Pointer<T>) -> QueryConstraint where T: ParseObject {\n    let condition = RelatedCondition(object: object, key: key)\n    return .init(key: QueryConstraint.Comparator.relatedTo.rawValue, value: condition)\n}\n\n/**\n  Add a constraint that requires a key is related.\n  - parameter key: The key that should be related.\n  - returns: The resulting `QueryConstraint`.\n  - throws: An error of type `ParseError`.\n */\npublic func related(key: String) -> QueryConstraint {\n    let condition = RelatedKeyCondition(key: key)\n    return .init(key: QueryConstraint.Comparator.relatedTo.rawValue, value: condition)\n}\n\n/**\n  Add a constraint that requires a key is related.\n  - parameter object: The object that should be related.\n  - returns: The resulting `QueryConstraint`.\n  - throws: An error of type `ParseError`.\n */\npublic func related <T>(object: T) throws -> QueryConstraint where T: ParseObject {\n    let pointer = try object.toPointer()\n    let condition = RelatedObjectCondition(object: pointer)\n    return .init(key: QueryConstraint.Comparator.relatedTo.rawValue, value: condition)\n}\n\n/**\n  Add a constraint that requires a key is related.\n  - parameter object: The pointer object that should be related.\n  - returns: The resulting `QueryConstraint`.\n */\npublic func related <T>(object: Pointer<T>) -> QueryConstraint where T: ParseObject {\n    let condition = RelatedObjectCondition(object: object)\n    return .init(key: QueryConstraint.Comparator.relatedTo.rawValue, value: condition)\n}\n"
  },
  {
    "path": "Sources/ParseSwift/Types/QueryViewModel.swift",
    "content": "//\n//  QueryViewModel.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 7/3/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(SwiftUI)\nimport Foundation\n\n/**\n A default implementation of the `QueryObservable` protocol. Suitable for `ObjectObserved`\n and can be used as a SwiftUI view model. Also can be used as a Combine publisher. See Apple's\n [documentation](https://developer.apple.com/documentation/combine/observableobject)\n for more details.\n */\nopen class QueryViewModel<T: ParseObject>: QueryObservable {\n\n    public var query: Query<T>\n    public typealias Object = T\n\n    /// Updates and notifies when the new results have been retrieved.\n    open var results = [Object]() {\n        willSet {\n            count = newValue.count\n            DispatchQueue.main.async {\n                self.objectWillChange.send()\n            }\n        }\n    }\n\n    /// Updates and notifies when the count of the results have been retrieved.\n    open var count = 0 {\n        willSet {\n            error = nil\n            if newValue != results.count {\n                DispatchQueue.main.async {\n                    self.objectWillChange.send()\n                }\n            }\n        }\n    }\n\n    /// Updates and notifies when there is an error retrieving the results.\n    open var error: ParseError? {\n        willSet {\n            if newValue != nil {\n                results.removeAll()\n                count = results.count\n                DispatchQueue.main.async {\n                    self.objectWillChange.send()\n                }\n            }\n        }\n    }\n\n    required public init(query: Query<T>) {\n        self.query = query\n    }\n\n    open func find(options: API.Options = []) {\n        query.find(options: options) { result in\n            switch result {\n            case .success(let results):\n                self.results = results\n            case .failure(let error):\n                self.error = error\n            }\n        }\n    }\n\n    open func findAll(batchLimit: Int? = nil,\n                      options: API.Options = []) {\n\n        query.findAll(batchLimit: batchLimit,\n                      options: options) { result in\n            switch result {\n            case .success(let results):\n                self.results = results\n            case .failure(let error):\n                self.error = error\n            }\n        }\n    }\n\n    open func first(options: API.Options = []) {\n        query.first(options: options) { result in\n            switch result {\n            case .success(let result):\n                self.results = [result]\n            case .failure(let error):\n                self.error = error\n            }\n        }\n    }\n\n    open func count(options: API.Options = []) {\n        query.count(options: options) { result in\n            switch result {\n            case .success(let count):\n                self.count = count\n            case .failure(let error):\n                self.error = error\n            }\n        }\n    }\n\n    open func aggregate(_ pipeline: [[String: Encodable]],\n                        options: API.Options = []) {\n        query.aggregate(pipeline, options: options) { result in\n            switch result {\n            case .success(let results):\n                self.results = results\n            case .failure(let error):\n                self.error = error\n            }\n        }\n    }\n}\n\n// MARK: QueryViewModel\npublic extension Query {\n\n    /**\n     Creates a view model for this query. Suitable for `ObjectObserved`\n     as the view model can be used as a SwiftUI publisher. Meaning it can serve\n     indepedently as a ViewModel in MVVM.\n     */\n    var viewModel: QueryViewModel<ResultType> {\n        QueryViewModel(query: self)\n    }\n\n    /**\n     Creates a view model for this query. Suitable for `ObjectObserved`\n     as the view model can be used as a SwiftUI publisher. Meaning it can serve\n     indepedently as a ViewModel in MVVM.\n     - parameter query: Any query.\n     - returns: The view model for this query.\n     */\n    static func viewModel(_ query: Self) -> QueryViewModel<ResultType> {\n        QueryViewModel(query: query)\n    }\n}\n#endif\n"
  },
  {
    "path": "Sources/ParseSwift/Types/QueryWhere.swift",
    "content": "//\n//  QueryWhere.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 12/9/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\n/// The **where** of a `Query`.\npublic struct QueryWhere: ParseTypeable {\n    var constraints = [String: Set<QueryConstraint>]()\n\n    mutating func add(_ constraint: QueryConstraint) {\n        var existing = constraints[constraint.key] ?? []\n        existing.insert(constraint)\n        constraints[constraint.key] = existing\n    }\n\n    public func encode(to encoder: Encoder) throws {\n        var container = encoder.container(keyedBy: RawCodingKey.self)\n        try constraints.forEach { (key, value) in\n            try value.forEach { (constraint) in\n                if let comparator = constraint.comparator {\n                    var nestedContainer = container.nestedContainer(keyedBy: QueryConstraint.Comparator.self,\n                                                                    forKey: .key(key))\n                    try constraint.encode(to: nestedContainer.superEncoder(forKey: comparator))\n                } else {\n                    try container.encode(constraint, forKey: .key(key))\n                }\n            }\n        }\n    }\n}\n\npublic extension QueryWhere {\n    init(from decoder: Decoder) throws {\n        let container = try decoder.container(keyedBy: RawCodingKey.self)\n        try container.allKeys.forEach { key in\n            do {\n                let pointer = try container.decode(PointerType.self, forKey: key)\n                var constraint = QueryConstraint(key: key.stringValue)\n                constraint.value = AnyCodable(pointer)\n                self.add(constraint)\n            } catch {\n                do {\n                    let nestedContainer = try container.nestedContainer(keyedBy: QueryConstraint.Comparator.self,\n                                                                        forKey: key)\n                    QueryConstraint.Comparator.allCases.forEach { comparator in\n                        guard var constraint = try? nestedContainer.decode(QueryConstraint.self,\n                                                                           forKey: comparator) else {\n                            return\n                        }\n                        constraint.key = key.stringValue\n                        self.add(constraint)\n                    }\n                } catch {\n                    var constraint = try container.decode(QueryConstraint.self, forKey: key)\n                    constraint.key = key.stringValue\n                    self.add(constraint)\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "TestHost/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  TestHost\n//\n//  Created by Florent Vilmart on 17-09-25.\n//  Copyright © 2017 Parse. All rights reserved.\n//\n\nimport UIKit\n\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n    func application(_ application: UIApplication,\n                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {\n        return true\n    }\n}\n"
  },
  {
    "path": "TestHost/Assets.xcassets/AppIcon.appiconset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"iphone\",\n      \"size\" : \"60x60\",\n      \"scale\" : \"3x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"20x20\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"29x29\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"40x40\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"76x76\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ipad\",\n      \"size\" : \"83.5x83.5\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"ios-marketing\",\n      \"size\" : \"1024x1024\",\n      \"scale\" : \"1x\"\n    }\n  ],\n  \"info\" : {\n    \"version\" : 1,\n    \"author\" : \"xcode\"\n  }\n}"
  },
  {
    "path": "TestHost/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" systemVersion=\"17A277\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"01J-lp-oVM\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"EHf-IW-A2E\">\n            <objects>\n                <viewController id=\"01J-lp-oVM\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"Ze5-6b-2t3\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"iYj-Kq-Ea1\" userLabel=\"First Responder\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n            <point key=\"canvasLocation\" x=\"53\" y=\"375\"/>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "TestHost/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB\" version=\"3.0\" toolsVersion=\"13122.16\" systemVersion=\"17A277\" targetRuntime=\"iOS.CocoaTouch\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"375\" height=\"667\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"1\" green=\"1\" blue=\"1\" alpha=\"1\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"6Tk-OE-BBY\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "TestHost/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>APPL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>armv7</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n\t<key>UISupportedInterfaceOrientations~ipad</key>\n\t<array>\n\t\t<string>UIInterfaceOrientationPortrait</string>\n\t\t<string>UIInterfaceOrientationPortraitUpsideDown</string>\n\t\t<string>UIInterfaceOrientationLandscapeLeft</string>\n\t\t<string>UIInterfaceOrientationLandscapeRight</string>\n\t</array>\n    <key>NSAppTransportSecurity</key>\n    <dict>\n        <key>NSAllowsArbitraryLoads</key>\n        <false/>\n        <key>NSExceptionDomains</key>\n        <dict>\n            <key>localhost</key>\n            <dict>\n                <key>NSAllowsArbitraryLoads</key>\n                <true/>\n            </dict>\n        </dict>\n    </dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "TestHostTV/AppDelegate.swift",
    "content": "//\n//  AppDelegate.swift\n//  TestHostTV\n//\n//  Created by Corey Baker on 11/8/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport UIKit\n\n@main\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n\n    var window: UIWindow?\n\n    func application(_ application: UIApplication,\n                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {\n        return true\n    }\n}\n"
  },
  {
    "path": "TestHostTV/Assets.xcassets/AccentColor.colorset/Contents.json",
    "content": "{\n  \"colors\" : [\n    {\n      \"idiom\" : \"universal\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "TestHostTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "TestHostTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "TestHostTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"layers\" : [\n    {\n      \"filename\" : \"Front.imagestacklayer\"\n    },\n    {\n      \"filename\" : \"Middle.imagestacklayer\"\n    },\n    {\n      \"filename\" : \"Back.imagestacklayer\"\n    }\n  ]\n}\n"
  },
  {
    "path": "TestHostTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "TestHostTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "TestHostTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "TestHostTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "TestHostTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "TestHostTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "TestHostTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  },\n  \"layers\" : [\n    {\n      \"filename\" : \"Front.imagestacklayer\"\n    },\n    {\n      \"filename\" : \"Middle.imagestacklayer\"\n    },\n    {\n      \"filename\" : \"Back.imagestacklayer\"\n    }\n  ]\n}\n"
  },
  {
    "path": "TestHostTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "TestHostTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "TestHostTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "TestHostTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "TestHostTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json",
    "content": "{\n  \"assets\" : [\n    {\n      \"filename\" : \"App Icon - App Store.imagestack\",\n      \"idiom\" : \"tv\",\n      \"role\" : \"primary-app-icon\",\n      \"size\" : \"1280x768\"\n    },\n    {\n      \"filename\" : \"App Icon.imagestack\",\n      \"idiom\" : \"tv\",\n      \"role\" : \"primary-app-icon\",\n      \"size\" : \"400x240\"\n    },\n    {\n      \"filename\" : \"Top Shelf Image Wide.imageset\",\n      \"idiom\" : \"tv\",\n      \"role\" : \"top-shelf-image-wide\",\n      \"size\" : \"2320x720\"\n    },\n    {\n      \"filename\" : \"Top Shelf Image.imageset\",\n      \"idiom\" : \"tv\",\n      \"role\" : \"top-shelf-image\",\n      \"size\" : \"1920x720\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "TestHostTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"tv-marketing\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"tv-marketing\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "TestHostTV/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json",
    "content": "{\n  \"images\" : [\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"tv\",\n      \"scale\" : \"2x\"\n    },\n    {\n      \"idiom\" : \"tv-marketing\",\n      \"scale\" : \"1x\"\n    },\n    {\n      \"idiom\" : \"tv-marketing\",\n      \"scale\" : \"2x\"\n    }\n  ],\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "TestHostTV/Assets.xcassets/Contents.json",
    "content": "{\n  \"info\" : {\n    \"author\" : \"xcode\",\n    \"version\" : 1\n  }\n}\n"
  },
  {
    "path": "TestHostTV/Base.lproj/LaunchScreen.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<document type=\"com.apple.InterfaceBuilder.AppleTV.Storyboard\" version=\"3.0\" toolsVersion=\"13122.16\" targetRuntime=\"AppleTV\" propertyAccessControl=\"none\" useAutolayout=\"YES\" launchScreen=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" sceneMemberID=\"viewController\">\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1920\" height=\"1080\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"0.0\" green=\"0.0\" blue=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"wu6-TO-1qx\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "TestHostTV/Base.lproj/Main.storyboard",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document type=\"com.apple.InterfaceBuilder.AppleTV.Storyboard\" version=\"3.0\" toolsVersion=\"13122.16\" targetRuntime=\"AppleTV\" propertyAccessControl=\"none\" useAutolayout=\"YES\" useTraitCollections=\"YES\" useSafeAreas=\"YES\" colorMatched=\"YES\" initialViewController=\"BYZ-38-t0r\">\n    <dependencies>\n        <plugIn identifier=\"com.apple.InterfaceBuilder.IBCocoaTouchPlugin\" version=\"13104.12\"/>\n        <capability name=\"Safe area layout guides\" minToolsVersion=\"9.0\"/>\n        <capability name=\"documents saved in the Xcode 8 format\" minToolsVersion=\"8.0\"/>\n    </dependencies>\n    <scenes>\n        <!--View Controller-->\n        <scene sceneID=\"tne-QT-ifu\">\n            <objects>\n                <viewController id=\"BYZ-38-t0r\" customClass=\"ViewController\" customModuleProvider=\"target\" sceneMemberID=\"viewController\">\n                    <layoutGuides>\n                        <viewControllerLayoutGuide type=\"top\" id=\"y3c-jy-aDJ\"/>\n                        <viewControllerLayoutGuide type=\"bottom\" id=\"wfy-db-euE\"/>\n                    </layoutGuides>\n                    <view key=\"view\" contentMode=\"scaleToFill\" id=\"8bC-Xf-vdC\">\n                        <rect key=\"frame\" x=\"0.0\" y=\"0.0\" width=\"1920\" height=\"1080\"/>\n                        <autoresizingMask key=\"autoresizingMask\" widthSizable=\"YES\" heightSizable=\"YES\"/>\n                        <color key=\"backgroundColor\" red=\"0.0\" green=\"0.0\" blue=\"0.0\" alpha=\"0.0\" colorSpace=\"custom\" customColorSpace=\"sRGB\"/>\n                        <viewLayoutGuide key=\"safeArea\" id=\"wu6-TO-1qx\"/>\n                    </view>\n                </viewController>\n                <placeholder placeholderIdentifier=\"IBFirstResponder\" id=\"dkx-z0-nzr\" sceneMemberID=\"firstResponder\"/>\n            </objects>\n        </scene>\n    </scenes>\n</document>\n"
  },
  {
    "path": "TestHostTV/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n\t<key>LSRequiresIPhoneOS</key>\n\t<true/>\n\t<key>UILaunchStoryboardName</key>\n\t<string>LaunchScreen</string>\n\t<key>UIMainStoryboardFile</key>\n\t<string>Main</string>\n\t<key>UIRequiredDeviceCapabilities</key>\n\t<array>\n\t\t<string>arm64</string>\n\t</array>\n\t<key>UIUserInterfaceStyle</key>\n\t<string>Automatic</string>\n    <key>NSAppTransportSecurity</key>\n    <dict>\n        <key>NSAllowsArbitraryLoads</key>\n        <false/>\n        <key>NSExceptionDomains</key>\n        <dict>\n            <key>localhost</key>\n            <dict>\n                <key>NSAllowsArbitraryLoads</key>\n                <true/>\n            </dict>\n        </dict>\n    </dict>\n</dict>\n</plist>\n"
  },
  {
    "path": "TestHostTV/ViewController.swift",
    "content": "//\n//  ViewController.swift\n//  TestHostTV\n//\n//  Created by Corey Baker on 11/8/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport UIKit\n\nclass ViewController: UIViewController {\n\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        // Do any additional setup after loading the view.\n    }\n\n}\n"
  },
  {
    "path": "Tests/LinuxMain.swift",
    "content": "import XCTest\n\nimport ParseSwiftTests\n\nfatalError(\"Running tests like this is unsupported. Run the tests again by using `swift test --enable-test-discovery`\")\n"
  },
  {
    "path": "Tests/ParseSwiftTests/APICommandTests.swift",
    "content": "//\n//  APICommandTests.swift\n//  ParseSwiftTests\n//\n//  Created by Corey Baker on 7/19/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass APICommandTests: XCTestCase {\n\n    struct Level: ParseObject {\n        var objectId: String?\n\n        var createdAt: Date?\n\n        var updatedAt: Date?\n\n        var ACL: ParseACL?\n\n        var name = \"First\"\n\n        var originalData: Data?\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    func userLogin() {\n        let loginResponse = LoginSignupResponse()\n        let loginUserName = \"hello10\"\n        let loginPassword = \"world\"\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        do {\n            _ = try User.login(username: loginUserName, password: loginPassword)\n            MockURLProtocol.removeAll()\n        } catch {\n            XCTFail(\"Should login\")\n        }\n    }\n\n    func testOptionCacheHasher() throws {\n        var options = API.Options()\n        options.insert(.cachePolicy(.returnCacheDataDontLoad))\n        XCTAssertFalse(options.contains(.useMasterKey))\n        XCTAssertTrue(options.contains(.cachePolicy(.returnCacheDataDontLoad)))\n        XCTAssertTrue(options.contains(.cachePolicy(.reloadRevalidatingCacheData)))\n        options.insert(.useMasterKey)\n        XCTAssertTrue(options.contains(.useMasterKey))\n    }\n\n    func testExecuteCorrectly() {\n        let originalObject = \"test\"\n        MockURLProtocol.mockRequests { _ in\n            do {\n                return try MockURLResponse(string: originalObject, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        do {\n            let returnedObject =\n                try API.NonParseBodyCommand<NoBody, String>(method: .GET,\n                                                            path: .login,\n                                                            params: nil,\n                                                            mapper: { (data) -> String in\n                    return try JSONDecoder().decode(String.self, from: data)\n                }).execute(options: [])\n            XCTAssertEqual(originalObject, returnedObject)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    //This is how errors from the server should typically come in\n    func testErrorFromParseServer() {\n        let originalError = ParseError(code: .unknownError, message: \"Could not decode\")\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try JSONEncoder().encode(originalError)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                XCTFail(\"Should encode error\")\n                return nil\n            }\n        }\n\n        do {\n            _ = try API.NonParseBodyCommand<NoBody, NoBody>(method: .GET,\n                                                            path: .login,\n                                                            params: nil,\n                                                            mapper: { (_) -> NoBody in\n                throw originalError\n            }).execute(options: [])\n            XCTFail(\"Should have thrown an error\")\n        } catch {\n            guard let error = error as? ParseError else {\n                XCTFail(\"should be able unwrap final error to ParseError\")\n                return\n            }\n            XCTAssertEqual(originalError.code, error.code)\n        }\n    }\n\n    // This is how errors HTTP errors should typically come in\n    func testErrorHTTP400JSON() {\n        let parseError = ParseError(code: .connectionFailed, message: \"Connection failed\")\n        let errorKey = \"error\"\n        let errorValue = \"yarr\"\n        let codeKey = \"code\"\n        let codeValue = 100\n        let responseDictionary: [String: Any] = [\n            errorKey: errorValue,\n            codeKey: codeValue\n        ]\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let json = try JSONSerialization.data(withJSONObject: responseDictionary, options: [])\n                return MockURLResponse(data: json, statusCode: 400, delay: 0.0)\n            } catch {\n                XCTFail(error.localizedDescription)\n                return nil\n            }\n        }\n\n        do {\n            _ = try API.NonParseBodyCommand<NoBody, NoBody>(method: .GET,\n                                                            path: .login,\n                                                            params: nil,\n                                                            mapper: { (_) -> NoBody in\n                throw parseError\n            }).execute(options: [])\n\n            XCTFail(\"Should have thrown an error\")\n        } catch {\n            guard let error = error as? ParseError else {\n                XCTFail(\"should be able unwrap final error to ParseError\")\n                return\n            }\n            XCTAssertEqual(error.code, parseError.code)\n        }\n    }\n\n    //This is how errors HTTP errors should typically come in\n    func testErrorHTTP500JSON() {\n        let parseError = ParseError(code: .connectionFailed, message: \"Connection failed\")\n        let errorKey = \"error\"\n        let errorValue = \"yarr\"\n        let codeKey = \"code\"\n        let codeValue = 100\n        let responseDictionary: [String: Any] = [\n            errorKey: errorValue,\n            codeKey: codeValue\n        ]\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let json = try JSONSerialization.data(withJSONObject: responseDictionary, options: [])\n                return MockURLResponse(data: json, statusCode: 500, delay: 0.0)\n            } catch {\n                XCTFail(error.localizedDescription)\n                return nil\n            }\n        }\n\n        do {\n            _ = try API.NonParseBodyCommand<NoBody, NoBody>(method: .GET,\n                                                            path: .login,\n                                                            params: nil,\n                                                            mapper: { (_) -> NoBody in\n                throw parseError\n            }).execute(options: [])\n\n            XCTFail(\"Should have thrown an error\")\n        } catch {\n            guard let error = error as? ParseError else {\n                XCTFail(\"should be able unwrap final error to ParseError\")\n                return\n            }\n            XCTAssertEqual(error.code, parseError.code)\n        }\n    }\n\n    func testErrorHTTPReturns400NoDataFromServer() {\n        let originalError = ParseError(code: .unknownError, message: \"Could not decode\")\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(error: originalError) // Status code defaults to 400\n        }\n        do {\n            _ = try API.NonParseBodyCommand<NoBody, NoBody>(method: .GET,\n                                                            path: .login,\n                                                            params: nil,\n                                                            mapper: { (_) -> NoBody in\n                throw originalError\n            }).execute(options: [])\n            XCTFail(\"Should have thrown an error\")\n        } catch {\n            guard let error = error as? ParseError else {\n                XCTFail(\"should be able unwrap final error to ParseError\")\n                return\n            }\n            XCTAssertEqual(originalError.code, error.code)\n        }\n    }\n\n    func testErrorHTTPReturns500NoDataFromServer() {\n        let originalError = ParseError(code: .unknownError, message: \"Could not decode\")\n        MockURLProtocol.mockRequests { _ in\n            var response = MockURLResponse(error: originalError)\n            response.statusCode = 500\n            return response\n        }\n        do {\n            _ = try API.NonParseBodyCommand<NoBody, NoBody>(method: .GET,\n                                                            path: .login,\n                                                            params: nil,\n                                                            mapper: { (_) -> NoBody in\n                throw originalError\n            }).execute(options: [])\n            XCTFail(\"Should have thrown an error\")\n        } catch {\n            guard let error = error as? ParseError else {\n                XCTFail(\"should be able unwrap final error to ParseError\")\n                return\n            }\n            XCTAssertEqual(originalError.code, error.code)\n        }\n    }\n\n    func testApplicationIdHeader() {\n        let headers = API.getHeaders(options: [])\n        XCTAssertEqual(headers[\"X-Parse-Application-Id\"], ParseSwift.configuration.applicationId)\n\n        let post = API.NonParseBodyCommand<NoBody, NoBody?>(method: .POST, path: .login) { _ in\n            return nil\n        }\n\n        switch post.prepareURLRequest(options: []) {\n\n        case .success(let request):\n            XCTAssertEqual(request.allHTTPHeaderFields?[\"X-Parse-Application-Id\"],\n                           ParseSwift.configuration.applicationId)\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testClientKeyHeader() throws {\n        guard let clientKey = ParseSwift.configuration.clientKey else {\n            throw ParseError(code: .unknownError, message: \"Parse configuration should contain key\")\n        }\n\n        let headers = API.getHeaders(options: [])\n        XCTAssertEqual(headers[\"X-Parse-Client-Key\"], clientKey)\n\n        let post = API.NonParseBodyCommand<NoBody, NoBody?>(method: .POST, path: .login) { _ in\n            return nil\n        }\n\n        switch post.prepareURLRequest(options: []) {\n\n        case .success(let request):\n            XCTAssertEqual(request.allHTTPHeaderFields?[\"X-Parse-Client-Key\"],\n                           clientKey)\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testPrimaryKeyHeader() throws {\n        guard let primaryKey = ParseSwift.configuration.masterKey else {\n            throw ParseError(code: .unknownError, message: \"Parse configuration should contain key\")\n        }\n\n        let headers = API.getHeaders(options: [])\n        XCTAssertNil(headers[\"X-Parse-Master-Key\"])\n\n        let post = API.NonParseBodyCommand<NoBody, NoBody?>(method: .POST, path: .login) { _ in\n            return nil\n        }\n\n        switch post.prepareURLRequest(options: [.useMasterKey]) {\n\n        case .success(let request):\n            XCTAssertEqual(request.allHTTPHeaderFields?[\"X-Parse-Master-Key\"],\n                           primaryKey)\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testSessionTokenHeader() throws {\n        userLogin()\n        guard let sessionToken = BaseParseUser.currentContainer?.sessionToken else {\n            throw ParseError(code: .unknownError, message: \"Parse current user should have session token\")\n        }\n\n        let headers = API.getHeaders(options: [])\n        XCTAssertEqual(headers[\"X-Parse-Session-Token\"], sessionToken)\n\n        let post = API.NonParseBodyCommand<NoBody, NoBody?>(method: .POST, path: .login) { _ in\n            return nil\n        }\n\n        switch post.prepareURLRequest(options: []) {\n\n        case .success(let request):\n            XCTAssertEqual(request.allHTTPHeaderFields?[\"X-Parse-Session-Token\"],\n                           sessionToken)\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testReplaceSessionTokenHeader() throws {\n\n        let post = API.NonParseBodyCommand<NoBody, NoBody?>(method: .POST, path: .login) { _ in\n            return nil\n        }\n\n        switch post.prepareURLRequest(options: [.sessionToken(\"hello\")]) {\n\n        case .success(let request):\n            XCTAssertEqual(request.allHTTPHeaderFields?[\"X-Parse-Session-Token\"],\n                           \"hello\")\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testInstallationIdHeader() throws {\n        guard let installationId = BaseParseInstallation.currentContainer.installationId else {\n            throw ParseError(code: .unknownError, message: \"Parse current user should have session token\")\n        }\n\n        let headers = API.getHeaders(options: [])\n        XCTAssertEqual(headers[\"X-Parse-Installation-Id\"], installationId)\n\n        let post = API.NonParseBodyCommand<NoBody, NoBody?>(method: .POST, path: .login) { _ in\n            return nil\n        }\n\n        switch post.prepareURLRequest(options: []) {\n\n        case .success(let request):\n            XCTAssertEqual(request.allHTTPHeaderFields?[\"X-Parse-Installation-Id\"],\n                           installationId)\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testReplaceInstallationIdHeader() throws {\n        let post = API.NonParseBodyCommand<NoBody, NoBody?>(method: .POST, path: .login) { _ in\n            return nil\n        }\n\n        switch post.prepareURLRequest(options: [.installationId(\"hello\")]) {\n\n        case .success(let request):\n            XCTAssertEqual(request.allHTTPHeaderFields?[\"X-Parse-Installation-Id\"],\n                           \"hello\")\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testContentHeader() {\n        let headers = API.getHeaders(options: [])\n        XCTAssertEqual(headers[\"Content-Type\"], \"application/json\")\n\n        let post = API.NonParseBodyCommand<NoBody, NoBody?>(method: .POST, path: .login) { _ in\n            return nil\n        }\n\n        switch post.prepareURLRequest(options: []) {\n\n        case .success(let request):\n            XCTAssertEqual(request.allHTTPHeaderFields?[\"Content-Type\"],\n                           \"application/json\")\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testReplaceContentHeader() {\n        let headers = API.getHeaders(options: [])\n        XCTAssertEqual(headers[\"Content-Type\"], \"application/json\")\n\n        let post = API.NonParseBodyCommand<NoBody, NoBody?>(method: .POST, path: .login) { _ in\n            return nil\n        }\n\n        switch post.prepareURLRequest(options: [.mimeType(\"application/html\")]) {\n\n        case .success(let request):\n            XCTAssertEqual(request.allHTTPHeaderFields?[\"Content-Type\"],\n                           \"application/html\")\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testContentLengthHeader() {\n        let post = API.NonParseBodyCommand<NoBody, NoBody?>(method: .POST, path: .login) { _ in\n            return nil\n        }\n\n        switch post.prepareURLRequest(options: [.fileSize(\"512\")]) {\n\n        case .success(let request):\n            XCTAssertEqual(request.allHTTPHeaderFields?[\"Content-Length\"],\n                           \"512\")\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testRemoveContentHeader() {\n        let headers = API.getHeaders(options: [])\n        XCTAssertEqual(headers[\"Content-Type\"], \"application/json\")\n\n        let post = API.NonParseBodyCommand<NoBody, NoBody?>(method: .POST, path: .login) { _ in\n            return nil\n        }\n\n        switch post.prepareURLRequest(options: [.removeMimeType]) {\n\n        case .success(let request):\n            XCTAssertNil(request.allHTTPHeaderFields?[\"Content-Type\"])\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testClientVersionAPIMethod() {\n        let clientVersion = API.clientVersion()\n        XCTAssertTrue(clientVersion.contains(ParseConstants.sdk))\n        XCTAssertTrue(clientVersion.contains(ParseConstants.version))\n\n        let splitString = clientVersion\n            .components(separatedBy: ParseConstants.sdk)\n        XCTAssertEqual(splitString.count, 2)\n        //If successful, will remove `swift` resulting in \"\"\n        XCTAssertEqual(splitString[0], \"\")\n        XCTAssertEqual(splitString[1], ParseConstants.version)\n\n        //Test incorrect split\n        let splitString2 = clientVersion\n            .components(separatedBy: \"hello\")\n        XCTAssertEqual(splitString2.count, 1)\n        XCTAssertEqual(splitString2[0], clientVersion)\n    }\n\n    func testClientVersionHeader() {\n        let headers = API.getHeaders(options: [])\n        XCTAssertEqual(headers[\"X-Parse-Client-Version\"], API.clientVersion())\n\n        let post = API.Command<Level, NoBody?>(method: .POST, path: .login) { _ in\n            return nil\n        }\n        switch post.prepareURLRequest(options: []) {\n\n        case .success(let request):\n            if request.allHTTPHeaderFields?[\"X-Parse-Client-Version\"] != API.clientVersion() {\n                XCTFail(\"Should contain correct Client Version header\")\n            }\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n\n        let put = API.Command<Level, NoBody?>(method: .PUT, path: .login) { _ in\n            return nil\n        }\n        switch put.prepareURLRequest(options: []) {\n\n        case .success(let request):\n            if request.allHTTPHeaderFields?[\"X-Parse-Client-Version\"] != API.clientVersion() {\n                XCTFail(\"Should contain correct Client Version header\")\n            }\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n\n        let patch = API.Command<Level, NoBody?>(method: .PATCH, path: .login) { _ in\n            return nil\n        }\n        switch patch.prepareURLRequest(options: []) {\n\n        case .success(let request):\n            if request.allHTTPHeaderFields?[\"X-Parse-Client-Version\"] != API.clientVersion() {\n                XCTFail(\"Should contain correct Client Version header\")\n            }\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n\n        let delete = API.Command<Level, NoBody?>(method: .DELETE, path: .login) { _ in\n            return nil\n        }\n        switch delete.prepareURLRequest(options: []) {\n\n        case .success(let request):\n            if request.allHTTPHeaderFields?[\"X-Parse-Client-Version\"] != API.clientVersion() {\n                XCTFail(\"Should contain correct Client Version header\")\n            }\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n\n        let get = API.Command<Level, NoBody?>(method: .GET, path: .login) { _ in\n            return nil\n        }\n        switch get.prepareURLRequest(options: []) {\n\n        case .success(let request):\n            if request.allHTTPHeaderFields?[\"X-Parse-Client-Version\"] != API.clientVersion() {\n                XCTFail(\"Should contain correct Client Version header\")\n            }\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testIdempodency() {\n        let headers = API.getHeaders(options: [])\n        XCTAssertNotNil(headers[\"X-Parse-Request-Id\"])\n\n        let post = API.Command<Level, NoBody?>(method: .POST, path: .login) { _ in\n            return nil\n        }\n        switch post.prepareURLRequest(options: []) {\n\n        case .success(let request):\n            if request.allHTTPHeaderFields?[\"X-Parse-Request-Id\"] == nil {\n                XCTFail(\"Should contain idempotent header ID\")\n            }\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n\n        let put = API.Command<Level, NoBody?>(method: .PUT, path: .login) { _ in\n            return nil\n        }\n        switch put.prepareURLRequest(options: []) {\n\n        case .success(let request):\n            if request.allHTTPHeaderFields?[\"X-Parse-Request-Id\"] == nil {\n                XCTFail(\"Should contain idempotent header ID\")\n            }\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n\n        let patch = API.Command<Level, NoBody?>(method: .PATCH, path: .login) { _ in\n            return nil\n        }\n        switch patch.prepareURLRequest(options: []) {\n\n        case .success(let request):\n            if request.allHTTPHeaderFields?[\"X-Parse-Request-Id\"] == nil {\n                XCTFail(\"Should contain idempotent header ID\")\n            }\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n\n        let delete = API.Command<Level, NoBody?>(method: .DELETE, path: .login) { _ in\n            return nil\n        }\n        switch delete.prepareURLRequest(options: []) {\n\n        case .success(let request):\n            if request.allHTTPHeaderFields?[\"X-Parse-Request-Id\"] != nil {\n                XCTFail(\"Should not contain idempotent header ID\")\n            }\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n\n        let get = API.Command<Level, NoBody?>(method: .GET, path: .login) { _ in\n            return nil\n        }\n        switch get.prepareURLRequest(options: []) {\n\n        case .success(let request):\n            if request.allHTTPHeaderFields?[\"X-Parse-Request-Id\"] != nil {\n                XCTFail(\"Should not contain idempotent header ID\")\n            }\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testIdempodencyNoParseBody() {\n        let headers = API.getHeaders(options: [])\n        XCTAssertNotNil(headers[\"X-Parse-Request-Id\"])\n\n        let post = API.NonParseBodyCommand<NoBody, NoBody?>(method: .POST, path: .login) { _ in\n            return nil\n        }\n        switch post.prepareURLRequest(options: []) {\n\n        case .success(let request):\n            if request.allHTTPHeaderFields?[\"X-Parse-Request-Id\"] == nil {\n                XCTFail(\"Should contain idempotent header ID\")\n            }\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n\n        let put = API.NonParseBodyCommand<NoBody, NoBody?>(method: .PUT, path: .login) { _ in\n            return nil\n        }\n        switch put.prepareURLRequest(options: []) {\n\n        case .success(let request):\n            if request.allHTTPHeaderFields?[\"X-Parse-Request-Id\"] == nil {\n                XCTFail(\"Should contain idempotent header ID\")\n            }\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n\n        let patch = API.NonParseBodyCommand<NoBody, NoBody?>(method: .PATCH, path: .login) { _ in\n            return nil\n        }\n        switch patch.prepareURLRequest(options: []) {\n\n        case .success(let request):\n            if request.allHTTPHeaderFields?[\"X-Parse-Request-Id\"] == nil {\n                XCTFail(\"Should contain idempotent header ID\")\n            }\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n\n        let delete = API.NonParseBodyCommand<NoBody, NoBody?>(method: .DELETE, path: .login) { _ in\n            return nil\n        }\n        switch delete.prepareURLRequest(options: []) {\n\n        case .success(let request):\n            if request.allHTTPHeaderFields?[\"X-Parse-Request-Id\"] != nil {\n                XCTFail(\"Should not contain idempotent header ID\")\n            }\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n\n        let get = API.NonParseBodyCommand<NoBody, NoBody?>(method: .GET, path: .login) { _ in\n            return nil\n        }\n        switch get.prepareURLRequest(options: []) {\n\n        case .success(let request):\n            if request.allHTTPHeaderFields?[\"X-Parse-Request-Id\"] != nil {\n                XCTFail(\"Should not contain idempotent header ID\")\n            }\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testMetaDataHeader() {\n        let post = API.NonParseBodyCommand<NoBody, NoBody?>(method: .POST, path: .login) { _ in\n            return nil\n        }\n\n        switch post.prepareURLRequest(options: [.metadata([\"hello\": \"world\"])]) {\n\n        case .success(let request):\n            XCTAssertEqual(request.allHTTPHeaderFields?[\"hello\"], \"world\")\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testTagsHeader() {\n        let post = API.NonParseBodyCommand<NoBody, NoBody?>(method: .POST, path: .login) { _ in\n            return nil\n        }\n\n        switch post.prepareURLRequest(options: [.tags([\"hello\": \"world\"])]) {\n\n        case .success(let request):\n            XCTAssertEqual(request.allHTTPHeaderFields?[\"hello\"], \"world\")\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testContextHeader() {\n        let headers = API.getHeaders(options: [])\n        XCTAssertNil(headers[\"X-Parse-Cloud-Context\"])\n\n        let post = API.NonParseBodyCommand<NoBody, NoBody?>(method: .POST, path: .login) { _ in\n            return nil\n        }\n\n        switch post.prepareURLRequest(options: [.context([\"hello\": \"world\"])]) {\n\n        case .success(let request):\n            XCTAssertEqual(request.allHTTPHeaderFields?[\"X-Parse-Cloud-Context\"], \"{\\\"hello\\\":\\\"world\\\"}\")\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/AnyCodableTests/AnyCodableTests.swift",
    "content": "import XCTest\n@testable import ParseSwift\n\nclass AnyCodableTests: XCTestCase {\n\n    struct SomeCodable: Codable {\n        var string: String\n        var int: Int\n        var bool: Bool\n        var hasUnderscore: String\n\n        // swiftlint:disable:next nesting\n        enum CodingKeys: String, CodingKey {\n            case string\n            case int\n            case bool\n            case hasUnderscore = \"has_underscore\"\n        }\n    }\n\n    func testJSONDecoding() {\n        guard let json = \"\"\"\n        {\n            \"boolean\": true,\n            \"integer\": 1,\n            \"double\": 3.14159265358979323846,\n            \"string\": \"string\",\n            \"array\": [1, 2, 3],\n            \"nested\": {\n                \"a\": \"alpha\",\n                \"b\": \"bravo\",\n                \"c\": \"charlie\"\n            }\n        }\n        \"\"\".data(using: .utf8) else {\n            XCTFail(\"Should unrap data as utf8\")\n            return\n        }\n        let decoder = JSONDecoder()\n        do {\n            let dictionary = try decoder.decode([String: AnyCodable].self, from: json)\n            XCTAssertEqual(dictionary[\"boolean\"]?.value as? Bool, true)\n            XCTAssertEqual(dictionary[\"integer\"]?.value as? Int, 1)\n            guard let doubleValue = dictionary[\"double\"]?.value as? Double else {\n                XCTFail(\"Should unrap value as Double\")\n                return\n            }\n            XCTAssertEqual(doubleValue, 3.14159265358979323846, accuracy: 0.001)\n            XCTAssertEqual(dictionary[\"string\"]?.value as? String, \"string\")\n            XCTAssertEqual(dictionary[\"array\"]?.value as? [Int], [1, 2, 3])\n            XCTAssertEqual(dictionary[\"nested\"]?.value as? [String: String],\n                           [\"a\": \"alpha\", \"b\": \"bravo\", \"c\": \"charlie\"])\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    //Test has objective-c\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testJSONEncoding() {\n\n        let someCodable = AnyCodable(SomeCodable(string: \"String\",\n                                                 int: 100,\n                                                 bool: true,\n                                                 hasUnderscore: \"another string\"))\n\n        let dictionary: [String: AnyCodable] = [\n            \"boolean\": true,\n            \"integer\": 42,\n            \"double\": 3.14159265358979323846,\n            \"string\": \"string\",\n            \"array\": [1, 2, 3],\n            \"nested\": [\n                \"a\": \"alpha\",\n                \"b\": \"bravo\",\n                \"c\": \"charlie\"\n            ],\n            \"someCodable\": someCodable,\n            \"null\": nil\n        ]\n        do {\n            let encoder = JSONEncoder()\n            let json = try encoder.encode(dictionary)\n            guard let encodedJSONObject =\n                try JSONSerialization.jsonObject(with: json, options: []) as? NSDictionary else {\n                    XCTFail(\"Should unrap JSON serialized object\")\n                    return\n            }\n            guard let expected = \"\"\"\n            {\n                \"boolean\": 1,\n                \"integer\": 42,\n                \"double\": 3.14159265358979323846,\n                \"string\": \"string\",\n                \"array\": [1, 2, 3],\n                \"nested\": {\n                    \"a\": \"alpha\",\n                    \"b\": \"bravo\",\n                    \"c\": \"charlie\"\n                },\n                \"someCodable\": {\n                    \"string\":\"String\",\n                    \"int\":100,\n                    \"bool\": true,\n                    \"has_underscore\":\"another string\"\n                },\n                \"null\": null\n            }\n            \"\"\".data(using: .utf8) else {\n                XCTFail(\"Should unrap data to utf8\")\n                return\n            }\n            guard let expectedJSONObject =\n                try JSONSerialization.jsonObject(with: expected, options: []) as? NSDictionary else {\n                XCTFail(\"Should unrap JSON serialized object\")\n                return\n            }\n            XCTAssertEqual(encodedJSONObject, expectedJSONObject)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n    #endif\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/AnyCodableTests/AnyDecodableTests.swift",
    "content": "import XCTest\n@testable import ParseSwift\n\nclass AnyDecodableTests: XCTestCase {\n    func testJSONDecoding() {\n        guard let json = \"\"\"\n        {\n            \"boolean\": true,\n            \"integer\": 1,\n            \"double\": 3.14159265358979323846,\n            \"string\": \"string\",\n            \"array\": [1, 2, 3],\n            \"nested\": {\n                \"a\": \"alpha\",\n                \"b\": \"bravo\",\n                \"c\": \"charlie\"\n            }\n        }\n        \"\"\".data(using: .utf8) else {\n            XCTFail(\"Should unrap data as utf8\")\n            return\n        }\n        do {\n            let decoder = JSONDecoder()\n            let dictionary = try decoder.decode([String: AnyDecodable].self, from: json)\n            XCTAssertEqual(dictionary[\"boolean\"]?.value as? Bool, true)\n            XCTAssertEqual(dictionary[\"integer\"]?.value as? Int, 1)\n            guard let doubleValue = dictionary[\"double\"]?.value as? Double else {\n                XCTFail(\"Should unrap data as Double\")\n                return\n            }\n            XCTAssertEqual(doubleValue, 3.14159265358979323846, accuracy: 0.001)\n            XCTAssertEqual(dictionary[\"string\"]?.value as? String, \"string\")\n            XCTAssertEqual(dictionary[\"array\"]?.value as? [Int], [1, 2, 3])\n            XCTAssertEqual(dictionary[\"nested\"]?.value as? [String: String],\n                           [\"a\": \"alpha\", \"b\": \"bravo\", \"c\": \"charlie\"])\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/AnyCodableTests/AnyEncodableTests.swift",
    "content": "import XCTest\n@testable import ParseSwift\n\n// Test has objective-c\n#if !os(Linux) && !os(Android) && !os(Windows)\nclass AnyEncodableTests: XCTestCase {\n\n    struct SomeEncodable: Encodable {\n        var string: String\n        var int: Int\n        var bool: Bool\n        var hasUnderscore: String\n\n        // swiftlint:disable:next nesting\n        enum CodingKeys: String, CodingKey {\n            case string\n            case int\n            case bool\n            case hasUnderscore = \"has_underscore\"\n        }\n    }\n\n    func testJSONEncoding() {\n\n        let someEncodable = AnyEncodable(SomeEncodable(string: \"String\",\n                                                       int: 100,\n                                                       bool: true,\n                                                       hasUnderscore: \"another string\"))\n\n        let dictionary: [String: AnyEncodable] = [\n            \"boolean\": true,\n            \"integer\": 42,\n            \"double\": 3.14159265358979323846,\n            \"string\": \"string\",\n            \"array\": [1, 2, 3],\n            \"nested\": [\n                \"a\": \"alpha\",\n                \"b\": \"bravo\",\n                \"c\": \"charlie\"\n            ],\n            \"someCodable\": someEncodable,\n            \"null\": nil\n        ]\n\n        do {\n            let encoder = JSONEncoder()\n            let json = try encoder.encode(dictionary)\n            guard let encodedJSONObject =\n                try JSONSerialization.jsonObject(with: json, options: []) as? NSDictionary else {\n                    XCTFail(\"Should encode JSON object\")\n                    return\n            }\n            guard let expected = \"\"\"\n            {\n                \"boolean\": 1,\n                \"integer\": 42,\n                \"double\": 3.14159265358979323846,\n                \"string\": \"string\",\n                \"array\": [1, 2, 3],\n                \"nested\": {\n                    \"a\": \"alpha\",\n                    \"b\": \"bravo\",\n                    \"c\": \"charlie\"\n                },\n                \"someCodable\": {\n                    \"string\": \"String\",\n                    \"int\": 100,\n                    \"bool\": true,\n                    \"has_underscore\": \"another string\"\n                },\n                \"null\": null\n            }\n            \"\"\".data(using: .utf8) else {\n                XCTFail(\"Should unrap data to utf8\")\n                return\n            }\n            guard let expectedJSONObject =\n                try JSONSerialization.jsonObject(with: expected, options: []) as? NSDictionary else {\n                XCTFail(\"Should unrap serialized json object\")\n                return\n            }\n            XCTAssertEqual(encodedJSONObject, expectedJSONObject)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testEncodeNSNumber() throws {\n        let dictionary: [String: NSNumber] = [\n            \"boolean\": true,\n            \"char\": -127,\n            \"int\": -32767,\n            \"short\": -32767,\n            \"long\": -2147483647,\n            \"longlong\": -9223372036854775807,\n            \"uchar\": 255,\n            \"uint\": 65535,\n            \"ushort\": 65535,\n            \"ulong\": 4294967295,\n            \"ulonglong\": 18446744073709615,\n            \"double\": 3.141592653589793\n        ]\n\n        let encoder = JSONEncoder()\n\n        let json = try encoder.encode(AnyEncodable(dictionary))\n        guard let encodedJSONObject = try JSONSerialization.jsonObject(with: json, options: []) as? NSDictionary else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        let expected = \"\"\"\n        {\n            \"boolean\": 1,\n            \"char\": -127,\n            \"int\": -32767,\n            \"short\": -32767,\n            \"long\": -2147483647,\n            \"longlong\": -9223372036854775807,\n            \"uchar\": 255,\n            \"uint\": 65535,\n            \"ushort\": 65535,\n            \"ulong\": 4294967295,\n            \"ulonglong\": 18446744073709615,\n            \"double\": 3.141592653589793,\n        }\n        \"\"\".data(using: .utf8)!\n        // swiftlint:disable:next line_length\n        guard let expectedJSONObject = try JSONSerialization.jsonObject(with: expected, options: []) as? NSDictionary else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        XCTAssertEqual(encodedJSONObject, expectedJSONObject)\n        XCTAssert(encodedJSONObject[\"boolean\"] is Bool)\n\n        XCTAssert(encodedJSONObject[\"char\"] is Int8)\n        XCTAssert(encodedJSONObject[\"int\"] is Int16)\n        XCTAssert(encodedJSONObject[\"short\"] is Int32)\n        XCTAssert(encodedJSONObject[\"long\"] is Int32)\n        XCTAssert(encodedJSONObject[\"longlong\"] is Int64)\n\n        XCTAssert(encodedJSONObject[\"uchar\"] is UInt8)\n        XCTAssert(encodedJSONObject[\"uint\"] is UInt16)\n        XCTAssert(encodedJSONObject[\"ushort\"] is UInt32)\n        XCTAssert(encodedJSONObject[\"ulong\"] is UInt32)\n        XCTAssert(encodedJSONObject[\"ulonglong\"] is UInt64)\n\n        XCTAssert(encodedJSONObject[\"double\"] is Double)\n    }\n\n    func testStringInterpolationEncoding() throws {\n        let dictionary: [String: AnyEncodable] = [\n            \"boolean\": \"\\(true)\",\n            \"integer\": \"\\(42)\",\n            \"double\": \"\\(3.141592653589793)\",\n            \"string\": \"\\(\"string\")\",\n            \"array\": \"\\([1, 2, 3])\"\n        ]\n\n        let encoder = JSONEncoder()\n\n        let json = try encoder.encode(dictionary)\n        guard let encodedJSONObject = try JSONSerialization.jsonObject(with: json, options: []) as? NSDictionary else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        let expected = \"\"\"\n        {\n            \"boolean\": \"true\",\n            \"integer\": \"42\",\n            \"double\": \"3.141592653589793\",\n            \"string\": \"string\",\n            \"array\": \"[1, 2, 3]\",\n        }\n        \"\"\".data(using: .utf8)!\n        // swiftlint:disable:next line_length\n        guard let expectedJSONObject = try JSONSerialization.jsonObject(with: expected, options: []) as? NSDictionary else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        XCTAssertEqual(encodedJSONObject, expectedJSONObject)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/BatchUtilsTests.swift",
    "content": "//\n//  BatchUtilsTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/2/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass BatchUtilsTests: XCTestCase {\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n    }\n\n    func testSplitArrayLessSegments() throws {\n        let array = [1, 2]\n        let splitArray = BatchUtils.splitArray(array, valuesPerSegment: 3)\n        guard let firstSplit = splitArray.first else {\n            XCTFail(\"Should have a first item in the array\")\n            return\n        }\n        XCTAssertEqual(splitArray.count, 1)\n        XCTAssertEqual(firstSplit, array)\n    }\n\n    func testSplitArrayExactSegments() throws {\n        let array = [1, 2]\n        let splitArray = BatchUtils.splitArray(array, valuesPerSegment: 2)\n        guard let firstSplit = splitArray.first else {\n            XCTFail(\"Should have a first item in the array\")\n            return\n        }\n        XCTAssertEqual(splitArray.count, 1)\n        XCTAssertEqual(firstSplit, array)\n    }\n\n    func testSplitArrayMoreSegments() throws {\n        let array = [1, 2]\n        let splitArray = BatchUtils.splitArray(array, valuesPerSegment: 1)\n        guard let firstSplit = splitArray.first,\n              let lastSplit = splitArray.last else {\n            XCTFail(\"Should have a first item in the array\")\n            return\n        }\n        XCTAssertEqual(splitArray.count, 2)\n        XCTAssertEqual(firstSplit, [1])\n        XCTAssertEqual(lastSplit, [2])\n    }\n\n    func testSplitArrayEvenMoreSegments() throws {\n        let array = [1, 2, 3, 4, 5]\n        let splitArray = BatchUtils.splitArray(array, valuesPerSegment: 1)\n        guard let firstSplit = splitArray.first,\n              let lastSplit = splitArray.last else {\n            XCTFail(\"Should have a first item in the array\")\n            return\n        }\n        XCTAssertEqual(splitArray.count, 5)\n        XCTAssertEqual(firstSplit, [1])\n        XCTAssertEqual(lastSplit, [5])\n\n        guard splitArray.count == 5 else {\n            XCTFail(\"Should have 5 items\")\n            return\n        }\n\n        XCTAssertEqual(splitArray[1], [2])\n        XCTAssertEqual(splitArray[2], [3])\n        XCTAssertEqual(splitArray[3], [4])\n    }\n\n    func testSplitArrayComplexSegments() throws {\n        let array = [1, 2, 3, 4, 5, 6, 7]\n        let splitArray = BatchUtils.splitArray(array, valuesPerSegment: 2)\n        guard let firstSplit = splitArray.first,\n              let lastSplit = splitArray.last else {\n            XCTFail(\"Should have a first item in the array\")\n            return\n        }\n        XCTAssertEqual(splitArray.count, 4)\n        XCTAssertEqual(firstSplit, [1, 2])\n        XCTAssertEqual(lastSplit, [7])\n\n        guard splitArray.count == 4 else {\n            XCTFail(\"Should have 4 items\")\n            return\n        }\n\n        XCTAssertEqual(splitArray[1], [3, 4])\n        XCTAssertEqual(splitArray[2], [5, 6])\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ExtensionsTests.swift",
    "content": "//\n//  ExtensionsTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 11/19/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ExtensionsTests: XCTestCase {\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: false)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testURLSessionTesting() throws {\n        XCTAssertNotNil(URLSession.parse.configuration.urlCache)\n    }\n\n    func testURLSession() throws {\n        let headerKey = \"User-Agent\"\n        let headerValue = \"ParseSwift/\\(ParseConstants.version) (\\(ParseConstants.deviceType)\"\n        Parse.configuration.httpAdditionalHeaders = [headerKey: headerValue]\n        let session = URLSession.parse\n        XCTAssertNotNil(session.configuration.urlCache)\n        XCTAssertEqual(session.configuration.requestCachePolicy, ParseSwift.configuration.requestCachePolicy)\n    }\n\n    func testReconnectInterval() throws {\n        for index in 1 ..< 50 {\n            let time = URLSession.reconnectInterval(index)\n            XCTAssertLessThan(time, 30)\n            XCTAssertGreaterThan(time, -1)\n        }\n    }\n    #endif\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/IOS13Tests.swift",
    "content": "//\n//  IOS13Tests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 7/2/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass IOS13Tests: XCTestCase { // swiftlint:disable:this type_body_length\n    struct Level: ParseObject {\n        var objectId: String?\n\n        var createdAt: Date?\n\n        var updatedAt: Date?\n\n        var ACL: ParseACL?\n\n        var originalData: Data?\n\n        var name = \"First\"\n    }\n\n    struct GameScore: ParseObject {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int?\n        var player: String?\n        var level: Level?\n        var levels: [Level]?\n\n        //custom initializers\n        init() {}\n        init (objectId: String?) {\n            self.objectId = objectId\n        }\n        init(points: Int) {\n            self.points = points\n            self.player = \"Jen\"\n        }\n        init(points: Int, name: String) {\n            self.points = points\n            self.player = name\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n\n        guard let fileManager = ParseFileManager() else {\n            throw ParseError(code: .unknownError, message: \"Should have initialized file manage\")\n        }\n\n        let directory2 = try ParseFileManager.downloadDirectory()\n        let expectation2 = XCTestExpectation(description: \"Delete files2\")\n        fileManager.removeDirectoryContents(directory2) { _ in\n            expectation2.fulfill()\n        }\n        wait(for: [expectation2], timeout: 20.0)\n    }\n\n    func testSaveCommand() throws {\n        let score = GameScore(points: 10)\n        let className = score.className\n\n        let command = try score.saveCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/classes/\\(className)\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertNil(command.params)\n\n        let expected = \"GameScore ({\\\"player\\\":\\\"Jen\\\",\\\"points\\\":10})\"\n        let decoded = score.debugDescription\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testUpdateCommand() throws {\n        var score = GameScore(points: 10)\n        let className = score.className\n        let objectId = \"yarr\"\n        score.objectId = objectId\n        score.createdAt = Date()\n        score.updatedAt = score.createdAt\n\n        let command = try score.saveCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/classes/\\(className)/\\(objectId)\")\n        XCTAssertEqual(command.method, API.Method.PUT)\n        XCTAssertNil(command.params)\n\n        guard let body = command.body else {\n            XCTFail(\"Should be able to unwrap\")\n            return\n        }\n\n        let expected = \"{\\\"player\\\":\\\"Jen\\\",\\\"points\\\":10}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(body, collectChildren: false,\n                    objectsSavedBeforeThisOne: nil,\n                    filesSavedBeforeThisOne: nil).encoded\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/Info.plist",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>CFBundleDevelopmentRegion</key>\n\t<string>$(DEVELOPMENT_LANGUAGE)</string>\n\t<key>CFBundleExecutable</key>\n\t<string>$(EXECUTABLE_NAME)</string>\n\t<key>CFBundleIdentifier</key>\n\t<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n\t<key>CFBundleInfoDictionaryVersion</key>\n\t<string>6.0</string>\n\t<key>CFBundleName</key>\n\t<string>$(PRODUCT_NAME)</string>\n\t<key>CFBundlePackageType</key>\n\t<string>BNDL</string>\n\t<key>CFBundleShortVersionString</key>\n\t<string>1.0</string>\n\t<key>CFBundleVersion</key>\n\t<string>1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "Tests/ParseSwiftTests/InitializeSDKTests.swift",
    "content": "//\n//  InitializeSDKTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 4/3/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport XCTest\n@testable import ParseSwift\n\nclass InitializeSDKTests: XCTestCase {\n\n    struct Installation: ParseInstallation {\n        var installationId: String?\n        var deviceType: String?\n        var deviceToken: String?\n        var badge: Int?\n        var timeZone: String?\n        var channels: [String]?\n        var appName: String?\n        var appIdentifier: String?\n        var appVersion: String?\n        var parseVersion: String?\n        var localeIdentifier: String?\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n        var customKey: String?\n    }\n\n    struct Config: ParseConfig {\n        var welcomeMessage: String?\n        var winningNumber: Int?\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        Parse.configuration = .init(applicationId: \"applicationId\",\n                                    serverURL: url)\n        Parse.configuration.isTestingSDK = true\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        try KeychainStore.objectiveC?.deleteAllObjectiveC()\n        try KeychainStore.old.deleteAll()\n        URLSession.shared.configuration.urlCache?.removeAllCachedResponses()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testDeprecatedInitializers() {\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              allowingCustomObjectIds: false) { (_, credential) in\n            credential(.performDefaultHandling, nil)\n        }\n        XCTAssertNotNil(Parse.sessionDelegate.authentication)\n        ParseSwift.updateAuthentication(nil)\n        XCTAssertNil(Parse.sessionDelegate.authentication)\n\n        let configuration = ParseConfiguration(applicationId: \"applicationId\",\n                                               clientKey: \"clientKey\",\n                                               masterKey: \"masterKey\",\n                                               serverURL: url,\n                                               allowingCustomObjectIds: false) { (_, credential) in\n            credential(.performDefaultHandling, nil)\n        }\n        ParseSwift.initialize(configuration: configuration)\n        XCTAssertNotNil(Parse.sessionDelegate.authentication)\n        ParseSwift.updateAuthentication(nil)\n        XCTAssertNil(Parse.sessionDelegate.authentication)\n\n        let configuration2 = ParseConfiguration(applicationId: \"applicationId\",\n                                               clientKey: \"clientKey\",\n                                               masterKey: \"masterKey\",\n                                               serverURL: url,\n                                               migratingFromObjcSDK: false) { (_, credential) in\n            credential(.performDefaultHandling, nil)\n        }\n        ParseSwift.initialize(configuration: configuration2)\n        XCTAssertNotNil(Parse.sessionDelegate.authentication)\n        ParseSwift.updateAuthentication(nil)\n        XCTAssertNil(Parse.sessionDelegate.authentication)\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func addCachedResponse() {\n        if URLSession.parse.configuration.urlCache == nil {\n            URLSession.parse.configuration.urlCache = .init()\n        }\n        guard let server = URL(string: \"http://parse.com\"),\n              let data = \"Test\".data(using: .utf8) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        let response = URLResponse(url: server, mimeType: nil,\n                                   expectedContentLength: data.count,\n                                   textEncodingName: nil)\n        URLSession.parse.configuration.urlCache?\n            .storeCachedResponse(.init(response: response,\n                                       data: data),\n                                 for: .init(url: server))\n        guard let currentCache = URLSession.parse.configuration.urlCache else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertTrue(currentCache.currentMemoryUsage > 0)\n    }\n/*\n    func testDeleteKeychainOnFirstRun() throws {\n        let memory = InMemoryKeyValueStore()\n        ParseStorage.shared.use(memory)\n        guard let server = URL(string: \"http://parse.com\") else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        Parse.configuration = ParseConfiguration(applicationId: \"yo\",\n                                                      serverURL: server,\n                                                      isDeletingKeychainIfNeeded: false)\n        let key = \"Hello\"\n        let value = \"World\"\n        try KeychainStore.shared.set(value, for: key)\n        addCachedResponse()\n\n        // Keychain should contain value on first run\n        ParseSwift.deleteKeychainIfNeeded()\n\n        do {\n            let storedValue: String? = try KeychainStore.shared.get(valueFor: key)\n            XCTAssertEqual(storedValue, value)\n            guard let firstRun = UserDefaults.standard.object(forKey: ParseConstants.bundlePrefix) as? String else {\n                XCTFail(\"Should have unwrapped\")\n                return\n            }\n            XCTAssertEqual(firstRun, ParseConstants.bundlePrefix)\n\n            // Keychain should remain unchanged on 2+ runs\n            ParseSwift.configuration.isDeletingKeychainIfNeeded = true\n            ParseSwift.deleteKeychainIfNeeded()\n            let storedValue2: String? = try KeychainStore.shared.get(valueFor: key)\n            XCTAssertEqual(storedValue2, value)\n            guard let firstRun2 = UserDefaults.standard\n                    .object(forKey: ParseConstants.bundlePrefix) as? String else {\n                        XCTFail(\"Should have unwrapped\")\n                        return\n                    }\n            XCTAssertEqual(firstRun2, ParseConstants.bundlePrefix)\n\n            // Keychain should delete on first run\n            UserDefaults.standard.removeObject(forKey: ParseConstants.bundlePrefix)\n            UserDefaults.standard.synchronize()\n            let firstRun3 = UserDefaults.standard.object(forKey: ParseConstants.bundlePrefix) as? String\n            XCTAssertNil(firstRun3)\n            addCachedResponse()\n            ParseSwift.deleteKeychainIfNeeded()\n            let storedValue3: String? = try KeychainStore.shared.get(valueFor: key)\n            XCTAssertNil(storedValue3)\n            guard let firstRun4 = UserDefaults.standard\n                    .object(forKey: ParseConstants.bundlePrefix) as? String else {\n                        XCTFail(\"Should have unwrapped\")\n                        return\n                    }\n            XCTAssertEqual(firstRun4, ParseConstants.bundlePrefix)\n\n            guard let currentCache = URLSession.parse.configuration.urlCache else {\n                XCTFail(\"Should have unwrapped\")\n                return\n            }\n            XCTAssertTrue(currentCache.currentMemoryUsage == 0)\n        } catch {\n            XCTFail(\"\\(error)\")\n        }\n    }*/\n    #endif\n\n    func testCreateParseInstallationOnInit() {\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true) { (_, credential) in\n            credential(.performDefaultHandling, nil)\n        }\n\n        guard let currentInstallation = Installation.current else {\n            XCTFail(\"Should unwrap current Installation\")\n            return\n        }\n\n        // Should be in Keychain\n        guard let memoryInstallation: CurrentInstallationContainer<Installation>\n            = try? ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentInstallation) else {\n                XCTFail(\"Should get object from Keychain\")\n            return\n        }\n        XCTAssertEqual(memoryInstallation.currentInstallation, currentInstallation)\n\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        // Should be in Keychain\n        guard let keychainInstallation: CurrentInstallationContainer<Installation>\n            = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) else {\n                XCTFail(\"Should get object from Keychain\")\n            return\n        }\n        XCTAssertEqual(keychainInstallation.currentInstallation, currentInstallation)\n        #endif\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testFetchMissingCurrentInstallation() {\n        let memory = InMemoryKeyValueStore()\n        ParseStorage.shared.use(memory)\n        let installationId = \"testMe\"\n        let badContainer = CurrentInstallationContainer<Installation>(currentInstallation: nil,\n                                                                      installationId: installationId)\n        Installation.currentContainer = badContainer\n        Installation.saveCurrentContainerToKeychain()\n        ParseVersion.current = ParseConstants.version\n\n        var foundInstallation = Installation()\n        foundInstallation.updateAutomaticInfo()\n        foundInstallation.objectId = \"yarr\"\n        foundInstallation.installationId = installationId\n\n        let results = QueryResponse<Installation>(results: [foundInstallation], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Wait\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n\n            guard let url = URL(string: \"http://localhost:1337/1\") else {\n                XCTFail(\"Should create valid URL\")\n                expectation1.fulfill()\n                return\n            }\n\n            ParseSwift.initialize(applicationId: \"applicationId\",\n                                  clientKey: \"clientKey\",\n                                  masterKey: \"masterKey\",\n                                  serverURL: url,\n                                  primitiveStore: memory,\n                                  testing: true)\n\n            guard let currentInstallation = Installation.current else {\n                XCTFail(\"Should unwrap current Installation\")\n                expectation1.fulfill()\n                return\n            }\n\n            XCTAssertEqual(currentInstallation.installationId, installationId)\n\n            // Should be in Keychain\n            guard let memoryInstallation: CurrentInstallationContainer<Installation>\n                = try? ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentInstallation) else {\n                    XCTFail(\"Should get object from Keychain\")\n                expectation1.fulfill()\n                return\n            }\n            XCTAssertEqual(memoryInstallation.currentInstallation, currentInstallation)\n\n            // Should be in Keychain\n            guard let keychainInstallation: CurrentInstallationContainer<Installation>\n                = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) else {\n                    XCTFail(\"Should get object from Keychain\")\n                    expectation1.fulfill()\n                return\n            }\n            XCTAssertEqual(keychainInstallation.currentInstallation, currentInstallation)\n            MockURLProtocol.removeAll()\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n    #endif\n\n    func testUpdateAuthChallenge() {\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true) { (_, credential) in\n            credential(.performDefaultHandling, nil)\n        }\n        XCTAssertNotNil(Parse.sessionDelegate.authentication)\n        ParseSwift.updateAuthentication(nil)\n        XCTAssertNil(Parse.sessionDelegate.authentication)\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testDontOverwriteMigratedInstallation() throws {\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        let memory = InMemoryKeyValueStore()\n        ParseStorage.shared.use(memory)\n        var newInstallation = Installation()\n        newInstallation.updateAutomaticInfo()\n        newInstallation.objectId = \"yarr\"\n        newInstallation.installationId = UUID().uuidString.lowercased()\n        Installation.currentContainer.installationId = newInstallation.installationId\n        Installation.currentContainer.currentInstallation = newInstallation\n        Installation.saveCurrentContainerToKeychain()\n\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              primitiveStore: memory,\n                              testing: true)\n        guard let installation = Installation.current else {\n            XCTFail(\"Should have installation\")\n            return\n        }\n        XCTAssertTrue(installation.hasSameObjectId(as: newInstallation))\n        XCTAssertTrue(installation.hasSameInstallationId(as: newInstallation))\n    }\n\n    func testDontOverwriteOldInstallationBecauseVersionLess() throws {\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        let memory = InMemoryKeyValueStore()\n        ParseStorage.shared.use(memory)\n        ParseVersion.current = \"0.0.0\"\n        var newInstallation = Installation()\n        newInstallation.updateAutomaticInfo()\n        newInstallation.installationId = UUID().uuidString.lowercased()\n        Installation.currentContainer.installationId = newInstallation.installationId\n        Installation.currentContainer.currentInstallation = newInstallation\n        Installation.saveCurrentContainerToKeychain()\n\n        XCTAssertNil(newInstallation.objectId)\n        guard let oldInstallation = Installation.current else {\n            XCTFail(\"Should have installation\")\n            return\n        }\n        XCTAssertTrue(oldInstallation.hasSameInstallationId(as: newInstallation))\n\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              primitiveStore: memory,\n                              testing: true)\n        guard let installation = Installation.current else {\n            XCTFail(\"Should have installation\")\n            return\n        }\n        XCTAssertTrue(installation.hasSameInstallationId(as: newInstallation))\n        XCTAssertEqual(ParseVersion.current, ParseConstants.version)\n    }\n\n    func testDontOverwriteOldInstallationBecauseVersionEqual() throws {\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        let memory = InMemoryKeyValueStore()\n        ParseStorage.shared.use(memory)\n        ParseVersion.current = ParseConstants.version\n        var newInstallation = Installation()\n        newInstallation.updateAutomaticInfo()\n        newInstallation.installationId = UUID().uuidString.lowercased()\n        Installation.currentContainer.installationId = newInstallation.installationId\n        Installation.currentContainer.currentInstallation = newInstallation\n        Installation.saveCurrentContainerToKeychain()\n\n        XCTAssertNil(newInstallation.objectId)\n        guard let oldInstallation = Installation.current else {\n            XCTFail(\"Should have installation\")\n            return\n        }\n        XCTAssertTrue(oldInstallation.hasSameInstallationId(as: newInstallation))\n\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              primitiveStore: memory,\n                              testing: true)\n        guard let installation = Installation.current else {\n            XCTFail(\"Should have installation\")\n            return\n        }\n        XCTAssertTrue(installation.hasSameInstallationId(as: newInstallation))\n        XCTAssertEqual(ParseVersion.current, ParseConstants.version)\n    }\n\n    func testDontOverwriteOldInstallationBecauseVersionGreater() throws {\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        let memory = InMemoryKeyValueStore()\n        ParseStorage.shared.use(memory)\n        let newVersion = \"1000.0.0\"\n        ParseVersion.current = newVersion\n        var newInstallation = Installation()\n        newInstallation.updateAutomaticInfo()\n        newInstallation.installationId = UUID().uuidString.lowercased()\n        Installation.currentContainer.installationId = newInstallation.installationId\n        Installation.currentContainer.currentInstallation = newInstallation\n        Installation.saveCurrentContainerToKeychain()\n\n        XCTAssertNil(newInstallation.objectId)\n        guard let oldInstallation = Installation.current else {\n            XCTFail(\"Should have installation\")\n            return\n        }\n        XCTAssertTrue(oldInstallation.hasSameInstallationId(as: newInstallation))\n\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              primitiveStore: memory,\n                              testing: true)\n        guard let installation = Installation.current else {\n            XCTFail(\"Should have installation\")\n            return\n        }\n        XCTAssertTrue(installation.hasSameInstallationId(as: newInstallation))\n        XCTAssertEqual(ParseVersion.current, newVersion)\n    }\n    #endif\n\n    func testOverwriteOldInstallation() throws {\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        let memory = InMemoryKeyValueStore()\n        ParseStorage.shared.use(memory)\n        var newInstallation = Installation()\n        newInstallation.updateAutomaticInfo()\n        newInstallation.installationId = UUID().uuidString.lowercased()\n        Installation.currentContainer.installationId = newInstallation.installationId\n        Installation.currentContainer.currentInstallation = newInstallation\n        Installation.saveCurrentContainerToKeychain()\n\n        XCTAssertNil(newInstallation.objectId)\n        guard let oldInstallation = Installation.current else {\n            XCTFail(\"Should have installation\")\n            return\n        }\n        XCTAssertTrue(oldInstallation.hasSameInstallationId(as: newInstallation))\n\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              primitiveStore: memory,\n                              testing: true)\n        guard let installation = Installation.current else {\n            XCTFail(\"Should have installation\")\n            return\n        }\n        XCTAssertFalse(installation.hasSameInstallationId(as: newInstallation))\n    }\n\n    func testMigrateObjcKeychainMissing() {\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              migratingFromObjcSDK: true,\n                              testing: true)\n        guard let installation = Installation.current else {\n            XCTFail(\"Should have installation\")\n            return\n        }\n        XCTAssertNotNil(installation.installationId)\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testMigrateOldKeychainToNew() throws {\n        var user = BaseParseUser()\n        user.objectId = \"wow\"\n        var userContainer = CurrentUserContainer<BaseParseUser>()\n        userContainer.currentUser = user\n        userContainer.sessionToken = \"session\"\n        let installationId = \"id\"\n        var installation = Installation()\n        installation.installationId = installationId\n        installation.objectId = \"now\"\n        installation.updateAutomaticInfo()\n        var installationContainer = CurrentInstallationContainer<Installation>()\n        installationContainer.currentInstallation = installation\n        installationContainer.installationId = installationId\n        let config = Config(welcomeMessage: \"hello\", winningNumber: 5)\n        var configContainer = CurrentConfigContainer<Config>()\n        configContainer.currentConfig = config\n        var acl = ParseACL()\n        acl.setReadAccess(objectId: \"hello\", value: true)\n        acl.setReadAccess(objectId: \"wow\", value: true)\n        acl.setWriteAccess(objectId: \"wow\", value: true)\n        let aclContainer = DefaultACL(defaultACL: acl,\n                                      lastCurrentUserObjectId: user.objectId,\n                                      useCurrentUser: true)\n        let version = \"1.9.7\"\n        try? KeychainStore.old.set(version, for: ParseStorage.Keys.currentVersion)\n        try? KeychainStore.old.set(userContainer, for: ParseStorage.Keys.currentUser)\n        try? KeychainStore.old.set(installationContainer, for: ParseStorage.Keys.currentInstallation)\n        try? KeychainStore.old.set(configContainer, for: ParseStorage.Keys.currentConfig)\n        try? KeychainStore.old.set(aclContainer, for: ParseStorage.Keys.defaultACL)\n        let expectation1 = XCTestExpectation(description: \"Wait\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n            guard let url = URL(string: \"http://localhost:1337/1\") else {\n                XCTFail(\"Should create valid URL\")\n                expectation1.fulfill()\n                return\n            }\n            ParseSwift.initialize(applicationId: \"applicationId\",\n                                  clientKey: \"clientKey\",\n                                  masterKey: \"masterKey\",\n                                  serverURL: url,\n                                  testing: true)\n            XCTAssertEqual(ParseVersion.current, ParseConstants.version)\n            XCTAssertEqual(BaseParseUser.current, user)\n            XCTAssertEqual(Installation.current, installation)\n            XCTAssertEqual(Config.current?.welcomeMessage, config.welcomeMessage)\n            XCTAssertEqual(Config.current?.winningNumber, config.winningNumber)\n            let defaultACL = try? ParseACL.defaultACL()\n            XCTAssertEqual(defaultACL, acl)\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 10.0)\n    }\n\n    func testMigrateObjcSDK() {\n\n        // Set keychain the way objc sets keychain\n        guard let objcParseKeychain = KeychainStore.objectiveC else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let objcInstallationId = \"helloWorld\"\n        _ = objcParseKeychain.setObjectiveC(object: objcInstallationId, forKey: \"installationId\")\n\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              migratingFromObjcSDK: true,\n                              testing: true)\n        guard let installation = Installation.current else {\n            XCTFail(\"Should have installation\")\n            return\n        }\n        XCTAssertEqual(installation.installationId, objcInstallationId)\n        XCTAssertEqual(Installation.currentContainer.installationId, objcInstallationId)\n    }\n\n    #if !os(macOS)\n    func testMigrateObjcSDKNoTest() {\n\n        // Set keychain the way objc sets keychain\n        guard let objcParseKeychain = KeychainStore.objectiveC else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let objcInstallationId = \"helloWorld\"\n        _ = objcParseKeychain.setObjectiveC(object: objcInstallationId, forKey: \"installationId\")\n\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              migratingFromObjcSDK: true,\n                              parseFileTransfer: nil)\n        guard let installation = Installation.current else {\n            XCTFail(\"Should have installation\")\n            return\n        }\n        XCTAssertEqual(installation.installationId, objcInstallationId)\n        XCTAssertEqual(Installation.currentContainer.installationId, objcInstallationId)\n    }\n\n    func testInitializeSDKNoTest() {\n\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url)\n        guard Installation.current != nil else {\n            XCTFail(\"Should have installation\")\n            return\n        }\n    }\n    #endif\n\n    func testDeleteObjcSDKKeychain() throws {\n\n        //Set keychain the way objc sets keychain\n        guard let objcParseKeychain = KeychainStore.objectiveC else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let objcInstallationId = \"helloWorld\"\n        _ = objcParseKeychain.setObjectiveC(object: objcInstallationId, forKey: \"installationId\")\n\n        guard let retrievedInstallationId: String? = objcParseKeychain.objectObjectiveC(forKey: \"installationId\") else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertEqual(retrievedInstallationId, objcInstallationId)\n        XCTAssertNoThrow(try ParseSwift.deleteObjectiveCKeychain())\n        let retrievedInstallationId2: String? = objcParseKeychain.objectObjectiveC(forKey: \"installationId\")\n        XCTAssertNil(retrievedInstallationId2)\n\n        //This is needed for tear down\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    func testMigrateObjcSDKMissingInstallation() {\n\n        //Set keychain the way objc sets keychain\n        guard let objcParseKeychain = KeychainStore.objectiveC else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let objcInstallationId = \"helloWorld\"\n        _ = objcParseKeychain.setObjectiveC(object: objcInstallationId, forKey: \"anotherPlace\")\n\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              migratingFromObjcSDK: true,\n                              testing: true)\n        guard let installation = Installation.current else {\n            XCTFail(\"Should have installation\")\n            return\n        }\n        XCTAssertNotNil(installation.installationId)\n        XCTAssertNotNil(Installation.currentContainer.installationId)\n        XCTAssertNotEqual(installation.installationId, objcInstallationId)\n        XCTAssertNotEqual(Installation.currentContainer.installationId, objcInstallationId)\n    }\n    #endif\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/KeychainStoreTests.swift",
    "content": "//\n//  KeychainStoreTests.swift\n//  ParseSwift\n//\n//  Created by Florent Vilmart on 17-09-25.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\n#if !os(Linux) && !os(Android) && !os(Windows)\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass KeychainStoreTests: XCTestCase {\n    var testStore: KeychainStore!\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url, testing: true)\n        testStore = KeychainStore(service: \"test\")\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        _ = testStore.removeAllObjects()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        try? KeychainStore.objectiveC?.deleteAllObjectiveC()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testSetObject() {\n        XCTAssertTrue(testStore.set(object: \"yarr\", forKey: \"blah\"), \"Set should succeed\")\n    }\n\n    func testGetObject() {\n        let key = \"yarrKey\"\n        let value = \"yarrValue\"\n        testStore[key] = value\n        guard let storedValue: String = testStore.object(forKey: key) else {\n            XCTFail(\"Should unwrap to String\")\n            return\n        }\n        XCTAssertEqual(storedValue, value, \"Values should be equal after get\")\n    }\n\n    func testGetObjectSubscript() {\n        let key = \"yarrKey\"\n        let value = \"yarrValue\"\n        testStore[key] = value\n        guard let storedValue: String = testStore[key] else {\n            XCTFail(\"Should unwrap to String\")\n            return\n        }\n        XCTAssertEqual(storedValue, value, \"Values should be equal after get\")\n    }\n\n    func testGetObjectStringTypedSubscript() {\n        let key = \"yarrKey\"\n        let value = \"yarrValue\"\n        testStore[key] = value\n        XCTAssertEqual(testStore[string: key], value, \"Values should be equal after get\")\n    }\n\n    func testGetObjectWrongStringTypedSubscript() {\n        let key = \"yarrKey\"\n        let value = 1\n        testStore[key] = value\n        XCTAssertNil(testStore[string: key], \"Values should be nil after get\")\n    }\n\n    func testGetObjectBoolTypedSubscript() {\n        let key = \"yarrKey\"\n        let value = true\n        testStore[bool: key] = value\n        XCTAssertEqual(testStore[bool: key], true, \"Values should be equal after get\")\n    }\n\n    func testGetObjectWrongBoolTypedSubscript() {\n        let key = \"yarrKey\"\n        let value = \"Yo!\"\n        testStore[key] = value\n        XCTAssertNil(testStore[bool: key], \"Values should be nil after get\")\n    }\n\n    func testGetAnyCodableObject() {\n        let key = \"yarrKey\"\n        let value: AnyCodable = \"yarrValue\"\n        testStore[key] = value\n        guard let storedValue: AnyCodable = testStore.object(forKey: key) else {\n            XCTFail(\"Should unwrap to AnyCodable\")\n            return\n        }\n        XCTAssertEqual(storedValue, value, \"Values should be equal after get\")\n    }\n\n    func testSetComplextObject() {\n        let complexObject: [AnyCodable] = [[\"key\": \"value\"], \"string2\", 1234]\n        testStore[\"complexObject\"] = complexObject\n        guard let retrievedObject: [AnyCodable] = testStore[\"complexObject\"] else {\n            return XCTFail(\"Should retrieve the object\")\n        }\n        XCTAssertTrue(retrievedObject.count == 3)\n        retrievedObject.enumerated().forEach { (offset, retrievedValue) in\n            let value = complexObject[offset].value\n            switch offset {\n            case 0:\n                guard let dict = value as? [String: String],\n                    let retrievedDictionary = retrievedValue.value as? [String: String] else {\n                        return XCTFail(\"Should be both dictionaries\")\n                }\n                XCTAssertTrue(dict == retrievedDictionary)\n            case 1:\n                guard let string = value as? String,\n                    let retrievedString = retrievedValue.value as? String else {\n                        return XCTFail(\"Should be both strings\")\n                }\n                XCTAssertTrue(string == retrievedString)\n            case 2:\n                guard let int = value as? Int,\n                    let retrievedInt = retrievedValue.value as? Int else {\n                        return XCTFail(\"Should be both ints\")\n                }\n                XCTAssertTrue(int == retrievedInt)\n            default: break\n            }\n        }\n    }\n\n    func testRemoveObject() {\n        testStore[\"key1\"] = \"value1\"\n        XCTAssertNotNil(testStore[string: \"key1\"], \"The value should be set\")\n        _ = testStore.removeObject(forKey: \"key1\")\n        let key1Val: String? = testStore[\"key1\"]\n        XCTAssertNil(key1Val, \"There should be no value after removal\")\n    }\n\n    func testRemoveObjectSubscript() {\n        testStore[\"key1\"] = \"value1\"\n        XCTAssertNotNil(testStore[string: \"key1\"], \"The value should be set\")\n        testStore[string: \"key1\"] = nil\n        let key1Val: String? = testStore[\"key1\"]\n        XCTAssertNil(key1Val, \"There should be no value after removal\")\n    }\n\n    func testRemoveAllObjects() {\n        testStore[\"key1\"] = \"value1\"\n        testStore[\"key2\"] = \"value2\"\n        XCTAssertNotNil(testStore[string: \"key1\"], \"The value should be set\")\n        XCTAssertNotNil(testStore[string: \"key2\"], \"The value should be set\")\n        _ = testStore.removeAllObjects()\n        let key1Val: String? = testStore[\"key1\"]\n        let key2Val: String? = testStore[\"key1\"]\n        XCTAssertNil(key1Val, \"There should be no value after removal\")\n        XCTAssertNil(key2Val, \"There should be no value after removal\")\n    }\n\n    func testThreadSafeSet() {\n        DispatchQueue.concurrentPerform(iterations: 100) { _ in\n            XCTAssertTrue(testStore.set(object: \"yarr\", forKey: \"pirate\"), \"Should set value\")\n        }\n    }\n\n    func testThreadSafeRemoveObject() {\n        DispatchQueue.concurrentPerform(iterations: 100) { (index) in\n            XCTAssertTrue(testStore.set(object: \"yarr\", forKey: \"\\(index)\"), \"Should set value\")\n            XCTAssertTrue(testStore.removeObject(forKey: \"\\(index)\"), \"Should set value\")\n        }\n    }\n\n    func testThreadSafeRemoveAllObjects() {\n        DispatchQueue.concurrentPerform(iterations: 100) { (_) in\n            XCTAssertTrue(testStore.set(object: \"yarr\", forKey: \"pirate1\"), \"Should set value\")\n            XCTAssertTrue(testStore.set(object: \"yarr\", forKey: \"pirate2\"), \"Should set value\")\n            XCTAssertTrue(testStore.removeAllObjects(), \"Should set value\")\n        }\n    }\n\n    func testQueryTemplate() throws {\n        let query = KeychainStore.shared.getKeychainQueryTemplate()\n        XCTAssertEqual(query.count, 2)\n        XCTAssertEqual(query[kSecAttrService as String] as? String, KeychainStore.shared.service)\n        XCTAssertEqual(query[kSecClass as String] as? String, kSecClassGenericPassword as String)\n    }\n\n    func testQueryNoAccessGroup() throws {\n        let accessGroup = ParseKeychainAccessGroup()\n        let query = KeychainStore.shared.keychainQuery(forKey: \"hello\", accessGroup: accessGroup)\n        XCTAssertEqual(query.count, 5)\n        XCTAssertEqual(query[kSecAttrService as String] as? String, KeychainStore.shared.service)\n        XCTAssertEqual(query[kSecClass as String] as? String, kSecClassGenericPassword as String)\n        XCTAssertEqual(query[kSecAttrAccount as String] as? String, \"hello\")\n        XCTAssertEqual(query[kSecAttrSynchronizable as String] as? Bool, kCFBooleanFalse as? Bool)\n        XCTAssertEqual(query[kSecAttrAccessible as String] as? String,\n                       kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly as String)\n    }\n\n    func testQueryAccessGroupSyncableKeyTrue() throws {\n        let accessGroup = ParseKeychainAccessGroup(accessGroup: \"world\", isSyncingKeychainAcrossDevices: true)\n        let query = KeychainStore.shared.keychainQuery(forKey: \"hello\", accessGroup: accessGroup)\n        XCTAssertEqual(query.count, 6)\n        XCTAssertEqual(query[kSecAttrService as String] as? String, KeychainStore.shared.service)\n        XCTAssertEqual(query[kSecClass as String] as? String, kSecClassGenericPassword as String)\n        XCTAssertEqual(query[kSecAttrAccount as String] as? String, \"hello\")\n        XCTAssertEqual(query[kSecAttrAccessGroup as String] as? String, \"world\")\n        XCTAssertEqual(query[kSecAttrSynchronizable as String] as? Bool, kCFBooleanTrue as? Bool)\n        XCTAssertEqual(query[kSecAttrAccessible as String] as? String,\n                       kSecAttrAccessibleAfterFirstUnlock as String)\n    }\n\n    func testQueryAccessGroupSyncableKeyFalse() throws {\n        let accessGroup = ParseKeychainAccessGroup(accessGroup: \"world\", isSyncingKeychainAcrossDevices: false)\n        let query = KeychainStore.shared.keychainQuery(forKey: \"hello\", accessGroup: accessGroup)\n        XCTAssertEqual(query.count, 6)\n        XCTAssertEqual(query[kSecAttrService as String] as? String, KeychainStore.shared.service)\n        XCTAssertEqual(query[kSecClass as String] as? String, kSecClassGenericPassword as String)\n        XCTAssertEqual(query[kSecAttrAccount as String] as? String, \"hello\")\n        XCTAssertEqual(query[kSecAttrAccessGroup as String] as? String, \"world\")\n        XCTAssertEqual(query[kSecAttrSynchronizable as String] as? Bool, kCFBooleanFalse as? Bool)\n        XCTAssertEqual(query[kSecAttrAccessible as String] as? String,\n                       kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly as String)\n    }\n\n    func testQueryAccessGroupNoSyncableKeyTrue() throws {\n        let key = ParseStorage.Keys.currentInstallation\n        let accessGroup = ParseKeychainAccessGroup(accessGroup: \"world\", isSyncingKeychainAcrossDevices: true)\n        let query = KeychainStore.shared.keychainQuery(forKey: key, accessGroup: accessGroup)\n        XCTAssertEqual(query.count, 6)\n        XCTAssertEqual(query[kSecAttrService as String] as? String, KeychainStore.shared.service)\n        XCTAssertEqual(query[kSecClass as String] as? String, kSecClassGenericPassword as String)\n        XCTAssertEqual(query[kSecAttrAccount as String] as? String, key)\n        XCTAssertEqual(query[kSecAttrAccessGroup as String] as? String, \"world\")\n        XCTAssertEqual(query[kSecAttrSynchronizable as String] as? Bool, kCFBooleanFalse as? Bool)\n        XCTAssertEqual(query[kSecAttrAccessible as String] as? String,\n                       kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly as String)\n    }\n\n    func testQueryAccessGroupNoSyncableKeyFalse() throws {\n        let key = ParseStorage.Keys.currentInstallation\n        let accessGroup = ParseKeychainAccessGroup(accessGroup: \"world\", isSyncingKeychainAcrossDevices: false)\n        let query = KeychainStore.shared.keychainQuery(forKey: key, accessGroup: accessGroup)\n        XCTAssertEqual(query.count, 6)\n        XCTAssertEqual(query[kSecAttrService as String] as? String, KeychainStore.shared.service)\n        XCTAssertEqual(query[kSecClass as String] as? String, kSecClassGenericPassword as String)\n        XCTAssertEqual(query[kSecAttrAccount as String] as? String, key)\n        XCTAssertEqual(query[kSecAttrAccessGroup as String] as? String, \"world\")\n        XCTAssertEqual(query[kSecAttrSynchronizable as String] as? Bool, kCFBooleanFalse as? Bool)\n        XCTAssertEqual(query[kSecAttrAccessible as String] as? String,\n                       kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly as String)\n    }\n\n    func testSetObjectiveC() throws {\n        // Set keychain the way objc sets keychain\n        guard let objcParseKeychain = KeychainStore.objectiveC else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let objcInstallationId = \"helloWorld\"\n        _ = objcParseKeychain.setObjectiveC(object: objcInstallationId, forKey: \"installationId\")\n\n        guard let retrievedValue: String = objcParseKeychain.objectObjectiveC(forKey: \"installationId\") else {\n            XCTFail(\"Should have casted\")\n            return\n        }\n        XCTAssertEqual(retrievedValue, objcInstallationId)\n        let newInstallationId: String? = nil\n        _ = objcParseKeychain.setObjectiveC(object: newInstallationId, forKey: \"installationId\")\n        let retrievedValue2: String? = objcParseKeychain.objectObjectiveC(forKey: \"installationId\")\n        XCTAssertNil(retrievedValue2)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/MigrateObjCSDKCombineTests.swift",
    "content": "//\n//  MigrateObjCSDKCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 8/21/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine) && !os(Linux) && !os(Android) && !os(Windows)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass MigrateObjCSDKCombineTests: XCTestCase {\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        //: Implement your own version of merge\n        func merge(with object: Self) throws -> Self {\n            var updated = try mergeParse(with: object)\n            if updated.shouldRestoreKey(\\.customKey,\n                                         original: object) {\n                updated.customKey = object.customKey\n            }\n            return updated\n        }\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    struct Installation: ParseInstallation {\n        var installationId: String?\n        var deviceType: String?\n        var deviceToken: String?\n        var badge: Int?\n        var timeZone: String?\n        var channels: [String]?\n        var appName: String?\n        var appIdentifier: String?\n        var appVersion: String?\n        var parseVersion: String?\n        var localeIdentifier: String?\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n        var customKey: String?\n\n        //: Implement your own version of merge\n        func merge(with object: Self) throws -> Self {\n            var updated = try mergeParse(with: object)\n            if updated.shouldRestoreKey(\\.customKey,\n                                         original: object) {\n                updated.customKey = object.customKey\n            }\n            return updated\n        }\n    }\n\n    let loginUserName = \"hello10\"\n    let loginPassword = \"world\"\n    let objcInstallationId = \"helloWorld\"\n    let objcSessionToken = \"wow\"\n    let objcSessionToken2 = \"now\"\n    let testInstallationObjectId = \"yarr\"\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        try KeychainStore.objectiveC?.deleteAllObjectiveC()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func setupObjcKeychainSDK(useOldObjCToken: Bool = false,\n                              useBothTokens: Bool = false,\n                              installationId: String) {\n\n        // Set keychain the way objc sets keychain\n        guard let objcParseKeychain = KeychainStore.objectiveC else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        let currentUserDictionary = [\"sessionToken\": objcSessionToken]\n        let currentUserDictionary2 = [\"session_token\": objcSessionToken2]\n        let currentUserDictionary3 = [\"sessionToken\": objcSessionToken,\n                                      \"session_token\": objcSessionToken2]\n        _ = objcParseKeychain.setObjectiveC(object: installationId, forKey: \"installationId\")\n        if useBothTokens {\n            _ = objcParseKeychain.setObjectiveC(object: currentUserDictionary3, forKey: \"currentUser\")\n        } else if !useOldObjCToken {\n            _ = objcParseKeychain.setObjectiveC(object: currentUserDictionary, forKey: \"currentUser\")\n        } else {\n            _ = objcParseKeychain.setObjectiveC(object: currentUserDictionary2, forKey: \"currentUser\")\n        }\n    }\n\n    func loginNormally(sessionToken: String) throws -> User {\n        var loginResponse = LoginSignupResponse()\n        loginResponse.sessionToken = sessionToken\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try User.login(username: \"parse\", password: \"user\")\n    }\n\n    func testLoginUsingObjCKeychain() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        setupObjcKeychainSDK(installationId: objcInstallationId)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = User.current?.updatedAt?.addingTimeInterval(+300)\n        serverResponse.sessionToken = objcSessionToken\n        serverResponse.username = loginUserName\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                serverResponse = try ParseCoding.jsonDecoder().decode(LoginSignupResponse.self, from: encoded)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let publisher = User.loginUsingObjCKeychainPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { loggedIn in\n            XCTAssertEqual(loggedIn.updatedAt, serverResponse.updatedAt)\n            XCTAssertEqual(loggedIn.email, serverResponse.email)\n            XCTAssertEqual(loggedIn.username, self.loginUserName)\n            XCTAssertNil(loggedIn.password)\n            XCTAssertEqual(loggedIn.objectId, serverResponse.objectId)\n            XCTAssertEqual(loggedIn.sessionToken, self.objcSessionToken)\n            XCTAssertEqual(loggedIn.customKey, serverResponse.customKey)\n            XCTAssertNil(loggedIn.ACL)\n\n            guard let userFromKeychain = User.current else {\n                XCTFail(\"Could not get CurrentUser from Keychain\")\n                expectation1.fulfill()\n                return\n            }\n\n            XCTAssertEqual(loggedIn.updatedAt, userFromKeychain.updatedAt)\n            XCTAssertEqual(loggedIn.email, userFromKeychain.email)\n            XCTAssertEqual(userFromKeychain.username, self.loginUserName)\n            XCTAssertNil(userFromKeychain.password)\n            XCTAssertEqual(loggedIn.objectId, userFromKeychain.objectId)\n            XCTAssertEqual(userFromKeychain.sessionToken, self.objcSessionToken)\n            XCTAssertEqual(loggedIn.customKey, userFromKeychain.customKey)\n            XCTAssertNil(userFromKeychain.ACL)\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginUsingObjCKeychainOldSessionTokenKey() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        setupObjcKeychainSDK(useOldObjCToken: true,\n                             installationId: objcInstallationId)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = User.current?.updatedAt?.addingTimeInterval(+300)\n        serverResponse.sessionToken = objcSessionToken2\n        serverResponse.username = loginUserName\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                serverResponse = try ParseCoding.jsonDecoder().decode(LoginSignupResponse.self, from: encoded)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let publisher = User.loginUsingObjCKeychainPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { loggedIn in\n            XCTAssertEqual(loggedIn.updatedAt, serverResponse.updatedAt)\n            XCTAssertEqual(loggedIn.email, serverResponse.email)\n            XCTAssertEqual(loggedIn.username, self.loginUserName)\n            XCTAssertNil(loggedIn.password)\n            XCTAssertEqual(loggedIn.objectId, serverResponse.objectId)\n            XCTAssertEqual(loggedIn.sessionToken, self.objcSessionToken2)\n            XCTAssertEqual(loggedIn.customKey, serverResponse.customKey)\n            XCTAssertNil(loggedIn.ACL)\n\n            guard let userFromKeychain = User.current else {\n                XCTFail(\"Could not get CurrentUser from Keychain\")\n                expectation1.fulfill()\n                return\n            }\n\n            XCTAssertEqual(loggedIn.updatedAt, userFromKeychain.updatedAt)\n            XCTAssertEqual(loggedIn.email, userFromKeychain.email)\n            XCTAssertEqual(userFromKeychain.username, self.loginUserName)\n            XCTAssertNil(userFromKeychain.password)\n            XCTAssertEqual(loggedIn.objectId, userFromKeychain.objectId)\n            XCTAssertEqual(userFromKeychain.sessionToken, self.objcSessionToken2)\n            XCTAssertEqual(loggedIn.customKey, userFromKeychain.customKey)\n            XCTAssertNil(userFromKeychain.ACL)\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginUsingObjCKeychainUseNewOverOld() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        setupObjcKeychainSDK(useBothTokens: true,\n                             installationId: objcInstallationId)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = User.current?.updatedAt?.addingTimeInterval(+300)\n        serverResponse.sessionToken = objcSessionToken\n        serverResponse.username = loginUserName\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                serverResponse = try ParseCoding.jsonDecoder().decode(LoginSignupResponse.self, from: encoded)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let publisher = User.loginUsingObjCKeychainPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { loggedIn in\n            XCTAssertEqual(loggedIn.updatedAt, serverResponse.updatedAt)\n            XCTAssertEqual(loggedIn.email, serverResponse.email)\n            XCTAssertEqual(loggedIn.username, self.loginUserName)\n            XCTAssertNil(loggedIn.password)\n            XCTAssertEqual(loggedIn.objectId, serverResponse.objectId)\n            XCTAssertEqual(loggedIn.sessionToken, self.objcSessionToken)\n            XCTAssertEqual(loggedIn.customKey, serverResponse.customKey)\n            XCTAssertNil(loggedIn.ACL)\n\n            guard let userFromKeychain = User.current else {\n                XCTFail(\"Could not get CurrentUser from Keychain\")\n                expectation1.fulfill()\n                return\n            }\n\n            XCTAssertEqual(loggedIn.updatedAt, userFromKeychain.updatedAt)\n            XCTAssertEqual(loggedIn.email, userFromKeychain.email)\n            XCTAssertEqual(userFromKeychain.username, self.loginUserName)\n            XCTAssertNil(userFromKeychain.password)\n            XCTAssertEqual(loggedIn.objectId, userFromKeychain.objectId)\n            XCTAssertEqual(userFromKeychain.sessionToken, self.objcSessionToken)\n            XCTAssertEqual(loggedIn.customKey, userFromKeychain.customKey)\n            XCTAssertNil(userFromKeychain.ACL)\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginUsingObjCKeychainNoKeychain() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        let publisher = User.loginUsingObjCKeychainPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTAssertTrue(error.message.contains(\"Objective-C\"))\n                } else {\n                    XCTFail(\"Should have thrown error\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown error\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginUsingObjCKeychainAlreadyLoggedIn() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        setupObjcKeychainSDK(installationId: objcInstallationId)\n        let currentUser = try loginNormally(sessionToken: objcSessionToken)\n        MockURLProtocol.removeAll()\n\n        let publisher = User.loginUsingObjCKeychainPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { returnedUser in\n            XCTAssertTrue(currentUser.hasSameObjectId(as: returnedUser))\n            XCTAssertEqual(currentUser.sessionToken, returnedUser.sessionToken)\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginUsingObjCKeychainAlreadyLoggedInWithDiffererentSession() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        setupObjcKeychainSDK(installationId: objcInstallationId)\n        _ = try loginNormally(sessionToken: objcSessionToken2)\n        MockURLProtocol.removeAll()\n\n        let publisher = User.loginUsingObjCKeychainPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTAssertTrue(error.message.contains(\"different\"))\n                } else {\n                    XCTFail(\"Should have thrown error\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown error\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func saveCurrentInstallation() throws {\n        guard var installation = Installation.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n        installation.objectId = testInstallationObjectId\n        installation.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        installation.ACL = nil\n\n        var installationOnServer = installation\n\n        let encoded: Data!\n        do {\n            encoded = try installationOnServer.getEncoder().encode(installationOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            guard let saved = try Installation.current?.save(),\n                let newCurrentInstallation = Installation.current else {\n                XCTFail(\"Should have a new current installation\")\n                return\n            }\n            XCTAssertTrue(saved.hasSameInstallationId(as: newCurrentInstallation))\n            XCTAssertTrue(saved.hasSameObjectId(as: newCurrentInstallation))\n            XCTAssertTrue(saved.hasSameObjectId(as: installationOnServer))\n            XCTAssertTrue(saved.hasSameInstallationId(as: installationOnServer))\n            XCTAssertNil(saved.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testMigrateInstallation() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Migrate Installation\")\n\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let installation = Installation.current,\n            let savedObjectId = installation.objectId else {\n                XCTFail(\"Should unwrap\")\n                return\n        }\n        XCTAssertEqual(savedObjectId, self.testInstallationObjectId)\n\n        setupObjcKeychainSDK(installationId: objcInstallationId)\n\n        var installationOnServer = installation\n        installationOnServer.createdAt = installation.updatedAt\n        installationOnServer.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n        installationOnServer.customKey = \"newValue\"\n        installationOnServer.installationId = objcInstallationId\n        installationOnServer.channels = [\"yo\"]\n        installationOnServer.deviceToken = \"no\"\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            // Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self,\n                                                                                from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = Installation.migrateFromObjCKeychainPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n            guard let currentInstallation = Installation.current else {\n                XCTFail(\"Should have current installation\")\n                expectation1.fulfill()\n                return\n            }\n            XCTAssertTrue(installationOnServer.hasSameObjectId(as: saved))\n            XCTAssertTrue(installationOnServer.hasSameInstallationId(as: saved))\n            XCTAssertTrue(installationOnServer.hasSameObjectId(as: currentInstallation))\n            XCTAssertTrue(installationOnServer.hasSameInstallationId(as: currentInstallation))\n            guard let savedCreatedAt = saved.createdAt else {\n                XCTFail(\"Should unwrap dates\")\n                expectation1.fulfill()\n                return\n            }\n            guard let originalCreatedAt = installationOnServer.createdAt else {\n                XCTFail(\"Should unwrap dates\")\n                expectation1.fulfill()\n                return\n            }\n            XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n            XCTAssertEqual(saved.channels, installationOnServer.channels)\n            XCTAssertEqual(saved.deviceToken, installationOnServer.deviceToken)\n\n            // Should be updated in memory\n            XCTAssertEqual(Installation.current?.installationId, self.objcInstallationId)\n            XCTAssertEqual(Installation.current?.customKey, installationOnServer.customKey)\n            XCTAssertEqual(Installation.current?.channels, installationOnServer.channels)\n            XCTAssertEqual(Installation.current?.deviceToken, installationOnServer.deviceToken)\n\n            #if !os(Linux) && !os(Android) && !os(Windows)\n            // Should be updated in Keychain\n            guard let keychainInstallation: CurrentInstallationContainer<BaseParseInstallation>\n                = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) else {\n                    XCTFail(\"Should get object from Keychain\")\n                expectation1.fulfill()\n                return\n            }\n            XCTAssertEqual(keychainInstallation.currentInstallation?.installationId, self.objcInstallationId)\n            XCTAssertEqual(keychainInstallation.currentInstallation?.channels, installationOnServer.channels)\n            XCTAssertEqual(keychainInstallation.currentInstallation?.deviceToken, installationOnServer.deviceToken)\n            #endif\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testMigrateInstallationDontCopyEntire() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Migrate Installation\")\n\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let installation = Installation.current,\n            let savedObjectId = installation.objectId else {\n                XCTFail(\"Should unwrap\")\n                return\n        }\n        XCTAssertEqual(savedObjectId, self.testInstallationObjectId)\n\n        setupObjcKeychainSDK(installationId: objcInstallationId)\n\n        var installationOnServer = installation\n        installationOnServer.createdAt = installation.updatedAt\n        installationOnServer.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n        installationOnServer.customKey = \"newValue\"\n        installationOnServer.installationId = objcInstallationId\n        installationOnServer.channels = [\"yo\"]\n        installationOnServer.deviceToken = \"no\"\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            // Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self,\n                                                                                from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = Installation.migrateFromObjCKeychainPublisher(copyEntireInstallation: false)\n            .sink(receiveCompletion: { result in\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n            guard let currentInstallation = Installation.current else {\n                XCTFail(\"Should have current installation\")\n                return\n            }\n            XCTAssertTrue(installationOnServer.hasSameObjectId(as: saved))\n            XCTAssertTrue(installation.hasSameInstallationId(as: saved))\n            XCTAssertTrue(installationOnServer.hasSameObjectId(as: currentInstallation))\n            XCTAssertTrue(installation.hasSameInstallationId(as: currentInstallation))\n            guard let savedCreatedAt = saved.createdAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n            }\n            guard let originalCreatedAt = installationOnServer.createdAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n            }\n            XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n            XCTAssertEqual(saved.channels, installationOnServer.channels)\n            XCTAssertEqual(saved.deviceToken, installationOnServer.deviceToken)\n\n            // Should be updated in memory\n            XCTAssertEqual(Installation.current?.installationId, installation.installationId)\n            XCTAssertNotEqual(Installation.current?.customKey, installationOnServer.customKey)\n            XCTAssertEqual(Installation.current?.channels, installationOnServer.channels)\n            XCTAssertEqual(Installation.current?.deviceToken, installationOnServer.deviceToken)\n\n            // Should be updated in Keychain\n            guard let keychainInstallation: CurrentInstallationContainer<BaseParseInstallation>\n                = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) else {\n                    XCTFail(\"Should get object from Keychain\")\n                return\n            }\n            XCTAssertEqual(keychainInstallation.currentInstallation?.installationId, installation.installationId)\n            XCTAssertEqual(keychainInstallation.currentInstallation?.channels, installationOnServer.channels)\n            XCTAssertEqual(keychainInstallation.currentInstallation?.deviceToken, installationOnServer.deviceToken)\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testMigrateInstallationServerError() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Migrate Installation\")\n\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        setupObjcKeychainSDK(installationId: objcInstallationId)\n\n        let serverError = ParseError(code: .objectNotFound, message: \"Not found\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverError)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = Installation.migrateFromObjCKeychainPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTAssertEqual(error, serverError)\n                } else {\n                    XCTFail(\"Should have thrown error\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown error\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testMigrateInstallationNoObjcKeychain() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Migrate Installation\")\n\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let installation = Installation.current,\n            let savedObjectId = installation.objectId else {\n                XCTFail(\"Should unwrap\")\n                return\n        }\n        XCTAssertEqual(savedObjectId, self.testInstallationObjectId)\n\n        let publisher = Installation.migrateFromObjCKeychainPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTAssertTrue(error.message.contains(\"find Installation\"))\n                } else {\n                    XCTFail(\"Should have thrown error\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown error\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testMigrateInstallationNoCurrentInstallation() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Migrate Installation\")\n\n        setupObjcKeychainSDK(installationId: objcInstallationId)\n\n        try ParseStorage.shared.delete(valueFor: ParseStorage.Keys.currentInstallation)\n        try KeychainStore.shared.delete(valueFor: ParseStorage.Keys.currentInstallation)\n        Installation.currentContainer.currentInstallation = nil\n\n        let publisher = Installation.migrateFromObjCKeychainPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTAssertTrue(error.message.contains(\"Current installation\"))\n                } else {\n                    XCTFail(\"Should have thrown error\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown error\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDeleteObjCKeychain() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Delete ObjC Installation\")\n\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let installation = Installation.current,\n              let savedObjectId = installation.objectId,\n              let savedInstallationId = installation.installationId else {\n                XCTFail(\"Should unwrap\")\n                return\n        }\n        XCTAssertEqual(savedObjectId, self.testInstallationObjectId)\n\n        setupObjcKeychainSDK(installationId: objcInstallationId)\n\n        var installationOnServer = installation\n        installationOnServer.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n        installationOnServer.customKey = \"newValue\"\n        installationOnServer.installationId = objcInstallationId\n        installationOnServer.channels = [\"yo\"]\n        installationOnServer.deviceToken = \"no\"\n\n        let encoded: Data!\n        do {\n            encoded = try installationOnServer.getEncoder().encode(installationOnServer, skipKeys: .none)\n            // Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = Installation.deleteObjCKeychainPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            // Should be updated in memory\n            XCTAssertEqual(Installation.current?.installationId, savedInstallationId)\n            XCTAssertEqual(Installation.current?.customKey, installation.customKey)\n\n            // Should be updated in Keychain\n            guard let keychainInstallation: CurrentInstallationContainer<BaseParseInstallation>\n                = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) else {\n                    XCTFail(\"Should get object from Keychain\")\n                return\n            }\n            XCTAssertEqual(keychainInstallation.currentInstallation?.installationId, savedInstallationId)\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDeleteObjCKeychainAlreadyMigrated() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Delete ObjC Installation\")\n\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let installation = Installation.current,\n              let savedObjectId = installation.objectId,\n              let savedInstallationId = installation.installationId else {\n                XCTFail(\"Should unwrap\")\n                return\n        }\n        XCTAssertEqual(savedObjectId, self.testInstallationObjectId)\n\n        setupObjcKeychainSDK(installationId: savedInstallationId)\n\n        let publisher = Installation.deleteObjCKeychainPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            // Should be updated in memory\n            XCTAssertEqual(Installation.current?.installationId, savedInstallationId)\n            XCTAssertEqual(Installation.current?.customKey, installation.customKey)\n\n            // Should be updated in Keychain\n            guard let keychainInstallation: CurrentInstallationContainer<BaseParseInstallation>\n                = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) else {\n                    XCTFail(\"Should get object from Keychain\")\n                return\n            }\n            XCTAssertEqual(keychainInstallation.currentInstallation?.installationId, savedInstallationId)\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDeleteObjCKeychainNoObjcKeychain() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Delete ObjC Installation\")\n\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let installation = Installation.current,\n            let savedObjectId = installation.objectId else {\n                XCTFail(\"Should unwrap\")\n                return\n        }\n        XCTAssertEqual(savedObjectId, self.testInstallationObjectId)\n\n        let publisher = Installation.deleteObjCKeychainPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTAssertTrue(error.message.contains(\"find Installation\"))\n                } else {\n                    XCTFail(\"Should have thrown error\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown error\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDeleteObjCKeychainNoCurrentInstallation() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Delete ObjC Installation\")\n\n        setupObjcKeychainSDK(installationId: objcInstallationId)\n\n        try ParseStorage.shared.delete(valueFor: ParseStorage.Keys.currentInstallation)\n        try KeychainStore.shared.delete(valueFor: ParseStorage.Keys.currentInstallation)\n        Installation.currentContainer.currentInstallation = nil\n\n        let publisher = Installation.deleteObjCKeychainPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTAssertTrue(error.message.contains(\"Current installation\"))\n                } else {\n                    XCTFail(\"Should have thrown error\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown error\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/MigrateObjCSDKTests.swift",
    "content": "//\n//  MigrateObjCSDKTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 8/19/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency) && !os(Linux) && !os(Android) && !os(Windows)\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass MigrateObjCSDKTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        //: Implement your own version of merge\n        func merge(with object: Self) throws -> Self {\n            var updated = try mergeParse(with: object)\n            if updated.shouldRestoreKey(\\.customKey,\n                                         original: object) {\n                updated.customKey = object.customKey\n            }\n            return updated\n        }\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    struct Installation: ParseInstallation {\n        var installationId: String?\n        var deviceType: String?\n        var deviceToken: String?\n        var badge: Int?\n        var timeZone: String?\n        var channels: [String]?\n        var appName: String?\n        var appIdentifier: String?\n        var appVersion: String?\n        var parseVersion: String?\n        var localeIdentifier: String?\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n        var customKey: String?\n\n        //: Implement your own version of merge\n        func merge(with object: Self) throws -> Self {\n            var updated = try mergeParse(with: object)\n            if updated.shouldRestoreKey(\\.customKey,\n                                         original: object) {\n                updated.customKey = object.customKey\n            }\n            return updated\n        }\n    }\n\n    let loginUserName = \"hello10\"\n    let loginPassword = \"world\"\n    let objcInstallationId = \"helloWorld\"\n    let objcSessionToken = \"wow\"\n    let objcSessionToken2 = \"now\"\n    let testInstallationObjectId = \"yarr\"\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        try KeychainStore.objectiveC?.deleteAllObjectiveC()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func setupObjcKeychainSDK(useOldObjCToken: Bool = false,\n                              useBothTokens: Bool = false,\n                              installationId: String) {\n\n        // Set keychain the way objc sets keychain\n        guard let objcParseKeychain = KeychainStore.objectiveC else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        let currentUserDictionary = [\"sessionToken\": objcSessionToken]\n        let currentUserDictionary2 = [\"session_token\": objcSessionToken2]\n        let currentUserDictionary3 = [\"sessionToken\": objcSessionToken,\n                                      \"session_token\": objcSessionToken2]\n        _ = objcParseKeychain.setObjectiveC(object: installationId, forKey: \"installationId\")\n        if useBothTokens {\n            _ = objcParseKeychain.setObjectiveC(object: currentUserDictionary3, forKey: \"currentUser\")\n        } else if !useOldObjCToken {\n            _ = objcParseKeychain.setObjectiveC(object: currentUserDictionary, forKey: \"currentUser\")\n        } else {\n            _ = objcParseKeychain.setObjectiveC(object: currentUserDictionary2, forKey: \"currentUser\")\n        }\n    }\n\n    func loginNormally(sessionToken: String) async throws -> User {\n        var loginResponse = LoginSignupResponse()\n        loginResponse.sessionToken = sessionToken\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try await User.login(username: \"parse\", password: \"user\")\n    }\n\n    @MainActor\n    func testLoginUsingObjCKeychain() async throws {\n        setupObjcKeychainSDK(installationId: objcInstallationId)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = User.current?.updatedAt?.addingTimeInterval(+300)\n        serverResponse.sessionToken = objcSessionToken\n        serverResponse.username = loginUserName\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                serverResponse = try ParseCoding.jsonDecoder().decode(LoginSignupResponse.self, from: encoded)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let loggedIn = try await User.loginUsingObjCKeychain()\n        XCTAssertEqual(loggedIn.updatedAt, serverResponse.updatedAt)\n        XCTAssertEqual(loggedIn.email, serverResponse.email)\n        XCTAssertEqual(loggedIn.username, loginUserName)\n        XCTAssertNil(loggedIn.password)\n        XCTAssertEqual(loggedIn.objectId, serverResponse.objectId)\n        XCTAssertEqual(loggedIn.sessionToken, objcSessionToken)\n        XCTAssertEqual(loggedIn.customKey, serverResponse.customKey)\n        XCTAssertNil(loggedIn.ACL)\n\n        guard let userFromKeychain = User.current else {\n            XCTFail(\"Could not get CurrentUser from Keychain\")\n            return\n        }\n\n        XCTAssertEqual(loggedIn.updatedAt, userFromKeychain.updatedAt)\n        XCTAssertEqual(loggedIn.email, userFromKeychain.email)\n        XCTAssertEqual(userFromKeychain.username, loginUserName)\n        XCTAssertNil(userFromKeychain.password)\n        XCTAssertEqual(loggedIn.objectId, userFromKeychain.objectId)\n        XCTAssertEqual(userFromKeychain.sessionToken, objcSessionToken)\n        XCTAssertEqual(loggedIn.customKey, userFromKeychain.customKey)\n        XCTAssertNil(userFromKeychain.ACL)\n    }\n\n    @MainActor\n    func testLoginUsingObjCKeychainOldSessionTokenKey() async throws {\n        setupObjcKeychainSDK(useOldObjCToken: true,\n                             installationId: objcInstallationId)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = User.current?.updatedAt?.addingTimeInterval(+300)\n        serverResponse.sessionToken = objcSessionToken2\n        serverResponse.username = loginUserName\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                serverResponse = try ParseCoding.jsonDecoder().decode(LoginSignupResponse.self, from: encoded)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let loggedIn = try await User.loginUsingObjCKeychain()\n        XCTAssertEqual(loggedIn.updatedAt, serverResponse.updatedAt)\n        XCTAssertEqual(loggedIn.email, serverResponse.email)\n        XCTAssertEqual(loggedIn.username, loginUserName)\n        XCTAssertNil(loggedIn.password)\n        XCTAssertEqual(loggedIn.objectId, serverResponse.objectId)\n        XCTAssertEqual(loggedIn.sessionToken, objcSessionToken2)\n        XCTAssertEqual(loggedIn.customKey, serverResponse.customKey)\n        XCTAssertNil(loggedIn.ACL)\n\n        guard let userFromKeychain = User.current else {\n            XCTFail(\"Could not get CurrentUser from Keychain\")\n            return\n        }\n\n        XCTAssertEqual(loggedIn.updatedAt, userFromKeychain.updatedAt)\n        XCTAssertEqual(loggedIn.email, userFromKeychain.email)\n        XCTAssertEqual(userFromKeychain.username, loginUserName)\n        XCTAssertNil(userFromKeychain.password)\n        XCTAssertEqual(loggedIn.objectId, userFromKeychain.objectId)\n        XCTAssertEqual(userFromKeychain.sessionToken, objcSessionToken2)\n        XCTAssertEqual(loggedIn.customKey, userFromKeychain.customKey)\n        XCTAssertNil(userFromKeychain.ACL)\n    }\n\n    @MainActor\n    func testLoginUsingObjCKeychainUseNewOverOld() async throws {\n        setupObjcKeychainSDK(useBothTokens: true,\n                             installationId: objcInstallationId)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = User.current?.updatedAt?.addingTimeInterval(+300)\n        serverResponse.sessionToken = objcSessionToken\n        serverResponse.username = loginUserName\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                serverResponse = try ParseCoding.jsonDecoder().decode(LoginSignupResponse.self, from: encoded)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let loggedIn = try await User.loginUsingObjCKeychain()\n        XCTAssertEqual(loggedIn.updatedAt, serverResponse.updatedAt)\n        XCTAssertEqual(loggedIn.email, serverResponse.email)\n        XCTAssertEqual(loggedIn.username, loginUserName)\n        XCTAssertNil(loggedIn.password)\n        XCTAssertEqual(loggedIn.objectId, serverResponse.objectId)\n        XCTAssertEqual(loggedIn.sessionToken, objcSessionToken)\n        XCTAssertEqual(loggedIn.customKey, serverResponse.customKey)\n        XCTAssertNil(loggedIn.ACL)\n\n        guard let userFromKeychain = User.current else {\n            XCTFail(\"Could not get CurrentUser from Keychain\")\n            return\n        }\n\n        XCTAssertEqual(loggedIn.updatedAt, userFromKeychain.updatedAt)\n        XCTAssertEqual(loggedIn.email, userFromKeychain.email)\n        XCTAssertEqual(userFromKeychain.username, loginUserName)\n        XCTAssertNil(userFromKeychain.password)\n        XCTAssertEqual(loggedIn.objectId, userFromKeychain.objectId)\n        XCTAssertEqual(userFromKeychain.sessionToken, objcSessionToken)\n        XCTAssertEqual(loggedIn.customKey, userFromKeychain.customKey)\n        XCTAssertNil(userFromKeychain.ACL)\n    }\n\n    @MainActor\n    func testLoginUsingObjCKeychainNoKeychain() async throws {\n\n        do {\n            _ = try await User.loginUsingObjCKeychain()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted to ParseError\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"Objective-C\"))\n        }\n    }\n\n    @MainActor\n    func testLoginUsingObjCKeychainAlreadyLoggedIn() async throws {\n        setupObjcKeychainSDK(installationId: objcInstallationId)\n        let currentUser = try await loginNormally(sessionToken: objcSessionToken)\n        MockURLProtocol.removeAll()\n        let returnedUser = try await User.loginUsingObjCKeychain()\n        XCTAssertTrue(currentUser.hasSameObjectId(as: returnedUser))\n        XCTAssertEqual(currentUser.sessionToken, returnedUser.sessionToken)\n    }\n\n    @MainActor\n    func testLoginUsingObjCKeychainAlreadyLoggedInWithDiffererentSession() async throws {\n        setupObjcKeychainSDK(installationId: objcInstallationId)\n        _ = try await loginNormally(sessionToken: objcSessionToken2)\n        MockURLProtocol.removeAll()\n        do {\n            _ = try await User.loginUsingObjCKeychain()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted to ParseError\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"different\"))\n        }\n    }\n\n    func saveCurrentInstallation() throws {\n        guard var installation = Installation.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n        installation.objectId = testInstallationObjectId\n        installation.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        installation.ACL = nil\n\n        var installationOnServer = installation\n\n        let encoded: Data!\n        do {\n            encoded = try installationOnServer.getEncoder().encode(installationOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            guard let saved = try Installation.current?.save(),\n                let newCurrentInstallation = Installation.current else {\n                XCTFail(\"Should have a new current installation\")\n                return\n            }\n            XCTAssertTrue(saved.hasSameInstallationId(as: newCurrentInstallation))\n            XCTAssertTrue(saved.hasSameObjectId(as: newCurrentInstallation))\n            XCTAssertTrue(saved.hasSameObjectId(as: installationOnServer))\n            XCTAssertTrue(saved.hasSameInstallationId(as: installationOnServer))\n            XCTAssertNil(saved.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    @MainActor\n    func testMigrateInstallation() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let installation = Installation.current,\n            let savedObjectId = installation.objectId else {\n                XCTFail(\"Should unwrap\")\n                return\n        }\n        XCTAssertEqual(savedObjectId, self.testInstallationObjectId)\n\n        setupObjcKeychainSDK(installationId: objcInstallationId)\n\n        var installationOnServer = installation\n        installationOnServer.createdAt = installation.updatedAt\n        installationOnServer.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n        installationOnServer.customKey = \"newValue\"\n        installationOnServer.installationId = objcInstallationId\n        installationOnServer.channels = [\"yo\"]\n        installationOnServer.deviceToken = \"no\"\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            // Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self,\n                                                                                from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await Installation.migrateFromObjCKeychain()\n        guard let currentInstallation = Installation.current else {\n            XCTFail(\"Should have current installation\")\n            return\n        }\n        XCTAssertTrue(installationOnServer.hasSameObjectId(as: saved))\n        XCTAssertTrue(installationOnServer.hasSameInstallationId(as: saved))\n        XCTAssertTrue(installationOnServer.hasSameObjectId(as: currentInstallation))\n        XCTAssertTrue(installationOnServer.hasSameInstallationId(as: currentInstallation))\n        guard let savedCreatedAt = currentInstallation.createdAt else {\n            XCTFail(\"Should unwrap dates\")\n            return\n        }\n        guard let originalCreatedAt = saved.createdAt else {\n            XCTFail(\"Should unwrap dates\")\n            return\n        }\n        XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n        XCTAssertEqual(saved.channels, installationOnServer.channels)\n        XCTAssertEqual(saved.deviceToken, installationOnServer.deviceToken)\n\n        // Should be updated in memory\n        XCTAssertEqual(Installation.current?.installationId, objcInstallationId)\n        XCTAssertEqual(Installation.current?.customKey, installationOnServer.customKey)\n        XCTAssertEqual(Installation.current?.channels, installationOnServer.channels)\n        XCTAssertEqual(Installation.current?.deviceToken, installationOnServer.deviceToken)\n\n        // Should be updated in Keychain\n        guard let keychainInstallation: CurrentInstallationContainer<BaseParseInstallation>\n            = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) else {\n                XCTFail(\"Should get object from Keychain\")\n            return\n        }\n        XCTAssertEqual(keychainInstallation.currentInstallation?.installationId, objcInstallationId)\n        XCTAssertEqual(keychainInstallation.currentInstallation?.channels, installationOnServer.channels)\n        XCTAssertEqual(keychainInstallation.currentInstallation?.deviceToken, installationOnServer.deviceToken)\n    }\n\n    @MainActor\n    func testMigrateInstallationServerError() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        setupObjcKeychainSDK(installationId: objcInstallationId)\n\n        let serverError = ParseError(code: .objectNotFound, message: \"Not found\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverError)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            _ = try await Installation.migrateFromObjCKeychain()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted to ParseError\")\n                return\n            }\n            XCTAssertEqual(parseError, serverError)\n        }\n    }\n\n    @MainActor\n    func testMigrateInstallationNoObjcKeychain() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let installation = Installation.current,\n            let savedObjectId = installation.objectId else {\n                XCTFail(\"Should unwrap\")\n                return\n        }\n        XCTAssertEqual(savedObjectId, self.testInstallationObjectId)\n\n        do {\n            _ = try await Installation.migrateFromObjCKeychain()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted to ParseError\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"find Installation\"))\n        }\n    }\n\n    @MainActor\n    func testMigrateInstallationNoCurrentInstallation() async throws {\n        setupObjcKeychainSDK(installationId: objcInstallationId)\n\n        try ParseStorage.shared.delete(valueFor: ParseStorage.Keys.currentInstallation)\n        try KeychainStore.shared.delete(valueFor: ParseStorage.Keys.currentInstallation)\n        Installation.currentContainer.currentInstallation = nil\n\n        do {\n            _ = try await Installation.migrateFromObjCKeychain()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted to ParseError\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"Current installation\"))\n        }\n    }\n\n    @MainActor\n    func testMigrateInstallationDontCopyEntire() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let installation = Installation.current,\n            let savedObjectId = installation.objectId else {\n                XCTFail(\"Should unwrap\")\n                return\n        }\n        XCTAssertEqual(savedObjectId, self.testInstallationObjectId)\n\n        setupObjcKeychainSDK(installationId: objcInstallationId)\n\n        var installationOnServer = installation\n        installationOnServer.createdAt = installation.updatedAt\n        installationOnServer.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n        installationOnServer.customKey = \"newValue\"\n        installationOnServer.installationId = objcInstallationId\n        installationOnServer.channels = [\"yo\"]\n        installationOnServer.deviceToken = \"no\"\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            // Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self,\n                                                                                from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await Installation.migrateFromObjCKeychain(copyEntireInstallation: false)\n        guard let currentInstallation = Installation.current else {\n            XCTFail(\"Should have current installation\")\n            return\n        }\n        XCTAssertTrue(installationOnServer.hasSameObjectId(as: saved))\n        XCTAssertTrue(installation.hasSameInstallationId(as: saved))\n        XCTAssertTrue(installationOnServer.hasSameObjectId(as: currentInstallation))\n        XCTAssertTrue(installation.hasSameInstallationId(as: currentInstallation))\n        guard let savedCreatedAt = currentInstallation.createdAt else {\n            XCTFail(\"Should unwrap dates\")\n            return\n        }\n        guard let originalCreatedAt = saved.createdAt else {\n            XCTFail(\"Should unwrap dates\")\n            return\n        }\n        XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n        XCTAssertEqual(saved.channels, installationOnServer.channels)\n        XCTAssertEqual(saved.deviceToken, installationOnServer.deviceToken)\n\n        // Should be updated in memory\n        XCTAssertEqual(Installation.current?.installationId, installation.installationId)\n        XCTAssertNotEqual(Installation.current?.customKey, installationOnServer.customKey)\n        XCTAssertEqual(Installation.current?.channels, installationOnServer.channels)\n        XCTAssertEqual(Installation.current?.deviceToken, installationOnServer.deviceToken)\n\n        // Should be updated in Keychain\n        guard let keychainInstallation: CurrentInstallationContainer<BaseParseInstallation>\n            = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) else {\n                XCTFail(\"Should get object from Keychain\")\n            return\n        }\n        XCTAssertEqual(keychainInstallation.currentInstallation?.installationId, installation.installationId)\n        XCTAssertEqual(keychainInstallation.currentInstallation?.channels, installationOnServer.channels)\n        XCTAssertEqual(keychainInstallation.currentInstallation?.deviceToken, installationOnServer.deviceToken)\n    }\n\n    @MainActor\n    func testDeleteObjCKeychain() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let installation = Installation.current,\n              let savedObjectId = installation.objectId,\n              let savedInstallationId = installation.installationId else {\n                XCTFail(\"Should unwrap\")\n                return\n        }\n        XCTAssertEqual(savedObjectId, self.testInstallationObjectId)\n\n        setupObjcKeychainSDK(installationId: objcInstallationId)\n\n        var installationOnServer = installation\n        installationOnServer.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n        installationOnServer.customKey = \"newValue\"\n        installationOnServer.installationId = objcInstallationId\n        installationOnServer.channels = [\"yo\"]\n        installationOnServer.deviceToken = \"no\"\n\n        let encoded: Data!\n        do {\n            encoded = try installationOnServer.getEncoder().encode(installationOnServer, skipKeys: .none)\n            // Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        try await Installation.deleteObjCKeychain()\n\n        // Should be updated in memory\n        XCTAssertEqual(Installation.current?.installationId, savedInstallationId)\n        XCTAssertEqual(Installation.current?.customKey, installation.customKey)\n\n        // Should be updated in Keychain\n        guard let keychainInstallation: CurrentInstallationContainer<BaseParseInstallation>\n            = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) else {\n                XCTFail(\"Should get object from Keychain\")\n            return\n        }\n        XCTAssertEqual(keychainInstallation.currentInstallation?.installationId, savedInstallationId)\n    }\n\n    @MainActor\n    func testDeleteObjCKeychainAlreadyMigrated() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let installation = Installation.current,\n              let savedObjectId = installation.objectId,\n              let savedInstallationId = installation.installationId else {\n                XCTFail(\"Should unwrap\")\n                return\n        }\n        XCTAssertEqual(savedObjectId, self.testInstallationObjectId)\n\n        setupObjcKeychainSDK(installationId: savedInstallationId)\n\n        try await Installation.deleteObjCKeychain()\n\n        // Should be updated in memory\n        XCTAssertEqual(Installation.current?.installationId, savedInstallationId)\n        XCTAssertEqual(Installation.current?.customKey, installation.customKey)\n\n        // Should be updated in Keychain\n        guard let keychainInstallation: CurrentInstallationContainer<BaseParseInstallation>\n            = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) else {\n                XCTFail(\"Should get object from Keychain\")\n            return\n        }\n        XCTAssertEqual(keychainInstallation.currentInstallation?.installationId, savedInstallationId)\n    }\n\n    @MainActor\n    func testDeleteObjCKeychainNoObjcKeychain() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let installation = Installation.current,\n            let savedObjectId = installation.objectId else {\n                XCTFail(\"Should unwrap\")\n                return\n        }\n        XCTAssertEqual(savedObjectId, self.testInstallationObjectId)\n\n        do {\n            _ = try await Installation.deleteObjCKeychain()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted to ParseError\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"find Installation\"))\n        }\n    }\n\n    @MainActor\n    func testDeleteObjCKeychainNoCurrentInstallation() async throws {\n        setupObjcKeychainSDK(installationId: objcInstallationId)\n\n        try ParseStorage.shared.delete(valueFor: ParseStorage.Keys.currentInstallation)\n        try KeychainStore.shared.delete(valueFor: ParseStorage.Keys.currentInstallation)\n        Installation.currentContainer.currentInstallation = nil\n\n        do {\n            _ = try await Installation.deleteObjCKeychain()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted to ParseError\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"Current installation\"))\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/NetworkMocking/MockURLProtocol.swift",
    "content": "//\n//  MockURLProtocol.swift\n//  ParseSwiftTests\n//\n//  Created by Corey E. Baker on 7/19/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\n\ntypealias MockURLProtocolRequestTestClosure = (URLRequest) -> Bool\ntypealias MockURLResponseContructingClosure = (URLRequest) -> MockURLResponse?\n\nstruct MockURLProtocolMock {\n    var attempts: Int\n    var test: (URLRequest) -> Bool\n    var response: (URLRequest) -> MockURLResponse?\n}\n\nclass MockURLProtocol: URLProtocol {\n    var mock: MockURLProtocolMock?\n    static var mocks: [MockURLProtocolMock] = []\n    private var loading: Bool = false\n    var isLoading: Bool {\n        return loading\n    }\n\n    class func mockRequests(response: @escaping (URLRequest) -> MockURLResponse?) {\n        mockRequestsPassing(Int.max, test: { _ in return true }, with: response)\n    }\n\n    class func mockRequestsPassing(_ test: @escaping (URLRequest) -> Bool,\n                                   with response: @escaping (URLRequest) -> MockURLResponse?) {\n        mockRequestsPassing(Int.max, test: test, with: response)\n    }\n\n    class func mockRequestsPassing(_ attempts: Int,\n                                   test: @escaping (URLRequest) -> Bool,\n                                   with response: @escaping (URLRequest) -> MockURLResponse?) {\n        let mock = MockURLProtocolMock(attempts: attempts, test: test, response: response)\n        mocks.append(mock)\n        if mocks.count == 1 {\n            URLProtocol.registerClass(MockURLProtocol.self)\n        }\n    }\n\n    class func removeAll() {\n        if !mocks.isEmpty {\n            URLProtocol.unregisterClass(MockURLProtocol.self)\n        }\n        mocks.removeAll()\n    }\n\n    class func firstMockForRequest(_ request: URLRequest) -> MockURLProtocolMock? {\n        for mock in mocks {\n            if (mock.attempts > 0) && mock.test(request) {\n                return mock\n            }\n        }\n        return nil\n    }\n\n    override class func canInit(with request: URLRequest) -> Bool {\n        return MockURLProtocol.firstMockForRequest(request) != nil\n    }\n\n    override class func canInit(with task: URLSessionTask) -> Bool {\n        guard let originalRequest = task.originalRequest else {\n            return false\n        }\n        return MockURLProtocol.firstMockForRequest(originalRequest) != nil\n    }\n\n    override class func canonicalRequest(for request: URLRequest) -> URLRequest {\n        return request\n    }\n\n    override required init(request: URLRequest,\n                           cachedResponse: CachedURLResponse?,\n                           client: URLProtocolClient?) {\n        super.init(request: request, cachedResponse: cachedResponse, client: client)\n        guard let mock = MockURLProtocol.firstMockForRequest(request) else {\n            self.mock = nil\n            return\n        }\n        self.mock = mock\n    }\n\n    override func startLoading() {\n        self.loading = true\n        self.mock?.attempts -= 1\n        guard let response = self.mock?.response(request) else {\n            return\n        }\n\n        if let error = response.error {\n            DispatchQueue.global(qos: .default).asyncAfter(deadline: .now() + response.delay) {\n\n                if self.loading {\n                    self.client?.urlProtocol(self, didFailWithError: error)\n                }\n\n            }\n            return\n        }\n\n        guard let url = request.url,\n            let urlResponse = HTTPURLResponse(url: url,\n                                              statusCode: response.statusCode,\n                                              httpVersion: \"HTTP/2\",\n                                              headerFields: response.headerFields) else {\n                return\n            }\n\n        DispatchQueue.global(qos: .default).asyncAfter(deadline: .now() + response.delay) {\n            if !self.loading {\n                return\n            }\n            self.client?.urlProtocol(self, didReceive: urlResponse, cacheStoragePolicy: .notAllowed)\n            if let data = response.responseData {\n                self.client?.urlProtocol(self, didLoad: data)\n            }\n            self.client?.urlProtocolDidFinishLoading(self)\n        }\n\n    }\n\n    override func stopLoading() {\n        self.loading = false\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/NetworkMocking/MockURLResponse.swift",
    "content": "//\n//  MockURLResponse.swift\n//  ParseSwiftTests\n//\n//  Created by Corey Baker on 7/18/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\n@testable import ParseSwift\n\nstruct MockURLResponse {\n    var statusCode: Int = 200\n    var headerFields = [String: String]()\n    var responseData: Data?\n    var delay: TimeInterval!\n    var error: Error?\n\n    init(error: Error) {\n        self.delay = .init(0.0)\n        self.error = error\n        self.responseData = nil\n        self.statusCode = 400\n    }\n\n    init(string: String) throws {\n        try self.init(string: string, statusCode: 200, delay: .init(0.0))\n    }\n\n    init(string: String,\n         statusCode: Int,\n         delay: TimeInterval,\n         headerFields: [String: String] = [\"Content-Type\": \"application/json\"]) throws {\n        let encoded = try JSONEncoder().encode(string)\n        self.init(data: encoded, statusCode: statusCode, delay: delay, headerFields: headerFields)\n    }\n\n    init(data: Data,\n         statusCode: Int,\n         delay: TimeInterval,\n         headerFields: [String: String] = [\"Content-Type\": \"application/json\"]) {\n        self.statusCode = statusCode\n        self.headerFields = headerFields\n        self.responseData = data\n        self.delay = delay\n        self.error = nil\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseACLTests.swift",
    "content": "//\n//  ParseACLTests.swift\n//  ParseSwiftTests\n//\n//  Created by Corey Baker on 8/22/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseACLTests: XCTestCase {\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url, testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    struct Role<RoleUser: ParseUser>: ParseRole {\n\n        // required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // provided by Role\n        var name: String?\n    }\n\n    func testCantSetDefaultACLWhenNotLoggedIn() throws {\n        XCTAssertThrowsError(try ParseACL.defaultACL())\n    }\n\n    func testPublicAccess() {\n        var acl = ParseACL()\n        XCTAssertFalse(acl.publicRead)\n        XCTAssertFalse(acl.publicWrite)\n\n        acl.publicRead = true\n        XCTAssertTrue(acl.publicRead)\n\n        acl.publicWrite = true\n        XCTAssertTrue(acl.publicWrite)\n    }\n\n    func testReadAccess() {\n        var acl = ParseACL()\n        XCTAssertFalse(acl.getReadAccess(objectId: \"someUserID\"))\n        XCTAssertFalse(acl.getReadAccess(roleName: \"someRoleName\"))\n\n        acl.setReadAccess(objectId: \"someUserID\", value: true)\n        XCTAssertTrue(acl.getReadAccess(objectId: \"someUserID\"))\n\n        acl.setReadAccess(roleName: \"someRoleName\", value: true)\n        XCTAssertTrue(acl.getReadAccess(roleName: \"someRoleName\"))\n\n        acl.publicWrite = true\n        XCTAssertTrue(acl.publicWrite)\n    }\n\n    func testReadAccessObject() throws {\n        let user = User(objectId: \"someUserID\")\n        let role = try Role<User>(name: \"someRoleName\")\n        var acl = ParseACL()\n        XCTAssertFalse(acl.getReadAccess(user: user))\n        XCTAssertFalse(acl.getReadAccess(role: role))\n\n        acl.setReadAccess(user: user, value: true)\n        XCTAssertTrue(acl.getReadAccess(user: user))\n\n        acl.setReadAccess(role: role, value: true)\n        XCTAssertTrue(acl.getReadAccess(role: role))\n\n        let user2 = User()\n        acl.setReadAccess(user: user2, value: true)\n        XCTAssertFalse(acl.getReadAccess(user: user2))\n\n        acl.publicWrite = true\n        XCTAssertTrue(acl.publicWrite)\n    }\n\n    func testWriteAccess() {\n        var acl = ParseACL()\n        XCTAssertFalse(acl.getWriteAccess(objectId: \"someUserID\"))\n        XCTAssertFalse(acl.getWriteAccess(roleName: \"someRoleName\"))\n\n        acl.setWriteAccess(objectId: \"someUserID\", value: true)\n        XCTAssertTrue(acl.getWriteAccess(objectId: \"someUserID\"))\n\n        acl.setWriteAccess(roleName: \"someRoleName\", value: true)\n        XCTAssertTrue(acl.getWriteAccess(roleName: \"someRoleName\"))\n\n        acl.publicWrite = true\n        XCTAssertTrue(acl.publicWrite)\n    }\n\n    func testWriteAccessObject() throws {\n        let user = User(objectId: \"someUserID\")\n        let role = try Role<User>(name: \"someRoleName\")\n        var acl = ParseACL()\n        XCTAssertFalse(acl.getWriteAccess(user: user))\n        XCTAssertFalse(acl.getWriteAccess(role: role))\n\n        acl.setWriteAccess(user: user, value: true)\n        XCTAssertTrue(acl.getWriteAccess(user: user))\n\n        acl.setWriteAccess(role: role, value: true)\n        XCTAssertTrue(acl.getWriteAccess(role: role))\n\n        let user2 = User()\n        acl.setWriteAccess(user: user2, value: true)\n        XCTAssertFalse(acl.getWriteAccess(user: user2))\n\n        acl.publicWrite = true\n        XCTAssertTrue(acl.publicWrite)\n    }\n\n    func testCoding() {\n        var acl = ParseACL()\n        acl.setReadAccess(objectId: \"a\", value: false)\n        acl.setReadAccess(objectId: \"b\", value: true)\n        acl.setWriteAccess(objectId: \"c\", value: false)\n        acl.setWriteAccess(objectId: \"d\", value: true)\n\n        var encoded: Data?\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(acl)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        if let dataToDecode = encoded {\n            do {\n                let decoded = try ParseCoding.jsonDecoder().decode(ParseACL.self, from: dataToDecode)\n                XCTAssertEqual(acl.getReadAccess(objectId: \"a\"), decoded.getReadAccess(objectId: \"a\"))\n                XCTAssertEqual(acl.getReadAccess(objectId: \"b\"), decoded.getReadAccess(objectId: \"b\"))\n                XCTAssertEqual(acl.getWriteAccess(objectId: \"c\"), decoded.getWriteAccess(objectId: \"c\"))\n                XCTAssertEqual(acl.getWriteAccess(objectId: \"d\"), decoded.getWriteAccess(objectId: \"d\"))\n            } catch {\n                XCTFail(error.localizedDescription)\n            }\n        } else {\n            XCTAssertNil(encoded)\n        }\n    }\n\n    func testCodingAccess() throws {\n        let access = ParseACL.Access.read\n        let encoded = try ParseCoding.jsonEncoder().encode(access)\n        let decoded = try ParseCoding.jsonDecoder().decode(ParseACL.Access.self, from: encoded)\n        XCTAssertEqual(access, decoded)\n        let access2 = ParseACL.Access.write\n        let encoded2 = try ParseCoding.jsonEncoder().encode(access2)\n        let decoded2 = try ParseCoding.jsonDecoder().decode(ParseACL.Access.self, from: encoded2)\n        XCTAssertEqual(access2, decoded2)\n        guard let data = \"hello\".data(using: .utf8) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertThrowsError(try ParseCoding.jsonDecoder().decode(ParseACL.Access.self, from: data))\n    }\n\n    func testDebugString() {\n        var acl = ParseACL()\n        acl.setReadAccess(objectId: \"a\", value: false)\n        acl.setReadAccess(objectId: \"b\", value: true)\n        acl.setWriteAccess(objectId: \"c\", value: false)\n        acl.setWriteAccess(objectId: \"d\", value: true)\n\n        XCTAssertTrue(acl.debugDescription.contains(\"\\\"b\\\":{\\\"read\\\":true}\"))\n        XCTAssertTrue(acl.debugDescription.contains(\"\\\"d\\\":{\\\"write\\\":true}\"))\n        XCTAssertTrue(acl.description.contains(\"\\\"b\\\":{\\\"read\\\":true}\"))\n        XCTAssertTrue(acl.description.contains(\"\\\"d\\\":{\\\"write\\\":true}\"))\n    }\n\n    func testDefaultACLNoUser() {\n        var newACL = ParseACL()\n        let userId = \"someUserID\"\n        newACL.setReadAccess(objectId: userId, value: true)\n        do {\n            var defaultACL = try ParseACL.defaultACL()\n            XCTAssertNotEqual(newACL, defaultACL)\n            defaultACL = try ParseACL.setDefaultACL(defaultACL, withAccessForCurrentUser: true)\n            if defaultACL.getReadAccess(objectId: userId) {\n                XCTFail(\"Should not have set read access because there is no current user\")\n            }\n        } catch {\n            return\n        }\n\n        do {\n            _ = try ParseACL.setDefaultACL(newACL, withAccessForCurrentUser: true)\n            let defaultACL = try ParseACL.defaultACL()\n            if !defaultACL.getReadAccess(objectId: userId) {\n                XCTFail(\"Should have set defaultACL with read access even though there is no current user\")\n            }\n        } catch {\n            return\n        }\n    }\n\n    func testNoDefaultACL() {\n        XCTAssertThrowsError(try ParseACL.defaultACL())\n    }\n\n    func testDefaultACL() {\n        let loginResponse = LoginSignupResponse()\n        let loginUserName = \"hello10\"\n        let loginPassword = \"world\"\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        do {\n            _ = try User.signup(username: loginUserName, password: loginPassword)\n        } catch {\n            XCTFail(\"Could not signUp user: \\(error)\")\n        }\n\n        guard let userObjectId = User.current?.objectId else {\n            XCTFail(\"Could not get objectId of currentUser\")\n            return\n        }\n\n        var newACL = ParseACL()\n        newACL.publicRead = true\n        newACL.publicWrite = true\n        do {\n            _ = try ParseACL.setDefaultACL(newACL, withAccessForCurrentUser: true)\n            let defaultACL = try ParseACL.defaultACL()\n            XCTAssertEqual(newACL.publicRead, defaultACL.publicRead)\n            XCTAssertEqual(newACL.publicWrite, defaultACL.publicWrite)\n            XCTAssertTrue(defaultACL.getReadAccess(objectId: userObjectId))\n            XCTAssertTrue(defaultACL.getWriteAccess(objectId: userObjectId))\n            try User.logout()\n            XCTAssertThrowsError(try ParseACL.defaultACL())\n        } catch {\n            XCTFail(\"Should have set new ACL. Error \\(error)\")\n        }\n    }\n\n    func testDefaultACLDontUseCurrentUser() {\n        let loginResponse = LoginSignupResponse()\n        let loginUserName = \"hello10\"\n        let loginPassword = \"world\"\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        do {\n            _ = try User.signup(username: loginUserName, password: loginPassword)\n        } catch {\n            XCTFail(\"Could not signUp user: \\(error.localizedDescription)\")\n        }\n\n        guard let userObjectId = User.current?.objectId else {\n            XCTFail(\"Could not get objectId of currentUser\")\n            return\n        }\n\n        var newACL = ParseACL()\n        newACL.setReadAccess(objectId: \"someUserID\", value: true)\n        do {\n            _ = try ParseACL.setDefaultACL(newACL, withAccessForCurrentUser: false)\n            let defaultACL = try ParseACL.defaultACL()\n            XCTAssertTrue(defaultACL.getReadAccess(objectId: \"someUserID\"))\n            XCTAssertFalse(defaultACL.getReadAccess(objectId: userObjectId))\n            XCTAssertFalse(defaultACL.getWriteAccess(objectId: userObjectId))\n        } catch {\n            XCTFail(\"Should have set new ACL. Error \\(error.localizedDescription)\")\n        }\n    }\n}\n\nextension ParseACLTests.User {\n    init(objectId: String) {\n        self.objectId = objectId\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseAnalyticsAsyncTests.swift",
    "content": "//\n//  ParseAnalyticsAsyncTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/28/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseAnalyticsAsyncTests: XCTestCase { // swiftlint:disable:this type_body_length\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    #if os(iOS)\n    @MainActor\n    func testTrackAppOpenedUIKit() async throws {\n\n        let serverResponse = NoBody()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        let options = [UIApplication.LaunchOptionsKey.remoteNotification: [\"stop\": \"drop\"]]\n        _ = try await ParseAnalytics.trackAppOpened(launchOptions: options)\n    }\n\n    func testTrackAppOpenedUIKitError() async throws {\n\n        let serverResponse = NoBody()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        let options = [UIApplication.LaunchOptionsKey.remoteNotification: [\"stop\": \"drop\"]]\n        _ = try await ParseAnalytics.trackAppOpened(launchOptions: options)\n    }\n    #endif\n\n    @MainActor\n    func testTrackAppOpened() async throws {\n        let serverResponse = ParseError(code: .internalServer, message: \"none\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            _ = try await ParseAnalytics.trackAppOpened(dimensions: [\"stop\": \"drop\"])\n            XCTFail(\"Should have thrown error\")\n        } catch {\n\n            guard let error = error as? ParseError else {\n                XCTFail(\"Should be ParseError\")\n                return\n            }\n            XCTAssertEqual(error.message, serverResponse.message)\n        }\n    }\n\n    @MainActor\n    func testTrackAppOpenedError() async throws {\n        let serverResponse = ParseError(code: .internalServer, message: \"none\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            _ = try await ParseAnalytics.trackAppOpened(dimensions: [\"stop\": \"drop\"])\n            XCTFail(\"Should have thrown error\")\n        } catch {\n\n            guard let error = error as? ParseError else {\n                XCTFail(\"Should be ParseError\")\n                return\n            }\n            XCTAssertEqual(error.message, serverResponse.message)\n        }\n    }\n\n    @MainActor\n    func testTrackEvent() async throws {\n        let serverResponse = NoBody()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        let event = ParseAnalytics(name: \"hello\")\n        _ = try await event.track()\n    }\n\n    @MainActor\n    func testTrackEventError() async throws {\n        let serverResponse = ParseError(code: .internalServer, message: \"none\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        let event = ParseAnalytics(name: \"hello\")\n\n        do {\n            _ = try await event.track()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n\n            guard let error = error as? ParseError else {\n                XCTFail(\"Should be ParseError\")\n                return\n            }\n            XCTAssertEqual(error.message, serverResponse.message)\n        }\n    }\n\n    func testTrackEventMutated() async throws {\n        let serverResponse = NoBody()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        var event = ParseAnalytics(name: \"hello\")\n        _ = try await event.track(dimensions: [\"stop\": \"drop\"])\n    }\n\n    func testTrackEventMutatedError() async throws {\n        let serverResponse = ParseError(code: .internalServer, message: \"none\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        var event = ParseAnalytics(name: \"hello\")\n        do {\n            _ = try await event.track(dimensions: [\"stop\": \"drop\"])\n            XCTFail(\"Should have thrown error\")\n        } catch {\n\n            guard let error = error as? ParseError else {\n                XCTFail(\"Should be ParseError\")\n                return\n            }\n            XCTAssertEqual(error.message, serverResponse.message)\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseAnalyticsCombineTests.swift",
    "content": "//\n//  ParseAnalyticsCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 5/22/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseAnalyticsCombineTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    #if os(iOS)\n    func testTrackAppOpenedUIKit() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        let serverResponse = NoBody()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        let options = [UIApplication.LaunchOptionsKey.remoteNotification: [\"stop\": \"drop\"]]\n        let publisher = ParseAnalytics.trackAppOpenedPublisher(launchOptions: options)\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n    #endif\n\n    func testTrackAppOpened() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        let serverResponse = NoBody()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = ParseAnalytics.trackAppOpenedPublisher(dimensions: [\"stop\": \"drop\"])\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testTrackEvent() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        let serverResponse = NoBody()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        let event = ParseAnalytics(name: \"hello\")\n        let publisher = event.trackPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testTrackEventMutated() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        let serverResponse = NoBody()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        let event = ParseAnalytics(name: \"hello\")\n        let publisher = event.trackPublisher(dimensions: [\"stop\": \"drop\"])\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseAnalyticsTests.swift",
    "content": "//\n//  ParseAnalyticsTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 5/20/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseAnalyticsTests: XCTestCase {\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testSaveCommand() throws {\n        let name = \"hello\"\n        let event = ParseAnalytics(name: name)\n        let command = event.saveCommand()\n        XCTAssertEqual(command.path.urlComponent, \"/events/\\(name)\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertNotNil(command.body)\n        XCTAssertNil(command.body?.at)\n        XCTAssertNil(command.body?.dimensions)\n\n        let date = Date()\n        let dimensions = [\"stop\": \"drop\"]\n        var event2 = ParseAnalytics(name: name, dimensions: dimensions, at: date)\n        let command2 = event2.saveCommand()\n        XCTAssertEqual(command2.path.urlComponent, \"/events/\\(name)\")\n        XCTAssertEqual(command2.method, API.Method.POST)\n        XCTAssertNotNil(command2.body)\n        XCTAssertEqual(command2.body?.at, date)\n        XCTAssertNotNil(command2.body?.dimensions)\n\n        event2.date = nil //Clear date for comparison\n        let decoded = event2.debugDescription\n        let expected = \"{\\\"dimensions\\\":{\\\"stop\\\":\\\"drop\\\"},\\\"name\\\":\\\"hello\\\"}\"\n        XCTAssertEqual(decoded, expected)\n        let decoded2 = event2.description\n        let expected2 = \"{\\\"dimensions\\\":{\\\"stop\\\":\\\"drop\\\"},\\\"name\\\":\\\"hello\\\"}\"\n        XCTAssertEqual(decoded2, expected2)\n        let encoded3 = try ParseCoding.parseEncoder().encode(event2)\n        let decoded3 = String(data: encoded3, encoding: .utf8)\n        let expected3 = \"{\\\"dimensions\\\":{\\\"stop\\\":\\\"drop\\\"}}\"\n        XCTAssertEqual(decoded3, expected3)\n    }\n\n    func testEquatable() throws {\n        let name = \"hello\"\n        let event = ParseAnalytics(name: name)\n        let event2 = ParseAnalytics(name: name,\n                                    dimensions: [\"stop\": \"drop\"],\n                                    at: Date())\n        XCTAssertEqual(event, event)\n        XCTAssertNotEqual(event, event2)\n        XCTAssertEqual(event2, event2)\n    }\n\n    func testHashable() throws {\n        let name = \"hello\"\n        let event = ParseAnalytics(name: name)\n        let event2 = ParseAnalytics(name: name,\n                                    dimensions: [\"stop\": \"drop\"],\n                                    at: Date())\n        let event3 = ParseAnalytics(name: \"world\")\n        let events = [event: 1, event2: 2]\n        XCTAssertEqual(events[event], 1)\n        XCTAssertEqual(events[event2], 2)\n        XCTAssertNil(events[event3])\n    }\n\n    func testSetDimensions() throws {\n        let name = \"hello\"\n        let dimensions = [\"stop\": \"drop\"]\n        let dimensions2 = [\"open\": \"up shop\"]\n        var event = ParseAnalytics(name: name, dimensions: dimensions)\n        let encodedDimensions = try ParseCoding.jsonEncoder().encode(AnyCodable(event.dimensions))\n        let decodedDictionary = try ParseCoding.jsonDecoder().decode([String: String].self,\n                                                                     from: encodedDimensions)\n        XCTAssertEqual(decodedDictionary, dimensions)\n        event.dimensions = dimensions2\n        let encoded = try ParseCoding.jsonEncoder().encode(AnyCodable(event.dimensions))\n        let encodedExpected = try ParseCoding.jsonEncoder().encode(dimensions2)\n        XCTAssertEqual(encoded, encodedExpected)\n        let encoded2 = try ParseCoding.jsonEncoder().encode(event.dimensionsAnyCodable)\n        XCTAssertEqual(encoded2, encodedExpected)\n    }\n\n    func testUpdateDimensions() throws {\n        let name = \"hello\"\n        let dimensions = [\"stop\": \"drop\"]\n        let dimensions2 = [\"open\": \"up shop\"]\n        var dimensions3 = dimensions\n        for (key, value) in dimensions2 {\n            dimensions3[key] = value\n        }\n        var event = ParseAnalytics(name: name, dimensions: dimensions)\n        event.dimensions = dimensions2\n        let encoded = try ParseCoding.jsonEncoder().encode(AnyCodable(event.dimensions))\n        let encodedExpected = try ParseCoding.jsonEncoder().encode(dimensions2)\n        XCTAssertEqual(encoded, encodedExpected)\n    }\n\n    func testUpdateDimensionsNonInitially() throws {\n        let name = \"hello\"\n        let dimensions = [\"stop\": \"drop\"]\n        var event = ParseAnalytics(name: name)\n        XCTAssertNil(event.dimensions)\n        event.dimensions = dimensions\n        let encoded = try ParseCoding.jsonEncoder().encode(AnyCodable(event.dimensions))\n        let encodedExpected = try ParseCoding.jsonEncoder().encode(dimensions)\n        XCTAssertEqual(encoded, encodedExpected)\n    }\n\n    #if os(iOS)\n    func testTrackAppOpenedUIKit() {\n        let serverResponse = NoBody()\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation = XCTestExpectation(description: \"Analytics save\")\n        let options = [UIApplication.LaunchOptionsKey.remoteNotification: [\"stop\": \"drop\"]]\n        ParseAnalytics.trackAppOpened(launchOptions: options) { result in\n\n            if case .failure(let error) = result {\n                XCTFail(error.localizedDescription)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 10.0)\n    }\n\n    func testTrackAppOpenedUIKitError() {\n        let serverResponse = ParseError(code: .missingObjectId, message: \"Object missing objectId\")\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation = XCTestExpectation(description: \"Analytics save\")\n        let options = [UIApplication.LaunchOptionsKey.remoteNotification: [\"stop\": \"drop\"]]\n        ParseAnalytics.trackAppOpened(launchOptions: options) { result in\n\n            if case .success = result {\n                XCTFail(\"Should have failed with error.\")\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 10.0)\n    }\n    #endif\n\n    func testTrackAppOpened() {\n        let serverResponse = NoBody()\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation = XCTestExpectation(description: \"Analytics save\")\n        ParseAnalytics.trackAppOpened(dimensions: [\"stop\": \"drop\"]) { result in\n\n            if case .failure(let error) = result {\n                XCTFail(error.localizedDescription)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 10.0)\n    }\n\n    func testTrackAppOpenedError() {\n        let serverResponse = ParseError(code: .missingObjectId, message: \"Object missing objectId\")\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation = XCTestExpectation(description: \"Analytics save\")\n        ParseAnalytics.trackAppOpened(dimensions: [\"stop\": \"drop\"]) { result in\n\n            if case .success = result {\n                XCTFail(\"Should have failed with error.\")\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 10.0)\n    }\n\n    func testTrackEvent() {\n        let serverResponse = NoBody()\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation = XCTestExpectation(description: \"Analytics save\")\n        let event = ParseAnalytics(name: \"hello\")\n        event.track { result in\n\n            if case .failure(let error) = result {\n                XCTFail(error.localizedDescription)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 10.0)\n    }\n\n    func testTrackEventMutated() {\n        let serverResponse = NoBody()\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation = XCTestExpectation(description: \"Analytics save\")\n        var event = ParseAnalytics(name: \"hello\")\n        event.track(dimensions: nil) { result in\n\n            if case .failure(let error) = result {\n                XCTFail(error.localizedDescription)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 10.0)\n    }\n\n    func testTrackEventError() {\n        let serverResponse = ParseError(code: .missingObjectId, message: \"Object missing objectId\")\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation = XCTestExpectation(description: \"Analytics save\")\n        let event = ParseAnalytics(name: \"hello\")\n        event.track { result in\n\n            if case .success = result {\n                XCTFail(\"Should have failed with error.\")\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 10.0)\n    }\n\n    func testTrackEventErrorMutated() {\n        let serverResponse = ParseError(code: .missingObjectId, message: \"Object missing objectId\")\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation = XCTestExpectation(description: \"Analytics save\")\n        var event = ParseAnalytics(name: \"hello\")\n        event.track(dimensions: nil) { result in\n\n            if case .success = result {\n                XCTFail(\"Should have failed with error.\")\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 10.0)\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseAnonymousAsyncTests.swift",
    "content": "//\n//  ParseAnonymousAsyncTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/28/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseAnonymousAsyncTests: XCTestCase { // swiftlint:disable:this type_body_length\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            self.createdAt = Date()\n            self.updatedAt = Date()\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    @MainActor\n    func testLogin() async throws {\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.anonymous.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.anonymous.login()\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testLoginAuthData() async throws {\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.anonymous.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.anonymous.login(authData: .init())\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testLink() async throws {\n        do {\n            _ = try await User.anonymous.link(authData: .init())\n            XCTFail(\"Should have returned error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted to parse error\")\n                return\n            }\n            XCTAssertEqual(parseError.message, \"Not supported\")\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseAnonymousCombineTests.swift",
    "content": "//\n//  ParseAnonymousCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/30/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseAnonymousCombineTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            self.createdAt = Date()\n            self.updatedAt = Date()\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testLogin() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.anonymous.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.anonymous.loginPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user, userOnServer)\n            XCTAssertEqual(user.username, \"hello\")\n            XCTAssertEqual(user.password, \"world\")\n            XCTAssertTrue(user.anonymous.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginAuthData() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.anonymous.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.anonymous.loginPublisher(authData: .init())\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user, userOnServer)\n            XCTAssertEqual(user.username, \"hello\")\n            XCTAssertEqual(user.password, \"world\")\n            XCTAssertTrue(user.anonymous.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLink() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        let publisher = User.anonymous.linkPublisher(authData: .init())\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTAssertEqual(error.message, \"Not supported\")\n                } else {\n                    XCTFail(\"Should have returned error\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n\n            XCTFail(\"Should have returned error\")\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseAnonymousTests.swift",
    "content": "//\n//  ParseAnonymousTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/16/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseAnonymousTests: XCTestCase {\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    struct UpdateSessionTokenResponse: Codable {\n        var updatedAt: Date\n        let sessionToken: String?\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func loginNormally() throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try User.login(username: \"parse\", password: \"user\")\n    }\n\n    func testStrip() throws {\n\n        let expectedAuth = [\"id\": \"yolo\"]\n        var user = User()\n        user.authData = [user.anonymous.__type: expectedAuth]\n        XCTAssertEqual(user.authData, [\"anonymous\": expectedAuth])\n        let strippedAuth = user.anonymous.strip(user)\n        XCTAssertEqual(strippedAuth.authData, [\"anonymous\": nil])\n\n    }\n\n    func testAuthenticationKeys() throws {\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        XCTAssertEqual(Array(authData.keys), [\"id\"])\n        XCTAssertNotNil(authData[\"id\"])\n        XCTAssertNotEqual(authData[\"id\"], \"\")\n        XCTAssertNotEqual(authData[\"id\"], \"12345\")\n    }\n\n    func testLogin() throws {\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.anonymous.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let login1 = try User.anonymous.login()\n        XCTAssertEqual(login1, User.current)\n        XCTAssertEqual(login1, userOnServer)\n        XCTAssertEqual(login1.username, \"hello\")\n        XCTAssertEqual(login1.password, \"world\")\n        XCTAssertTrue(login1.anonymous.isLinked)\n    }\n\n    func testLoginAuthData() throws {\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.anonymous.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let login1 = try User.anonymous.login(authData: .init())\n        XCTAssertEqual(login1, User.current)\n        XCTAssertEqual(login1, userOnServer)\n        XCTAssertEqual(login1.username, \"hello\")\n        XCTAssertEqual(login1.password, \"world\")\n        XCTAssertTrue(login1.anonymous.isLinked)\n    }\n\n    func testLoginAsync() throws {\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.anonymous.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.anonymous.login { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user, userOnServer)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.anonymous.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginAuthDataAsync() throws {\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.anonymous.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.anonymous.login(authData: .init()) { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user, userOnServer)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.anonymous.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testReplaceAnonymousUser() throws {\n        try testLogin()\n        guard let user = User.current,\n              let updatedAt = user.updatedAt else {\n            XCTFail(\"Shold have unwrapped\")\n            return\n        }\n        XCTAssertTrue(user.anonymous.isLinked)\n\n        var response = UpdateSessionTokenResponse(updatedAt: updatedAt.addingTimeInterval(+300),\n            sessionToken: \"blast\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n            //Get dates in correct format from ParseDecoding strategy\n            response = try ParseCoding.jsonDecoder().decode(UpdateSessionTokenResponse.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.removeAll()\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        var current = User.current\n        current?.username = \"hello\"\n        current?.password = \"world\"\n        current?.signup { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertFalse(user.anonymous.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testReplaceAnonymousUserBody() throws {\n        try testLogin()\n        guard let user = User.current,\n              let updatedAt = user.updatedAt else {\n            XCTFail(\"Shold have unwrapped\")\n            return\n        }\n        XCTAssertTrue(user.anonymous.isLinked)\n\n        var response = UpdateSessionTokenResponse(updatedAt: updatedAt.addingTimeInterval(+300),\n            sessionToken: \"blast\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n            //Get dates in correct format from ParseDecoding strategy\n            response = try ParseCoding.jsonDecoder().decode(UpdateSessionTokenResponse.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.removeAll()\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.signup(username: \"hello\",\n                    password: \"world\") { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertFalse(user.anonymous.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testReplaceAnonymousUserSync() throws {\n        try testLogin()\n        guard let user = User.current,\n              let updatedAt = user.updatedAt else {\n            XCTFail(\"Shold have unwrapped\")\n            return\n        }\n        XCTAssertTrue(user.anonymous.isLinked)\n\n        var response = UpdateSessionTokenResponse(updatedAt: updatedAt.addingTimeInterval(+300),\n            sessionToken: \"blast\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n            //Get dates in correct format from ParseDecoding strategy\n            response = try ParseCoding.jsonDecoder().decode(UpdateSessionTokenResponse.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.removeAll()\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        User.current?.username = \"hello\"\n        User.current?.password = \"world\"\n        guard let signedInUser = try User.current?.signup() else {\n            XCTFail(\"Shouuld have unwrapped\")\n            return\n        }\n        XCTAssertEqual(signedInUser, User.current)\n        XCTAssertEqual(signedInUser.username, \"hello\")\n        XCTAssertEqual(signedInUser.password, \"world\")\n        XCTAssertFalse(signedInUser.anonymous.isLinked)\n    }\n\n    func testReplaceAnonymousUserBodySync() throws {\n        try testLogin()\n        guard let user = User.current,\n              let updatedAt = user.updatedAt else {\n            XCTFail(\"Shold have unwrapped\")\n            return\n        }\n        XCTAssertTrue(user.anonymous.isLinked)\n\n        var response = UpdateSessionTokenResponse(updatedAt: updatedAt.addingTimeInterval(+300),\n            sessionToken: \"blast\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n            //Get dates in correct format from ParseDecoding strategy\n            response = try ParseCoding.jsonDecoder().decode(UpdateSessionTokenResponse.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.removeAll()\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let signedInUser = try User.signup(username: \"hello\",\n                                           password: \"world\")\n        XCTAssertEqual(signedInUser, User.current)\n        XCTAssertEqual(signedInUser.username, \"hello\")\n        XCTAssertEqual(signedInUser.password, \"world\")\n        XCTAssertFalse(signedInUser.anonymous.isLinked)\n    }\n\n    func testCantReplaceAnonymousWithDifferentUser() throws {\n        try testLogin()\n        guard let user = User.current else {\n            XCTFail(\"Shold have unwrapped\")\n            return\n        }\n        XCTAssertTrue(user.anonymous.isLinked)\n\n        let expectation1 = XCTestExpectation(description: \"SignUp\")\n        var differentUser = User()\n        differentUser.objectId = \"nope\"\n        differentUser.username = \"shouldnot\"\n        differentUser.password = \"work\"\n        differentUser.signup { result in\n            if case let .failure(error) = result {\n                XCTAssertEqual(error.code, .unknownError)\n                XCTAssertTrue(error.message.contains(\"different\"))\n            } else {\n                XCTFail(\"Should have returned error\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testCantReplaceAnonymousWithDifferentUserSync() throws {\n        try testLogin()\n        guard let user = User.current else {\n            XCTFail(\"Shold have unwrapped\")\n            return\n        }\n        XCTAssertTrue(user.anonymous.isLinked)\n\n        var differentUser = User()\n        differentUser.objectId = \"nope\"\n        differentUser.username = \"shouldnot\"\n        differentUser.password = \"work\"\n        XCTAssertThrowsError(try differentUser.signup())\n    }\n\n    func testReplaceAnonymousWithBecome() throws { // swiftlint:disable:this function_body_length\n        XCTAssertNil(User.current?.objectId)\n        try testLogin()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n        XCTAssertTrue(User.anonymous.isLinked)\n\n        guard let user = User.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.createdAt = User.current?.createdAt\n        serverResponse.updatedAt = User.current?.updatedAt?.addingTimeInterval(+300)\n        serverResponse.sessionToken = \"newValue\"\n        serverResponse.username = \"stop\"\n        serverResponse.password = \"this\"\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Fetch user1\")\n        user.become(sessionToken: \"newValue\") { result in\n\n            switch result {\n            case .success(let become):\n                XCTAssert(become.hasSameObjectId(as: userOnServer))\n                guard let becomeCreatedAt = become.createdAt,\n                    let becomeUpdatedAt = become.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                guard let originalCreatedAt = user.createdAt,\n                    let originalUpdatedAt = user.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(becomeCreatedAt, originalCreatedAt)\n                XCTAssertGreaterThan(becomeUpdatedAt, originalUpdatedAt)\n                XCTAssertNil(become.ACL)\n\n                //Should be updated in memory\n                XCTAssertEqual(User.current?.updatedAt, becomeUpdatedAt)\n                XCTAssertFalse(User.anonymous.isLinked)\n\n                #if !os(Linux) && !os(Android) && !os(Windows)\n                //Should be updated in Keychain\n                guard let keychainUser: CurrentUserContainer<BaseParseUser>\n                    = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser) else {\n                        XCTFail(\"Should get object from Keychain\")\n                    return\n                }\n                XCTAssertEqual(keychainUser.currentUser?.updatedAt, becomeUpdatedAt)\n                #endif\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLink() throws {\n\n        let expectation1 = XCTestExpectation(description: \"Fetch user1\")\n        User.anonymous.link(authData: .init()) { result in\n            if case let .failure(error) = result {\n                XCTAssertEqual(error.message, \"Not supported\")\n            } else {\n                XCTFail(\"Should have returned error\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseAppleAsyncTests.swift",
    "content": "//\n//  ParseAppleAsyncTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/28/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseAppleAsyncTests: XCTestCase { // swiftlint:disable:this type_body_length\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    @MainActor\n    func testLogin() async throws {\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.apple.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        guard let tokenData = \"this\".data(using: .utf8) else {\n            XCTFail(\"Could not convert token data to string\")\n            return\n        }\n\n        let user = try await User.apple.login(user: \"testing\", identityToken: tokenData)\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.apple.isLinked)\n    }\n\n    @MainActor\n    func testLoginAuthData() async throws {\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.apple.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.apple.login(authData: [\"id\": \"testing\",\n                                                         \"token\": \"test\"])\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.apple.isLinked)\n    }\n\n    func loginNormally() async throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try await User.login(username: \"parse\", password: \"user\")\n    }\n\n    @MainActor\n    func testLink() async throws {\n        _ = try await loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        guard let tokenData = \"this\".data(using: .utf8) else {\n            XCTFail(\"Could not convert token data to string\")\n            return\n        }\n\n        let user = try await User.apple.link(user: \"testing\", identityToken: tokenData)\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.apple.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testLinkAuthData() async throws {\n        _ = try await loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.apple.link(authData: [\"id\": \"testing\",\n                                                        \"token\": \"test\"])\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.apple.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testUnlink() async throws {\n        _ = try await loginNormally()\n        MockURLProtocol.removeAll()\n\n        guard let tokenData = \"this\".data(using: .utf8) else {\n            XCTFail(\"Could not convert token data to string\")\n            return\n        }\n\n        let authData = try ParseApple<User>\n            .AuthenticationKeys.id.makeDictionary(user: \"testing\",\n                                                  identityToken: tokenData)\n        User.current?.authData = [User.apple.__type: authData]\n        XCTAssertTrue(User.apple.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.apple.unlink()\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertFalse(user.apple.isLinked)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseAppleCombineTests.swift",
    "content": "//\n//  ParseAppleCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/30/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseAppleCombineTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testLogin() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.apple.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        guard let tokenData = \"this\".data(using: .utf8) else {\n            XCTFail(\"Could not convert token data to string\")\n            return\n        }\n\n        let publisher = User.apple.loginPublisher(user: \"testing\", identityToken: tokenData)\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user, userOnServer)\n            XCTAssertEqual(user.username, \"hello\")\n            XCTAssertEqual(user.password, \"world\")\n            XCTAssertTrue(user.apple.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginAuthData() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.apple.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.apple.loginPublisher(authData: [\"id\": \"testing\",\n                                                             \"token\": \"test\"])\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user, userOnServer)\n            XCTAssertEqual(user.username, \"hello\")\n            XCTAssertEqual(user.password, \"world\")\n            XCTAssertTrue(user.apple.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func loginNormally() throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try User.login(username: \"parse\", password: \"user\")\n    }\n\n    func testLink() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        guard let tokenData = \"this\".data(using: .utf8) else {\n            XCTFail(\"Could not convert token data to string\")\n            return\n        }\n\n        let publisher = User.apple.linkPublisher(user: \"testing\", identityToken: tokenData)\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertTrue(user.apple.isLinked)\n            XCTAssertFalse(user.anonymous.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkAuthData() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.apple.linkPublisher(authData: [\"id\": \"testing\",\n                                                            \"token\": \"test\"])\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertTrue(user.apple.isLinked)\n            XCTAssertFalse(user.anonymous.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUnlink() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        guard let tokenData = \"this\".data(using: .utf8) else {\n            XCTFail(\"Could not convert token data to string\")\n            return\n        }\n\n        let authData = try ParseApple<User>\n            .AuthenticationKeys.id.makeDictionary(user: \"testing\",\n                                                  identityToken: tokenData)\n        User.current?.authData = [User.apple.__type: authData]\n        XCTAssertTrue(User.apple.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.apple.unlinkPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertFalse(user.apple.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseAppleTests.swift",
    "content": "//\n//  ParseAppleTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/16/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseAppleTests: XCTestCase {\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func loginNormally() throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try User.login(username: \"parse\", password: \"user\")\n    }\n\n    func testAuthenticationKeys() throws {\n        guard let tokenData = \"test\".data(using: .utf8) else {\n            XCTFail(\"Should have created Data\")\n            return\n        }\n        let authData = try ParseApple<User>\n            .AuthenticationKeys.id.makeDictionary(user: \"testing\",\n                                                  identityToken: tokenData)\n        XCTAssertEqual(authData, [\"id\": \"testing\", \"token\": \"test\"])\n    }\n\n    func testVerifyMandatoryKeys() throws {\n        let authData = [\"id\": \"testing\", \"token\": \"test\"]\n        let authDataWrong = [\"id\": \"testing\", \"hello\": \"test\"]\n        XCTAssertTrue(ParseApple<User>\n                        .AuthenticationKeys.id.verifyMandatoryKeys(authData: authData))\n        XCTAssertFalse(ParseApple<User>\n                        .AuthenticationKeys.id.verifyMandatoryKeys(authData: authDataWrong))\n    }\n\n    func testLogin() throws {\n        var serverResponse = LoginSignupResponse()\n        guard let tokenData = \"this\".data(using: .utf8) else {\n            XCTFail(\"Could not convert token data to string\")\n            return\n        }\n\n        let authData = try ParseApple<User>\n            .AuthenticationKeys.id.makeDictionary(user: \"testing\",\n                                                  identityToken: tokenData)\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.apple.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.apple.login(user: \"testing\", identityToken: tokenData) { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user, userOnServer)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.apple.isLinked)\n\n                //Test stripping\n                user.apple.strip()\n                XCTAssertFalse(user.apple.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginAuthData() throws {\n        var serverResponse = LoginSignupResponse()\n        guard let tokenData = \"this\".data(using: .utf8) else {\n            XCTFail(\"Could not convert token data to string\")\n            return\n        }\n\n        let authData = try ParseApple<User>\n            .AuthenticationKeys.id.makeDictionary(user: \"testing\",\n                                                  identityToken: tokenData)\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.apple.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.apple.login(authData: authData) { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user, userOnServer)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.apple.isLinked)\n\n                //Test stripping\n                user.apple.strip()\n                XCTAssertFalse(user.apple.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginWrongKeys() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.apple.login(authData: [\"hello\": \"world\"]) { result in\n\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"consisting of keys\"))\n            } else {\n                XCTFail(\"Should have returned error\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func loginAnonymousUser() throws {\n        let authData = [\"id\": \"yolo\"]\n\n        //: Convert the anonymous user to a real new user.\n        var serverResponse = LoginSignupResponse()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.anonymous.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try User.anonymous.login()\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.anonymous.isLinked)\n    }\n\n    func testReplaceAnonymousWithApple() throws {\n        try loginAnonymousUser()\n        MockURLProtocol.removeAll()\n        guard let tokenData = \"this\".data(using: .utf8) else {\n            XCTFail(\"Could not convert token data to string\")\n            return\n        }\n\n        let authData = try ParseApple<User>\n            .AuthenticationKeys.id.makeDictionary(user: \"testing\",\n                                                  identityToken: tokenData)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.apple.__type: authData,\n                                   serverResponse.anonymous.__type: nil]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.apple.login(user: \"testing\", identityToken: tokenData) { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.authData, userOnServer.authData)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.apple.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testReplaceAnonymousWithLinkedApple() throws {\n        try loginAnonymousUser()\n        MockURLProtocol.removeAll()\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        guard let tokenData = \"this\".data(using: .utf8) else {\n            XCTFail(\"Could not convert token data to string\")\n            return\n        }\n\n        User.apple.link(user: \"testing\", identityToken: tokenData) { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.apple.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkLoggedInUserWithApple() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.sessionToken = nil\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        guard let tokenData = \"this\".data(using: .utf8) else {\n            XCTFail(\"Could not convert token data to string\")\n            return\n        }\n\n        User.apple.link(user: \"testing\", identityToken: tokenData) { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello10\")\n                XCTAssertNil(user.password)\n                XCTAssertTrue(user.apple.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n                XCTAssertEqual(User.current?.sessionToken, \"myToken\")\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkLoggedInAuthData() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.sessionToken = nil\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        guard let tokenData = \"this\".data(using: .utf8) else {\n            XCTFail(\"Could not convert token data to string\")\n            return\n        }\n\n        let authData = try ParseApple<User>\n            .AuthenticationKeys.id.makeDictionary(user: \"testing\",\n                                                  identityToken: tokenData)\n\n        User.apple.link(authData: authData) { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello10\")\n                XCTAssertNil(user.password)\n                XCTAssertTrue(user.apple.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n                XCTAssertEqual(User.current?.sessionToken, \"myToken\")\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkLoggedInUserWrongKeys() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.apple.link(authData: [\"hello\": \"world\"]) { result in\n\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"consisting of keys\"))\n            } else {\n                XCTFail(\"Should have returned error\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUnlink() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n        guard let tokenData = \"this\".data(using: .utf8) else {\n            XCTFail(\"Could not convert token data to string\")\n            return\n        }\n\n        let authData = try ParseApple<User>\n            .AuthenticationKeys.id.makeDictionary(user: \"testing\",\n                                                  identityToken: tokenData)\n        User.current?.authData = [User.apple.__type: authData]\n        XCTAssertTrue(User.apple.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.apple.unlink { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello10\")\n                XCTAssertNil(user.password)\n                XCTAssertFalse(user.apple.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseAuthenticationAsyncTests.swift",
    "content": "//\n//  ParseAuthenticationAsyncTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/28/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n#if canImport(Combine)\nimport Combine\n#endif\n\nclass ParseAuthenticationAsyncTests: XCTestCase { // swiftlint:disable:this type_body_length\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    struct TestAuth<AuthenticatedUser: ParseUser>: ParseAuthentication {\n        static var __type: String { // swiftlint:disable:this identifier_name\n            \"test\"\n        }\n        func login(authData: [String: String],\n                   options: API.Options,\n                   callbackQueue: DispatchQueue,\n                   completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n            let error = ParseError(code: .unknownError, message: \"Not implemented\")\n            completion(.failure(error))\n        }\n\n        func link(authData: [String: String],\n                  options: API.Options,\n                  callbackQueue: DispatchQueue,\n                  completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n            let error = ParseError(code: .unknownError, message: \"Not implemented\")\n            completion(.failure(error))\n        }\n\n        #if canImport(Combine)\n        func loginPublisher(authData: [String: String],\n                            options: API.Options) -> Future<AuthenticatedUser, ParseError> {\n            let error = ParseError(code: .unknownError, message: \"Not implemented\")\n            return Future { promise in\n                promise(.failure(error))\n            }\n        }\n\n        func linkPublisher(authData: [String: String],\n                           options: API.Options) -> Future<AuthenticatedUser, ParseError> {\n            let error = ParseError(code: .unknownError, message: \"Not implemented\")\n            return Future { promise in\n                promise(.failure(error))\n            }\n        }\n        #endif\n\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        func login(authData: [String: String],\n                   options: API.Options) async throws -> AuthenticatedUser {\n            throw ParseError(code: .unknownError, message: \"Not implemented\")\n        }\n\n        func link(authData: [String: String],\n                  options: API.Options) async throws -> AuthenticatedUser {\n            throw ParseError(code: .unknownError, message: \"Not implemented\")\n        }\n        #endif\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    @MainActor\n    func testLogin() async throws {\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        let type = TestAuth<User>.__type\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.login(type, authData: [\"id\": \"yolo\"])\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertEqual(user.authData, serverResponse.authData)\n    }\n\n    func loginNormally() async throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try await User.login(username: \"parse\", password: \"user\")\n    }\n\n    @MainActor\n    func testLink() async throws {\n\n        _ = try await loginNormally()\n        MockURLProtocol.removeAll()\n\n        let type = TestAuth<User>.__type\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.link(type, authData: [\"id\": \"yolo\"])\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseAuthenticationCombineTests.swift",
    "content": "//\n//  ParseAuthenticationCombineTests.swift\n//  ParseAuthenticationCombineTests\n//\n//  Created by Corey Baker on 8/21/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseAuthenticationCombineTests: XCTestCase {\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    struct TestAuth<AuthenticatedUser: ParseUser>: ParseAuthentication {\n        static var __type: String { // swiftlint:disable:this identifier_name\n            \"test\"\n        }\n        func login(authData: [String: String],\n                   options: API.Options,\n                   callbackQueue: DispatchQueue,\n                   completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n            let error = ParseError(code: .unknownError, message: \"Not implemented\")\n            completion(.failure(error))\n        }\n\n        func link(authData: [String: String],\n                  options: API.Options,\n                  callbackQueue: DispatchQueue,\n                  completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n            let error = ParseError(code: .unknownError, message: \"Not implemented\")\n            completion(.failure(error))\n        }\n\n        #if canImport(Combine)\n        func loginPublisher(authData: [String: String],\n                            options: API.Options) -> Future<AuthenticatedUser, ParseError> {\n            let error = ParseError(code: .unknownError, message: \"Not implemented\")\n            return Future { promise in\n                promise(.failure(error))\n            }\n        }\n\n        func linkPublisher(authData: [String: String],\n                           options: API.Options) -> Future<AuthenticatedUser, ParseError> {\n            let error = ParseError(code: .unknownError, message: \"Not implemented\")\n            return Future { promise in\n                promise(.failure(error))\n            }\n        }\n        #endif\n\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        func login(authData: [String: String],\n                   options: API.Options) async throws -> AuthenticatedUser {\n            throw ParseError(code: .unknownError, message: \"Not implemented\")\n        }\n\n        func link(authData: [String: String],\n                  options: API.Options) async throws -> AuthenticatedUser {\n            throw ParseError(code: .unknownError, message: \"Not implemented\")\n        }\n        #endif\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testLogin() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        let type = TestAuth<User>.__type\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.loginPublisher(type, authData: [\"id\": \"yolo\"])\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user, userOnServer)\n            XCTAssertEqual(user.username, \"hello\")\n            XCTAssertEqual(user.password, \"world\")\n            XCTAssertEqual(user.authData, serverResponse.authData)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func loginNormally() throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try User.login(username: \"parse\", password: \"user\")\n    }\n\n    func testLink() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let type = TestAuth<User>.__type\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.linkPublisher(type, authData: [\"id\": \"yolo\"])\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseAuthenticationTests.swift",
    "content": "//\n//  ParseAuthenticationTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/16/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n#if canImport(Combine)\nimport Combine\n#endif\n\nclass ParseAuthenticationTests: XCTestCase {\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    struct TestAuth<AuthenticatedUser: ParseUser>: ParseAuthentication {\n        static var __type: String { // swiftlint:disable:this identifier_name\n            \"test\"\n        }\n        func login(authData: [String: String],\n                   options: API.Options,\n                   callbackQueue: DispatchQueue,\n                   completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n            let error = ParseError(code: .unknownError, message: \"Not implemented\")\n            completion(.failure(error))\n        }\n\n        func link(authData: [String: String],\n                  options: API.Options,\n                  callbackQueue: DispatchQueue,\n                  completion: @escaping (Result<AuthenticatedUser, ParseError>) -> Void) {\n            let error = ParseError(code: .unknownError, message: \"Not implemented\")\n            completion(.failure(error))\n        }\n\n        #if canImport(Combine)\n        func loginPublisher(authData: [String: String],\n                            options: API.Options) -> Future<AuthenticatedUser, ParseError> {\n            let error = ParseError(code: .unknownError, message: \"Not implemented\")\n            return Future { promise in\n                promise(.failure(error))\n            }\n        }\n\n        func linkPublisher(authData: [String: String],\n                           options: API.Options) -> Future<AuthenticatedUser, ParseError> {\n            let error = ParseError(code: .unknownError, message: \"Not implemented\")\n            return Future { promise in\n                promise(.failure(error))\n            }\n        }\n        #endif\n\n        #if compiler(>=5.5.2) && canImport(_Concurrency)\n        func login(authData: [String: String],\n                   options: API.Options) async throws -> AuthenticatedUser {\n            throw ParseError(code: .unknownError, message: \"Not implemented\")\n        }\n\n        func link(authData: [String: String],\n                  options: API.Options) async throws -> AuthenticatedUser {\n            throw ParseError(code: .unknownError, message: \"Not implemented\")\n        }\n        #endif\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func loginNormally() throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try User.login(username: \"parse\", password: \"user\")\n    }\n\n    func testLinkCommand() throws {\n        let user = User()\n        let body = SignupLoginBody(authData: [\"test\": [\"id\": \"yolo\"]])\n        let command = user.linkCommand(body: body)\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/users\")\n        XCTAssertEqual(command.method, API.Method.PUT)\n        XCTAssertNotNil(command.body)\n        XCTAssertEqual(command.body?.authData, body.authData)\n    }\n\n    func testLinkCommandParseBody() throws {\n        var user = User()\n        user.username = \"hello\"\n        user.password = \"world\"\n        let command = try user.linkCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/users\")\n        XCTAssertEqual(command.method, API.Method.PUT)\n        XCTAssertNotNil(command.body)\n        XCTAssertNil(command.body?.authData)\n    }\n\n    func testLinkCommandLoggedIn() throws {\n        let user = try loginNormally()\n        let body = SignupLoginBody(authData: [\"test\": [\"id\": \"yolo\"]])\n        let command = user.linkCommand(body: body)\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/users/\\(\"yarr\")\")\n        XCTAssertEqual(command.method, API.Method.PUT)\n        XCTAssertNotNil(command.body)\n        XCTAssertEqual(command.body?.authData, body.authData)\n    }\n\n    func testLinkCommandNoBodyLoggedIn() throws {\n        let user = try loginNormally()\n        let command = try user.linkCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/users/\\(\"yarr\")\")\n        XCTAssertEqual(command.method, API.Method.PUT)\n        XCTAssertNotNil(command.body)\n        XCTAssertNil(command.body?.authData)\n    }\n\n    func testIsLinkedWithString() throws {\n\n        let expectedAuth = [\"id\": \"yolo\"]\n        var user = User()\n        let auth = TestAuth<User>()\n        user.authData = [auth.__type: expectedAuth]\n        XCTAssertEqual(user.authData, [\"test\": expectedAuth])\n        XCTAssertTrue(user.isLinked(with: \"test\"))\n    }\n\n    func testAuthStrip() throws {\n\n        let expectedAuth = [\"id\": \"yolo\"]\n        var user = User()\n        let auth = TestAuth<User>()\n        user.authData = [auth.__type: expectedAuth]\n        XCTAssertEqual(user.authData, [\"test\": expectedAuth])\n        let strippedAuth = auth.strip(user)\n        XCTAssertEqual(strippedAuth.authData, [\"test\": nil])\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseBytesTests.swift",
    "content": "//\n//  ParseBytesTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 7/9/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport XCTest\n@testable import ParseSwift\n\nclass ParseBytesTests: XCTestCase {\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testDecode() throws {\n        let bytes = ParseBytes(base64: \"ZnJveW8=\")\n        let encoded = try ParseCoding.jsonEncoder().encode(bytes)\n        let decoded = try ParseCoding.jsonDecoder().decode(ParseBytes.self, from: encoded)\n        XCTAssertEqual(decoded, bytes)\n    }\n\n    func testDebugString() {\n        let bytes = ParseBytes(base64: \"ZnJveW8=\")\n        let expected = \"{\\\"__type\\\":\\\"Bytes\\\",\\\"base64\\\":\\\"ZnJveW8=\\\"}\"\n        XCTAssertEqual(bytes.debugDescription, expected)\n        guard let data = Data(base64Encoded: \"ZnJveW8=\") else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let bytes2 = ParseBytes(data: data)\n        XCTAssertEqual(bytes2.debugDescription, expected)\n    }\n\n    func testDescription() {\n        let bytes = ParseBytes(base64: \"ZnJveW8=\")\n        let expected = \"{\\\"__type\\\":\\\"Bytes\\\",\\\"base64\\\":\\\"ZnJveW8=\\\"}\"\n        XCTAssertEqual(bytes.description, expected)\n        guard let data = Data(base64Encoded: \"ZnJveW8=\") else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let bytes2 = ParseBytes(data: data)\n        XCTAssertEqual(bytes2.description, expected)\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseCLPTests.swift",
    "content": "//\n//  ParseCLPTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 5/28/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseCLPTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() { }\n        init(objectId: String) {\n            self.objectId = objectId\n        }\n    }\n\n    struct Role<RoleUser: ParseUser>: ParseRole {\n\n        // required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // provided by Role\n        var name: String?\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    let objectId = \"1234\"\n    let user = User(objectId: \"1234\")\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testInitializerRequiresAuthentication() throws {\n        let clp = ParseCLP(requiresAuthentication: true, publicAccess: false)\n        XCTAssertEqual(clp.get?[ParseCLP.Access.requiresAuthentication.rawValue], true)\n        XCTAssertEqual(clp.find?[ParseCLP.Access.requiresAuthentication.rawValue], true)\n        XCTAssertEqual(clp.create?[ParseCLP.Access.requiresAuthentication.rawValue], true)\n        XCTAssertEqual(clp.update?[ParseCLP.Access.requiresAuthentication.rawValue], true)\n        XCTAssertEqual(clp.delete?[ParseCLP.Access.requiresAuthentication.rawValue], true)\n        XCTAssertEqual(clp.count?[ParseCLP.Access.requiresAuthentication.rawValue], true)\n        XCTAssertNil(clp.addField?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp.protectedFields)\n        XCTAssertNil(clp.readUserFields)\n        XCTAssertNil(clp.writeUserFields)\n        XCTAssertNil(clp.get?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp.find?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp.create?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp.update?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp.delete?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp.count?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp.addField?[ParseCLP.Access.publicScope.rawValue])\n    }\n\n    func testInitializerPublicAccess() throws {\n        let clp = ParseCLP(requiresAuthentication: false, publicAccess: true)\n        XCTAssertEqual(clp.get?[ParseCLP.Access.publicScope.rawValue], true)\n        XCTAssertEqual(clp.find?[ParseCLP.Access.publicScope.rawValue], true)\n        XCTAssertEqual(clp.create?[ParseCLP.Access.publicScope.rawValue], true)\n        XCTAssertEqual(clp.update?[ParseCLP.Access.publicScope.rawValue], true)\n        XCTAssertEqual(clp.delete?[ParseCLP.Access.publicScope.rawValue], true)\n        XCTAssertEqual(clp.count?[ParseCLP.Access.publicScope.rawValue], true)\n        XCTAssertNil(clp.addField?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp.protectedFields)\n        XCTAssertNil(clp.readUserFields)\n        XCTAssertNil(clp.writeUserFields)\n        XCTAssertNil(clp.get?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp.find?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp.create?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp.update?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp.delete?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp.count?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp.addField?[ParseCLP.Access.requiresAuthentication.rawValue])\n    }\n\n    func testInitializerRequireAndPublicAccess() throws {\n        let clp = ParseCLP(requiresAuthentication: true, publicAccess: true)\n        XCTAssertEqual(clp.get?[ParseCLP.Access.publicScope.rawValue], true)\n        XCTAssertEqual(clp.find?[ParseCLP.Access.publicScope.rawValue], true)\n        XCTAssertEqual(clp.create?[ParseCLP.Access.publicScope.rawValue], true)\n        XCTAssertEqual(clp.update?[ParseCLP.Access.publicScope.rawValue], true)\n        XCTAssertEqual(clp.delete?[ParseCLP.Access.publicScope.rawValue], true)\n        XCTAssertEqual(clp.count?[ParseCLP.Access.publicScope.rawValue], true)\n        XCTAssertNil(clp.addField?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp.protectedFields)\n        XCTAssertNil(clp.readUserFields)\n        XCTAssertNil(clp.writeUserFields)\n        XCTAssertEqual(clp.get?[ParseCLP.Access.requiresAuthentication.rawValue], true)\n        XCTAssertEqual(clp.find?[ParseCLP.Access.requiresAuthentication.rawValue], true)\n        XCTAssertEqual(clp.create?[ParseCLP.Access.requiresAuthentication.rawValue], true)\n        XCTAssertEqual(clp.update?[ParseCLP.Access.requiresAuthentication.rawValue], true)\n        XCTAssertEqual(clp.delete?[ParseCLP.Access.requiresAuthentication.rawValue], true)\n        XCTAssertEqual(clp.count?[ParseCLP.Access.requiresAuthentication.rawValue], true)\n        XCTAssertNil(clp.addField?[ParseCLP.Access.requiresAuthentication.rawValue])\n    }\n\n    func testPointerFields() throws {\n        let fields = Set<String>([\"hello\", \"world\"])\n        let clp = ParseCLP().setPointerFields(fields, on: .create)\n        XCTAssertEqual(clp.getPointerFields(.create), fields)\n\n        let newField = Set<String>([\"new\"])\n        let clp2 = clp.addPointerFields(newField, on: .create)\n        XCTAssertEqual(clp2.getPointerFields(.create), fields.union(newField))\n\n        let clp3 = clp2.removePointerFields(newField, on: .create)\n        XCTAssertEqual(clp3.getPointerFields(.create), fields)\n\n        let clp4 = ParseCLP().addPointerFields(newField, on: .create)\n        XCTAssertEqual(clp4.getPointerFields(.create), newField)\n\n        let clp5 = ParseCLP().setAccess(true, on: .create, for: \"yo\")\n            .setPointerFields(fields, on: .create)\n        XCTAssertEqual(clp5.getPointerFields(.create), fields)\n        XCTAssertEqual(clp5.hasAccess(.create, for: \"yo\"), true)\n    }\n\n    func testPointerFieldsEncode() throws {\n        let fields = Set<String>([\"world\"])\n        let clp = ParseCLP().setPointerFields(fields, on: .create)\n        XCTAssertEqual(clp.description, \"{\\\"create\\\":{\\\"pointerFields\\\":[\\\"world\\\"]}}\")\n    }\n\n    func testPointerAndWriteAccessPublicSetEncode() throws {\n        let fields = Set<String>([\"world\"])\n        let clp = ParseCLP()\n            .setPointerFields(fields, on: .create)\n            .setWriteAccessPublic(true, canAddField: true)\n        // swiftlint:disable:next line_length\n        XCTAssertEqual(clp.description, \"{\\\"addField\\\":{\\\"*\\\":true},\\\"create\\\":{\\\"*\\\":true,\\\"pointerFields\\\":[\\\"world\\\"]},\\\"delete\\\":{\\\"*\\\":true},\\\"update\\\":{\\\"*\\\":true}}\")\n    }\n\n    func testProtectedFieldsPublic() throws {\n        let fields = Set<String>([\"hello\", \"world\"])\n        let clp = ParseCLP().setProtectedFieldsPublic(fields)\n        XCTAssertEqual(clp.getProtectedFieldsPublic(), fields)\n\n        let newField = Set<String>([\"new\"])\n        let clp2 = clp.addProtectedFieldsPublic(newField)\n        XCTAssertEqual(clp2.getProtectedFieldsPublic(), fields.union(newField))\n\n        let clp3 = clp2.removeProtectedFieldsPublic(newField)\n        XCTAssertEqual(clp3.getProtectedFieldsPublic(), fields)\n\n        let clp4 = ParseCLP().addProtectedFieldsPublic(newField)\n        XCTAssertEqual(clp4.getProtectedFieldsPublic(), newField)\n\n        let clp5 = clp.setProtectedFieldsRequiresAuthentication(newField)\n        XCTAssertEqual(clp5.getProtectedFieldsPublic(), fields)\n        XCTAssertEqual(clp5.getProtectedFieldsRequiresAuthentication(), newField)\n    }\n\n    func testProtectedFieldsRequiresAuthentication() throws {\n        let fields = Set<String>([\"hello\", \"world\"])\n        let clp = ParseCLP().setProtectedFieldsRequiresAuthentication(fields)\n        XCTAssertEqual(clp.getProtectedFieldsRequiresAuthentication(), fields)\n\n        let newField = Set<String>([\"new\"])\n        let clp2 = clp.addProtectedFieldsRequiresAuthentication(newField)\n        XCTAssertEqual(clp2.getProtectedFieldsRequiresAuthentication(), fields.union(newField))\n\n        let clp3 = clp2.removeProtectedFieldsRequiresAuthentication(newField)\n        XCTAssertEqual(clp3.getProtectedFieldsRequiresAuthentication(), fields)\n\n        let clp4 = ParseCLP().addProtectedFieldsRequiresAuthentication(newField)\n        XCTAssertEqual(clp4.getProtectedFieldsRequiresAuthentication(), newField)\n    }\n\n    func testProtectedFieldsUserField() throws {\n        let fields = Set<String>([\"hello\", \"world\"])\n        let userField = \"peace\"\n        let clp = ParseCLP().setProtectedFields(fields, userField: userField)\n        XCTAssertEqual(clp.getProtectedFieldsUser(userField), fields)\n\n        let newField = Set<String>([\"new\"])\n        let clp2 = clp.addProtectedFieldsUser(newField, userField: userField)\n        XCTAssertEqual(clp2.getProtectedFieldsUser(userField), fields.union(newField))\n\n        let clp3 = clp2.removeProtectedFieldsUser(newField, userField: userField)\n        XCTAssertEqual(clp3.getProtectedFieldsUser(userField), fields)\n\n        let clp4 = ParseCLP().addProtectedFieldsUser(newField, userField: userField)\n        XCTAssertEqual(clp4.getProtectedFieldsUser(userField), newField)\n    }\n\n    func testProtectedFieldsObjectId() throws {\n        let fields = Set<String>([\"hello\", \"world\"])\n        let clp = ParseCLP().setProtectedFields(fields, for: objectId)\n        XCTAssertEqual(clp.getProtectedFields(objectId), fields)\n\n        let newField = Set<String>([\"new\"])\n        let clp2 = clp.addProtectedFields(newField, for: objectId)\n        XCTAssertEqual(clp2.getProtectedFields(objectId), fields.union(newField))\n\n        let clp3 = clp2.removeProtectedFields(newField, for: objectId)\n        XCTAssertEqual(clp3.getProtectedFields(objectId), fields)\n\n        let clp4 = ParseCLP().addProtectedFields(newField, for: objectId)\n        XCTAssertEqual(clp4.getProtectedFields(objectId), newField)\n    }\n\n    func testProtectedFieldsUser() throws {\n        let fields = Set<String>([\"hello\", \"world\"])\n        let clp = try ParseCLP().setProtectedFields(fields, for: user)\n        XCTAssertEqual(try clp.getProtectedFields(user), fields)\n\n        let newField = Set<String>([\"new\"])\n        let clp2 = try clp.addProtectedFields(newField, for: user)\n        XCTAssertEqual(try clp2.getProtectedFields(user), fields.union(newField))\n\n        let clp3 = try clp2.removeProtectedFields(newField, for: user)\n        XCTAssertEqual(try clp3.getProtectedFields(user), fields)\n\n        let clp4 = try ParseCLP().addProtectedFields(newField, for: user)\n        XCTAssertEqual(try clp4.getProtectedFields(user), newField)\n    }\n\n    func testProtectedFieldsPointer() throws {\n        let pointer = try user.toPointer()\n        let fields = Set<String>([\"hello\", \"world\"])\n        let clp = ParseCLP().setProtectedFields(fields, for: pointer)\n        XCTAssertEqual(clp.getProtectedFields(pointer), fields)\n\n        let newField = Set<String>([\"new\"])\n        let clp2 = clp.addProtectedFields(newField, for: pointer)\n        XCTAssertEqual(clp2.getProtectedFields(pointer), fields.union(newField))\n\n        let clp3 = clp2.removeProtectedFields(newField, for: pointer)\n        XCTAssertEqual(clp3.getProtectedFields(pointer), fields)\n\n        let clp4 = ParseCLP().addProtectedFields(newField, for: pointer)\n        XCTAssertEqual(clp4.getProtectedFields(pointer), newField)\n    }\n\n    func testProtectedFieldsRole() throws {\n        let role = try Role<User>(name: \"hello\")\n        let fields = Set<String>([\"hello\", \"world\"])\n        let clp = try ParseCLP().setProtectedFields(fields, for: role)\n        XCTAssertEqual(try clp.getProtectedFields(role), fields)\n\n        let newField = Set<String>([\"new\"])\n        let clp2 = try clp.addProtectedFields(newField, for: role)\n        XCTAssertEqual(try clp2.getProtectedFields(role), fields.union(newField))\n\n        let clp3 = try clp2.removeProtectedFields(newField, for: role)\n        XCTAssertEqual(try clp3.getProtectedFields(role), fields)\n\n        let clp4 = try ParseCLP().addProtectedFields(newField, for: role)\n        XCTAssertEqual(try clp4.getProtectedFields(role), newField)\n    }\n\n    func testProtectedFieldsEncode() throws {\n        let role = try Role<User>(name: \"hello\")\n        let fields = Set<String>([\"world\"])\n        let clp = try ParseCLP().setProtectedFields(fields, for: role)\n        XCTAssertEqual(clp.description, \"{\\\"protectedFields\\\":{\\\"role:hello\\\":[\\\"world\\\"]}}\")\n    }\n\n    func testPublicAccess() throws {\n        let clp = ParseCLP().setAccessPublic(true, on: .create)\n        XCTAssertTrue(clp.hasAccessPublic(.create))\n\n        let clp2 = clp.setAccessPublic(false, on: .create)\n        XCTAssertFalse(clp2.hasAccessPublic(.create))\n    }\n\n    func testRequiresAuthenticationAccess() throws {\n        let clp = ParseCLP().setAccessRequiresAuthentication(true, on: .create)\n        XCTAssertTrue(clp.hasAccessRequiresAuthentication(.create))\n\n        let clp2 = clp.setAccessRequiresAuthentication(false, on: .create)\n        XCTAssertFalse(clp2.hasAccessRequiresAuthentication(.create))\n    }\n\n    func testAccessUser() throws {\n        let clp = try ParseCLP().setAccess(true, on: .create, for: user)\n        XCTAssertTrue(try clp.hasAccess(.create, for: user))\n\n        let clp2 = try clp.setAccess(false, on: .create, for: user)\n        XCTAssertFalse(try clp2.hasAccess(.create, for: user))\n    }\n\n    func testAccessPointer() throws {\n        let user = try user.toPointer()\n        let clp = ParseCLP().setAccess(true, on: .create, for: user)\n        XCTAssertTrue(clp.hasAccess(.create, for: user))\n\n        let clp2 = clp.setAccess(false, on: .create, for: user)\n        XCTAssertFalse(clp2.hasAccess(.create, for: user))\n    }\n\n    func testAccessRole() throws {\n        let role = try Role<User>(name: \"hello\")\n        let clp = try ParseCLP().setAccess(true, on: .create, for: role)\n        XCTAssertTrue(try clp.hasAccess(.create, for: role))\n\n        let clp2 = try clp.setAccess(false, on: .create, for: role)\n        XCTAssertFalse(try clp2.hasAccess(.create, for: user))\n    }\n\n    func testAccessEncode() throws {\n        let clp = ParseCLP().setAccess(true, on: .create, for: objectId)\n        XCTAssertEqual(clp.description, \"{\\\"create\\\":{\\\"\\(objectId)\\\":true}}\")\n    }\n\n    func testWriteAccessPublicSet() throws {\n        let clp = ParseCLP().setWriteAccessPublic(true)\n        XCTAssertNil(clp.get?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp.find?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertEqual(clp.create?[ParseCLP.Access.publicScope.rawValue], true)\n        XCTAssertEqual(clp.update?[ParseCLP.Access.publicScope.rawValue], true)\n        XCTAssertEqual(clp.delete?[ParseCLP.Access.publicScope.rawValue], true)\n        XCTAssertNil(clp.count?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp.addField?[ParseCLP.Access.publicScope.rawValue])\n\n        let clp2 = ParseCLP().setWriteAccessPublic(true, canAddField: true)\n        XCTAssertNil(clp2.get?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp2.find?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertEqual(clp2.create?[ParseCLP.Access.publicScope.rawValue], true)\n        XCTAssertEqual(clp2.update?[ParseCLP.Access.publicScope.rawValue], true)\n        XCTAssertEqual(clp2.delete?[ParseCLP.Access.publicScope.rawValue], true)\n        XCTAssertNil(clp2.count?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertEqual(clp2.addField?[ParseCLP.Access.publicScope.rawValue], true)\n\n        let clp3 = clp.setWriteAccessPublic(false)\n        XCTAssertNil(clp3.get?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp3.find?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp3.create?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp3.update?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp3.delete?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp3.count?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp3.addField?[ParseCLP.Access.publicScope.rawValue])\n\n        let clp4 = clp2.setWriteAccessPublic(false)\n        XCTAssertNil(clp4.get?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp4.find?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp4.create?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp4.update?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp4.delete?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp4.count?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp4.addField?[ParseCLP.Access.publicScope.rawValue])\n    }\n\n    func testWriteAccessPublicSetEncode() throws {\n        let clp = ParseCLP().setWriteAccessPublic(true, canAddField: true)\n        // swiftlint:disable:next line_length\n        XCTAssertEqual(clp.description, \"{\\\"addField\\\":{\\\"*\\\":true},\\\"create\\\":{\\\"*\\\":true},\\\"delete\\\":{\\\"*\\\":true},\\\"update\\\":{\\\"*\\\":true}}\")\n    }\n\n    func testWriteAccessRequiresAuthenticationSet() throws {\n        let clp = ParseCLP().setWriteAccessRequiresAuthentication(true)\n        XCTAssertNil(clp.get?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp.find?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertEqual(clp.create?[ParseCLP.Access.requiresAuthentication.rawValue], true)\n        XCTAssertEqual(clp.update?[ParseCLP.Access.requiresAuthentication.rawValue], true)\n        XCTAssertEqual(clp.delete?[ParseCLP.Access.requiresAuthentication.rawValue], true)\n        XCTAssertNil(clp.count?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp.addField?[ParseCLP.Access.requiresAuthentication.rawValue])\n\n        let clp2 = ParseCLP().setWriteAccessRequiresAuthentication(true, canAddField: true)\n        XCTAssertNil(clp2.get?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp2.find?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertEqual(clp2.create?[ParseCLP.Access.requiresAuthentication.rawValue], true)\n        XCTAssertEqual(clp2.update?[ParseCLP.Access.requiresAuthentication.rawValue], true)\n        XCTAssertEqual(clp2.delete?[ParseCLP.Access.requiresAuthentication.rawValue], true)\n        XCTAssertNil(clp2.count?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertEqual(clp2.addField?[ParseCLP.Access.requiresAuthentication.rawValue], true)\n\n        let clp3 = clp.setWriteAccessRequiresAuthentication(false)\n        XCTAssertNil(clp3.get?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp3.find?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp3.create?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp3.update?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp3.delete?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp3.count?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp3.addField?[ParseCLP.Access.requiresAuthentication.rawValue])\n\n        let clp4 = clp2.setWriteAccessRequiresAuthentication(false)\n        XCTAssertNil(clp4.get?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp4.find?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp4.create?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp4.update?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp4.delete?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp4.count?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp4.addField?[ParseCLP.Access.requiresAuthentication.rawValue])\n    }\n\n    func testWriteAccessRequiresAuthenticationSetEncode() throws {\n        let clp = ParseCLP().setWriteAccessRequiresAuthentication(true, canAddField: true)\n        // swiftlint:disable:next line_length\n        XCTAssertEqual(clp.description, \"{\\\"addField\\\":{\\\"requiresAuthentication\\\":true},\\\"create\\\":{\\\"requiresAuthentication\\\":true},\\\"delete\\\":{\\\"requiresAuthentication\\\":true},\\\"update\\\":{\\\"requiresAuthentication\\\":true}}\")\n    }\n\n    func testWriteAccessObjectIdSet() throws {\n        let clp = ParseCLP().setWriteAccess(true, for: objectId)\n        XCTAssertNil(clp.get?[objectId])\n        XCTAssertNil(clp.find?[objectId])\n        XCTAssertEqual(clp.create?[objectId], true)\n        XCTAssertEqual(clp.update?[objectId], true)\n        XCTAssertEqual(clp.delete?[objectId], true)\n        XCTAssertNil(clp.count?[objectId])\n        XCTAssertNil(clp.addField?[objectId])\n\n        let clp2 = ParseCLP().setWriteAccess(true, for: objectId, canAddField: true)\n        XCTAssertNil(clp2.get?[objectId])\n        XCTAssertNil(clp2.find?[objectId])\n        XCTAssertEqual(clp2.create?[objectId], true)\n        XCTAssertEqual(clp2.update?[objectId], true)\n        XCTAssertEqual(clp2.delete?[objectId], true)\n        XCTAssertNil(clp2.count?[objectId])\n        XCTAssertEqual(clp2.addField?[objectId], true)\n\n        let clp3 = clp.setWriteAccess(false, for: objectId)\n        XCTAssertNil(clp3.get?[objectId])\n        XCTAssertNil(clp3.find?[objectId])\n        XCTAssertNil(clp3.create?[objectId])\n        XCTAssertNil(clp3.update?[objectId])\n        XCTAssertNil(clp3.delete?[objectId])\n        XCTAssertNil(clp3.count?[objectId])\n        XCTAssertNil(clp3.addField?[objectId])\n\n        let clp4 = clp2.setWriteAccess(false, for: objectId)\n        XCTAssertNil(clp4.get?[objectId])\n        XCTAssertNil(clp4.find?[objectId])\n        XCTAssertNil(clp4.create?[objectId])\n        XCTAssertNil(clp4.update?[objectId])\n        XCTAssertNil(clp4.delete?[objectId])\n        XCTAssertNil(clp4.count?[objectId])\n        XCTAssertNil(clp4.addField?[objectId])\n    }\n\n    func testWriteAccessObjectIdSetEncode() throws {\n        let clp = ParseCLP().setWriteAccess(true, for: objectId, canAddField: true)\n        // swiftlint:disable:next line_length\n        XCTAssertEqual(clp.description, \"{\\\"addField\\\":{\\\"\\(objectId)\\\":true},\\\"create\\\":{\\\"\\(objectId)\\\":true},\\\"delete\\\":{\\\"\\(objectId)\\\":true},\\\"update\\\":{\\\"\\(objectId)\\\":true}}\")\n    }\n\n    func testWriteAccessUserSet() throws {\n        let clp = try ParseCLP().setWriteAccess(true, for: user)\n        XCTAssertNil(clp.get?[objectId])\n        XCTAssertNil(clp.find?[objectId])\n        XCTAssertEqual(clp.create?[objectId], true)\n        XCTAssertEqual(clp.update?[objectId], true)\n        XCTAssertEqual(clp.delete?[objectId], true)\n        XCTAssertNil(clp.count?[objectId])\n        XCTAssertNil(clp.addField?[objectId])\n\n        let clp2 = try ParseCLP().setWriteAccess(true, for: user, canAddField: true)\n        XCTAssertNil(clp2.get?[objectId])\n        XCTAssertNil(clp2.find?[objectId])\n        XCTAssertEqual(clp2.create?[objectId], true)\n        XCTAssertEqual(clp2.update?[objectId], true)\n        XCTAssertEqual(clp2.delete?[objectId], true)\n        XCTAssertNil(clp2.count?[objectId])\n        XCTAssertEqual(clp2.addField?[objectId], true)\n\n        let clp3 = try clp.setWriteAccess(false, for: user)\n        XCTAssertNil(clp3.get?[objectId])\n        XCTAssertNil(clp3.find?[objectId])\n        XCTAssertNil(clp3.create?[objectId])\n        XCTAssertNil(clp3.update?[objectId])\n        XCTAssertNil(clp3.delete?[objectId])\n        XCTAssertNil(clp3.count?[objectId])\n        XCTAssertNil(clp3.addField?[objectId])\n\n        let clp4 = try clp2.setWriteAccess(false, for: user)\n        XCTAssertNil(clp4.get?[objectId])\n        XCTAssertNil(clp4.find?[objectId])\n        XCTAssertNil(clp4.create?[objectId])\n        XCTAssertNil(clp4.update?[objectId])\n        XCTAssertNil(clp4.delete?[objectId])\n        XCTAssertNil(clp4.count?[objectId])\n        XCTAssertNil(clp4.addField?[objectId])\n    }\n\n    func testWriteAccessUserSetEncode() throws {\n        let clp = try ParseCLP().setWriteAccess(true, for: user, canAddField: true)\n        // swiftlint:disable:next line_length\n        XCTAssertEqual(clp.description, \"{\\\"addField\\\":{\\\"\\(objectId)\\\":true},\\\"create\\\":{\\\"\\(objectId)\\\":true},\\\"delete\\\":{\\\"\\(objectId)\\\":true},\\\"update\\\":{\\\"\\(objectId)\\\":true}}\")\n    }\n\n    func testWriteAccessPointerSet() throws {\n        let clp = ParseCLP().setWriteAccess(true, for: try user.toPointer())\n        XCTAssertNil(clp.get?[objectId])\n        XCTAssertNil(clp.find?[objectId])\n        XCTAssertEqual(clp.create?[objectId], true)\n        XCTAssertEqual(clp.update?[objectId], true)\n        XCTAssertEqual(clp.delete?[objectId], true)\n        XCTAssertNil(clp.count?[objectId])\n        XCTAssertNil(clp.addField?[objectId])\n\n        let clp2 = ParseCLP().setWriteAccess(true,\n                                             for: try user.toPointer(),\n                                             canAddField: true)\n        XCTAssertNil(clp2.get?[objectId])\n        XCTAssertNil(clp2.find?[objectId])\n        XCTAssertEqual(clp2.create?[objectId], true)\n        XCTAssertEqual(clp2.update?[objectId], true)\n        XCTAssertEqual(clp2.delete?[objectId], true)\n        XCTAssertNil(clp2.count?[objectId])\n        XCTAssertEqual(clp2.addField?[objectId], true)\n\n        let clp3 = clp.setWriteAccess(false, for: try user.toPointer())\n        XCTAssertNil(clp3.get?[objectId])\n        XCTAssertNil(clp3.find?[objectId])\n        XCTAssertNil(clp3.create?[objectId])\n        XCTAssertNil(clp3.update?[objectId])\n        XCTAssertNil(clp3.delete?[objectId])\n        XCTAssertNil(clp3.count?[objectId])\n        XCTAssertNil(clp3.addField?[objectId])\n\n        let clp4 = clp2.setWriteAccess(false, for: try user.toPointer())\n        XCTAssertNil(clp4.get?[objectId])\n        XCTAssertNil(clp4.find?[objectId])\n        XCTAssertNil(clp4.create?[objectId])\n        XCTAssertNil(clp4.update?[objectId])\n        XCTAssertNil(clp4.delete?[objectId])\n        XCTAssertNil(clp4.count?[objectId])\n        XCTAssertNil(clp4.addField?[objectId])\n    }\n\n    func testWriteAccessPointerSetEncode() throws {\n        let clp = ParseCLP().setWriteAccess(true,\n                                            for: try user.toPointer(),\n                                            canAddField: true)\n        // swiftlint:disable:next line_length\n        XCTAssertEqual(clp.description, \"{\\\"addField\\\":{\\\"\\(objectId)\\\":true},\\\"create\\\":{\\\"\\(objectId)\\\":true},\\\"delete\\\":{\\\"\\(objectId)\\\":true},\\\"update\\\":{\\\"\\(objectId)\\\":true}}\")\n    }\n\n    func testWriteAccessRoleSet() throws {\n        let name = \"hello\"\n        let role = try Role<User>(name: name)\n        let roleName = try ParseACL.getRoleAccessName(role)\n        let clp = try ParseCLP().setWriteAccess(true, for: role)\n        XCTAssertNil(clp.get?[roleName])\n        XCTAssertNil(clp.find?[roleName])\n        XCTAssertEqual(clp.create?[roleName], true)\n        XCTAssertEqual(clp.update?[roleName], true)\n        XCTAssertEqual(clp.delete?[roleName], true)\n        XCTAssertNil(clp.count?[roleName])\n        XCTAssertNil(clp.addField?[roleName])\n\n        let clp2 = try ParseCLP().setWriteAccess(true,\n                                                 for: role,\n                                                 canAddField: true)\n        XCTAssertNil(clp2.get?[roleName])\n        XCTAssertNil(clp2.find?[roleName])\n        XCTAssertEqual(clp2.create?[roleName], true)\n        XCTAssertEqual(clp2.update?[roleName], true)\n        XCTAssertEqual(clp2.delete?[roleName], true)\n        XCTAssertNil(clp2.count?[roleName])\n        XCTAssertEqual(clp2.addField?[roleName], true)\n\n        let clp3 = try clp.setWriteAccess(false, for: role)\n        XCTAssertNil(clp3.get?[roleName])\n        XCTAssertNil(clp3.find?[roleName])\n        XCTAssertNil(clp3.create?[roleName])\n        XCTAssertNil(clp3.update?[roleName])\n        XCTAssertNil(clp3.delete?[roleName])\n        XCTAssertNil(clp3.count?[roleName])\n        XCTAssertNil(clp3.addField?[roleName])\n\n        let clp4 = try clp2.setWriteAccess(false, for: role)\n        XCTAssertNil(clp4.get?[roleName])\n        XCTAssertNil(clp4.find?[roleName])\n        XCTAssertNil(clp4.create?[roleName])\n        XCTAssertNil(clp4.update?[roleName])\n        XCTAssertNil(clp4.delete?[roleName])\n        XCTAssertNil(clp4.count?[roleName])\n        XCTAssertNil(clp4.addField?[roleName])\n    }\n\n    func testWriteAccessRoleSetEncode() throws {\n        let name = \"hello\"\n        let role = try Role<User>(name: name)\n        let roleName = try ParseACL.getRoleAccessName(role)\n        let clp = try ParseCLP().setWriteAccess(true,\n                                                for: role,\n                                                canAddField: true)\n        // swiftlint:disable:next line_length\n        XCTAssertEqual(clp.description, \"{\\\"addField\\\":{\\\"\\(roleName)\\\":true},\\\"create\\\":{\\\"\\(roleName)\\\":true},\\\"delete\\\":{\\\"\\(roleName)\\\":true},\\\"update\\\":{\\\"\\(roleName)\\\":true}}\")\n    }\n\n    func testWriteAccessPublicHas() throws {\n        let clp = ParseCLP().setWriteAccessPublic(true)\n        XCTAssertTrue(clp.hasWriteAccessPublic())\n        XCTAssertFalse(clp.hasWriteAccessRequiresAuthentication())\n\n        let clp2 = ParseCLP().setWriteAccessPublic(false)\n        XCTAssertFalse(clp2.hasWriteAccessPublic())\n        XCTAssertFalse(clp2.hasWriteAccessRequiresAuthentication())\n\n        let clp3 = clp.setWriteAccessPublic(false)\n        XCTAssertFalse(clp3.hasWriteAccessPublic())\n        XCTAssertFalse(clp3.hasWriteAccessRequiresAuthentication())\n    }\n\n    func testWriteAccessRequiresAuthenticationHas() throws {\n        let clp = ParseCLP().setWriteAccessRequiresAuthentication(true)\n        XCTAssertTrue(clp.hasWriteAccessRequiresAuthentication())\n        XCTAssertFalse(clp.hasWriteAccessPublic())\n\n        let clp2 = ParseCLP().setWriteAccessRequiresAuthentication(false)\n        XCTAssertFalse(clp2.hasWriteAccessRequiresAuthentication())\n        XCTAssertFalse(clp2.hasWriteAccessPublic())\n\n        let clp3 = clp.setWriteAccessRequiresAuthentication(false)\n        XCTAssertFalse(clp3.hasWriteAccessRequiresAuthentication())\n        XCTAssertFalse(clp3.hasWriteAccessPublic())\n    }\n\n    func testWriteAccessObjectIdHas() throws {\n        let clp = ParseCLP().setWriteAccess(true, for: objectId)\n        XCTAssertFalse(clp.hasReadAccess(objectId))\n        XCTAssertTrue(clp.hasWriteAccess(objectId))\n        XCTAssertFalse(clp.hasWriteAccess(objectId, check: true))\n\n        let clp2 = ParseCLP().setWriteAccess(false, for: objectId)\n        XCTAssertFalse(clp2.hasReadAccess(objectId))\n        XCTAssertFalse(clp2.hasWriteAccess(objectId))\n\n        let clp3 = clp.setWriteAccess(false, for: objectId)\n        XCTAssertFalse(clp3.hasReadAccess(objectId))\n        XCTAssertFalse(clp3.hasWriteAccess(objectId))\n\n        let clp4 = ParseCLP().setWriteAccess(true, for: objectId, canAddField: true)\n        XCTAssertFalse(clp4.hasReadAccess(objectId))\n        XCTAssertTrue(clp4.hasWriteAccess(objectId, check: true))\n    }\n\n    func testWriteAccessUserHas() throws {\n        let clp = try ParseCLP().setWriteAccess(true, for: user)\n        XCTAssertFalse(try clp.hasReadAccess(user))\n        XCTAssertTrue(try clp.hasWriteAccess(user))\n        XCTAssertFalse(try clp.hasWriteAccess(user, checkAddField: true))\n\n        let clp2 = try ParseCLP().setWriteAccess(false, for: user)\n        XCTAssertFalse(try clp2.hasReadAccess(user))\n        XCTAssertFalse(try clp2.hasWriteAccess(user))\n\n        let clp3 = try clp.setWriteAccess(false, for: user)\n        XCTAssertFalse(try clp3.hasReadAccess(user))\n        XCTAssertFalse(try clp3.hasWriteAccess(user))\n\n        let clp4 = try ParseCLP().setWriteAccess(true, for: user, canAddField: true)\n        XCTAssertFalse(try clp4.hasReadAccess(user))\n        XCTAssertTrue(try clp4.hasWriteAccess(user, checkAddField: true))\n    }\n\n    func testWriteAccessPointerHas() throws {\n        let clp = ParseCLP().setWriteAccess(true, for: try user.toPointer())\n        XCTAssertFalse(clp.hasReadAccess(try user.toPointer()))\n        XCTAssertTrue(clp.hasWriteAccess(try user.toPointer()))\n        XCTAssertFalse(clp.hasWriteAccess(try user.toPointer(), checkAddField: true))\n\n        let clp2 = ParseCLP().setWriteAccess(false, for: try user.toPointer())\n        XCTAssertFalse(clp2.hasReadAccess(try user.toPointer()))\n        XCTAssertFalse(clp2.hasWriteAccess(try user.toPointer()))\n\n        let clp3 = clp.setWriteAccess(false, for: try user.toPointer())\n        XCTAssertFalse(clp3.hasReadAccess(try user.toPointer()))\n        XCTAssertFalse(clp3.hasWriteAccess(try user.toPointer()))\n\n        let clp4 = ParseCLP().setWriteAccess(true, for: try user.toPointer(), canAddField: true)\n        XCTAssertFalse(clp4.hasReadAccess(try user.toPointer()))\n        XCTAssertTrue(clp4.hasWriteAccess(try user.toPointer(), checkAddField: true))\n    }\n\n    func testWriteAccessRoleHas() throws {\n        let name = \"hello\"\n        let role = try Role<User>(name: name)\n        let clp = try ParseCLP().setWriteAccess(true, for: role)\n        XCTAssertFalse(try clp.hasReadAccess(role))\n        XCTAssertTrue(try clp.hasWriteAccess(role))\n        XCTAssertFalse(try clp.hasWriteAccess(role, checkAddField: true))\n\n        let clp2 = try ParseCLP().setWriteAccess(false, for: role)\n        XCTAssertFalse(try clp2.hasReadAccess(role))\n        XCTAssertFalse(try clp2.hasWriteAccess(role))\n\n        let clp3 = try clp.setWriteAccess(false, for: role)\n        XCTAssertFalse(try clp3.hasReadAccess(role))\n        XCTAssertFalse(try clp3.hasWriteAccess(role))\n\n        let clp4 = try ParseCLP().setWriteAccess(true, for: role, canAddField: true)\n        XCTAssertFalse(try clp4.hasReadAccess(role))\n        XCTAssertTrue(try clp4.hasWriteAccess(role, checkAddField: true))\n    }\n\n    func testReadAccessPublicSet() throws {\n        let clp = ParseCLP().setReadAccessPublic(true)\n        XCTAssertEqual(clp.get?[ParseCLP.Access.publicScope.rawValue], true)\n        XCTAssertEqual(clp.find?[ParseCLP.Access.publicScope.rawValue], true)\n        XCTAssertNil(clp.create?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp.update?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp.delete?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertEqual(clp.count?[ParseCLP.Access.publicScope.rawValue], true)\n        XCTAssertNil(clp.addField?[ParseCLP.Access.publicScope.rawValue])\n\n        let clp2 = ParseCLP().setReadAccessPublic(false)\n        XCTAssertNil(clp2.get?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp2.find?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp2.create?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp2.update?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp2.delete?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp2.count?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp2.addField?[ParseCLP.Access.publicScope.rawValue])\n\n        let clp3 = clp.setReadAccessPublic(false)\n        XCTAssertNil(clp3.get?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp3.find?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp3.create?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp3.update?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp3.delete?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp3.count?[ParseCLP.Access.publicScope.rawValue])\n        XCTAssertNil(clp3.addField?[ParseCLP.Access.publicScope.rawValue])\n    }\n\n    func testReadAccessPublicSetEncode() throws {\n        let clp = ParseCLP().setReadAccessPublic(true)\n        XCTAssertEqual(clp.description,\n                       \"{\\\"count\\\":{\\\"*\\\":true},\\\"find\\\":{\\\"*\\\":true},\\\"get\\\":{\\\"*\\\":true}}\")\n    }\n\n    func testReadAccessRequiresAuthenticationSet() throws {\n        let clp = ParseCLP().setReadAccessRequiresAuthentication(true)\n        XCTAssertEqual(clp.get?[ParseCLP.Access.requiresAuthentication.rawValue], true)\n        XCTAssertEqual(clp.find?[ParseCLP.Access.requiresAuthentication.rawValue], true)\n        XCTAssertNil(clp.create?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp.update?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp.delete?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertEqual(clp.count?[ParseCLP.Access.requiresAuthentication.rawValue], true)\n        XCTAssertNil(clp.addField?[ParseCLP.Access.requiresAuthentication.rawValue])\n\n        let clp2 = ParseCLP().setReadAccessRequiresAuthentication(false)\n        XCTAssertNil(clp2.get?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp2.find?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp2.create?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp2.update?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp2.delete?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp2.count?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp2.addField?[ParseCLP.Access.requiresAuthentication.rawValue])\n\n        let clp3 = clp.setReadAccessRequiresAuthentication(false)\n        XCTAssertNil(clp3.get?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp3.find?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp3.create?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp3.update?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp3.delete?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp3.count?[ParseCLP.Access.requiresAuthentication.rawValue])\n        XCTAssertNil(clp3.addField?[ParseCLP.Access.requiresAuthentication.rawValue])\n    }\n\n    func testReadAccessRequiresAuthenticationSetEncode() throws {\n        let clp = ParseCLP().setReadAccessRequiresAuthentication(true)\n        // swiftlint:disable:next line_length\n        XCTAssertEqual(clp.description, \"{\\\"count\\\":{\\\"requiresAuthentication\\\":true},\\\"find\\\":{\\\"requiresAuthentication\\\":true},\\\"get\\\":{\\\"requiresAuthentication\\\":true}}\")\n    }\n\n    func testReadAccessObjectIdSet() throws {\n        let clp = ParseCLP().setReadAccess(true, for: objectId)\n        XCTAssertEqual(clp.get?[objectId], true)\n        XCTAssertEqual(clp.find?[objectId], true)\n        XCTAssertNil(clp.create?[objectId])\n        XCTAssertNil(clp.update?[objectId])\n        XCTAssertNil(clp.delete?[objectId])\n        XCTAssertEqual(clp.count?[objectId], true)\n        XCTAssertNil(clp.addField?[objectId])\n\n        let clp2 = ParseCLP().setReadAccess(false, for: objectId)\n        XCTAssertNil(clp2.get?[objectId])\n        XCTAssertNil(clp2.find?[objectId])\n        XCTAssertNil(clp2.create?[objectId])\n        XCTAssertNil(clp2.update?[objectId])\n        XCTAssertNil(clp2.delete?[objectId])\n        XCTAssertNil(clp2.count?[objectId])\n        XCTAssertNil(clp2.addField?[objectId])\n\n        let clp3 = clp.setReadAccess(false, for: objectId)\n        XCTAssertNil(clp3.get?[objectId])\n        XCTAssertNil(clp3.find?[objectId])\n        XCTAssertNil(clp3.create?[objectId])\n        XCTAssertNil(clp3.update?[objectId])\n        XCTAssertNil(clp3.delete?[objectId])\n        XCTAssertNil(clp3.count?[objectId])\n        XCTAssertNil(clp3.addField?[objectId])\n    }\n\n    func testReadAccessObjectIdSetEncode() throws {\n        let clp = ParseCLP().setReadAccess(true, for: objectId)\n        // swiftlint:disable:next line_length\n        XCTAssertEqual(clp.description, \"{\\\"count\\\":{\\\"\\(objectId)\\\":true},\\\"find\\\":{\\\"\\(objectId)\\\":true},\\\"get\\\":{\\\"\\(objectId)\\\":true}}\")\n    }\n\n    func testReadAccessUserSet() throws {\n        let clp = try ParseCLP().setReadAccess(true, for: user)\n        XCTAssertEqual(clp.get?[objectId], true)\n        XCTAssertEqual(clp.find?[objectId], true)\n        XCTAssertNil(clp.create?[objectId])\n        XCTAssertNil(clp.update?[objectId])\n        XCTAssertNil(clp.delete?[objectId])\n        XCTAssertEqual(clp.count?[objectId], true)\n        XCTAssertNil(clp.addField?[objectId])\n\n        let clp2 = try ParseCLP().setReadAccess(false, for: user)\n        XCTAssertNil(clp2.get?[objectId])\n        XCTAssertNil(clp2.find?[objectId])\n        XCTAssertNil(clp2.create?[objectId])\n        XCTAssertNil(clp2.update?[objectId])\n        XCTAssertNil(clp2.delete?[objectId])\n        XCTAssertNil(clp2.count?[objectId])\n        XCTAssertNil(clp2.addField?[objectId])\n\n        let clp3 = try clp.setReadAccess(false, for: user)\n        XCTAssertNil(clp3.get?[objectId])\n        XCTAssertNil(clp3.find?[objectId])\n        XCTAssertNil(clp3.create?[objectId])\n        XCTAssertNil(clp3.update?[objectId])\n        XCTAssertNil(clp3.delete?[objectId])\n        XCTAssertNil(clp3.count?[objectId])\n        XCTAssertNil(clp3.addField?[objectId])\n    }\n\n    func testReadAccessUserSetEncode() throws {\n        let clp = try ParseCLP().setReadAccess(true, for: user)\n        // swiftlint:disable:next line_length\n        XCTAssertEqual(clp.description, \"{\\\"count\\\":{\\\"\\(objectId)\\\":true},\\\"find\\\":{\\\"\\(objectId)\\\":true},\\\"get\\\":{\\\"\\(objectId)\\\":true}}\")\n    }\n\n    func testReadAccessPointerSet() throws {\n        let clp = ParseCLP().setReadAccess(true, for: try user.toPointer())\n        XCTAssertEqual(clp.get?[objectId], true)\n        XCTAssertEqual(clp.find?[objectId], true)\n        XCTAssertNil(clp.create?[objectId])\n        XCTAssertNil(clp.update?[objectId])\n        XCTAssertNil(clp.delete?[objectId])\n        XCTAssertEqual(clp.count?[objectId], true)\n        XCTAssertNil(clp.addField?[objectId])\n\n        let clp2 = ParseCLP().setReadAccess(false, for: try user.toPointer())\n        XCTAssertNil(clp2.get?[objectId])\n        XCTAssertNil(clp2.find?[objectId])\n        XCTAssertNil(clp2.create?[objectId])\n        XCTAssertNil(clp2.update?[objectId])\n        XCTAssertNil(clp2.delete?[objectId])\n        XCTAssertNil(clp2.count?[objectId])\n        XCTAssertNil(clp2.addField?[objectId])\n\n        let clp3 = clp.setReadAccess(false, for: try user.toPointer())\n        XCTAssertNil(clp3.get?[objectId])\n        XCTAssertNil(clp3.find?[objectId])\n        XCTAssertNil(clp3.create?[objectId])\n        XCTAssertNil(clp3.update?[objectId])\n        XCTAssertNil(clp3.delete?[objectId])\n        XCTAssertNil(clp3.count?[objectId])\n        XCTAssertNil(clp3.addField?[objectId])\n    }\n\n    func testReadAccessPointerSetEncode() throws {\n        let clp = ParseCLP().setReadAccess(true,\n                                           for: try user.toPointer())\n        // swiftlint:disable:next line_length\n        XCTAssertEqual(clp.description, \"{\\\"count\\\":{\\\"\\(objectId)\\\":true},\\\"find\\\":{\\\"\\(objectId)\\\":true},\\\"get\\\":{\\\"\\(objectId)\\\":true}}\")\n    }\n\n    func testReadAccessRoleSet() throws {\n        let name = \"hello\"\n        let role = try Role<User>(name: name)\n        let roleName = try ParseACL.getRoleAccessName(role)\n        let clp = try ParseCLP().setReadAccess(true, for: role)\n        XCTAssertEqual(clp.get?[roleName], true)\n        XCTAssertEqual(clp.find?[roleName], true)\n        XCTAssertNil(clp.create?[roleName])\n        XCTAssertNil(clp.update?[roleName])\n        XCTAssertNil(clp.delete?[roleName])\n        XCTAssertEqual(clp.count?[roleName], true)\n        XCTAssertNil(clp.addField?[roleName])\n\n        let clp2 = try ParseCLP().setReadAccess(false, for: role)\n        XCTAssertNil(clp2.get?[roleName])\n        XCTAssertNil(clp2.find?[roleName])\n        XCTAssertNil(clp2.create?[roleName])\n        XCTAssertNil(clp2.update?[roleName])\n        XCTAssertNil(clp2.delete?[roleName])\n        XCTAssertNil(clp2.count?[roleName])\n        XCTAssertNil(clp2.addField?[roleName])\n\n        let clp3 = try clp.setReadAccess(false, for: role)\n        XCTAssertNil(clp3.get?[roleName])\n        XCTAssertNil(clp3.find?[roleName])\n        XCTAssertNil(clp3.create?[roleName])\n        XCTAssertNil(clp3.update?[roleName])\n        XCTAssertNil(clp3.delete?[roleName])\n        XCTAssertNil(clp3.count?[roleName])\n        XCTAssertNil(clp3.addField?[roleName])\n    }\n\n    func testReadAccessRoleSetEncode() throws {\n        let name = \"hello\"\n        let role = try Role<User>(name: name)\n        let roleName = try ParseACL.getRoleAccessName(role)\n        let clp = try ParseCLP().setReadAccess(true,\n                                               for: role)\n        XCTAssertEqual(clp.description,\n                       // swiftlint:disable:next line_length\n                       \"{\\\"count\\\":{\\\"\\(roleName)\\\":true},\\\"find\\\":{\\\"\\(roleName)\\\":true},\\\"get\\\":{\\\"\\(roleName)\\\":true}}\")\n    }\n\n    func testReadAccessPublicHas() throws {\n        let clp = ParseCLP().setReadAccessPublic(true)\n        XCTAssertTrue(clp.hasReadAccessPublic())\n        XCTAssertFalse(clp.hasReadAccessRequiresAuthentication())\n\n        let clp2 = ParseCLP().setReadAccessPublic(false)\n        XCTAssertFalse(clp2.hasReadAccessPublic())\n        XCTAssertFalse(clp2.hasReadAccessRequiresAuthentication())\n\n        let clp3 = clp.setReadAccessPublic(false)\n        XCTAssertFalse(clp3.hasReadAccessPublic())\n        XCTAssertFalse(clp3.hasReadAccessRequiresAuthentication())\n    }\n\n    func testReadAccessRequiresAuthenticationHas() throws {\n        let clp = ParseCLP().setReadAccessRequiresAuthentication(true)\n        XCTAssertTrue(clp.hasReadAccessRequiresAuthentication())\n        XCTAssertFalse(clp.hasReadAccessPublic())\n\n        let clp2 = ParseCLP().setReadAccessRequiresAuthentication(false)\n        XCTAssertFalse(clp2.hasReadAccessRequiresAuthentication())\n        XCTAssertFalse(clp2.hasReadAccessPublic())\n\n        let clp3 = clp.setReadAccessRequiresAuthentication(false)\n        XCTAssertFalse(clp3.hasReadAccessRequiresAuthentication())\n        XCTAssertFalse(clp3.hasReadAccessPublic())\n    }\n\n    func testReadAccessObjectIdHas() throws {\n        let clp = ParseCLP().setReadAccess(true, for: objectId)\n        XCTAssertTrue(clp.hasReadAccess(objectId))\n        XCTAssertFalse(clp.hasWriteAccess(objectId))\n\n        let clp2 = ParseCLP().setReadAccess(false, for: objectId)\n        XCTAssertFalse(clp2.hasReadAccess(objectId))\n        XCTAssertFalse(clp2.hasWriteAccess(objectId))\n\n        let clp3 = clp.setReadAccess(false, for: objectId)\n        XCTAssertFalse(clp3.hasReadAccess(objectId))\n        XCTAssertFalse(clp3.hasWriteAccess(objectId))\n    }\n\n    func testReadAccessUserHas() throws {\n        let clp = try ParseCLP().setReadAccess(true, for: user)\n        XCTAssertTrue(try clp.hasReadAccess(user))\n        XCTAssertFalse(try clp.hasWriteAccess(user))\n\n        let clp2 = try ParseCLP().setReadAccess(false, for: user)\n        XCTAssertFalse(try clp2.hasReadAccess(user))\n        XCTAssertFalse(try clp2.hasWriteAccess(user))\n\n        let clp3 = try clp.setReadAccess(false, for: user)\n        XCTAssertFalse(try clp3.hasReadAccess(user))\n        XCTAssertFalse(try clp3.hasWriteAccess(user))\n    }\n\n    func testReadAccessPointerHas() throws {\n        let clp = ParseCLP().setReadAccess(true, for: try user.toPointer())\n        XCTAssertTrue(clp.hasReadAccess(try user.toPointer()))\n        XCTAssertFalse(clp.hasWriteAccess(try user.toPointer()))\n\n        let clp2 = ParseCLP().setReadAccess(false, for: try user.toPointer())\n        XCTAssertFalse(clp2.hasReadAccess(try user.toPointer()))\n        XCTAssertFalse(clp2.hasWriteAccess(try user.toPointer()))\n\n        let clp3 = clp.setReadAccess(false, for: try user.toPointer())\n        XCTAssertFalse(clp3.hasReadAccess(try user.toPointer()))\n        XCTAssertFalse(clp3.hasWriteAccess(try user.toPointer()))\n    }\n\n    func testReadAccessRoleHas() throws {\n        let name = \"hello\"\n        let role = try Role<User>(name: name)\n        let clp = try ParseCLP().setReadAccess(true, for: role)\n        XCTAssertTrue(try clp.hasReadAccess(role))\n        XCTAssertFalse(try clp.hasWriteAccess(role))\n\n        let clp2 = try ParseCLP().setReadAccess(false, for: role)\n        XCTAssertFalse(try clp2.hasReadAccess(role))\n        XCTAssertFalse(try clp2.hasWriteAccess(role))\n\n        let clp3 = try clp.setReadAccess(false, for: role)\n        XCTAssertFalse(try clp3.hasReadAccess(role))\n        XCTAssertFalse(try clp3.hasWriteAccess(role))\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseCloudViewModelTests.swift",
    "content": "//\n//  ParseCloudViewModelTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 7/11/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(SwiftUI)\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseCloudViewModelTests: XCTestCase {\n    struct Cloud: ParseCloud {\n        typealias ReturnType = String? // swiftlint:disable:this nesting\n\n        // These are required by ParseObject\n        var functionJobName: String\n    }\n\n    struct AnyResultResponse<U: Codable>: Codable {\n        let result: U\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        try KeychainStore.shared.deleteAll()\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testFunction() {\n        let response = AnyResultResponse<String>(result: \"hello\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(response)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let viewModel = Cloud(functionJobName: \"test\")\n            .viewModel\n        viewModel.error = ParseError(code: .unknownError, message: \"error\")\n        viewModel.runFunction()\n\n        let expectation = XCTestExpectation(description: \"Run Function\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {\n            XCTAssertEqual(viewModel.results, \"hello\")\n            XCTAssertNil(viewModel.error)\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testFunctionError() {\n        let response = ParseError(code: .unknownError, message: \"Custom error\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(response)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let viewModel = Cloud(functionJobName: \"test\")\n            .viewModel\n        viewModel.results = \"Test\"\n        viewModel.runFunction()\n\n        let expectation = XCTestExpectation(description: \"Run Function\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {\n            XCTAssertEqual(viewModel.results, nil)\n            XCTAssertNotNil(viewModel.error)\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testJob() {\n        let response = AnyResultResponse<String>(result: \"hello\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(response)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let viewModel = Cloud(functionJobName: \"test\")\n            .viewModel\n        viewModel.error = ParseError(code: .unknownError, message: \"error\")\n        viewModel.startJob()\n\n        let expectation = XCTestExpectation(description: \"Start Job\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {\n            XCTAssertEqual(viewModel.results, \"hello\")\n            XCTAssertNil(viewModel.error)\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testViewModelStatic() {\n        let response = AnyResultResponse<String>(result: \"hello\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(response)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let cloud = Cloud(functionJobName: \"test\")\n        let viewModel = Cloud.viewModel(cloud)\n        viewModel.error = ParseError(code: .unknownError, message: \"error\")\n        viewModel.startJob()\n\n        let expectation = XCTestExpectation(description: \"Start Job\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {\n            XCTAssertEqual(viewModel.results, \"hello\")\n            XCTAssertNil(viewModel.error)\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testJobError() {\n        let response = ParseError(code: .unknownError, message: \"Custom error\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(response)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let viewModel = Cloud(functionJobName: \"test\")\n            .viewModel\n        viewModel.results = \"Test\"\n        viewModel.startJob()\n\n        let expectation = XCTestExpectation(description: \"Start Job\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {\n            XCTAssertEqual(viewModel.results, nil)\n            XCTAssertNotNil(viewModel.error)\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseCloudableAsyncTests.swift",
    "content": "//\n//  ParseCloudableAsyncTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/28/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseCloudableAsyncTests: XCTestCase { // swiftlint:disable:this type_body_length\n    struct Cloud: ParseCloudable {\n        typealias ReturnType = String? // swiftlint:disable:this nesting\n\n        // These are required by ParseObject\n        var functionJobName: String\n    }\n\n    struct AnyResultResponse<U: Codable>: Codable {\n        let result: U\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    @MainActor\n    func testFunction() async throws {\n\n        let response = AnyResultResponse<String?>(result: nil)\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(response)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let cloud = Cloud(functionJobName: \"test\")\n        let functionResponse = try await cloud.runFunction()\n        XCTAssertNil(functionResponse)\n    }\n\n    @MainActor\n    func testJob() async throws {\n\n        let response = AnyResultResponse<String?>(result: nil)\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(response)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let cloud = Cloud(functionJobName: \"test\")\n        let functionResponse = try await cloud.startJob()\n        XCTAssertNil(functionResponse)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseCloudableCombineTests.swift",
    "content": "//\n//  ParseCloudableCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/30/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseCloudableCombineTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct Cloud: ParseCloudable {\n        typealias ReturnType = String? // swiftlint:disable:this nesting\n\n        // These are required by ParseObject\n        var functionJobName: String\n    }\n\n    struct AnyResultResponse<U: Codable>: Codable {\n        let result: U\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testFunction() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        let response = AnyResultResponse<String?>(result: nil)\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(response)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let cloud = Cloud(functionJobName: \"test\")\n        let publisher = cloud.runFunctionPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { functionResponse in\n\n            XCTAssertNil(functionResponse)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testJob() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        let response = AnyResultResponse<String?>(result: nil)\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(response)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let cloud = Cloud(functionJobName: \"test\")\n        let publisher = cloud.startJobPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { functionResponse in\n\n            XCTAssertNil(functionResponse)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseCloudableTests.swift",
    "content": "//\n//  ParseCloudableTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 12/29/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseCloudableTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct Cloud: ParseCloudable {\n        typealias ReturnType = String? // swiftlint:disable:this nesting\n\n        // These are required by ParseObject\n        var functionJobName: String\n    }\n\n    struct Cloud2: ParseCloudable {\n        typealias ReturnType = String? // swiftlint:disable:this nesting\n\n        // These are required by ParseObject\n        var functionJobName: String\n\n        // Your custom keys\n        var customKey: String?\n    }\n\n    struct Cloud3: ParseCloud {\n        typealias ReturnType = [String: String] // swiftlint:disable:this nesting\n\n        // These are required by ParseObject\n        var functionJobName: String\n    }\n\n    struct AnyResultResponse<U: Codable>: Codable {\n        let result: U\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testJSONEncoding() throws {\n        let expected = [\"functionJobName\": \"test\"]\n        let cloud = Cloud(functionJobName: \"test\")\n        let encoded = try JSONEncoder().encode(cloud)\n        let decoded = try JSONDecoder().decode([String: String].self, from: encoded)\n        XCTAssertEqual(decoded, expected, \"all keys should show up in JSONEncoder\")\n    }\n\n    func testJSONEncoding2() throws {\n        let expected = [\n            \"functionJobName\": \"test\",\n            \"customKey\": \"parse\"\n        ]\n        let cloud = Cloud2(functionJobName: \"test\", customKey: \"parse\")\n        let encoded = try JSONEncoder().encode(cloud)\n        let decoded = try JSONDecoder().decode([String: String].self, from: encoded)\n        XCTAssertEqual(decoded, expected, \"all keys should show up in JSONEncoder\")\n    }\n\n    func testParseEncoding() throws {\n        let expected = [String: String]()\n        let cloud = Cloud(functionJobName: \"test\")\n        let encoded = try ParseCoding.parseEncoder().encode(cloud, skipKeys: .cloud)\n        let decoded = try JSONDecoder().decode([String: String].self, from: encoded)\n        XCTAssertEqual(decoded, expected, \"\\\"functionJobName\\\" key should be skipped by ParseEncoder\")\n    }\n\n    func testParseEncoding2() throws {\n        let expected = [\n            \"customKey\": \"parse\"\n        ]\n        let cloud = Cloud2(functionJobName: \"test\", customKey: \"parse\")\n        let encoded = try ParseCoding.parseEncoder().encode(cloud, skipKeys: .cloud)\n        let decoded = try JSONDecoder().decode([String: String].self, from: encoded)\n        XCTAssertEqual(decoded, expected, \"\\\"functionJobName\\\" key should be skipped by ParseEncoder\")\n    }\n\n    func testDebugString() {\n        let cloud = Cloud2(functionJobName: \"test\", customKey: \"parse\")\n        let expected = \"{\\\"customKey\\\":\\\"parse\\\",\\\"functionJobName\\\":\\\"test\\\"}\"\n        XCTAssertEqual(cloud.debugDescription, expected)\n    }\n\n    func testDescription() {\n        let cloud = Cloud2(functionJobName: \"test\", customKey: \"parse\")\n        let expected = \"{\\\"customKey\\\":\\\"parse\\\",\\\"functionJobName\\\":\\\"test\\\"}\"\n        XCTAssertEqual(cloud.description, expected)\n    }\n\n    func testCallFunctionCommand() throws {\n        let cloud = Cloud(functionJobName: \"test\")\n        let command = cloud.runFunctionCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/functions/test\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertNil(command.params)\n        XCTAssertEqual(command.body?.functionJobName, \"test\")\n    }\n\n    func testCallFunctionWithArgsCommand() throws {\n        let cloud = Cloud2(functionJobName: \"test\", customKey: \"parse\")\n        let command = cloud.runFunctionCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/functions/test\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertNil(command.params)\n        XCTAssertEqual(command.body?.functionJobName, \"test\")\n        XCTAssertEqual(command.body?.customKey, \"parse\")\n    }\n\n    func testFunction() {\n        let response = AnyResultResponse<String?>(result: nil)\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(response)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        do {\n            let cloud = Cloud(functionJobName: \"test\")\n            let functionResponse = try cloud.runFunction()\n            XCTAssertNil(functionResponse)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testFunction2() {\n        var result = [\"hello\": \"world\"]\n        let response = AnyResultResponse(result: result)\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(response)\n                let encodedResult = try ParseCoding.jsonEncoder().encode(result)\n                result = try ParseCoding.jsonDecoder().decode([String: String].self, from: encodedResult)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        do {\n            let cloud = Cloud3(functionJobName: \"test\")\n            let functionResponse = try cloud.runFunction()\n            XCTAssertEqual(functionResponse, [\"hello\": \"world\"])\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testFunctionError() {\n\n        let parseError = ParseError(code: .scriptFailed, message: \"Error: Invalid function\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(parseError)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let cloud = Cloud(functionJobName: \"test\")\n            _ = try cloud.runFunction()\n            XCTFail(\"Should have thrown ParseError\")\n        } catch {\n            if let error = error as? ParseError {\n                XCTAssertEqual(error.code, parseError.code)\n            } else {\n                XCTFail(\"Should have thrown ParseError\")\n            }\n        }\n    }\n\n    func functionAsync(serverResponse: [String: String], callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Logout user1\")\n        let cloud = Cloud3(functionJobName: \"test\")\n        cloud.runFunction(callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let response):\n                XCTAssertEqual(response, serverResponse)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 10.0)\n    }\n\n    func testFunctionMainQueue() {\n        let response = AnyResultResponse(result: [\"hello\": \"world\"])\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(response)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        self.functionAsync(serverResponse: [\"hello\": \"world\"], callbackQueue: .main)\n    }\n\n    func functionAsyncError(parseError: ParseError, callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Logout user1\")\n        let cloud = Cloud(functionJobName: \"test\")\n        cloud.runFunction(callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success:\n                XCTFail(\"Should have thrown ParseError\")\n                expectation1.fulfill()\n\n            case .failure(let error):\n                XCTAssertEqual(error.code, parseError.code)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 10.0)\n    }\n\n    func testFunctionMainQueueError() {\n        let parseError = ParseError(code: .scriptFailed, message: \"Error: Invalid function\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(parseError)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        self.functionAsyncError(parseError: parseError, callbackQueue: .main)\n    }\n\n    func testCallJobCommand() throws {\n        let cloud = Cloud(functionJobName: \"test\")\n        let command = cloud.startJobCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/jobs/test\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertNil(command.params)\n        XCTAssertEqual(command.body?.functionJobName, \"test\")\n    }\n\n    func testCallJobWithArgsCommand() throws {\n        let cloud = Cloud2(functionJobName: \"test\", customKey: \"parse\")\n        let command = cloud.startJobCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/jobs/test\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertNil(command.params)\n        XCTAssertEqual(command.body?.functionJobName, \"test\")\n        XCTAssertEqual(command.body?.customKey, \"parse\")\n    }\n\n    func testJob() {\n        let response = AnyResultResponse<String?>(result: nil)\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(response)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        do {\n            let cloud = Cloud(functionJobName: \"test\")\n            let functionResponse = try cloud.startJob()\n            XCTAssertNil(functionResponse)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testJob2() {\n        let response = AnyResultResponse(result: [\"hello\": \"world\"])\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(response)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        do {\n            let cloud = Cloud3(functionJobName: \"test\")\n            let functionResponse = try cloud.startJob()\n            XCTAssertEqual(functionResponse, response.result)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testJobError() {\n\n        let parseError = ParseError(code: .scriptFailed, message: \"Error: Invalid function\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(parseError)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let cloud = Cloud(functionJobName: \"test\")\n            _ = try cloud.startJob()\n            XCTFail(\"Should have thrown ParseError\")\n        } catch {\n            if let error = error as? ParseError {\n                XCTAssertEqual(error.code, parseError.code)\n            } else {\n                XCTFail(\"Should have thrown ParseError\")\n            }\n        }\n    }\n\n    func testCustomError() {\n\n        guard let encoded: Data = \"{\\\"error\\\":\\\"Error: Custom Error\\\",\\\"code\\\":2000}\".data(using: .utf8) else {\n            XCTFail(\"Could not unwrap encoded data\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let cloud = Cloud(functionJobName: \"test\")\n            _ = try cloud.runFunction()\n            XCTFail(\"Should have thrown ParseError\")\n        } catch {\n            if let error = error as? ParseError {\n                XCTAssertEqual(error.code, .other)\n                XCTAssertEqual(error.message, \"Error: Custom Error\")\n                XCTAssertEqual(error.otherCode, 2000)\n            } else {\n                XCTFail(\"Should have thrown ParseError\")\n            }\n        }\n    }\n\n    func jobAsync(serverResponse: [String: String], callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Logout user1\")\n        let cloud = Cloud3(functionJobName: \"test\")\n        cloud.startJob(callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let response):\n                XCTAssertEqual(response, serverResponse)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 10.0)\n    }\n\n    func testJobMainQueue() {\n        let response = AnyResultResponse(result: [\"hello\": \"world\"])\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(response)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        self.jobAsync(serverResponse: [\"hello\": \"world\"], callbackQueue: .main)\n    }\n\n    func jobAsyncError(parseError: ParseError, callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Logout user1\")\n        let cloud = Cloud(functionJobName: \"test\")\n        cloud.startJob(callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success:\n                XCTFail(\"Should have thrown ParseError\")\n                expectation1.fulfill()\n\n            case .failure(let error):\n                XCTAssertEqual(error.code, parseError.code)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 10.0)\n    }\n\n    func testJobMainQueueError() {\n        let parseError = ParseError(code: .scriptFailed, message: \"Error: Invalid function\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(parseError)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        self.jobAsyncError(parseError: parseError, callbackQueue: .main)\n    }\n} // swiftlint:disable:this file_length\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseConfigAsyncTests.swift",
    "content": "//\n//  ParseConfigAsyncTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/28/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseConfigAsyncTests: XCTestCase { // swiftlint:disable:this type_body_length\n    struct Config: ParseConfig {\n        var welcomeMessage: String?\n        var winningNumber: Int?\n    }\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func userLogin() {\n        let loginResponse = LoginSignupResponse()\n        let loginUserName = \"hello10\"\n        let loginPassword = \"world\"\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        do {\n            _ = try User.login(username: loginUserName, password: loginPassword)\n            MockURLProtocol.removeAll()\n        } catch {\n            XCTFail(\"Should login\")\n        }\n    }\n\n    @MainActor\n    func testFetch() async throws {\n\n        userLogin()\n        let config = Config()\n\n        var configOnServer = config\n        configOnServer.welcomeMessage = \"Hello\"\n        let serverResponse = ConfigFetchResponse(params: configOnServer)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let fetched = try await config.fetch()\n        XCTAssertEqual(fetched.welcomeMessage, configOnServer.welcomeMessage)\n        XCTAssertEqual(Config.current?.welcomeMessage, configOnServer.welcomeMessage)\n\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        //Should be updated in Keychain\n        guard let keychainConfig: CurrentConfigContainer<Config>\n            = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentConfig) else {\n                XCTFail(\"Should get object from Keychain\")\n            return\n        }\n        XCTAssertEqual(keychainConfig.currentConfig?.welcomeMessage, configOnServer.welcomeMessage)\n        #endif\n    }\n\n    @MainActor\n    func testSave() async throws {\n\n        userLogin()\n        var config = Config()\n        config.welcomeMessage = \"Hello\"\n\n        let serverResponse = BooleanResponse(result: true)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await config.save()\n        XCTAssertTrue(saved)\n        XCTAssertEqual(Config.current?.welcomeMessage, config.welcomeMessage)\n\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        //Should be updated in Keychain\n        guard let keychainConfig: CurrentConfigContainer<Config>\n            = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentConfig) else {\n                XCTFail(\"Should get object from Keychain\")\n            return\n        }\n        XCTAssertEqual(keychainConfig.currentConfig?.welcomeMessage, config.welcomeMessage)\n        #endif\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseConfigCombineTests.swift",
    "content": "//\n//  ParseConfigCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/30/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseConfigCombineTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct Config: ParseConfig {\n        var welcomeMessage: String?\n        var winningNumber: Int?\n    }\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func userLogin() {\n        let loginResponse = LoginSignupResponse()\n        let loginUserName = \"hello10\"\n        let loginPassword = \"world\"\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        do {\n            _ = try User.login(username: loginUserName, password: loginPassword)\n            MockURLProtocol.removeAll()\n        } catch {\n            XCTFail(\"Should login\")\n        }\n    }\n\n    func testFetch() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        userLogin()\n        let config = Config()\n\n        var configOnServer = config\n        configOnServer.welcomeMessage = \"Hello\"\n        let serverResponse = ConfigFetchResponse(params: configOnServer)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = config.fetchPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { fetched in\n\n            XCTAssertEqual(fetched.welcomeMessage, configOnServer.welcomeMessage)\n            XCTAssertEqual(Config.current?.welcomeMessage, configOnServer.welcomeMessage)\n\n            #if !os(Linux) && !os(Android) && !os(Windows)\n            //Should be updated in Keychain\n            guard let keychainConfig: CurrentConfigContainer<Config>\n                = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentConfig) else {\n                    XCTFail(\"Should get object from Keychain\")\n                return\n            }\n            XCTAssertEqual(keychainConfig.currentConfig?.welcomeMessage, configOnServer.welcomeMessage)\n            #endif\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSave() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        userLogin()\n        var config = Config()\n        config.welcomeMessage = \"Hello\"\n\n        let serverResponse = BooleanResponse(result: true)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = config.savePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            XCTAssertTrue(saved)\n            XCTAssertEqual(Config.current?.welcomeMessage, config.welcomeMessage)\n\n            #if !os(Linux) && !os(Android) && !os(Windows)\n            //Should be updated in Keychain\n            guard let keychainConfig: CurrentConfigContainer<Config>\n                = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentConfig) else {\n                    XCTFail(\"Should get object from Keychain\")\n                return\n            }\n            XCTAssertEqual(keychainConfig.currentConfig?.welcomeMessage, config.welcomeMessage)\n            #endif\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseConfigTests.swift",
    "content": "//\n//  ParseConfigTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/22/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseConfigTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct Config: ParseConfig {\n        var welcomeMessage: String?\n        var winningNumber: Int?\n    }\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func userLogin() {\n        let loginResponse = LoginSignupResponse()\n        let loginUserName = \"hello10\"\n        let loginPassword = \"world\"\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        do {\n            _ = try User.login(username: loginUserName, password: loginPassword)\n            MockURLProtocol.removeAll()\n        } catch {\n            XCTFail(\"Should login\")\n        }\n    }\n\n    func testUpdateKeyChainIfNeeded() throws {\n        userLogin()\n        let config = Config()\n        XCTAssertNil(Config.current)\n\n        Config.updateKeychainIfNeeded(config, deleting: true)\n        XCTAssertNil(Config.current)\n    }\n\n    func testDeleteFromKeychainOnLogout() throws {\n        userLogin()\n        var config = Config()\n        config.welcomeMessage = \"Hello\"\n        XCTAssertNil(Config.current)\n\n        Config.updateKeychainIfNeeded(config)\n        XCTAssertNotNil(Config.current)\n        XCTAssertEqual(config.welcomeMessage, Config.current?.welcomeMessage)\n\n        let logoutResponse = NoBody()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(logoutResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        try User.logout()\n        XCTAssertNil(Config.current)\n    }\n\n    func testFetchCommand() throws {\n        var config = Config()\n        config.welcomeMessage = \"Hello\"\n        let command = config.fetchCommand()\n        XCTAssertEqual(command.path.urlComponent, \"/config\")\n        XCTAssertEqual(command.method, API.Method.GET)\n        XCTAssertNil(command.body)\n    }\n\n    func testDebugString() {\n        var config = Config()\n        config.welcomeMessage = \"Hello\"\n        let expected = \"{\\\"welcomeMessage\\\":\\\"Hello\\\"}\"\n        XCTAssertEqual(config.debugDescription, expected)\n    }\n\n    func testDescription() {\n        var config = Config()\n        config.welcomeMessage = \"Hello\"\n        let expected = \"{\\\"welcomeMessage\\\":\\\"Hello\\\"}\"\n        XCTAssertEqual(config.description, expected)\n    }\n\n    func testFetch() {\n        userLogin()\n        let config = Config()\n\n        var configOnServer = config\n        configOnServer.welcomeMessage = \"Hello\"\n        let serverResponse = ConfigFetchResponse(params: configOnServer)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let fetched = try config.fetch()\n            XCTAssertEqual(fetched.welcomeMessage, configOnServer.welcomeMessage)\n            XCTAssertEqual(Config.current?.welcomeMessage, configOnServer.welcomeMessage)\n\n            #if !os(Linux) && !os(Android) && !os(Windows)\n            //Should be updated in Keychain\n            guard let keychainConfig: CurrentConfigContainer<Config>\n                = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentConfig) else {\n                    XCTFail(\"Should get object from Keychain\")\n                return\n            }\n            XCTAssertEqual(keychainConfig.currentConfig?.welcomeMessage, configOnServer.welcomeMessage)\n            #endif\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testFetchAsync() {\n        userLogin()\n        let config = Config()\n\n        var configOnServer = config\n        configOnServer.welcomeMessage = \"Hello\"\n        let serverResponse = ConfigFetchResponse(params: configOnServer)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation = XCTestExpectation(description: \"Config save\")\n        config.fetch { result in\n            switch result {\n\n            case .success(let fetched):\n                XCTAssertEqual(fetched.welcomeMessage, configOnServer.welcomeMessage)\n                XCTAssertEqual(Config.current?.welcomeMessage, configOnServer.welcomeMessage)\n\n                #if !os(Linux) && !os(Android) && !os(Windows)\n                //Should be updated in Keychain\n                guard let keychainConfig: CurrentConfigContainer<Config>\n                    = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentConfig) else {\n                        XCTFail(\"Should get object from Keychain\")\n                    expectation.fulfill()\n                    return\n                }\n                XCTAssertEqual(keychainConfig.currentConfig?.welcomeMessage, configOnServer.welcomeMessage)\n                #endif\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 10.0)\n    }\n\n    func testUpdateCommand() throws {\n        var config = Config()\n        config.welcomeMessage = \"Hello\"\n        let command = config.updateCommand()\n        XCTAssertEqual(command.path.urlComponent, \"/config\")\n        XCTAssertEqual(command.method, API.Method.PUT)\n        XCTAssertNotNil(command.body)\n    }\n\n    func testSave() {\n        userLogin()\n        var config = Config()\n        config.welcomeMessage = \"Hello\"\n\n        let serverResponse = BooleanResponse(result: true)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try config.save()\n            XCTAssertTrue(saved)\n            XCTAssertEqual(Config.current?.welcomeMessage, config.welcomeMessage)\n\n            #if !os(Linux) && !os(Android) && !os(Windows)\n            //Should be updated in Keychain\n            guard let keychainConfig: CurrentConfigContainer<Config>\n                = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentConfig) else {\n                    XCTFail(\"Should get object from Keychain\")\n                return\n            }\n            XCTAssertEqual(keychainConfig.currentConfig?.welcomeMessage, config.welcomeMessage)\n            #endif\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testSaveAsync() {\n        userLogin()\n        var config = Config()\n        config.welcomeMessage = \"Hello\"\n\n        let serverResponse = BooleanResponse(result: true)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation = XCTestExpectation(description: \"Config save\")\n        config.save { result in\n            switch result {\n\n            case .success(let saved):\n                XCTAssertTrue(saved)\n                XCTAssertEqual(Config.current?.welcomeMessage, config.welcomeMessage)\n\n                #if !os(Linux) && !os(Android) && !os(Windows)\n                //Should be updated in Keychain\n                guard let keychainConfig: CurrentConfigContainer<Config>\n                    = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentConfig) else {\n                        XCTFail(\"Should get object from Keychain\")\n                    expectation.fulfill()\n                    return\n                }\n                XCTAssertEqual(keychainConfig.currentConfig?.welcomeMessage, config.welcomeMessage)\n                #endif\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 10.0)\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseEncoderTests/ParseEncoderExtraTests.swift",
    "content": "//\n//  ParseEncoderTests.swift\n//  ParseSwiftTests\n//\n//  Created by Pranjal Satija on 8/7/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport XCTest\n@testable import ParseSwift\n\nclass ParseEncoderTests: XCTestCase {\n    struct GameScore: ParseObject, ParseQueryScorable {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var score: Double?\n        var originalData: Data?\n\n        //: ParseUser property\n        var emailVerified: Bool?\n\n        //: Your own properties\n        var points: Int\n\n        //: a custom initializer\n        init() {\n            self.points = 5\n        }\n        init(points: Int) {\n            self.points = points\n        }\n    }\n\n    struct Address: Codable {\n        let street: String\n        let city: String\n    }\n\n    struct Name: Codable {\n        let first: String\n        let last: String\n    }\n\n    struct Person: Codable {\n        let addresses: [String: Address]\n        let age: Int\n        let name: Name\n        let nicknames: [Name]\n        let phoneNumbers: [String]\n    }\n\n    func referenceEncoding<T: Encodable>(for object: T) -> Data {\n        let encoder = JSONEncoder()\n        encoder.outputFormatting = .sortedKeys\n\n        guard let encoding = try? encoder.encode(object) else {\n            XCTFail(\"Could not get a reference encoding.\")\n            return Data()\n        }\n\n        return encoding\n    }\n\n    func testNestedContatiner() throws {\n        var newACL = ParseACL()\n        newACL.publicRead = true\n\n        let jsonEncoded = try JSONEncoder().encode(newACL)\n        let jsonDecoded = try ParseCoding.jsonDecoder().decode([String: [String: Bool]].self, from: jsonEncoded)\n\n        let parseEncoded = try ParseCoding.jsonEncoder().encode(newACL)\n        let parseDecoded = try ParseCoding.jsonDecoder().decode([String: [String: Bool]].self, from: parseEncoded)\n\n        XCTAssertEqual(jsonDecoded.keys.count, parseDecoded.keys.count)\n        XCTAssertEqual(jsonDecoded.values.count, parseDecoded.values.count)\n        XCTAssertEqual(jsonDecoded[\"*\"]?[\"read\"], true)\n        XCTAssertEqual(parseDecoded[\"*\"]?[\"read\"], true)\n    }\n\n    func testSkipKeysDefaultCodingKeys() throws {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        score.createdAt = Date()\n        score.updatedAt = score.createdAt\n        score.emailVerified = true\n\n        let encodedJSON = try ParseCoding.jsonEncoder().encode(score)\n        let decodedJSON = try ParseCoding.jsonDecoder().decode([String: AnyCodable].self, from: encodedJSON)\n        XCTAssertEqual(decodedJSON[\"points\"]?.value as? Int, score.points)\n        XCTAssertNotNil(decodedJSON[\"objectId\"])\n        XCTAssertNotNil(decodedJSON[\"createdAt\"])\n        XCTAssertNotNil(decodedJSON[\"updatedAt\"])\n        XCTAssertNotNil(decodedJSON[\"emailVerified\"])\n\n        //ParseEncoder\n        let encoded = try ParseCoding.parseEncoder().encode(score, skipKeys: .object)\n        let decoded = try ParseCoding.jsonDecoder().decode([String: AnyCodable].self, from: encoded)\n        XCTAssertEqual(decoded[\"points\"]?.value as? Int, score.points)\n        XCTAssertNil(decoded[\"objectId\"])\n        XCTAssertNil(decoded[\"createdAt\"])\n        XCTAssertNil(decoded[\"updatedAt\"])\n        XCTAssertNil(decoded[\"emailVerified\"])\n        XCTAssertNil(decoded[\"className\"])\n        XCTAssertNil(decoded[\"score\"])\n        XCTAssertNil(decoded[\"id\"])\n\n        let encoded2 = try ParseCoding.parseEncoder().encode(score, skipKeys: .customObjectId)\n        let decoded2 = try ParseCoding.jsonDecoder().decode([String: AnyCodable].self, from: encoded2)\n        XCTAssertEqual(decoded2[\"points\"]?.value as? Int, score.points)\n        XCTAssertNotNil(decoded2[\"objectId\"])\n        XCTAssertNil(decoded2[\"createdAt\"])\n        XCTAssertNil(decoded2[\"updatedAt\"])\n        XCTAssertNil(decoded2[\"emailVerified\"])\n        XCTAssertNil(decoded2[\"className\"])\n        XCTAssertNil(decoded2[\"score\"])\n        XCTAssertNil(decoded2[\"id\"])\n    }\n\n    func testSkipKeysDefaultCodingKeysWithScore() throws {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        score.createdAt = Date()\n        score.updatedAt = score.createdAt\n        score.emailVerified = true\n        \n        var encodedJSON = try ParseCoding.jsonEncoder().encode(score)\n        var decodedJSON = try ParseCoding.jsonDecoder().decode([String: AnyCodable].self, from: encodedJSON)\n        decodedJSON[\"score\"] = 0.99\n        encodedJSON = try ParseCoding.jsonEncoder().encode(decodedJSON)\n        decodedJSON = try ParseCoding.jsonDecoder().decode([String: AnyCodable].self, from: encodedJSON)\n        XCTAssertNotNil(decodedJSON[\"score\"])\n        score = try ParseCoding.jsonDecoder().decode(GameScore.self, from: encodedJSON)\n        XCTAssertNotNil(score.score)\n\n        //ParseEncoder\n        let encoded = try ParseCoding.parseEncoder().encode(score, skipKeys: .object)\n        let decoded = try ParseCoding.jsonDecoder().decode([String: AnyCodable].self, from: encoded)\n        XCTAssertNil(decoded[\"score\"])\n\n        let encoded2 = try ParseCoding.parseEncoder().encode(score, skipKeys: .customObjectId)\n        let decoded2 = try ParseCoding.jsonDecoder().decode([String: AnyCodable].self, from: encoded2)\n        XCTAssertNil(decoded2[\"score\"])\n    }\n\n    func testDateStringEncoding() throws {\n        let jsonScore = \"{\\\"createdAt\\\":\\\"2021-03-15T02:24:47.841Z\\\",\\\"points\\\":5}\"\n        guard let encoded = jsonScore.data(using: .utf8) else {\n            XCTFail(\"Shuld have created data\")\n            return\n        }\n        XCTAssertNoThrow(try ParseCoding.jsonDecoder().decode(GameScore.self, from: encoded))\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseEncoderTests/TestParseEncoder.swift",
    "content": "// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors\n// Licensed under Apache License v2.0 with Runtime Library Exception\n//\n// See https://swift.org/LICENSE.txt for license information\n// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors\n//\n//===----------------------------------------------------------------------===//\n//\n// RUN: %target-run-simple-swift\n// REQUIRES: executable_test\n// REQUIRES: objc_interop\n// REQUIRES: rdar55727144\n\n/*\nAll Credit to Apple, this testsuite matches the encoder tests found in [Swift 5.4](https://github.com/apple/swift/blob/main/test/stdlib/TestJSONEncoder.swift).\nUpdate commits as needed for improvement.\n*/\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass TestParseEncoder: XCTestCase {\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n    }\n\n  // MARK: - Encoding Top-Level Empty Types\n  func testEncodingTopLevelEmptyStruct() {\n    let empty = EmptyStruct()\n    _testRoundTrip(of: empty, expectedJSON: _jsonEmptyDictionary)\n  }\n\n  func testEncodingTopLevelEmptyClass() {\n    let empty = EmptyClass()\n    _testRoundTrip(of: empty, expectedJSON: _jsonEmptyDictionary)\n  }\n\n  // MARK: - Encoding Top-Level Single-Value Types\n  func testEncodingTopLevelSingleValueEnum() {\n    _testRoundTrip(of: Switch.off)\n    _testRoundTrip(of: Switch.on)\n  }\n\n  func testEncodingTopLevelSingleValueStruct() {\n    _testRoundTrip(of: Timestamp(3141592653))\n  }\n\n  func testEncodingTopLevelSingleValueClass() {\n    _testRoundTrip(of: Counter())\n  }\n\n  // MARK: - Encoding Top-Level Structured Types\n  func testEncodingTopLevelStructuredStruct() {\n    // Address is a struct type with multiple fields.\n    let address = Address.testValue\n    _testRoundTrip(of: address)\n  }\n\n  func testEncodingTopLevelStructuredClass() {\n    // Person is a class with multiple fields.\n    let expectedJSON = \"{\\\"email\\\":\\\"appleseed@apple.com\\\",\\\"name\\\":\\\"Johnny Appleseed\\\"}\".data(using: .utf8)!\n    let person = Person.testValue\n    _testRoundTrip(of: person, expectedJSON: expectedJSON)\n  }\n\n  func testEncodingTopLevelStructuredSingleStruct() {\n    // Numbers is a struct which encodes as an array through a single value container.\n    let numbers = Numbers.testValue\n    _testRoundTrip(of: numbers)\n  }\n\n  func testEncodingTopLevelStructuredSingleClass() {\n    // Mapping is a class which encodes as a dictionary through a single value container.\n    let mapping = Mapping.testValue\n    _testRoundTrip(of: mapping)\n  }\n\n  func testEncodingTopLevelDeepStructuredType() {\n    // Company is a type with fields which are Codable themselves.\n    let company = Company.testValue\n    _testRoundTrip(of: company)\n  }\n\n  func testEncodingClassWhichSharesEncoderWithSuper() {\n    // Employee is a type which shares its encoder & decoder with its superclass, Person.\n    let employee = Employee.testValue\n    _testRoundTrip(of: employee)\n  }\n\n  func testEncodingTopLevelNullableType() {\n    // EnhancedBool is a type which encodes either as a Bool or as nil.\n    _testRoundTrip(of: EnhancedBool.true, expectedJSON: \"true\".data(using: .utf8)!)\n    _testRoundTrip(of: EnhancedBool.false, expectedJSON: \"false\".data(using: .utf8)!)\n    _testRoundTrip(of: EnhancedBool.fileNotFound, expectedJSON: \"null\".data(using: .utf8)!)\n  }\n\n#if !os(Linux) && !os(Android) && !os(Windows)\n  func testEncodingMultipleNestedContainersWithTheSameTopLevelKey() {\n    struct Model: Codable, Equatable {\n      let first: String\n      let second: String\n\n      init(from coder: Decoder) throws {\n        let container = try coder.container(keyedBy: TopLevelCodingKeys.self)\n\n        let firstNestedContainer = try container.nestedContainer(keyedBy: FirstNestedCodingKeys.self, forKey: .top)\n        self.first = try firstNestedContainer.decode(String.self, forKey: .first)\n\n        let secondNestedContainer = try container.nestedContainer(keyedBy: SecondNestedCodingKeys.self, forKey: .top)\n        self.second = try secondNestedContainer.decode(String.self, forKey: .second)\n      }\n\n      func encode(to encoder: Encoder) throws {\n        var container = encoder.container(keyedBy: TopLevelCodingKeys.self)\n\n        var firstNestedContainer = container.nestedContainer(keyedBy: FirstNestedCodingKeys.self, forKey: .top)\n        try firstNestedContainer.encode(self.first, forKey: .first)\n\n        var secondNestedContainer = container.nestedContainer(keyedBy: SecondNestedCodingKeys.self, forKey: .top)\n        try secondNestedContainer.encode(self.second, forKey: .second)\n      }\n\n      init(first: String, second: String) {\n        self.first = first\n        self.second = second\n      }\n\n      static var testValue: Model {\n        return Model(first: \"Johnny Appleseed\",\n                     second: \"appleseed@apple.com\")\n      }\n\n      enum TopLevelCodingKeys: String, CodingKey {\n        case top\n      }\n\n      enum FirstNestedCodingKeys: String, CodingKey {\n        case first\n      }\n      enum SecondNestedCodingKeys: String, CodingKey {\n        case second\n      }\n    }\n\n    let model = Model.testValue\n    if #available(OSX 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) {\n      let expectedJSON = \"{\\\"top\\\":{\\\"first\\\":\\\"Johnny Appleseed\\\",\\\"second\\\":\\\"appleseed@apple.com\\\"}}\".data(using: .utf8)!\n      _testRoundTrip(of: model, expectedJSON: expectedJSON, outputFormatting: [.sortedKeys])\n    } else {\n      _testRoundTrip(of: model)\n    }\n  }\n    #endif\n    /*\n  func testEncodingConflictedTypeNestedContainersWithTheSameTopLevelKey() throws {\n    struct Model: Encodable, Equatable {\n      let first: String\n\n      func encode(to encoder: Encoder) throws {\n        var container = encoder.container(keyedBy: TopLevelCodingKeys.self)\n\n        var firstNestedContainer = container.nestedContainer(keyedBy: FirstNestedCodingKeys.self, forKey: .top)\n        try firstNestedContainer.encode(self.first, forKey: .first)\n\n        // The following line would fail as it attempts to re-encode into already encoded container is invalid. This will always fail\n        var secondNestedContainer = container.nestedUnkeyedContainer(forKey: .top)\n        try secondNestedContainer.encode(\"second\")\n      }\n\n      init(first: String) {\n        self.first = first\n      }\n\n      static var testValue: Model {\n        return Model(first: \"Johnny Appleseed\")\n      }\n\n      enum TopLevelCodingKeys: String, CodingKey {\n        case top\n      }\n      enum FirstNestedCodingKeys: String, CodingKey {\n        case first\n      }\n    }\n\n    let model = Model.testValue\n    // This following test would fail as it attempts to re-encode into already encoded container is invalid. This will always fail\n    if #available(OSX 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) {\n      _testEncodeFailure(of: model)\n    } else {\n      _testEncodeFailure(of: model)\n    }\n  }*/\n\n  // MARK: - Output Formatting Tests\n  func testEncodingOutputFormattingDefault() {\n    let expectedJSON = \"{\\\"email\\\":\\\"appleseed@apple.com\\\",\\\"name\\\":\\\"Johnny Appleseed\\\"}\".data(using: .utf8)!\n    let person = Person.testValue\n    _testRoundTrip(of: person, expectedJSON: expectedJSON)\n  }\n/*\n  func testEncodingOutputFormattingPrettyPrinted() {\n    let expectedJSON = \"{\\n  \\\"name\\\" : \\\"Johnny Appleseed\\\",\\n  \\\"email\\\" : \\\"appleseed@apple.com\\\"\\n}\".data(using: .utf8)!\n    let person = Person.testValue\n    _testRoundTrip(of: person, expectedJSON: expectedJSON, outputFormatting: [.prettyPrinted])\n  }\n\n  func testEncodingOutputFormattingSortedKeys() {\n    if #available(OSX 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) {\n      let expectedJSON = \"{\\\"email\\\":\\\"appleseed@apple.com\\\",\\\"name\\\":\\\"Johnny Appleseed\\\"}\".data(using: .utf8)!\n      let person = Person.testValue\n      _testRoundTrip(of: person, expectedJSON: expectedJSON, outputFormatting: [.sortedKeys])\n    }\n  }\n\n  func testEncodingOutputFormattingPrettyPrintedSortedKeys() {\n    if #available(OSX 10.13, iOS 11.0, watchOS 4.0, tvOS 11.0, *) {\n      let expectedJSON = \"{\\n  \\\"email\\\" : \\\"appleseed@apple.com\\\",\\n  \\\"name\\\" : \\\"Johnny Appleseed\\\"\\n}\".data(using: .utf8)!\n      let person = Person.testValue\n      _testRoundTrip(of: person, expectedJSON: expectedJSON, outputFormatting: [.prettyPrinted, .sortedKeys])\n    }\n  }*/\n\n  // MARK: - Date Strategy Tests\n    #if !os(Linux) && !os(Android) && !os(Windows)\n  // Disabled for now till we resolve rdar://52618414\n  func x_testEncodingDate() throws {\n\n    func formattedLength(of value: Double) -> Int {\n      let empty = UnsafeMutablePointer<Int8>.allocate(capacity: 0)\n      defer { empty.deallocate() }\n      let length = snprintf(ptr: empty, 0, \"%0.*g\", DBL_DECIMAL_DIG, value)\n      return Int(length)\n    }\n\n    // Duplicated to handle a special case\n    func localTestRoundTrip<T: Codable & Equatable>(of value: T) throws {\n      var payload: Data! = nil\n      do {\n        let encoder = ParseEncoder()\n        payload = try encoder.encode(value)\n      } catch {\n        XCTAssertThrowsError(\"Failed to encode \\(T.self) to JSON: \\(error)\")\n      }\n\n      do {\n        let decoder = JSONDecoder()\n        let decoded = try decoder.decode(T.self, from: payload)\n\n        /// `snprintf`'s `%g`, which `JSONSerialization` uses internally for double values, does not respect \n        /// our precision requests in every case. This bug effects Darwin, FreeBSD, and Linux currently\n        /// causing this test (which uses the current time) to fail occasionally.\n        if formattedLength(of: (decoded as! Date).timeIntervalSinceReferenceDate) > DBL_DECIMAL_DIG + 2 {\n          let adjustedTimeIntervalSinceReferenceDate: (Date) -> Double = { date in\n              let adjustment = pow(10, Double(DBL_DECIMAL_DIG))\n              return Double(floor(adjustment * date.timeIntervalSinceReferenceDate).rounded() / adjustment)\n          }\n\n          let decodedAprox = adjustedTimeIntervalSinceReferenceDate(decoded as! Date)\n          let valueAprox = adjustedTimeIntervalSinceReferenceDate(value as! Date)\n          XCTAssertEqual(decodedAprox, valueAprox, \"\\(T.self) did not round-trip to an equal value after DBL_DECIMAL_DIG adjustment \\(decodedAprox) != \\(valueAprox).\")\n          return\n        }\n\n        XCTAssertEqual(decoded, value, \"\\(T.self) did not round-trip to an equal value. \\((decoded as! Date).timeIntervalSinceReferenceDate) != \\((value as! Date).timeIntervalSinceReferenceDate)\")\n      } catch {\n        XCTAssertThrowsError(\"Failed to decode \\(T.self) from JSON: \\(error)\")\n      }\n    }\n\n    // Test the above `snprintf` edge case evaluation with a known triggering case\n    let knownBadDate = Date(timeIntervalSinceReferenceDate: 0.0021413276231263384)\n    try localTestRoundTrip(of: knownBadDate)\n\n    try localTestRoundTrip(of: Date())\n\n    // Optional dates should encode the same way.\n    try localTestRoundTrip(of: Optional(Date()))\n  }\n    #endif\n\n  func testEncodingDateSecondsSince1970() {\n    // Cannot encode an arbitrary number of seconds since we've lost precision since 1970.\n    let seconds = 1000.0\n    let expectedJSON = \"1000\".data(using: .utf8)!\n\n    _testRoundTrip(of: Date(timeIntervalSince1970: seconds),\n                   expectedJSON: expectedJSON,\n                   dateEncodingStrategy: .secondsSince1970,\n                   dateDecodingStrategy: .secondsSince1970)\n\n    // Optional dates should encode the same way.\n    _testRoundTrip(of: Optional(Date(timeIntervalSince1970: seconds)),\n                   expectedJSON: expectedJSON,\n                   dateEncodingStrategy: .secondsSince1970,\n                   dateDecodingStrategy: .secondsSince1970)\n  }\n\n  func testEncodingDateMillisecondsSince1970() {\n    // Cannot encode an arbitrary number of seconds since we've lost precision since 1970.\n    let seconds = 1000.0\n    let expectedJSON = \"1000000\".data(using: .utf8)!\n\n    _testRoundTrip(of: Date(timeIntervalSince1970: seconds),\n                   expectedJSON: expectedJSON,\n                   dateEncodingStrategy: .millisecondsSince1970,\n                   dateDecodingStrategy: .millisecondsSince1970)\n\n    // Optional dates should encode the same way.\n    _testRoundTrip(of: Optional(Date(timeIntervalSince1970: seconds)),\n                   expectedJSON: expectedJSON,\n                   dateEncodingStrategy: .millisecondsSince1970,\n                   dateDecodingStrategy: .millisecondsSince1970)\n  }\n\n  func testEncodingDateISO8601() {\n    if #available(OSX 10.12, iOS 10.0, watchOS 3.0, tvOS 10.0, *) {\n      let formatter = ISO8601DateFormatter()\n      formatter.formatOptions = .withInternetDateTime\n\n      let timestamp = Date(timeIntervalSince1970: 1000)\n      let expectedJSON = \"\\\"\\(formatter.string(from: timestamp))\\\"\".data(using: .utf8)!\n\n      _testRoundTrip(of: timestamp,\n                     expectedJSON: expectedJSON,\n                     dateEncodingStrategy: .iso8601,\n                     dateDecodingStrategy: .iso8601)\n\n      // Optional dates should encode the same way.\n      _testRoundTrip(of: Optional(timestamp),\n                     expectedJSON: expectedJSON,\n                     dateEncodingStrategy: .iso8601,\n                     dateDecodingStrategy: .iso8601)\n    }\n  }\n\n  func testEncodingDateFormatted() {\n    let formatter = DateFormatter()\n    formatter.dateStyle = .full\n    formatter.timeStyle = .full\n\n    let timestamp = Date(timeIntervalSince1970: 1000)\n    let expectedJSON = \"\\\"\\(formatter.string(from: timestamp))\\\"\".data(using: .utf8)!\n\n    _testRoundTrip(of: timestamp,\n                   expectedJSON: expectedJSON,\n                   dateEncodingStrategy: .formatted(formatter),\n                   dateDecodingStrategy: .formatted(formatter))\n\n    // Optional dates should encode the same way.\n    _testRoundTrip(of: Optional(timestamp),\n                   expectedJSON: expectedJSON,\n                   dateEncodingStrategy: .formatted(formatter),\n                   dateDecodingStrategy: .formatted(formatter))\n  }\n\n  func testEncodingDateCustom() {\n    let timestamp = Date()\n\n    // We'll encode a number instead of a date.\n    let encode = { (_ data: Date, _ encoder: Encoder) throws -> Void in\n      var container = encoder.singleValueContainer()\n      try container.encode(42)\n    }\n    let decode = { (_: Decoder) throws -> Date in return timestamp }\n\n    let expectedJSON = \"42\".data(using: .utf8)!\n    _testRoundTrip(of: timestamp,\n                   expectedJSON: expectedJSON,\n                   dateEncodingStrategy: .custom(encode),\n                   dateDecodingStrategy: .custom(decode))\n\n    // Optional dates should encode the same way.\n    _testRoundTrip(of: Optional(timestamp),\n                   expectedJSON: expectedJSON,\n                   dateEncodingStrategy: .custom(encode),\n                   dateDecodingStrategy: .custom(decode))\n  }\n\n  func testEncodingDateCustomEmpty() {\n    let timestamp = Date()\n\n    // Encoding nothing should encode an empty keyed container ({}).\n    let encode = { (_: Date, _: Encoder) throws -> Void in }\n    let decode = { (_: Decoder) throws -> Date in return timestamp }\n\n    let expectedJSON = \"{}\".data(using: .utf8)!\n    _testRoundTrip(of: timestamp,\n                   expectedJSON: expectedJSON,\n                   dateEncodingStrategy: .custom(encode),\n                   dateDecodingStrategy: .custom(decode))\n\n    // Optional dates should encode the same way.\n    _testRoundTrip(of: Optional(timestamp),\n                   expectedJSON: expectedJSON,\n                   dateEncodingStrategy: .custom(encode),\n                   dateDecodingStrategy: .custom(decode))\n  }\n\n  // MARK: - Data Strategy Tests\n  /*func testEncodingData() {\n    let data = Data([0xDE, 0xAD, 0xBE, 0xEF])\n\n    let expectedJSON = \"[222,173,190,239]\".data(using: .utf8)!\n    _testRoundTrip(of: data,\n                   expectedJSON: expectedJSON,\n                   dataEncodingStrategy: .deferredToData,\n                   dataDecodingStrategy: .deferredToData)\n\n    // Optional data should encode the same way.\n    _testRoundTrip(of: Optional(data),\n                   expectedJSON: expectedJSON,\n                   dataEncodingStrategy: .deferredToData,\n                   dataDecodingStrategy: .deferredToData)\n  }*/\n\n  func testEncodingDataBase64() {\n    let data = Data([0xDE, 0xAD, 0xBE, 0xEF])\n\n    let expectedJSON = \"\\\"3q2+7w==\\\"\".data(using: .utf8)!\n    _testRoundTrip(of: data, expectedJSON: expectedJSON)\n\n    // Optional data should encode the same way.\n    _testRoundTrip(of: Optional(data), expectedJSON: expectedJSON)\n  }\n/*\n  func testEncodingDataCustom() {\n    // We'll encode a number instead of data.\n    let encode = { (_ data: Data, _ encoder: Encoder) throws -> Void in\n      var container = encoder.singleValueContainer()\n      try container.encode(42)\n    }\n    let decode = { (_: Decoder) throws -> Data in return Data() }\n\n    let expectedJSON = \"42\".data(using: .utf8)!\n    _testRoundTrip(of: Data(),\n                   expectedJSON: expectedJSON,\n                   dataEncodingStrategy: .custom(encode),\n                   dataDecodingStrategy: .custom(decode))\n\n    // Optional data should encode the same way.\n    _testRoundTrip(of: Optional(Data()),\n                   expectedJSON: expectedJSON,\n                   dataEncodingStrategy: .custom(encode),\n                   dataDecodingStrategy: .custom(decode))\n  }\n\n  func testEncodingDataCustomEmpty() {\n    // Encoding nothing should encode an empty keyed container ({}).\n    let encode = { (_: Data, _: Encoder) throws -> Void in }\n    let decode = { (_: Decoder) throws -> Data in return Data() }\n\n    let expectedJSON = \"{}\".data(using: .utf8)!\n    _testRoundTrip(of: Data(),\n                   expectedJSON: expectedJSON,\n                   dataEncodingStrategy: .custom(encode),\n                   dataDecodingStrategy: .custom(decode))\n\n    // Optional Data should encode the same way.\n    _testRoundTrip(of: Optional(Data()),\n                   expectedJSON: expectedJSON,\n                   dataEncodingStrategy: .custom(encode),\n                   dataDecodingStrategy: .custom(decode))\n  }*/\n\n  // MARK: - Non-Conforming Floating Point Strategy Tests\n  func testEncodingNonConformingFloats() {\n    _testEncodeFailure(of: Float.infinity)\n    _testEncodeFailure(of: Float.infinity)\n    _testEncodeFailure(of: -Float.infinity)\n    _testEncodeFailure(of: Float.nan)\n\n    _testEncodeFailure(of: Double.infinity)\n    _testEncodeFailure(of: -Double.infinity)\n    _testEncodeFailure(of: Double.nan)\n\n    // Optional Floats/Doubles should encode the same way.\n    _testEncodeFailure(of: Float.infinity)\n    _testEncodeFailure(of: -Float.infinity)\n    _testEncodeFailure(of: Float.nan)\n\n    _testEncodeFailure(of: Double.infinity)\n    _testEncodeFailure(of: -Double.infinity)\n    _testEncodeFailure(of: Double.nan)\n  }\n/*\n  func testEncodingNonConformingFloatStrings() {\n    let encodingStrategy: JSONEncoder.NonConformingFloatEncodingStrategy = .convertToString(positiveInfinity: \"INF\", negativeInfinity: \"-INF\", nan: \"NaN\")\n    let decodingStrategy: JSONDecoder.NonConformingFloatDecodingStrategy = .convertFromString(positiveInfinity: \"INF\", negativeInfinity: \"-INF\", nan: \"NaN\")\n\n    _testRoundTrip(of: Float.infinity,\n                   expectedJSON: \"\\\"INF\\\"\".data(using: .utf8)!,\n                   nonConformingFloatEncodingStrategy: encodingStrategy,\n                   nonConformingFloatDecodingStrategy: decodingStrategy)\n    _testRoundTrip(of: -Float.infinity,\n                   expectedJSON: \"\\\"-INF\\\"\".data(using: .utf8)!,\n                   nonConformingFloatEncodingStrategy: encodingStrategy,\n                   nonConformingFloatDecodingStrategy: decodingStrategy)\n\n    // Since Float.nan != Float.nan, we have to use a placeholder that'll encode NaN but actually round-trip.\n    _testRoundTrip(of: FloatNaNPlaceholder(),\n                   expectedJSON: \"\\\"NaN\\\"\".data(using: .utf8)!,\n                   nonConformingFloatEncodingStrategy: encodingStrategy,\n                   nonConformingFloatDecodingStrategy: decodingStrategy)\n\n    _testRoundTrip(of: Double.infinity,\n                   expectedJSON: \"\\\"INF\\\"\".data(using: .utf8)!,\n                   nonConformingFloatEncodingStrategy: encodingStrategy,\n                   nonConformingFloatDecodingStrategy: decodingStrategy)\n    _testRoundTrip(of: -Double.infinity,\n                   expectedJSON: \"\\\"-INF\\\"\".data(using: .utf8)!,\n                   nonConformingFloatEncodingStrategy: encodingStrategy,\n                   nonConformingFloatDecodingStrategy: decodingStrategy)\n\n    // Since Double.nan != Double.nan, we have to use a placeholder that'll encode NaN but actually round-trip.\n    _testRoundTrip(of: DoubleNaNPlaceholder(),\n                   expectedJSON: \"\\\"NaN\\\"\".data(using: .utf8)!,\n                   nonConformingFloatEncodingStrategy: encodingStrategy,\n                   nonConformingFloatDecodingStrategy: decodingStrategy)\n\n    // Optional Floats and Doubles should encode the same way.\n    _testRoundTrip(of: Optional(Float.infinity),\n                   expectedJSON: \"\\\"INF\\\"\".data(using: .utf8)!,\n                   nonConformingFloatEncodingStrategy: encodingStrategy,\n                   nonConformingFloatDecodingStrategy: decodingStrategy)\n    _testRoundTrip(of: Optional(-Float.infinity),\n                   expectedJSON: \"\\\"-INF\\\"\".data(using: .utf8)!,\n                   nonConformingFloatEncodingStrategy: encodingStrategy,\n                   nonConformingFloatDecodingStrategy: decodingStrategy)\n    _testRoundTrip(of: Optional(Double.infinity),\n                   expectedJSON: \"\\\"INF\\\"\".data(using: .utf8)!,\n                   nonConformingFloatEncodingStrategy: encodingStrategy,\n                   nonConformingFloatDecodingStrategy: decodingStrategy)\n    _testRoundTrip(of: Optional(-Double.infinity),\n                   expectedJSON: \"\\\"-INF\\\"\".data(using: .utf8)!,\n                   nonConformingFloatEncodingStrategy: encodingStrategy,\n                   nonConformingFloatDecodingStrategy: decodingStrategy)\n  }\n*/\n  // MARK: - Key Strategy Tests\n  private struct EncodeMe: Encodable {\n    var keyName: String\n    func encode(to coder: Encoder) throws {\n      var c = coder.container(keyedBy: _TestKey.self)\n      try c.encode(\"test\", forKey: _TestKey(stringValue: keyName)!)\n    }\n  }\n/*\n  func testEncodingKeyStrategySnake() {\n    let toSnakeCaseTests = [\n      (\"simpleOneTwo\", \"simple_one_two\"),\n      (\"myURL\", \"my_url\"),\n      (\"singleCharacterAtEndX\", \"single_character_at_end_x\"),\n      (\"thisIsAnXMLProperty\", \"this_is_an_xml_property\"),\n      (\"single\", \"single\"), // no underscore\n      (\"\", \"\"), // do not die on empty string\n      (\"a\", \"a\"), // single character\n      (\"aA\", \"a_a\"), // two characters\n      (\"version4Thing\", \"version4_thing\"), // numerics\n      (\"partCAPS\", \"part_caps\"), // only insert underscore before first all caps\n      (\"partCAPSLowerAGAIN\", \"part_caps_lower_again\"), // switch back and forth caps.\n      (\"manyWordsInThisThing\", \"many_words_in_this_thing\"), // simple lowercase + underscore + more\n      (\"asdfĆqer\", \"asdf_ćqer\"),\n      (\"already_snake_case\", \"already_snake_case\"),\n      (\"dataPoint22\", \"data_point22\"),\n      (\"dataPoint22Word\", \"data_point22_word\"),\n      (\"_oneTwoThree\", \"_one_two_three\"),\n      (\"oneTwoThree_\", \"one_two_three_\"),\n      (\"__oneTwoThree\", \"__one_two_three\"),\n      (\"oneTwoThree__\", \"one_two_three__\"),\n      (\"_oneTwoThree_\", \"_one_two_three_\"),\n      (\"__oneTwoThree\", \"__one_two_three\"),\n      (\"__oneTwoThree__\", \"__one_two_three__\"),\n      (\"_test\", \"_test\"),\n      (\"_test_\", \"_test_\"),\n      (\"__test\", \"__test\"),\n      (\"test__\", \"test__\"),\n      (\"m͉̟̹y̦̳G͍͚͎̳r̤͉̤͕ͅea̲͕t͇̥̼͖U͇̝̠R͙̻̥͓̣L̥̖͎͓̪̫ͅR̩͖̩eq͈͓u̞e̱s̙t̤̺ͅ\", \"m͉̟̹y̦̳_g͍͚͎̳r̤͉̤͕ͅea̲͕t͇̥̼͖_u͇̝̠r͙̻̥͓̣l̥̖͎͓̪̫ͅ_r̩͖̩eq͈͓u̞e̱s̙t̤̺ͅ\"), // because Itai wanted to test this\n      (\"🐧🐟\", \"🐧🐟\") // fishy emoji example?\n    ]\n\n    for test in toSnakeCaseTests {\n      let expected = \"{\\\"\\(test.1)\\\":\\\"test\\\"}\"\n      let encoded = EncodeMe(keyName: test.0)\n\n      let encoder = ParseEncoder()\n      encoder.keyEncodingStrategy = .convertToSnakeCase\n      let resultData = try! encoder.encode(encoded)\n      let resultString = String(bytes: resultData, encoding: .utf8)\n\n      XCTAssertEqual(expected, resultString)\n    }\n  }\n\n  func testEncodingKeyStrategyCustom() {\n    let expected = \"{\\\"QQQhello\\\":\\\"test\\\"}\"\n    let encoded = EncodeMe(keyName: \"hello\")\n\n    let encoder = ParseEncoder()\n    let customKeyConversion = { (_ path: [CodingKey]) -> CodingKey in\n      let key = _TestKey(stringValue: \"QQQ\" + path.last!.stringValue)!\n      return key\n    }\n    encoder.keyEncodingStrategy = .custom(customKeyConversion)\n    let resultData = try! encoder.encode(encoded)\n    let resultString = String(bytes: resultData, encoding: .utf8)\n\n    XCTAssertEqual(expected, resultString)\n  }\n\n  func testEncodingDictionaryStringKeyConversionUntouched() {\n    let expected = \"{\\\"leaveMeAlone\\\":\\\"test\\\"}\"\n    let toEncode: [String: String] = [\"leaveMeAlone\": \"test\"]\n\n    let encoder = ParseEncoder()\n    encoder.keyEncodingStrategy = .convertToSnakeCase\n    let resultData = try! encoder.encode(toEncode)\n    let resultString = String(bytes: resultData, encoding: .utf8)\n\n    XCTAssertEqual(expected, resultString)\n  }\n\n  private struct EncodeFailure: Encodable {\n    var someValue: Double\n  }\n\n  private struct EncodeFailureNested: Encodable {\n    var nestedValue: EncodeFailure\n  }\n\n  func testEncodingDictionaryFailureKeyPath() {\n    let toEncode: [String: EncodeFailure] = [\"key\": EncodeFailure(someValue: Double.nan)]\n\n    let encoder = ParseEncoder()\n    encoder.keyEncodingStrategy = .convertToSnakeCase\n    do {\n      _ = try encoder.encode(toEncode)\n    } catch EncodingError.invalidValue(_, let context) {\n      XCTAssertEqual(2, context.codingPath.count)\n      XCTAssertEqual(\"key\", context.codingPath[0].stringValue)\n      XCTAssertEqual(\"someValue\", context.codingPath[1].stringValue)\n    } catch {\n      XCTAssertThrowsError(\"Unexpected error: \\(String(describing: error))\")\n    }\n  }\n\n  func testEncodingDictionaryFailureKeyPathNested() {\n    let toEncode: [String: [String: EncodeFailureNested]] = [\"key\": [\"sub_key\": EncodeFailureNested(nestedValue: EncodeFailure(someValue: Double.nan))]]\n\n    let encoder = ParseEncoder()\n    encoder.keyEncodingStrategy = .convertToSnakeCase\n    do {\n      _ = try encoder.encode(toEncode)\n    } catch EncodingError.invalidValue(_, let context) {\n      XCTAssertEqual(4, context.codingPath.count)\n      XCTAssertEqual(\"key\", context.codingPath[0].stringValue)\n      XCTAssertEqual(\"sub_key\", context.codingPath[1].stringValue)\n      XCTAssertEqual(\"nestedValue\", context.codingPath[2].stringValue)\n      XCTAssertEqual(\"someValue\", context.codingPath[3].stringValue)\n    } catch {\n      XCTAssertThrowsError(\"Unexpected error: \\(String(describing: error))\")\n    }\n  }\n*/\n  private struct EncodeNested: Encodable {\n    let nestedValue: EncodeMe\n  }\n\n  private struct EncodeNestedNested: Encodable {\n    let outerValue: EncodeNested\n  }\n/*\n  func testEncodingKeyStrategyPath() {\n    // Make sure a more complex path shows up the way we want\n    // Make sure the path reflects keys in the Swift, not the resulting ones in the JSON\n    let expected = \"{\\\"QQQouterValue\\\":{\\\"QQQnestedValue\\\":{\\\"QQQhelloWorld\\\":\\\"test\\\"}}}\"\n    let encoded = EncodeNestedNested(outerValue: EncodeNested(nestedValue: EncodeMe(keyName: \"helloWorld\")))\n\n    let encoder = ParseEncoder()\n    var callCount = 0\n\n    let customKeyConversion = { (_ path: [CodingKey]) -> CodingKey in\n      // This should be called three times:\n      // 1. to convert 'outerValue' to something\n      // 2. to convert 'nestedValue' to something\n      // 3. to convert 'helloWorld' to something\n      callCount = callCount + 1\n\n      if path.count == 0 {\n        XCTAssertThrowsError(\"The path should always have at least one entry\")\n      } else if path.count == 1 {\n        XCTAssertEqual([\"outerValue\"], path.map { $0.stringValue })\n      } else if path.count == 2 {\n        XCTAssertEqual([\"outerValue\", \"nestedValue\"], path.map { $0.stringValue })\n      } else if path.count == 3 {\n        XCTAssertEqual([\"outerValue\", \"nestedValue\", \"helloWorld\"], path.map { $0.stringValue })\n      } else {\n        XCTAssertThrowsError(\"The path mysteriously had more entries\")\n      }\n\n      let key = _TestKey(stringValue: \"QQQ\" + path.last!.stringValue)!\n      return key\n    }\n    encoder.keyEncodingStrategy = .custom(customKeyConversion)\n    let resultData = try! encoder.encode(encoded)\n    let resultString = String(bytes: resultData, encoding: .utf8)\n\n    XCTAssertEqual(expected, resultString)\n    XCTAssertEqual(3, callCount)\n  }\n*/\n    \n    \n/*\n  func testDecodingKeyStrategyCamelGenerated() {\n    let encoded = DecodeMe3(thisIsCamelCase: \"test\")\n    let encoder = ParseEncoder()\n    encoder.keyEncodingStrategy = .convertToSnakeCase\n    let resultData = try! encoder.encode(encoded)\n    let resultString = String(bytes: resultData, encoding: .utf8)\n    XCTAssertEqual(\"{\\\"this_is_camel_case\\\":\\\"test\\\"}\", resultString)\n  }\n\n  func testKeyStrategySnakeGeneratedAndCustom() {\n    // Test that this works with a struct that has automatically generated keys\n    struct DecodeMe4: Codable {\n        var thisIsCamelCase: String\n        var thisIsCamelCaseToo: String\n        private enum CodingKeys: String, CodingKey {\n            case thisIsCamelCase = \"fooBar\"\n            case thisIsCamelCaseToo\n        }\n    }\n\n    // Decoding\n    let input = \"{\\\"foo_bar\\\":\\\"test\\\",\\\"this_is_camel_case_too\\\":\\\"test2\\\"}\".data(using: .utf8)!\n    let decoder = JSONDecoder()\n    decoder.keyDecodingStrategy = .convertFromSnakeCase\n    let decodingResult = try! decoder.decode(DecodeMe4.self, from: input)\n\n    XCTAssertEqual(\"test\", decodingResult.thisIsCamelCase)\n    XCTAssertEqual(\"test2\", decodingResult.thisIsCamelCaseToo)\n\n    // Encoding\n    let encoded = DecodeMe4(thisIsCamelCase: \"test\", thisIsCamelCaseToo: \"test2\")\n    let encoder = ParseEncoder()\n    encoder.keyEncodingStrategy = .convertToSnakeCase\n    let encodingResultData = try! encoder.encode(encoded)\n    let encodingResultString = String(bytes: encodingResultData, encoding: .utf8)\n    XCTAssertEqual(\"{\\\"foo_bar\\\":\\\"test\\\",\\\"this_is_camel_case_too\\\":\\\"test2\\\"}\", encodingResultString)\n  }\n\n  func testKeyStrategyDuplicateKeys() {\n    // This test is mostly to make sure we do not assert on duplicate keys\n    struct DecodeMe5: Codable {\n        var oneTwo: String\n        var numberOfKeys: Int\n\n        enum CodingKeys: String, CodingKey {\n          case oneTwo\n          case oneTwoThree\n        }\n\n        init() {\n            oneTwo = \"test\"\n            numberOfKeys = 0\n        }\n\n        init(from decoder: Decoder) throws {\n          let container = try decoder.container(keyedBy: CodingKeys.self)\n          oneTwo = try container.decode(String.self, forKey: .oneTwo)\n          numberOfKeys = container.allKeys.count\n        }\n\n        func encode(to encoder: Encoder) throws {\n          var container = encoder.container(keyedBy: CodingKeys.self)\n          try container.encode(oneTwo, forKey: .oneTwo)\n          try container.encode(\"test2\", forKey: .oneTwoThree)\n        }\n    }\n\n    let customKeyConversion = { (_ path: [CodingKey]) -> CodingKey in\n      // All keys are the same!\n      return _TestKey(stringValue: \"oneTwo\")!\n    }\n\n    // Decoding\n    // This input has a dictionary with two keys, but only one will end up in the container\n    let input = \"{\\\"unused key 1\\\":\\\"test1\\\",\\\"unused key 2\\\":\\\"test2\\\"}\".data(using: .utf8)!\n    let decoder = JSONDecoder()\n    decoder.keyDecodingStrategy = .custom(customKeyConversion)\n\n    let decodingResult = try! decoder.decode(DecodeMe5.self, from: input)\n    // There will be only one result for oneTwo (the second one in the json)\n    XCTAssertEqual(1, decodingResult.numberOfKeys)\n\n    // Encoding\n    let encoded = DecodeMe5()\n    let encoder = ParseEncoder()\n    encoder.keyEncodingStrategy = .custom(customKeyConversion)\n    let decodingResultData = try! encoder.encode(encoded)\n    let decodingResultString = String(bytes: decodingResultData, encoding: .utf8)\n\n    // There will be only one value in the result (the second one encoded)\n    XCTAssertEqual(\"{\\\"oneTwo\\\":\\\"test2\\\"}\", decodingResultString)\n  }\n*/\n  // MARK: - Encoder Features\n  func testNestedContainerCodingPaths() {\n    let encoder = ParseEncoder()\n    do {\n      _ = try encoder.encode(NestedContainersTestType())\n    } catch let error as NSError {\n      XCTAssertThrowsError(\"Caught error during encoding nested container types: \\(error)\")\n    }\n  }\n\n  func testSuperEncoderCodingPaths() {\n    let encoder = ParseEncoder()\n    do {\n      _ = try encoder.encode(NestedContainersTestType(testSuperEncoder: true))\n    } catch let error as NSError {\n      XCTAssertThrowsError(\"Caught error during encoding nested container types: \\(error)\")\n    }\n  }\n\n  func testInterceptDecimal() {\n    let expectedJSON = \"10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\".data(using: .utf8)!\n\n    // Want to make sure we write out a JSON number, not the keyed encoding here.\n    // 1e127 is too big to fit natively in a Double, too, so want to make sure it is encoded as a Decimal.\n    let decimal = Decimal(sign: .plus, exponent: 127, significand: Decimal(1))\n    _testRoundTrip(of: decimal, expectedJSON: expectedJSON)\n\n    // Optional Decimals should encode the same way.\n    _testRoundTrip(of: Optional(decimal), expectedJSON: expectedJSON)\n  }\n\n  func testInterceptURL() {\n    // Want to make sure JSONEncoder writes out single-value URLs, not the keyed encoding.\n    let expectedJSON = \"\\\"http:\\\\/\\\\/swift.org\\\"\".data(using: .utf8)!\n    let url = URL(string: \"http://swift.org\")!\n    _testRoundTrip(of: url, expectedJSON: expectedJSON)\n\n    // Optional URLs should encode the same way.\n    _testRoundTrip(of: Optional(url), expectedJSON: expectedJSON)\n  }\n/*\n  func testInterceptURLWithoutEscapingOption() {\n      // Want to make sure JSONEncoder writes out single-value URLs, not the keyed encoding.\n      let expectedJSON = \"\\\"http://swift.org\\\"\".data(using: .utf8)!\n      let url = URL(string: \"http://swift.org\")!\n      _testRoundTrip(of: url, expectedJSON: expectedJSON, outputFormatting: [.withoutEscapingSlashes])\n\n      // Optional URLs should encode the same way.\n      _testRoundTrip(of: Optional(url), expectedJSON: expectedJSON, outputFormatting: [.withoutEscapingSlashes])\n  }*/\n\n  // MARK: - Type coercion\n  func testTypeCoercion() {\n    _testRoundTripTypeCoercionFailure(of: [false, true], as: [Int].self)\n    _testRoundTripTypeCoercionFailure(of: [false, true], as: [Int8].self)\n    _testRoundTripTypeCoercionFailure(of: [false, true], as: [Int16].self)\n    _testRoundTripTypeCoercionFailure(of: [false, true], as: [Int32].self)\n    _testRoundTripTypeCoercionFailure(of: [false, true], as: [Int64].self)\n    _testRoundTripTypeCoercionFailure(of: [false, true], as: [UInt].self)\n    _testRoundTripTypeCoercionFailure(of: [false, true], as: [UInt8].self)\n    _testRoundTripTypeCoercionFailure(of: [false, true], as: [UInt16].self)\n    _testRoundTripTypeCoercionFailure(of: [false, true], as: [UInt32].self)\n    _testRoundTripTypeCoercionFailure(of: [false, true], as: [UInt64].self)\n    _testRoundTripTypeCoercionFailure(of: [false, true], as: [Float].self)\n    _testRoundTripTypeCoercionFailure(of: [false, true], as: [Double].self)\n    _testRoundTripTypeCoercionFailure(of: [0, 1] as [Int], as: [Bool].self)\n    _testRoundTripTypeCoercionFailure(of: [0, 1] as [Int8], as: [Bool].self)\n    _testRoundTripTypeCoercionFailure(of: [0, 1] as [Int16], as: [Bool].self)\n    _testRoundTripTypeCoercionFailure(of: [0, 1] as [Int32], as: [Bool].self)\n    _testRoundTripTypeCoercionFailure(of: [0, 1] as [Int64], as: [Bool].self)\n    _testRoundTripTypeCoercionFailure(of: [0, 1] as [UInt], as: [Bool].self)\n    _testRoundTripTypeCoercionFailure(of: [0, 1] as [UInt8], as: [Bool].self)\n    _testRoundTripTypeCoercionFailure(of: [0, 1] as [UInt16], as: [Bool].self)\n    _testRoundTripTypeCoercionFailure(of: [0, 1] as [UInt32], as: [Bool].self)\n    _testRoundTripTypeCoercionFailure(of: [0, 1] as [UInt64], as: [Bool].self)\n    _testRoundTripTypeCoercionFailure(of: [0.0, 1.0] as [Float], as: [Bool].self)\n    _testRoundTripTypeCoercionFailure(of: [0.0, 1.0] as [Double], as: [Bool].self)\n  }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n  func testDecodingConcreteTypeParameter() {\n      let encoder = ParseEncoder()\n      guard let json = try? encoder.encode(Employee.testValue) else {\n          XCTAssertThrowsError(\"Unable to encode Employee.\")\n          return\n      }\n\n      let decoder = JSONDecoder()\n      guard let decoded = try? decoder.decode(Employee.self as Person.Type, from: json) else {\n          XCTAssertThrowsError(\"Failed to decode Employee as Person from JSON.\")\n          return\n      }\n    XCTAssertTrue(type(of: decoded) == Employee.self, \"Expected decoded value to be of type Employee; got \\(type(of: decoded)) instead.\")\n  }\n    #endif\n\n  // MARK: - Encoder State\n  // SR-6078\n  func testEncoderStateThrowOnEncode() {\n    struct ReferencingEncoderWrapper<T : Encodable>: Encodable {\n      let value: T\n      init(_ value: T) { self.value = value }\n\n      func encode(to encoder: Encoder) throws {\n        // This approximates a subclass calling into its superclass, where the superclass encodes a value that might throw.\n        // The key here is that getting the superEncoder creates a referencing encoder.\n        var container = encoder.unkeyedContainer()\n        let superEncoder = container.superEncoder()\n\n        // Pushing a nested container on leaves the referencing encoder with multiple containers.\n        var nestedContainer = superEncoder.unkeyedContainer()\n        try nestedContainer.encode(value)\n      }\n    }\n\n    // The structure that would be encoded here looks like\n    //\n    //   [[[Float.infinity]]]\n    //\n    // The wrapper asks for an unkeyed container ([^]), gets a super encoder, and creates a nested container into that ([[^]]).\n    // We then encode an array into that ([[[^]]]), which happens to be a value that causes us to throw an error.\n    //\n    // The issue at hand reproduces when you have a referencing encoder (superEncoder() creates one) that has a container on the stack (unkeyedContainer() adds one) that encodes a value going through box_() (Array does that) that encodes something which throws (Float.infinity does that).\n    // When reproducing, this will cause a test failure via fatalError().\n    _ = try? ParseEncoder().encode(ReferencingEncoderWrapper([Float.infinity]))\n  }\n\n  func testEncoderStateThrowOnEncodeCustomDate() {\n    // This test is identical to testEncoderStateThrowOnEncode, except throwing via a custom Date closure.\n    struct ReferencingEncoderWrapper<T : Encodable>: Encodable {\n      let value: T\n      init(_ value: T) { self.value = value }\n      func encode(to encoder: Encoder) throws {\n        var container = encoder.unkeyedContainer()\n        let superEncoder = container.superEncoder()\n        var nestedContainer = superEncoder.unkeyedContainer()\n        try nestedContainer.encode(value)\n      }\n    }\n\n    // The closure needs to push a container before throwing an error to trigger.\n    let encoder = ParseEncoder(dateEncodingStrategy: .custom({ _, encoder in\n        _ = encoder.unkeyedContainer()\n        enum CustomError: Error { case foo }\n        throw CustomError.foo\n    }))\n\n    _ = try? encoder.encode(ReferencingEncoderWrapper(Date()))\n  }\n/*\n  func testEncoderStateThrowOnEncodeCustomData() {\n    // This test is identical to testEncoderStateThrowOnEncode, except throwing via a custom Data closure.\n    struct ReferencingEncoderWrapper<T : Encodable>: Encodable {\n      let value: T\n      init(_ value: T) { self.value = value }\n      func encode(to encoder: Encoder) throws {\n        var container = encoder.unkeyedContainer()\n        let superEncoder = container.superEncoder()\n        var nestedContainer = superEncoder.unkeyedContainer()\n        try nestedContainer.encode(value)\n      }\n    }\n\n    // The closure needs to push a container before throwing an error to trigger.\n    let encoder = ParseEncoder(dateEncodingStrategy: .custom({ _, encoder in\n        _ = encoder.unkeyedContainer()\n        enum CustomError: Error { case foo }\n        throw CustomError.foo\n    }))\n\n    _ = try? encoder.encode(ReferencingEncoderWrapper(Data()))\n  }*/\n\n  // MARK: - Helper Functions\n  private var _jsonEmptyDictionary: Data {\n    return \"{}\".data(using: .utf8)!\n  }\n\n  private func _testEncodeFailure<T: Encodable>(of value: T) {\n    do {\n      _ = try ParseEncoder().encode(value)\n      XCTAssertThrowsError(\"Encode of top-level \\(T.self) was expected to fail.\")\n    } catch {}\n  }\n\n  private func _testRoundTrip<T>(of value: T,\n                                 expectedJSON json: Data? = nil,\n                                 outputFormatting: JSONEncoder.OutputFormatting = [],\n                                 dateEncodingStrategy: JSONEncoder.DateEncodingStrategy = .deferredToDate,\n                                 dateDecodingStrategy: JSONDecoder.DateDecodingStrategy = .deferredToDate,\n                                 dataEncodingStrategy: JSONEncoder.DataEncodingStrategy = .base64,\n                                 dataDecodingStrategy: JSONDecoder.DataDecodingStrategy = .base64,\n                                 keyEncodingStrategy: JSONEncoder.KeyEncodingStrategy = .useDefaultKeys,\n                                 keyDecodingStrategy: JSONDecoder.KeyDecodingStrategy = .useDefaultKeys,\n                                 nonConformingFloatEncodingStrategy: JSONEncoder.NonConformingFloatEncodingStrategy = .throw,\n                                 nonConformingFloatDecodingStrategy: JSONDecoder.NonConformingFloatDecodingStrategy = .throw) where T: Codable, T: Equatable {\n    var payload: Data! = nil\n    do {\n        let encoder = ParseEncoder(dateEncodingStrategy: dateEncodingStrategy)\n      /*encoder.outputFormatting = outputFormatting\n      encoder.dateEncodingStrategy = dateEncodingStrategy\n      encoder.dataEncodingStrategy = dataEncodingStrategy\n      encoder.nonConformingFloatEncodingStrategy = nonConformingFloatEncodingStrategy\n      encoder.keyEncodingStrategy = keyEncodingStrategy*/\n      payload = try encoder.encode(value)\n    } catch {\n      XCTAssertThrowsError(\"Failed to encode \\(T.self) to JSON: \\(error)\")\n    }\n\n    if let expectedJSON = json {\n        XCTAssertEqual(expectedJSON, payload, \"Produced JSON not identical to expected JSON.\")\n    }\n\n    do {\n      let decoder = JSONDecoder()\n      decoder.dateDecodingStrategy = dateDecodingStrategy\n      /*decoder.dataDecodingStrategy = dataDecodingStrategy\n      decoder.nonConformingFloatDecodingStrategy = nonConformingFloatDecodingStrategy\n      decoder.keyDecodingStrategy = keyDecodingStrategy*/\n      let decoded = try decoder.decode(T.self, from: payload)\n      XCTAssertEqual(decoded, value, \"\\(T.self) did not round-trip to an equal value.\")\n    } catch {\n      XCTAssertThrowsError(\"Failed to decode \\(T.self) from JSON: \\(error)\")\n    }\n  }\n\n    private func _testRoundTripTypeCoercionFailure<T, U>(of value: T, as type: U.Type) where T: Codable, U: Codable {\n        do {\n            let data = try ParseEncoder().encode(value)\n            _ = try JSONDecoder().decode(U.self, from: data)\n            XCTAssertThrowsError(\"Coercion from \\(T.self) to \\(U.self) was expected to fail.\")\n        } catch {}\n    }\n}\n\n// MARK: - Helper Global Functions\nfunc XCTAssertEqualPaths(_ lhs: [CodingKey], _ rhs: [CodingKey], _ prefix: String) {\n  if lhs.count != rhs.count {\n    XCTAssertThrowsError(\"\\(prefix) [CodingKey].count mismatch: \\(lhs.count) != \\(rhs.count)\")\n    return\n  }\n\n  for (key1, key2) in zip(lhs, rhs) {\n    switch (key1.intValue, key2.intValue) {\n    case (.none, .none): break\n    case (.some(let i1), .none):\n      XCTAssertThrowsError(\"\\(prefix) CodingKey.intValue mismatch: \\(type(of: key1))(\\(i1)) != nil\")\n      return\n    case (.none, .some(let i2)):\n      XCTAssertThrowsError(\"\\(prefix) CodingKey.intValue mismatch: nil != \\(type(of: key2))(\\(i2))\")\n      return\n    case (.some(let i1), .some(let i2)):\n        guard i1 == i2 else {\n            XCTAssertThrowsError(\"\\(prefix) CodingKey.intValue mismatch: \\(type(of: key1))(\\(i1)) != \\(type(of: key2))(\\(i2))\")\n            return\n        }\n    }\n\n    XCTAssertEqual(key1.stringValue, key2.stringValue, \"\\(prefix) CodingKey.stringValue mismatch: \\(type(of: key1))('\\(key1.stringValue)') != \\(type(of: key2))('\\(key2.stringValue)')\")\n  }\n}\n\n// MARK: - Test Types\n\n// MARK: - Empty Types\nprivate struct EmptyStruct: Codable, Equatable {\n  static func ==(_ lhs: EmptyStruct, _ rhs: EmptyStruct) -> Bool {\n    return true\n  }\n}\n\nprivate class EmptyClass: Codable, Equatable {\n  static func ==(_ lhs: EmptyClass, _ rhs: EmptyClass) -> Bool {\n    return true\n  }\n}\n\n// MARK: - Single-Value Types\n/// A simple on-off switch type that encodes as a single Bool value.\nprivate enum Switch: Codable {\n  case off\n  case on\n\n  init(from decoder: Decoder) throws {\n    let container = try decoder.singleValueContainer()\n    switch try container.decode(Bool.self) {\n    case false: self = .off\n    case true:  self = .on\n    }\n  }\n\n  func encode(to encoder: Encoder) throws {\n    var container = encoder.singleValueContainer()\n    switch self {\n    case .off: try container.encode(false)\n    case .on:  try container.encode(true)\n    }\n  }\n}\n\n/// A simple timestamp type that encodes as a single Double value.\nprivate struct Timestamp: Codable, Equatable {\n  let value: Double\n\n  init(_ value: Double) {\n    self.value = value\n  }\n\n  init(from decoder: Decoder) throws {\n    let container = try decoder.singleValueContainer()\n    value = try container.decode(Double.self)\n  }\n\n  func encode(to encoder: Encoder) throws {\n    var container = encoder.singleValueContainer()\n    try container.encode(self.value)\n  }\n\n  static func ==(_ lhs: Timestamp, _ rhs: Timestamp) -> Bool {\n    return lhs.value == rhs.value\n  }\n}\n\n/// A simple referential counter type that encodes as a single Int value.\nfileprivate final class Counter: Codable, Equatable {\n  var count: Int = 0\n\n  init() {}\n\n  init(from decoder: Decoder) throws {\n    let container = try decoder.singleValueContainer()\n    count = try container.decode(Int.self)\n  }\n\n  func encode(to encoder: Encoder) throws {\n    var container = encoder.singleValueContainer()\n    try container.encode(self.count)\n  }\n\n  static func ==(_ lhs: Counter, _ rhs: Counter) -> Bool {\n    return lhs === rhs || lhs.count == rhs.count\n  }\n}\n\n// MARK: - Structured Types\n/// A simple address type that encodes as a dictionary of values.\nprivate struct Address: Codable, Equatable {\n  let street: String\n  let city: String\n  let state: String\n  let zipCode: Int\n  let country: String\n\n  init(street: String, city: String, state: String, zipCode: Int, country: String) {\n    self.street = street\n    self.city = city\n    self.state = state\n    self.zipCode = zipCode\n    self.country = country\n  }\n\n  static func ==(_ lhs: Address, _ rhs: Address) -> Bool {\n    return lhs.street == rhs.street &&\n           lhs.city == rhs.city &&\n           lhs.state == rhs.state &&\n           lhs.zipCode == rhs.zipCode &&\n           lhs.country == rhs.country\n  }\n\n  static var testValue: Address {\n    return Address(street: \"1 Infinite Loop\",\n                   city: \"Cupertino\",\n                   state: \"CA\",\n                   zipCode: 95014,\n                   country: \"United States\")\n  }\n}\n\n/// A simple person class that encodes as a dictionary of values.\nprivate class Person: Codable, Equatable {\n  let name: String\n  let email: String\n  let website: URL?\n\n  init(name: String, email: String, website: URL? = nil) {\n    self.name = name\n    self.email = email\n    self.website = website\n  }\n\n  func isEqual(_ other: Person) -> Bool {\n    return self.name == other.name &&\n           self.email == other.email &&\n           self.website == other.website\n  }\n\n  static func ==(_ lhs: Person, _ rhs: Person) -> Bool {\n    return lhs.isEqual(rhs)\n  }\n\n  class var testValue: Person {\n    return Person(name: \"Johnny Appleseed\", email: \"appleseed@apple.com\")\n  }\n}\n\n/// A class which shares its encoder and decoder with its superclass.\nprivate class Employee: Person {\n  let id: Int\n\n  init(name: String, email: String, website: URL? = nil, id: Int) {\n    self.id = id\n    super.init(name: name, email: email, website: website)\n  }\n\n  enum CodingKeys: String, CodingKey {\n    case id\n  }\n\n  required init(from decoder: Decoder) throws {\n    let container = try decoder.container(keyedBy: CodingKeys.self)\n    id = try container.decode(Int.self, forKey: .id)\n    try super.init(from: decoder)\n  }\n\n  override func encode(to encoder: Encoder) throws {\n    var container = encoder.container(keyedBy: CodingKeys.self)\n    try container.encode(id, forKey: .id)\n    try super.encode(to: encoder)\n  }\n\n  override func isEqual(_ other: Person) -> Bool {\n    if let employee = other as? Employee {\n      guard self.id == employee.id else { return false }\n    }\n\n    return super.isEqual(other)\n  }\n\n  override class var testValue: Employee {\n    return Employee(name: \"Johnny Appleseed\", email: \"appleseed@apple.com\", id: 42)\n  }\n}\n\n/// A simple company struct which encodes as a dictionary of nested values.\nprivate struct Company: Codable, Equatable {\n  let address: Address\n  var employees: [Employee]\n\n  init(address: Address, employees: [Employee]) {\n    self.address = address\n    self.employees = employees\n  }\n\n  static func ==(_ lhs: Company, _ rhs: Company) -> Bool {\n    return lhs.address == rhs.address && lhs.employees == rhs.employees\n  }\n\n  static var testValue: Company {\n    return Company(address: Address.testValue, employees: [Employee.testValue])\n  }\n}\n\n/// An enum type which decodes from Bool?.\nprivate enum EnhancedBool: Codable {\n  case `true`\n  case `false`\n  case fileNotFound\n\n  init(from decoder: Decoder) throws {\n    let container = try decoder.singleValueContainer()\n    if container.decodeNil() {\n      self = .fileNotFound\n    } else {\n      let value = try container.decode(Bool.self)\n      self = value ? .true : .false\n    }\n  }\n\n  func encode(to encoder: Encoder) throws {\n    var container = encoder.singleValueContainer()\n    switch self {\n    case .true: try container.encode(true)\n    case .false: try container.encode(false)\n    case .fileNotFound: try container.encodeNil()\n    }\n  }\n}\n\n/// A type which encodes as an array directly through a single value container.\nstruct Numbers: Codable, Equatable {\n  let values = [4, 8, 15, 16, 23, 42]\n\n  init() {}\n\n  init(from decoder: Decoder) throws {\n    let container = try decoder.singleValueContainer()\n    let decodedValues = try container.decode([Int].self)\n    guard decodedValues == values else {\n      throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: \"The Numbers are wrong!\"))\n    }\n  }\n\n  func encode(to encoder: Encoder) throws {\n    var container = encoder.singleValueContainer()\n    try container.encode(values)\n  }\n\n  static func ==(_ lhs: Numbers, _ rhs: Numbers) -> Bool {\n    return lhs.values == rhs.values\n  }\n\n  static var testValue: Numbers {\n    return Numbers()\n  }\n}\n\n/// A type which encodes as a dictionary directly through a single value container.\nfileprivate final class Mapping: Codable, Equatable {\n  let values: [String: URL]\n\n  init(values: [String: URL]) {\n    self.values = values\n  }\n\n  init(from decoder: Decoder) throws {\n    let container = try decoder.singleValueContainer()\n    values = try container.decode([String: URL].self)\n  }\n\n  func encode(to encoder: Encoder) throws {\n    var container = encoder.singleValueContainer()\n    try container.encode(values)\n  }\n\n  static func ==(_ lhs: Mapping, _ rhs: Mapping) -> Bool {\n    return lhs === rhs || lhs.values == rhs.values\n  }\n\n  static var testValue: Mapping {\n    return Mapping(values: [\"Apple\": URL(string: \"http://apple.com\")!,\n                            \"localhost\": URL(string: \"http://127.0.0.1\")!])\n  }\n}\n\nstruct NestedContainersTestType: Encodable {\n  let testSuperEncoder: Bool\n\n  init(testSuperEncoder: Bool = false) {\n    self.testSuperEncoder = testSuperEncoder\n  }\n\n  enum TopLevelCodingKeys: Int, CodingKey {\n    case a\n    case b\n    case c\n  }\n\n  enum IntermediateCodingKeys: Int, CodingKey {\n      case one\n      case two\n  }\n\n  func encode(to encoder: Encoder) throws {\n    if self.testSuperEncoder {\n      var topLevelContainer = encoder.container(keyedBy: TopLevelCodingKeys.self)\n      XCTAssertEqualPaths(encoder.codingPath, [], \"Top-level Encoder's codingPath changed.\")\n      XCTAssertEqualPaths(topLevelContainer.codingPath, [], \"New first-level keyed container has non-empty codingPath.\")\n\n      let superEncoder = topLevelContainer.superEncoder(forKey: .a)\n      XCTAssertEqualPaths(encoder.codingPath, [], \"Top-level Encoder's codingPath changed.\")\n      XCTAssertEqualPaths(topLevelContainer.codingPath, [], \"First-level keyed container's codingPath changed.\")\n      XCTAssertEqualPaths(superEncoder.codingPath, [TopLevelCodingKeys.a], \"New superEncoder had unexpected codingPath.\")\n      _testNestedContainers(in: superEncoder, baseCodingPath: [TopLevelCodingKeys.a])\n    } else {\n      _testNestedContainers(in: encoder, baseCodingPath: [])\n    }\n  }\n\n  func _testNestedContainers(in encoder: Encoder, baseCodingPath: [CodingKey]) {\n    XCTAssertEqualPaths(encoder.codingPath, baseCodingPath, \"New encoder has non-empty codingPath.\")\n\n    // codingPath should not change upon fetching a non-nested container.\n    var firstLevelContainer = encoder.container(keyedBy: TopLevelCodingKeys.self)\n    XCTAssertEqualPaths(encoder.codingPath, baseCodingPath, \"Top-level Encoder's codingPath changed.\")\n    XCTAssertEqualPaths(firstLevelContainer.codingPath, baseCodingPath, \"New first-level keyed container has non-empty codingPath.\")\n\n    // Nested Keyed Container\n    do {\n      // Nested container for key should have a new key pushed on.\n      var secondLevelContainer = firstLevelContainer.nestedContainer(keyedBy: IntermediateCodingKeys.self, forKey: .a)\n      XCTAssertEqualPaths(encoder.codingPath, baseCodingPath, \"Top-level Encoder's codingPath changed.\")\n      XCTAssertEqualPaths(firstLevelContainer.codingPath, baseCodingPath, \"First-level keyed container's codingPath changed.\")\n      XCTAssertEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.a], \"New second-level keyed container had unexpected codingPath.\")\n\n      // Inserting a keyed container should not change existing coding paths.\n      let thirdLevelContainerKeyed = secondLevelContainer.nestedContainer(keyedBy: IntermediateCodingKeys.self, forKey: .one)\n      XCTAssertEqualPaths(encoder.codingPath, baseCodingPath, \"Top-level Encoder's codingPath changed.\")\n      XCTAssertEqualPaths(firstLevelContainer.codingPath, baseCodingPath, \"First-level keyed container's codingPath changed.\")\n      XCTAssertEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.a], \"Second-level keyed container's codingPath changed.\")\n      XCTAssertEqualPaths(thirdLevelContainerKeyed.codingPath, baseCodingPath + [TopLevelCodingKeys.a, IntermediateCodingKeys.one], \"New third-level keyed container had unexpected codingPath.\")\n\n      // Inserting an unkeyed container should not change existing coding paths.\n      let thirdLevelContainerUnkeyed = secondLevelContainer.nestedUnkeyedContainer(forKey: .two)\n      XCTAssertEqualPaths(encoder.codingPath, baseCodingPath + [], \"Top-level Encoder's codingPath changed.\")\n      XCTAssertEqualPaths(firstLevelContainer.codingPath, baseCodingPath + [], \"First-level keyed container's codingPath changed.\")\n      XCTAssertEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.a], \"Second-level keyed container's codingPath changed.\")\n      XCTAssertEqualPaths(thirdLevelContainerUnkeyed.codingPath, baseCodingPath + [TopLevelCodingKeys.a, IntermediateCodingKeys.two], \"New third-level unkeyed container had unexpected codingPath.\")\n    }\n\n    // Nested Unkeyed Container\n    do {\n      // Nested container for key should have a new key pushed on.\n      var secondLevelContainer = firstLevelContainer.nestedUnkeyedContainer(forKey: .b)\n      XCTAssertEqualPaths(encoder.codingPath, baseCodingPath, \"Top-level Encoder's codingPath changed.\")\n      XCTAssertEqualPaths(firstLevelContainer.codingPath, baseCodingPath, \"First-level keyed container's codingPath changed.\")\n      XCTAssertEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.b], \"New second-level keyed container had unexpected codingPath.\")\n\n      // Appending a keyed container should not change existing coding paths.\n      let thirdLevelContainerKeyed = secondLevelContainer.nestedContainer(keyedBy: IntermediateCodingKeys.self)\n      XCTAssertEqualPaths(encoder.codingPath, baseCodingPath, \"Top-level Encoder's codingPath changed.\")\n      XCTAssertEqualPaths(firstLevelContainer.codingPath, baseCodingPath, \"First-level keyed container's codingPath changed.\")\n      XCTAssertEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.b], \"Second-level unkeyed container's codingPath changed.\")\n      XCTAssertEqualPaths(thirdLevelContainerKeyed.codingPath, baseCodingPath + [TopLevelCodingKeys.b, _TestKey(index: 0)], \"New third-level keyed container had unexpected codingPath.\")\n\n      // Appending an unkeyed container should not change existing coding paths.\n      let thirdLevelContainerUnkeyed = secondLevelContainer.nestedUnkeyedContainer()\n      XCTAssertEqualPaths(encoder.codingPath, baseCodingPath, \"Top-level Encoder's codingPath changed.\")\n      XCTAssertEqualPaths(firstLevelContainer.codingPath, baseCodingPath, \"First-level keyed container's codingPath changed.\")\n      XCTAssertEqualPaths(secondLevelContainer.codingPath, baseCodingPath + [TopLevelCodingKeys.b], \"Second-level unkeyed container's codingPath changed.\")\n      XCTAssertEqualPaths(thirdLevelContainerUnkeyed.codingPath, baseCodingPath + [TopLevelCodingKeys.b, _TestKey(index: 1)], \"New third-level unkeyed container had unexpected codingPath.\")\n    }\n  }\n}\n\n// MARK: - Helper Types\n\n/// A key type which can take on any string or integer value.\n/// This needs to mirror _JSONKey.\nprivate struct _TestKey: CodingKey {\n  var stringValue: String\n  var intValue: Int?\n\n  init?(stringValue: String) {\n    self.stringValue = stringValue\n    self.intValue = nil\n  }\n\n  init?(intValue: Int) {\n    self.stringValue = \"\\(intValue)\"\n    self.intValue = intValue\n  }\n\n  init(index: Int) {\n    self.stringValue = \"Index \\(index)\"\n    self.intValue = index\n  }\n}\n\nprivate struct FloatNaNPlaceholder: Codable, Equatable {\n  init() {}\n\n  func encode(to encoder: Encoder) throws {\n    var container = encoder.singleValueContainer()\n    try container.encode(Float.nan)\n  }\n\n  init(from decoder: Decoder) throws {\n    let container = try decoder.singleValueContainer()\n    let float = try container.decode(Float.self)\n    if !float.isNaN {\n      throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: \"Could not decode NaN.\"))\n    }\n  }\n\n  static func ==(_ lhs: FloatNaNPlaceholder, _ rhs: FloatNaNPlaceholder) -> Bool {\n    return true\n  }\n}\n\nprivate struct DoubleNaNPlaceholder: Codable, Equatable {\n  init() {}\n\n  func encode(to encoder: Encoder) throws {\n    var container = encoder.singleValueContainer()\n    try container.encode(Double.nan)\n  }\n\n  init(from decoder: Decoder) throws {\n    let container = try decoder.singleValueContainer()\n    let double = try container.decode(Double.self)\n    if !double.isNaN {\n      throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: \"Could not decode NaN.\"))\n    }\n  }\n\n  static func ==(_ lhs: DoubleNaNPlaceholder, _ rhs: DoubleNaNPlaceholder) -> Bool {\n    return true\n  }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseErrorTests.swift",
    "content": "//\n//  ParseErrorTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/16/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseErrorTests: XCTestCase {\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testInitializers() throws {\n        let error = ParseError(code: .accountAlreadyLinked, message: \"hello\")\n        let expected = \"ParseError code=208 error=hello\"\n        XCTAssertEqual(error.description, expected)\n        let error2 = ParseError(otherCode: 593, message: \"yolo\")\n        let expected2 = \"error=yolo otherCode=593\"\n        XCTAssertTrue(error2.description.contains(expected2))\n    }\n\n    func testDecode() throws {\n        let code = -1\n        let message = \"testing ParseError\"\n        guard let encoded: Data = \"{\\\"error\\\":\\\"\\(message)\\\",\\\"code\\\":\\(code)}\".data(using: .utf8) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let decoded = try ParseCoding.jsonDecoder().decode(ParseError.self, from: encoded)\n        XCTAssertEqual(decoded.code.rawValue, code)\n        XCTAssertEqual(decoded.message, message)\n        XCTAssertNil(decoded.error)\n        XCTAssertEqual(decoded.debugDescription, \"ParseError code=\\(code) error=\\(message)\")\n        XCTAssertEqual(decoded.description, \"ParseError code=\\(code) error=\\(message)\")\n        XCTAssertEqual(decoded.errorDescription, \"ParseError code=\\(code) error=\\(message)\")\n    }\n\n    func testDecodeMessage() throws {\n        let code = -1\n        let message = \"testing ParseError\"\n        guard let encoded: Data = \"{\\\"message\\\":\\\"\\(message)\\\",\\\"code\\\":\\(code)}\".data(using: .utf8) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let decoded = try ParseCoding.jsonDecoder().decode(ParseError.self, from: encoded)\n        XCTAssertEqual(decoded.code.rawValue, code)\n        XCTAssertEqual(decoded.message, message)\n        XCTAssertNil(decoded.error)\n        XCTAssertEqual(decoded.debugDescription, \"ParseError code=\\(code) error=\\(message)\")\n        XCTAssertEqual(decoded.description, \"ParseError code=\\(code) error=\\(message)\")\n        XCTAssertEqual(decoded.errorDescription, \"ParseError code=\\(code) error=\\(message)\")\n    }\n\n    func testDecodeOther() throws {\n        let code = 2000\n        let message = \"testing ParseError\"\n        guard let encoded = \"{\\\"error\\\":\\\"\\(message)\\\",\\\"code\\\":\\(code)}\".data(using: .utf8) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let decoded = try ParseCoding.jsonDecoder().decode(ParseError.self, from: encoded)\n        XCTAssertEqual(decoded.code, .other)\n        XCTAssertEqual(decoded.message, message)\n        XCTAssertNil(decoded.error)\n        XCTAssertEqual(decoded.debugDescription,\n                       \"ParseError code=\\(ParseError.Code.other.rawValue) error=\\(message) otherCode=\\(code)\")\n        XCTAssertEqual(decoded.otherCode, code)\n    }\n\n    func testDecodeMissingCode() throws {\n        let code = -1\n        let message = \"testing ParseError\"\n        guard let encoded = \"{\\\"error\\\":\\\"\\(message)\\\"}\".data(using: .utf8) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let decoded = try ParseCoding.jsonDecoder().decode(ParseError.self, from: encoded)\n        XCTAssertEqual(decoded.code, .unknownError)\n        XCTAssertEqual(decoded.message, message)\n        XCTAssertNil(decoded.error)\n        XCTAssertEqual(decoded.debugDescription,\n                       \"ParseError code=\\(code) error=\\(message)\")\n        XCTAssertNil(decoded.otherCode)\n    }\n\n    func testCompare() throws {\n        let code = ParseError.Code.objectNotFound.rawValue\n        let message = \"testing ParseError\"\n        guard let encoded = \"{\\\"error\\\":\\\"\\(message)\\\",\\\"code\\\":\\(code)}\".data(using: .utf8) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let decoded = try ParseCoding.jsonDecoder().decode(ParseError.self, from: encoded)\n\n        let error: Error = decoded\n\n        XCTAssertTrue(error.equalsTo(.objectNotFound))\n        XCTAssertFalse(error.equalsTo(.invalidQuery))\n\n        XCTAssertTrue(error.containedIn(.objectNotFound, .invalidQuery))\n        XCTAssertFalse(error.containedIn(.operationForbidden, .invalidQuery))\n\n        XCTAssertTrue(error.containedIn([.objectNotFound, .invalidQuery]))\n        XCTAssertFalse(error.containedIn([.operationForbidden, .invalidQuery]))\n\n        XCTAssertNotNil(error.equalsTo(.objectNotFound))\n        XCTAssertNil(error.equalsTo(.invalidQuery))\n\n        XCTAssertNotNil(error.containedIn(.objectNotFound, .invalidQuery))\n        XCTAssertNil(error.containedIn(.operationForbidden, .invalidQuery))\n\n        XCTAssertNotNil(error.containedIn([.objectNotFound, .invalidQuery]))\n        XCTAssertNil(error.containedIn([.operationForbidden, .invalidQuery]))\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseFacebookAsyncTests.swift",
    "content": "//\n//  ParseFacebookAsyncTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/28/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseFacebookAsyncTests: XCTestCase { // swiftlint:disable:this type_body_length\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    @MainActor\n    func testLimitedLogin() async throws {\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.facebook.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.facebook.login(userId: \"testing\",\n                                                 authenticationToken: \"authenticationToken\")\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.facebook.isLinked)\n    }\n\n    @MainActor\n    func testGraphAPILogin() async throws {\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.facebook.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.facebook.login(userId: \"testing\", accessToken: \"accessToken\")\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.facebook.isLinked)\n    }\n\n    @MainActor\n    func testLoginAuthData() async throws {\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.facebook.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let faceookAuthData = ParseFacebook<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  accessToken: \"accessToken\",\n                                                  authenticationToken: nil)\n\n        let user = try await User.facebook.login(authData: faceookAuthData)\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.facebook.isLinked)\n    }\n\n    func loginNormally() async throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try await User.login(username: \"parse\", password: \"user\")\n    }\n\n    @MainActor\n    func testLinkLimitedLogin() async throws {\n\n        _ = try await loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.facebook.link(userId: \"testing\",\n                                                authenticationToken: \"authenticationToken\")\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.facebook.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testLinkGraphAPILogin() async throws {\n\n        _ = try await loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.facebook.link(userId: \"testing\",\n                                                accessToken: \"accessToken\")\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.facebook.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testLinkAuthData() async throws {\n\n        _ = try await loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let authData = ParseFacebook<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  accessToken: \"accessToken\",\n                                                  authenticationToken: nil)\n\n        let user = try await User.facebook.link(authData: authData)\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.facebook.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testUnlinkLimitedLogin() async throws {\n\n        _ = try await loginNormally()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseFacebook<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  accessToken: nil,\n                                                  authenticationToken: \"authenticationToken\")\n        User.current?.authData = [User.facebook.__type: authData]\n        XCTAssertTrue(User.facebook.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.facebook.unlink()\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertFalse(user.facebook.isLinked)\n    }\n\n    @MainActor\n    func testUnlinkGraphAPILogin() async throws {\n\n        _ = try await loginNormally()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseFacebook<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  accessToken: \"accessToken\",\n                                                  authenticationToken: nil)\n        User.current?.authData = [User.facebook.__type: authData]\n        XCTAssertTrue(User.facebook.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.facebook.unlink()\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertFalse(user.facebook.isLinked)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseFacebookCombineTests.swift",
    "content": "//\n//  ParseFacebookCombineTests.swift\n//  ParseSwift\n//\n//  Created by Abdulaziz Alhomaidhi on 3/19/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseFacebookCombineTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n    func testLimitedLogin() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.facebook.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.facebook.loginPublisher(userId: \"testing\",\n                                                     authenticationToken: \"authenticationToken\")\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user, userOnServer)\n            XCTAssertEqual(user.username, \"hello\")\n            XCTAssertEqual(user.password, \"world\")\n            XCTAssertTrue(user.facebook.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testGraphAPILogin() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.facebook.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.facebook.loginPublisher(userId: \"testing\", accessToken: \"accessToken\")\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user, userOnServer)\n            XCTAssertEqual(user.username, \"hello\")\n            XCTAssertEqual(user.password, \"world\")\n            XCTAssertTrue(user.facebook.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginAuthData() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.facebook.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let faceookAuthData = ParseFacebook<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  accessToken: \"accessToken\",\n                                                  authenticationToken: nil)\n\n        let publisher = User.facebook.loginPublisher(authData: faceookAuthData)\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user, userOnServer)\n            XCTAssertEqual(user.username, \"hello\")\n            XCTAssertEqual(user.password, \"world\")\n            XCTAssertTrue(user.facebook.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func loginNormally() throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try User.login(username: \"parse\", password: \"user\")\n    }\n\n    func testLinkLimitedLogin() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.facebook.linkPublisher(userId: \"testing\", authenticationToken: \"authenticationToken\")\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertTrue(user.facebook.isLinked)\n            XCTAssertFalse(user.anonymous.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkGraphAPILogin() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.facebook.linkPublisher(userId: \"testing\",\n                                                    accessToken: \"accessToken\")\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertTrue(user.facebook.isLinked)\n            XCTAssertFalse(user.anonymous.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkAuthData() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let authData = ParseFacebook<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  accessToken: \"accessToken\",\n                                                  authenticationToken: nil)\n\n        let publisher = User.facebook.linkPublisher(authData: authData)\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertTrue(user.facebook.isLinked)\n            XCTAssertFalse(user.anonymous.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUnlinkLimitedLogin() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseFacebook<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  accessToken: nil,\n                                                  authenticationToken: \"authenticationToken\")\n        User.current?.authData = [User.facebook.__type: authData]\n        XCTAssertTrue(User.facebook.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.facebook.unlinkPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertFalse(user.facebook.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUnlinkGraphAPILogin() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseFacebook<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  accessToken: \"accessToken\",\n                                                  authenticationToken: nil)\n        User.current?.authData = [User.facebook.__type: authData]\n        XCTAssertTrue(User.facebook.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.facebook.unlinkPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertFalse(user.facebook.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseFacebookTests.swift",
    "content": "//\n//  ParseFacebookTests.swift\n//  ParseSwift\n//\n//  Created by Abdulaziz Alhomaidhi on 3/18/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseFacebookTests: XCTestCase {\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func loginNormally() throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try User.login(username: \"parse\", password: \"user\")\n    }\n\n    func testAuthenticationKeysLimitedLogin() throws {\n        let authData = ParseFacebook<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  accessToken: nil,\n                                                  authenticationToken: \"authenticationToken\")\n        XCTAssertEqual(authData, [\"id\": \"testing\",\n                                  \"token\": \"authenticationToken\"])\n    }\n\n    func testAuthenticationKeysLimitedLoginExpires() throws {\n        let expiresIn = 10\n        let authData = ParseFacebook<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  accessToken: nil,\n                                                  authenticationToken: \"authenticationToken\",\n                                                  expiresIn: expiresIn)\n        guard let dateString = authData[\"expiration_date\"] else {\n            XCTFail(\"Should have found date\")\n            return\n        }\n        XCTAssertEqual(authData, [\"id\": \"testing\",\n                                  \"token\": \"authenticationToken\",\n                                  \"expiration_date\": dateString])\n    }\n\n    func testVerifyMandatoryKeys() throws {\n        let authData = [\"id\": \"testing\",\n                        \"token\": \"authenticationToken\"]\n        XCTAssertTrue(ParseFacebook<User>\n                        .AuthenticationKeys.id.verifyMandatoryKeys(authData: authData))\n        let authData2 = [\"id\": \"testing\",\n                        \"access_token\": \"accessToken\"]\n        XCTAssertTrue(ParseFacebook<User>\n                        .AuthenticationKeys.id.verifyMandatoryKeys(authData: authData2))\n        XCTAssertTrue(ParseFacebook<User>\n                        .AuthenticationKeys.id.verifyMandatoryKeys(authData: authData))\n        let authDataWrong = [\"id\": \"testing\", \"hello\": \"test\"]\n        XCTAssertFalse(ParseFacebook<User>\n                        .AuthenticationKeys.id.verifyMandatoryKeys(authData: authDataWrong))\n        let authDataWrong2 = [\"world\": \"testing\", \"token\": \"test\"]\n        XCTAssertFalse(ParseFacebook<User>\n                        .AuthenticationKeys.id.verifyMandatoryKeys(authData: authDataWrong2))\n        let authDataWrong3 = [\"world\": \"testing\", \"access_token\": \"test\"]\n        XCTAssertFalse(ParseFacebook<User>\n                        .AuthenticationKeys.id.verifyMandatoryKeys(authData: authDataWrong3))\n    }\n\n    func testAuthenticationKeysGraphAPILogin() throws {\n        let authData = ParseFacebook<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  accessToken: \"accessToken\",\n                                                  authenticationToken: nil)\n        XCTAssertEqual(authData, [\"id\": \"testing\", \"access_token\": \"accessToken\"])\n    }\n\n    func testAuthenticationKeysGraphAPILoginExpires() throws {\n        let expiresIn = 10\n        let authData = ParseFacebook<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  accessToken: \"accessToken\",\n                                                  authenticationToken: nil,\n                                                  expiresIn: expiresIn)\n        guard let dateString = authData[\"expiration_date\"] else {\n            XCTFail(\"Should have found date\")\n            return\n        }\n        XCTAssertEqual(authData, [\"id\": \"testing\", \"access_token\": \"accessToken\", \"expiration_date\": dateString])\n    }\n\n    func testLimitedLogin() throws {\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseFacebook<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  accessToken: nil,\n                                                  authenticationToken: \"authenticationToken\")\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.facebook.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.facebook.login(userId: \"testing\",\n                            authenticationToken: \"authenticationToken\") { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user, userOnServer)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.facebook.isLinked)\n\n                //Test stripping\n                user.facebook.strip()\n                XCTAssertFalse(user.facebook.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testGraphAPILogin() throws {\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseFacebook<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  accessToken: \"accessToken\",\n                                                  authenticationToken: nil)\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.facebook.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.facebook.login(userId: \"testing\",\n                            accessToken: \"accessToken\") { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user, userOnServer)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.facebook.isLinked)\n\n                //Test stripping\n                user.facebook.strip()\n                XCTAssertFalse(user.facebook.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginAuthData() throws {\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseFacebook<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  accessToken: nil,\n                                                  authenticationToken: \"authenticationToken\")\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.facebook.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.facebook.login(authData: authData) { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user, userOnServer)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.facebook.isLinked)\n\n                //Test stripping\n                user.facebook.strip()\n                XCTAssertFalse(user.facebook.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginWrongKeys() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n        let currentDate = ParseCoding.dateFormatter.string(from: Date())\n        let authData = [\"id\": \"hello\",\n                        \"expirationDate\": currentDate]\n        User.facebook.login(authData: authData) { result in\n\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"consisting of keys\"))\n            } else {\n                XCTFail(\"Should have returned error\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func loginAnonymousUser() throws {\n        let authData = [\"id\": \"yolo\"]\n\n        //: Convert the anonymous user to a real new user.\n        var serverResponse = LoginSignupResponse()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.anonymous.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try User.anonymous.login()\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.anonymous.isLinked)\n    }\n\n    func testReplaceAnonymousWithFacebookLimitedLogin() throws {\n        try loginAnonymousUser()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseFacebook<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  accessToken: nil,\n                                                  authenticationToken: \"authenticationToken\")\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.facebook.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.facebook.login(userId: \"testing\",\n                            authenticationToken: \"authenticationToken\") { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.facebook.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testReplaceAnonymousWithFacebookGraphAPILogin() throws {\n        try loginAnonymousUser()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseFacebook<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  accessToken: \"this\",\n                                                  authenticationToken: nil)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.facebook.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.facebook.login(userId: \"testing\",\n                            accessToken: \"accessToken\") { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.facebook.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testReplaceAnonymousWithLinkedFacebookLimitedLogin() throws {\n        try loginAnonymousUser()\n        MockURLProtocol.removeAll()\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n        let expiresIn = 10\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.facebook.link(userId: \"testing\", authenticationToken: \"authenticationToken\",\n                           expiresIn: expiresIn) { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.facebook.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testReplaceAnonymousWithLinkedFacebookGraphAPILogin() throws {\n        try loginAnonymousUser()\n        MockURLProtocol.removeAll()\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n        let expiresIn = 10\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.facebook.link(userId: \"testing\", accessToken: \"acceeToken\", expiresIn: expiresIn) { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.facebook.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkLoggedInUserWithFacebookLimitedLogin() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n        let expiresIn = 10\n        var serverResponse = LoginSignupResponse()\n        serverResponse.sessionToken = nil\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.facebook.link(userId: \"testing\", authenticationToken: \"authenticationToken\",\n                           expiresIn: expiresIn) { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello10\")\n                XCTAssertNil(user.password)\n                XCTAssertTrue(user.facebook.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n                XCTAssertEqual(User.current?.sessionToken, \"myToken\")\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkLoggedInUserWithFacebookGraphAPILogin() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n        let expiresIn = 10\n        var serverResponse = LoginSignupResponse()\n        serverResponse.sessionToken = nil\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.facebook.link(userId: \"testing\", accessToken: \"accessToken\", expiresIn: expiresIn) { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello10\")\n                XCTAssertNil(user.password)\n                XCTAssertTrue(user.facebook.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n                XCTAssertEqual(User.current?.sessionToken, \"myToken\")\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkLoggedInAuthData() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n        var serverResponse = LoginSignupResponse()\n        serverResponse.sessionToken = nil\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        let authData = ParseFacebook<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  accessToken: nil,\n                                                  authenticationToken: \"authenticationToken\")\n\n        User.facebook.link(authData: authData) { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello10\")\n                XCTAssertNil(user.password)\n                XCTAssertTrue(user.facebook.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n                XCTAssertEqual(User.current?.sessionToken, \"myToken\")\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkWrongKeys() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n        let currentDate = ParseCoding.dateFormatter.string(from: Date())\n        let authData = [\"id\": \"hello\",\n                        \"expirationDate\": currentDate]\n        User.facebook.link(authData: authData) { result in\n\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"consisting of keys\"))\n            } else {\n                XCTFail(\"Should have returned error\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUnlinkLimitedLogin() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseFacebook<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  accessToken: nil,\n                                                  authenticationToken: \"authenticationToken\")\n        User.current?.authData = [User.facebook.__type: authData]\n        XCTAssertTrue(User.facebook.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.facebook.unlink { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello10\")\n                XCTAssertNil(user.password)\n                XCTAssertFalse(user.facebook.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUnlinkGraphAPILogin() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseFacebook<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  accessToken: \"accessToken\",\n                                                  authenticationToken: nil)\n        User.current?.authData = [User.facebook.__type: authData]\n        XCTAssertTrue(User.facebook.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.facebook.unlink { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello10\")\n                XCTAssertNil(user.password)\n                XCTAssertFalse(user.facebook.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseFileAsyncTests.swift",
    "content": "//\n//  ParseFileAsyncTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/28/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseFileAsyncTests: XCTestCase { // swiftlint:disable:this type_body_length\n    let temporaryDirectory = \"\\(NSTemporaryDirectory())test/\"\n\n    struct FileUploadResponse: Codable {\n        let name: String\n        let url: URL\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n        guard let fileManager = ParseFileManager() else {\n            throw ParseError(code: .unknownError, message: \"Should have initialized file manage\")\n        }\n        try fileManager.createDirectoryIfNeeded(temporaryDirectory)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n\n        guard let fileManager = ParseFileManager() else {\n            throw ParseError(code: .unknownError, message: \"Should have initialized file manager\")\n        }\n        let directory = URL(fileURLWithPath: temporaryDirectory, isDirectory: true)\n        let expectation1 = XCTestExpectation(description: \"Delete files1\")\n        fileManager.removeDirectoryContents(directory) { error in\n            guard let error = error else {\n                expectation1.fulfill()\n                return\n            }\n            XCTFail(error.localizedDescription)\n            expectation1.fulfill()\n        }\n        let directory2 = try ParseFileManager.downloadDirectory()\n        let expectation2 = XCTestExpectation(description: \"Delete files2\")\n        fileManager.removeDirectoryContents(directory2) { _ in\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    //URL Mocker is not able to mock this in linux and tests fail, so do not run.\n    @MainActor\n    func testFetch() async throws {\n\n        // swiftlint:disable:next line_length\n        guard let parseFileURL = URL(string: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        var parseFile = ParseFile(name: \"d3a37aed0672a024595b766f97133615_logo.svg\", cloudURL: parseFileURL)\n        parseFile.url = parseFileURL\n\n        let response = FileUploadResponse(name: \"d3a37aed0672a024595b766f97133615_logo.svg\",\n                                          url: parseFileURL)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let fetched = try await parseFile.fetch()\n        XCTAssertEqual(fetched.name, response.name)\n        XCTAssertEqual(fetched.url, response.url)\n        XCTAssertNotNil(fetched.localURL)\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let fetchedFileCached = try await parseFile.fetch(options: [.cachePolicy(.returnCacheDataDontLoad)])\n        XCTAssertEqual(fetchedFileCached, fetched)\n    }\n\n    @MainActor\n    func testFetchLoadFromRemote() async throws {\n\n        // swiftlint:disable:next line_length\n        guard let parseFileURL = URL(string: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        var parseFile = ParseFile(name: \"d3a37aed0672a024595b766f97133615_logo.svg\", cloudURL: parseFileURL)\n        parseFile.url = parseFileURL\n\n        let response = FileUploadResponse(name: \"d3a37aed0672a024595b766f97133615_logo.svg\",\n                                          url: parseFileURL)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let fetched = try await parseFile.fetch(options: [.cachePolicy(.reloadIgnoringLocalAndRemoteCacheData)])\n        XCTAssertEqual(fetched.name, response.name)\n        XCTAssertEqual(fetched.url, response.url)\n        XCTAssertNotNil(fetched.localURL)\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let fetchedFileCached = try await parseFile.fetch(options: [.cachePolicy(.returnCacheDataDontLoad)])\n        XCTAssertEqual(fetchedFileCached, fetched)\n    }\n\n    @MainActor\n    func testFetchLoadFromCacheNoCache() async throws {\n\n        // swiftlint:disable:next line_length\n        guard let parseFileURL = URL(string: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        var parseFile = ParseFile(name: \"d3a37aed0672a024595b766f97133615_logo.svg\", cloudURL: parseFileURL)\n        parseFile.url = parseFileURL\n\n        do {\n            _ = try await parseFile.fetch(options: [.cachePolicy(.returnCacheDataDontLoad)])\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(parseError.code, .unsavedFileFailure)\n        }\n    }\n\n    @MainActor\n    func testFetchFileProgress() async throws {\n\n        // swiftlint:disable:next line_length\n        guard let parseFileURL = URL(string: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        var parseFile = ParseFile(name: \"d3a37aed0672a024595b766f97133615_logo.svg\", cloudURL: parseFileURL)\n        parseFile.url = parseFileURL\n\n        let response = FileUploadResponse(name: \"d3a37aed0672a024595b766f97133615_logo.svg\",\n                                          url: parseFileURL)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let fetched = try await parseFile.fetch(progress: { (_, _, totalDownloaded, totalExpected) in\n            let currentProgess = Double(totalDownloaded)/Double(totalExpected) * 100\n            XCTAssertGreaterThan(currentProgess, -1)\n        })\n        XCTAssertEqual(fetched.name, response.name)\n        XCTAssertEqual(fetched.url, response.url)\n        XCTAssertNotNil(fetched.localURL)\n    }\n    #endif\n\n    @MainActor\n    func testSave() async throws {\n\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        let parseFile = ParseFile(name: \"sampleData.txt\", data: sampleData)\n\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_sampleData.txt\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let response = FileUploadResponse(name: \"89d74fcfa4faa5561799e5076593f67c_\\(parseFile.name)\", url: url)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let fetched = try await parseFile.save()\n        XCTAssertEqual(fetched.name, response.name)\n        XCTAssertEqual(fetched.url, response.url)\n    }\n\n    @MainActor\n    func testSaveFileProgress() async throws {\n\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        let parseFile = ParseFile(name: \"sampleData.txt\", data: sampleData)\n\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_sampleData.txt\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let response = FileUploadResponse(name: \"89d74fcfa4faa5561799e5076593f67c_\\(parseFile.name)\", url: url)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let fetched = try await parseFile.save(progress: { (_, _, totalDownloaded, totalExpected) in\n            let currentProgess = Double(totalDownloaded)/Double(totalExpected) * 100\n            XCTAssertGreaterThan(currentProgess, -1)\n        })\n        XCTAssertEqual(fetched.name, response.name)\n        XCTAssertEqual(fetched.url, response.url)\n    }\n\n    @MainActor\n    func testDelete() async throws {\n\n        // swiftlint:disable:next line_length\n        guard let parseFileURL = URL(string: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        var parseFile = ParseFile(name: \"d3a37aed0672a024595b766f97133615_logo.svg\", cloudURL: parseFileURL)\n        parseFile.url = parseFileURL\n\n        let response = FileUploadResponse(name: \"d3a37aed0672a024595b766f97133615_logo.svg\",\n                                          url: parseFileURL)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        _ = try await parseFile.delete(options: [.useMasterKey])\n    }\n\n    @MainActor\n    func testDeleteError () async throws {\n        // swiftlint:disable:next line_length\n        guard let parseFileURL = URL(string: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        var parseFile = ParseFile(name: \"d3a37aed0672a024595b766f97133615_logo.svg\", cloudURL: parseFileURL)\n        parseFile.url = parseFileURL\n\n        let serverResponse = ParseError(code: .fileDeleteFailure, message: \"not found\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            _ = try await parseFile.delete(options: [.useMasterKey])\n            XCTFail(\"Should have thrown error\")\n        } catch {\n\n            guard let error = error as? ParseError else {\n                XCTFail(\"Should be ParseError\")\n                return\n            }\n            XCTAssertEqual(error.message, serverResponse.message)\n        }\n    }\n\n    @MainActor\n    func testParseURLSessionDelegates() async throws {\n        // swiftlint:disable:next line_length\n        let downloadTask = URLSession.shared.downloadTask(with: .init(fileURLWithPath: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\"))\n        let task = downloadTask as URLSessionTask\n        // swiftlint:disable:next line_length\n        let uploadCompletion: ((URLSessionTask, Int64, Int64, Int64) -> Void) = { (_: URLSessionTask, _: Int64, _: Int64, _: Int64) -> Void in }\n        // swiftlint:disable:next line_length\n        let downloadCompletion: ((URLSessionDownloadTask, Int64, Int64, Int64) -> Void) = { (_: URLSessionDownloadTask, _: Int64, _: Int64, _: Int64) -> Void in }\n\n        // Add tasks\n        Parse.sessionDelegate.streamDelegates[task] = .init(data: .init())\n        XCTAssertEqual(Parse.sessionDelegate.streamDelegates.count, 1)\n        await Parse.sessionDelegate.delegates.updateTask(task, queue: DispatchQueue.main)\n        let taskCount = await Parse.sessionDelegate.delegates.taskCallbackQueues.count\n        XCTAssertEqual(taskCount, 1)\n        await Parse.sessionDelegate.delegates.updateUpload(task, callback: uploadCompletion)\n        let uploadCount = await Parse.sessionDelegate.delegates.uploadDelegates.count\n        XCTAssertEqual(uploadCount, 1)\n        await Parse.sessionDelegate.delegates.updateDownload(downloadTask, callback: downloadCompletion)\n        let downloadCount = await Parse.sessionDelegate.delegates.downloadDelegates.count\n        XCTAssertEqual(downloadCount, 1)\n\n        // Remove tasks\n        Parse.sessionDelegate.streamDelegates.removeValue(forKey: task)\n        XCTAssertEqual(Parse.sessionDelegate.streamDelegates.count, 0)\n        await Parse.sessionDelegate.delegates.removeTask(task)\n        let taskCount2 = await Parse.sessionDelegate.delegates.taskCallbackQueues.count\n        XCTAssertEqual(taskCount2, 0)\n        await Parse.sessionDelegate.delegates.removeUpload(task)\n        let uploadCount2 = await Parse.sessionDelegate.delegates.uploadDelegates.count\n        XCTAssertEqual(uploadCount2, 0)\n        await Parse.sessionDelegate.delegates.removeDownload(downloadTask)\n        let downloadCount2 = await Parse.sessionDelegate.delegates.downloadDelegates.count\n        XCTAssertEqual(downloadCount2, 0)\n    }\n\n    #if !os(iOS)\n    func testParseURLSessionDelegateUpload() async throws {\n        // swiftlint:disable:next line_length\n        let downloadTask = URLSession.shared.downloadTask(with: .init(fileURLWithPath: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\"))\n        let task = downloadTask as URLSessionTask\n        let queue = DispatchQueue.global(qos: .utility)\n\n        let expectation1 = XCTestExpectation(description: \"Call delegate 1\")\n        let expectation2 = XCTestExpectation(description: \"Call delegate 2\")\n\n        // swiftlint:disable:next line_length\n        let uploadCompletion: ((URLSessionTask, Int64, Int64, Int64) -> Void) = { (_: URLSessionTask, _: Int64, sent: Int64, total: Int64) -> Void in\n            if sent < total {\n                Task {\n                    let uploadCount = await Parse.sessionDelegate.delegates.uploadDelegates.count\n                    let taskCount = await Parse.sessionDelegate.delegates.taskCallbackQueues.count\n                    Parse.sessionDelegate.urlSession(URLSession.parse,\n                                                          task: task,\n                                                          didCompleteWithError: nil)\n                    DispatchQueue.main.asyncAfter(deadline: .now() + 4) {\n                        XCTAssertEqual(uploadCount, 1)\n                        XCTAssertEqual(taskCount, 1)\n                        expectation1.fulfill()\n\n                        Task {\n                            let uploadCount = await Parse.sessionDelegate.delegates.uploadDelegates.count\n                            let taskCount = await Parse.sessionDelegate.delegates.taskCallbackQueues.count\n                            XCTAssertEqual(uploadCount, 0)\n                            XCTAssertEqual(taskCount, 0)\n                            expectation2.fulfill()\n                        }\n                    }\n                }\n            }\n        }\n\n        // Add tasks\n        await Parse.sessionDelegate.delegates.updateUpload(task, callback: uploadCompletion)\n        await Parse.sessionDelegate.delegates.updateTask(task, queue: queue)\n\n        Parse.sessionDelegate.urlSession(URLSession.parse,\n                                              task: task,\n                                              didSendBodyData: 0,\n                                              totalBytesSent: 0,\n                                              totalBytesExpectedToSend: 10)\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testParseURLSessionDelegateDownload() async throws {\n        // swiftlint:disable:next line_length\n        let downloadTask = URLSession.shared.downloadTask(with: .init(fileURLWithPath: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\"))\n        let task = downloadTask as URLSessionTask\n        let queue = DispatchQueue.global(qos: .utility)\n        guard let fileManager = ParseFileManager(),\n              let filePath = fileManager.dataItemPathForPathComponent(\"test.txt\") else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Call delegate 1\")\n        let expectation2 = XCTestExpectation(description: \"Call delegate 2\")\n\n        // swiftlint:disable:next line_length\n        let downloadCompletion: ((URLSessionDownloadTask, Int64, Int64, Int64) -> Void) = { (_: URLSessionDownloadTask, _: Int64, sent: Int64, total: Int64) -> Void in\n            if sent < total {\n                Task {\n                    let downloadCount = await Parse.sessionDelegate.delegates.downloadDelegates.count\n                    let taskCount = await Parse.sessionDelegate.delegates.taskCallbackQueues.count\n                    Parse.sessionDelegate.urlSession(URLSession.parse,\n                                                          downloadTask: downloadTask,\n                                                          didFinishDownloadingTo: filePath)\n                    DispatchQueue.main.asyncAfter(deadline: .now() + 4) {\n                        XCTAssertEqual(downloadCount, 1)\n                        XCTAssertEqual(taskCount, 1)\n                        expectation1.fulfill()\n\n                        Task {\n                            let downloadCount = await Parse.sessionDelegate.delegates.downloadDelegates.count\n                            let taskCount = await Parse.sessionDelegate.delegates.taskCallbackQueues.count\n                            XCTAssertEqual(downloadCount, 0)\n                            XCTAssertEqual(taskCount, 0)\n                            expectation2.fulfill()\n                        }\n                    }\n                }\n            }\n        }\n\n        // Add tasks\n        await Parse.sessionDelegate.delegates.updateDownload(downloadTask, callback: downloadCompletion)\n        await Parse.sessionDelegate.delegates.updateTask(task, queue: queue)\n\n        Parse.sessionDelegate.urlSession(URLSession.parse,\n                                              downloadTask: downloadTask,\n                                              didWriteData: 0,\n                                              totalBytesWritten: 0,\n                                              totalBytesExpectedToWrite: 10)\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testParseURLSessionDelegateStream() async throws {\n        // swiftlint:disable:next line_length\n        let downloadTask = URLSession.shared.downloadTask(with: .init(fileURLWithPath: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\"))\n        let task = downloadTask as URLSessionTask\n        let queue = DispatchQueue.global(qos: .utility)\n\n        let expectation1 = XCTestExpectation(description: \"Call delegate 1\")\n        let expectation2 = XCTestExpectation(description: \"Call delegate 2\")\n\n        let streamCompletion: ((InputStream?) -> Void) = { (_: InputStream?) -> Void in\n            Task {\n                let streamCount = Parse.sessionDelegate.streamDelegates.count\n                let taskCount = await Parse.sessionDelegate.delegates.taskCallbackQueues.count\n                Parse.sessionDelegate.urlSession(URLSession.parse, task: task, didCompleteWithError: nil)\n\n                DispatchQueue.main.asyncAfter(deadline: .now() + 4) {\n                    XCTAssertEqual(streamCount, 1)\n                    XCTAssertEqual(taskCount, 1)\n                    expectation1.fulfill()\n\n                    Task {\n                        let streamCount = Parse.sessionDelegate.streamDelegates.count\n                        let taskCount = await Parse.sessionDelegate.delegates.taskCallbackQueues.count\n                        XCTAssertEqual(streamCount, 0)\n                        XCTAssertEqual(taskCount, 0)\n                        expectation2.fulfill()\n                    }\n                }\n            }\n        }\n\n        // Add tasks\n        Parse.sessionDelegate.streamDelegates[task] = .init(data: .init())\n        await Parse.sessionDelegate.delegates.updateTask(task, queue: queue)\n\n        Parse.sessionDelegate.urlSession(URLSession.parse, task: task, needNewBodyStream: streamCompletion)\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n    #endif\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseFileCombineTests.swift",
    "content": "//\n//  ParseFileCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/30/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseFileCombineTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    let temporaryDirectory = \"\\(NSTemporaryDirectory())test/\"\n\n    struct FileUploadResponse: Codable {\n        let name: String\n        let url: URL\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n        guard let fileManager = ParseFileManager() else {\n            throw ParseError(code: .unknownError, message: \"Should have initialized file manage\")\n        }\n        try fileManager.createDirectoryIfNeeded(temporaryDirectory)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n\n        guard let fileManager = ParseFileManager() else {\n            throw ParseError(code: .unknownError, message: \"Should have initialized file manage\")\n        }\n        let directory = URL(fileURLWithPath: temporaryDirectory, isDirectory: true)\n        let expectation1 = XCTestExpectation(description: \"Delete files1\")\n        fileManager.removeDirectoryContents(directory) { error in\n            guard let error = error else {\n                expectation1.fulfill()\n                return\n            }\n            XCTFail(error.localizedDescription)\n            expectation1.fulfill()\n        }\n        let directory2 = try ParseFileManager.downloadDirectory()\n        let expectation2 = XCTestExpectation(description: \"Delete files2\")\n        fileManager.removeDirectoryContents(directory2) { _ in\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testFetch() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Fetch\")\n\n        // swiftlint:disable:next line_length\n        guard let parseFileURL = URL(string: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        var parseFile = ParseFile(name: \"d3a37aed0672a024595b766f97133615_logo.svg\", cloudURL: parseFileURL)\n        parseFile.url = parseFileURL\n\n        let response = FileUploadResponse(name: \"d3a37aed0672a024595b766f97133615_logo.svg\",\n                                          url: parseFileURL)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = parseFile.fetchPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { fetched in\n\n            XCTAssertEqual(fetched.name, response.name)\n            XCTAssertEqual(fetched.url, response.url)\n            XCTAssertNotNil(fetched.localURL)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testFetchFileProgress() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Fetch\")\n\n        // swiftlint:disable:next line_length\n        guard let parseFileURL = URL(string: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        var parseFile = ParseFile(name: \"d3a37aed0672a024595b766f97133615_logo.svg\", cloudURL: parseFileURL)\n        parseFile.url = parseFileURL\n\n        let response = FileUploadResponse(name: \"d3a37aed0672a024595b766f97133615_logo.svg\",\n                                          url: parseFileURL)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = parseFile.fetchPublisher(progress: { (_, _, totalDownloaded, totalExpected) in\n            let currentProgess = Double(totalDownloaded)/Double(totalExpected) * 100\n            XCTAssertGreaterThan(currentProgess, -1)\n        }).sink(receiveCompletion: { result in\n\n            if case let .failure(error) = result {\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n\n        }, receiveValue: { fetched in\n\n            XCTAssertEqual(fetched.name, response.name)\n            XCTAssertEqual(fetched.url, response.url)\n            XCTAssertNotNil(fetched.localURL)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSave() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Fetch\")\n\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        let parseFile = ParseFile(name: \"sampleData.txt\", data: sampleData)\n\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_sampleData.txt\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let response = FileUploadResponse(name: \"89d74fcfa4faa5561799e5076593f67c_\\(parseFile.name)\", url: url)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = parseFile.savePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { fetched in\n\n            XCTAssertEqual(fetched.name, response.name)\n            XCTAssertEqual(fetched.url, response.url)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSaveFileProgress() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Fetch\")\n\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        let parseFile = ParseFile(name: \"sampleData.txt\", data: sampleData)\n\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_sampleData.txt\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let response = FileUploadResponse(name: \"89d74fcfa4faa5561799e5076593f67c_\\(parseFile.name)\", url: url)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = parseFile.savePublisher(progress: { (_, _, totalDownloaded, totalExpected) in\n            let currentProgess = Double(totalDownloaded)/Double(totalExpected) * 100\n            XCTAssertGreaterThan(currentProgess, -1)\n        }).sink(receiveCompletion: { result in\n\n            if case let .failure(error) = result {\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n\n        }, receiveValue: { fetched in\n\n            XCTAssertEqual(fetched.name, response.name)\n            XCTAssertEqual(fetched.url, response.url)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDelete() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Fetch\")\n\n        // swiftlint:disable:next line_length\n        guard let parseFileURL = URL(string: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        var parseFile = ParseFile(name: \"d3a37aed0672a024595b766f97133615_logo.svg\", cloudURL: parseFileURL)\n        parseFile.url = parseFileURL\n\n        let response = FileUploadResponse(name: \"d3a37aed0672a024595b766f97133615_logo.svg\",\n                                          url: parseFileURL)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = parseFile.deletePublisher(options: [.useMasterKey])\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseFileManagerTests.swift",
    "content": "//\n//  ParseFileManagerTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 12/26/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nstruct FileUploadResponse: Codable {\n    let name: String\n    let url: URL\n}\n\nclass ParseFileManagerTests: XCTestCase {\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n\n        guard let fileManager = ParseFileManager(),\n              let defaultDirectory = fileManager.defaultDataDirectoryPath else {\n            throw ParseError(code: .unknownError, message: \"Should have initialized file manage\")\n        }\n        try fileManager.createDirectoryIfNeeded(defaultDirectory.relativePath)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n\n        guard let fileManager = ParseFileManager(),\n              let defaultDirectoryPath = fileManager.defaultDataDirectoryPath else {\n            throw ParseError(code: .unknownError, message: \"Should have initialized file manage\")\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Delete files1\")\n        fileManager.removeDirectoryContents(defaultDirectoryPath) { error in\n            guard let error = error else {\n                expectation1.fulfill()\n                return\n            }\n            XCTFail(error.localizedDescription)\n            expectation1.fulfill()\n        }\n        let directory2 = defaultDirectoryPath\n            .appendingPathComponent(ParseConstants.fileDownloadsDirectory, isDirectory: true)\n        let expectation2 = XCTestExpectation(description: \"Delete files2\")\n        fileManager.removeDirectoryContents(directory2) { _ in\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testWriteData() throws {\n        guard let data = \"Hello World\".data(using: .utf8),\n              let fileManager = ParseFileManager(),\n              let filePath = fileManager.dataItemPathForPathComponent(\"test.txt\") else {\n            throw ParseError(code: .unknownError, message: \"Should have initialized file manage\")\n        }\n\n        let expectation1 = XCTestExpectation(description: \"ParseFile async\")\n        fileManager.writeData(data, filePath: filePath) { error in\n            guard let error = error else {\n                guard let readFile = try? Data(contentsOf: filePath) else {\n                    XCTFail(\"Should have read as string\")\n                    return\n                }\n                XCTAssertEqual(readFile, data)\n                expectation1.fulfill()\n                return\n            }\n            XCTFail(error.localizedDescription)\n            expectation1.fulfill()\n        }\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testCopyItem() throws {\n        let dataAsString = \"Hello World\"\n        guard let fileManager = ParseFileManager(),\n              let filePath = fileManager.dataItemPathForPathComponent(\"test.txt\"),\n              let filePath2 = fileManager.dataItemPathForPathComponent(\"test2.txt\") else {\n            throw ParseError(code: .unknownError, message: \"Should have initialized file manage\")\n        }\n\n        let expectation1 = XCTestExpectation(description: \"ParseFile async\")\n        fileManager.writeString(dataAsString, filePath: filePath) { error in\n            guard let error = error else {\n                guard let readFile = try? String(contentsOf: filePath) else {\n                    XCTFail(\"Should have read as string\")\n                    return\n                }\n                XCTAssertEqual(readFile, dataAsString)\n\n                fileManager.copyItem(filePath, toPath: filePath2) { _ in\n                    guard let readFile = try? String(contentsOf: filePath),\n                          let readFile2 = try? String(contentsOf: filePath2) else {\n                        XCTFail(\"Should have read as string\")\n                        return\n                    }\n\n                    XCTAssertEqual(readFile, dataAsString)\n                    XCTAssertEqual(readFile2, dataAsString)\n                    expectation1.fulfill()\n                }\n                return\n            }\n            XCTFail(error.localizedDescription)\n            expectation1.fulfill()\n        }\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testMoveItem() throws {\n        let dataAsString = \"Hello World\"\n        guard let fileManager = ParseFileManager(),\n              let filePath = fileManager.dataItemPathForPathComponent(\"test.txt\"),\n              let filePath2 = fileManager.dataItemPathForPathComponent(\"test2.txt\") else {\n            throw ParseError(code: .unknownError, message: \"Should have initialized file manage\")\n        }\n\n        let expectation1 = XCTestExpectation(description: \"ParseFile async\")\n        fileManager.writeString(dataAsString, filePath: filePath) { error in\n            guard let error = error else {\n                guard let readFile = try? String(contentsOf: filePath) else {\n                    XCTFail(\"Should have read as string\")\n                    return\n                }\n                XCTAssertEqual(readFile, dataAsString)\n\n                fileManager.moveItem(filePath, toPath: filePath2) { _ in\n                    guard let readFile2 = try? String(contentsOf: filePath2) else {\n                        XCTFail(\"Should have read as string\")\n                        return\n                    }\n                    XCTAssertFalse(FileManager.default.fileExists(atPath: filePath.relativePath))\n                    XCTAssertEqual(readFile2, dataAsString)\n                    expectation1.fulfill()\n                }\n                return\n            }\n            XCTFail(error.localizedDescription)\n            expectation1.fulfill()\n        }\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDontMoveSameItem() throws {\n        let dataAsString = \"Hello World\"\n        guard let fileManager = ParseFileManager(),\n              let filePath = fileManager.dataItemPathForPathComponent(\"test.txt\"),\n              let filePath2 = fileManager.dataItemPathForPathComponent(\"test.txt\") else {\n            throw ParseError(code: .unknownError, message: \"Should have initialized file manage\")\n        }\n\n        let expectation1 = XCTestExpectation(description: \"ParseFile async\")\n        fileManager.writeString(dataAsString, filePath: filePath) { error in\n            guard let error = error else {\n                guard let readFile = try? String(contentsOf: filePath) else {\n                    XCTFail(\"Should have read as string\")\n                    return\n                }\n                XCTAssertEqual(readFile, dataAsString)\n\n                fileManager.moveItem(filePath, toPath: filePath2) { _ in\n                    guard let readFile2 = try? String(contentsOf: filePath2) else {\n                        XCTFail(\"Should have read as string\")\n                        return\n                    }\n                    XCTAssertTrue(FileManager.default.fileExists(atPath: filePath2.relativePath))\n                    XCTAssertEqual(readFile2, dataAsString)\n                    expectation1.fulfill()\n                }\n                return\n            }\n            XCTFail(error.localizedDescription)\n            expectation1.fulfill()\n        }\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testMoveContentsOfDirectory() throws {\n        let dataAsString = \"Hello World\"\n        guard let fileManager = ParseFileManager(),\n              let defaultFilePath = fileManager.defaultDataDirectoryPath else {\n            throw ParseError(code: .unknownError, message: \"Should have initialized file manage\")\n        }\n\n        let oldPath = defaultFilePath.appendingPathComponent(\"old\")\n        try fileManager.createDirectoryIfNeeded(oldPath.relativePath)\n        let filePath = oldPath.appendingPathComponent(\"test.txt\")\n        let filePath2 = defaultFilePath.appendingPathComponent(\"new/\")\n\n        let expectation1 = XCTestExpectation(description: \"ParseFile async\")\n        fileManager.writeString(dataAsString, filePath: filePath) { error in\n            guard let error = error else {\n                guard let readFile = try? String(contentsOf: filePath) else {\n                    XCTFail(\"Should have read as string\")\n                    return\n                }\n                XCTAssertEqual(readFile, dataAsString)\n\n                fileManager.moveContentsOfDirectory(oldPath, toPath: filePath2) { _ in\n                    let movedFilePath = filePath2.appendingPathComponent(\"test.txt\")\n                    guard let readFile2 = try? String(contentsOf: movedFilePath) else {\n                        XCTFail(\"Should have read as string\")\n                        return\n                    }\n                    XCTAssertFalse(FileManager.default.fileExists(atPath: filePath.relativePath))\n                    XCTAssertEqual(readFile2, dataAsString)\n                    expectation1.fulfill()\n                }\n                return\n            }\n            XCTFail(error.localizedDescription)\n            expectation1.fulfill()\n        }\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseFileTests.swift",
    "content": "//\n//  ParseFileTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 12/23/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseFileTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    let temporaryDirectory = \"\\(NSTemporaryDirectory())test/\"\n\n    struct FileUploadResponse: Codable {\n        let name: String\n        let url: URL\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n\n        guard let fileManager = ParseFileManager() else {\n            throw ParseError(code: .unknownError, message: \"Should have initialized file manage\")\n        }\n        try fileManager.createDirectoryIfNeeded(temporaryDirectory)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        URLSession.parse.configuration.urlCache?.removeAllCachedResponses()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n\n        guard let fileManager = ParseFileManager() else {\n            throw ParseError(code: .unknownError, message: \"Should have initialized file manage\")\n        }\n        let directory = URL(fileURLWithPath: temporaryDirectory, isDirectory: true)\n        let expectation1 = XCTestExpectation(description: \"Delete files1\")\n        fileManager.removeDirectoryContents(directory) { error in\n            guard let error = error else {\n                expectation1.fulfill()\n                return\n            }\n            XCTFail(error.localizedDescription)\n            expectation1.fulfill()\n        }\n        let directory2 = try ParseFileManager.downloadDirectory()\n        let expectation2 = XCTestExpectation(description: \"Delete files2\")\n        fileManager.removeDirectoryContents(directory2) { _ in\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testUploadCommand() throws {\n        guard let url = URL(string: \"http://localhost/\") else {\n            XCTFail(\"Should have created url\")\n            return\n        }\n        let file = ParseFile(name: \"a\", cloudURL: url)\n\n        let command = try file.uploadFileCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/files/a\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertNil(command.params)\n        XCTAssertNil(command.body)\n\n        let file2 = ParseFile(cloudURL: url)\n\n        let command2 = try file2.uploadFileCommand()\n        XCTAssertNotNil(command2)\n        XCTAssertEqual(command2.path.urlComponent, \"/files/file\")\n        XCTAssertEqual(command2.method, API.Method.POST)\n        XCTAssertNil(command2.params)\n        XCTAssertNil(command2.body)\n    }\n\n    func testUploadCommandDontAllowUpdate() throws {\n        guard let url = URL(string: \"http://localhost/\") else {\n            XCTFail(\"Should have created url\")\n            return\n        }\n\n        var file = ParseFile(cloudURL: url)\n        file.url = url\n        XCTAssertThrowsError(try file.uploadFileCommand())\n    }\n\n    func testDeleteCommand() {\n        guard let url = URL(string: \"http://localhost/\") else {\n            XCTFail(\"Should have created url\")\n            return\n        }\n        var file = ParseFile(name: \"a\", cloudURL: url)\n        file.url = url\n        let command = file.deleteFileCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/files/a\")\n        XCTAssertEqual(command.method, API.Method.DELETE)\n        XCTAssertNil(command.params)\n        XCTAssertNil(command.body)\n\n        var file2 = ParseFile(cloudURL: url)\n        file2.url = url\n        let command2 = file2.deleteFileCommand()\n        XCTAssertNotNil(command2)\n        XCTAssertEqual(command2.path.urlComponent, \"/files/file\")\n        XCTAssertEqual(command2.method, API.Method.DELETE)\n        XCTAssertNil(command2.params)\n        XCTAssertNil(command2.body)\n    }\n\n    func testDownloadCommand() {\n        guard let url = URL(string: \"http://localhost/\") else {\n            XCTFail(\"Should have created url\")\n            return\n        }\n        var file = ParseFile(name: \"a\", cloudURL: url)\n        file.url = url\n        let command = file.downloadFileCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/files/a\")\n        XCTAssertEqual(command.method, API.Method.GET)\n        XCTAssertNil(command.params)\n        XCTAssertNil(command.body)\n\n        let file2 = ParseFile(cloudURL: url)\n        let command2 = file2.downloadFileCommand()\n        XCTAssertNotNil(command2)\n        XCTAssertEqual(command2.path.urlComponent, \"/files/file\")\n        XCTAssertEqual(command2.method, API.Method.GET)\n        XCTAssertNil(command2.params)\n        XCTAssertNil(command2.body)\n    }\n\n    func testLocalUUID() throws {\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        let parseFile = ParseFile(name: \"sampleData.txt\", data: sampleData)\n        let localId = parseFile.id\n        XCTAssertNotNil(localId)\n        XCTAssertEqual(localId,\n                       parseFile.id,\n                       \"localId should remain the same no matter how many times the getter is called\")\n    }\n\n    func testFileEquality() throws {\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n\n        guard let url1 = URL(string: \"https://parseplatform.org/img/logo.svg\"),\n              let url2 = URL(string: \"https://parseplatform.org/img/logo2.svg\") else {\n            throw ParseError(code: .unknownError, message: \"Should have created urls\")\n        }\n\n        var parseFile1 = ParseFile(name: \"sampleData.txt\", data: sampleData)\n        parseFile1.url = url1\n        var parseFile2 = ParseFile(name: \"sampleData2.txt\", data: sampleData)\n        parseFile2.url = url2\n        var parseFile3 = ParseFile(name: \"sampleData3.txt\", data: sampleData)\n        parseFile3.url = url1\n        XCTAssertNotEqual(parseFile1, parseFile2, \"different urls, url takes precedence over localId\")\n        XCTAssertEqual(parseFile1, parseFile3, \"same urls\")\n        parseFile1.url = nil\n        parseFile2.url = nil\n        XCTAssertNotEqual(parseFile1, parseFile2, \"no urls, but localIds shoud be different\")\n        let uuid = UUID()\n        parseFile1.id = uuid\n        parseFile2.id = uuid\n        XCTAssertEqual(parseFile1, parseFile2, \"no urls, but localIds shoud be the same\")\n    }\n\n    func testDebugString() throws {\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        let parseFile = ParseFile(name: \"sampleData.txt\",\n                                  data: sampleData,\n                                  metadata: [\"Testing\": \"123\"],\n                                  tags: [\"Hey\": \"now\"])\n        XCTAssertEqual(parseFile.debugDescription,\n                       \"{\\\"__type\\\":\\\"File\\\",\\\"name\\\":\\\"sampleData.txt\\\"}\")\n        XCTAssertEqual(parseFile.description,\n                       \"{\\\"__type\\\":\\\"File\\\",\\\"name\\\":\\\"sampleData.txt\\\"}\")\n    }\n\n    func testDebugStringWithFolderInName() throws {\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        let parseFile = ParseFile(name: \"myFolder/sampleData.txt\",\n                                  data: sampleData,\n                                  metadata: [\"Testing\": \"123\"],\n                                  tags: [\"Hey\": \"now\"])\n        XCTAssertEqual(parseFile.debugDescription,\n                       \"{\\\"__type\\\":\\\"File\\\",\\\"name\\\":\\\"myFolder\\\\/sampleData.txt\\\"}\")\n        XCTAssertEqual(parseFile.description,\n                       \"{\\\"__type\\\":\\\"File\\\",\\\"name\\\":\\\"myFolder\\\\/sampleData.txt\\\"}\")\n    }\n\n    func testSave() throws {\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        let parseFile = ParseFile(name: \"sampleData.txt\",\n                                  data: sampleData,\n                                  metadata: [\"Testing\": \"123\"],\n                                  tags: [\"Hey\": \"now\"])\n\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_sampleData.txt\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let response = FileUploadResponse(name: \"89d74fcfa4faa5561799e5076593f67c_\\(parseFile.name)\", url: url)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let savedFile = try parseFile.save()\n        XCTAssertEqual(savedFile.name, response.name)\n        XCTAssertEqual(savedFile.url, response.url)\n    }\n\n    func testSaveWithSpecifyingMime() throws {\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        let parseFile = ParseFile(data: sampleData, mimeType: \"application/txt\")\n\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_file\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let response = FileUploadResponse(name: \"89d74fcfa4faa5561799e5076593f67c_\\(parseFile.name)\", url: url)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let savedFile = try parseFile.save()\n        XCTAssertEqual(savedFile.name, response.name)\n        XCTAssertEqual(savedFile.url, response.url)\n    }\n\n    func testSaveLocalFile() throws {\n        let tempFilePath = URL(fileURLWithPath: \"\\(temporaryDirectory)sampleData.txt\")\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        try sampleData.write(to: tempFilePath)\n\n        let parseFile = ParseFile(name: \"sampleData.txt\", localURL: tempFilePath)\n\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_sampleData.txt\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let response = FileUploadResponse(name: \"89d74fcfa4faa5561799e5076593f67c_\\(parseFile.name)\", url: url)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let savedFile = try parseFile.save()\n        XCTAssertEqual(savedFile.name, response.name)\n        XCTAssertEqual(savedFile.url, response.url)\n        XCTAssertEqual(savedFile.localURL, tempFilePath)\n    }\n\n    func testSaveFileStream() throws {\n        let tempFilePath = URL(fileURLWithPath: \"\\(temporaryDirectory)sampleData.dat\")\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        try sampleData.write(to: tempFilePath)\n\n        let parseFile = ParseFile(name: \"sampleData.data\", localURL: tempFilePath)\n\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_sampleData.txt\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let response = FileUploadResponse(name: \"89d74fcfa4faa5561799e5076593f67c_\\(parseFile.name)\", url: url)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        guard let stream = InputStream(fileAtPath: tempFilePath.relativePath) else {\n            throw ParseError(code: .unknownError, message: \"Should have created file stream\")\n        }\n        try parseFile.save(options: [], stream: stream, progress: nil)\n    }\n\n    func testSaveFileStreamProgress() throws {\n        let tempFilePath = URL(fileURLWithPath: \"\\(temporaryDirectory)sampleData.dat\")\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        try sampleData.write(to: tempFilePath)\n\n        let parseFile = ParseFile(name: \"sampleData.data\", localURL: tempFilePath)\n\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_sampleData.txt\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let response = FileUploadResponse(name: \"89d74fcfa4faa5561799e5076593f67c_\\(parseFile.name)\", url: url)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        guard let stream = InputStream(fileAtPath: tempFilePath.relativePath) else {\n            throw ParseError(code: .unknownError, message: \"Should have created file stream\")\n        }\n\n        try parseFile.save(stream: stream) { (_, _, totalWritten, totalExpected) in\n            let currentProgess = Double(totalWritten)/Double(totalExpected) * 100\n            XCTAssertGreaterThan(currentProgess, -1)\n        }\n    }\n\n    func testSaveFileStreamCancel() throws {\n        let tempFilePath = URL(fileURLWithPath: \"\\(temporaryDirectory)sampleData.dat\")\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        try sampleData.write(to: tempFilePath)\n\n        let parseFile = ParseFile(name: \"sampleData.data\", localURL: tempFilePath)\n\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_sampleData.txt\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let response = FileUploadResponse(name: \"89d74fcfa4faa5561799e5076593f67c_\\(parseFile.name)\", url: url)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        guard let stream = InputStream(fileAtPath: tempFilePath.relativePath) else {\n            throw ParseError(code: .unknownError, message: \"Should have created file stream\")\n        }\n\n        try parseFile.save(stream: stream) { (task, _, totalWritten, totalExpected) in\n            let currentProgess = Double(totalWritten)/Double(totalExpected) * 100\n            if currentProgess > 10 {\n                task.cancel()\n            }\n        }\n    }\n\n    func testUpdateFileError() throws {\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        var parseFile = ParseFile(name: \"sampleData.txt\",\n                                  data: sampleData,\n                                  metadata: [\"Testing\": \"123\"],\n                                  tags: [\"Hey\": \"now\"])\n        parseFile.url = URL(string: \"http://localhost/\")\n\n        XCTAssertThrowsError(try parseFile.save())\n    }\n\n    func testFetchFileStream() throws {\n        let tempFilePath = URL(fileURLWithPath: \"\\(temporaryDirectory)sampleData.dat\")\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        try sampleData.write(to: tempFilePath)\n\n        let parseFile = ParseFile(name: \"sampleData.data\", localURL: tempFilePath)\n\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_sampleData.txt\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let response = FileUploadResponse(name: \"89d74fcfa4faa5561799e5076593f67c_\\(parseFile.name)\", url: url)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        guard let stream = InputStream(fileAtPath: tempFilePath.relativePath) else {\n            throw ParseError(code: .unknownError, message: \"Should have created file stream\")\n        }\n        try parseFile.fetch(stream: stream)\n    }\n\n    func testSaveAysnc() throws {\n\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        let parseFile = ParseFile(name: \"sampleData.txt\", data: sampleData)\n\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_sampleData.txt\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let response = FileUploadResponse(name: \"89d74fcfa4faa5561799e5076593f67c_\\(parseFile.name)\", url: url)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"ParseFile async\")\n        parseFile.save { result in\n\n            switch result {\n            case .success(let saved):\n                XCTAssertEqual(saved.name, response.name)\n                XCTAssertEqual(saved.url, response.url)\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSaveFileProgressAsync() throws {\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        let parseFile = ParseFile(name: \"sampleData.txt\", data: sampleData)\n\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_sampleData.txt\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let response = FileUploadResponse(name: \"89d74fcfa4faa5561799e5076593f67c_\\(parseFile.name)\", url: url)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"ParseFile async\")\n        parseFile.save(progress: { (_, _, totalWritten, totalExpected) in\n            let currentProgess = Double(totalWritten)/Double(totalExpected) * 100\n            XCTAssertGreaterThan(currentProgess, -1)\n        }) { result in // swiftlint:disable:this multiple_closures_with_trailing_closure\n\n            switch result {\n            case .success(let saved):\n                XCTAssertEqual(saved.name, response.name)\n                XCTAssertEqual(saved.url, response.url)\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSaveFileCancelAsync() throws {\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        let parseFile = ParseFile(name: \"sampleData.txt\", data: sampleData)\n\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_sampleData.txt\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let response = FileUploadResponse(name: \"89d74fcfa4faa5561799e5076593f67c_\\(parseFile.name)\", url: url)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"ParseFile async\")\n        parseFile.save(progress: { (task, _, totalWritten, totalExpected) in\n            let currentProgess = Double(totalWritten)/Double(totalExpected) * 100\n            if currentProgess > 10 {\n                task.cancel()\n            }\n        }) { result in // swiftlint:disable:this multiple_closures_with_trailing_closure\n\n            switch result {\n            case .success(let saved):\n                XCTAssertEqual(saved.name, response.name)\n                XCTAssertEqual(saved.url, response.url)\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSaveWithSpecifyingMimeAysnc() throws {\n\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        let parseFile = ParseFile(data: sampleData, mimeType: \"application/txt\")\n\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_file\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let response = FileUploadResponse(name: \"89d74fcfa4faa5561799e5076593f67c_\\(parseFile.name)\", url: url)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"ParseFile async\")\n        parseFile.save { result in\n\n            switch result {\n            case .success(let saved):\n                XCTAssertEqual(saved.name, response.name)\n                XCTAssertEqual(saved.url, response.url)\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSaveLocalFileAysnc() throws {\n\n        let tempFilePath = URL(fileURLWithPath: \"\\(temporaryDirectory)sampleData.txt\")\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        try sampleData.write(to: tempFilePath)\n\n        let parseFile = ParseFile(name: \"sampleData.txt\", localURL: tempFilePath)\n\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_sampleData.txt\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let response = FileUploadResponse(name: \"89d74fcfa4faa5561799e5076593f67c_\\(parseFile.name)\", url: url)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"ParseFile async\")\n        parseFile.save { result in\n\n            switch result {\n            case .success(let saved):\n                XCTAssertEqual(saved.name, response.name)\n                XCTAssertEqual(saved.url, response.url)\n                XCTAssertEqual(saved.localURL, tempFilePath)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUpdateErrorAysnc() throws {\n\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        var parseFile = ParseFile(name: \"sampleData.txt\", data: sampleData)\n        parseFile.url = URL(string: \"http://localhost/\")\n\n        let expectation1 = XCTestExpectation(description: \"ParseFile async\")\n        parseFile.save { result in\n\n            switch result {\n            case .success:\n                XCTFail(\"Should have returned error\")\n            case .failure(let error):\n                XCTAssertTrue(error.message.contains(\"File is already\"))\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    #if compiler(<5.5.2)\n    func testParseURLSessionDelegates() throws {\n        // swiftlint:disable:next line_length\n        let dowloadTask = URLSession.shared.downloadTask(with: .init(fileURLWithPath: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\"))\n        let task = dowloadTask as URLSessionTask\n        // swiftlint:disable:next line_length\n        let uploadCompletion: ((URLSessionTask, Int64, Int64, Int64) -> Void) = { (_: URLSessionTask, _: Int64, _: Int64, _: Int64) -> Void in }\n        // swiftlint:disable:next line_length\n        let dowbloadCompletion: ((URLSessionDownloadTask, Int64, Int64, Int64) -> Void) = { (_: URLSessionDownloadTask, _: Int64, _: Int64, _: Int64) -> Void in }\n\n        // Add tasks\n        Parse.sessionDelegate.taskCallbackQueues[task] = DispatchQueue.main\n        XCTAssertEqual(Parse.sessionDelegate.taskCallbackQueues.count, 1)\n        Parse.sessionDelegate.streamDelegates[task] = .init(data: .init())\n        XCTAssertEqual(Parse.sessionDelegate.streamDelegates.count, 1)\n        Parse.sessionDelegate.uploadDelegates[task] = uploadCompletion\n        XCTAssertEqual(Parse.sessionDelegate.uploadDelegates.count, 1)\n        Parse.sessionDelegate.downloadDelegates[dowloadTask] = dowbloadCompletion\n        XCTAssertEqual(Parse.sessionDelegate.downloadDelegates.count, 1)\n\n        // Remove tasks\n        Parse.sessionDelegate.taskCallbackQueues.removeValue(forKey: task)\n        XCTAssertEqual(Parse.sessionDelegate.taskCallbackQueues.count, 0)\n        Parse.sessionDelegate.streamDelegates.removeValue(forKey: task)\n        XCTAssertEqual(Parse.sessionDelegate.streamDelegates.count, 0)\n        Parse.sessionDelegate.uploadDelegates.removeValue(forKey: task)\n        XCTAssertEqual(Parse.sessionDelegate.uploadDelegates.count, 0)\n        Parse.sessionDelegate.downloadDelegates.removeValue(forKey: dowloadTask)\n        XCTAssertEqual(Parse.sessionDelegate.downloadDelegates.count, 0)\n    }\n\n    func testParseURLSessionDelegateUpload() throws {\n        // swiftlint:disable:next line_length\n        let downloadTask = URLSession.shared.downloadTask(with: .init(fileURLWithPath: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\"))\n        let task = downloadTask as URLSessionTask\n        let queue = DispatchQueue.global(qos: .utility)\n\n        let expectation1 = XCTestExpectation(description: \"Call delegate 1\")\n        let expectation2 = XCTestExpectation(description: \"Call delegate 2\")\n\n        // swiftlint:disable:next line_length\n        let uploadCompletion: ((URLSessionTask, Int64, Int64, Int64) -> Void) = { (_: URLSessionTask, _: Int64, sent: Int64, total: Int64) -> Void in\n            if sent < total {\n                let uploadCount = Parse.sessionDelegate.uploadDelegates.count\n                let taskCount = Parse.sessionDelegate.taskCallbackQueues.count\n                XCTAssertEqual(uploadCount, 1)\n                XCTAssertEqual(taskCount, 1)\n                expectation1.fulfill()\n                Parse.sessionDelegate.urlSession(URLSession.parse, task: task, didCompleteWithError: nil)\n                DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n                    let uploadCount = Parse.sessionDelegate.uploadDelegates.count\n                    let taskCount = Parse.sessionDelegate.taskCallbackQueues.count\n                    XCTAssertEqual(uploadCount, 0)\n                    XCTAssertEqual(taskCount, 0)\n                    expectation2.fulfill()\n                }\n            }\n        }\n\n        // Add tasks\n        Parse.sessionDelegate.uploadDelegates[task] = uploadCompletion\n        Parse.sessionDelegate.taskCallbackQueues[task] = queue\n\n        Parse.sessionDelegate.urlSession(URLSession.parse,\n                                              task: task,\n                                              didSendBodyData: 0,\n                                              totalBytesSent: 0,\n                                              totalBytesExpectedToSend: 10)\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testParseURLSessionDelegateDownload() throws {\n        // swiftlint:disable:next line_length\n        let downloadTask = URLSession.shared.downloadTask(with: .init(fileURLWithPath: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\"))\n        let task = downloadTask as URLSessionTask\n        let queue = DispatchQueue.global(qos: .utility)\n        guard let fileManager = ParseFileManager(),\n              let filePath = fileManager.dataItemPathForPathComponent(\"test.txt\") else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Call delegate 1\")\n        let expectation2 = XCTestExpectation(description: \"Call delegate 2\")\n\n        // swiftlint:disable:next line_length\n        let downloadCompletion: ((URLSessionDownloadTask, Int64, Int64, Int64) -> Void) = { (_: URLSessionDownloadTask, _: Int64, sent: Int64, total: Int64) -> Void in\n            if sent < total {\n                let downloadCount = Parse.sessionDelegate.downloadDelegates.count\n                let taskCount = Parse.sessionDelegate.taskCallbackQueues.count\n                XCTAssertEqual(downloadCount, 1)\n                XCTAssertEqual(taskCount, 1)\n                expectation1.fulfill()\n                Parse.sessionDelegate.urlSession(URLSession.parse,\n                                                      downloadTask: downloadTask,\n                                                      didFinishDownloadingTo: filePath)\n                DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n                    let downloadCount = Parse.sessionDelegate.downloadDelegates.count\n                    let taskCount = Parse.sessionDelegate.taskCallbackQueues.count\n                    XCTAssertEqual(downloadCount, 0)\n                    XCTAssertEqual(taskCount, 0)\n                    expectation2.fulfill()\n                }\n            }\n        }\n\n        // Add tasks\n        Parse.sessionDelegate.downloadDelegates[downloadTask] = downloadCompletion\n        Parse.sessionDelegate.taskCallbackQueues[task] = queue\n\n        Parse.sessionDelegate.urlSession(URLSession.parse,\n                                              downloadTask: downloadTask,\n                                              didWriteData: 0,\n                                              totalBytesWritten: 0,\n                                              totalBytesExpectedToWrite: 10)\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testParseURLSessionDelegateStream() throws {\n        // swiftlint:disable:next line_length\n        let downloadTask = URLSession.shared.downloadTask(with: .init(fileURLWithPath: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\"))\n        let task = downloadTask as URLSessionTask\n        let queue = DispatchQueue.global(qos: .utility)\n\n        let expectation1 = XCTestExpectation(description: \"Call delegate 1\")\n        let expectation2 = XCTestExpectation(description: \"Call delegate 2\")\n\n        let streamCompletion: ((InputStream?) -> Void) = { (_: InputStream?) -> Void in\n            let streamCount = Parse.sessionDelegate.streamDelegates.count\n            let taskCount = Parse.sessionDelegate.taskCallbackQueues.count\n            XCTAssertEqual(streamCount, 1)\n            XCTAssertEqual(taskCount, 1)\n            expectation1.fulfill()\n            Parse.sessionDelegate.urlSession(URLSession.parse, task: task, didCompleteWithError: nil)\n            DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n                let streamCount = Parse.sessionDelegate.streamDelegates.count\n                let taskCount = Parse.sessionDelegate.taskCallbackQueues.count\n                XCTAssertEqual(streamCount, 0)\n                XCTAssertEqual(taskCount, 0)\n                expectation2.fulfill()\n            }\n        }\n\n        // Add tasks\n        Parse.sessionDelegate.streamDelegates[task] = .init(data: .init())\n        Parse.sessionDelegate.taskCallbackQueues[task] = queue\n\n        Parse.sessionDelegate.urlSession(URLSession.parse, task: task, needNewBodyStream: streamCompletion)\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n    #endif\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n\n    // URL Mocker is not able to mock this in linux and tests fail, so do not run.\n    func testFetchFileCancelAsync() throws {\n        // swiftlint:disable:next line_length\n        guard let parseFileURL = URL(string: \"http://localhost:1337/1/files/applicationId/7793939a2e59b98138c1bbf2412a060c_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        var parseFile = ParseFile(name: \"7793939a2e59b98138c1bbf2412a060c_logo.svg\", cloudURL: parseFileURL)\n        parseFile.url = parseFileURL\n\n        let response = FileUploadResponse(name: \"7793939a2e59b98138c1bbf2412a060c_logo.svg\",\n                                          url: parseFileURL)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"ParseFile async\")\n        parseFile.fetch(progress: { (task, _, totalDownloaded, totalExpected) in\n            let currentProgess = Double(totalDownloaded)/Double(totalExpected) * 100\n            if currentProgess > 10 {\n                task.cancel()\n            }\n        }) { result in // swiftlint:disable:this multiple_closures_with_trailing_closure\n\n            switch result {\n            case .success(let fetched):\n                XCTAssertEqual(fetched.name, response.name)\n                XCTAssertEqual(fetched.url, response.url)\n                XCTAssertNotNil(fetched.localURL)\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testFetchFileAysnc() throws {\n\n        // swiftlint:disable:next line_length\n        guard let parseFileURL = URL(string: \"http://localhost:1337/1/files/applicationId/7793939a2e59b98138c1bbf2412a060c_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        var parseFile = ParseFile(name: \"7793939a2e59b98138c1bbf2412a060c_logo.svg\", cloudURL: parseFileURL)\n        parseFile.url = parseFileURL\n\n        let response = FileUploadResponse(name: \"7793939a2e59b98138c1bbf2412a060c_logo.svg\",\n                                          url: parseFileURL)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"ParseFile async\")\n        parseFile.fetch { result in\n\n            switch result {\n            case .success(let fetched):\n                XCTAssertEqual(fetched.name, response.name)\n                XCTAssertEqual(fetched.url, response.url)\n                XCTAssertNotNil(fetched.localURL)\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testFetchFileProgressAsync() throws {\n        // swiftlint:disable:next line_length\n        guard let parseFileURL = URL(string: \"http://localhost:1337/1/files/applicationId/6f9988ab5faa28f7247664c6ffd9fd85_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        var parseFile = ParseFile(name: \"6f9988ab5faa28f7247664c6ffd9fd85_logo.svg\", cloudURL: parseFileURL)\n        parseFile.url = parseFileURL\n\n        let response = FileUploadResponse(name: \"6f9988ab5faa28f7247664c6ffd9fd85_logo.svg\",\n                                          url: parseFileURL)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"ParseFile async\")\n        parseFile.fetch(progress: { (_, _, totalDownloaded, totalExpected) in\n            let currentProgess = Double(totalDownloaded)/Double(totalExpected) * 100\n            XCTAssertGreaterThan(currentProgess, -1)\n        }) { result in // swiftlint:disable:this multiple_closures_with_trailing_closure\n\n            switch result {\n            case .success(let fetched):\n                XCTAssertEqual(fetched.name, response.name)\n                XCTAssertEqual(fetched.url, response.url)\n                XCTAssertNotNil(fetched.localURL)\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSaveCloudFileProgressAysnc() throws {\n\n        guard let tempFilePath = URL(string: \"https://parseplatform.org/img/logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n\n        let parseFile = ParseFile(name: \"logo.svg\", cloudURL: tempFilePath)\n\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let response = FileUploadResponse(name: \"89d74fcfa4faa5561799e5076593f67c_\\(parseFile.name)\", url: url)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"ParseFile async\")\n        parseFile.save(progress: { (_, _, totalWritten, totalExpected) in\n            let currentProgess = Double(totalWritten)/Double(totalExpected) * 100\n            XCTAssertGreaterThan(currentProgess, -1)\n        }) { result in // swiftlint:disable:this multiple_closures_with_trailing_closure\n\n            switch result {\n            case .success(let saved):\n                XCTAssertEqual(saved.name, response.name)\n                XCTAssertEqual(saved.url, response.url)\n                XCTAssertEqual(saved.cloudURL, tempFilePath)\n                XCTAssertNotNil(saved.localURL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSaveCloudFileAysnc() throws {\n\n        guard let tempFilePath = URL(string: \"https://parseplatform.org/img/logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n\n        let parseFile = ParseFile(name: \"logo.svg\", cloudURL: tempFilePath)\n\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let response = FileUploadResponse(name: \"89d74fcfa4faa5561799e5076593f67c_\\(parseFile.name)\", url: url)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"ParseFile async\")\n        parseFile.save { result in\n\n            switch result {\n            case .success(let saved):\n                XCTAssertEqual(saved.name, response.name)\n                XCTAssertEqual(saved.url, response.url)\n                XCTAssertEqual(saved.cloudURL, tempFilePath)\n                XCTAssertNotNil(saved.localURL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSaveCloudFile() throws {\n        guard let tempFilePath = URL(string: \"https://parseplatform.org/img/logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n\n        let parseFile = ParseFile(name: \"logo.svg\", cloudURL: tempFilePath)\n\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let response = FileUploadResponse(name: \"89d74fcfa4faa5561799e5076593f67c_\\(parseFile.name)\", url: url)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let savedFile = try parseFile.save()\n        XCTAssertEqual(savedFile.name, response.name)\n        XCTAssertEqual(savedFile.url, response.url)\n        XCTAssertEqual(savedFile.cloudURL, tempFilePath)\n        XCTAssertNotNil(savedFile.localURL)\n    }\n\n    func testFetchFile() throws {\n        // swiftlint:disable:next line_length\n        guard let parseFileURL = URL(string: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        var parseFile = ParseFile(name: \"d3a37aed0672a024595b766f97133615_logo.svg\", cloudURL: parseFileURL)\n        parseFile.url = parseFileURL\n\n        let response = FileUploadResponse(name: \"d3a37aed0672a024595b766f97133615_logo.svg\",\n                                          url: parseFileURL)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let fetchedFile = try parseFile.fetch()\n        XCTAssertEqual(fetchedFile.name, response.name)\n        XCTAssertEqual(fetchedFile.url, response.url)\n        XCTAssertNotNil(fetchedFile.localURL)\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let fetchedFileCached = try parseFile.fetch(options: [.cachePolicy(.returnCacheDataDontLoad)])\n        XCTAssertEqual(fetchedFileCached, fetchedFile)\n    }\n\n    func testFetchFileLoadFromRemote() throws {\n        // swiftlint:disable:next line_length\n        guard let parseFileURL = URL(string: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        var parseFile = ParseFile(name: \"d3a37aed0672a024595b766f97133615_logo.svg\", cloudURL: parseFileURL)\n        parseFile.url = parseFileURL\n\n        let response = FileUploadResponse(name: \"d3a37aed0672a024595b766f97133615_logo.svg\",\n                                          url: parseFileURL)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let fetchedFile = try parseFile.fetch(options: [.cachePolicy(.reloadIgnoringLocalAndRemoteCacheData)])\n        XCTAssertEqual(fetchedFile.name, response.name)\n        XCTAssertEqual(fetchedFile.url, response.url)\n        XCTAssertNotNil(fetchedFile.localURL)\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let fetchedFileCached = try parseFile.fetch(options: [.cachePolicy(.returnCacheDataDontLoad)])\n        XCTAssertEqual(fetchedFileCached, fetchedFile)\n    }\n\n    func testFetchFileLoadFromCacheNoCache() throws {\n        // swiftlint:disable:next line_length\n        guard let parseFileURL = URL(string: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        var parseFile = ParseFile(name: \"d3a37aed0672a024595b766f97133615_logo.svg\", cloudURL: parseFileURL)\n        parseFile.url = parseFileURL\n\n        do {\n            _ = try parseFile.fetch(options: [.cachePolicy(.returnCacheDataDontLoad)])\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(parseError.code, .unsavedFileFailure)\n        }\n    }\n\n    func testFetchFileWithDirectoryInName() throws {\n        // swiftlint:disable:next line_length\n        guard let parseFileURL = URL(string: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        var parseFile = ParseFile(name: \"myFolder/d3a37aed0672a024595b766f97133615_logo.svg\", cloudURL: parseFileURL)\n        parseFile.url = parseFileURL\n\n        let response = FileUploadResponse(name: \"myFolder/d3a37aed0672a024595b766f97133615_logo.svg\",\n                                          url: parseFileURL)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let fetchedFile = try parseFile.fetch()\n        XCTAssertEqual(fetchedFile.name, response.name)\n        XCTAssertEqual(fetchedFile.url, response.url)\n        guard let localURL = fetchedFile.localURL else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertFalse(localURL.pathComponents.contains(\"myFolder\"))\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let fetchedFileCached = try parseFile.fetch(options: [.cachePolicy(.returnCacheDataDontLoad)])\n        XCTAssertEqual(fetchedFileCached, fetchedFile)\n    }\n\n    func testFetchFileProgress() throws {\n        // swiftlint:disable:next line_length\n        guard let parseFileURL = URL(string: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        var parseFile = ParseFile(name: \"d3a37aed0672a024595b766f97133615_logo.svg\", cloudURL: parseFileURL)\n        parseFile.url = parseFileURL\n\n        let response = FileUploadResponse(name: \"d3a37aed0672a024595b766f97133615_logo.svg\",\n                                          url: parseFileURL)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let fetchedFile = try parseFile.fetch { (_, _, totalDownloaded, totalExpected) in\n            let currentProgess = Double(totalDownloaded)/Double(totalExpected) * 100\n            XCTAssertGreaterThan(currentProgess, -1)\n        }\n        XCTAssertEqual(fetchedFile.name, response.name)\n        XCTAssertEqual(fetchedFile.url, response.url)\n        XCTAssertNotNil(fetchedFile.localURL)\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        // swiftlint:disable:next line_length\n        let fetchedFileCached = try parseFile.fetch(options: [.cachePolicy(.returnCacheDataDontLoad)]) { (_, _, totalDownloaded, totalExpected) in\n            let currentProgess = Double(totalDownloaded)/Double(totalExpected) * 100\n            XCTAssertGreaterThan(currentProgess, -1)\n        }\n        XCTAssertEqual(fetchedFileCached, fetchedFile)\n    }\n\n    func testFetchFileProgressLoadFromRemote() throws {\n        // swiftlint:disable:next line_length\n        guard let parseFileURL = URL(string: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        var parseFile = ParseFile(name: \"d3a37aed0672a024595b766f97133615_logo.svg\", cloudURL: parseFileURL)\n        parseFile.url = parseFileURL\n\n        let response = FileUploadResponse(name: \"d3a37aed0672a024595b766f97133615_logo.svg\",\n                                          url: parseFileURL)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        // swiftlint:disable:next line_length\n        let fetchedFile = try parseFile.fetch(options: [.cachePolicy(.reloadIgnoringLocalAndRemoteCacheData)]) { (_, _, totalDownloaded, totalExpected) in\n            let currentProgess = Double(totalDownloaded)/Double(totalExpected) * 100\n            XCTAssertGreaterThan(currentProgess, -1)\n        }\n        XCTAssertEqual(fetchedFile.name, response.name)\n        XCTAssertEqual(fetchedFile.url, response.url)\n        XCTAssertNotNil(fetchedFile.localURL)\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        // swiftlint:disable:next line_length\n        let fetchedFileCached = try parseFile.fetch(options: [.cachePolicy(.returnCacheDataDontLoad)]) { (_, _, totalDownloaded, totalExpected) in\n            let currentProgess = Double(totalDownloaded)/Double(totalExpected) * 100\n            XCTAssertGreaterThan(currentProgess, -1)\n        }\n        XCTAssertEqual(fetchedFileCached, fetchedFile)\n    }\n\n    func testFetchFileProgressFromCacheNoCache() throws {\n        // swiftlint:disable:next line_length\n        guard let parseFileURL = URL(string: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        var parseFile = ParseFile(name: \"d3a37aed0672a024595b766f97133615_logo.svg\", cloudURL: parseFileURL)\n        parseFile.url = parseFileURL\n\n        do {\n            // swiftlint:disable:next line_length\n            _ = try parseFile.fetch(options: [.cachePolicy(.returnCacheDataDontLoad)]) { (_, _, totalDownloaded, totalExpected) in\n                let currentProgess = Double(totalDownloaded)/Double(totalExpected) * 100\n                XCTAssertGreaterThan(currentProgess, -1)\n            }\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(parseError.code, .unsavedFileFailure)\n        }\n    }\n\n    func testDeleteFileAysnc() throws {\n        // swiftlint:disable:next line_length\n        guard let parseFileURL = URL(string: \"http://localhost:1337/1/files/applicationId/1b0683d529463e173cbf8046d7d9a613_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        var parseFile = ParseFile(name: \"1b0683d529463e173cbf8046d7d9a613_logo.svg\", cloudURL: parseFileURL)\n        parseFile.url = parseFileURL\n\n        let response = FileUploadResponse(name: \"1b0683d529463e173cbf8046d7d9a613_logo.svg\",\n                                          url: parseFileURL)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"ParseFile async\")\n        parseFile.delete(options: [.useMasterKey]) { result in\n\n            if case let .failure(error) = result {\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDeleteFileAysncError() throws {\n        // swiftlint:disable:next line_length\n        guard let parseFileURL = URL(string: \"http://localhost:1337/1/files/applicationId/1b0683d529463e173cbf8046d7d9a613_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        var parseFile = ParseFile(name: \"1b0683d529463e173cbf8046d7d9a613_logo.svg\", cloudURL: parseFileURL)\n        parseFile.url = parseFileURL\n\n        let response = ParseError(code: .fileTooLarge, message: \"Too large.\")\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"ParseFile async\")\n        parseFile.delete(options: [.useMasterKey]) { result in\n\n            if case .success = result {\n                XCTFail(\"Should have failed with error\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDeleteFile() throws {\n        // swiftlint:disable:next line_length\n        guard let parseFileURL = URL(string: \"http://localhost:1337/1/files/applicationId/d3a37aed0672a024595b766f97133615_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        var parseFile = ParseFile(name: \"d3a37aed0672a024595b766f97133615_logo.svg\", cloudURL: parseFileURL)\n        parseFile.url = parseFileURL\n\n        let response = FileUploadResponse(name: \"d3a37aed0672a024595b766f97133615_logo.svg\",\n                                          url: parseFileURL)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        try parseFile.delete(options: [.useMasterKey])\n    }\n\n    func testCloudFileProgress() throws {\n        guard let tempFilePath = URL(string: \"https://parseplatform.org/img/logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n\n        let parseFile = ParseFile(name: \"logo.svg\", cloudURL: tempFilePath)\n\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let response = FileUploadResponse(name: \"89d74fcfa4faa5561799e5076593f67c_\\(parseFile.name)\", url: url)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let savedFile = try parseFile.save { (_, _, totalWritten, totalExpected) in\n            let currentProgess = Double(totalWritten)/Double(totalExpected) * 100\n            XCTAssertGreaterThan(currentProgess, -1)\n        }\n        XCTAssertEqual(savedFile.name, response.name)\n        XCTAssertEqual(savedFile.url, response.url)\n        XCTAssertEqual(savedFile.cloudURL, tempFilePath)\n        XCTAssertNotNil(savedFile.localURL)\n    }\n\n    func testCloudFileCancel() throws {\n        guard let tempFilePath = URL(string: \"https://parseplatform.org/img/logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n\n        let parseFile = ParseFile(name: \"logo.svg\", cloudURL: tempFilePath)\n\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let response = FileUploadResponse(name: \"89d74fcfa4faa5561799e5076593f67c_\\(parseFile.name)\", url: url)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let savedFile = try parseFile.save { (task, _, totalWritten, totalExpected) in\n            let currentProgess = Double(totalWritten)/Double(totalExpected) * 100\n            if currentProgess > 10 {\n                task.cancel()\n            }\n        }\n        XCTAssertEqual(savedFile.name, response.name)\n        XCTAssertEqual(savedFile.url, response.url)\n        XCTAssertEqual(savedFile.cloudURL, tempFilePath)\n        XCTAssertNotNil(savedFile.localURL)\n    }\n    #endif\n} // swiftlint:disable:this file_length\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseFileTransferableTests.swift",
    "content": "//\n//  ParseFileTransferableTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/13/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseFileTransferableTests: XCTestCase {\n    let temporaryDirectory = \"\\(NSTemporaryDirectory())test/\"\n\n    struct FileUploadResponse: Codable, Equatable {\n        let name: String\n        let url: URL\n    }\n\n    class TestFileTransfer: ParseFileTransferable {\n        let name: String\n        let url: URL\n\n        init(name: String, url: URL?) throws {\n            guard let url = url else {\n                throw ParseError(code: .unknownError,\n                                 message: \"URL should not be nil\")\n            }\n            self.url = url\n            self.name = name\n        }\n\n        func upload(with request: URLRequest,\n                    from bodyData: Data?,\n                    // swiftlint:disable:next line_length\n                    completion: @escaping (Data?, URLResponse?, URLRequest?, Error?) -> Void) throws -> URLSessionUploadTask {\n            try fakeUpload(completion: completion)\n        }\n\n        func upload(with request: URLRequest,\n                    fromFile fileURL: URL,\n                    // swiftlint:disable:next line_length\n                    completion: @escaping (Data?, URLResponse?, URLRequest?, Error?) -> Void) throws -> URLSessionUploadTask {\n            try fakeUpload(completion: completion)\n        }\n\n        func fakeUpload(completion: @escaping (Data?,\n                                               URLResponse?,\n                                               URLRequest?,\n                                               Error?) -> Void) throws -> URLSessionUploadTask {\n            let response = try makeSuccessfulUploadResponse(name, url: url)\n            DispatchQueue.main.asyncAfter(deadline: .now() + 3) {\n                completion(response.0, response.1, nil, nil)\n            }\n            return try makeDummyUploadTask()\n        }\n    }\n\n    class TestFileTransferThrowError: ParseFileTransferable {\n        let name: String\n        let url: URL\n\n        init(name: String, url: URL?) throws {\n            guard let url = url else {\n                throw ParseError(code: .unknownError,\n                                 message: \"URL should not be nil\")\n            }\n            self.url = url\n            self.name = name\n        }\n\n        func upload(with request: URLRequest,\n                    from bodyData: Data?,\n                    // swiftlint:disable:next line_length\n                    completion: @escaping (Data?, URLResponse?, URLRequest?, Error?) -> Void) throws -> URLSessionUploadTask {\n            throw ParseError(code: .unknownError, message: \"Thrown on purpose\")\n        }\n\n        func upload(with request: URLRequest,\n                    fromFile fileURL: URL,\n                    // swiftlint:disable:next line_length\n                    completion: @escaping (Data?, URLResponse?, URLRequest?, Error?) -> Void) throws -> URLSessionUploadTask {\n            throw ParseError(code: .unknownError, message: \"Thrown on purpose\")\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n\n        guard let fileManager = ParseFileManager() else {\n            throw ParseError(code: .unknownError, message: \"Should have initialized file manage\")\n        }\n        try fileManager.createDirectoryIfNeeded(temporaryDirectory)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        URLSession.parse.configuration.urlCache?.removeAllCachedResponses()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n\n        guard let fileManager = ParseFileManager() else {\n            throw ParseError(code: .unknownError, message: \"Should have initialized file manage\")\n        }\n        let directory = URL(fileURLWithPath: temporaryDirectory, isDirectory: true)\n        let expectation1 = XCTestExpectation(description: \"Delete files1\")\n        fileManager.removeDirectoryContents(directory) { error in\n            guard let error = error else {\n                expectation1.fulfill()\n                return\n            }\n            XCTFail(error.localizedDescription)\n            expectation1.fulfill()\n        }\n        let directory2 = try ParseFileManager.downloadDirectory()\n        let expectation2 = XCTestExpectation(description: \"Delete files2\")\n        fileManager.removeDirectoryContents(directory2) { _ in\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testSDKInitializers() throws {\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        let fileTransferAdapter = try TestFileTransfer(name: \"test\", url: url)\n        let fileTransferAdapterOther = try TestFileTransfer(name: \"test\", url: url)\n        XCTAssertTrue(fileTransferAdapter !== fileTransferAdapterOther)\n        XCTAssertTrue(ParseSwift.configuration.parseFileTransfer !== fileTransferAdapter)\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              parseFileTransfer: fileTransferAdapter)\n        XCTAssertTrue(ParseSwift.configuration.parseFileTransfer === fileTransferAdapter)\n        ParseSwift.initialize(configuration: .init(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              parseFileTransfer: fileTransferAdapterOther))\n        XCTAssertTrue(ParseSwift.configuration.parseFileTransfer === fileTransferAdapterOther)\n    }\n\n    func testMakeSuccessfulUploadResponse() throws {\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        let fileTransferAdapter = try TestFileTransfer(name: \"test\", url: url)\n        let originalUploadResponse = FileUploadResponse(name: \"hello\", url: url)\n        let fileUploadResponseData = try fileTransferAdapter.makeSuccessfulUploadResponse(\"hello\",\n                                                                                          url: url)\n        let decodedUploadResponse = try ParseCoding.jsonDecoder().decode(FileUploadResponse.self,\n                                                                         from: fileUploadResponseData.0)\n        XCTAssertEqual(originalUploadResponse, decodedUploadResponse)\n        XCTAssertEqual(fileUploadResponseData.1?.url, url)\n        XCTAssertEqual(fileUploadResponseData.1?.statusCode, 200)\n    }\n\n    func testMakeDummyUploadTask() throws {\n        XCTAssertNoThrow(try ParseSwift.configuration.parseFileTransfer.makeDummyUploadTask())\n    }\n\n    func testSaveFromData() throws {\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        let fileName = \"sampleData.txt\"\n        let parseFile = ParseFile(name: \"sampleData.txt\",\n                                  data: sampleData,\n                                  metadata: [\"Testing\": \"123\"],\n                                  tags: [\"Hey\": \"now\"])\n\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_sampleData.txt\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let fileTransferAdapter = try TestFileTransfer(name: fileName, url: url)\n        Parse.configuration.parseFileTransfer = fileTransferAdapter\n\n        let expectation1 = XCTestExpectation(description: \"ParseFile save\")\n        parseFile.save { result in\n            switch result {\n            case .success(let savedFile):\n                XCTAssertEqual(savedFile.name, fileName)\n                XCTAssertEqual(savedFile.url, url)\n            case .failure(let error):\n                XCTFail(\"\\(error)\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSaveFromFile() throws {\n        let tempFilePath = URL(fileURLWithPath: \"\\(temporaryDirectory)sampleData.txt\")\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        try sampleData.write(to: tempFilePath)\n        let fileName = \"sampleData.txt\"\n        let parseFile = ParseFile(name: fileName, localURL: tempFilePath)\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_sampleData.txt\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let fileTransferAdapter = try TestFileTransfer(name: fileName, url: url)\n        Parse.configuration.parseFileTransfer = fileTransferAdapter\n\n        let expectation1 = XCTestExpectation(description: \"ParseFile save\")\n        parseFile.save { result in\n            switch result {\n            case .success(let savedFile):\n                XCTAssertEqual(savedFile.name, fileName)\n                XCTAssertEqual(savedFile.url, url)\n            case .failure(let error):\n                XCTFail(\"\\(error)\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSaveFromDataThrowError() throws {\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        let fileName = \"sampleData.txt\"\n        let parseFile = ParseFile(name: \"sampleData.txt\",\n                                  data: sampleData,\n                                  metadata: [\"Testing\": \"123\"],\n                                  tags: [\"Hey\": \"now\"])\n\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_sampleData.txt\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let fileTransferAdapter = try TestFileTransferThrowError(name: fileName, url: url)\n        Parse.configuration.parseFileTransfer = fileTransferAdapter\n\n        let expectation1 = XCTestExpectation(description: \"ParseFile save\")\n        parseFile.save { result in\n            switch result {\n            case .success:\n                XCTFail(\"Should have failed\")\n            case .failure(let error):\n                XCTAssertTrue(error.message.contains(\"purpose\"))\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSaveFromFileThrowError() throws {\n        let tempFilePath = URL(fileURLWithPath: \"\\(temporaryDirectory)sampleData.txt\")\n        guard let sampleData = \"Hello World\".data(using: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have converted to data\")\n        }\n        try sampleData.write(to: tempFilePath)\n        let fileName = \"sampleData.txt\"\n        let parseFile = ParseFile(name: fileName, localURL: tempFilePath)\n        // swiftlint:disable:next line_length\n        guard let url = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_sampleData.txt\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n        let fileTransferAdapter = try TestFileTransferThrowError(name: fileName, url: url)\n        Parse.configuration.parseFileTransfer = fileTransferAdapter\n\n        let expectation1 = XCTestExpectation(description: \"ParseFile save\")\n        parseFile.save { result in\n            switch result {\n            case .success:\n                XCTFail(\"Should have failed\")\n            case .failure(let error):\n                XCTAssertTrue(error.message.contains(\"purpose\"))\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseGeoPointTests.swift",
    "content": "//\n//  ParseGeoPointTests.swift\n//  ParseSwiftTests\n//\n//  Created by Corey Baker on 9/21/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport XCTest\n#if canImport(CoreLocation)\nimport CoreLocation\n#endif\n@testable import ParseSwift\n\nclass ParseGeoPointTests: XCTestCase {\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testDefaults() {\n        let point = ParseGeoPoint()\n        // Check default values\n        XCTAssertEqual(point.latitude, 0.0, accuracy: 0.00001, \"Latitude should be 0.0\")\n        XCTAssertEqual(point.longitude, 0.0, accuracy: 0.00001, \"Longitude should be 0.0\")\n        XCTAssertThrowsError(try ParseGeoPoint(latitude: 100, longitude: 0))\n        XCTAssertThrowsError(try ParseGeoPoint(latitude: -100, longitude: 0))\n        XCTAssertThrowsError(try ParseGeoPoint(latitude: 0, longitude: 200))\n        XCTAssertThrowsError(try ParseGeoPoint(latitude: 0, longitude: -200))\n    }\n\n    #if canImport(CoreLocation)\n    func testGeoPointFromLocation() throws {\n        let location = CLLocation(latitude: 10.0, longitude: 20.0)\n        let geoPoint = try ParseGeoPoint(location: location)\n        XCTAssertEqual(geoPoint.latitude, location.coordinate.latitude)\n        XCTAssertEqual(geoPoint.longitude, location.coordinate.longitude)\n    }\n\n    func testGeoPointFromLocationCoordinate2D() throws {\n        let location = CLLocationCoordinate2D(latitude: 10.0, longitude: 20.0)\n        let geoPoint = try ParseGeoPoint(coordinate: location)\n        XCTAssertEqual(geoPoint.latitude, location.latitude)\n        XCTAssertEqual(geoPoint.longitude, location.longitude)\n    }\n\n    func testToCLLocation() throws {\n        let point = try ParseGeoPoint(latitude: 10, longitude: 20)\n        let location = point.toCLLocation()\n        XCTAssertEqual(point.latitude, location.coordinate.latitude)\n        XCTAssertEqual(point.longitude, location.coordinate.longitude)\n    }\n\n    func testToCLLocationCoordinate2D() throws {\n        let point = try ParseGeoPoint(latitude: 10, longitude: 20)\n        let location = point.toCLLocationCoordinate2D()\n        XCTAssertEqual(point.latitude, location.latitude)\n        XCTAssertEqual(point.longitude, location.longitude)\n    }\n    #endif\n\n    func testGeoPointEncoding() throws {\n        let point = try ParseGeoPoint(latitude: 10, longitude: 20)\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(point)\n            let decoded = try JSONDecoder().decode(ParseGeoPoint.self, from: encoded)\n            XCTAssertEqual(point, decoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded\")\n        }\n    }\n\n    func testDebugString() throws {\n        let point = try ParseGeoPoint(latitude: 10, longitude: 20)\n        let expected = \"{\\\"__type\\\":\\\"GeoPoint\\\",\\\"latitude\\\":10,\\\"longitude\\\":20}\"\n        XCTAssertEqual(point.debugDescription, expected)\n    }\n\n    func testDescription() throws {\n        let point = try ParseGeoPoint(latitude: 10, longitude: 20)\n        let expected = \"{\\\"__type\\\":\\\"GeoPoint\\\",\\\"latitude\\\":10,\\\"longitude\\\":20}\"\n        XCTAssertEqual(point.description, expected)\n    }\n\n    // swiftlint:disable:next function_body_length\n    func testGeoUtilityDistance() throws {\n        let d2R = Double.pi / 180.0\n        var pointA = ParseGeoPoint()\n        var pointB = ParseGeoPoint()\n\n        // Zero\n        XCTAssertEqual(pointA.distanceInRadians(pointB), 0.0,\n                       accuracy: 0.00001, \"Origin points with non-zero distance.\")\n        XCTAssertEqual(pointB.distanceInRadians(pointA), 0.0,\n                       accuracy: 0.00001, \"Origin points with non-zero distance.\")\n\n        // Wrap Long\n        pointA.longitude = 179.0\n        pointB.longitude = -179.0\n        XCTAssertEqual(pointA.distanceInRadians(pointB), 2.0 * d2R,\n                       accuracy: 0.00001, \"Long wrap angular distance error.\")\n        XCTAssertEqual(pointB.distanceInRadians(pointA), 2.0 * d2R,\n                       accuracy: 0.00001, \"Long wrap angular distance error.\")\n\n        // North South Lat\n        pointA.latitude = 89.0\n        pointA.longitude = 0.0\n        pointB.latitude = -89.0\n        pointB.longitude = 0.0\n        XCTAssertEqual(pointA.distanceInRadians(pointB), 178.0 * d2R,\n                       accuracy: 0.00001, \"NS pole wrap error.\")\n        XCTAssertEqual(pointB.distanceInRadians(pointA), 178.0 * d2R,\n                       accuracy: 0.00001, \"NS pole wrap error.\")\n\n        // Long wrap Lat\n        pointA.latitude = 89.0\n        pointA.longitude = 0.0\n        pointB.latitude = -89.0\n        pointB.longitude = 179.9999\n        XCTAssertEqual(pointA.distanceInRadians(pointB), 180.0 * d2R,\n                       accuracy: 0.00001, \"Lat wrap error.\")\n        XCTAssertEqual(pointB.distanceInRadians(pointA), 180.0 * d2R,\n                       accuracy: 0.00001, \"Lat wrap error.\")\n\n        pointA.latitude = 79.0\n        pointA.longitude = 90.0\n        pointB.latitude = -79.0\n        pointB.longitude = -90\n        XCTAssertEqual(pointA.distanceInRadians(pointB), 180.0 * d2R,\n                       accuracy: 0.00001, \"Lat long wrap error.\")\n        XCTAssertEqual(pointB.distanceInRadians(pointA), 180.0 * d2R,\n                       accuracy: 0.00001, \"Lat long wrap error.\")\n\n        // Wrap near pole - somewhat ill conditioned case due to pole proximity\n        pointA.latitude = 85.0\n        pointA.longitude = 90.0\n        pointB.latitude = 85.0\n        pointB.longitude = -90\n        XCTAssertEqual(pointA.distanceInRadians(pointB), 10.0 * d2R,\n                       accuracy: 0.00001, \"Pole proximity fail\")\n        XCTAssertEqual(pointB.distanceInRadians(pointA), 10.0 * d2R,\n                       accuracy: 0.00001, \"Pole proximity fail\")\n\n        // Reference cities\n        // Sydney Australia\n        pointA.latitude = -34.0\n        pointA.longitude = 151.0\n\n        // Buenos Aires\n        pointB.latitude = -34.5\n        pointB.longitude = -58.35\n\n        XCTAssertEqual(pointA.distanceInRadians(pointB), 1.85,\n                       accuracy: 0.01, \"Sydney to Buenos Aires Fail\")\n        XCTAssertEqual(pointB.distanceInRadians(pointA), 1.85,\n                       accuracy: 0.01, \"Sydney to Buenos Aires Fail\")\n\n        // [SAC]  38.52  -121.50  Sacramento,CA\n        let sacramento = try ParseGeoPoint(latitude: 38.52, longitude: -121.50)\n\n        // [HNL]  21.35  -157.93  Honolulu Int,HI\n        let honolulu = try ParseGeoPoint(latitude: 21.35, longitude: -157.93)\n\n        // [51Q]  37.75  -122.68  San Francisco,CA\n        let sanfran = try ParseGeoPoint(latitude: 37.75, longitude: -122.68)\n\n        // Vorkuta 67.509619,64.085999\n        let vorkuta = try ParseGeoPoint(latitude: 67.509619, longitude: 64.085999)\n\n        // London\n        let london = try ParseGeoPoint(latitude: 51.501904, longitude: -0.115356)\n\n        // Northampton\n        let northhampton = try ParseGeoPoint(latitude: 52.241256, longitude: -0.895386)\n\n        // Powell St BART station\n        let powell = try ParseGeoPoint(latitude: 37.78507, longitude: -122.407007)\n\n        // Apple store\n        let astore = try ParseGeoPoint(latitude: 37.785809, longitude: -122.406363)\n\n        // Self\n        XCTAssertEqual(honolulu.distanceInKilometers(honolulu), 0.0,\n                       accuracy: 0.00001, \"Self distance\")\n\n        // Sac to HNL\n        XCTAssertEqual(sacramento.distanceInKilometers(honolulu), 3964.8,\n                       accuracy: 10.0, \"SAC to HNL\")\n        XCTAssertEqual(sacramento.distanceInMiles(honolulu), 2463.6,\n                       accuracy: 10.0, \"SAC to HNL\")\n\n        // Semi-local\n        XCTAssertEqual(london.distanceInKilometers(northhampton), 98.0,\n                       accuracy: 1.0, \"London Northhampton\")\n        XCTAssertEqual(london.distanceInMiles(northhampton), 61.2,\n                       accuracy: 1.0, \"London Northhampton\")\n\n        XCTAssertEqual(sacramento.distanceInKilometers(sanfran), 134.5,\n                       accuracy: 2.0, \"Sacramento San Fran\")\n        XCTAssertEqual(sacramento.distanceInMiles(sanfran), 84.8,\n                       accuracy: 2.0, \"Sacramento San Fran\")\n\n        // Very local\n        XCTAssertEqual(powell.distanceInKilometers(astore), 0.1,\n                       accuracy: 0.05, \"Powell station and Apple store\")\n\n        // Far (for error tolerances's sake)\n        XCTAssertEqual(sacramento.distanceInKilometers(vorkuta), 8303.8,\n                       accuracy: 100.0, \"Sacramento to Vorkuta\")\n        XCTAssertEqual(sacramento.distanceInMiles(vorkuta), 5159.7,\n                       accuracy: 100.0, \"Sacramento to Vorkuta\")\n    }\n\n    func testDebugGeoPoint() throws {\n        let point = try ParseGeoPoint(latitude: 10, longitude: 20)\n        XCTAssertTrue(point.debugDescription.contains(\"10\"))\n        XCTAssertTrue(point.debugDescription.contains(\"20\"))\n    }\n\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseGitHubCombineTests.swift",
    "content": "//\n//  ParseGitHubCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/1/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseGitHubCombineTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testLogin() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.github.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.github.loginPublisher(id: \"testing\", accessToken: \"this\")\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user, userOnServer)\n            XCTAssertEqual(user.username, \"hello\")\n            XCTAssertEqual(user.password, \"world\")\n            XCTAssertTrue(user.github.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginAuthData() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.github.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.github.loginPublisher(authData: ([\"id\": \"testing\",\n                                                               \"access_token\": \"this\"]))\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user, userOnServer)\n            XCTAssertEqual(user.username, \"hello\")\n            XCTAssertEqual(user.password, \"world\")\n            XCTAssertTrue(user.github.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func loginNormally() throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try User.login(username: \"parse\", password: \"user\")\n    }\n\n    func testLink() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.github.linkPublisher(id: \"testing\",\n                                                  accessToken: \"this\")\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertTrue(user.github.isLinked)\n            XCTAssertFalse(user.anonymous.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkAuthData() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let authData = ParseGitHub<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\", accessToken: \"accessToken\")\n        let publisher = User.github.linkPublisher(authData: authData)\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertTrue(user.github.isLinked)\n            XCTAssertFalse(user.anonymous.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUnlink() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseGitHub<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"this\")\n        User.current?.authData = [User.github.__type: authData]\n        XCTAssertTrue(User.github.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.github.unlinkPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertFalse(user.github.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseGitHubTests.swift",
    "content": "//\n//  ParseGitHubTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/1/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseGitHubTests: XCTestCase { // swiftlint:disable:this type_body_length\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func loginNormally() throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try User.login(username: \"parse\", password: \"user\")\n    }\n\n    func loginAnonymousUser() throws {\n        let authData = [\"id\": \"yolo\"]\n\n        //: Convert the anonymous user to a real new user.\n        var serverResponse = LoginSignupResponse()\n        serverResponse.username = \"hello\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.anonymous.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try User.anonymous.login()\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.anonymous.isLinked)\n    }\n\n    func testAuthenticationKeys() throws {\n        let authData = ParseGitHub<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"that\")\n        XCTAssertEqual(authData, [\"id\": \"testing\", \"access_token\": \"that\"])\n    }\n\n    func testVerifyMandatoryKeys() throws {\n        let authData = [\"id\": \"testing\", \"access_token\": \"this\"]\n        let authDataWrong = [\"id\": \"testing\", \"hello\": \"test\"]\n        XCTAssertTrue(ParseGitHub<User>\n                        .AuthenticationKeys.id.verifyMandatoryKeys(authData: authData))\n        XCTAssertFalse(ParseGitHub<User>\n                        .AuthenticationKeys.id.verifyMandatoryKeys(authData: authDataWrong))\n    }\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\n    @MainActor\n    func testLogin() async throws {\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.github.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.github.login(id: \"testing\",\n                                               accessToken: \"that\")\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.github.isLinked)\n    }\n\n    @MainActor\n    func testLoginAuthData() async throws {\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.github.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.github.login(authData: ([\"id\": \"testing\",\n                                                           \"access_token\": \"this\"]))\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.github.isLinked)\n    }\n\n    @MainActor\n    func testLoginAuthDataBadAuth() async throws {\n        do {\n            _ = try await User.github.login(authData: ([\"id\": \"testing\",\n                                                        \"bad\": \"token\"]))\n        } catch {\n            guard let parseError = error.containedIn([.unknownError]) else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"consisting of keys\"))\n        }\n    }\n\n    @MainActor\n    func testReplaceAnonymousWithLoggedIn() async throws {\n        try loginAnonymousUser()\n        MockURLProtocol.removeAll()\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n        serverResponse.password = nil\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.github.login(id: \"testing\",\n                                               accessToken: \"that\")\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.github.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testReplaceAnonymousWithLinked() async throws {\n        try loginAnonymousUser()\n        MockURLProtocol.removeAll()\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n        serverResponse.password = nil\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.github.link(id: \"testing\",\n                                              accessToken: \"that\")\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.github.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testLink() async throws {\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.github.link(id: \"testing\",\n                                              accessToken: \"that\")\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.github.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testLinkLoggedInAuthData() async throws {\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n        serverResponse.sessionToken = nil\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let authData = ParseGitHub<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\", accessToken: \"accessToken\")\n\n        let user = try await User.github.link(authData: authData)\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.github.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testLinkLoggedInUserWrongKeys() async throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n        do {\n            _ = try await User.github.link(authData: [\"hello\": \"world\"])\n        } catch {\n            guard let parseError = error.containedIn([.unknownError]) else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"consisting of keys\"))\n        }\n    }\n\n    @MainActor\n    func testUnlink() async throws {\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseGitHub<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"this\")\n        User.current?.authData = [User.github.__type: authData]\n        XCTAssertTrue(User.github.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.github.unlink()\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertFalse(user.github.isLinked)\n    }\n#endif\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseGoogleCombineTests.swift",
    "content": "//\n//  ParseGoogleCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/1/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseGoogleCombineTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testLogin() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.google.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.google.loginPublisher(id: \"testing\", accessToken: \"this\")\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user, userOnServer)\n            XCTAssertEqual(user.username, \"hello\")\n            XCTAssertEqual(user.password, \"world\")\n            XCTAssertTrue(user.google.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginAuthData() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.google.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.google.loginPublisher(authData: ([\"id\": \"testing\",\n                                                               \"access_token\": \"this\"]))\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user, userOnServer)\n            XCTAssertEqual(user.username, \"hello\")\n            XCTAssertEqual(user.password, \"world\")\n            XCTAssertTrue(user.google.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func loginNormally() throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try User.login(username: \"parse\", password: \"user\")\n    }\n\n    func testLink() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.google.linkPublisher(id: \"testing\",\n                                                  accessToken: \"this\")\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertTrue(user.google.isLinked)\n            XCTAssertFalse(user.anonymous.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkAuthData() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let authData = ParseGoogle<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\", accessToken: \"accessToken\")\n        let publisher = User.google.linkPublisher(authData: authData)\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertTrue(user.google.isLinked)\n            XCTAssertFalse(user.anonymous.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUnlink() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseGoogle<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"this\")\n        User.current?.authData = [User.google.__type: authData]\n        XCTAssertTrue(User.google.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.google.unlinkPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertFalse(user.google.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseGoogleTests.swift",
    "content": "//\n//  ParseGoogleTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/1/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseGoogleTests: XCTestCase { // swiftlint:disable:this type_body_length\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func loginNormally() throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try User.login(username: \"parse\", password: \"user\")\n    }\n\n    func loginAnonymousUser() throws {\n        let authData = [\"id\": \"yolo\"]\n\n        //: Convert the anonymous user to a real new user.\n        var serverResponse = LoginSignupResponse()\n        serverResponse.username = \"hello\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.anonymous.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try User.anonymous.login()\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.anonymous.isLinked)\n    }\n\n    func testAuthenticationKeys() throws {\n        let authData = ParseGoogle<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  idToken: \"this\",\n                                                  accessToken: \"that\")\n        XCTAssertEqual(authData, [\"id\": \"testing\", \"access_token\": \"that\"])\n        let authData2 = ParseGoogle<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"that\")\n        XCTAssertEqual(authData2, [\"id\": \"testing\", \"access_token\": \"that\"])\n        let authData3 = ParseGoogle<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  idToken: \"this\")\n        XCTAssertEqual(authData3, [\"id\": \"testing\", \"id_token\": \"this\"])\n    }\n\n    func testVerifyMandatoryKeys() throws {\n        let authData = [\"id\": \"testing\", \"id_token\": \"this\"]\n        let authData2 = [\"id\": \"testing\", \"access_token\": \"this\"]\n        let authDataWrong = [\"id\": \"testing\", \"hello\": \"test\"]\n        XCTAssertTrue(ParseGoogle<User>\n                        .AuthenticationKeys.id.verifyMandatoryKeys(authData: authData))\n        XCTAssertTrue(ParseGoogle<User>\n                        .AuthenticationKeys.id.verifyMandatoryKeys(authData: authData2))\n        XCTAssertFalse(ParseGoogle<User>\n                        .AuthenticationKeys.id.verifyMandatoryKeys(authData: authDataWrong))\n    }\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\n    @MainActor\n    func testLogin() async throws {\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.google.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.google.login(id: \"testing\",\n                                               idToken: \"this\",\n                                               accessToken: \"that\")\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.google.isLinked)\n    }\n\n    @MainActor\n    func testLoginAuthData() async throws {\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.google.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.google.login(authData: ([\"id\": \"testing\",\n                                                           \"id_token\": \"this\"]))\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.google.isLinked)\n    }\n\n    @MainActor\n    func testLoginAuthDataBadAuth() async throws {\n        do {\n            _ = try await User.google.login(authData: ([\"id\": \"testing\",\n                                                        \"bad\": \"token\"]))\n        } catch {\n            guard let parseError = error.containedIn([.unknownError]) else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"consisting of keys\"))\n        }\n    }\n\n    @MainActor\n    func testReplaceAnonymousWithLoggedIn() async throws {\n        try loginAnonymousUser()\n        MockURLProtocol.removeAll()\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n        serverResponse.password = nil\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.google.login(id: \"testing\",\n                                               idToken: \"this\",\n                                               accessToken: \"that\")\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.google.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testReplaceAnonymousWithLinked() async throws {\n        try loginAnonymousUser()\n        MockURLProtocol.removeAll()\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n        serverResponse.password = nil\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.google.link(id: \"testing\",\n                                              idToken: \"this\",\n                                              accessToken: \"that\")\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.google.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testLink() async throws {\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.google.link(id: \"testing\",\n                                              idToken: \"this\",\n                                              accessToken: \"that\")\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.google.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testLinkLoggedInAuthData() async throws {\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n        serverResponse.sessionToken = nil\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let authData = ParseGoogle<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\", accessToken: \"accessToken\")\n\n        let user = try await User.google.link(authData: authData)\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.google.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testLinkLoggedInUserWrongKeys() async throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n        do {\n            _ = try await User.google.link(authData: [\"hello\": \"world\"])\n        } catch {\n            guard let parseError = error.containedIn([.unknownError]) else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"consisting of keys\"))\n        }\n    }\n\n    @MainActor\n    func testUnlink() async throws {\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseGoogle<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  idToken: \"this\")\n        User.current?.authData = [User.google.__type: authData]\n        XCTAssertTrue(User.google.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.google.unlink()\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertFalse(user.google.isLinked)\n    }\n#endif\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseHealthAsyncTests.swift",
    "content": "//\n//  ParseHealthAsyncTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/28/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseHealthAsyncTests: XCTestCase { // swiftlint:disable:this type_body_length\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    @MainActor\n    func testCheck() async throws {\n\n        let healthOfServer = \"ok\"\n        let serverResponse = HealthResponse(status: healthOfServer)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let health = try await ParseHealth.check()\n        XCTAssertEqual(health, healthOfServer)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseHealthCombineTests.swift",
    "content": "//\n//  ParseHealthCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 4/28/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseHealthCombineTests: XCTestCase {\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testCheck() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        let healthOfServer = \"ok\"\n        let serverResponse = HealthResponse(status: healthOfServer)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = ParseHealth.checkPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { health in\n            XCTAssertEqual(health, healthOfServer)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseHealthTests.swift",
    "content": "//\n//  ParseHealthTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 4/28/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseHealthTests: XCTestCase {\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testCheckCommand() throws {\n        let command = ParseHealth.healthCommand()\n        XCTAssertEqual(command.path.urlComponent, \"/health\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertNil(command.body)\n    }\n\n    func testCheck() {\n\n        let healthOfServer = \"ok\"\n        let serverResponse = HealthResponse(status: healthOfServer)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let health = try ParseHealth.check()\n            XCTAssertEqual(health, healthOfServer)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testCheckAsync() {\n        let healthOfServer = \"ok\"\n        let serverResponse = HealthResponse(status: healthOfServer)\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation = XCTestExpectation(description: \"Health check\")\n        ParseHealth.check { result in\n            switch result {\n\n            case .success(let health):\n                XCTAssertEqual(health, healthOfServer)\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 10.0)\n    }\n\n    func testCheckErrorAsync() {\n        let healthOfServer = \"Should throw error\"\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(healthOfServer)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation = XCTestExpectation(description: \"Health check\")\n        ParseHealth.check { result in\n            if case .success = result {\n                XCTFail(\"Should have thrown error\")\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 10.0)\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseHookFunctionCombineTests.swift",
    "content": "//\n//  ParseHookFunctionCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/20/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseHookFunctionCombineTests: XCTestCase {\n    struct TestFunction: ParseHookFunctionable {\n        var functionName: String?\n        var url: URL?\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testCreate() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Create hook\")\n\n        let hookFunction = TestFunction(name: \"foo\",\n                                        url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = hookFunction\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = hookFunction.createPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { created in\n            XCTAssertEqual(created, server)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testCreateError() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Create hook\")\n\n        let hookFunction = TestFunction(name: \"foo\",\n                                        url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = hookFunction.createPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case .finished = result {\n                    XCTFail(\"Should have thrown ParseError\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown ParseError\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUpdate() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Update hook\")\n\n        let hookFunction = TestFunction(name: \"foo\",\n                                        url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = hookFunction\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = hookFunction.updatePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { updated in\n            XCTAssertEqual(updated, server)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUpdateError() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Update hook\")\n\n        let hookFunction = TestFunction(name: \"foo\",\n                                        url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = hookFunction.updatePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case .finished = result {\n                    XCTFail(\"Should have thrown ParseError\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown ParseError\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testFetch() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Fetch hook\")\n\n        let hookFunction = TestFunction(name: \"foo\",\n                                        url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = hookFunction\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = hookFunction.fetchPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { fetched in\n            XCTAssertEqual(fetched, server)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testFetchError() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Fetch hook\")\n\n        let hookFunction = TestFunction(name: \"foo\",\n                                        url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = hookFunction.fetchPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case .finished = result {\n                    XCTFail(\"Should have thrown ParseError\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown ParseError\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testFetchAll() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"FetchAll hook\")\n\n        let hookFunction = TestFunction(name: \"foo\",\n                                        url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = [hookFunction]\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = hookFunction.fetchAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { fetched in\n            XCTAssertEqual(fetched, server)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testFetchAllError() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"FetchAll hook\")\n\n        let hookFunction = TestFunction(name: \"foo\",\n                                        url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = hookFunction.fetchAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case .finished = result {\n                    XCTFail(\"Should have thrown ParseError\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown ParseError\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDelete() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Delete hook\")\n\n        let hookFunction = TestFunction(name: \"foo\",\n                                        url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = hookFunction\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = hookFunction.deletePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDeleteError() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Delete hook\")\n\n        let hookFunction = TestFunction(name: \"foo\",\n                                        url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = hookFunction.deletePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case .finished = result {\n                    XCTFail(\"Should have thrown ParseError\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown ParseError\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseHookFunctionRequestCombineTests.swift",
    "content": "//\n//  ParseHookFunctionRequestCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/20/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseHookFunctionRequestCombineTests: XCTestCase {\n    struct Parameters: ParseHookParametable {\n        var hello = \"world\"\n    }\n\n    struct User: ParseCloudUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n        var sessionToken: String?\n\n        // Your custom keys\n        var customKey: String?\n\n        //: Implement your own version of merge\n        func merge(with object: Self) throws -> Self {\n            var updated = try mergeParse(with: object)\n            if updated.shouldRestoreKey(\\.customKey,\n                                         original: object) {\n                updated.customKey = object.customKey\n            }\n            return updated\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testHydrateUser() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Hydrate User\")\n\n        let sessionToken = \"dog\"\n        let user = User(objectId: \"objectId\", sessionToken: sessionToken)\n        var userOnServer = user\n        userOnServer.createdAt = Date()\n        userOnServer.updatedAt = Date()\n        var server = userOnServer\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n        //Get dates in correct format from ParseDecoding strategy\n        server = try ParseCoding.jsonDecoder().decode(User.self, from: encoded)\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let parameters = Parameters()\n        let installationId = \"cat\"\n        let functionRequest = ParseHookFunctionRequest<User, Parameters>(masterKey: true,\n                                                                         user: user,\n                                                                         installationId: installationId,\n                                                                         ipAddress: \"1.1.1.1\",\n                                                                         headers: [\"yolo\": \"me\"],\n                                                                         parameters: parameters)\n        let requestHydrated = ParseHookFunctionRequest<User, Parameters>(masterKey: true,\n                                                                         user: server,\n                                                                         installationId: installationId,\n                                                                         ipAddress: \"1.1.1.1\",\n                                                                         headers: [\"yolo\": \"me\"],\n                                                                         parameters: parameters)\n\n        let publisher = functionRequest.hydrateUserPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { hydrated in\n            XCTAssertEqual(hydrated, requestHydrated)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testHydrateUserError() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Hydrate User Error\")\n\n        let sessionToken = \"dog\"\n        let user = User(objectId: \"objectId\", sessionToken: sessionToken)\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let parameters = Parameters()\n        let installationId = \"cat\"\n        let functionRequest = ParseHookFunctionRequest<User, Parameters>(masterKey: true,\n                                                                         user: user,\n                                                                         installationId: installationId,\n                                                                         ipAddress: \"1.1.1.1\",\n                                                                         headers: [\"yolo\": \"me\"],\n                                                                         parameters: parameters)\n        let publisher = functionRequest.hydrateUserPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case .finished = result {\n                    XCTFail(\"Should have thrown ParseError\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown ParseError\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseHookFunctionRequestTests.swift",
    "content": "//\n//  ParseHookFunctionRequestTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/20/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseHookFunctionRequestTests: XCTestCase {\n\n    struct Parameters: ParseHookParametable {\n        var hello = \"world\"\n    }\n\n    struct User: ParseCloudUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n        var sessionToken: String?\n\n        // Your custom keys\n        var customKey: String?\n\n        //: Implement your own version of merge\n        func merge(with object: Self) throws -> Self {\n            var updated = try mergeParse(with: object)\n            if updated.shouldRestoreKey(\\.customKey,\n                                         original: object) {\n                updated.customKey = object.customKey\n            }\n            return updated\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testCoding() async throws {\n        let parameters = Parameters()\n        let functionRequest = ParseHookFunctionRequest<User, Parameters>(masterKey: true,\n                                                                         ipAddress: \"1.1.1.1\",\n                                                                         headers: [\"yolo\": \"me\"],\n                                                                         parameters: parameters)\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"headers\\\":{\\\"yolo\\\":\\\"me\\\"},\\\"ip\\\":\\\"1.1.1.1\\\",\\\"master\\\":true,\\\"params\\\":{\\\"hello\\\":\\\"world\\\"}}\"\n        XCTAssertEqual(functionRequest.description, expected)\n    }\n\n    func testGetLog() async throws {\n        let parameters = Parameters()\n        let functionRequest = ParseHookFunctionRequest<User, Parameters>(masterKey: true,\n                                                                         ipAddress: \"1.1.1.1\",\n                                                                         headers: [\"yolo\": \"me\"],\n                                                                         parameters: parameters,\n                                                                         log: AnyCodable(\"peace\"))\n        let log: String = try functionRequest.getLog()\n        XCTAssertEqual(log, \"peace\")\n    }\n\n    func testGetLogError() async throws {\n        let parameters = Parameters()\n        let functionRequest = ParseHookFunctionRequest<User, Parameters>(masterKey: true,\n                                                                         ipAddress: \"1.1.1.1\",\n                                                                         headers: [\"yolo\": \"me\"],\n                                                                         parameters: parameters,\n                                                                         log: AnyCodable(\"peace\"))\n        do {\n            let _: Double = try functionRequest.getLog()\n            XCTFail(\"Should have failed\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"inferred\"))\n        }\n    }\n\n    func testGetContext() async throws {\n        let parameters = Parameters()\n        let context = [\"peace\": \"out\"]\n        let functionRequest = ParseHookFunctionRequest<User, Parameters>(masterKey: true,\n                                                                         ipAddress: \"1.1.1.1\",\n                                                                         headers: [\"yolo\": \"me\"],\n                                                                         parameters: parameters,\n                                                                         context: AnyCodable(context))\n        let requestContext: [String: String] = try functionRequest.getContext()\n        XCTAssertEqual(requestContext, context)\n    }\n\n    func testGetContextError() async throws {\n        let parameters = Parameters()\n        let context = [\"peace\": \"out\"]\n        let functionRequest = ParseHookFunctionRequest<User, Parameters>(masterKey: true,\n                                                                         ipAddress: \"1.1.1.1\",\n                                                                         headers: [\"yolo\": \"me\"],\n                                                                         parameters: parameters,\n                                                                         context: AnyCodable(context))\n        do {\n            let _: Double = try functionRequest.getContext()\n            XCTFail(\"Should have failed\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"inferred\"))\n        }\n    }\n\n    func testOptions() throws {\n        let parameters = Parameters()\n        let sessionToken = \"dog\"\n        let installationId = \"cat\"\n        let user = User(sessionToken: sessionToken)\n        let functionRequest = ParseHookFunctionRequest<User, Parameters>(masterKey: true,\n                                                                         user: user,\n                                                                         installationId: installationId,\n                                                                         ipAddress: \"1.1.1.1\",\n                                                                         headers: [\"yolo\": \"me\"],\n                                                                         parameters: parameters)\n        let options = API.Options([.useMasterKey])\n        let requestOptions = functionRequest.options()\n        XCTAssertEqual(requestOptions, options)\n        let functionRequest2 = ParseHookFunctionRequest<User, Parameters>(masterKey: false,\n                                                                          user: user,\n                                                                          installationId: installationId,\n                                                                          ipAddress: \"1.1.1.1\",\n                                                                          headers: [\"yolo\": \"me\"],\n                                                                          parameters: parameters)\n        let options2 = API.Options([.sessionToken(sessionToken),\n            .installationId(installationId)])\n        let requestOptions2 = functionRequest2.options()\n        XCTAssertEqual(requestOptions2, options2)\n        let functionRequest3 = ParseHookFunctionRequest<User, Parameters>(masterKey: false,\n                                                                          user: user,\n                                                                          ipAddress: \"1.1.1.1\",\n                                                                          headers: [\"yolo\": \"me\"],\n                                                                          parameters: parameters)\n        let options3 = API.Options([.sessionToken(sessionToken)])\n        let requestOptions3 = functionRequest3.options()\n        XCTAssertEqual(requestOptions3, options3)\n        let functionRequest4 = ParseHookFunctionRequest<User, Parameters>(masterKey: false,\n                                                                          installationId: installationId,\n                                                                          ipAddress: \"1.1.1.1\",\n                                                                          headers: [\"yolo\": \"me\"],\n                                                                          parameters: parameters)\n        let options4 = API.Options([.installationId(installationId)])\n        let requestOptions4 = functionRequest4.options()\n        XCTAssertEqual(requestOptions4, options4)\n        let functionRequest5 = ParseHookFunctionRequest<User, Parameters>(masterKey: false,\n                                                                          ipAddress: \"1.1.1.1\",\n                                                                          headers: [\"yolo\": \"me\"],\n                                                                          parameters: parameters)\n        let options5 = API.Options()\n        let requestOptions5 = functionRequest5.options()\n        XCTAssertEqual(requestOptions5, options5)\n    }\n\n    @MainActor\n    func testHydrateUser() async throws {\n        let sessionToken = \"dog\"\n        let user = User(objectId: \"objectId\", sessionToken: sessionToken)\n        var userOnServer = user\n        userOnServer.createdAt = Date()\n        userOnServer.updatedAt = Date()\n        var server = userOnServer\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n        //Get dates in correct format from ParseDecoding strategy\n        server = try ParseCoding.jsonDecoder().decode(User.self, from: encoded)\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let parameters = Parameters()\n        let installationId = \"cat\"\n        let functionRequest = ParseHookFunctionRequest<User, Parameters>(masterKey: true,\n                                                                         user: user,\n                                                                         installationId: installationId,\n                                                                         ipAddress: \"1.1.1.1\",\n                                                                         headers: [\"yolo\": \"me\"],\n                                                                         parameters: parameters)\n        let requestHydrated = ParseHookFunctionRequest<User, Parameters>(masterKey: true,\n                                                                         user: server,\n                                                                         installationId: installationId,\n                                                                         ipAddress: \"1.1.1.1\",\n                                                                         headers: [\"yolo\": \"me\"],\n                                                                         parameters: parameters)\n        let hydrated = try await functionRequest.hydrateUser()\n        XCTAssertEqual(hydrated, requestHydrated)\n    }\n\n    @MainActor\n    func testHydrateUserError() async throws {\n        let sessionToken = \"dog\"\n        let user = User(objectId: \"objectId\", sessionToken: sessionToken)\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let parameters = Parameters()\n        let installationId = \"cat\"\n        let functionRequest = ParseHookFunctionRequest<User, Parameters>(masterKey: true,\n                                                                         user: user,\n                                                                         installationId: installationId,\n                                                                         ipAddress: \"1.1.1.1\",\n                                                                         headers: [\"yolo\": \"me\"],\n                                                                         parameters: parameters)\n        do {\n            _ = try await functionRequest.hydrateUser()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(server.code))\n        }\n    }\n\n    @MainActor\n    func testHydrateUserError3() async throws {\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let parameters = Parameters()\n        let installationId = \"cat\"\n        let functionRequest = ParseHookFunctionRequest<User, Parameters>(masterKey: true,\n                                                                         installationId: installationId,\n                                                                         ipAddress: \"1.1.1.1\",\n                                                                         headers: [\"yolo\": \"me\"],\n                                                                         parameters: parameters)\n        do {\n            _ = try await functionRequest.hydrateUser()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(.unknownError))\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseHookFunctionTests.swift",
    "content": "//\n//  ParseHookFunctionTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/20/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseHookFunctionTests: XCTestCase {\n    struct TestFunction: ParseHookFunctionable {\n        var functionName: String?\n        var url: URL?\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testCoding() throws {\n        let hookFunction = TestFunction(name: \"foo\",\n                                        url: URL(string: \"https://api.example.com/foo\"))\n        let expected = \"{\\\"functionName\\\":\\\"foo\\\",\\\"url\\\":\\\"https:\\\\/\\\\/api.example.com\\\\/foo\\\"}\"\n        XCTAssertEqual(hookFunction.description, expected)\n    }\n\n    @MainActor\n    func testCreate() async throws {\n\n        let hookFunction = TestFunction(name: \"foo\",\n                                        url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = hookFunction\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let created = try await hookFunction.create()\n        XCTAssertEqual(created, server)\n    }\n\n    @MainActor\n    func testCreateError() async throws {\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let hookFunction = TestFunction(name: \"foo\",\n                                        url: URL(string: \"https://api.example.com/foo\"))\n        do {\n            _ = try await hookFunction.create()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(server.code))\n        }\n    }\n\n    @MainActor\n    func testCreateError2() async throws {\n\n        let hookFunction = TestFunction(url: URL(string: \"https://api.example.com/foo\"))\n        do {\n            _ = try await hookFunction.create()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(.unknownError))\n        }\n    }\n\n    @MainActor\n    func testUpdate() async throws {\n\n        let hookFunction = TestFunction(name: \"foo\",\n                                        url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = hookFunction\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let updated = try await hookFunction.update()\n        XCTAssertEqual(updated, server)\n    }\n\n    @MainActor\n    func testUpdateError() async throws {\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let hookFunction = TestFunction(name: \"foo\",\n                                        url: URL(string: \"https://api.example.com/foo\"))\n        do {\n            _ = try await hookFunction.update()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(server.code))\n        }\n    }\n\n    @MainActor\n    func testUpdateError2() async throws {\n\n        let hookFunction = TestFunction(url: URL(string: \"https://api.example.com/foo\"))\n        do {\n            _ = try await hookFunction.update()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(.unknownError))\n        }\n    }\n\n    @MainActor\n    func testFetch() async throws {\n\n        let hookFunction = TestFunction(name: \"foo\",\n                                        url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = hookFunction\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let fetched = try await hookFunction.fetch()\n        XCTAssertEqual(fetched, server)\n    }\n\n    @MainActor\n    func testFetchError() async throws {\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let hookFunction = TestFunction(name: \"foo\",\n                                        url: URL(string: \"https://api.example.com/foo\"))\n        do {\n            _ = try await hookFunction.fetch()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(server.code))\n        }\n    }\n\n    @MainActor\n    func testFetchError2() async throws {\n\n        let hookFunction = TestFunction(url: URL(string: \"https://api.example.com/foo\"))\n        do {\n            _ = try await hookFunction.fetch()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(.unknownError))\n        }\n    }\n\n    @MainActor\n    func testFetchAll() async throws {\n\n        let hookFunction = TestFunction(name: \"foo\",\n                                        url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = [hookFunction]\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let fetched = try await hookFunction.fetchAll()\n        XCTAssertEqual(fetched, server)\n    }\n\n    @MainActor\n    func testFetchAllError() async throws {\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let hookFunction = TestFunction(name: \"foo\",\n                                        url: URL(string: \"https://api.example.com/foo\"))\n        do {\n            _ = try await hookFunction.fetchAll()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(server.code))\n        }\n    }\n\n    @MainActor\n    func testDelete() async throws {\n        let server = NoBody()\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let hookFunction = TestFunction(name: \"foo\",\n                                        url: URL(string: \"https://api.example.com/foo\"))\n        try await hookFunction.delete()\n    }\n\n    @MainActor\n    func testDeleteError() async throws {\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let hookFunction = TestFunction(name: \"foo\",\n                                        url: URL(string: \"https://api.example.com/foo\"))\n        do {\n            try await hookFunction.delete()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(server.code))\n        }\n    }\n\n    @MainActor\n    func testDeleteError2() async throws {\n\n        let hookFunction = TestFunction(url: URL(string: \"https://api.example.com/foo\"))\n        do {\n            _ = try await hookFunction.delete()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(.unknownError))\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseHookResponseTests.swift",
    "content": "//\n//  ParseHookResponseTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/21/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseHookResponseTests: XCTestCase {\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testInitializers() throws {\n        let response1 = ParseHookResponse<String>(success: \"test\")\n        XCTAssertNotNil(response1.success)\n        XCTAssertNil(response1.error)\n        let response4 = ParseHookResponse<String>(error: .init(code: .unknownError, message: \"yup\"))\n        XCTAssertNil(response4.success)\n        XCTAssertNotNil(response4.error)\n    }\n\n    func testSuccess() throws {\n        var response = ParseHookResponse(success: true)\n        let expected = \"{\\\"success\\\":true}\"\n        XCTAssertEqual(response.description, expected)\n        response.error = .init(code: .accountAlreadyLinked, message: \"yo\")\n        XCTAssertEqual(response.description, expected)\n    }\n\n    func testError() throws {\n        let code = -1\n        let message = \"testing ParseHookResponse\"\n        guard let encoded: Data = \"{\\\"error\\\":\\\"\\(message)\\\",\\\"code\\\":\\(code)}\".data(using: .utf8) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let decoded = try ParseCoding.jsonDecoder().decode(ParseHookResponse<String>.self, from: encoded)\n        XCTAssertEqual(decoded.error?.code.rawValue, code)\n        XCTAssertEqual(decoded.error?.message, message)\n        XCTAssertNil(decoded.success)\n        XCTAssertEqual(decoded.debugDescription, \"{\\\"code\\\":\\(code),\\\"error\\\":\\\"\\(message)\\\"}\")\n        XCTAssertEqual(decoded.description, \"{\\\"code\\\":\\(code),\\\"error\\\":\\\"\\(message)\\\"}\")\n        XCTAssertEqual(decoded.errorDescription, \"{\\\"code\\\":\\(code),\\\"error\\\":\\\"\\(message)\\\"}\")\n    }\n\n    func testCompare() throws {\n        let code = ParseError.Code.objectNotFound.rawValue\n        let message = \"testing ParseHookResponse\"\n        guard let encoded = \"{\\\"code\\\":\\(code),\\\"error\\\":\\\"\\(message)\\\"}\".data(using: .utf8),\n                let decoded = try ParseCoding\n                    .jsonDecoder()\n                    .decode(ParseHookResponse<String>.self,\n                            from: encoded).error else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        let error: Error = decoded\n\n        XCTAssertTrue(error.equalsTo(.objectNotFound))\n        XCTAssertFalse(error.equalsTo(.invalidQuery))\n\n        XCTAssertTrue(error.containedIn(.objectNotFound, .invalidQuery))\n        XCTAssertFalse(error.containedIn(.operationForbidden, .invalidQuery))\n\n        XCTAssertTrue(error.containedIn([.objectNotFound, .invalidQuery]))\n        XCTAssertFalse(error.containedIn([.operationForbidden, .invalidQuery]))\n\n        XCTAssertNotNil(error.equalsTo(.objectNotFound))\n        XCTAssertNil(error.equalsTo(.invalidQuery))\n\n        XCTAssertNotNil(error.containedIn(.objectNotFound, .invalidQuery))\n        XCTAssertNil(error.containedIn(.operationForbidden, .invalidQuery))\n\n        XCTAssertNotNil(error.containedIn([.objectNotFound, .invalidQuery]))\n        XCTAssertNil(error.containedIn([.operationForbidden, .invalidQuery]))\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseHookTriggerCombineTests.swift",
    "content": "//\n//  ParseHookTriggerCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/20/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseHookTriggerCombineTests: XCTestCase {\n    struct TestTrigger: ParseHookTriggerable {\n        var className: String?\n        var triggerName: ParseHookTriggerType?\n        var url: URL?\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testCreate() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Create hook\")\n\n        let hookTrigger = TestTrigger(className: \"foo\",\n                                      triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = hookTrigger\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = hookTrigger.createPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { created in\n            XCTAssertEqual(created, server)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testCreateError() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Create hook\")\n\n        let hookTrigger = TestTrigger(className: \"foo\",\n                                      triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = hookTrigger.createPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case .finished = result {\n                    XCTFail(\"Should have thrown ParseError\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown ParseError\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUpdate() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Update hook\")\n\n        let hookTrigger = TestTrigger(className: \"foo\",\n                                      triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = hookTrigger\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = hookTrigger.updatePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { updated in\n            XCTAssertEqual(updated, server)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUpdateError() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Update hook\")\n\n        let hookTrigger = TestTrigger(className: \"foo\",\n                                      triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = hookTrigger.updatePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case .finished = result {\n                    XCTFail(\"Should have thrown ParseError\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown ParseError\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testFetch() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Fetch hook\")\n\n        let hookTrigger = TestTrigger(className: \"foo\",\n                                      triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = hookTrigger\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = hookTrigger.fetchPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { fetched in\n            XCTAssertEqual(fetched, server)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testFetchError() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Fetch hook\")\n\n        let hookTrigger = TestTrigger(className: \"foo\",\n                                      triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = hookTrigger.fetchPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case .finished = result {\n                    XCTFail(\"Should have thrown ParseError\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown ParseError\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testFetchAll() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"FetchAll hook\")\n\n        let hookTrigger = TestTrigger(className: \"foo\",\n                                      triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = [hookTrigger]\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = hookTrigger.fetchAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { fetched in\n            XCTAssertEqual(fetched, server)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testFetchAllError() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"FetchAll hook\")\n\n        let hookTrigger = TestTrigger(className: \"foo\",\n                                      triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = hookTrigger.fetchAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case .finished = result {\n                    XCTFail(\"Should have thrown ParseError\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown ParseError\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDelete() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Delete hook\")\n\n        let hookTrigger = TestTrigger(className: \"foo\",\n                                      triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = hookTrigger\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = hookTrigger.deletePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDeleteError() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Delete hook\")\n\n        let hookTrigger = TestTrigger(className: \"foo\",\n                                      triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = hookTrigger.deletePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case .finished = result {\n                    XCTFail(\"Should have thrown ParseError\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown ParseError\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseHookTriggerRequestCombineTests.swift",
    "content": "//\n//  ParseHookTriggerRequestCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/20/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseHookTriggerRequestCombineTests: XCTestCase {\n\n    struct User: ParseCloudUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n        var sessionToken: String?\n\n        // Your custom keys\n        var customKey: String?\n\n        //: Implement your own version of merge\n        func merge(with object: Self) throws -> Self {\n            var updated = try mergeParse(with: object)\n            if updated.shouldRestoreKey(\\.customKey,\n                                         original: object) {\n                updated.customKey = object.customKey\n            }\n            return updated\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testHydrateUser() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Hydrate User\")\n\n        let sessionToken = \"dog\"\n        let user = User(objectId: \"objectId\", sessionToken: sessionToken)\n        var userOnServer = user\n        userOnServer.createdAt = Date()\n        userOnServer.updatedAt = Date()\n        var server = userOnServer\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n        //Get dates in correct format from ParseDecoding strategy\n        server = try ParseCoding.jsonDecoder().decode(User.self, from: encoded)\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let object = User(objectId: \"geez\")\n        let installationId = \"cat\"\n        let triggerRequest = ParseHookTriggerRequest<User, User>(masterKey: true,\n                                                                 user: user,\n                                                                 installationId: installationId,\n                                                                 ipAddress: \"1.1.1.1\",\n                                                                 headers: [\"yolo\": \"me\"],\n                                                                 object: object)\n        let requestHydrated = ParseHookTriggerRequest<User, User>(masterKey: true,\n                                                                  user: server,\n                                                                  installationId: installationId,\n                                                                  ipAddress: \"1.1.1.1\",\n                                                                  headers: [\"yolo\": \"me\"],\n                                                                  object: object)\n\n        let publisher = triggerRequest.hydrateUserPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { hydrated in\n            XCTAssertEqual(hydrated, requestHydrated)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testHydrateUserError() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Hydrate User Error\")\n\n        let sessionToken = \"dog\"\n        let user = User(objectId: \"objectId\", sessionToken: sessionToken)\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let object = User(objectId: \"geez\")\n        let installationId = \"cat\"\n        let triggerRequest = ParseHookTriggerRequest<User, User>(masterKey: true,\n                                                                 user: user,\n                                                                 installationId: installationId,\n                                                                 ipAddress: \"1.1.1.1\",\n                                                                 headers: [\"yolo\": \"me\"],\n                                                                 object: object)\n        let publisher = triggerRequest.hydrateUserPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case .finished = result {\n                    XCTFail(\"Should have thrown ParseError\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown ParseError\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseHookTriggerRequestTests.swift",
    "content": "//\n//  ParseHookTriggerRequestTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/20/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseHookTriggerRequestTests: XCTestCase {\n\n    struct User: ParseCloudUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n        var sessionToken: String?\n\n        // Your custom keys\n        var customKey: String?\n\n        //: Implement your own version of merge\n        func merge(with object: Self) throws -> Self {\n            var updated = try mergeParse(with: object)\n            if updated.shouldRestoreKey(\\.customKey,\n                                         original: object) {\n                updated.customKey = object.customKey\n            }\n            return updated\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testCoding() async throws {\n        let object = User(objectId: \"geez\")\n        let triggerRequest = ParseHookTriggerRequest<User, User>(masterKey: true,\n                                                                 ipAddress: \"1.1.1.1\",\n                                                                 headers: [\"yolo\": \"me\"],\n                                                                 object: object)\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"headers\\\":{\\\"yolo\\\":\\\"me\\\"},\\\"ip\\\":\\\"1.1.1.1\\\",\\\"master\\\":true,\\\"object\\\":{\\\"objectId\\\":\\\"geez\\\"}}\"\n        XCTAssertEqual(triggerRequest.description, expected)\n        let triggerRequest2 = ParseHookTriggerRequest<User, User>(ipAddress: \"1.1.1.1\",\n                                                                  headers: [\"yolo\": \"me\"],\n                                                                  object: object)\n        let expected2 = \"{\\\"headers\\\":{\\\"yolo\\\":\\\"me\\\"},\\\"ip\\\":\\\"1.1.1.1\\\",\\\"object\\\":{\\\"objectId\\\":\\\"geez\\\"}}\"\n        XCTAssertEqual(triggerRequest2.description, expected2)\n    }\n\n    func testGetLog() async throws {\n        let object = User(objectId: \"geez\")\n        let triggerRequest = ParseHookTriggerRequest<User, User>(masterKey: true,\n                                                                 ipAddress: \"1.1.1.1\",\n                                                                 headers: [\"yolo\": \"me\"],\n                                                                 object: object,\n                                                                 log: AnyCodable(\"peace\"))\n        let log: String = try triggerRequest.getLog()\n        XCTAssertEqual(log, \"peace\")\n    }\n\n    func testGetLogError() async throws {\n        let object = User(objectId: \"geez\")\n        let triggerRequest = ParseHookTriggerRequest<User, User>(masterKey: true,\n                                                                 ipAddress: \"1.1.1.1\",\n                                                                 headers: [\"yolo\": \"me\"],\n                                                                 object: object,\n                                                                 log: AnyCodable(\"peace\"))\n        do {\n            let _: Double = try triggerRequest.getLog()\n            XCTFail(\"Should have failed\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"inferred\"))\n        }\n    }\n\n    func testGetContext() async throws {\n        let object = User(objectId: \"geez\")\n        let context = [\"peace\": \"out\"]\n        let triggerRequest = ParseHookTriggerRequest<User, User>(masterKey: true,\n                                                                 ipAddress: \"1.1.1.1\",\n                                                                 headers: [\"yolo\": \"me\"],\n                                                                 object: object,\n                                                                 context: AnyCodable(context))\n        let requestContext: [String: String] = try triggerRequest.getContext()\n        XCTAssertEqual(requestContext, context)\n    }\n\n    func testGetContextError() async throws {\n        let object = User(objectId: \"geez\")\n        let context = [\"peace\": \"out\"]\n        let triggerRequest = ParseHookTriggerRequest<User, User>(masterKey: true,\n                                                                 ipAddress: \"1.1.1.1\",\n                                                                 headers: [\"yolo\": \"me\"],\n                                                                 object: object,\n                                                                 context: AnyCodable(context))\n        do {\n            let _: Double = try triggerRequest.getContext()\n            XCTFail(\"Should have failed\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"inferred\"))\n        }\n    }\n\n    func testOptions() throws {\n        let object = User(objectId: \"geez\")\n        let sessionToken = \"dog\"\n        let installationId = \"cat\"\n        let user = User(sessionToken: sessionToken)\n        let triggerRequest = ParseHookTriggerRequest<User, User>(masterKey: true,\n                                                                 user: user,\n                                                                 installationId: installationId,\n                                                                 ipAddress: \"1.1.1.1\",\n                                                                 headers: [\"yolo\": \"me\"],\n                                                                 object: object)\n        let options = API.Options([.useMasterKey])\n        let requestOptions = triggerRequest.options()\n        XCTAssertEqual(requestOptions, options)\n        let triggerRequest2 = ParseHookTriggerRequest<User, User>(masterKey: false,\n                                                                   user: user,\n                                                                   installationId: installationId,\n                                                                   ipAddress: \"1.1.1.1\",\n                                                                   headers: [\"yolo\": \"me\"],\n                                                                   object: object)\n        let options2 = API.Options([.sessionToken(sessionToken),\n            .installationId(installationId)])\n        let requestOptions2 = triggerRequest2.options()\n        XCTAssertEqual(requestOptions2, options2)\n        let triggerRequest3 = ParseHookTriggerRequest<User, User>(masterKey: false,\n                                                                  user: user,\n                                                                  ipAddress: \"1.1.1.1\",\n                                                                  headers: [\"yolo\": \"me\"],\n                                                                  object: object)\n        let options3 = API.Options([.sessionToken(sessionToken)])\n        let requestOptions3 = triggerRequest3.options()\n        XCTAssertEqual(requestOptions3, options3)\n        let triggerRequest4 = ParseHookTriggerRequest<User, User>(masterKey: false,\n                                                                  installationId: installationId,\n                                                                  ipAddress: \"1.1.1.1\",\n                                                                  headers: [\"yolo\": \"me\"],\n                                                                  object: object)\n        let options4 = API.Options([.installationId(installationId)])\n        let requestOptions4 = triggerRequest4.options()\n        XCTAssertEqual(requestOptions4, options4)\n        let triggerRequest5 = ParseHookTriggerRequest<User, User>(masterKey: false,\n                                                                  ipAddress: \"1.1.1.1\",\n                                                                  headers: [\"yolo\": \"me\"],\n                                                                  object: object)\n        let options5 = API.Options()\n        let requestOptions5 = triggerRequest5.options()\n        XCTAssertEqual(requestOptions5, options5)\n    }\n\n    @MainActor\n    func testHydrateUser() async throws {\n        let sessionToken = \"dog\"\n        let user = User(objectId: \"objectId\", sessionToken: sessionToken)\n        var userOnServer = user\n        userOnServer.createdAt = Date()\n        userOnServer.updatedAt = Date()\n        var server = userOnServer\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n        //Get dates in correct format from ParseDecoding strategy\n        server = try ParseCoding.jsonDecoder().decode(User.self, from: encoded)\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let object = User(objectId: \"geez\")\n        let installationId = \"cat\"\n        let triggerRequest = ParseHookTriggerRequest<User, User>(masterKey: true,\n                                                                 user: user,\n                                                                 installationId: installationId,\n                                                                 ipAddress: \"1.1.1.1\",\n                                                                 headers: [\"yolo\": \"me\"],\n                                                                 object: object)\n        let requestHydrated = ParseHookTriggerRequest<User, User>(masterKey: true,\n                                                                  user: server,\n                                                                  installationId: installationId,\n                                                                  ipAddress: \"1.1.1.1\",\n                                                                  headers: [\"yolo\": \"me\"],\n                                                                  object: object)\n        let hydrated = try await triggerRequest.hydrateUser()\n        XCTAssertEqual(hydrated, requestHydrated)\n    }\n\n    @MainActor\n    func testHydrateUserError() async throws {\n        let sessionToken = \"dog\"\n        let user = User(objectId: \"objectId\", sessionToken: sessionToken)\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let object = User(objectId: \"geez\")\n        let installationId = \"cat\"\n        let triggerRequest = ParseHookTriggerRequest<User, User>(masterKey: true,\n                                                                 user: user,\n                                                                 installationId: installationId,\n                                                                 ipAddress: \"1.1.1.1\",\n                                                                 headers: [\"yolo\": \"me\"],\n                                                                 object: object)\n        do {\n            _ = try await triggerRequest.hydrateUser()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(server.code))\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseHookTriggerTests.swift",
    "content": "//\n//  ParseHookTriggerTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/20/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseHookTriggerTests: XCTestCase {\n    struct TestTrigger: ParseHookTriggerable {\n        var className: String?\n        var triggerName: ParseHookTriggerType?\n        var url: URL?\n    }\n\n    struct GameScore: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int?\n\n        //: custom initializers\n        init() {}\n\n        init(objectId: String?) {\n            self.objectId = objectId\n        }\n        init(points: Int) {\n            self.points = points\n        }\n\n        //: Implement your own version of merge\n        func merge(with object: Self) throws -> Self {\n            var updated = try mergeParse(with: object)\n            if updated.shouldRestoreKey(\\.points,\n                                         original: object) {\n                updated.points = object.points\n            }\n            return updated\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testCoding() throws {\n        let hookTrigger = TestTrigger(className: \"foo\",\n                                      triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"className\\\":\\\"foo\\\",\\\"triggerName\\\":\\\"afterSave\\\",\\\"url\\\":\\\"https:\\\\/\\\\/api.example.com\\\\/foo\\\"}\"\n        XCTAssertEqual(hookTrigger.description, expected)\n        let object = GameScore()\n        guard let url = URL(string: \"https://api.example.com/foo\") else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let hookTrigger2 = TestTrigger(object: object,\n                                       triggerName: .afterSave,\n                                       url: url)\n        // swiftlint:disable:next line_length\n        let expected2 = \"{\\\"className\\\":\\\"GameScore\\\",\\\"triggerName\\\":\\\"afterSave\\\",\\\"url\\\":\\\"https:\\\\/\\\\/api.example.com\\\\/foo\\\"}\"\n        XCTAssertEqual(hookTrigger2.description, expected2)\n        let hookTrigger3 = try TestTrigger(triggerName: .afterSave,\n                                           url: url)\n        // swiftlint:disable:next line_length\n        let expected3 = \"{\\\"className\\\":\\\"@File\\\",\\\"triggerName\\\":\\\"afterSave\\\",\\\"url\\\":\\\"https:\\\\/\\\\/api.example.com\\\\/foo\\\"}\"\n        XCTAssertEqual(hookTrigger3.description, expected3)\n        let hookTrigger4 = try TestTrigger(triggerName: .beforeConnect,\n                                           url: url)\n        // swiftlint:disable:next line_length\n        let expected4 = \"{\\\"className\\\":\\\"@Connect\\\",\\\"triggerName\\\":\\\"beforeConnect\\\",\\\"url\\\":\\\"https:\\\\/\\\\/api.example.com\\\\/foo\\\"}\"\n        XCTAssertEqual(hookTrigger4.description, expected4)\n    }\n\n    func testInitializerError() throws {\n        guard let url = URL(string: \"https://api.example.com/foo\") else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertThrowsError(try TestTrigger(triggerName: .afterFind,\n                                             url: url))\n    }\n\n    @MainActor\n    func testCreate() async throws {\n\n        let hookTrigger = TestTrigger(className: \"foo\",\n                                      triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = hookTrigger\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let created = try await hookTrigger.create()\n        XCTAssertEqual(created, server)\n    }\n\n    @MainActor\n    func testCreateError() async throws {\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let hookTrigger = TestTrigger(className: \"foo\",\n                                      triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n        do {\n            _ = try await hookTrigger.create()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(server.code))\n        }\n    }\n\n    @MainActor\n    func testCreateError2() async throws {\n\n        let hookTrigger = TestTrigger(triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n        do {\n            _ = try await hookTrigger.create()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(.unknownError))\n        }\n    }\n\n    @MainActor\n    func testUpdate() async throws {\n\n        let hookTrigger = TestTrigger(className: \"foo\",\n                                      triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = hookTrigger\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let updated = try await hookTrigger.update()\n        XCTAssertEqual(updated, server)\n    }\n\n    @MainActor\n    func testUpdateError() async throws {\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let hookTrigger = TestTrigger(className: \"foo\",\n                                      triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n        do {\n            _ = try await hookTrigger.update()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(server.code))\n        }\n    }\n\n    @MainActor\n    func testUpdateError2() async throws {\n\n        let hookTrigger = TestTrigger(triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n        do {\n            _ = try await hookTrigger.update()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(.unknownError))\n        }\n    }\n\n    @MainActor\n    func testUpdateError3() async throws {\n\n        let hookTrigger = TestTrigger(className: \"foo\",\n                                      url: URL(string: \"https://api.example.com/foo\"))\n        do {\n            _ = try await hookTrigger.update()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(.unknownError))\n        }\n    }\n\n    @MainActor\n    func testFetch() async throws {\n\n        let hookTrigger = TestTrigger(className: \"foo\",\n                                      triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = hookTrigger\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let fetched = try await hookTrigger.fetch()\n        XCTAssertEqual(fetched, server)\n    }\n\n    @MainActor\n    func testFetchError() async throws {\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let hookTrigger = TestTrigger(className: \"foo\",\n                                      triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n        do {\n            _ = try await hookTrigger.fetch()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(server.code))\n        }\n    }\n\n    @MainActor\n    func testFetchError2() async throws {\n\n        let hookTrigger = TestTrigger(triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n        do {\n            _ = try await hookTrigger.fetch()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(.unknownError))\n        }\n    }\n\n    @MainActor\n    func testFetchAll() async throws {\n\n        let hookTrigger = TestTrigger(className: \"foo\",\n                                      triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n\n        let server = [hookTrigger]\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let fetched = try await hookTrigger.fetchAll()\n        XCTAssertEqual(fetched, server)\n    }\n\n    @MainActor\n    func testFetchAllError() async throws {\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let hookTrigger = TestTrigger(className: \"foo\",\n                                      triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n        do {\n            _ = try await hookTrigger.fetchAll()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(server.code))\n        }\n    }\n\n    @MainActor\n    func testDelete() async throws {\n        let server = NoBody()\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let hookTrigger = TestTrigger(className: \"foo\",\n                                      triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n        try await hookTrigger.delete()\n    }\n\n    @MainActor\n    func testDeleteError() async throws {\n        let server = ParseError(code: .commandUnavailable, message: \"no delete\")\n        let encoded = try ParseCoding.jsonEncoder().encode(server)\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let hookTrigger = TestTrigger(className: \"foo\",\n                                      triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n        do {\n            try await hookTrigger.delete()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(server.code))\n        }\n    }\n\n    @MainActor\n    func testDeleteError2() async throws {\n\n        let hookTrigger = TestTrigger(triggerName: .afterSave,\n                                      url: URL(string: \"https://api.example.com/foo\"))\n        do {\n            _ = try await hookTrigger.delete()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(.unknownError))\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseInstagramAsyncTests.swift",
    "content": "//\n//  ParseInstagramAsyncTests.swift\n//  ParseSwift\n//\n//  Created by Ulaş Sancak on 06/19/22.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseInstagramAsyncTests: XCTestCase { // swiftlint:disable:this type_body_length\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    @MainActor\n    func testLogin() async throws {\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.instagram.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.instagram.login(id: \"testing\", accessToken: \"access_token\", apiURL: \"apiURL\")\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.instagram.isLinked)\n    }\n\n    @MainActor\n    func testLoginAuthData() async throws {\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.instagram.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.instagram.login(authData: [\"id\": \"testing\",\n                                                             \"access_token\": \"access_token\",\n                                                             \"apiURL\": \"apiURL\"])\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.instagram.isLinked)\n    }\n\n    func loginNormally() async throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try await User.login(username: \"parse\", password: \"user\")\n    }\n\n    @MainActor\n    func testLink() async throws {\n        _ = try await loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.instagram.link(id: \"testing\", accessToken: \"access_token\", apiURL: \"apiURL\")\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.instagram.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testLinkAuthData() async throws {\n        _ = try await loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.instagram.link(authData: [\"id\": \"testing\",\n                                                            \"access_token\": \"access_token\",\n                                                            \"apiURL\": \"apiURL\"])\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.instagram.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testUnlink() async throws {\n        _ = try await loginNormally()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseInstagram<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"access_token\",\n                                                  apiURL: \"apiURL\")\n        User.current?.authData = [User.instagram.__type: authData]\n        XCTAssertTrue(User.instagram.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.instagram.unlink()\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertFalse(user.instagram.isLinked)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseInstagramCombineTests.swift",
    "content": "//\n//  ParseInstagramCombineTests.swift\n//  ParseSwift\n//\n//  Created by Ulaş Sancak on 06/19/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseInstagramCombineTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testLogin() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.instagram.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.instagram.loginPublisher(id: \"testing\",\n                                                      accessToken: \"access_token\",\n                                                      apiURL: \"apiURL\")\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user, userOnServer)\n            XCTAssertEqual(user.username, \"hello\")\n            XCTAssertEqual(user.password, \"world\")\n            XCTAssertTrue(user.instagram.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginAuthData() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.instagram.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.instagram.loginPublisher(authData: ([\"id\": \"testing\",\n                                                                 \"access_token\": \"access_token\",\n                                                                 \"apiURL\": \"apiURL\"]))\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user, userOnServer)\n            XCTAssertEqual(user.username, \"hello\")\n            XCTAssertEqual(user.password, \"world\")\n            XCTAssertTrue(user.instagram.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func loginNormally() throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try User.login(username: \"parse\", password: \"user\")\n    }\n\n    func testLink() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.instagram.linkPublisher(id: \"testing\",\n                                                     accessToken: \"access_token\",\n                                                     apiURL: \"apiURL\")\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertTrue(user.instagram.isLinked)\n            XCTAssertFalse(user.anonymous.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkAuthData() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let authData = ParseInstagram<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"access_token\",\n                                                  apiURL: \"apiURL\")\n        let publisher = User.instagram.linkPublisher(authData: authData)\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertTrue(user.instagram.isLinked)\n            XCTAssertFalse(user.anonymous.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUnlink() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseInstagram<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"access_token\",\n                                                  apiURL: \"apiURL\")\n        User.current?.authData = [User.instagram.__type: authData]\n        XCTAssertTrue(User.instagram.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.instagram.unlinkPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertFalse(user.instagram.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseInstagramTests.swift",
    "content": "//\n//  ParseInstagramTests.swift\n//  ParseSwift\n//\n//  Created by Ulaş Sancak on 06/19/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseInstagramTests: XCTestCase {\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func loginNormally() throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try User.login(username: \"parse\", password: \"user\")\n    }\n\n    func testAuthenticationKeys() throws {\n        let authData = ParseInstagram<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"access_token\",\n                                                  apiURL: \"apiURL\")\n        XCTAssertEqual(authData, [\"id\": \"testing\",\n                                  \"access_token\": \"access_token\",\n                                  \"apiURL\": \"apiURL\"])\n    }\n\n    func testAuthenticationKeysWithDefaultApiURL() throws {\n        let authData = ParseInstagram<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"access_token\")\n        XCTAssertEqual(authData, [\"id\": \"testing\",\n                                  \"access_token\": \"access_token\",\n                                  \"apiURL\": \"https://graph.instagram.com/\"])\n    }\n\n    func testVerifyMandatoryKeys() throws {\n        let authData = [\"id\": \"testing\", \"access_token\": \"access_token\", \"apiURL\": \"apiURL\"]\n        let authDataWrong = [\"id\": \"testing\", \"hello\": \"test\"]\n        XCTAssertTrue(ParseInstagram<User>\n                        .AuthenticationKeys.id.verifyMandatoryKeys(authData: authData))\n        XCTAssertFalse(ParseInstagram<User>\n                        .AuthenticationKeys.id.verifyMandatoryKeys(authData: authDataWrong))\n    }\n\n    func testLogin() throws {\n        var serverResponse = LoginSignupResponse()\n\n        let authData = ParseInstagram<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"access_token\",\n                                                  apiURL: \"apiURL\")\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.instagram.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.instagram.login(id: \"testing\", accessToken: \"access_token\", apiURL: \"apiURL\") { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user, userOnServer)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.instagram.isLinked)\n\n                //Test stripping\n                user.instagram.strip()\n                XCTAssertFalse(user.instagram.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginAuthData() throws {\n        var serverResponse = LoginSignupResponse()\n\n        let authData = ParseInstagram<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"access_token\",\n                                                  apiURL: \"apiURL\")\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.instagram.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.instagram.login(authData: authData) { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user, userOnServer)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.instagram.isLinked)\n\n                //Test stripping\n                user.instagram.strip()\n                XCTAssertFalse(user.instagram.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginWrongKeys() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.instagram.login(authData: [\"hello\": \"world\"]) { result in\n\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"consisting of keys\"))\n            } else {\n                XCTFail(\"Should have returned error\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func loginAnonymousUser() throws {\n        let authData = [\"id\": \"yolo\"]\n\n        //: Convert the anonymous user to a real new user.\n        var serverResponse = LoginSignupResponse()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.anonymous.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try User.anonymous.login()\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.anonymous.isLinked)\n    }\n\n    func testReplaceAnonymousWithInstagram() throws {\n        try loginAnonymousUser()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseInstagram<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"access_token\",\n                                                  apiURL: \"apiURL\")\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.instagram.__type: authData,\n                                   serverResponse.anonymous.__type: nil]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.instagram.login(id: \"testing\", accessToken: \"access_token\", apiURL: \"apiURL\") { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.authData, userOnServer.authData)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.instagram.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testReplaceAnonymousWithLinkedInstagram() throws {\n        try loginAnonymousUser()\n        MockURLProtocol.removeAll()\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.instagram.link(id: \"testing\", accessToken: \"access_token\") { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.instagram.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkLoggedInUserWithInstagram() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.sessionToken = nil\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.instagram.login(id: \"testing\", accessToken: \"access_token\", apiURL: \"apiURL\") { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello10\")\n                XCTAssertNil(user.password)\n                XCTAssertTrue(user.instagram.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n                XCTAssertEqual(User.current?.sessionToken, \"myToken\")\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkLoggedInAuthData() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.sessionToken = nil\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        let authData = ParseInstagram<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"access_token\",\n                                                  apiURL: \"apiURL\")\n\n        User.instagram.link(authData: authData) { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello10\")\n                XCTAssertNil(user.password)\n                XCTAssertTrue(user.instagram.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n                XCTAssertEqual(User.current?.sessionToken, \"myToken\")\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkLoggedInUserWrongKeys() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.instagram.link(authData: [\"hello\": \"world\"]) { result in\n\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"consisting of keys\"))\n            } else {\n                XCTFail(\"Should have returned error\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUnlink() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseInstagram<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"access_token\",\n                                                  apiURL: \"apiURL\")\n        User.current?.authData = [User.instagram.__type: authData]\n        XCTAssertTrue(User.instagram.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.instagram.unlink { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello10\")\n                XCTAssertNil(user.password)\n                XCTAssertFalse(user.instagram.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseInstallationAsyncTests.swift",
    "content": "//\n//  ParseInstallationAsyncTests.swift\n//  ParseInstallationAsyncTests\n//\n//  Created by Corey Baker on 8/6/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseInstallationAsyncTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    struct Installation: ParseInstallation {\n        var installationId: String?\n        var deviceType: String?\n        var deviceToken: String?\n        var badge: Int?\n        var timeZone: String?\n        var channels: [String]?\n        var appName: String?\n        var appIdentifier: String?\n        var appVersion: String?\n        var parseVersion: String?\n        var localeIdentifier: String?\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n        var customKey: String?\n\n        //: Implement your own version of merge\n        func merge(with object: Self) throws -> Self {\n            var updated = try mergeParse(with: object)\n            if updated.shouldRestoreKey(\\.customKey,\n                                         original: object) {\n                updated.customKey = object.customKey\n            }\n            return updated\n        }\n    }\n\n    struct InstallationDefaultMerge: ParseInstallation {\n        var installationId: String?\n        var deviceType: String?\n        var deviceToken: String?\n        var badge: Int?\n        var timeZone: String?\n        var channels: [String]?\n        var appName: String?\n        var appIdentifier: String?\n        var appVersion: String?\n        var parseVersion: String?\n        var localeIdentifier: String?\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n        var customKey: String?\n    }\n\n    struct InstallationDefault: ParseInstallation {\n        var installationId: String?\n        var deviceType: String?\n        var deviceToken: String?\n        var badge: Int?\n        var timeZone: String?\n        var channels: [String]?\n        var appName: String?\n        var appIdentifier: String?\n        var appVersion: String?\n        var parseVersion: String?\n        var localeIdentifier: String?\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n    }\n\n    let testInstallationObjectId = \"yarr\"\n\n    let loginUserName = \"hello10\"\n    let loginPassword = \"world\"\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n        login()\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func login() {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        do {\n            _ = try User.login(username: loginUserName, password: loginPassword)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func saveCurrentInstallation() throws {\n        guard let installation = Installation.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n\n        var installationOnServer = installation\n        installationOnServer.objectId = testInstallationObjectId\n        installationOnServer.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        let encoded: Data!\n        do {\n            encoded = try installationOnServer.getEncoder().encode(installationOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            guard let saved = try Installation.current?.save(),\n                let newCurrentInstallation = Installation.current else {\n                XCTFail(\"Should have a new current installation\")\n                return\n            }\n            XCTAssertTrue(saved.hasSameInstallationId(as: newCurrentInstallation))\n            XCTAssertTrue(saved.hasSameObjectId(as: newCurrentInstallation))\n            XCTAssertTrue(saved.hasSameObjectId(as: installationOnServer))\n            XCTAssertTrue(saved.hasSameInstallationId(as: installationOnServer))\n            XCTAssertNil(saved.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testOriginalDataNeverSavesToKeychain() async throws {\n        // Save current Installation\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        Installation.current?.originalData = Data()\n        let original = Installation.current\n        Installation.saveCurrentContainerToKeychain()\n\n        let expectation1 = XCTestExpectation(description: \"Original installation1\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n            guard let original = original,\n                let saved = Installation.current else {\n                XCTFail(\"Should have a new current installation\")\n                expectation1.fulfill()\n                return\n            }\n            XCTAssertTrue(saved.hasSameInstallationId(as: original))\n            XCTAssertTrue(saved.hasSameObjectId(as: original))\n            XCTAssertNotNil(original.originalData)\n            XCTAssertNil(saved.originalData)\n            XCTAssertEqual(saved.customKey, original.customKey)\n            XCTAssertEqual(saved.badge, original.badge)\n            XCTAssertEqual(saved.deviceType, original.deviceType)\n            XCTAssertEqual(saved.deviceToken, original.deviceToken)\n            XCTAssertEqual(saved.channels, original.channels)\n            XCTAssertEqual(saved.installationId, original.installationId)\n            XCTAssertEqual(saved.timeZone, original.timeZone)\n            XCTAssertEqual(saved.appName, original.appName)\n            XCTAssertEqual(saved.appVersion, original.appVersion)\n            XCTAssertEqual(saved.appIdentifier, original.appIdentifier)\n            XCTAssertEqual(saved.parseVersion, original.parseVersion)\n            XCTAssertEqual(saved.localeIdentifier, original.localeIdentifier)\n            XCTAssertEqual(saved.createdAt, original.createdAt)\n            XCTAssertEqual(saved.updatedAt, original.updatedAt)\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    @MainActor\n    func testFetch() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let installation = Installation.current,\n            let savedObjectId = installation.objectId else {\n                XCTFail(\"Should unwrap\")\n                return\n        }\n        XCTAssertEqual(savedObjectId, self.testInstallationObjectId)\n\n        var serverResponse = installation\n        serverResponse.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n        serverResponse.customKey = \"newValue\"\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let fetched = try await installation.fetch()\n        XCTAssert(fetched.hasSameObjectId(as: serverResponse))\n        XCTAssert(fetched.hasSameInstallationId(as: serverResponse))\n        XCTAssertEqual(Installation.current?.customKey, serverResponse.customKey)\n    }\n\n    @MainActor\n    func testSaveCurrent() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard var installation = Installation.current,\n            let savedObjectId = installation.objectId else {\n                XCTFail(\"Should unwrap\")\n                return\n        }\n        installation.customKey = \"newValue\"\n        XCTAssertEqual(savedObjectId, self.testInstallationObjectId)\n\n        var serverResponse = installation\n        serverResponse.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let fetched = try await installation.save()\n        XCTAssert(fetched.hasSameObjectId(as: serverResponse))\n        XCTAssert(fetched.hasSameInstallationId(as: serverResponse))\n        XCTAssertEqual(Installation.current?.customKey, serverResponse.customKey)\n    }\n\n    @MainActor\n    func testSave() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        var installation = Installation()\n        installation.customKey = \"newValue\"\n        installation.installationId = \"123\"\n\n        var serverResponse = installation\n        serverResponse.objectId = \"yolo\"\n        serverResponse.createdAt = Date()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                //Get dates in correct format from ParseDecoding strategy\n                serverResponse = try serverResponse.getDecoder().decode(Installation.self, from: encoded)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let saved = try await installation.save()\n        XCTAssert(saved.hasSameObjectId(as: serverResponse))\n        XCTAssert(saved.hasSameInstallationId(as: serverResponse))\n        XCTAssertEqual(saved.createdAt, serverResponse.createdAt)\n        XCTAssertEqual(saved.updatedAt, serverResponse.createdAt)\n    }\n\n    @MainActor\n    func testCreate() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        var installation = Installation()\n        installation.customKey = \"newValue\"\n        installation.installationId = \"123\"\n\n        var serverResponse = installation\n        serverResponse.objectId = \"yolo\"\n        serverResponse.createdAt = Date()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                //Get dates in correct format from ParseDecoding strategy\n                serverResponse = try serverResponse.getDecoder().decode(Installation.self, from: encoded)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let saved = try await installation.create()\n        XCTAssert(saved.hasSameObjectId(as: serverResponse))\n        XCTAssert(saved.hasSameInstallationId(as: serverResponse))\n        XCTAssertEqual(saved.createdAt, serverResponse.createdAt)\n        XCTAssertEqual(saved.updatedAt, serverResponse.createdAt)\n    }\n\n    @MainActor\n    func testReplaceCreate() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        var installation = Installation()\n        installation.objectId = \"yolo\"\n        installation.customKey = \"newValue\"\n        installation.installationId = \"123\"\n\n        var serverResponse = installation\n        serverResponse.createdAt = Date()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                //Get dates in correct format from ParseDecoding strategy\n                serverResponse = try serverResponse.getDecoder().decode(Installation.self, from: encoded)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let saved = try await installation.replace()\n        XCTAssert(saved.hasSameObjectId(as: serverResponse))\n        XCTAssert(saved.hasSameInstallationId(as: serverResponse))\n        XCTAssertEqual(saved.createdAt, serverResponse.createdAt)\n        XCTAssertEqual(saved.updatedAt, serverResponse.createdAt)\n    }\n\n    @MainActor\n    func testReplaceUpdate() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        var installation = Installation()\n        installation.objectId = \"yolo\"\n        installation.customKey = \"newValue\"\n        installation.installationId = \"123\"\n\n        var serverResponse = installation\n        serverResponse.updatedAt = Date()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                //Get dates in correct format from ParseDecoding strategy\n                serverResponse = try serverResponse.getDecoder().decode(Installation.self, from: encoded)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let saved = try await installation.replace()\n        XCTAssert(saved.hasSameObjectId(as: serverResponse))\n        XCTAssert(saved.hasSameInstallationId(as: serverResponse))\n        XCTAssertEqual(saved.updatedAt, serverResponse.updatedAt)\n    }\n\n    @MainActor\n    func testUpdate() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        var installation = Installation()\n        installation.objectId = \"yolo\"\n        installation.customKey = \"newValue\"\n        installation.installationId = \"123\"\n\n        var serverResponse = installation\n        serverResponse.updatedAt = Date()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                // Get dates in correct format from ParseDecoding strategy\n                serverResponse = try serverResponse.getDecoder().decode(Installation.self, from: encoded)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let saved = try await installation.update()\n        XCTAssert(saved.hasSameObjectId(as: serverResponse))\n        XCTAssert(saved.hasSameInstallationId(as: serverResponse))\n        XCTAssertEqual(saved.updatedAt, serverResponse.updatedAt)\n    }\n\n    @MainActor\n    func testUpdateDefaultMerge() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        var installation = InstallationDefaultMerge()\n        installation.objectId = \"yolo\"\n        installation.installationId = \"123\"\n\n        var serverResponse = installation\n        serverResponse.updatedAt = Date()\n        serverResponse.customKey = \"newValue\"\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                // Get dates in correct format from ParseDecoding strategy\n                serverResponse = try serverResponse.getDecoder().decode(InstallationDefaultMerge.self, from: encoded)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        installation = installation.set(\\.customKey, to: \"newValue\")\n        let saved = try await installation.update()\n        XCTAssertEqual(saved, serverResponse)\n    }\n\n    func testUpdateMutableMergeCurrentInstallation() async throws {\n        // Save current Installation\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let original = Installation.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n        var originalResponse = original.mergeable\n        originalResponse.createdAt = nil\n        originalResponse.updatedAt = Calendar.current.date(byAdding: .init(day: 1), to: Date())\n\n        let encoded: Data!\n        do {\n            encoded = try originalResponse.getEncoder().encode(originalResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            originalResponse = try originalResponse.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        let response = originalResponse\n        var originalUpdate = original.mergeable\n        originalUpdate.customKey = \"hello\"\n        originalUpdate.deviceToken = \"1234\"\n        let updated = originalUpdate\n\n        do {\n            let saved = try await updated.update()\n            let expectation1 = XCTestExpectation(description: \"Update installation1\")\n            DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n                guard let newCurrentInstallation = Installation.current else {\n                    XCTFail(\"Should have a new current installation\")\n                    expectation1.fulfill()\n                    return\n                }\n                XCTAssertTrue(saved.hasSameInstallationId(as: newCurrentInstallation))\n                XCTAssertTrue(saved.hasSameObjectId(as: newCurrentInstallation))\n                XCTAssertTrue(saved.hasSameObjectId(as: response))\n                XCTAssertEqual(saved.customKey, updated.customKey)\n                XCTAssertEqual(saved.badge, original.badge)\n                XCTAssertEqual(saved.deviceType, original.deviceType)\n                XCTAssertEqual(saved.deviceToken, updated.deviceToken)\n                XCTAssertEqual(saved.channels, original.channels)\n                XCTAssertEqual(saved.installationId, original.installationId)\n                XCTAssertEqual(saved.timeZone, original.timeZone)\n                XCTAssertEqual(saved.appName, original.appName)\n                XCTAssertEqual(saved.appVersion, original.appVersion)\n                XCTAssertEqual(saved.appIdentifier, original.appIdentifier)\n                XCTAssertEqual(saved.parseVersion, original.parseVersion)\n                XCTAssertEqual(saved.localeIdentifier, original.localeIdentifier)\n                XCTAssertEqual(saved.createdAt, original.createdAt)\n                XCTAssertEqual(saved.updatedAt, response.updatedAt)\n                XCTAssertNil(saved.originalData)\n                XCTAssertEqual(saved.customKey, newCurrentInstallation.customKey)\n                XCTAssertEqual(saved.badge, newCurrentInstallation.badge)\n                XCTAssertEqual(saved.deviceType, newCurrentInstallation.deviceType)\n                XCTAssertEqual(saved.deviceToken, newCurrentInstallation.deviceToken)\n                XCTAssertEqual(saved.channels, newCurrentInstallation.channels)\n                XCTAssertEqual(saved.installationId, newCurrentInstallation.installationId)\n                XCTAssertEqual(saved.timeZone, newCurrentInstallation.timeZone)\n                XCTAssertEqual(saved.appName, newCurrentInstallation.appName)\n                XCTAssertEqual(saved.appVersion, newCurrentInstallation.appVersion)\n                XCTAssertEqual(saved.appIdentifier, newCurrentInstallation.appIdentifier)\n                XCTAssertEqual(saved.parseVersion, newCurrentInstallation.parseVersion)\n                XCTAssertEqual(saved.localeIdentifier, newCurrentInstallation.localeIdentifier)\n                XCTAssertEqual(saved.createdAt, newCurrentInstallation.createdAt)\n                XCTAssertEqual(saved.updatedAt, newCurrentInstallation.updatedAt)\n                expectation1.fulfill()\n            }\n            wait(for: [expectation1], timeout: 20.0)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testUpdateMutableMergeCurrentInstallationDefault() async throws {\n        // Save current Installation\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let original = InstallationDefault.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n        var originalResponse = original.mergeable\n        originalResponse.createdAt = nil\n        originalResponse.updatedAt = Calendar.current.date(byAdding: .init(day: 1), to: Date())\n\n        let encoded: Data!\n        do {\n            encoded = try originalResponse.getEncoder().encode(originalResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            originalResponse = try originalResponse.getDecoder().decode(InstallationDefault.self,\n                                                                        from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        let response = originalResponse\n        var originalUpdate = original.mergeable\n        originalUpdate.deviceToken = \"1234\"\n        let updated = originalUpdate\n\n        do {\n            let saved = try await updated.update()\n            let expectation1 = XCTestExpectation(description: \"Update installation1\")\n            DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n                guard let newCurrentInstallation = Installation.current else {\n                    XCTFail(\"Should have a new current installation\")\n                    expectation1.fulfill()\n                    return\n                }\n                XCTAssertTrue(saved.hasSameInstallationId(as: newCurrentInstallation))\n                XCTAssertTrue(saved.hasSameObjectId(as: newCurrentInstallation))\n                XCTAssertTrue(saved.hasSameObjectId(as: response))\n                XCTAssertEqual(saved.badge, original.badge)\n                XCTAssertEqual(saved.deviceType, original.deviceType)\n                XCTAssertEqual(saved.deviceToken, updated.deviceToken)\n                XCTAssertEqual(saved.channels, original.channels)\n                XCTAssertEqual(saved.installationId, original.installationId)\n                XCTAssertEqual(saved.timeZone, original.timeZone)\n                XCTAssertEqual(saved.appName, original.appName)\n                XCTAssertEqual(saved.appVersion, original.appVersion)\n                XCTAssertEqual(saved.appIdentifier, original.appIdentifier)\n                XCTAssertEqual(saved.parseVersion, original.parseVersion)\n                XCTAssertEqual(saved.localeIdentifier, original.localeIdentifier)\n                XCTAssertEqual(saved.createdAt, original.createdAt)\n                XCTAssertEqual(saved.updatedAt, response.updatedAt)\n                XCTAssertNil(saved.originalData)\n                XCTAssertEqual(saved.badge, newCurrentInstallation.badge)\n                XCTAssertEqual(saved.deviceType, newCurrentInstallation.deviceType)\n                XCTAssertEqual(saved.deviceToken, newCurrentInstallation.deviceToken)\n                XCTAssertEqual(saved.channels, newCurrentInstallation.channels)\n                XCTAssertEqual(saved.installationId, newCurrentInstallation.installationId)\n                XCTAssertEqual(saved.timeZone, newCurrentInstallation.timeZone)\n                XCTAssertEqual(saved.appName, newCurrentInstallation.appName)\n                XCTAssertEqual(saved.appVersion, newCurrentInstallation.appVersion)\n                XCTAssertEqual(saved.appIdentifier, newCurrentInstallation.appIdentifier)\n                XCTAssertEqual(saved.parseVersion, newCurrentInstallation.parseVersion)\n                XCTAssertEqual(saved.localeIdentifier, newCurrentInstallation.localeIdentifier)\n                XCTAssertEqual(saved.createdAt, newCurrentInstallation.createdAt)\n                XCTAssertEqual(saved.updatedAt, newCurrentInstallation.updatedAt)\n                expectation1.fulfill()\n            }\n            wait(for: [expectation1], timeout: 20.0)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    @MainActor\n    func testUpdateClientMissingObjectId() async throws {\n        var installation = Installation()\n        installation.installationId = \"123\"\n        do {\n            _ = try await installation.update()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted to ParseError\")\n                return\n            }\n            XCTAssertEqual(parseError.code, .missingObjectId)\n        }\n    }\n\n    @MainActor\n    func testDelete() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let installation = Installation.current,\n            let savedObjectId = installation.objectId else {\n                XCTFail(\"Should unwrap\")\n                return\n        }\n        XCTAssertEqual(savedObjectId, self.testInstallationObjectId)\n\n        var serverResponse = installation\n        serverResponse.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n        serverResponse.customKey = \"newValue\"\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        _ = try await installation.delete()\n        if let newInstallation = Installation.current {\n            XCTAssertFalse(installation.hasSameInstallationId(as: newInstallation))\n        }\n    }\n\n    @MainActor\n    func testDeleteError() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let installation = Installation.current,\n            let savedObjectId = installation.objectId else {\n                XCTFail(\"Should unwrap\")\n                return\n        }\n        XCTAssertEqual(savedObjectId, self.testInstallationObjectId)\n\n        let serverResponse = ParseError(code: .objectNotFound, message: \"not found\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        do {\n            _ = try await installation.delete()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let error = error as? ParseError else {\n                XCTFail(\"Should be ParseError\")\n                return\n            }\n            XCTAssertEqual(error.message, serverResponse.message)\n        }\n\n        if let newInstallation = Installation.current {\n            XCTAssertTrue(installation.hasSameInstallationId(as: newInstallation))\n        }\n    }\n\n    @MainActor\n    func testFetchAll() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard var installation = Installation.current else {\n            XCTFail(\"Should unwrap dates\")\n            return\n        }\n\n        installation.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n        installation.customKey = \"newValue\"\n        let installationOnServer = QueryResponse<Installation>(results: [installation], count: 1)\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(installation)\n            installation = try installation.getDecoder().decode(Installation.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let fetched = try await [installation].fetchAll()\n        fetched.forEach {\n            switch $0 {\n            case .success(let fetched):\n                XCTAssert(fetched.hasSameObjectId(as: installation))\n                guard let fetchedCreatedAt = fetched.createdAt,\n                    let fetchedUpdatedAt = fetched.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                guard let originalCreatedAt = installation.createdAt,\n                    let originalUpdatedAt = installation.updatedAt,\n                    let serverUpdatedAt = installation.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n                XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n                XCTAssertEqual(fetchedUpdatedAt, serverUpdatedAt)\n                XCTAssertEqual(Installation.current?.customKey, installation.customKey)\n\n                //Should be updated in memory\n                guard let updatedCurrentDate = Installation.current?.updatedAt else {\n                    XCTFail(\"Should unwrap current date\")\n                    return\n                }\n                XCTAssertEqual(updatedCurrentDate, serverUpdatedAt)\n\n                #if !os(Linux) && !os(Android) && !os(Windows)\n                //Should be updated in Keychain\n                guard let keychainInstallation: CurrentInstallationContainer<BaseParseInstallation>\n                    = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation),\n                    let keychainUpdatedCurrentDate = keychainInstallation.currentInstallation?.updatedAt else {\n                        XCTFail(\"Should get object from Keychain\")\n                    return\n                }\n                XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt)\n                #endif\n            case .failure(let error):\n                XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n            }\n        }\n    }\n\n    @MainActor\n    func testSaveAll() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard var installation = Installation.current else {\n            XCTFail(\"Should unwrap dates\")\n            return\n        }\n        installation.createdAt = nil\n        installation.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n        installation.customKey = \"newValue\"\n        let installationOnServer = [BatchResponseItem<Installation>(success: installation, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(installation)\n            installation = try installation.getDecoder().decode(Installation.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await [installation].saveAll()\n        saved.forEach {\n            switch $0 {\n            case .success(let saved):\n                XCTAssert(saved.hasSameObjectId(as: installation))\n                XCTAssert(saved.hasSameInstallationId(as: installation))\n                guard let savedUpdatedAt = saved.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                guard let originalUpdatedAt = installation.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n                XCTAssertEqual(Installation.current?.customKey, installation.customKey)\n\n                //Should be updated in memory\n                guard let updatedCurrentDate = Installation.current?.updatedAt else {\n                    XCTFail(\"Should unwrap current date\")\n                    return\n                }\n                XCTAssertEqual(updatedCurrentDate, originalUpdatedAt)\n\n                #if !os(Linux) && !os(Android) && !os(Windows)\n                //Should be updated in Keychain\n                guard let keychainInstallation: CurrentInstallationContainer<BaseParseInstallation>\n                    = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation),\n                    let keychainUpdatedCurrentDate = keychainInstallation.currentInstallation?.updatedAt else {\n                        XCTFail(\"Should get object from Keychain\")\n                    return\n                }\n                XCTAssertEqual(keychainUpdatedCurrentDate, originalUpdatedAt)\n                #endif\n            case .failure(let error):\n                XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n            }\n        }\n    }\n\n    @MainActor\n    func testCreateAll() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        var installation = Installation()\n        installation.customKey = \"newValue\"\n        installation.installationId = \"123\"\n\n        var serverResponse = installation\n        serverResponse.objectId = \"yolo\"\n        serverResponse.createdAt = Date()\n        let installationOnServer = [BatchResponseItem<Installation>(success: serverResponse, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(serverResponse)\n            serverResponse = try installation.getDecoder().decode(Installation.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await [installation].createAll()\n        saved.forEach {\n            switch $0 {\n            case .success(let saved):\n                XCTAssert(saved.hasSameObjectId(as: serverResponse))\n                XCTAssert(saved.hasSameInstallationId(as: serverResponse))\n                guard let savedCreatedAt = saved.createdAt,\n                    let savedUpdatedAt = saved.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                guard let originalCreatedAt = serverResponse.createdAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n                XCTAssertEqual(savedUpdatedAt, originalCreatedAt)\n\n            case .failure(let error):\n                XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n            }\n        }\n    }\n\n    @MainActor\n    func testReplaceAllCreate() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        var installation = Installation()\n        installation.customKey = \"newValue\"\n        installation.installationId = \"123\"\n        installation.objectId = \"yolo\"\n\n        var serverResponse = installation\n        serverResponse.createdAt = Date()\n        let installationOnServer = [BatchResponseItem<Installation>(success: serverResponse, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(serverResponse)\n            serverResponse = try installation.getDecoder().decode(Installation.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await [installation].replaceAll()\n        saved.forEach {\n            switch $0 {\n            case .success(let saved):\n                XCTAssert(saved.hasSameObjectId(as: serverResponse))\n                XCTAssert(saved.hasSameInstallationId(as: serverResponse))\n                XCTAssertEqual(saved.createdAt, serverResponse.createdAt)\n                XCTAssertEqual(saved.updatedAt, serverResponse.createdAt)\n\n            case .failure(let error):\n                XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n            }\n        }\n    }\n\n    @MainActor\n    func testReplaceAllUpdate() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        var installation = Installation()\n        installation.customKey = \"newValue\"\n        installation.installationId = \"123\"\n        installation.objectId = \"yolo\"\n\n        var serverResponse = installation\n        serverResponse.updatedAt = Date()\n        let installationOnServer = [BatchResponseItem<Installation>(success: serverResponse, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(serverResponse)\n            serverResponse = try installation.getDecoder().decode(Installation.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await [installation].replaceAll()\n        saved.forEach {\n            switch $0 {\n            case .success(let saved):\n                XCTAssert(saved.hasSameObjectId(as: serverResponse))\n                XCTAssert(saved.hasSameInstallationId(as: serverResponse))\n                guard let savedUpdatedAt = saved.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                guard let originalUpdatedAt = serverResponse.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n\n            case .failure(let error):\n                XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n            }\n        }\n    }\n\n    @MainActor\n    func testUpdateAll() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        var installation = Installation()\n        installation.customKey = \"newValue\"\n        installation.installationId = \"123\"\n        installation.objectId = \"yolo\"\n\n        var serverResponse = installation\n        serverResponse.updatedAt = Date()\n        let installationOnServer = [BatchResponseItem<Installation>(success: serverResponse, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(serverResponse)\n            serverResponse = try installation.getDecoder().decode(Installation.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await [installation].updateAll()\n        saved.forEach {\n            switch $0 {\n            case .success(let saved):\n                XCTAssert(saved.hasSameObjectId(as: serverResponse))\n                XCTAssert(saved.hasSameInstallationId(as: serverResponse))\n                guard let savedUpdatedAt = saved.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                guard let originalUpdatedAt = serverResponse.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n\n            case .failure(let error):\n                XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n            }\n        }\n    }\n\n    @MainActor\n    func testDeleteAll() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let installation = Installation.current else {\n            XCTFail(\"Should unwrap dates\")\n            return\n        }\n\n        let installationOnServer = [BatchResponseItem<NoBody>(success: NoBody(), error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let deleted = try await [installation].deleteAll()\n        deleted.forEach {\n            if case let .failure(error) = $0 {\n                XCTFail(\"Should have deleted: \\(error.localizedDescription)\")\n            }\n            if let newInstallation = Installation.current {\n                XCTAssertFalse(installation.hasSameInstallationId(as: newInstallation))\n            }\n        }\n    }\n\n    @MainActor\n    func testBecome() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let installation = Installation.current,\n            let savedObjectId = installation.objectId else {\n                XCTFail(\"Should unwrap\")\n                return\n        }\n        XCTAssertEqual(savedObjectId, self.testInstallationObjectId)\n\n        var installationOnServer = installation\n        installationOnServer.createdAt = installation.updatedAt\n        installationOnServer.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n        installationOnServer.customKey = \"newValue\"\n        installationOnServer.installationId = \"wowsers\"\n        installationOnServer.channels = [\"yo\"]\n        installationOnServer.deviceToken = \"no\"\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            // Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self,\n                                                                                from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await Installation.become(\"wowsers\")\n        guard let currentInstallation = Installation.current else {\n            XCTFail(\"Should have current installation\")\n            return\n        }\n        XCTAssertTrue(installationOnServer.hasSameObjectId(as: saved))\n        XCTAssertTrue(installationOnServer.hasSameInstallationId(as: saved))\n        XCTAssertTrue(installationOnServer.hasSameObjectId(as: currentInstallation))\n        XCTAssertTrue(installationOnServer.hasSameInstallationId(as: currentInstallation))\n        guard let savedCreatedAt = saved.createdAt else {\n            XCTFail(\"Should unwrap dates\")\n            return\n        }\n        guard let originalCreatedAt = installationOnServer.createdAt else {\n            XCTFail(\"Should unwrap dates\")\n            return\n        }\n        XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n        XCTAssertEqual(saved.channels, installationOnServer.channels)\n        XCTAssertEqual(saved.deviceToken, installationOnServer.deviceToken)\n\n        // Should be updated in memory\n        XCTAssertEqual(Installation.current?.installationId, \"wowsers\")\n        XCTAssertEqual(Installation.current?.customKey, installationOnServer.customKey)\n        XCTAssertEqual(Installation.current?.channels, installationOnServer.channels)\n        XCTAssertEqual(Installation.current?.deviceToken, installationOnServer.deviceToken)\n\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        // Should be updated in Keychain\n        guard let keychainInstallation: CurrentInstallationContainer<BaseParseInstallation>\n            = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) else {\n                XCTFail(\"Should get object from Keychain\")\n            return\n        }\n        XCTAssertEqual(keychainInstallation.currentInstallation?.installationId, \"wowsers\")\n        XCTAssertEqual(keychainInstallation.currentInstallation?.channels, installationOnServer.channels)\n        XCTAssertEqual(keychainInstallation.currentInstallation?.deviceToken, installationOnServer.deviceToken)\n        #endif\n    }\n\n    @MainActor\n    func testBecomeSameObjectId() async throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let installation = Installation.current,\n            let savedObjectId = installation.objectId else {\n                XCTFail(\"Should unwrap\")\n                return\n        }\n        XCTAssertEqual(savedObjectId, self.testInstallationObjectId)\n\n        let saved = try await Installation.become(testInstallationObjectId)\n        guard let currentInstallation = Installation.current else {\n            XCTFail(\"Should have current installation\")\n            return\n        }\n        XCTAssertEqual(saved, currentInstallation)\n    }\n\n    @MainActor\n    func testBecomeMissingObjectId() async throws {\n        try ParseStorage.shared.delete(valueFor: ParseStorage.Keys.currentInstallation)\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.delete(valueFor: ParseStorage.Keys.currentInstallation)\n        #endif\n        Installation.currentContainer.currentInstallation = nil\n\n        do {\n            _ = try await Installation.become(testInstallationObjectId)\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"does not exist\"))\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseInstallationCombineTests.swift",
    "content": "//\n//  ParseInstallationCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/30/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseInstallationCombineTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    struct Installation: ParseInstallation {\n        var installationId: String?\n        var deviceType: String?\n        var deviceToken: String?\n        var badge: Int?\n        var timeZone: String?\n        var channels: [String]?\n        var appName: String?\n        var appIdentifier: String?\n        var appVersion: String?\n        var parseVersion: String?\n        var localeIdentifier: String?\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n        var customKey: String?\n    }\n\n    let testInstallationObjectId = \"yarr\"\n\n    let loginUserName = \"hello10\"\n    let loginPassword = \"world\"\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n        login()\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func login() {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        do {\n            _ = try User.login(username: loginUserName, password: loginPassword)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func saveCurrentInstallation() throws {\n        guard let installation = Installation.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n\n        var installationOnServer = installation\n        installationOnServer.objectId = testInstallationObjectId\n        installationOnServer.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        let encoded: Data!\n        do {\n            encoded = try installationOnServer.getEncoder().encode(installationOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            guard let saved = try Installation.current?.save(),\n                let newCurrentInstallation = Installation.current else {\n                XCTFail(\"Should have a new current installation\")\n                return\n            }\n            XCTAssertTrue(saved.hasSameInstallationId(as: newCurrentInstallation))\n            XCTAssertTrue(saved.hasSameObjectId(as: newCurrentInstallation))\n            XCTAssertTrue(saved.hasSameObjectId(as: installationOnServer))\n            XCTAssertTrue(saved.hasSameInstallationId(as: installationOnServer))\n            XCTAssertNil(saved.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testFetch() throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Update installation1\")\n\n        guard let installation = Installation.current,\n            let savedObjectId = installation.objectId else {\n                XCTFail(\"Should unwrap\")\n                expectation1.fulfill()\n                return\n        }\n        XCTAssertEqual(savedObjectId, self.testInstallationObjectId)\n\n        var serverResponse = installation\n        serverResponse.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n        serverResponse.customKey = \"newValue\"\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let publisher = installation.fetchPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { fetched in\n\n            XCTAssert(fetched.hasSameObjectId(as: serverResponse))\n            XCTAssert(fetched.hasSameInstallationId(as: serverResponse))\n            XCTAssertEqual(Installation.current?.customKey, serverResponse.customKey)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSave() throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Update installation1\")\n        guard var installation = Installation.current,\n            let savedObjectId = installation.objectId else {\n                XCTFail(\"Should unwrap\")\n                expectation1.fulfill()\n                return\n        }\n        installation.customKey = \"newValue\"\n        XCTAssertEqual(savedObjectId, self.testInstallationObjectId)\n\n        var serverResponse = installation\n        serverResponse.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let publisher = installation.savePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { fetched in\n\n            XCTAssert(fetched.hasSameObjectId(as: serverResponse))\n            XCTAssert(fetched.hasSameInstallationId(as: serverResponse))\n            XCTAssertEqual(Installation.current?.customKey, serverResponse.customKey)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testCreate() throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Update installation1\")\n        var installation = Installation()\n        installation.customKey = \"newValue\"\n        installation.installationId = \"123\"\n\n        var serverResponse = installation\n        serverResponse.objectId = \"yolo\"\n        serverResponse.createdAt = Date()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                //Get dates in correct format from ParseDecoding strategy\n                serverResponse = try serverResponse.getDecoder().decode(Installation.self, from: encoded)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let publisher = installation.createPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { fetched in\n\n            XCTAssert(fetched.hasSameObjectId(as: serverResponse))\n            XCTAssert(fetched.hasSameInstallationId(as: serverResponse))\n            XCTAssertEqual(fetched.customKey, serverResponse.customKey)\n            XCTAssertEqual(fetched.installationId, serverResponse.installationId)\n            XCTAssertEqual(fetched.createdAt, serverResponse.createdAt)\n            XCTAssertEqual(fetched.updatedAt, serverResponse.createdAt)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUpdate() throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Update installation1\")\n        var installation = Installation()\n        installation.customKey = \"newValue\"\n        installation.objectId = \"yolo\"\n        installation.installationId = \"123\"\n\n        var serverResponse = installation\n        serverResponse.updatedAt = Date()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                //Get dates in correct format from ParseDecoding strategy\n                serverResponse = try serverResponse.getDecoder().decode(Installation.self, from: encoded)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let publisher = installation.updatePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { fetched in\n\n            XCTAssert(fetched.hasSameObjectId(as: serverResponse))\n            XCTAssert(fetched.hasSameInstallationId(as: serverResponse))\n            XCTAssertEqual(fetched.customKey, serverResponse.customKey)\n            XCTAssertEqual(fetched.installationId, serverResponse.installationId)\n            XCTAssertEqual(fetched.updatedAt, serverResponse.updatedAt)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDelete() throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Update installation1\")\n        guard let installation = Installation.current,\n            let savedObjectId = installation.objectId else {\n                XCTFail(\"Should unwrap\")\n                expectation1.fulfill()\n                return\n        }\n        XCTAssertEqual(savedObjectId, self.testInstallationObjectId)\n\n        var serverResponse = installation\n        serverResponse.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n        serverResponse.customKey = \"newValue\"\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let publisher = installation.deletePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            if let newInstallation = Installation.current {\n                XCTAssertFalse(installation.hasSameInstallationId(as: newInstallation))\n            }\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testFetchAll() throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Fetch\")\n\n        guard var installation = Installation.current else {\n                XCTFail(\"Should unwrap dates\")\n            expectation1.fulfill()\n                return\n        }\n\n        installation.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n        installation.customKey = \"newValue\"\n        let installationOnServer = QueryResponse<Installation>(results: [installation], count: 1)\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(installation)\n            installation = try installation.getDecoder().decode(Installation.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = [installation].fetchAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { fetched in\n\n            fetched.forEach {\n                switch $0 {\n                case .success(let fetched):\n                    XCTAssert(fetched.hasSameObjectId(as: installation))\n                    guard let fetchedCreatedAt = fetched.createdAt,\n                        let fetchedUpdatedAt = fetched.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    guard let originalCreatedAt = installation.createdAt,\n                        let originalUpdatedAt = installation.updatedAt,\n                        let serverUpdatedAt = installation.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n                    XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n                    XCTAssertEqual(fetchedUpdatedAt, serverUpdatedAt)\n                    XCTAssertEqual(Installation.current?.customKey, installation.customKey)\n\n                    //Should be updated in memory\n                    guard let updatedCurrentDate = Installation.current?.updatedAt else {\n                        XCTFail(\"Should unwrap current date\")\n                        expectation1.fulfill()\n                        return\n                    }\n                    XCTAssertEqual(updatedCurrentDate, serverUpdatedAt)\n\n                    #if !os(Linux) && !os(Android) && !os(Windows)\n                    //Should be updated in Keychain\n                    guard let keychainInstallation: CurrentInstallationContainer<BaseParseInstallation>\n                        = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation),\n                        let keychainUpdatedCurrentDate = keychainInstallation.currentInstallation?.updatedAt else {\n                            XCTFail(\"Should get object from Keychain\")\n                            expectation1.fulfill()\n                        return\n                    }\n                    XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt)\n                    #endif\n                case .failure(let error):\n                    XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                }\n            }\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSaveAll() throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        guard var installation = Installation.current else {\n                XCTFail(\"Should unwrap dates\")\n            expectation1.fulfill()\n                return\n        }\n        installation.createdAt = nil\n        installation.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n        installation.customKey = \"newValue\"\n        let installationOnServer = [BatchResponseItem<Installation>(success: installation, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(installation)\n            installation = try installation.getDecoder().decode(Installation.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = [installation].saveAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            saved.forEach {\n                switch $0 {\n                case .success(let saved):\n                    XCTAssert(saved.hasSameObjectId(as: installation))\n                    XCTAssert(saved.hasSameInstallationId(as: installation))\n                    guard let savedUpdatedAt = saved.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    guard let originalUpdatedAt = installation.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n                    XCTAssertEqual(Installation.current?.customKey, installation.customKey)\n\n                    //Should be updated in memory\n                    guard let updatedCurrentDate = Installation.current?.updatedAt else {\n                        XCTFail(\"Should unwrap current date\")\n                        expectation1.fulfill()\n                        return\n                    }\n                    XCTAssertEqual(updatedCurrentDate, originalUpdatedAt)\n\n                    #if !os(Linux) && !os(Android) && !os(Windows)\n                    //Should be updated in Keychain\n                    guard let keychainInstallation: CurrentInstallationContainer<BaseParseInstallation>\n                        = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation),\n                        let keychainUpdatedCurrentDate = keychainInstallation.currentInstallation?.updatedAt else {\n                            XCTFail(\"Should get object from Keychain\")\n                            expectation1.fulfill()\n                        return\n                    }\n                    XCTAssertEqual(keychainUpdatedCurrentDate, originalUpdatedAt)\n                    #endif\n                case .failure(let error):\n                    XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                }\n            }\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testCreateAll() throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var installation = Installation()\n        installation.customKey = \"newValue\"\n        installation.installationId = \"123\"\n\n        var serverResponse = installation\n        serverResponse.objectId = \"yolo\"\n        serverResponse.createdAt = Date()\n        let installationOnServer = [BatchResponseItem<Installation>(success: serverResponse, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(serverResponse)\n            serverResponse = try installation.getDecoder().decode(Installation.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = [installation].createAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            saved.forEach {\n                switch $0 {\n                case .success(let saved):\n                    XCTAssertTrue(saved.hasSameObjectId(as: serverResponse))\n                    XCTAssertTrue(saved.hasSameInstallationId(as: serverResponse))\n                    guard let savedCreatedAt = saved.createdAt,\n                        let savedUpdatedAt = saved.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    guard let originalCreatedAt = serverResponse.createdAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n                    XCTAssertEqual(savedUpdatedAt, originalCreatedAt)\n\n                case .failure(let error):\n                    XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                }\n            }\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testReplaceAllCreate() throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var installation = Installation()\n        installation.objectId = \"yolo\"\n        installation.customKey = \"newValue\"\n        installation.installationId = \"123\"\n\n        var serverResponse = installation\n        serverResponse.createdAt = Date()\n        let installationOnServer = [BatchResponseItem<Installation>(success: serverResponse, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(serverResponse)\n            serverResponse = try installation.getDecoder().decode(Installation.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = [installation].replaceAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            saved.forEach {\n                switch $0 {\n                case .success(let saved):\n                    XCTAssertTrue(saved.hasSameObjectId(as: serverResponse))\n                    XCTAssertTrue(saved.hasSameInstallationId(as: serverResponse))\n                    XCTAssertEqual(saved.createdAt, serverResponse.createdAt)\n                    XCTAssertEqual(saved.updatedAt, serverResponse.createdAt)\n\n                case .failure(let error):\n                    XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                }\n            }\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testReplaceAllUpdate() throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var installation = Installation()\n        installation.objectId = \"yolo\"\n        installation.customKey = \"newValue\"\n        installation.installationId = \"123\"\n\n        var serverResponse = installation\n        serverResponse.updatedAt = Date()\n        let installationOnServer = [BatchResponseItem<Installation>(success: serverResponse, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(serverResponse)\n            serverResponse = try installation.getDecoder().decode(Installation.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = [installation].replaceAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            saved.forEach {\n                switch $0 {\n                case .success(let saved):\n                    XCTAssertTrue(saved.hasSameObjectId(as: serverResponse))\n                    XCTAssertTrue(saved.hasSameInstallationId(as: serverResponse))\n                    guard let savedUpdatedAt = saved.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    guard let originalUpdatedAt = serverResponse.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n\n                case .failure(let error):\n                    XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                }\n            }\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUpdateAll() throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var installation = Installation()\n        installation.objectId = \"yolo\"\n        installation.customKey = \"newValue\"\n        installation.installationId = \"123\"\n\n        var serverResponse = installation\n        serverResponse.updatedAt = Date()\n        let installationOnServer = [BatchResponseItem<Installation>(success: serverResponse, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(serverResponse)\n            serverResponse = try installation.getDecoder().decode(Installation.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = [installation].updateAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            saved.forEach {\n                switch $0 {\n                case .success(let saved):\n                    XCTAssertTrue(saved.hasSameObjectId(as: serverResponse))\n                    XCTAssertTrue(saved.hasSameInstallationId(as: serverResponse))\n                    guard let savedUpdatedAt = saved.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    guard let originalUpdatedAt = serverResponse.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n\n                case .failure(let error):\n                    XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                }\n            }\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDeleteAll() throws {\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        guard let installation = Installation.current else {\n                XCTFail(\"Should unwrap dates\")\n            expectation1.fulfill()\n                return\n        }\n\n        let installationOnServer = [BatchResponseItem<NoBody>(success: NoBody(), error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = [installation].deleteAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { deleted in\n            deleted.forEach {\n                if case let .failure(error) = $0 {\n                    XCTFail(\"Should have deleted: \\(error.localizedDescription)\")\n                }\n                if let newInstallation = Installation.current {\n                    XCTAssertFalse(installation.hasSameInstallationId(as: newInstallation))\n                }\n            }\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testBecome() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Become Installation\")\n\n        try saveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let installation = Installation.current,\n            let savedObjectId = installation.objectId else {\n                XCTFail(\"Should unwrap\")\n                return\n        }\n        XCTAssertEqual(savedObjectId, self.testInstallationObjectId)\n\n        var installationOnServer = installation\n        installationOnServer.createdAt = installation.updatedAt\n        installationOnServer.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n        installationOnServer.customKey = \"newValue\"\n        installationOnServer.installationId = \"wowsers\"\n        installationOnServer.channels = [\"yo\"]\n        installationOnServer.deviceToken = \"no\"\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            // Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self,\n                                                                                from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = Installation.becomePublisher(\"wowsers\")\n            .sink(receiveCompletion: { result in\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n            guard let currentInstallation = Installation.current else {\n                XCTFail(\"Should have current installation\")\n                expectation1.fulfill()\n                return\n            }\n            XCTAssertTrue(installationOnServer.hasSameObjectId(as: saved))\n            XCTAssertTrue(installationOnServer.hasSameInstallationId(as: saved))\n            XCTAssertTrue(installationOnServer.hasSameObjectId(as: currentInstallation))\n            XCTAssertTrue(installationOnServer.hasSameInstallationId(as: currentInstallation))\n            guard let savedCreatedAt = saved.createdAt else {\n                XCTFail(\"Should unwrap dates\")\n                expectation1.fulfill()\n                return\n            }\n            guard let originalCreatedAt = installationOnServer.createdAt else {\n                XCTFail(\"Should unwrap dates\")\n                expectation1.fulfill()\n                return\n            }\n            XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n            XCTAssertEqual(saved.channels, installationOnServer.channels)\n            XCTAssertEqual(saved.deviceToken, installationOnServer.deviceToken)\n\n            // Should be updated in memory\n            XCTAssertEqual(Installation.current?.installationId, \"wowsers\")\n            XCTAssertEqual(Installation.current?.customKey, installationOnServer.customKey)\n            XCTAssertEqual(Installation.current?.channels, installationOnServer.channels)\n            XCTAssertEqual(Installation.current?.deviceToken, installationOnServer.deviceToken)\n\n            #if !os(Linux) && !os(Android) && !os(Windows)\n            // Should be updated in Keychain\n            guard let keychainInstallation: CurrentInstallationContainer<BaseParseInstallation>\n                = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) else {\n                    XCTFail(\"Should get object from Keychain\")\n                expectation1.fulfill()\n                return\n            }\n            XCTAssertEqual(keychainInstallation.currentInstallation?.installationId, \"wowsers\")\n            XCTAssertEqual(keychainInstallation.currentInstallation?.channels, installationOnServer.channels)\n            XCTAssertEqual(keychainInstallation.currentInstallation?.deviceToken, installationOnServer.deviceToken)\n            #endif\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testBecomeMissingObjectId() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Become Installation\")\n        try ParseStorage.shared.delete(valueFor: ParseStorage.Keys.currentInstallation)\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.delete(valueFor: ParseStorage.Keys.currentInstallation)\n        #endif\n        Installation.currentContainer.currentInstallation = nil\n\n        let publisher = Installation.becomePublisher(\"wowsers\")\n            .sink(receiveCompletion: { result in\n                if case let .failure(error) = result {\n                    XCTAssertTrue(error.message.contains(\"does not exist\"))\n                } else {\n                    XCTFail(\"Should have error\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown error\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseInstallationTests.swift",
    "content": "//\n//  ParseInstallationTests.swift\n//  ParseSwiftTests\n//\n//  Created by Corey Baker on 9/7/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseInstallationTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    struct Installation: ParseInstallation {\n        var installationId: String?\n        var deviceType: String?\n        var deviceToken: String?\n        var badge: Int?\n        var timeZone: String?\n        var channels: [String]?\n        var appName: String?\n        var appIdentifier: String?\n        var appVersion: String?\n        var parseVersion: String?\n        var localeIdentifier: String?\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n        var customKey: String?\n\n        //: Implement your own version of merge\n        func merge(with object: Self) throws -> Self {\n            var updated = try mergeParse(with: object)\n            if updated.shouldRestoreKey(\\.customKey,\n                                         original: object) {\n                updated.customKey = object.customKey\n            }\n            return updated\n        }\n    }\n\n    struct InstallationDefaultMerge: ParseInstallation {\n        var installationId: String?\n        var deviceType: String?\n        var deviceToken: String?\n        var badge: Int?\n        var timeZone: String?\n        var channels: [String]?\n        var appName: String?\n        var appIdentifier: String?\n        var appVersion: String?\n        var parseVersion: String?\n        var localeIdentifier: String?\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n        var customKey: String?\n    }\n\n    let testInstallationObjectId = \"yarr\"\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n        try userLogin()\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func userLogin() throws {\n        let loginResponse = LoginSignupResponse()\n        let loginUserName = \"hello10\"\n        let loginPassword = \"world\"\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        _ = try User.login(username: loginUserName, password: loginPassword)\n        MockURLProtocol.removeAll()\n    }\n\n    func testNewInstallationIdentifierIsLowercase() {\n        guard let installationIdFromContainer\n            = Installation.currentContainer.installationId else {\n            XCTFail(\"Should have retreived installationId from container\")\n            return\n        }\n\n        XCTAssertEqual(installationIdFromContainer, installationIdFromContainer.lowercased())\n\n        guard let installationIdFromCurrent = Installation.current?.installationId else {\n            XCTFail(\"Should have retreived installationId from container\")\n            return\n        }\n\n        XCTAssertEqual(installationIdFromCurrent, installationIdFromCurrent.lowercased())\n        XCTAssertEqual(installationIdFromContainer, installationIdFromCurrent)\n    }\n\n    func testDeviceTokenAsString() throws {\n        let data = Data([0, 1, 127, 128, 255])\n        XCTAssertEqual(data.hexEncodedString(), \"00017f80ff\")\n        XCTAssertEqual(data.hexEncodedString(options: .upperCase), \"00017F80FF\")\n    }\n\n    func testInstallationMutableValuesCanBeChangedInMemory() {\n        guard let originalInstallation = Installation.current else {\n            XCTFail(\"All of these Installation values should have unwraped\")\n            return\n        }\n\n        Installation.current?.customKey = \"Changed\"\n        Installation.current?.setDeviceToken(Data([0, 1, 127, 128, 255]))\n        XCTAssertNotEqual(originalInstallation.customKey, Installation.current?.customKey)\n        XCTAssertNotEqual(originalInstallation.deviceToken, Installation.current?.customKey)\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testInstallationImmutableFieldsCannotBeChangedInMemory() {\n        guard let originalInstallation = Installation.current,\n            let originalInstallationId = originalInstallation.installationId,\n            let originalDeviceType = originalInstallation.deviceType,\n            let originalTimeZone = originalInstallation.timeZone,\n            let originalAppName = originalInstallation.appName,\n            let originalAppIdentifier = originalInstallation.appIdentifier,\n            let originalAppVersion = originalInstallation.appVersion,\n            let originalParseVersion = originalInstallation.parseVersion,\n            let originalLocaleIdentifier = originalInstallation.localeIdentifier\n            else {\n                XCTFail(\"All of these Installation values should have unwraped\")\n            return\n        }\n\n        Installation.current?.installationId = \"changed\"\n        Installation.current?.deviceType = \"changed\"\n        Installation.current?.badge = 500\n        Installation.current?.timeZone = \"changed\"\n        Installation.current?.appName = \"changed\"\n        Installation.current?.appIdentifier = \"changed\"\n        Installation.current?.appVersion = \"changed\"\n        Installation.current?.parseVersion = \"changed\"\n        Installation.current?.localeIdentifier = \"changed\"\n\n        XCTAssertEqual(originalInstallationId, Installation.current?.installationId)\n        XCTAssertEqual(originalDeviceType, Installation.current?.deviceType)\n        XCTAssertEqual(500, Installation.current?.badge)\n        XCTAssertEqual(originalTimeZone, Installation.current?.timeZone)\n        XCTAssertEqual(originalAppName, Installation.current?.appName)\n        XCTAssertEqual(originalAppIdentifier, Installation.current?.appIdentifier)\n        XCTAssertEqual(originalAppVersion, Installation.current?.appVersion)\n        XCTAssertEqual(originalParseVersion, Installation.current?.parseVersion)\n        XCTAssertEqual(originalLocaleIdentifier, Installation.current?.localeIdentifier)\n    }\n\n    func testInstallationCustomValuesSavedToKeychain() {\n        let customField = \"Changed\"\n        Installation.current?.customKey = customField\n        Installation.saveCurrentContainerToKeychain()\n        guard let keychainInstallation: CurrentInstallationContainer<Installation>\n            = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) else {\n            return\n        }\n        XCTAssertEqual(keychainInstallation.currentInstallation?.customKey, customField)\n    }\n\n    // swiftlint:disable:next function_body_length\n    func testInstallationImmutableFieldsCannotBeChangedInKeychain() {\n        guard let originalInstallation = Installation.current,\n            let originalInstallationId = originalInstallation.installationId,\n            let originalDeviceType = originalInstallation.deviceType,\n            let originalTimeZone = originalInstallation.timeZone,\n            let originalAppName = originalInstallation.appName,\n            let originalAppIdentifier = originalInstallation.appIdentifier,\n            let originalAppVersion = originalInstallation.appVersion,\n            let originalParseVersion = originalInstallation.parseVersion,\n            let originalLocaleIdentifier = originalInstallation.localeIdentifier\n            else {\n                XCTFail(\"All of these Installation values should have unwraped\")\n            return\n        }\n\n        Installation.current?.installationId = \"changed\"\n        Installation.current?.deviceType = \"changed\"\n        Installation.current?.badge = 500\n        Installation.current?.timeZone = \"changed\"\n        Installation.current?.appName = \"changed\"\n        Installation.current?.appIdentifier = \"changed\"\n        Installation.current?.appVersion = \"changed\"\n        Installation.current?.parseVersion = \"changed\"\n        Installation.current?.localeIdentifier = \"changed\"\n\n        Installation.saveCurrentContainerToKeychain()\n\n        guard let keychainInstallation: CurrentInstallationContainer<Installation>\n            = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertEqual(originalInstallationId, keychainInstallation.currentInstallation?.installationId)\n        XCTAssertEqual(originalDeviceType, keychainInstallation.currentInstallation?.deviceType)\n        XCTAssertEqual(500, keychainInstallation.currentInstallation?.badge)\n        XCTAssertEqual(originalTimeZone, keychainInstallation.currentInstallation?.timeZone)\n        XCTAssertEqual(originalAppName, keychainInstallation.currentInstallation?.appName)\n        XCTAssertEqual(originalAppIdentifier, keychainInstallation.currentInstallation?.appIdentifier)\n        XCTAssertEqual(originalAppVersion, keychainInstallation.currentInstallation?.appVersion)\n        XCTAssertEqual(originalParseVersion, keychainInstallation.currentInstallation?.parseVersion)\n        XCTAssertEqual(originalLocaleIdentifier, keychainInstallation.currentInstallation?.localeIdentifier)\n    }\n    #endif\n\n    func testMerge() throws {\n        guard var original = Installation.current else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        original.objectId = \"yolo\"\n        original.createdAt = Date()\n        original.updatedAt = Date()\n        original.badge = 10\n        var acl = ParseACL()\n        acl.publicRead = true\n        original.ACL = acl\n\n        var updated = original.mergeable\n        updated.updatedAt = Calendar.current.date(byAdding: .init(day: 1), to: Date())\n        updated.badge = 1\n        updated.deviceToken = \"12345\"\n        updated.customKey = \"newKey\"\n        let merged = try updated.merge(with: original)\n        XCTAssertEqual(merged.customKey, updated.customKey)\n        XCTAssertEqual(merged.badge, updated.badge)\n        XCTAssertEqual(merged.deviceType, original.deviceType)\n        XCTAssertEqual(merged.deviceToken, updated.deviceToken)\n        XCTAssertEqual(merged.channels, original.channels)\n        XCTAssertEqual(merged.installationId, original.installationId)\n        XCTAssertEqual(merged.timeZone, original.timeZone)\n        XCTAssertEqual(merged.appName, original.appName)\n        XCTAssertEqual(merged.appVersion, original.appVersion)\n        XCTAssertEqual(merged.appIdentifier, original.appIdentifier)\n        XCTAssertEqual(merged.parseVersion, original.parseVersion)\n        XCTAssertEqual(merged.localeIdentifier, original.localeIdentifier)\n        XCTAssertEqual(merged.ACL, original.ACL)\n        XCTAssertEqual(merged.createdAt, original.createdAt)\n        XCTAssertEqual(merged.updatedAt, updated.updatedAt)\n    }\n\n    func testMerge2() throws {\n        guard var original = Installation.current else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        original.objectId = \"yolo\"\n        original.createdAt = Date()\n        original.updatedAt = Date()\n        original.badge = 10\n        original.deviceToken = \"bruh\"\n        original.channels = [\"halo\"]\n        var acl = ParseACL()\n        acl.publicRead = true\n        original.ACL = acl\n\n        var updated = original.mergeable\n        updated.updatedAt = Calendar.current.date(byAdding: .init(day: 1), to: Date())\n        updated.customKey = \"newKey\"\n        let merged = try updated.merge(with: original)\n        XCTAssertEqual(merged.customKey, updated.customKey)\n        XCTAssertEqual(merged.badge, original.badge)\n        XCTAssertEqual(merged.deviceType, original.deviceType)\n        XCTAssertEqual(merged.deviceToken, original.deviceToken)\n        XCTAssertEqual(merged.channels, original.channels)\n        XCTAssertEqual(merged.installationId, original.installationId)\n        XCTAssertEqual(merged.timeZone, original.timeZone)\n        XCTAssertEqual(merged.appName, original.appName)\n        XCTAssertEqual(merged.appVersion, original.appVersion)\n        XCTAssertEqual(merged.appIdentifier, original.appIdentifier)\n        XCTAssertEqual(merged.parseVersion, original.parseVersion)\n        XCTAssertEqual(merged.localeIdentifier, original.localeIdentifier)\n        XCTAssertEqual(merged.ACL, original.ACL)\n        XCTAssertEqual(merged.createdAt, original.createdAt)\n        XCTAssertEqual(merged.updatedAt, updated.updatedAt)\n    }\n\n    func testMergeDefaultImplementation() throws {\n        guard let currentInstallation = Installation.current else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        var original = InstallationDefaultMerge()\n        original.installationId = currentInstallation.installationId\n        original.objectId = \"yolo\"\n        original.createdAt = Date()\n        original.updatedAt = Date()\n        original.badge = 10\n        original.deviceToken = \"bruh\"\n        original.channels = [\"halo\"]\n        var acl = ParseACL()\n        acl.publicRead = true\n        original.ACL = acl\n\n        var updated = original.set(\\.customKey, to: \"newKey\")\n        updated.updatedAt = Calendar.current.date(byAdding: .init(day: 1), to: Date())\n        original.updatedAt = updated.updatedAt\n        original.customKey = updated.customKey\n        var merged = try updated.merge(with: original)\n        merged.originalData = nil\n        // Get dates in correct format from ParseDecoding strategy\n        let encoded = try ParseCoding.jsonEncoder().encode(original)\n        original = try ParseCoding.jsonDecoder().decode(InstallationDefaultMerge.self, from: encoded)\n        XCTAssertEqual(merged, original)\n    }\n\n    func testMergeDifferentObjectId() throws {\n        var installation = Installation()\n        installation.objectId = \"yolo\"\n        var installation2 = installation\n        installation2.objectId = \"nolo\"\n        XCTAssertThrowsError(try installation2.merge(with: installation))\n    }\n\n    func testUpdate() {\n        var installation = Installation()\n        installation.objectId = testInstallationObjectId\n        installation.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        installation.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        installation.ACL = nil\n        installation.installationId = \"hello\"\n\n        var installationOnServer = installation\n        installationOnServer.createdAt = nil\n        installationOnServer.updatedAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try installationOnServer.getEncoder().encode(installationOnServer, skipKeys: .none)\n            // Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            let saved = try installation.save()\n            XCTAssertTrue(saved.hasSameObjectId(as: installationOnServer))\n            XCTAssertTrue(saved.hasSameInstallationId(as: installationOnServer))\n            guard let savedUpdatedAt = saved.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n            }\n            guard let serverUpdatedAt = installationOnServer.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n            }\n            XCTAssertEqual(savedUpdatedAt, serverUpdatedAt)\n            XCTAssertNil(saved.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testUpdateWithDefaultACL() throws {\n        try userLogin()\n        _ = try ParseACL.setDefaultACL(ParseACL(),\n                                       withAccessForCurrentUser: true)\n\n        var installation = Installation()\n        installation.objectId = testInstallationObjectId\n        installation.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        installation.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        installation.ACL = nil\n        installation.installationId = \"hello\"\n\n        var installationOnServer = installation\n        installationOnServer.createdAt = nil\n        installationOnServer.updatedAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try installationOnServer.getEncoder().encode(installationOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            let saved = try installation.save()\n            XCTAssertTrue(saved.hasSameObjectId(as: installationOnServer))\n            XCTAssertTrue(saved.hasSameInstallationId(as: installationOnServer))\n            guard let savedUpdatedAt = saved.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n            }\n            guard let serverUpdatedAt = installationOnServer.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n            }\n            XCTAssertEqual(savedUpdatedAt, serverUpdatedAt)\n            XCTAssertNil(saved.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testSaveCurrentInstallation() throws {\n        guard var installation = Installation.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n        installation.objectId = testInstallationObjectId\n        installation.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        installation.ACL = nil\n\n        var installationOnServer = installation\n\n        let encoded: Data!\n        do {\n            encoded = try installationOnServer.getEncoder().encode(installationOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            guard let saved = try Installation.current?.save(),\n                let newCurrentInstallation = Installation.current else {\n                XCTFail(\"Should have a new current installation\")\n                return\n            }\n            XCTAssertTrue(saved.hasSameInstallationId(as: newCurrentInstallation))\n            XCTAssertTrue(saved.hasSameObjectId(as: newCurrentInstallation))\n            XCTAssertTrue(saved.hasSameObjectId(as: installationOnServer))\n            XCTAssertTrue(saved.hasSameInstallationId(as: installationOnServer))\n            XCTAssertNil(saved.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testSaveMutableMergeCurrentInstallation() throws {\n        // Save current Installation\n        try testSaveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let original = Installation.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n        var response = original.mergeable\n        response.createdAt = nil\n        response.updatedAt = Calendar.current.date(byAdding: .init(day: 1), to: Date())\n\n        let encoded: Data!\n        do {\n            encoded = try response.getEncoder().encode(response, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            response = try response.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        var updated = original.mergeable\n        updated.customKey = \"hello\"\n        updated.deviceToken = \"1234\"\n\n        do {\n            let saved = try updated.save()\n            let expectation1 = XCTestExpectation(description: \"Update installation1\")\n            DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n                guard let newCurrentInstallation = Installation.current else {\n                    XCTFail(\"Should have a new current installation\")\n                    expectation1.fulfill()\n                    return\n                }\n                XCTAssertTrue(saved.hasSameInstallationId(as: newCurrentInstallation))\n                XCTAssertTrue(saved.hasSameObjectId(as: newCurrentInstallation))\n                XCTAssertTrue(saved.hasSameObjectId(as: response))\n                XCTAssertEqual(saved.customKey, updated.customKey)\n                XCTAssertEqual(saved.badge, original.badge)\n                XCTAssertEqual(saved.deviceType, original.deviceType)\n                XCTAssertEqual(saved.deviceToken, updated.deviceToken)\n                XCTAssertEqual(saved.channels, original.channels)\n                XCTAssertEqual(saved.installationId, original.installationId)\n                XCTAssertEqual(saved.timeZone, original.timeZone)\n                XCTAssertEqual(saved.appName, original.appName)\n                XCTAssertEqual(saved.appVersion, original.appVersion)\n                XCTAssertEqual(saved.appIdentifier, original.appIdentifier)\n                XCTAssertEqual(saved.parseVersion, original.parseVersion)\n                XCTAssertEqual(saved.localeIdentifier, original.localeIdentifier)\n                XCTAssertEqual(saved.createdAt, original.createdAt)\n                XCTAssertEqual(saved.updatedAt, response.updatedAt)\n                XCTAssertNil(saved.originalData)\n                XCTAssertEqual(saved.customKey, newCurrentInstallation.customKey)\n                XCTAssertEqual(saved.badge, newCurrentInstallation.badge)\n                XCTAssertEqual(saved.deviceType, newCurrentInstallation.deviceType)\n                XCTAssertEqual(saved.deviceToken, newCurrentInstallation.deviceToken)\n                XCTAssertEqual(saved.channels, newCurrentInstallation.channels)\n                XCTAssertEqual(saved.installationId, newCurrentInstallation.installationId)\n                XCTAssertEqual(saved.timeZone, newCurrentInstallation.timeZone)\n                XCTAssertEqual(saved.appName, newCurrentInstallation.appName)\n                XCTAssertEqual(saved.appVersion, newCurrentInstallation.appVersion)\n                XCTAssertEqual(saved.appIdentifier, newCurrentInstallation.appIdentifier)\n                XCTAssertEqual(saved.parseVersion, newCurrentInstallation.parseVersion)\n                XCTAssertEqual(saved.localeIdentifier, newCurrentInstallation.localeIdentifier)\n                XCTAssertEqual(saved.createdAt, newCurrentInstallation.createdAt)\n                XCTAssertEqual(saved.updatedAt, newCurrentInstallation.updatedAt)\n                expectation1.fulfill()\n            }\n            wait(for: [expectation1], timeout: 20.0)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testSaveCurrentInstallationWithDefaultACL() throws {\n        try userLogin()\n        guard let userObjectId = User.current?.objectId else {\n            XCTFail(\"Should have objectId\")\n            return\n        }\n        let defaultACL = try ParseACL.setDefaultACL(ParseACL(),\n                                                    withAccessForCurrentUser: true)\n\n        guard var installation = Installation.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n        installation.objectId = testInstallationObjectId\n        installation.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        installation.ACL = nil\n\n        var installationOnServer = installation\n\n        let encoded: Data!\n        do {\n            encoded = try installationOnServer.getEncoder().encode(installationOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            guard let saved = try Installation.current?.save(),\n                let newCurrentInstallation = Installation.current else {\n                XCTFail(\"Should have a new current installation\")\n                return\n            }\n            XCTAssertTrue(saved.hasSameInstallationId(as: newCurrentInstallation))\n            XCTAssertTrue(saved.hasSameObjectId(as: newCurrentInstallation))\n            XCTAssertTrue(saved.hasSameObjectId(as: installationOnServer))\n            XCTAssertTrue(saved.hasSameInstallationId(as: installationOnServer))\n            XCTAssertNotNil(saved.ACL)\n            XCTAssertEqual(saved.ACL?.publicRead, defaultACL.publicRead)\n            XCTAssertEqual(saved.ACL?.publicWrite, defaultACL.publicWrite)\n            XCTAssertTrue(defaultACL.getReadAccess(objectId: userObjectId))\n            XCTAssertTrue(defaultACL.getWriteAccess(objectId: userObjectId))\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    // swiftlint:disable:next function_body_length\n    func updateAsync(installation: Installation, installationOnServer: Installation, callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Update installation1\")\n        installation.save(options: [], callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let saved):\n                guard let savedUpdatedAt = saved.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    expectation1.fulfill()\n                    return\n                }\n                guard let originalUpdatedAt = installation.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    expectation1.fulfill()\n                    return\n                }\n                XCTAssertTrue(saved.hasSameObjectId(as: installation))\n                XCTAssertTrue(saved.hasSameInstallationId(as: installation))\n                XCTAssertGreaterThan(savedUpdatedAt, originalUpdatedAt)\n                XCTAssertNil(saved.ACL)\n                expectation1.fulfill()\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n                expectation1.fulfill()\n            }\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUpdateAsyncMainQueue() {\n        var installation = Installation()\n        installation.objectId = testInstallationObjectId\n        installation.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        installation.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        installation.ACL = nil\n        installation.installationId = \"hello\"\n\n        var installationOnServer = installation\n        installationOnServer.createdAt = nil\n        installationOnServer.updatedAt = Date()\n        let encoded: Data!\n        do {\n            let encodedOriginal = try ParseCoding.jsonEncoder().encode(installation)\n            //Get dates in correct format from ParseDecoding strategy\n            installation = try installation.getDecoder().decode(Installation.self, from: encodedOriginal)\n\n            encoded = try installationOnServer.getEncoder().encode(installationOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        self.updateAsync(installation: installation, installationOnServer: installationOnServer, callbackQueue: .main)\n    }\n\n    // swiftlint:disable:next function_body_length\n    func saveCurrentAsync(installation: Installation,\n                          installationOnServer: Installation,\n                          callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Update installation1\")\n        installation.save(options: [], callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let saved):\n                guard let currentInstallation = Installation.current else {\n                    XCTFail(\"Should have current\")\n                    expectation1.fulfill()\n                    return\n                }\n                XCTAssertTrue(saved.hasSameObjectId(as: currentInstallation))\n                XCTAssertTrue(saved.hasSameInstallationId(as: currentInstallation))\n                XCTAssertTrue(saved.hasSameObjectId(as: installationOnServer))\n                XCTAssertTrue(saved.hasSameInstallationId(as: installationOnServer))\n                guard let savedUpdatedAt = saved.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    expectation1.fulfill()\n                    return\n                }\n                guard let serverUpdatedAt = installationOnServer.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    expectation1.fulfill()\n                    return\n                }\n                XCTAssertEqual(savedUpdatedAt, serverUpdatedAt)\n                XCTAssertNil(saved.ACL)\n                XCTAssertNil(currentInstallation.ACL)\n                expectation1.fulfill()\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n                expectation1.fulfill()\n            }\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSaveCurrentAsyncMainQueue() {\n        guard var installation = Installation.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n        installation.objectId = testInstallationObjectId\n        installation.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        installation.ACL = nil\n\n        var installationOnServer = installation\n\n        let encoded: Data!\n        do {\n            let encodedOriginal = try ParseCoding.jsonEncoder().encode(installation)\n            //Get dates in correct format from ParseDecoding strategy\n            installation = try installation.getDecoder().decode(Installation.self, from: encodedOriginal)\n\n            encoded = try installationOnServer.getEncoder().encode(installationOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        self.saveCurrentAsync(installation: installation,\n                                installationOnServer: installationOnServer,\n                                callbackQueue: .main)\n    }\n\n    func testFetchCommand() {\n        var installation = Installation()\n        XCTAssertThrowsError(try installation.fetchCommand(include: nil))\n        let objectId = \"yarr\"\n        installation.objectId = objectId\n        do {\n            let command = try installation.fetchCommand(include: nil)\n            XCTAssertNotNil(command)\n            XCTAssertEqual(command.path.urlComponent, \"/installations/\\(objectId)\")\n            XCTAssertEqual(command.method, API.Method.GET)\n            XCTAssertNil(command.params)\n            XCTAssertNil(command.body)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        let installation2 = Installation()\n        XCTAssertThrowsError(try installation2.fetchCommand(include: nil))\n    }\n\n    func testFetchIncludeCommand() {\n        var installation = Installation()\n        let objectId = \"yarr\"\n        installation.objectId = objectId\n        let includeExpected = [\"include\": \"[\\\"yolo\\\", \\\"test\\\"]\"]\n        do {\n            let command = try installation.fetchCommand(include: [\"yolo\", \"test\"])\n            XCTAssertNotNil(command)\n            XCTAssertEqual(command.path.urlComponent, \"/installations/\\(objectId)\")\n            XCTAssertEqual(command.method, API.Method.GET)\n            XCTAssertEqual(command.params?.keys.first, includeExpected.keys.first)\n            if let value = command.params?.values.first,\n                let includeValue = value {\n                XCTAssertTrue(includeValue.contains(\"\\\"yolo\\\"\"))\n            } else {\n                XCTFail(\"Should have unwrapped value\")\n            }\n            XCTAssertNil(command.body)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        let installation2 = Installation()\n        XCTAssertThrowsError(try installation2.fetchCommand(include: nil))\n    }\n\n    func testFetchUpdatedCurrentInstallation() throws { // swiftlint:disable:this function_body_length\n        try testSaveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let installation = Installation.current,\n            let savedObjectId = installation.objectId else {\n                XCTFail(\"Should unwrap\")\n                return\n        }\n        XCTAssertEqual(savedObjectId, self.testInstallationObjectId)\n\n        var installationOnServer = installation\n        installationOnServer.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n        installationOnServer.customKey = \"newValue\"\n\n        let encoded: Data!\n        do {\n            encoded = try installationOnServer.getEncoder().encode(installationOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            let fetched = try installation.fetch()\n            guard let currentInstallation = Installation.current else {\n                XCTFail(\"Should have current installation\")\n                return\n            }\n            XCTAssertTrue(fetched.hasSameObjectId(as: currentInstallation))\n            XCTAssertTrue(fetched.hasSameInstallationId(as: currentInstallation))\n            XCTAssertTrue(fetched.hasSameObjectId(as: installationOnServer))\n            XCTAssertTrue(fetched.hasSameInstallationId(as: installationOnServer))\n            guard let fetchedCreatedAt = fetched.createdAt,\n                let fetchedUpdatedAt = fetched.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalCreatedAt = installationOnServer.createdAt,\n                let originalUpdatedAt = installation.updatedAt,\n                let serverUpdatedAt = installationOnServer.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n            XCTAssertGreaterThan(fetchedUpdatedAt, originalUpdatedAt)\n            XCTAssertEqual(fetchedUpdatedAt, serverUpdatedAt)\n            XCTAssertEqual(Installation.current?.customKey, installationOnServer.customKey)\n\n            //Should be updated in memory\n            guard let updatedCurrentDate = Installation.current?.updatedAt else {\n                XCTFail(\"Should unwrap current date\")\n                return\n            }\n            XCTAssertEqual(updatedCurrentDate, serverUpdatedAt)\n\n            //Should be updated in Keychain\n            #if !os(Linux) && !os(Android) && !os(Windows)\n            guard let keychainInstallation: CurrentInstallationContainer<BaseParseInstallation>\n                = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation),\n                let keychainUpdatedCurrentDate = keychainInstallation.currentInstallation?.updatedAt else {\n                    XCTFail(\"Should get object from Keychain\")\n                return\n            }\n            XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt)\n            #endif\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testFetchUpdatedCurrentInstallationAsync() throws { // swiftlint:disable:this function_body_length\n        try testSaveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        let expectation1 = XCTestExpectation(description: \"Update installation1\")\n\n        guard let installation = Installation.current else {\n            XCTFail(\"Should unwrap\")\n            expectation1.fulfill()\n            return\n        }\n\n        var installationOnServer = installation\n        installationOnServer.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n        installationOnServer.customKey = \"newValue\"\n\n        let encoded: Data!\n        do {\n            encoded = try installationOnServer.getEncoder().encode(installationOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        installation.fetch(options: [], callbackQueue: .main) { result in\n\n            switch result {\n            case .success(let fetched):\n                guard let currentInstallation = Installation.current else {\n                    XCTFail(\"Should have current installation\")\n                    return\n                }\n                XCTAssertTrue(fetched.hasSameObjectId(as: currentInstallation))\n                XCTAssertTrue(fetched.hasSameInstallationId(as: currentInstallation))\n                XCTAssertTrue(fetched.hasSameObjectId(as: installationOnServer))\n                XCTAssertTrue(fetched.hasSameInstallationId(as: installationOnServer))\n                guard let fetchedCreatedAt = fetched.createdAt,\n                    let fetchedUpdatedAt = fetched.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation1.fulfill()\n                        return\n                }\n                guard let originalCreatedAt = installationOnServer.createdAt,\n                    let originalUpdatedAt = installation.updatedAt,\n                    let serverUpdatedAt = installationOnServer.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation1.fulfill()\n                        return\n                }\n                XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n                XCTAssertGreaterThan(fetchedUpdatedAt, originalUpdatedAt)\n                XCTAssertEqual(fetchedUpdatedAt, serverUpdatedAt)\n                XCTAssertEqual(Installation.current?.customKey, installationOnServer.customKey)\n\n                //Should be updated in memory\n                guard let updatedCurrentDate = Installation.current?.updatedAt else {\n                    XCTFail(\"Should unwrap current date\")\n                    expectation1.fulfill()\n                    return\n                }\n                XCTAssertEqual(updatedCurrentDate, serverUpdatedAt)\n\n                #if !os(Linux) && !os(Android) && !os(Windows)\n                //Should be updated in Keychain\n                guard let keychainInstallation: CurrentInstallationContainer<BaseParseInstallation>\n                    = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation),\n                    let keychainUpdatedCurrentDate = keychainInstallation.currentInstallation?.updatedAt else {\n                        XCTFail(\"Should get object from Keychain\")\n                        expectation1.fulfill()\n                    return\n                }\n                XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt)\n                #endif\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDeleteCommand() {\n        var installation = Installation()\n        let objectId = \"yarr\"\n        installation.objectId = objectId\n        do {\n            let command = try installation.deleteCommand()\n            XCTAssertNotNil(command)\n            XCTAssertEqual(command.path.urlComponent, \"/installations/\\(objectId)\")\n            XCTAssertEqual(command.method, API.Method.DELETE)\n            XCTAssertNil(command.body)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        let installation2 = Installation()\n        XCTAssertThrowsError(try installation2.deleteCommand())\n    }\n\n    func testDeleteCurrent() throws {\n        try testSaveCurrentInstallation()\n\n        guard let installation = Installation.current else {\n            XCTFail(\"Should unwrap dates\")\n            return\n        }\n\n        do {\n            try installation.delete(options: [])\n            if let newInstallation = Installation.current {\n                XCTAssertFalse(installation.hasSameInstallationId(as: newInstallation))\n            }\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        do {\n            try installation.delete(options: [.useMasterKey])\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testDeleteCurrentAsyncMainQueue() throws {\n        try testSaveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        let expectation1 = XCTestExpectation(description: \"Delete installation1\")\n        guard let installation = Installation.current else {\n            XCTFail(\"Should unwrap\")\n            expectation1.fulfill()\n            return\n        }\n\n        var installationOnServer = installation\n        installationOnServer.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n\n        let encoded: Data!\n        do {\n            encoded = try installationOnServer.getEncoder().encode(installationOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        installation.delete { result in\n            if case let .failure(error) = result {\n                XCTFail(error.localizedDescription)\n            }\n            if let newInstallation = Installation.current {\n                XCTAssertFalse(installation.hasSameInstallationId(as: newInstallation))\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    // swiftlint:disable:next function_body_length\n    func testFetchAllCurrent() throws {\n        try testSaveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard var installation = Installation.current else {\n            XCTFail(\"Should unwrap dates\")\n            return\n        }\n\n        installation.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n        installation.customKey = \"newValue\"\n        let installationOnServer = QueryResponse<Installation>(results: [installation], count: 1)\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(installation)\n            installation = try installation.getDecoder().decode(Installation.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            let fetched = try [installation].fetchAll()\n            fetched.forEach {\n                switch $0 {\n                case .success(let fetched):\n                    guard let currentInstallation = Installation.current else {\n                        XCTFail(\"Should have current installation\")\n                        return\n                    }\n                    XCTAssertTrue(fetched.hasSameObjectId(as: currentInstallation))\n                    XCTAssertTrue(fetched.hasSameInstallationId(as: currentInstallation))\n                    guard let fetchedCreatedAt = fetched.createdAt,\n                        let fetchedUpdatedAt = fetched.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            return\n                    }\n                    guard let originalCreatedAt = installation.createdAt,\n                        let originalUpdatedAt = installation.updatedAt,\n                        let serverUpdatedAt = installation.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            return\n                    }\n                    XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n                    XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n                    XCTAssertEqual(fetchedUpdatedAt, serverUpdatedAt)\n                    XCTAssertEqual(Installation.current?.customKey, installation.customKey)\n\n                    //Should be updated in memory\n                    guard let updatedCurrentDate = Installation.current?.updatedAt else {\n                        XCTFail(\"Should unwrap current date\")\n                        return\n                    }\n                    XCTAssertEqual(updatedCurrentDate, serverUpdatedAt)\n\n                    #if !os(Linux) && !os(Android) && !os(Windows)\n                    //Should be updated in Keychain\n                    guard let keychainInstallation: CurrentInstallationContainer<BaseParseInstallation>\n                        = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation),\n                        let keychainUpdatedCurrentDate = keychainInstallation.currentInstallation?.updatedAt else {\n                            XCTFail(\"Should get object from Keychain\")\n                        return\n                    }\n                    XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt)\n                    #endif\n                case .failure(let error):\n                    XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                }\n            }\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    // swiftlint:disable:next function_body_length\n    func testFetchAllAsyncMainQueueCurrent() throws {\n        try testSaveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        let expectation1 = XCTestExpectation(description: \"Fetch installation1\")\n        guard var installation = Installation.current else {\n            XCTFail(\"Should unwrap\")\n            expectation1.fulfill()\n            return\n        }\n\n        installation.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n        installation.customKey = \"newValue\"\n        let installationOnServer = QueryResponse<Installation>(results: [installation], count: 1)\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(installation)\n            installation = try installation.getDecoder().decode(Installation.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        [installation].fetchAll { results in\n            switch results {\n\n            case .success(let fetched):\n                fetched.forEach {\n                    switch $0 {\n                    case .success(let fetched):\n                        guard let currentInstallation = Installation.current else {\n                            XCTFail(\"Should have current installation\")\n                            return\n                        }\n                        XCTAssertTrue(fetched.hasSameObjectId(as: currentInstallation))\n                        XCTAssertTrue(fetched.hasSameInstallationId(as: currentInstallation))\n                        guard let fetchedCreatedAt = fetched.createdAt,\n                            let fetchedUpdatedAt = fetched.updatedAt else {\n                                XCTFail(\"Should unwrap dates\")\n                                expectation1.fulfill()\n                                return\n                        }\n                        guard let originalCreatedAt = installation.createdAt,\n                            let originalUpdatedAt = installation.updatedAt,\n                            let serverUpdatedAt = installation.updatedAt else {\n                                XCTFail(\"Should unwrap dates\")\n                                expectation1.fulfill()\n                                return\n                        }\n                        XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n                        XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n                        XCTAssertEqual(fetchedUpdatedAt, serverUpdatedAt)\n                        XCTAssertEqual(Installation.current?.customKey, installation.customKey)\n\n                        //Should be updated in memory\n                        guard let updatedCurrentDate = Installation.current?.updatedAt else {\n                            XCTFail(\"Should unwrap current date\")\n                            expectation1.fulfill()\n                            return\n                        }\n                        XCTAssertEqual(updatedCurrentDate, serverUpdatedAt)\n\n                        #if !os(Linux) && !os(Android) && !os(Windows)\n                        //Should be updated in Keychain\n                        guard let keychainInstallation: CurrentInstallationContainer<BaseParseInstallation>\n                            = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation),\n                            let keychainUpdatedCurrentDate = keychainInstallation\n                                .currentInstallation?.updatedAt else {\n                                XCTFail(\"Should get object from Keychain\")\n                                expectation1.fulfill()\n                            return\n                        }\n                        XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt)\n                        #endif\n                    case .failure(let error):\n                        XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                    }\n                }\n            case .failure(let error):\n                XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSaveCommand() throws {\n        let installation = Installation()\n        let command = try installation.saveCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/installations\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertNil(command.params)\n        XCTAssertNotNil(command.body)\n    }\n\n    func testSaveUpdateCommand() throws {\n        var installation = Installation()\n        let objectId = \"yarr\"\n        installation.objectId = objectId\n\n        let command = try installation.saveCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/installations/\\(objectId)\")\n        XCTAssertEqual(command.method, API.Method.PUT)\n        XCTAssertNil(command.params)\n        XCTAssertNotNil(command.body)\n    }\n\n    func testCreateCommand() throws {\n        let installation = Installation()\n\n        let command = installation.createCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/installations\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertNil(command.params)\n        XCTAssertNotNil(command.body)\n    }\n\n    func testReplaceCommand() throws {\n        var installation = Installation()\n        XCTAssertThrowsError(try installation.replaceCommand())\n        let objectId = \"yarr\"\n        installation.objectId = objectId\n\n        let command = try installation.replaceCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/installations/\\(objectId)\")\n        XCTAssertEqual(command.method, API.Method.PUT)\n        XCTAssertNil(command.params)\n        XCTAssertNotNil(command.body)\n    }\n\n    func testUpdateCommand() throws {\n        var installation = Installation()\n        XCTAssertThrowsError(try installation.updateCommand())\n        let objectId = \"yarr\"\n        installation.objectId = objectId\n\n        let command = try installation.updateCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/installations/\\(objectId)\")\n        XCTAssertEqual(command.method, API.Method.PATCH)\n        XCTAssertNil(command.params)\n        XCTAssertNotNil(command.body)\n    }\n\n    // swiftlint:disable:next function_body_length\n    func testSaveAllCurrent() throws {\n        try testSaveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard var installation = Installation.current else {\n            XCTFail(\"Should unwrap dates\")\n            return\n        }\n        installation.createdAt = nil\n        var installation2 = installation\n        installation2.objectId = \"old\"\n        installation.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n        installation.customKey = \"newValue\"\n\n        let installationOnServer = [BatchResponseItem<Installation>(success: installation,\n                                                                    error: nil),\n                                    BatchResponseItem<Installation>(success: installation2,\n                                                                    error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(installation)\n            installation = try installation.getDecoder().decode(Installation.self, from: encoded1)\n            let encoded2 = try ParseCoding.jsonEncoder().encode(installation2)\n            installation2 = try installation.getDecoder().decode(Installation.self, from: encoded2)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            let saved = try [installation].saveAll()\n            saved.forEach {\n                switch $0 {\n                case .success(let saved):\n                    guard let currentInstallation = Installation.current else {\n                        XCTFail(\"Should have current installation\")\n                        return\n                    }\n                    XCTAssertTrue(saved.hasSameObjectId(as: currentInstallation))\n                    XCTAssertTrue(saved.hasSameInstallationId(as: currentInstallation))\n                    XCTAssertTrue(saved.hasSameObjectId(as: installation))\n                    XCTAssertTrue(saved.hasSameInstallationId(as: installation))\n                    guard let savedUpdatedAt = saved.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            return\n                    }\n                    XCTAssertEqual(savedUpdatedAt, installation.updatedAt)\n                    XCTAssertEqual(Installation.current?.customKey, installation.customKey)\n\n                    //Should be updated in memory\n                    guard let updatedCurrentDate = Installation.current?.updatedAt else {\n                        XCTFail(\"Should unwrap current date\")\n                        return\n                    }\n                    XCTAssertEqual(updatedCurrentDate, installation.updatedAt)\n\n                    #if !os(Linux) && !os(Android) && !os(Windows)\n                    //Should be updated in Keychain\n                    guard let keychainInstallation: CurrentInstallationContainer<BaseParseInstallation>\n                        = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation),\n                        let keychainUpdatedCurrentDate = keychainInstallation.currentInstallation?.updatedAt else {\n                            XCTFail(\"Should get object from Keychain\")\n                        return\n                    }\n                    XCTAssertEqual(keychainUpdatedCurrentDate, installation.updatedAt)\n                    #endif\n                case .failure(let error):\n                    XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                }\n            }\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        do {\n            let saved2 = try [installation].saveAll(transaction: true)\n            saved2.forEach {\n                switch $0 {\n                case .success(let saved):\n                    guard let currentInstallation = Installation.current else {\n                        XCTFail(\"Should have current installation\")\n                        return\n                    }\n                    XCTAssertTrue(saved.hasSameObjectId(as: currentInstallation))\n                    XCTAssertTrue(saved.hasSameInstallationId(as: currentInstallation))\n                    guard let savedUpdatedAt = saved.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            return\n                    }\n                    XCTAssertEqual(savedUpdatedAt, installation.updatedAt)\n                    XCTAssertEqual(Installation.current?.customKey, installation.customKey)\n\n                    //Should be updated in memory\n                    guard let updatedCurrentDate = Installation.current?.updatedAt else {\n                        XCTFail(\"Should unwrap current date\")\n                        return\n                    }\n                    XCTAssertEqual(updatedCurrentDate, installation.updatedAt)\n\n                    #if !os(Linux) && !os(Android) && !os(Windows)\n                    //Should be updated in Keychain\n                    guard let keychainInstallation: CurrentInstallationContainer<BaseParseInstallation>\n                        = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation),\n                        let keychainUpdatedCurrentDate = keychainInstallation.currentInstallation?.updatedAt else {\n                            XCTFail(\"Should get object from Keychain\")\n                        return\n                    }\n                    XCTAssertEqual(keychainUpdatedCurrentDate, installation.updatedAt)\n                    #endif\n                case .failure(let error):\n                    XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                }\n            }\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    // swiftlint:disable:next function_body_length\n    func testSaveAllAsyncMainQueueCurrent() throws {\n        try testSaveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        let expectation1 = XCTestExpectation(description: \"Fetch installation1\")\n        let expectation2 = XCTestExpectation(description: \"Fetch installation2\")\n        guard var installation = Installation.current else {\n            XCTFail(\"Should unwrap\")\n            expectation1.fulfill()\n            expectation2.fulfill()\n            return\n        }\n        installation.createdAt = nil\n        var installation2 = installation\n        installation2.objectId = \"old\"\n        installation.updatedAt = installation.updatedAt?.addingTimeInterval(+300)\n        installation.customKey = \"newValue\"\n        let installationOnServer = [BatchResponseItem<Installation>(success: installation,\n                                                                    error: nil),\n                                    BatchResponseItem<Installation>(success: installation2,\n                                                                    error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(installation)\n            installation = try installation.getDecoder().decode(Installation.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            expectation2.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        [installation].saveAll { results in\n            switch results {\n\n            case .success(let saved):\n                saved.forEach {\n                    switch $0 {\n                    case .success(let saved):\n                        guard let currentInstallation = Installation.current else {\n                            XCTFail(\"Should have current installation\")\n                            return\n                        }\n                        XCTAssertTrue(saved.hasSameObjectId(as: currentInstallation))\n                        XCTAssertTrue(saved.hasSameInstallationId(as: currentInstallation))\n                        XCTAssertTrue(saved.hasSameObjectId(as: installation))\n                        XCTAssertTrue(saved.hasSameInstallationId(as: installation))\n                        guard let savedUpdatedAt = saved.updatedAt else {\n                                XCTFail(\"Should unwrap dates\")\n                                expectation1.fulfill()\n                                return\n                        }\n                        XCTAssertEqual(savedUpdatedAt, installation.updatedAt)\n                        XCTAssertEqual(Installation.current?.customKey, installation.customKey)\n\n                        //Should be updated in memory\n                        guard let updatedCurrentDate = Installation.current?.updatedAt else {\n                            XCTFail(\"Should unwrap current date\")\n                            expectation1.fulfill()\n                            return\n                        }\n                        XCTAssertEqual(updatedCurrentDate, installation.updatedAt)\n                        #if !os(Linux) && !os(Android) && !os(Windows)\n                        //Should be updated in Keychain\n                        guard let keychainInstallation: CurrentInstallationContainer<BaseParseInstallation>\n                            = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation),\n                            let keychainUpdatedCurrentDate = keychainInstallation\n                                .currentInstallation?.updatedAt else {\n                                XCTFail(\"Should get object from Keychain\")\n                                expectation1.fulfill()\n                            return\n                        }\n                        XCTAssertEqual(keychainUpdatedCurrentDate, installation.updatedAt)\n                        #endif\n                    case .failure(let error):\n                        XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                    }\n                }\n            case .failure(let error):\n                XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n            }\n            expectation1.fulfill()\n        }\n\n        [installation].saveAll(transaction: true) { results in\n            switch results {\n\n            case .success(let saved):\n                saved.forEach {\n                    switch $0 {\n                    case .success(let saved):\n                        guard let currentInstallation = Installation.current else {\n                            XCTFail(\"Should have current installation\")\n                            return\n                        }\n                        XCTAssertTrue(saved.hasSameObjectId(as: currentInstallation))\n                        XCTAssertTrue(saved.hasSameInstallationId(as: currentInstallation))\n                        guard let savedUpdatedAt = saved.updatedAt else {\n                                XCTFail(\"Should unwrap dates\")\n                                expectation2.fulfill()\n                                return\n                        }\n                        XCTAssertEqual(savedUpdatedAt, installation.updatedAt)\n                        XCTAssertEqual(Installation.current?.customKey, installation.customKey)\n\n                        //Should be updated in memory\n                        guard let updatedCurrentDate = Installation.current?.updatedAt else {\n                            XCTFail(\"Should unwrap current date\")\n                            expectation2.fulfill()\n                            return\n                        }\n                        XCTAssertEqual(updatedCurrentDate, installation.updatedAt)\n                        #if !os(Linux) && !os(Android) && !os(Windows)\n                        //Should be updated in Keychain\n                        guard let keychainInstallation: CurrentInstallationContainer<BaseParseInstallation>\n                            = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation),\n                            let keychainUpdatedCurrentDate = keychainInstallation\n                                .currentInstallation?.updatedAt else {\n                                XCTFail(\"Should get object from Keychain\")\n                                expectation2.fulfill()\n                            return\n                        }\n                        XCTAssertEqual(keychainUpdatedCurrentDate, installation.updatedAt)\n                        #endif\n                    case .failure(let error):\n                        XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                    }\n                }\n            case .failure(let error):\n                XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n            }\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testDeleteAllCurrent() throws {\n        try testSaveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        guard let installation = Installation.current else {\n            XCTFail(\"Should unwrap dates\")\n            return\n        }\n\n        let installationOnServer = [BatchResponseItem<NoBody>(success: NoBody(), error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            let deleted = try [installation].deleteAll()\n            deleted.forEach {\n                if case let .failure(error) = $0 {\n                    XCTFail(\"Should have deleted: \\(error.localizedDescription)\")\n                }\n                if let newInstallation = Installation.current {\n                    XCTAssertFalse(installation.hasSameInstallationId(as: newInstallation))\n                }\n            }\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        do {\n            let deleted = try [installation].deleteAll(transaction: true)\n            deleted.forEach {\n                if case let .failure(error) = $0 {\n                    XCTFail(\"Should have deleted: \\(error.localizedDescription)\")\n                }\n            }\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testDeleteAllAsyncMainQueueCurrent() throws {\n        try testSaveCurrentInstallation()\n        MockURLProtocol.removeAll()\n\n        let expectation1 = XCTestExpectation(description: \"Delete installation1\")\n        let expectation2 = XCTestExpectation(description: \"Delete installation2\")\n\n        guard let installation = Installation.current else {\n            XCTFail(\"Should unwrap\")\n            expectation1.fulfill()\n            expectation2.fulfill()\n            return\n        }\n\n        let installationOnServer = [BatchResponseItem<NoBody>(success: NoBody(), error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            expectation2.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        [installation].deleteAll { results in\n            switch results {\n\n            case .success(let deleted):\n                deleted.forEach {\n                    if case let .failure(error) = $0 {\n                        XCTFail(\"Should have deleted: \\(error.localizedDescription)\")\n                    }\n                    if let newInstallation = Installation.current {\n                        XCTAssertFalse(installation.hasSameInstallationId(as: newInstallation))\n                    }\n                }\n            case .failure(let error):\n                XCTFail(\"Should have deleted: \\(error.localizedDescription)\")\n            }\n            expectation1.fulfill()\n        }\n\n        [installation].deleteAll(transaction: true) { results in\n            switch results {\n\n            case .success(let deleted):\n                deleted.forEach {\n                    if case let .failure(error) = $0 {\n                        XCTFail(\"Should have deleted: \\(error.localizedDescription)\")\n                    }\n                }\n            case .failure(let error):\n                XCTFail(\"Should have deleted: \\(error.localizedDescription)\")\n            }\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n}\n// swiftlint:disable:this file_length\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseKeychainAccessGroupTests.swift",
    "content": "//\n//  ParseKeychainAccessGroupTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 7/3/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if !os(Linux) && !os(Android) && !os(Windows)\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseKeychainAccessGroupTests: XCTestCase {\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    struct Installation: ParseInstallation {\n        var installationId: String?\n        var deviceType: String?\n        var deviceToken: String?\n        var badge: Int?\n        var timeZone: String?\n        var channels: [String]?\n        var appName: String?\n        var appIdentifier: String?\n        var appVersion: String?\n        var parseVersion: String?\n        var localeIdentifier: String?\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n        var customKey: String?\n\n        //: Implement your own version of merge\n        func merge(with object: Self) throws -> Self {\n            var updated = try mergeParse(with: object)\n            if updated.shouldRestoreKey(\\.customKey,\n                                         original: object) {\n                updated.customKey = object.customKey\n            }\n            return updated\n        }\n    }\n\n    struct Config: ParseConfig {\n        var welcomeMessage: String?\n        var winningNumber: Int?\n    }\n\n    let group = \"TEAM.com.parse.parseswift\"\n    let keychainAccessGroup = ParseKeychainAccessGroup(accessGroup: \"TEAM.com.parse.parseswift\",\n                                                       isSyncingKeychainAcrossDevices: false)\n    let keychainAccessGroupSync = ParseKeychainAccessGroup(accessGroup: \"TEAM.com.parse.parseswift\",\n                                                           isSyncingKeychainAcrossDevices: true)\n    let helloKeychainAccessGroup = ParseKeychainAccessGroup(accessGroup: \"hello\",\n                                                            isSyncingKeychainAcrossDevices: false)\n    let noKeychainAccessGroup = ParseKeychainAccessGroup()\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        _ = KeychainStore.shared.removeAllObjects()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func userLogin() throws {\n        let loginResponse = LoginSignupResponse()\n        let loginUserName = \"hello10\"\n        let loginPassword = \"world\"\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        _ = try User.login(username: loginUserName, password: loginPassword)\n        MockURLProtocol.removeAll()\n    }\n\n    func testKeychainAccessGroupCreatedOnServerInit() throws {\n        XCTAssertNotNil(ParseKeychainAccessGroup.current)\n        XCTAssertNil(ParseSwift.configuration.keychainAccessGroup.accessGroup)\n        XCTAssertFalse(ParseSwift.configuration.keychainAccessGroup.isSyncingKeychainAcrossDevices)\n        XCTAssertEqual(ParseSwift.configuration.keychainAccessGroup, ParseKeychainAccessGroup.current)\n    }\n\n    func testUpdateKeychainAccessGroup() throws {\n        XCTAssertEqual(ParseSwift.configuration.keychainAccessGroup, ParseKeychainAccessGroup.current)\n        ParseKeychainAccessGroup.current = keychainAccessGroupSync\n        XCTAssertEqual(ParseSwift.configuration.keychainAccessGroup, ParseKeychainAccessGroup.current)\n        ParseKeychainAccessGroup.current = nil\n        XCTAssertEqual(ParseKeychainAccessGroup.current, noKeychainAccessGroup)\n        XCTAssertEqual(ParseSwift.configuration.keychainAccessGroup, noKeychainAccessGroup)\n        ParseKeychainAccessGroup.current = keychainAccessGroupSync\n        XCTAssertEqual(ParseSwift.configuration.keychainAccessGroup, ParseKeychainAccessGroup.current)\n    }\n\n    func testCanGetKeychainAccessGroupFromKeychain() throws {\n        guard let currentAccessGroup = ParseKeychainAccessGroup.current else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        try ParseStorage.shared.delete(valueFor: ParseStorage.Keys.currentAccessGroup)\n        XCTAssertEqual(currentAccessGroup, ParseKeychainAccessGroup.current)\n    }\n\n    func testDeleteKeychainAccessGroup() throws {\n        XCTAssertEqual(ParseKeychainAccessGroup.current, noKeychainAccessGroup)\n        XCTAssertEqual(ParseSwift.configuration.keychainAccessGroup, noKeychainAccessGroup)\n        ParseKeychainAccessGroup.deleteCurrentContainerFromKeychain()\n        XCTAssertEqual(ParseSwift.configuration.keychainAccessGroup, noKeychainAccessGroup)\n        XCTAssertNil(ParseKeychainAccessGroup.current)\n        ParseKeychainAccessGroup.current = keychainAccessGroup\n        XCTAssertEqual(ParseKeychainAccessGroup.current, keychainAccessGroup)\n        XCTAssertEqual(ParseSwift.configuration.keychainAccessGroup, keychainAccessGroup)\n    }\n\n    func testCanCopyEntireKeychain() throws {\n        try userLogin()\n        Config.current = .init(welcomeMessage: \"yolo\", winningNumber: 1)\n        _ = try ParseACL.setDefaultACL(ParseACL(), withAccessForCurrentUser: true)\n        guard let user: CurrentUserContainer<User> =\n                try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        guard let installation: CurrentInstallationContainer<Installation> =\n                try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        guard let version: String =\n                try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentVersion) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        guard let accessGroup: ParseKeychainAccessGroup =\n                try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentAccessGroup) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        guard let config: CurrentConfigContainer<Config> =\n                try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentConfig) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        guard let acl: DefaultACL =\n                try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.defaultACL) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let otherKeychain = KeychainStore(service: \"other\")\n        try otherKeychain.copy(KeychainStore.shared,\n                               oldAccessGroup: ParseSwift.configuration.keychainAccessGroup,\n                               newAccessGroup: ParseSwift.configuration.keychainAccessGroup)\n        guard let otherUser: CurrentUserContainer<User> =\n                try? otherKeychain.get(valueFor: ParseStorage.Keys.currentUser) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        guard let otherInstallation: CurrentInstallationContainer<Installation> =\n                try? otherKeychain.get(valueFor: ParseStorage.Keys.currentInstallation) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        guard let otherVersion: String =\n                try? otherKeychain.get(valueFor: ParseStorage.Keys.currentVersion) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        guard let otherAccessGroup: ParseKeychainAccessGroup =\n                try? otherKeychain.get(valueFor: ParseStorage.Keys.currentAccessGroup) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        guard let otherConfig: CurrentConfigContainer<Config> =\n                try? otherKeychain.get(valueFor: ParseStorage.Keys.currentConfig) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        guard let otherAcl: DefaultACL =\n                try? otherKeychain.get(valueFor: ParseStorage.Keys.defaultACL) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertEqual(user, otherUser)\n        XCTAssertEqual(installation, otherInstallation)\n        XCTAssertEqual(version, otherVersion)\n        XCTAssertEqual(accessGroup, otherAccessGroup)\n        XCTAssertEqual(config, otherConfig)\n        XCTAssertEqual(acl, otherAcl)\n    }\n\n    func testRemoveOldObjectsFromKeychain() throws {\n        try userLogin()\n        Config.current = .init(welcomeMessage: \"yolo\", winningNumber: 1)\n        _ = try ParseACL.setDefaultACL(ParseACL(), withAccessForCurrentUser: true)\n\n        guard let _: CurrentUserContainer<User> =\n                try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        guard let _: CurrentInstallationContainer<Installation> =\n                try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        guard let _: String =\n                try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentVersion) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        guard let _: ParseKeychainAccessGroup =\n                try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentAccessGroup) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        guard let _: CurrentConfigContainer<Config> =\n                try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentConfig) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        guard let _: DefaultACL =\n                try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.defaultACL) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let deleted = KeychainStore.shared.removeOldObjects(accessGroup: ParseSwift.configuration.keychainAccessGroup)\n        XCTAssertTrue(deleted)\n        if let _: CurrentUserContainer<User> =\n                try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser) {\n            XCTFail(\"Should be nil\")\n        }\n        if let _: CurrentConfigContainer<Config> =\n                try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentConfig) {\n            XCTFail(\"Should be nil\")\n        }\n        if let _: DefaultACL =\n                try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.defaultACL) {\n            XCTFail(\"Should be nil\")\n        }\n        guard let _: CurrentInstallationContainer<Installation> =\n                try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        guard let _: String =\n                try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentVersion) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        guard let _: ParseKeychainAccessGroup =\n                try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentAccessGroup) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n    }\n\n    func testNoUserNoAccessGroupNoSync() throws {\n        XCTAssertNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentUser,\n                                               accessGroup: noKeychainAccessGroup))\n        XCTAssertNotNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentInstallation,\n                                                  accessGroup: noKeychainAccessGroup))\n        XCTAssertNotNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentVersion,\n                                                  accessGroup: noKeychainAccessGroup))\n    }\n\n    func testUserNoAccessGroupNoSync() throws {\n        try userLogin()\n        XCTAssertNotNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentUser,\n                                                  accessGroup: noKeychainAccessGroup))\n        XCTAssertNotNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentInstallation,\n                                                  accessGroup: noKeychainAccessGroup))\n        XCTAssertNotNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentVersion,\n                                                  accessGroup: noKeychainAccessGroup))\n    }\n\n    func testSetAccessGroupWithNoSync() throws {\n        try userLogin()\n        XCTAssertNotNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentUser,\n                                                  accessGroup: noKeychainAccessGroup))\n        XCTAssertNotNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentInstallation,\n                                                  accessGroup: noKeychainAccessGroup))\n        XCTAssertNotNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentVersion,\n                                                  accessGroup: noKeychainAccessGroup))\n        #if !os(macOS)\n        do {\n            try ParseSwift.setAccessGroup(group, synchronizeAcrossDevices: false)\n            XCTFail(\"Should have thrown error due to entitlements\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted to ParseError\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"-34018\"))\n        }\n        XCTAssertNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentUser,\n                                               accessGroup: helloKeychainAccessGroup))\n        XCTAssertNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentInstallation,\n                                               accessGroup: helloKeychainAccessGroup))\n        XCTAssertNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentVersion,\n                                               accessGroup: helloKeychainAccessGroup))\n        #endif\n        // Since error was thrown, original Keychain should be left intact\n        XCTAssertNotNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentUser,\n                                                  accessGroup: noKeychainAccessGroup))\n        XCTAssertNotNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentInstallation,\n                                                  accessGroup: noKeychainAccessGroup))\n        XCTAssertNotNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentVersion,\n                                                  accessGroup: noKeychainAccessGroup))\n    }\n\n    func testSetAccessGroupWithSync() throws {\n        try userLogin()\n        XCTAssertNotNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentUser,\n                                                  accessGroup: noKeychainAccessGroup))\n        XCTAssertNotNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentInstallation,\n                                                  accessGroup: noKeychainAccessGroup))\n        XCTAssertNotNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentVersion,\n                                                  accessGroup: noKeychainAccessGroup))\n        do {\n            try ParseSwift.setAccessGroup(group, synchronizeAcrossDevices: true)\n            XCTFail(\"Should have thrown error due to entitlements\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted to ParseError\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"-34018\"))\n        }\n        #if !os(macOS)\n        XCTAssertNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentUser,\n                                               accessGroup: helloKeychainAccessGroup))\n        XCTAssertNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentInstallation,\n                                               accessGroup: helloKeychainAccessGroup))\n        XCTAssertNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentVersion,\n                                               accessGroup: helloKeychainAccessGroup))\n        #endif\n        // Since error was thrown, original Keychain should be left intact\n        XCTAssertNotNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentUser,\n                                                  accessGroup: noKeychainAccessGroup))\n        XCTAssertNotNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentInstallation,\n                                                  accessGroup: noKeychainAccessGroup))\n        XCTAssertNotNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentVersion,\n                                                  accessGroup: noKeychainAccessGroup))\n    }\n\n    func testSetAccessNilGroupWithSync() throws {\n        try userLogin()\n        XCTAssertNotNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentUser,\n                                                  accessGroup: noKeychainAccessGroup))\n        XCTAssertNotNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentInstallation,\n                                                  accessGroup: noKeychainAccessGroup))\n        XCTAssertNotNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentVersion,\n                                                  accessGroup: noKeychainAccessGroup))\n        do {\n            try ParseSwift.setAccessGroup(nil, synchronizeAcrossDevices: true)\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted to ParseError\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"must be set to a valid string\"))\n        }\n        #if !os(macOS)\n        XCTAssertNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentUser,\n                                               accessGroup: helloKeychainAccessGroup))\n        XCTAssertNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentInstallation,\n                                               accessGroup: helloKeychainAccessGroup))\n        XCTAssertNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentVersion,\n                                               accessGroup: helloKeychainAccessGroup))\n        #endif\n        // Since error was thrown, original Keychain should be left intact\n        XCTAssertNotNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentUser,\n                                                  accessGroup: noKeychainAccessGroup))\n        XCTAssertNotNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentInstallation,\n                                                  accessGroup: noKeychainAccessGroup))\n        XCTAssertNotNil(KeychainStore.shared.data(forKey: ParseStorage.Keys.currentVersion,\n                                                  accessGroup: noKeychainAccessGroup))\n    }\n\n    func testSetAccessGroupWhenNotInit() throws {\n        try ParseStorage.shared.delete(valueFor: ParseStorage.Keys.currentAccessGroup)\n        try KeychainStore.shared.delete(valueFor: ParseStorage.Keys.currentAccessGroup)\n        do {\n            try ParseSwift.setAccessGroup(\"hello\", synchronizeAcrossDevices: true)\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted to ParseError\")\n                return\n            }\n            print(parseError)\n            XCTAssertTrue(parseError.message.contains(\"initialize the SDK\"))\n        }\n    }\n\n    func testSetAccessGroupNoChangeInAccessGroup() throws {\n        ParseKeychainAccessGroup.current = noKeychainAccessGroup\n        try userLogin()\n        try ParseSwift.setAccessGroup(noKeychainAccessGroup.accessGroup,\n                                      synchronizeAcrossDevices: noKeychainAccessGroup.isSyncingKeychainAcrossDevices)\n        XCTAssertEqual(ParseSwift.configuration.keychainAccessGroup, noKeychainAccessGroup)\n    }\n\n    func testSetAccessGroupChangeInAccessGroup() throws {\n        try userLogin()\n        ParseKeychainAccessGroup.current = keychainAccessGroup\n        try ParseSwift.setAccessGroup(helloKeychainAccessGroup.accessGroup,\n                                      synchronizeAcrossDevices: helloKeychainAccessGroup.isSyncingKeychainAcrossDevices)\n        XCTAssertEqual(ParseSwift.configuration.keychainAccessGroup, helloKeychainAccessGroup)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseLDAPAsyncTests.swift",
    "content": "//\n//  ParseLDAPAsyncTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/28/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseLDAPAsyncTests: XCTestCase { // swiftlint:disable:this type_body_length\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    @MainActor\n    func testLogin() async throws {\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.ldap.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.ldap.login(id: \"testing\", password: \"this\")\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.ldap.isLinked)\n    }\n\n    @MainActor\n    func testLoginAuthData() async throws {\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.ldap.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.ldap.login(authData: ([\"id\": \"testing\",\n                                                         \"password\": \"this\"]))\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.ldap.isLinked)\n    }\n\n    func loginNormally() async throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try await User.login(username: \"parse\", password: \"user\")\n    }\n\n    @MainActor\n    func testLink() async throws {\n\n        _ = try await loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.ldap.link(id: \"testing\", password: \"password\")\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.ldap.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testLinkAuthData() async throws {\n\n        _ = try await loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        let authData = ParseLDAP<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\", password: \"authenticationToken\")\n\n        let user = try await User.ldap.link(authData: authData)\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.ldap.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testUnlink() async throws {\n\n        _ = try await loginNormally()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseLDAP<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                              password: \"this\")\n        User.current?.authData = [User.ldap.__type: authData]\n        XCTAssertTrue(User.ldap.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.ldap.unlink()\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertFalse(user.ldap.isLinked)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseLDAPCombineTests.swift",
    "content": "//\n//  ParseLDAPCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 2/14/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseLDAPCombineTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testLogin() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.ldap.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.ldap.loginPublisher(id: \"testing\", password: \"this\")\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user, userOnServer)\n            XCTAssertEqual(user.username, \"hello\")\n            XCTAssertEqual(user.password, \"world\")\n            XCTAssertTrue(user.ldap.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginAuthData() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.ldap.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.ldap.loginPublisher(authData: ([\"id\": \"testing\",\n                                                             \"password\": \"this\"]))\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user, userOnServer)\n            XCTAssertEqual(user.username, \"hello\")\n            XCTAssertEqual(user.password, \"world\")\n            XCTAssertTrue(user.ldap.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func loginNormally() throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try User.login(username: \"parse\", password: \"user\")\n    }\n\n    func testLink() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.ldap.linkPublisher(id: \"testing\", password: \"this\")\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertTrue(user.ldap.isLinked)\n            XCTAssertFalse(user.anonymous.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkAuthData() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let authData = ParseLDAP<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\", password: \"authenticationToken\")\n        let publisher = User.ldap.linkPublisher(authData: authData)\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertTrue(user.ldap.isLinked)\n            XCTAssertFalse(user.anonymous.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUnlink() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseLDAP<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                              password: \"this\")\n        User.current?.authData = [User.ldap.__type: authData]\n        XCTAssertTrue(User.ldap.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.ldap.unlinkPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertFalse(user.ldap.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseLDAPTests.swift",
    "content": "//\n//  ParseLDAPTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 2/14/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseLDAPTests: XCTestCase {\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func loginNormally() throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try User.login(username: \"parse\", password: \"user\")\n    }\n\n    func testAuthenticationKeys() throws {\n        let authData = ParseLDAP<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  password: \"this\")\n        XCTAssertEqual(authData, [\"id\": \"testing\", \"password\": \"this\"])\n    }\n\n    func testVerifyMandatoryKeys() throws {\n        let authData = [\"id\": \"testing\", \"password\": \"this\"]\n        let authDataWrong = [\"id\": \"testing\", \"hello\": \"test\"]\n        XCTAssertTrue(ParseLDAP<User>\n                        .AuthenticationKeys.id.verifyMandatoryKeys(authData: authData))\n        XCTAssertFalse(ParseLDAP<User>\n                        .AuthenticationKeys.id.verifyMandatoryKeys(authData: authDataWrong))\n    }\n\n    func testLogin() throws {\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseLDAP<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  password: \"this\")\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.ldap.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.ldap.login(id: \"testing\", password: \"this\") { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user, userOnServer)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.ldap.isLinked)\n\n                //Test stripping\n                user.ldap.strip()\n                XCTAssertFalse(user.ldap.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginWrongKeys() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.ldap.login(authData: [\"hello\": \"world\"]) { result in\n\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"consisting of keys\"))\n            } else {\n                XCTFail(\"Should have returned error\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func loginAnonymousUser() throws {\n        let authData = [\"id\": \"yolo\"]\n\n        //: Convert the anonymous user to a real new user.\n        var serverResponse = LoginSignupResponse()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.anonymous.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try User.anonymous.login()\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.anonymous.isLinked)\n    }\n\n    func testReplaceAnonymousWithLDAP() throws {\n        try loginAnonymousUser()\n        MockURLProtocol.removeAll()\n        let authData = ParseLDAP<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  password: \"this\")\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.ldap.__type: authData,\n                                   serverResponse.anonymous.__type: nil]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.ldap.login(id: \"testing\", password: \"this\") { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.authData, userOnServer.authData)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.ldap.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testReplaceAnonymousWithLinkedLDAP() throws {\n        try loginAnonymousUser()\n        MockURLProtocol.removeAll()\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.ldap.link(id: \"testing\", password: \"this\") { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.ldap.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkLoggedInUserWithLDAP() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n        serverResponse.sessionToken = nil\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.ldap.link(id: \"testing\", password: \"this\") { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello10\")\n                XCTAssertNil(user.password)\n                XCTAssertTrue(user.ldap.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n                XCTAssertEqual(User.current?.sessionToken, \"myToken\")\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkLoggedInAuthData() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n        serverResponse.sessionToken = nil\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n        let authData = ParseLDAP<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\", password: \"authenticationToken\")\n        User.ldap.link(authData: authData) { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello10\")\n                XCTAssertNil(user.password)\n                XCTAssertTrue(user.ldap.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n                XCTAssertEqual(User.current?.sessionToken, \"myToken\")\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkLoggedInUserWrongKeys() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.ldap.link(authData: [\"hello\": \"world\"]) { result in\n\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"consisting of keys\"))\n            } else {\n                XCTFail(\"Should have returned error\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUnlink() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n        let authData = ParseLDAP<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                              password: \"this\")\n        User.current?.authData = [User.ldap.__type: authData]\n        XCTAssertTrue(User.ldap.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.ldap.unlink { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello10\")\n                XCTAssertNil(user.password)\n                XCTAssertFalse(user.ldap.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseLinkedInCombineTests.swift",
    "content": "//\n//  ParseLinkedInCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/1/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseLinkedInCombineTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testLogin() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.linkedin.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.linkedin.loginPublisher(id: \"testing\",\n                                                     accessToken: \"this\",\n                                                     isMobileSDK: true)\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user, userOnServer)\n            XCTAssertEqual(user.username, \"hello\")\n            XCTAssertEqual(user.password, \"world\")\n            XCTAssertTrue(user.linkedin.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginAuthData() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.linkedin.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.linkedin.loginPublisher(authData: ([\"id\": \"testing\",\n                                                                 \"access_token\": \"this\",\n                                                                 \"is_mobile_sdk\": \"\\(true)\"]))\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user, userOnServer)\n            XCTAssertEqual(user.username, \"hello\")\n            XCTAssertEqual(user.password, \"world\")\n            XCTAssertTrue(user.linkedin.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func loginNormally() throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try User.login(username: \"parse\", password: \"user\")\n    }\n\n    func testLink() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.linkedin.linkPublisher(id: \"testing\",\n                                                    accessToken: \"this\",\n                                                    isMobileSDK: true)\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertTrue(user.linkedin.isLinked)\n            XCTAssertFalse(user.anonymous.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkAuthData() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let authData = ParseLinkedIn<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"accessToken\",\n                                                  isMobileSDK: true)\n        let publisher = User.linkedin.linkPublisher(authData: authData)\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertTrue(user.linkedin.isLinked)\n            XCTAssertFalse(user.anonymous.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUnlink() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseLinkedIn<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"this\",\n                                                  isMobileSDK: true)\n        User.current?.authData = [User.linkedin.__type: authData]\n        XCTAssertTrue(User.linkedin.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.linkedin.unlinkPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertFalse(user.linkedin.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseLinkedInTests.swift",
    "content": "//\n//  ParseLinkedInTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/1/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseLinkedInTests: XCTestCase { // swiftlint:disable:this type_body_length\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func loginNormally() throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try User.login(username: \"parse\", password: \"user\")\n    }\n\n    func loginAnonymousUser() throws {\n        let authData = [\"id\": \"yolo\"]\n\n        //: Convert the anonymous user to a real new user.\n        var serverResponse = LoginSignupResponse()\n        serverResponse.username = \"hello\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.anonymous.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try User.anonymous.login()\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.anonymous.isLinked)\n    }\n\n    func testAuthenticationKeys() throws {\n        let authData = ParseLinkedIn<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"that\",\n                                                  isMobileSDK: true)\n        XCTAssertEqual(authData, [\"id\": \"testing\",\n                                  \"access_token\": \"that\",\n                                  \"is_mobile_sdk\": \"\\(true)\"])\n    }\n\n    func testVerifyMandatoryKeys() throws {\n        let authData = [\"id\": \"testing\", \"access_token\": \"this\", \"is_mobile_sdk\": \"\\(true)\"]\n        let authDataWrong = [\"id\": \"testing\", \"hello\": \"test\"]\n        XCTAssertTrue(ParseLinkedIn<User>\n                        .AuthenticationKeys.id.verifyMandatoryKeys(authData: authData))\n        XCTAssertFalse(ParseLinkedIn<User>\n                        .AuthenticationKeys.id.verifyMandatoryKeys(authData: authDataWrong))\n    }\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\n    @MainActor\n    func testLogin() async throws {\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.linkedin.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.linkedin.login(id: \"testing\",\n                                                 accessToken: \"that\",\n                                                 isMobileSDK: true)\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.linkedin.isLinked)\n    }\n\n    @MainActor\n    func testLoginAuthData() async throws {\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.linkedin.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.linkedin.login(authData: ([\"id\": \"testing\",\n                                                             \"access_token\": \"this\",\n                                                             \"is_mobile_sdk\": \"\\(true)\"]))\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.linkedin.isLinked)\n    }\n\n    @MainActor\n    func testLoginAuthDataBadAuth() async throws {\n        do {\n            _ = try await User.linkedin.login(authData: ([\"id\": \"testing\",\n                                                        \"bad\": \"token\"]))\n        } catch {\n            guard let parseError = error.containedIn([.unknownError]) else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"consisting of keys\"))\n        }\n    }\n\n    @MainActor\n    func testReplaceAnonymousWithLoggedIn() async throws {\n        try loginAnonymousUser()\n        MockURLProtocol.removeAll()\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n        serverResponse.password = nil\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.linkedin.login(id: \"testing\",\n                                                 accessToken: \"that\",\n                                                 isMobileSDK: true)\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.linkedin.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testReplaceAnonymousWithLinked() async throws {\n        try loginAnonymousUser()\n        MockURLProtocol.removeAll()\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n        serverResponse.password = nil\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.linkedin.link(id: \"testing\",\n                                                accessToken: \"that\",\n                                                isMobileSDK: true)\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.linkedin.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testLink() async throws {\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.linkedin.link(id: \"testing\",\n                                                accessToken: \"that\",\n                                                isMobileSDK: true)\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.linkedin.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testLinkLoggedInAuthData() async throws {\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n        serverResponse.sessionToken = nil\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let authData = ParseLinkedIn<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"accessToken\",\n                                                  isMobileSDK: true)\n\n        let user = try await User.linkedin.link(authData: authData)\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.linkedin.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testLinkLoggedInUserWrongKeys() async throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n        do {\n            _ = try await User.linkedin.link(authData: [\"hello\": \"world\"])\n        } catch {\n            guard let parseError = error.containedIn([.unknownError]) else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"consisting of keys\"))\n        }\n    }\n\n    @MainActor\n    func testUnlink() async throws {\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseLinkedIn<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"this\",\n                                                  isMobileSDK: true)\n        User.current?.authData = [User.linkedin.__type: authData]\n        XCTAssertTrue(User.linkedin.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.linkedin.unlink()\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertFalse(user.linkedin.isLinked)\n    }\n#endif\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseLiveQueryAsyncTests.swift",
    "content": "//\n//  ParseLiveQueryAsyncTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/28/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency) && !os(Linux) && !os(Android) && !os(Windows)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseLiveQueryAsyncTests: XCTestCase { // swiftlint:disable:this type_body_length\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n        ParseLiveQuery.defaultClient = try ParseLiveQuery(isDefault: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n        URLSession.liveQuery.closeAll()\n    }\n\n    @MainActor\n    func testOpen() async throws {\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        client.close()\n\n        do {\n            _ = try await client.open(isUserWantsToConnect: true)\n            XCTFail(\"Should always fail since WS is not intercepted.\")\n        } catch {\n            XCTAssertNotNil(error)\n        }\n    }\n\n    @MainActor\n    func testPingSocketNotEstablished() async throws {\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        client.close()\n\n        do {\n            _ = try await client.sendPing()\n            XCTFail(\"Should have produced error\")\n        } catch {\n            XCTAssertEqual(client.isSocketEstablished, false)\n            guard let urlError = error as? URLError else {\n                XCTFail(\"Should have casted to ParseError.\")\n                return\n            }\n            // \"Could not connect to the server\"\n            // because webSocket connections are not intercepted.\n            XCTAssertTrue([-1004, -1022].contains(urlError.errorCode))\n        }\n    }\n\n    @MainActor\n    func testPing() async throws {\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        client.isSocketEstablished = true // Socket needs to be true\n        client.isConnecting = true\n        client.isConnected = true\n        client.clientId = \"yolo\"\n\n        do {\n            _ = try await client.sendPing()\n            XCTFail(\"Should have produced error\")\n        } catch {\n            XCTAssertEqual(client.isSocketEstablished, true)\n            XCTAssertNotNil(error) // Should have error because testcases do not intercept websocket\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseLiveQueryCombineTests.swift",
    "content": "//\n//  ParseLiveQueryCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/25/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if !os(Linux) && !os(Android) && !os(Windows)\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n#if canImport(Combine)\nimport Combine\n#endif\n\nclass ParseLiveQueryCombineTests: XCTestCase {\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n        ParseLiveQuery.defaultClient = try ParseLiveQuery(isDefault: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n        URLSession.liveQuery.closeAll()\n    }\n\n    func testOpen() throws {\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        client.close()\n\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Send Ping\")\n        let publisher = client.openPublisher(isUserWantsToConnect: true)\n            .sink(receiveCompletion: { result in\n\n                switch result {\n\n                case .finished:\n                    XCTFail(\"Should have produced failure\")\n                case .failure(let error):\n                    XCTAssertNotNil(error) //Should always fail since WS is not intercepted.\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have produced error\")\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testPingSocketNotEstablished() throws {\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        client.close()\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Send Ping\")\n        let publisher = client.sendPingPublisher()\n            .sink(receiveCompletion: { result in\n\n                switch result {\n\n                case .finished:\n                    XCTFail(\"Should have produced failure\")\n                case .failure(let error):\n                    XCTAssertEqual(client.isSocketEstablished, false)\n                    guard let urlError = error as? URLError else {\n                        XCTFail(\"Should have casted to ParseError.\")\n                        expectation1.fulfill()\n                        return\n                    }\n                    // \"Could not connect to the server\"\n                    // because webSocket connections are not intercepted.\n                    XCTAssertTrue([-1004, -1022].contains(urlError.errorCode))\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have produced error\")\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testPing() throws {\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        client.isSocketEstablished = true // Socket needs to be true\n        client.isConnecting = true\n        client.isConnected = true\n        client.clientId = \"yolo\"\n\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Send Ping\")\n        let publisher = client.sendPingPublisher()\n            .sink(receiveCompletion: { result in\n\n                switch result {\n\n                case .finished:\n                    XCTFail(\"Should have produced failure\")\n                case .failure(let error):\n                    XCTAssertEqual(client.isSocketEstablished, true)\n                    XCTAssertNotNil(error) // Should have error because testcases do not intercept websocket\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have produced error\")\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseLiveQueryTests.swift",
    "content": "//\n//  ParseLiveQueryTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/3/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n#if !os(Linux) && !os(Android) && !os(Windows)\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseLiveQueryTests: XCTestCase {\n    struct GameScore: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int = 0\n\n        //custom initializer\n        init() {}\n\n        init(points: Int) {\n            self.points = points\n        }\n\n        init(objectId: String?) {\n            self.objectId = objectId\n        }\n    }\n\n    class TestDelegate: ParseLiveQueryDelegate {\n        var error: ParseError?\n        var code: URLSessionWebSocketTask.CloseCode?\n        var reason: Data?\n        func received(_ error: Error) {\n            if let error = error as? ParseError {\n                self.error = error\n            }\n        }\n        func closedSocket(_ code: URLSessionWebSocketTask.CloseCode?, reason: Data?) {\n            self.code = code\n            self.reason = reason\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n        ParseLiveQuery.setDefault(try ParseLiveQuery(isDefault: true))\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n        URLSession.liveQuery.closeAll()\n    }\n\n    func testWebsocketURL() throws {\n        guard let originalURL = URL(string: \"http://localhost:1337/1\"),\n            var components = URLComponents(url: originalURL,\n                                             resolvingAgainstBaseURL: false) else {\n            XCTFail(\"Should have retrieved URL components\")\n            return\n        }\n        components.scheme = (components.scheme == \"https\" || components.scheme == \"wss\") ? \"wss\" : \"ws\"\n        let webSocketURL = components.url\n\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n\n        XCTAssertEqual(client.url, webSocketURL)\n        XCTAssertTrue(client.url.absoluteString.contains(\"ws\"))\n\n        let expectation1 = XCTestExpectation(description: \"Socket delegate\")\n        client.synchronizationQueue.asyncAfter(deadline: .now() + 2) {\n            let socketDelegates = URLSession.liveQuery.delegates\n            XCTAssertNotNil(socketDelegates[client.task])\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testInitializeWithNewURL() throws {\n        guard let originalURL = URL(string: \"http://parse:1337/1\"),\n            var components = URLComponents(url: originalURL,\n                                             resolvingAgainstBaseURL: false) else {\n            XCTFail(\"Should have retrieved URL components\")\n            return\n        }\n        components.scheme = (components.scheme == \"https\" || components.scheme == \"wss\") ? \"wss\" : \"ws\"\n        let webSocketURL = components.url\n\n        guard let client = try? ParseLiveQuery(serverURL: originalURL),\n              let defaultClient = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to initialize a new client\")\n            return\n        }\n\n        XCTAssertEqual(client.url, webSocketURL)\n        XCTAssertTrue(client.url.absoluteString.contains(\"ws\"))\n        XCTAssertNotEqual(client, defaultClient)\n        let expectation1 = XCTestExpectation(description: \"Socket delegate\")\n        client.synchronizationQueue.asyncAfter(deadline: .now() + 2) {\n            let socketDelegates = URLSession.liveQuery.delegates\n            XCTAssertNotNil(socketDelegates[client.task])\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testInitializeNewDefault() throws {\n\n        guard let client = try? ParseLiveQuery(isDefault: true),\n              let defaultClient = ParseLiveQuery.getDefault() else {\n            XCTFail(\"Should be able to initialize a new client\")\n            return\n        }\n\n        XCTAssertTrue(client.url.absoluteString.contains(\"ws\"))\n        XCTAssertEqual(client, defaultClient)\n        let expectation1 = XCTestExpectation(description: \"Socket delegate\")\n        client.synchronizationQueue.asyncAfter(deadline: .now() + 2) {\n            let socketDelegates = URLSession.liveQuery.delegates\n            XCTAssertNotNil(socketDelegates[client.task])\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDeinitializingNewShouldNotEffectDefault() throws {\n        guard let defaultClient = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to initialize a new client\")\n            return\n        }\n        var client = try? ParseLiveQuery()\n        if let client = client {\n            XCTAssertTrue(client.url.absoluteString.contains(\"ws\"))\n        } else {\n            XCTFail(\"Should have initialized client and contained ws\")\n        }\n        XCTAssertNotEqual(client, defaultClient)\n        client = nil\n        XCTAssertNotNil(ParseLiveQuery.defaultClient)\n        let expectation1 = XCTestExpectation(description: \"Socket delegate\")\n        defaultClient.synchronizationQueue.asyncAfter(deadline: .now() + 2) {\n            let socketDelegates = URLSession.liveQuery.delegates\n            XCTAssertNotNil(socketDelegates[defaultClient.task])\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testBecomingSocketAuthDelegate() throws {\n        let delegate = TestDelegate()\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertNil(URLSession.liveQuery.authenticationDelegate)\n        client.authenticationDelegate = delegate\n        guard let authDelegate = URLSession\n                .liveQuery\n                .authenticationDelegate as? ParseLiveQuery else {\n            XCTFail(\"Should be able to cast\")\n            return\n        }\n        XCTAssertEqual(client, authDelegate)\n        XCTAssertNotNil(URLSession.liveQuery.authenticationDelegate)\n        client.authenticationDelegate = nil\n        XCTAssertNil(URLSession.liveQuery.authenticationDelegate)\n    }\n\n    func testStandardMessageEncoding() throws {\n        guard let installationId = BaseParseInstallation.currentContainer.installationId else {\n            XCTFail(\"Should have installationId\")\n            return\n        }\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"applicationId\\\":\\\"applicationId\\\",\\\"clientKey\\\":\\\"clientKey\\\",\\\"installationId\\\":\\\"\\(installationId)\\\",\\\"masterKey\\\":\\\"masterKey\\\",\\\"op\\\":\\\"connect\\\"}\"\n        let message = StandardMessage(operation: .connect, additionalProperties: true)\n        let encoded = try ParseCoding.jsonEncoder()\n            .encode(message)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testSubscribeMessageFieldsEncoding() throws {\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"op\\\":\\\"subscribe\\\",\\\"query\\\":{\\\"className\\\":\\\"GameScore\\\",\\\"fields\\\":[\\\"points\\\"],\\\"where\\\":{\\\"points\\\":{\\\"$gt\\\":9}}},\\\"requestId\\\":1}\"\n        let query = GameScore.query(\"points\" > 9)\n            .fields([\"points\"])\n            .select([\"talk\"])\n        let message = SubscribeMessage(operation: .subscribe,\n                                       requestId: RequestId(value: 1),\n                                       query: query,\n                                       additionalProperties: true)\n        let encoded = try ParseCoding.jsonEncoder()\n            .encode(message)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testSubscribeMessageSelectEncoding() throws {\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"op\\\":\\\"subscribe\\\",\\\"query\\\":{\\\"className\\\":\\\"GameScore\\\",\\\"fields\\\":[\\\"points\\\"],\\\"where\\\":{\\\"points\\\":{\\\"$gt\\\":9}}},\\\"requestId\\\":1}\"\n        let query = GameScore.query(\"points\" > 9)\n            .select([\"points\"])\n        let message = SubscribeMessage(operation: .subscribe,\n                                       requestId: RequestId(value: 1),\n                                       query: query,\n                                       additionalProperties: true)\n        let encoded = try ParseCoding.jsonEncoder()\n            .encode(message)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testFieldKeys() throws {\n        let query = GameScore.query\n        XCTAssertNil(query.keys)\n\n        var query2 = GameScore.query.fields([\"yolo\"])\n        XCTAssertEqual(query2.fields?.count, 1)\n        XCTAssertEqual(query2.fields?.first, \"yolo\")\n\n        query2 = query2.fields([\"hello\", \"wow\"])\n        XCTAssertEqual(query2.fields?.count, 3)\n        XCTAssertEqual(query2.fields, [\"yolo\", \"hello\", \"wow\"])\n    }\n\n    func testFieldKeysVariadic() throws {\n        let query = GameScore.query\n        XCTAssertNil(query.keys)\n\n        var query2 = GameScore.query.fields(\"yolo\")\n        XCTAssertEqual(query2.fields?.count, 1)\n        XCTAssertEqual(query2.fields?.first, \"yolo\")\n\n        query2 = query2.fields(\"hello\", \"wow\")\n        XCTAssertEqual(query2.fields?.count, 3)\n        XCTAssertEqual(query2.fields, [\"yolo\", \"hello\", \"wow\"])\n    }\n\n    func testRedirectResponseDecoding() throws {\n        guard let url = URL(string: \"http://parse.org\") else {\n            XCTFail(\"Should have url\")\n            return\n        }\n        let expected = \"{\\\"op\\\":\\\"redirect\\\",\\\"url\\\":\\\"http:\\\\/\\\\/parse.org\\\"}\"\n        let message = RedirectResponse(op: .redirect, url: url)\n        let encoded = try ParseCoding.jsonEncoder()\n            .encode(message)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testConnectionResponseDecoding() throws {\n        let expected = \"{\\\"clientId\\\":\\\"yolo\\\",\\\"installationId\\\":\\\"naw\\\",\\\"op\\\":\\\"connected\\\"}\"\n        let message = ConnectionResponse(op: .connected, clientId: \"yolo\", installationId: \"naw\")\n        let encoded = try ParseCoding.jsonEncoder()\n            .encode(message)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testUnsubscribeResponseDecoding() throws {\n        let expected = \"{\\\"clientId\\\":\\\"yolo\\\",\\\"installationId\\\":\\\"naw\\\",\\\"op\\\":\\\"connected\\\",\\\"requestId\\\":1}\"\n        let message = UnsubscribedResponse(op: .connected, requestId: 1, clientId: \"yolo\", installationId: \"naw\")\n        let encoded = try ParseCoding.jsonEncoder()\n            .encode(message)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testEventResponseDecoding() throws {\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"clientId\\\":\\\"yolo\\\",\\\"installationId\\\":\\\"naw\\\",\\\"object\\\":{\\\"points\\\":10},\\\"op\\\":\\\"connected\\\",\\\"requestId\\\":1}\"\n        let score = GameScore(points: 10)\n        let message = EventResponse(op: .connected,\n                                    requestId: 1,\n                                    object: score,\n                                    clientId: \"yolo\",\n                                    installationId: \"naw\")\n        let encoded = try ParseCoding.jsonEncoder()\n            .encode(message)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testErrorResponseDecoding() throws {\n        let expected = \"{\\\"code\\\":1,\\\"error\\\":\\\"message\\\",\\\"op\\\":\\\"error\\\",\\\"reconnect\\\":true}\"\n        let message = ErrorResponse(op: .error, code: 1, message: \"message\", reconnect: true)\n        let encoded = try ParseCoding.jsonEncoder()\n            .encode(message)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testPreliminaryResponseDecoding() throws {\n        let expected = \"{\\\"clientId\\\":\\\"message\\\",\\\"installationId\\\":\\\"naw\\\",\\\"op\\\":\\\"subscribed\\\",\\\"requestId\\\":1}\"\n        let message = PreliminaryMessageResponse(op: .subscribed,\n                                                 requestId: 1,\n                                                 clientId: \"message\",\n                                                 installationId: \"naw\")\n        let encoded = try ParseCoding.jsonEncoder()\n            .encode(message)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testSocketNotOpenState() throws {\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        client.isConnecting = true\n        XCTAssertEqual(client.isConnecting, false)\n        client.isConnected = true\n        XCTAssertEqual(client.isConnecting, false)\n        XCTAssertEqual(client.isConnected, false)\n    }\n\n    func testConnectedState() throws {\n        guard let client = ParseLiveQuery.defaultClient,\n              let task = client.task else {\n            XCTFail(\"Should be able to get client and task\")\n            return\n        }\n        client.isSocketEstablished = true // Socket needs to be true\n        client.isConnecting = true\n        client.isConnected = true\n        client.attempts = 5\n        client.clientId = \"yolo\"\n        client.isDisconnectedByUser = false\n        // Only continue test if this is not nil, otherwise skip\n        guard let receivingTask = URLSession.liveQuery.receivingTasks[task] else {\n            throw XCTSkip(\"Skip this test when the receiving task is nil\")\n        }\n        XCTAssertEqual(receivingTask, true)\n        XCTAssertEqual(client.isSocketEstablished, true)\n        XCTAssertEqual(client.isConnecting, false)\n        XCTAssertEqual(client.clientId, \"yolo\")\n        XCTAssertEqual(client.attempts, 5)\n\n        // Test too many attempts and close\n        client.isSocketEstablished = true // Socket needs to be true\n        client.isConnecting = true\n        client.isConnected = true\n        client.attempts = ParseLiveQueryConstants.maxConnectionAttempts + 1\n        client.clientId = \"yolo\"\n        client.isDisconnectedByUser = false\n\n        XCTAssertEqual(client.isSocketEstablished, false)\n        XCTAssertEqual(client.isConnecting, false)\n        XCTAssertEqual(client.clientId, \"yolo\")\n        XCTAssertEqual(client.attempts, ParseLiveQueryConstants.maxConnectionAttempts + 1)\n    }\n\n    func testDisconnectedState() throws {\n        guard let client = ParseLiveQuery.defaultClient,\n              let task = client.task else {\n            XCTFail(\"Should be able to get client and task\")\n            return\n        }\n        client.isSocketEstablished = true // Socket needs to be true\n        client.isConnecting = true\n        client.isConnected = true\n        client.clientId = \"yolo\"\n        // Only continue test if this is not nil, otherwise skip\n        guard let receivingTask = URLSession.liveQuery.receivingTasks[task] else {\n            throw XCTSkip(\"Skip this test when the receiving task is nil\")\n        }\n        XCTAssertEqual(receivingTask, true)\n        XCTAssertEqual(client.isConnected, true)\n        XCTAssertEqual(client.isConnecting, false)\n        XCTAssertEqual(client.clientId, \"yolo\")\n        client.isConnected = false\n\n        XCTAssertEqual(client.isSocketEstablished, true)\n        XCTAssertEqual(client.isConnected, false)\n        XCTAssertEqual(client.isConnecting, false)\n        XCTAssertNil(client.clientId)\n    }\n\n    func testSocketDisconnectedState() throws {\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        client.isSocketEstablished = true // Socket needs to be true\n        client.isConnecting = true\n        client.isConnected = true\n        client.clientId = \"yolo\"\n\n        XCTAssertEqual(client.isConnected, true)\n        XCTAssertEqual(client.isConnecting, false)\n        XCTAssertEqual(client.clientId, \"yolo\")\n        client.isSocketEstablished = false\n\n        XCTAssertEqual(client.isConnected, false)\n        XCTAssertEqual(client.isConnecting, false)\n        XCTAssertNil(client.clientId)\n    }\n\n    func testUserClosedConnectionState() throws {\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        client.isSocketEstablished = true // Socket needs to be true\n        client.isConnecting = true\n        client.isConnected = true\n        client.clientId = \"yolo\"\n        client.isDisconnectedByUser = false\n\n        XCTAssertEqual(client.isConnected, true)\n        XCTAssertEqual(client.isConnecting, false)\n        XCTAssertEqual(client.isDisconnectedByUser, false)\n        XCTAssertEqual(client.clientId, \"yolo\")\n        client.close()\n\n        XCTAssertEqual(client.isSocketEstablished, false)\n        XCTAssertEqual(client.isConnected, false)\n        XCTAssertEqual(client.isConnecting, false)\n        XCTAssertNil(client.clientId)\n        XCTAssertEqual(client.isDisconnectedByUser, true)\n    }\n\n    func testOpenSocket() throws {\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        client.close()\n        let expectation1 = XCTestExpectation(description: \"Response delegate\")\n        client.open(isUserWantsToConnect: true) { error in\n            XCTAssertNotNil(error) //Should always fail since WS is not intercepted.\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testCloseFromServer() throws {\n        guard let client = ParseLiveQuery.defaultClient else {\n            throw ParseError(code: .unknownError,\n                             message: \"Should be able to get client\")\n        }\n        let delegate = TestDelegate()\n        client.receiveDelegate = delegate\n        client.task = URLSession.liveQuery.createTask(client.url,\n                                                      taskDelegate: client)\n        // Only continue test if this is not nil, otherwise skip\n        guard let receivingTask = URLSession.liveQuery.receivingTasks[client.task] else {\n            throw XCTSkip(\"Skip this test when the receiving task is nil\")\n        }\n        XCTAssertEqual(receivingTask, true)\n        client.status(.closed, closeCode: .goingAway, reason: nil)\n        let expectation1 = XCTestExpectation(description: \"Response delegate\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n            XCTAssertEqual(delegate.code, .goingAway)\n            XCTAssertNil(delegate.reason)\n            XCTAssertTrue(client.task.state == .completed)\n            XCTAssertNil(URLSession.liveQuery.receivingTasks[client.task])\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testCloseExternal() throws {\n        let client = try ParseLiveQuery()\n        guard let originalTask = client.task,\n              client.task.state == .running else {\n            throw XCTSkip(\"Skip this test when state is not running\")\n        }\n        // Only continue test if this is not nil, otherwise skip\n        guard let receivingTask = URLSession.liveQuery.receivingTasks[client.task] else {\n            throw XCTSkip(\"Skip this test when the receiving task is nil\")\n        }\n        XCTAssertEqual(receivingTask, true)\n        client.isSocketEstablished = true\n        client.isConnected = true\n        client.close()\n        let expectation1 = XCTestExpectation(description: \"Close external\")\n        client.synchronizationQueue.asyncAfter(deadline: .now() + 2) {\n            XCTAssertTrue(client.task.state == .suspended)\n            XCTAssertFalse(client.isSocketEstablished)\n            XCTAssertFalse(client.isConnected)\n            XCTAssertNil(URLSession.liveQuery.delegates[originalTask])\n            XCTAssertNil(URLSession.liveQuery.receivingTasks[originalTask])\n            XCTAssertNotNil(URLSession.liveQuery.delegates[client.task])\n            XCTAssertEqual(URLSession.liveQuery.receivingTasks[client.task], true)\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testCloseInternalUseQueue() throws {\n        let client = try ParseLiveQuery()\n        guard let originalTask = client.task,\n              client.task.state == .running else {\n            throw XCTSkip(\"Skip this test when state is not running\")\n        }\n        // Only continue test if this is not nil, otherwise skip\n        guard let receivingTask = URLSession.liveQuery.receivingTasks[client.task] else {\n            throw XCTSkip(\"Skip this test when the receiving task is nil\")\n        }\n        XCTAssertEqual(receivingTask, true)\n        client.isSocketEstablished = true\n        client.isConnected = true\n        client.close(useDedicatedQueue: true)\n        let expectation1 = XCTestExpectation(description: \"Close internal\")\n        client.synchronizationQueue.asyncAfter(deadline: .now() + 2) {\n            XCTAssertTrue(client.task.state == .suspended)\n            XCTAssertFalse(client.isSocketEstablished)\n            XCTAssertFalse(client.isConnected)\n            XCTAssertNil(URLSession.liveQuery.delegates[originalTask])\n            XCTAssertNil(URLSession.liveQuery.receivingTasks[originalTask])\n            XCTAssertNotNil(URLSession.liveQuery.delegates[client.task])\n            XCTAssertEqual(URLSession.liveQuery.receivingTasks[client.task], true)\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testCloseInternalDoNotUseQueue() throws {\n        let client = try ParseLiveQuery()\n        guard let originalTask = client.task,\n              client.task.state == .running else {\n            throw XCTSkip(\"Skip this test when state is not running\")\n        }\n        // Only continue test if this is not nil, otherwise skip\n        guard let receivingTask = URLSession.liveQuery.receivingTasks[client.task] else {\n            throw XCTSkip(\"Skip this test when the receiving task is nil\")\n        }\n        XCTAssertEqual(receivingTask, true)\n        client.isSocketEstablished = true\n        client.isConnected = true\n        client.close(useDedicatedQueue: false)\n        XCTAssertTrue(client.task.state == .suspended)\n        XCTAssertFalse(client.isSocketEstablished)\n        XCTAssertFalse(client.isConnected)\n        XCTAssertNil(URLSession.liveQuery.delegates[originalTask])\n        XCTAssertNil(URLSession.liveQuery.receivingTasks[originalTask])\n        XCTAssertNotNil(URLSession.liveQuery.delegates[client.task])\n        XCTAssertEqual(URLSession.liveQuery.receivingTasks[client.task], true)\n    }\n\n    func testCloseAll() throws {\n        let client = try ParseLiveQuery()\n        guard let originalTask = client.task,\n              client.task.state == .running else {\n            throw XCTSkip(\"Skip this test when state is not running\")\n        }\n        // Only continue test if this is not nil, otherwise skip\n        guard let receivingTask = URLSession.liveQuery.receivingTasks[client.task] else {\n            throw XCTSkip(\"Skip this test when the receiving task is nil\")\n        }\n        XCTAssertEqual(receivingTask, true)\n        client.isSocketEstablished = true\n        client.isConnected = true\n        client.closeAll()\n        let expectation1 = XCTestExpectation(description: \"Close all\")\n        client.synchronizationQueue.asyncAfter(deadline: .now() + 2) {\n            XCTAssertTrue(client.task.state == .suspended)\n            XCTAssertFalse(client.isSocketEstablished)\n            XCTAssertFalse(client.isConnected)\n            XCTAssertNil(URLSession.liveQuery.delegates[originalTask])\n            XCTAssertNil(URLSession.liveQuery.receivingTasks[originalTask])\n            XCTAssertNotNil(URLSession.liveQuery.delegates[client.task])\n            XCTAssertEqual(URLSession.liveQuery.receivingTasks[client.task], true)\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testPingSocketNotEstablished() throws {\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        client.close()\n        let expectation1 = XCTestExpectation(description: \"Send Ping\")\n        client.sendPing { error in\n            XCTAssertEqual(client.isSocketEstablished, false)\n            guard let urlError = error as? URLError else {\n                XCTFail(\"Should have casted to ParseError.\")\n                expectation1.fulfill()\n                return\n            }\n            // \"Could not connect to the server\"\n            // because webSocket connections are not intercepted.\n            XCTAssertTrue([-1004, -1022].contains(urlError.errorCode))\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testPing() throws {\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        client.isSocketEstablished = true // Socket needs to be true\n        client.isConnecting = true\n        client.isConnected = true\n        client.clientId = \"yolo\"\n\n        let expectation1 = XCTestExpectation(description: \"Send Ping\")\n        client.sendPing { error in\n            XCTAssertEqual(client.isSocketEstablished, true)\n            XCTAssertNotNil(error) // Should have error because testcases do not intercept websocket\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testRandomIdGenerator() throws {\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        for index in 1 ..< 50 {\n            let idGenerated = client.requestIdGenerator()\n            XCTAssertEqual(idGenerated.value, index)\n        }\n    }\n\n    func testSubscribeNotConnected() throws {\n        let query = GameScore.query(\"points\" > 9)\n        guard let subscription = query.subscribe else {\n            XCTFail(\"Should create subscription\")\n            return\n        }\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        XCTAssertEqual(subscription.query, query)\n        XCTAssertFalse(try client.isSubscribed(query))\n        XCTAssertTrue(try client.isPendingSubscription(query))\n        XCTAssertEqual(client.subscriptions.count, 0)\n        XCTAssertEqual(client.pendingSubscriptions.count, 1)\n        XCTAssertNoThrow(try client.removePendingSubscription(query))\n        XCTAssertEqual(client.pendingSubscriptions.count, 0)\n    }\n\n    func pretendToBeConnected() throws {\n        guard let client = ParseLiveQuery.defaultClient else {\n            throw ParseError(code: .unknownError,\n                             message: \"Should be able to get client\")\n        }\n        client.task = URLSession.liveQuery.createTask(client.url,\n                                                      taskDelegate: client)\n        client.status(.open)\n        let response = ConnectionResponse(op: .connected, clientId: \"yolo\", installationId: \"naw\")\n        let encoded = try ParseCoding.jsonEncoder().encode(response)\n        client.received(encoded)\n        // Only continue test if this is not nil, otherwise skip\n        guard let receivingTask = URLSession.liveQuery.receivingTasks[client.task],\n            receivingTask == true else {\n            throw XCTSkip(\"Skip this test when the receiving task is nil or not true\")\n        }\n    }\n\n    func testSubscribeConnected() throws {\n        let query = GameScore.query(\"points\" > 9)\n        guard let subscription = query.subscribe else {\n            XCTFail(\"Should create subscription\")\n            return\n        }\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        XCTAssertEqual(subscription.query, query)\n\n        let expectation1 = XCTestExpectation(description: \"Subscribe Handler\")\n        let expectation2 = XCTestExpectation(description: \"Unsubscribe Handler\")\n\n        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n\n            guard let subscribed = subscription.subscribed else {\n                XCTFail(\"Should unwrap subscribed.\")\n                expectation1.fulfill()\n                expectation2.fulfill()\n                return\n            }\n            XCTAssertEqual(query, subscribed.query)\n            XCTAssertTrue(subscribed.isNew)\n            XCTAssertNil(subscription.unsubscribed)\n            XCTAssertNil(subscription.event)\n\n            //Unsubscribe\n            DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n                guard let unsubscribed = subscription.unsubscribed else {\n                    XCTFail(\"Should unwrap unsubscribed.\")\n                    expectation2.fulfill()\n                    return\n                }\n                XCTAssertEqual(query, unsubscribed)\n                XCTAssertNil(subscription.subscribed)\n                XCTAssertNil(subscription.event)\n                expectation2.fulfill()\n            }\n\n            XCTAssertNotNil(try? query.unsubscribe())\n            XCTAssertEqual(client.pendingSubscriptions.count, 1)\n            XCTAssertEqual(client.subscriptions.count, 1)\n\n            //Received Unsubscribe\n            let response2 = PreliminaryMessageResponse(op: .unsubscribed,\n                                                       requestId: 1,\n                                                       clientId: \"yolo\",\n                                                       installationId: \"naw\")\n            guard let encoded2 = try? ParseCoding.jsonEncoder().encode(response2) else {\n                XCTFail(\"Should have encoded second response\")\n                expectation2.fulfill()\n                return\n            }\n            client.received(encoded2)\n            XCTAssertEqual(client.pendingSubscriptions.count, 0)\n            XCTAssertEqual(client.subscriptions.count, 0)\n            expectation1.fulfill()\n        }\n\n        XCTAssertFalse(try client.isSubscribed(query))\n        XCTAssertTrue(try client.isPendingSubscription(query))\n        XCTAssertEqual(client.subscriptions.count, 0)\n        XCTAssertEqual(client.pendingSubscriptions.count, 1)\n        try pretendToBeConnected()\n        let response = PreliminaryMessageResponse(op: .subscribed,\n                                                           requestId: 1,\n                                                           clientId: \"yolo\",\n                                                           installationId: \"naw\")\n        let encoded = try ParseCoding.jsonEncoder().encode(response)\n        client.received(encoded)\n        XCTAssertTrue(try client.isSubscribed(query))\n        XCTAssertFalse(try client.isPendingSubscription(query))\n        XCTAssertEqual(client.subscriptions.count, 1)\n        XCTAssertEqual(client.pendingSubscriptions.count, 0)\n\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testSubscribeCallbackConnected() throws {\n        let query = GameScore.query(\"points\" > 9)\n        let handler = SubscriptionCallback(query: query)\n        let subscription = try Query<GameScore>.subscribe(handler)\n\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        XCTAssertEqual(subscription.query, query)\n\n        let expectation1 = XCTestExpectation(description: \"Subscribe Handler\")\n        let expectation2 = XCTestExpectation(description: \"Unsubscribe Handler\")\n        subscription.handleSubscribe { subscribedQuery, isNew in\n            XCTAssertEqual(query, subscribedQuery)\n            XCTAssertTrue(isNew)\n            expectation1.fulfill()\n\n            //Unsubscribe\n            subscription.handleUnsubscribe { query in\n                XCTAssertEqual(query, subscribedQuery)\n                XCTAssertTrue(client.pendingSubscriptions.isEmpty)\n                XCTAssertTrue(client.subscriptions.isEmpty)\n                XCTAssertFalse(client.isSocketEstablished)\n                expectation2.fulfill()\n            }\n            XCTAssertNotNil(try? query.unsubscribe())\n            XCTAssertEqual(client.pendingSubscriptions.count, 1)\n            XCTAssertEqual(client.subscriptions.count, 1)\n\n            //Received Unsubscribe\n            let response2 = PreliminaryMessageResponse(op: .unsubscribed,\n                                                               requestId: 1,\n                                                               clientId: \"yolo\",\n                                                               installationId: \"naw\")\n            guard let encoded2 = try? ParseCoding.jsonEncoder().encode(response2) else {\n                XCTFail(\"Should have encoded second response\")\n                expectation2.fulfill()\n                return\n            }\n            client.received(encoded2)\n            XCTAssertEqual(client.pendingSubscriptions.count, 0)\n            XCTAssertEqual(client.subscriptions.count, 0)\n        }\n\n        XCTAssertFalse(try client.isSubscribed(query))\n        XCTAssertTrue(try client.isPendingSubscription(query))\n        XCTAssertEqual(client.subscriptions.count, 0)\n        XCTAssertEqual(client.pendingSubscriptions.count, 1)\n        try pretendToBeConnected()\n        let response = PreliminaryMessageResponse(op: .subscribed,\n                                                           requestId: 1,\n                                                           clientId: \"yolo\",\n                                                           installationId: \"naw\")\n        let encoded = try ParseCoding.jsonEncoder().encode(response)\n        client.received(encoded)\n        XCTAssertTrue(try client.isSubscribed(query))\n        XCTAssertFalse(try client.isPendingSubscription(query))\n        XCTAssertEqual(client.subscriptions.count, 1)\n        XCTAssertEqual(client.pendingSubscriptions.count, 0)\n\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testSubscribeCloseSubscribe() throws {\n        let query = GameScore.query(\"points\" > 9)\n        let handler = SubscriptionCallback(query: query)\n        var subscription = try Query<GameScore>.subscribe(handler)\n\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        XCTAssertEqual(subscription.query, query)\n\n        let expectation1 = XCTestExpectation(description: \"Subscribe Handler\")\n        let expectation2 = XCTestExpectation(description: \"Resubscribe Handler\")\n        var count = 0\n        var originalTask: URLSessionWebSocketTask?\n        subscription.handleSubscribe { subscribedQuery, isNew in\n            XCTAssertEqual(query, subscribedQuery)\n            if count == 0 {\n                XCTAssertTrue(isNew)\n                XCTAssertEqual(client.pendingSubscriptions.count, 0)\n                XCTAssertEqual(client.subscriptions.count, 1)\n                XCTAssertNotNil(ParseLiveQuery.client?.task)\n                originalTask = ParseLiveQuery.client?.task\n                expectation1.fulfill()\n            } else {\n                XCTAssertNotNil(ParseLiveQuery.client?.task)\n                XCTAssertFalse(originalTask == ParseLiveQuery.client?.task)\n                expectation2.fulfill()\n                return\n            }\n\n            ParseLiveQuery.client?.close()\n            ParseLiveQuery.client?.synchronizationQueue.sync {\n            if let socketEstablished = ParseLiveQuery.client?.isSocketEstablished {\n                XCTAssertFalse(socketEstablished)\n            } else {\n                XCTFail(\"Should have socket that is not established\")\n                expectation2.fulfill()\n                return\n            }\n\n            //Resubscribe\n            do {\n                count += 1\n                subscription = try Query<GameScore>.subscribe(handler)\n            } catch {\n                XCTFail(\"\\(error)\")\n                expectation2.fulfill()\n                return\n            }\n\n            try? self.pretendToBeConnected()\n            let response2 = PreliminaryMessageResponse(op: .subscribed,\n                                                       requestId: 2,\n                                                       clientId: \"yolo\",\n                                                       installationId: \"naw\")\n            guard let encoded2 = try? ParseCoding.jsonEncoder().encode(response2) else {\n                XCTFail(\"Should have encoded second response\")\n                expectation2.fulfill()\n                return\n            }\n            client.received(encoded2)\n            }\n        }\n\n        XCTAssertFalse(try client.isSubscribed(query))\n        XCTAssertTrue(try client.isPendingSubscription(query))\n        XCTAssertEqual(client.subscriptions.count, 0)\n        XCTAssertEqual(client.pendingSubscriptions.count, 1)\n        try pretendToBeConnected()\n        let response = PreliminaryMessageResponse(op: .subscribed,\n                                                           requestId: 1,\n                                                           clientId: \"yolo\",\n                                                           installationId: \"naw\")\n        let encoded = try ParseCoding.jsonEncoder().encode(response)\n        client.received(encoded)\n        XCTAssertTrue(try client.isSubscribed(query))\n        XCTAssertFalse(try client.isPendingSubscription(query))\n        XCTAssertEqual(client.subscriptions.count, 1)\n        XCTAssertEqual(client.pendingSubscriptions.count, 0)\n\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testServerRedirectResponse() throws {\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n\n        guard let url = URL(string: \"wss://parse.com\") else {\n            XCTFail(\"should create url\")\n            return\n        }\n        XCTAssertNotEqual(client.url, url)\n        let response = RedirectResponse(op: .redirect, url: url)\n        let encoded = try ParseCoding.jsonEncoder().encode(response)\n        client.received(encoded)\n        XCTAssertEqual(client.url, url)\n    }\n\n    func testServerErrorResponse() throws {\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        let delegate = TestDelegate()\n        client.receiveDelegate = delegate\n        try pretendToBeConnected()\n        XCTAssertNil(delegate.error)\n        guard let url = URL(string: \"http://parse.com\") else {\n            XCTFail(\"should create url\")\n            return\n        }\n        XCTAssertNotEqual(client.url, url)\n        let response = ErrorResponse(op: .error, code: 1, message: \"message\", reconnect: true)\n        let encoded = try ParseCoding.jsonEncoder().encode(response)\n        client.received(encoded)\n        let expectation1 = XCTestExpectation(description: \"Response delegate\")\n        DispatchQueue.main.async {\n            XCTAssertNotNil(delegate.error)\n            XCTAssertEqual(delegate.error?.code, ParseError.Code.internalServer)\n            XCTAssertTrue(delegate.error?.message.contains(\"message\") != nil)\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testServerErrorResponseNoReconnect() throws {\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        let delegate = TestDelegate()\n        client.receiveDelegate = delegate\n        try pretendToBeConnected()\n        XCTAssertNil(delegate.error)\n        guard let url = URL(string: \"http://parse.com\") else {\n            XCTFail(\"should create url\")\n            return\n        }\n        XCTAssertNotEqual(client.url, url)\n        let response = ErrorResponse(op: .error, code: 1, message: \"message\", reconnect: false)\n        let encoded = try ParseCoding.jsonEncoder().encode(response)\n        client.received(encoded)\n        let expectation1 = XCTestExpectation(description: \"Response delegate\")\n        DispatchQueue.main.async {\n            XCTAssertNotNil(delegate.error)\n            XCTAssertEqual(delegate.error?.code, ParseError.Code.internalServer)\n            XCTAssertTrue(delegate.error?.message.contains(\"message\") != nil)\n            expectation1.fulfill()\n        }\n        let expectation2 = XCTestExpectation(description: \"Client closed\")\n        client.synchronizationQueue.asyncAfter(deadline: .now() + 2) {\n            XCTAssertTrue(client.isDisconnectedByUser)\n            XCTAssertFalse(client.isConnected)\n            XCTAssertFalse(client.isConnecting)\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testEventEnter() throws {\n        let query = GameScore.query(\"points\" > 9)\n        guard let subscription = query.subscribe else {\n            XCTFail(\"Should create subscription\")\n            return\n        }\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        XCTAssertEqual(subscription.query, query)\n\n        let score = GameScore(points: 10)\n        let expectation1 = XCTestExpectation(description: \"Subscribe Handler\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n            guard let event = subscription.event else {\n                XCTFail(\"Should unwrap\")\n                expectation1.fulfill()\n                return\n            }\n            XCTAssertEqual(query, event.query)\n            XCTAssertNil(subscription.subscribed)\n            XCTAssertNil(subscription.unsubscribed)\n\n            switch event.event {\n\n            case .entered(let enter):\n                XCTAssertEqual(enter, score)\n            default:\n                XCTFail(\"Should have receeived event\")\n            }\n            expectation1.fulfill()\n        }\n\n        try pretendToBeConnected()\n        let response = PreliminaryMessageResponse(op: .subscribed,\n                                                           requestId: 1,\n                                                           clientId: \"yolo\",\n                                                           installationId: \"naw\")\n        let encoded = try ParseCoding.jsonEncoder().encode(response)\n        client.received(encoded)\n\n        let response2 = EventResponse(op: .enter,\n                                      requestId: 1,\n                                      object: score,\n                                      clientId: \"yolo\",\n                                      installationId: \"naw\")\n        let encoded2 = try ParseCoding.jsonEncoder().encode(response2)\n        client.received(encoded2)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testEventLeave() throws {\n        let query = GameScore.query(\"points\" > 9)\n        guard let subscription = query.subscribe else {\n            XCTFail(\"Should create subscription\")\n            return\n        }\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        XCTAssertEqual(subscription.query, query)\n\n        let score = GameScore(points: 10)\n        let expectation1 = XCTestExpectation(description: \"Subscribe Handler\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n            guard let event = subscription.event else {\n                XCTFail(\"Should unwrap\")\n                expectation1.fulfill()\n                return\n            }\n            XCTAssertEqual(query, event.query)\n            XCTAssertNil(subscription.subscribed)\n            XCTAssertNil(subscription.unsubscribed)\n\n            switch event.event {\n\n            case .left(let enter):\n                XCTAssertEqual(enter, score)\n            default:\n                XCTFail(\"Should have receeived event\")\n            }\n            expectation1.fulfill()\n        }\n\n        try pretendToBeConnected()\n        let response = PreliminaryMessageResponse(op: .subscribed,\n                                                           requestId: 1,\n                                                           clientId: \"yolo\",\n                                                           installationId: \"naw\")\n        let encoded = try ParseCoding.jsonEncoder().encode(response)\n        client.received(encoded)\n\n        let response2 = EventResponse(op: .leave,\n                                      requestId: 1,\n                                      object: score,\n                                      clientId: \"yolo\",\n                                      installationId: \"naw\")\n        let encoded2 = try ParseCoding.jsonEncoder().encode(response2)\n        client.received(encoded2)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testEventCreate() throws {\n        let query = GameScore.query(\"points\" > 9)\n        guard let subscription = query.subscribe else {\n            XCTFail(\"Should create subscription\")\n            return\n        }\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        XCTAssertEqual(subscription.query, query)\n\n        let score = GameScore(points: 10)\n        let expectation1 = XCTestExpectation(description: \"Subscribe Handler\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n            guard let event = subscription.event else {\n                XCTFail(\"Should unwrap\")\n                expectation1.fulfill()\n                return\n            }\n            XCTAssertEqual(query, event.query)\n            XCTAssertNil(subscription.subscribed)\n            XCTAssertNil(subscription.unsubscribed)\n\n            switch event.event {\n\n            case .created(let enter):\n                XCTAssertEqual(enter, score)\n            default:\n                XCTFail(\"Should have receeived event\")\n            }\n            expectation1.fulfill()\n        }\n\n        try pretendToBeConnected()\n        let response = PreliminaryMessageResponse(op: .subscribed,\n                                                           requestId: 1,\n                                                           clientId: \"yolo\",\n                                                           installationId: \"naw\")\n        let encoded = try ParseCoding.jsonEncoder().encode(response)\n        client.received(encoded)\n\n        let response2 = EventResponse(op: .create,\n                                      requestId: 1,\n                                      object: score,\n                                      clientId: \"yolo\",\n                                      installationId: \"naw\")\n        let encoded2 = try ParseCoding.jsonEncoder().encode(response2)\n        client.received(encoded2)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testEventUpdate() throws {\n        let query = GameScore.query(\"points\" > 9)\n        guard let subscription = query.subscribe else {\n            XCTFail(\"Should create subscription\")\n            return\n        }\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        XCTAssertEqual(subscription.query, query)\n        XCTAssertNil(subscription.subscribed)\n        XCTAssertNil(subscription.unsubscribed)\n\n        let score = GameScore(points: 10)\n        let expectation1 = XCTestExpectation(description: \"Subscribe Handler\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n            guard let event = subscription.event else {\n                XCTFail(\"Should unwrap\")\n                expectation1.fulfill()\n                return\n            }\n            XCTAssertEqual(query, event.query)\n\n            switch event.event {\n\n            case .updated(let enter):\n                XCTAssertEqual(enter, score)\n            default:\n                XCTFail(\"Should have receeived event\")\n            }\n            expectation1.fulfill()\n        }\n\n        try pretendToBeConnected()\n        let response = PreliminaryMessageResponse(op: .subscribed,\n                                                           requestId: 1,\n                                                           clientId: \"yolo\",\n                                                           installationId: \"naw\")\n        let encoded = try ParseCoding.jsonEncoder().encode(response)\n        client.received(encoded)\n\n        let response2 = EventResponse(op: .update,\n                                      requestId: 1,\n                                      object: score,\n                                      clientId: \"yolo\",\n                                      installationId: \"naw\")\n        let encoded2 = try ParseCoding.jsonEncoder().encode(response2)\n        client.received(encoded2)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testEventDelete() throws {\n        let query = GameScore.query(\"points\" > 9)\n        guard let subscription = query.subscribe else {\n            XCTFail(\"Should create subscription\")\n            return\n        }\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        XCTAssertEqual(subscription.query, query)\n\n        let score = GameScore(points: 10)\n        let expectation1 = XCTestExpectation(description: \"Subscribe Handler\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n            guard let event = subscription.event else {\n                XCTFail(\"Should unwrap\")\n                expectation1.fulfill()\n                return\n            }\n            XCTAssertEqual(query, event.query)\n            XCTAssertNil(subscription.subscribed)\n            XCTAssertNil(subscription.unsubscribed)\n\n            switch event.event {\n\n            case .deleted(let enter):\n                XCTAssertEqual(enter, score)\n            default:\n                XCTFail(\"Should have receeived event\")\n            }\n            expectation1.fulfill()\n        }\n\n        try pretendToBeConnected()\n        let response = PreliminaryMessageResponse(op: .subscribed,\n                                                           requestId: 1,\n                                                           clientId: \"yolo\",\n                                                           installationId: \"naw\")\n        let encoded = try ParseCoding.jsonEncoder().encode(response)\n        client.received(encoded)\n\n        let response2 = EventResponse(op: .delete,\n                                      requestId: 1,\n                                      object: score,\n                                      clientId: \"yolo\",\n                                      installationId: \"naw\")\n        let encoded2 = try ParseCoding.jsonEncoder().encode(response2)\n        client.received(encoded2)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSubscriptionUpdate() throws {\n        let query = GameScore.query(\"points\" > 9)\n        guard let subscription = query.subscribe else {\n            XCTFail(\"Should create subscription\")\n            return\n        }\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        XCTAssertEqual(subscription.query, query)\n        XCTAssertNil(subscription.event)\n        XCTAssertNil(subscription.unsubscribed)\n\n        let expectation1 = XCTestExpectation(description: \"Subscribe Handler\")\n        let expectation2 = XCTestExpectation(description: \"Unsubscribe Handler\")\n        var count = 0\n        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n            guard let subscribed = subscription.subscribed else {\n                XCTFail(\"Should unwrap\")\n                expectation1.fulfill()\n                expectation2.fulfill()\n                return\n            }\n\n            XCTAssertEqual(query, subscribed.query)\n            if count == 0 {\n                XCTAssertTrue(subscribed.isNew)\n                count += 1\n                expectation1.fulfill()\n            }\n\n            //Update\n            DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n                guard let subscribed = subscription.subscribed else {\n                    XCTFail(\"Should unwrap\")\n                    expectation2.fulfill()\n                    return\n                }\n\n                XCTAssertFalse(subscribed.isNew)\n                XCTAssertEqual(client.subscriptions.count, 1)\n                XCTAssertEqual(client.pendingSubscriptions.count, 0)\n                expectation2.fulfill()\n                return\n            }\n            XCTAssertNotNil(try? query.update(subscription))\n\n            guard let isSubscribed = try? client.isSubscribed(query),\n                  let isPending = try? client.isPendingSubscription(query) else {\n                XCTFail(\"Shound unwrap\")\n                return\n            }\n            XCTAssertTrue(isSubscribed)\n            XCTAssertTrue(isPending)\n            XCTAssertEqual(client.subscriptions.count, 1)\n            XCTAssertEqual(client.pendingSubscriptions.count, 1)\n\n            let response = PreliminaryMessageResponse(op: .subscribed,\n                                                               requestId: 1,\n                                                               clientId: \"yolo\",\n                                                               installationId: \"naw\")\n            guard let encoded = try? ParseCoding.jsonEncoder().encode(response) else {\n                XCTFail(\"Should encode\")\n                return\n            }\n            client.received(encoded)\n        }\n\n        XCTAssertFalse(try client.isSubscribed(query))\n        XCTAssertTrue(try client.isPendingSubscription(query))\n        XCTAssertEqual(client.subscriptions.count, 0)\n        XCTAssertEqual(client.pendingSubscriptions.count, 1)\n        try pretendToBeConnected()\n        let response = PreliminaryMessageResponse(op: .subscribed,\n                                                           requestId: 1,\n                                                           clientId: \"yolo\",\n                                                           installationId: \"naw\")\n        let encoded = try ParseCoding.jsonEncoder().encode(response)\n        client.received(encoded)\n        XCTAssertTrue(try client.isSubscribed(query))\n        XCTAssertFalse(try client.isPendingSubscription(query))\n        XCTAssertEqual(client.subscriptions.count, 1)\n        XCTAssertEqual(client.pendingSubscriptions.count, 0)\n\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testResubscribing() throws {\n        let query = GameScore.query(\"points\" > 9)\n        guard let subscription = query.subscribe else {\n            XCTFail(\"Should create subscription\")\n            return\n        }\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        XCTAssertEqual(subscription.query, query)\n\n        let expectation1 = XCTestExpectation(description: \"Subscribe Handler\")\n        let expectation2 = XCTestExpectation(description: \"Unsubscribe Handler\")\n        var count = 0\n        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n            guard let subscribed = subscription.subscribed else {\n                XCTFail(\"Should unwrap\")\n                expectation1.fulfill()\n                expectation2.fulfill()\n                return\n            }\n            if count == 0 {\n                XCTAssertTrue(subscribed.isNew)\n                XCTAssertNil(subscription.event)\n                XCTAssertNil(subscription.unsubscribed)\n                count += 1\n                expectation1.fulfill()\n            }\n\n            //Disconnect, subscriptions should remain the same\n            client.isConnected = false\n            XCTAssertEqual(client.subscriptions.count, 1)\n            XCTAssertEqual(client.pendingSubscriptions.count, 0)\n\n            //Connect moving to true should move to pending\n            client.clientId = \"naw\"\n            client.isConnected = true\n            XCTAssertEqual(client.subscriptions.count, 0)\n            XCTAssertEqual(client.pendingSubscriptions.count, 1)\n\n            DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n                guard let subscribed = subscription.subscribed else {\n                    XCTFail(\"Should unwrap\")\n                    expectation2.fulfill()\n                    return\n                }\n\n                XCTAssertTrue(subscribed.isNew)\n                XCTAssertNil(subscription.event)\n                XCTAssertNil(subscription.unsubscribed)\n                XCTAssertEqual(client.subscriptions.count, 1)\n                XCTAssertEqual(client.pendingSubscriptions.count, 0)\n                expectation2.fulfill()\n                return\n            }\n\n            //Fake server response\n            let response = PreliminaryMessageResponse(op: .subscribed,\n                                                               requestId: 1,\n                                                               clientId: \"yolo\",\n                                                               installationId: \"naw\")\n            guard let encoded = try? ParseCoding.jsonEncoder().encode(response) else {\n                XCTFail(\"Should have encoded\")\n                return\n            }\n            client.received(encoded)\n        }\n\n        XCTAssertFalse(try client.isSubscribed(query))\n        XCTAssertTrue(try client.isPendingSubscription(query))\n        XCTAssertEqual(client.subscriptions.count, 0)\n        XCTAssertEqual(client.pendingSubscriptions.count, 1)\n        try pretendToBeConnected()\n        let response = PreliminaryMessageResponse(op: .subscribed,\n                                                           requestId: 1,\n                                                           clientId: \"yolo\",\n                                                           installationId: \"naw\")\n        let encoded = try ParseCoding.jsonEncoder().encode(response)\n        client.received(encoded)\n        XCTAssertTrue(try client.isSubscribed(query))\n        XCTAssertFalse(try client.isPendingSubscription(query))\n        XCTAssertEqual(client.subscriptions.count, 1)\n        XCTAssertEqual(client.pendingSubscriptions.count, 0)\n\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testEventEnterSubscriptionCallback() throws {\n        let query = GameScore.query(\"points\" > 9)\n        let handler = SubscriptionCallback(query: query)\n        let subscription = try Query<GameScore>.subscribe(handler)\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        XCTAssertEqual(subscription.query, query)\n\n        let score = GameScore(points: 10)\n        let expectation1 = XCTestExpectation(description: \"Subscribe Handler\")\n        subscription.handleEvent { subscribedQuery, event in\n            XCTAssertEqual(query, subscribedQuery)\n\n            switch event {\n\n            case .entered(let enter):\n                XCTAssertEqual(enter, score)\n            default:\n                XCTFail(\"Should have receeived event\")\n            }\n            expectation1.fulfill()\n        }\n\n        try pretendToBeConnected()\n        let response = PreliminaryMessageResponse(op: .subscribed,\n                                                           requestId: 1,\n                                                           clientId: \"yolo\",\n                                                           installationId: \"naw\")\n        let encoded = try ParseCoding.jsonEncoder().encode(response)\n        client.received(encoded)\n\n        let response2 = EventResponse(op: .enter,\n                                      requestId: 1,\n                                      object: score,\n                                      clientId: \"yolo\",\n                                      installationId: \"naw\")\n        let encoded2 = try ParseCoding.jsonEncoder().encode(response2)\n        client.received(encoded2)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testEventLeaveSubscriptioinCallback() throws {\n        let query = GameScore.query(\"points\" > 9)\n        let handler = SubscriptionCallback(query: query)\n        let subscription = try Query<GameScore>.subscribe(handler)\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        XCTAssertEqual(subscription.query, query)\n\n        let score = GameScore(points: 10)\n        let expectation1 = XCTestExpectation(description: \"Subscribe Handler\")\n        subscription.handleEvent { subscribedQuery, event in\n            XCTAssertEqual(query, subscribedQuery)\n\n            switch event {\n\n            case .left(let enter):\n                XCTAssertEqual(enter, score)\n            default:\n                XCTFail(\"Should have receeived event\")\n            }\n            expectation1.fulfill()\n        }\n\n        try pretendToBeConnected()\n        let response = PreliminaryMessageResponse(op: .subscribed,\n                                                  requestId: 1,\n                                                  clientId: \"yolo\",\n                                                  installationId: \"naw\")\n        let encoded = try ParseCoding.jsonEncoder().encode(response)\n        client.received(encoded)\n\n        let response2 = EventResponse(op: .leave,\n                                      requestId: 1,\n                                      object: score,\n                                      clientId: \"yolo\",\n                                      installationId: \"naw\")\n        let encoded2 = try ParseCoding.jsonEncoder().encode(response2)\n        client.received(encoded2)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testEventCreateSubscriptionCallback() throws {\n        let query = GameScore.query(\"points\" > 9)\n        let handler = SubscriptionCallback(query: query)\n        let subscription = try Query<GameScore>.subscribe(handler)\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        XCTAssertEqual(subscription.query, query)\n\n        let score = GameScore(points: 10)\n        let expectation1 = XCTestExpectation(description: \"Subscribe Handler\")\n        subscription.handleEvent { subscribedQuery, event in\n            XCTAssertEqual(query, subscribedQuery)\n\n            switch event {\n\n            case .created(let enter):\n                XCTAssertEqual(enter, score)\n            default:\n                XCTFail(\"Should have receeived event\")\n            }\n            expectation1.fulfill()\n        }\n\n        try pretendToBeConnected()\n        let response = PreliminaryMessageResponse(op: .subscribed,\n                                                           requestId: 1,\n                                                           clientId: \"yolo\",\n                                                           installationId: \"naw\")\n        let encoded = try ParseCoding.jsonEncoder().encode(response)\n        client.received(encoded)\n\n        let response2 = EventResponse(op: .create,\n                                      requestId: 1,\n                                      object: score,\n                                      clientId: \"yolo\",\n                                      installationId: \"naw\")\n        let encoded2 = try ParseCoding.jsonEncoder().encode(response2)\n        client.received(encoded2)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testEventUpdateSubscriptionCallback() throws {\n        let query = GameScore.query(\"points\" > 9)\n        let handler = SubscriptionCallback(query: query)\n        let subscription = try Query<GameScore>.subscribe(handler)\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        XCTAssertEqual(subscription.query, query)\n\n        let score = GameScore(points: 10)\n        let expectation1 = XCTestExpectation(description: \"Subscribe Handler\")\n        subscription.handleEvent { subscribedQuery, event in\n            XCTAssertEqual(query, subscribedQuery)\n\n            switch event {\n\n            case .updated(let enter):\n                XCTAssertEqual(enter, score)\n            default:\n                XCTFail(\"Should have receeived event\")\n            }\n            expectation1.fulfill()\n        }\n\n        try pretendToBeConnected()\n        let response = PreliminaryMessageResponse(op: .subscribed,\n                                                  requestId: 1,\n                                                  clientId: \"yolo\",\n                                                  installationId: \"naw\")\n        let encoded = try ParseCoding.jsonEncoder().encode(response)\n        client.received(encoded)\n\n        let response2 = EventResponse(op: .update,\n                                      requestId: 1,\n                                      object: score,\n                                      clientId: \"yolo\",\n                                      installationId: \"naw\")\n        let encoded2 = try ParseCoding.jsonEncoder().encode(response2)\n        client.received(encoded2)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testEventDeleteSubscriptionCallback() throws {\n        let query = GameScore.query(\"points\" > 9)\n        let handler = SubscriptionCallback(query: query)\n        let subscription = try Query<GameScore>.subscribe(handler)\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        XCTAssertEqual(subscription.query, query)\n\n        let score = GameScore(points: 10)\n        let expectation1 = XCTestExpectation(description: \"Subscribe Handler\")\n        subscription.handleEvent { subscribedQuery, event in\n            XCTAssertEqual(query, subscribedQuery)\n\n            switch event {\n\n            case .deleted(let enter):\n                XCTAssertEqual(enter, score)\n            default:\n                XCTFail(\"Should have receeived event\")\n            }\n            expectation1.fulfill()\n        }\n\n        try pretendToBeConnected()\n        let response = PreliminaryMessageResponse(op: .subscribed,\n                                                           requestId: 1,\n                                                           clientId: \"yolo\",\n                                                           installationId: \"naw\")\n        let encoded = try ParseCoding.jsonEncoder().encode(response)\n        client.received(encoded)\n\n        let response2 = EventResponse(op: .delete,\n                                      requestId: 1,\n                                      object: score,\n                                      clientId: \"yolo\",\n                                      installationId: \"naw\")\n        let encoded2 = try ParseCoding.jsonEncoder().encode(response2)\n        client.received(encoded2)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSubscriptionUpdateSubscriptionCallback() throws {\n        let query = GameScore.query(\"points\" > 9)\n        let handler = SubscriptionCallback(query: query)\n        let subscription = try Query<GameScore>.subscribe(handler)\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        XCTAssertEqual(subscription.query, query)\n\n        let expectation1 = XCTestExpectation(description: \"Subscribe Handler\")\n        let expectation2 = XCTestExpectation(description: \"Unsubscribe Handler\")\n        var count = 0\n        subscription.handleSubscribe { subscribedQuery, isNew in\n            XCTAssertEqual(query, subscribedQuery)\n            if count == 0 {\n                XCTAssertTrue(isNew)\n                count += 1\n                expectation1.fulfill()\n            } else {\n                XCTAssertFalse(isNew)\n                XCTAssertEqual(client.subscriptions.count, 1)\n                XCTAssertEqual(client.pendingSubscriptions.count, 0)\n                expectation2.fulfill()\n                return\n            }\n\n            //Update\n            XCTAssertNotNil(try? query.update(subscription))\n\n            guard let isSubscribed = try? client.isSubscribed(query),\n                  let isPending = try? client.isPendingSubscription(query) else {\n                XCTFail(\"Shound unwrap\")\n                expectation1.fulfill()\n                expectation2.fulfill()\n                return\n            }\n            XCTAssertTrue(isSubscribed)\n            XCTAssertTrue(isPending)\n            XCTAssertEqual(client.subscriptions.count, 1)\n            XCTAssertEqual(client.pendingSubscriptions.count, 1)\n\n            let response = PreliminaryMessageResponse(op: .subscribed,\n                                                               requestId: 1,\n                                                               clientId: \"yolo\",\n                                                               installationId: \"naw\")\n            guard let encoded = try? ParseCoding.jsonEncoder().encode(response) else {\n                XCTFail(\"Should encode\")\n                expectation1.fulfill()\n                expectation2.fulfill()\n                return\n            }\n            client.received(encoded)\n        }\n\n        XCTAssertFalse(try client.isSubscribed(query))\n        XCTAssertTrue(try client.isPendingSubscription(query))\n        XCTAssertEqual(client.subscriptions.count, 0)\n        XCTAssertEqual(client.pendingSubscriptions.count, 1)\n        try pretendToBeConnected()\n        let response = PreliminaryMessageResponse(op: .subscribed,\n                                                           requestId: 1,\n                                                           clientId: \"yolo\",\n                                                           installationId: \"naw\")\n        let encoded = try ParseCoding.jsonEncoder().encode(response)\n        client.received(encoded)\n        XCTAssertTrue(try client.isSubscribed(query))\n        XCTAssertFalse(try client.isPendingSubscription(query))\n        XCTAssertEqual(client.subscriptions.count, 1)\n        XCTAssertEqual(client.pendingSubscriptions.count, 0)\n\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testResubscribingSubscriptionCallback() throws {\n        let query = GameScore.query(\"points\" > 9)\n        let handler = SubscriptionCallback(query: query)\n        let subscription = try Query<GameScore>.subscribe(handler)\n        guard let client = ParseLiveQuery.defaultClient else {\n            XCTFail(\"Should be able to get client\")\n            return\n        }\n        XCTAssertEqual(subscription.query, query)\n\n        let expectation1 = XCTestExpectation(description: \"Subscribe Handler\")\n        let expectation2 = XCTestExpectation(description: \"Unsubscribe Handler\")\n        var count = 0\n        subscription.handleSubscribe { subscribedQuery, isNew in\n            XCTAssertEqual(query, subscribedQuery)\n            if count == 0 {\n                XCTAssertTrue(isNew)\n                count += 1\n                expectation1.fulfill()\n            } else {\n                XCTAssertTrue(isNew)\n                XCTAssertEqual(client.subscriptions.count, 1)\n                XCTAssertEqual(client.pendingSubscriptions.count, 0)\n                expectation2.fulfill()\n                return\n            }\n\n            //Disconnect, subscriptions should remain the same\n            client.isConnected = false\n            XCTAssertEqual(client.subscriptions.count, 1)\n            XCTAssertEqual(client.pendingSubscriptions.count, 0)\n\n            //Connect moving to true should move to pending\n            client.clientId = \"naw\"\n            client.isConnected = true\n            XCTAssertEqual(client.subscriptions.count, 0)\n            XCTAssertEqual(client.pendingSubscriptions.count, 1)\n\n            //Fake server response\n            let response = PreliminaryMessageResponse(op: .subscribed,\n                                                               requestId: 1,\n                                                               clientId: \"yolo\",\n                                                               installationId: \"naw\")\n            guard let encoded = try? ParseCoding.jsonEncoder().encode(response) else {\n                XCTFail(\"Should have encoded\")\n                expectation1.fulfill()\n                expectation2.fulfill()\n                return\n            }\n            client.received(encoded)\n        }\n\n        XCTAssertFalse(try client.isSubscribed(query))\n        XCTAssertTrue(try client.isPendingSubscription(query))\n        XCTAssertEqual(client.subscriptions.count, 0)\n        XCTAssertEqual(client.pendingSubscriptions.count, 1)\n        try pretendToBeConnected()\n        let response = PreliminaryMessageResponse(op: .subscribed,\n                                                           requestId: 1,\n                                                           clientId: \"yolo\",\n                                                           installationId: \"naw\")\n        let encoded = try ParseCoding.jsonEncoder().encode(response)\n        client.received(encoded)\n        XCTAssertTrue(try client.isSubscribed(query))\n        XCTAssertFalse(try client.isPendingSubscription(query))\n        XCTAssertEqual(client.subscriptions.count, 1)\n        XCTAssertEqual(client.pendingSubscriptions.count, 0)\n\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseObjectAsyncTests.swift",
    "content": "//\n//  ParseObjectAsyncTests.swift\n//  ParseObjectAsyncTests\n//\n//  Created by Corey Baker on 8/6/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseObjectAsyncTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct GameScore: ParseObject {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int?\n        var player: String?\n        var level: Level?\n        var levels: [Level]?\n        var nextLevel: Level?\n\n        //: Implement your own version of merge\n        func merge(with object: Self) throws -> Self {\n            var updated = try mergeParse(with: object)\n            if updated.shouldRestoreKey(\\.points,\n                                         original: object) {\n                updated.points = object.points\n            }\n            if updated.shouldRestoreKey(\\.player,\n                                         original: object) {\n                updated.player = object.player\n            }\n            return updated\n        }\n\n        init() { }\n\n        //custom initializers\n        init (objectId: String?) {\n            self.objectId = objectId\n        }\n        init(points: Int) {\n            self.points = points\n            self.player = \"Jen\"\n        }\n        init(points: Int, name: String) {\n            self.points = points\n            self.player = name\n        }\n    }\n\n    struct Level: ParseObject {\n        var objectId: String?\n\n        var createdAt: Date?\n\n        var updatedAt: Date?\n\n        var ACL: ParseACL?\n\n        var name: String?\n\n        var originalData: Data?\n    }\n\n    struct GameScoreDefaultMerge: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int?\n        var player: String?\n        var level: Level?\n        var levels: [Level]?\n        var nextLevel: Level?\n\n        //: custom initializers\n        init() {}\n\n        init(objectId: String?) {\n            self.objectId = objectId\n        }\n        init(points: Int) {\n            self.points = points\n            self.player = \"Jen\"\n        }\n        init(points: Int, name: String) {\n            self.points = points\n            self.player = name\n        }\n    }\n\n    struct GameScoreDefault: ParseObject {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n    }\n\n    struct Game: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var gameScore: GameScore\n        var gameScores = [GameScore]()\n        var name = \"Hello\"\n        var profilePicture: ParseFile?\n\n        //: a custom initializer\n        init() {\n            self.gameScore = GameScore()\n        }\n\n        init(gameScore: GameScore) {\n            self.gameScore = gameScore\n        }\n    }\n\n    struct Game2: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var name = \"Hello\"\n        var profilePicture: ParseFile?\n    }\n\n    final class GameScoreClass: ParseObject {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int\n        var player = \"Jen\"\n        var level: Level?\n        var levels: [Level]?\n        var game: GameClass?\n\n        //: a custom initializer\n        required init() {\n            self.points = 5\n        }\n\n        init(points: Int) {\n            self.points = points\n        }\n\n        /**\n         Conforms to Equatable by determining if an object has the same objectId.\n         - note: You can specify a custom way of `Equatable` if a more  detailed way is needed.\n         - warning: If you use the default implementation, equatable will only work if the ParseObject\n         has been previously synced to the parse-server (has an objectId). In addition, if two\n         `ParseObject`'s have the same objectId, but were modified at different times, the\n         default implementation will still return true. In these cases you either want to use a\n         \"struct\" (value types) to make your `ParseObject`s instead of a class (reference type) or\n         provide your own implementation of `==`.\n         - parameter lhs: first object to compare\n         - parameter rhs: second object to compare\n\n         - returns: Returns a **true** if the other object has the same `objectId` or **false** if unsuccessful.\n        */\n        public static func == (lhs: ParseObjectAsyncTests.GameScoreClass,\n                               rhs: ParseObjectAsyncTests.GameScoreClass) -> Bool {\n            lhs.hasSameObjectId(as: rhs)\n        }\n\n        /**\n         Conforms to `Hashable` using objectId.\n         - note: You can specify a custom way of `Hashable` if a more  detailed way is needed.\n         - warning: If you use the default implementation, hash will only work if the ParseObject has been previously\n         synced to the parse-server (has an objectId). In addition, if two `ParseObject`'s have the same objectId,\n         but were modified at different times, the default implementation will hash to the same value. In these\n         cases you either want to use a \"struct\" (value types) to make your `ParseObject`s instead of a\n         class (reference type) or provide your own implementation of `hash`.\n\n        */\n        public func hash(into hasher: inout Hasher) {\n            hasher.combine(self.id)\n        }\n    }\n\n    final class GameClass: ParseObject {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var gameScore: GameScoreClass\n        var gameScores = [GameScore]()\n        var name = \"Hello\"\n\n        //: a custom initializer\n        required init() {\n            self.gameScore = GameScoreClass()\n        }\n\n        init(gameScore: GameScoreClass) {\n            self.gameScore = gameScore\n        }\n\n        /**\n         Conforms to Equatable by determining if an object has the same objectId.\n         - note: You can specify a custom way of `Equatable` if a more  detailed way is needed.\n         - warning: If you use the default implementation, equatable will only work if the ParseObject\n         has been previously synced to the parse-server (has an objectId). In addition, if two\n         `ParseObject`'s have the same objectId, but were modified at different times, the\n         default implementation will still return true. In these cases you either want to use a\n         \"struct\" (value types) to make your `ParseObject`s instead of a class (reference type) or\n         provide your own implementation of `==`.\n         - parameter lhs: first object to compare\n         - parameter rhs: second object to compare\n\n         - returns: Returns a **true** if the other object has the same `objectId` or **false** if unsuccessful.\n        */\n        public static func == (lhs: ParseObjectAsyncTests.GameClass,\n                               rhs: ParseObjectAsyncTests.GameClass) -> Bool {\n            lhs.hasSameObjectId(as: rhs)\n        }\n\n        /**\n         Conforms to `Hashable` using objectId.\n         - note: You can specify a custom way of `Hashable` if a more  detailed way is needed.\n         - warning: If you use the default implementation, hash will only work if the ParseObject has been previously\n         synced to the parse-server (has an objectId). In addition, if two `ParseObject`'s have the same objectId,\n         but were modified at different times, the default implementation will hash to the same value. In these\n         cases you either want to use a \"struct\" (value types) to make your `ParseObject`s instead of a\n         class (reference type) or provide your own implementation of `hash`.\n\n        */\n        public func hash(into hasher: inout Hasher) {\n            hasher.combine(self.id)\n        }\n    }\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func loginNormally() async throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let user = try await User.login(username: \"parse\", password: \"user\")\n        MockURLProtocol.removeAll()\n        return user\n    }\n\n    @MainActor\n    func testFetch() async throws {\n        var score = GameScore(points: 10)\n        let objectId = \"yarr\"\n        score.objectId = objectId\n        let score2 = score\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n        let scoreOnServer2: GameScore!\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer2 = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let fetched = try await score2.fetch()\n        XCTAssert(fetched.hasSameObjectId(as: scoreOnServer2))\n        guard let fetchedCreatedAt = fetched.createdAt,\n            let fetchedUpdatedAt = fetched.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n        }\n        guard let originalCreatedAt = scoreOnServer2.createdAt,\n            let originalUpdatedAt = scoreOnServer2.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n        }\n        XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n        XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n        XCTAssertNil(fetched.ACL)\n    }\n\n    @MainActor\n    func testSave() async throws {\n        let score = GameScore(points: 10)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await score.save()\n        XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n        guard let savedCreatedAt = saved.createdAt,\n            let savedUpdatedAt = saved.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n        }\n        XCTAssertEqual(savedCreatedAt, scoreOnServer.createdAt)\n        XCTAssertEqual(savedUpdatedAt, scoreOnServer.createdAt)\n        XCTAssertEqual(saved.ACL, scoreOnServer.ACL)\n    }\n\n    @MainActor\n    func testSaveMutable() async throws {\n        var original = GameScore(points: 10)\n        original.objectId = \"yarr\"\n        original.player = \"beast\"\n\n        var originalResponse = original.mergeable\n        originalResponse.createdAt = nil\n        originalResponse.updatedAt = Calendar.current.date(byAdding: .init(day: 1), to: Date())\n\n        let encoded: Data!\n        do {\n            encoded = try originalResponse.getEncoder().encode(originalResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            originalResponse = try originalResponse.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        let response = originalResponse\n        var originalUpdated = original.mergeable\n        originalUpdated.points = 50\n        let updated = originalUpdated\n\n        do {\n            let saved = try await updated.save()\n            XCTAssertTrue(saved.hasSameObjectId(as: response))\n            XCTAssertEqual(saved.points, 50)\n            XCTAssertEqual(saved.player, original.player)\n            XCTAssertEqual(saved.createdAt, response.createdAt)\n            XCTAssertEqual(saved.updatedAt, response.updatedAt)\n            XCTAssertNil(saved.originalData)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    @MainActor\n    func testCreate() async throws {\n        let score = GameScore(points: 10)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await score.create()\n        XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n        guard let savedCreatedAt = saved.createdAt,\n            let savedUpdatedAt = saved.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n        }\n        guard let originalCreatedAt = scoreOnServer.createdAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n        }\n        XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n        XCTAssertEqual(savedUpdatedAt, originalCreatedAt)\n        XCTAssertEqual(saved.ACL, scoreOnServer.ACL)\n    }\n\n    @MainActor\n    func testReplaceCreated() async throws {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await score.replace()\n        XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n        guard let originalCreatedAt = scoreOnServer.createdAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n        }\n        XCTAssertEqual(saved.createdAt, originalCreatedAt)\n        XCTAssertEqual(saved.updatedAt, originalCreatedAt)\n        XCTAssertEqual(saved.ACL, scoreOnServer.ACL)\n    }\n\n    @MainActor\n    func testReplaceUpdated() async throws {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n\n        var scoreOnServer = score\n        scoreOnServer.updatedAt = Date()\n        scoreOnServer.ACL = nil\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await score.replace()\n        XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n        guard let savedUpdatedAt = saved.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n        }\n        guard let originalUpdatedAt = scoreOnServer.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n        }\n        XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n        XCTAssertEqual(saved.ACL, scoreOnServer.ACL)\n    }\n\n    @MainActor\n    func testReplaceClientMissingObjectId() async throws {\n        let score = GameScore(points: 10)\n        do {\n            _ = try await score.replace()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted to ParseError\")\n                return\n            }\n            XCTAssertEqual(parseError.code, .missingObjectId)\n        }\n    }\n\n    @MainActor\n    func testUpdate() async throws {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n\n        var scoreOnServer = score\n        scoreOnServer.updatedAt = Date()\n        scoreOnServer.ACL = nil\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await score.update()\n        XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n        guard let savedUpdatedAt = saved.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n        }\n        guard let originalUpdatedAt = scoreOnServer.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n        }\n        XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n        XCTAssertEqual(saved.ACL, scoreOnServer.ACL)\n    }\n\n    @MainActor\n    func testUpdateDefaultMerge() async throws {\n        var score = GameScoreDefaultMerge(points: 10)\n        score.objectId = \"yarr\"\n        var level = Level()\n        level.name = \"next\"\n        level.objectId = \"yolo\"\n        score.level = level\n\n        var scoreOnServer = score\n        scoreOnServer.updatedAt = Date()\n        scoreOnServer.ACL = nil\n        scoreOnServer.points = 50\n        scoreOnServer.player = \"Ali\"\n        level.objectId = \"nolo\"\n        scoreOnServer.level = level\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            // Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScoreDefaultMerge.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        score = score.set(\\.player, to: \"Ali\")\n            .set(\\.points, to: 50)\n            .set(\\.level, to: level)\n        let saved = try await score.update()\n        XCTAssertEqual(saved, scoreOnServer)\n    }\n\n    @MainActor\n    func testUpdateClientMissingObjectId() async throws {\n        let score = GameScore(points: 10)\n        do {\n            _ = try await score.update()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted to ParseError\")\n                return\n            }\n            XCTAssertEqual(parseError.code, .missingObjectId)\n        }\n    }\n\n    @MainActor\n    func testUpdateMutable() async throws {\n        var original = GameScore(points: 10)\n        original.objectId = \"yarr\"\n        original.player = \"beast\"\n\n        var originalResponse = original.mergeable\n        originalResponse.createdAt = nil\n        originalResponse.updatedAt = Calendar.current.date(byAdding: .init(day: 1), to: Date())\n\n        let encoded: Data!\n        do {\n            encoded = try originalResponse.getEncoder().encode(originalResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            originalResponse = try originalResponse.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        let response = originalResponse\n        var originalUpdated = original.mergeable\n        originalUpdated.points = 50\n        let updated = originalUpdated\n\n        do {\n            let saved = try await updated.update()\n            XCTAssertTrue(saved.hasSameObjectId(as: response))\n            XCTAssertEqual(saved.points, 50)\n            XCTAssertEqual(saved.player, original.player)\n            XCTAssertEqual(saved.createdAt, response.createdAt)\n            XCTAssertEqual(saved.updatedAt, response.updatedAt)\n            XCTAssertNil(saved.originalData)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    @MainActor\n    func testUpdateMutableDefault() async throws {\n        var original = GameScoreDefault()\n        original.objectId = \"yarr\"\n\n        var originalResponse = original.mergeable\n        originalResponse.createdAt = nil\n        originalResponse.updatedAt = Calendar.current.date(byAdding: .init(day: 1), to: Date())\n\n        let encoded: Data!\n        do {\n            encoded = try originalResponse.getEncoder().encode(originalResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            originalResponse = try originalResponse.getDecoder().decode(GameScoreDefault.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        let response = originalResponse\n        let originalUpdated = original.mergeable\n        let updated = originalUpdated\n\n        do {\n            let saved = try await updated.update()\n            XCTAssertTrue(saved.hasSameObjectId(as: response))\n            XCTAssertEqual(saved.createdAt, response.createdAt)\n            XCTAssertEqual(saved.updatedAt, response.updatedAt)\n            XCTAssertNil(saved.originalData)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    @MainActor\n    func testDelete() async throws {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        let score2 = score\n\n        let scoreOnServer = NoBody()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        try await score2.delete()\n    }\n\n    @MainActor\n    func testDeleteError() async throws {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        let score2 = score\n\n        let serverResponse = ParseError(code: .objectNotFound, message: \"not found\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            try await score2.delete()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n\n            guard let error = error as? ParseError else {\n                XCTFail(\"Should be ParseError\")\n                return\n            }\n            XCTAssertEqual(error.message, serverResponse.message)\n        }\n    }\n\n    @MainActor\n    func testFetchAll() async throws {\n        let score = GameScore(points: 10)\n        let score2 = GameScore(points: 20)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n        let scoreOnServerImmutable: GameScore!\n        let scoreOnServer2Immutable: GameScore!\n        var scoreOnServer2 = score2\n        scoreOnServer2.objectId = \"yolo\"\n        scoreOnServer2.createdAt = Calendar.current.date(byAdding: .init(day: -2), to: Date())\n        scoreOnServer2.updatedAt = scoreOnServer2.createdAt\n        scoreOnServer2.ACL = nil\n\n        let response = QueryResponse<GameScore>(results: [scoreOnServer, scoreOnServer2], count: 2)\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServerImmutable = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n           scoreOnServer2Immutable = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let fetched = try await [GameScore(objectId: \"yarr\"), GameScore(objectId: \"yolo\")].fetchAll()\n\n        XCTAssertEqual(fetched.count, 2)\n        guard let firstObject = try? fetched.first(where: {try $0.get().objectId == \"yarr\"}),\n            let secondObject = try? fetched.first(where: {try $0.get().objectId == \"yolo\"}) else {\n                XCTFail(\"Should unwrap\")\n                return\n        }\n\n        switch firstObject {\n\n        case .success(let first):\n            XCTAssert(first.hasSameObjectId(as: scoreOnServerImmutable))\n            guard let fetchedCreatedAt = first.createdAt,\n                let fetchedUpdatedAt = first.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalCreatedAt = scoreOnServerImmutable.createdAt,\n                let originalUpdatedAt = scoreOnServerImmutable.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n            XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(first.ACL)\n            XCTAssertEqual(first.points, scoreOnServerImmutable.points)\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n\n        switch secondObject {\n\n        case .success(let second):\n            XCTAssert(second.hasSameObjectId(as: scoreOnServer2Immutable))\n            guard let savedCreatedAt = second.createdAt,\n                let savedUpdatedAt = second.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalCreatedAt = scoreOnServer2Immutable.createdAt,\n                let originalUpdatedAt = scoreOnServer2Immutable.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n            XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(second.ACL)\n            XCTAssertEqual(second.points, scoreOnServer2Immutable.points)\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    @MainActor\n    func testSaveAll() async throws {\n        let score = GameScore(points: 10)\n        let score2 = GameScore(points: 20)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.objectId = \"yolo\"\n        scoreOnServer2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        scoreOnServer2.ACL = nil\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil),\n        BatchResponseItem<GameScore>(success: scoreOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n            scoreOnServer2 = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await [score, score2].saveAll()\n        XCTAssertEqual(saved.count, 2)\n        switch saved[0] {\n\n        case .success(let first):\n            XCTAssert(first.hasSameObjectId(as: scoreOnServer))\n            guard let savedCreatedAt = first.createdAt,\n                let savedUpdatedAt = first.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(savedCreatedAt, scoreOnServer.createdAt)\n            XCTAssertEqual(savedUpdatedAt, scoreOnServer.createdAt)\n            XCTAssertNil(first.ACL)\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n\n        switch saved[1] {\n\n        case .success(let second):\n            XCTAssert(second.hasSameObjectId(as: scoreOnServer2))\n            guard let savedCreatedAt = second.createdAt,\n                let savedUpdatedAt = second.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(savedCreatedAt, scoreOnServer2.createdAt)\n            XCTAssertEqual(savedUpdatedAt, scoreOnServer2.createdAt)\n            XCTAssertNil(second.ACL)\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    @MainActor\n    func testCreateAll() async throws {\n        let score = GameScore(points: 10)\n        let score2 = GameScore(points: 20)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.objectId = \"yolo\"\n        scoreOnServer2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        scoreOnServer2.ACL = nil\n        let scoreOnServerImmutable: GameScore!\n        let scoreOnServer2Immutable: GameScore!\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil),\n        BatchResponseItem<GameScore>(success: scoreOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            scoreOnServerImmutable = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n            scoreOnServer2Immutable = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await [score, score2].createAll()\n        XCTAssertEqual(saved.count, 2)\n        switch saved[0] {\n\n        case .success(let first):\n            XCTAssert(first.hasSameObjectId(as: scoreOnServerImmutable))\n            guard let savedCreatedAt = first.createdAt,\n                let savedUpdatedAt = first.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalCreatedAt = scoreOnServerImmutable.createdAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n            XCTAssertEqual(savedUpdatedAt, originalCreatedAt)\n            XCTAssertNil(first.ACL)\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n\n        switch saved[1] {\n\n        case .success(let second):\n            XCTAssert(second.hasSameObjectId(as: scoreOnServer2Immutable))\n            guard let savedCreatedAt = second.createdAt,\n                let savedUpdatedAt = second.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalCreatedAt = scoreOnServer2Immutable.createdAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n            XCTAssertEqual(savedUpdatedAt, originalCreatedAt)\n            XCTAssertNil(second.ACL)\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    @MainActor\n    func testCreateAllServerMissingObjectId() async throws {\n        let score = GameScore(points: 10)\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        let saved = try await [score].createAll()\n        XCTAssertEqual(saved.count, 1)\n        guard let savedObject = saved.first else {\n            XCTFail(\"Should have one item\")\n            return\n        }\n        if case .failure(let error) = savedObject {\n            XCTAssertEqual(error.code, .missingObjectId)\n            XCTAssertTrue(error.message.contains(\"objectId\"))\n        } else {\n            XCTFail(\"Should have thrown error\")\n        }\n    }\n\n    @MainActor\n    func testCreateAllServerMissingCreatedAt() async throws {\n        let score = GameScore(points: 10)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yolo\"\n        scoreOnServer.ACL = nil\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        let saved = try await [score].createAll()\n        XCTAssertEqual(saved.count, 1)\n        guard let savedObject = saved.first else {\n            XCTFail(\"Should have one item\")\n            return\n        }\n        if case .failure(let error) = savedObject {\n            XCTAssertEqual(error.code, .unknownError)\n            XCTAssertTrue(error.message.contains(\"createdAt\"))\n        } else {\n            XCTFail(\"Should have thrown error\")\n        }\n    }\n\n    @MainActor\n    func testReplaceAll() async throws {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        var score2 = GameScore(points: 20)\n        score2.objectId = \"yolo\"\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.objectId = \"yolo\"\n        scoreOnServer2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        scoreOnServer2.ACL = nil\n        let scoreOnServerImmutable: GameScore!\n        let scoreOnServer2Immutable: GameScore!\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil),\n        BatchResponseItem<GameScore>(success: scoreOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            scoreOnServerImmutable = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n            scoreOnServer2Immutable = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await [score, score2].replaceAll()\n        XCTAssertEqual(saved.count, 2)\n        switch saved[0] {\n\n        case .success(let first):\n            XCTAssert(first.hasSameObjectId(as: scoreOnServerImmutable))\n            guard let savedCreatedAt = first.createdAt,\n                let savedUpdatedAt = first.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalCreatedAt = scoreOnServerImmutable.createdAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n            XCTAssertEqual(savedUpdatedAt, originalCreatedAt)\n            XCTAssertNil(first.ACL)\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n\n        switch saved[1] {\n\n        case .success(let second):\n            XCTAssert(second.hasSameObjectId(as: scoreOnServer2Immutable))\n            guard let savedCreatedAt = second.createdAt,\n                let savedUpdatedAt = second.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalCreatedAt = scoreOnServer2Immutable.createdAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n            XCTAssertEqual(savedUpdatedAt, originalCreatedAt)\n            XCTAssertNil(second.ACL)\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    @MainActor\n    func testReplaceAllUpdate() async throws {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        var score2 = GameScore(points: 20)\n        score2.objectId = \"yolo\"\n\n        var scoreOnServer = score\n        scoreOnServer.updatedAt = Date()\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        let scoreOnServerImmutable: GameScore!\n        let scoreOnServer2Immutable: GameScore!\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil),\n        BatchResponseItem<GameScore>(success: scoreOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            scoreOnServerImmutable = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n            scoreOnServer2Immutable = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await [score, score2].replaceAll()\n        XCTAssertEqual(saved.count, 2)\n        switch saved[0] {\n\n        case .success(let first):\n            XCTAssert(first.hasSameObjectId(as: scoreOnServerImmutable))\n            guard let savedUpdatedAt = first.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalUpdatedAt = scoreOnServerImmutable.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(first.ACL)\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n\n        switch saved[1] {\n\n        case .success(let second):\n            XCTAssert(second.hasSameObjectId(as: scoreOnServer2Immutable))\n            guard let savedUpdatedAt = second.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalUpdatedAt = scoreOnServer2Immutable.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(second.ACL)\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    @MainActor\n    func testReplaceAllServerMissingObjectId() async throws {\n        let score = GameScore(points: 10)\n\n        do {\n            _ = try await [score].replaceAll()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted to ParseError\")\n                return\n            }\n            XCTAssertEqual(parseError.code, .missingObjectId)\n        }\n    }\n\n    @MainActor\n    func testReplaceAllServerMissingUpdatedAt() async throws {\n        var score = GameScore(points: 10)\n        score.objectId = \"yolo\"\n\n        let scoreOnServer = score\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        let saved = try await [score].replaceAll()\n        XCTAssertEqual(saved.count, 1)\n        guard let savedObject = saved.first else {\n            XCTFail(\"Should have one item\")\n            return\n        }\n        if case .failure(let error) = savedObject {\n            XCTAssertEqual(error.code, .unknownError)\n            XCTAssertTrue(error.message.contains(\"updatedAt\"))\n        } else {\n            XCTFail(\"Should have thrown error\")\n        }\n    }\n\n    @MainActor\n    func testUpdateAll() async throws {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        var score2 = GameScore(points: 20)\n        score2.objectId = \"yolo\"\n\n        var scoreOnServer = score\n        scoreOnServer.updatedAt = Date()\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        let scoreOnServerImmutable: GameScore!\n        let scoreOnServer2Immutable: GameScore!\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil),\n        BatchResponseItem<GameScore>(success: scoreOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            scoreOnServerImmutable = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n            scoreOnServer2Immutable = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await [score, score2].updateAll()\n        XCTAssertEqual(saved.count, 2)\n        switch saved[0] {\n\n        case .success(let first):\n            XCTAssert(first.hasSameObjectId(as: scoreOnServerImmutable))\n            guard let savedUpdatedAt = first.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalUpdatedAt = scoreOnServerImmutable.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(first.ACL)\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n\n        switch saved[1] {\n\n        case .success(let second):\n            XCTAssert(second.hasSameObjectId(as: scoreOnServer2Immutable))\n            guard let savedUpdatedAt = second.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalUpdatedAt = scoreOnServer2Immutable.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(second.ACL)\n        case .failure(let error):\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    @MainActor\n    func testUpdateAllServerMissingUpdatedAt() async throws {\n        var score = GameScore(points: 10)\n        score.objectId = \"yolo\"\n\n        var scoreOnServer = score\n        scoreOnServer.ACL = nil\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        let saved = try await [score].updateAll()\n        XCTAssertEqual(saved.count, 1)\n        guard let savedObject = saved.first else {\n            XCTFail(\"Should have one item\")\n            return\n        }\n        if case .failure(let error) = savedObject {\n            XCTAssertEqual(error.code, .unknownError)\n            XCTAssertTrue(error.message.contains(\"updatedAt\"))\n        } else {\n            XCTFail(\"Should have thrown error\")\n        }\n    }\n\n    @MainActor\n    func testDeleteAll() async throws {\n        let response = [BatchResponseItem<NoBody>(success: NoBody(), error: nil),\n                        BatchResponseItem<NoBody>(success: NoBody(), error: nil)]\n\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        let deleted = try await [GameScore(objectId: \"yarr\"), GameScore(objectId: \"yolo\")].deleteAll()\n        XCTAssertEqual(deleted.count, 2)\n        guard let firstObject = deleted.first else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n\n        if case let .failure(error) = firstObject {\n            XCTFail(error.localizedDescription)\n        }\n\n        guard let lastObject = deleted.last else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n\n        if case let .failure(error) = lastObject {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    // swiftlint:disable:next function_body_length\n    @MainActor\n    func testDeepSaveOneDeep() async throws {\n        let score = GameScore(points: 10)\n        var game = Game(gameScore: score)\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n        scoreOnServer.objectId = \"yarr\"\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try GameScore.getJSONEncoder().encode(response)\n            //Get dates in correct format from ParseDecoding strategy\n            let encodedScoreOnServer = try scoreOnServer.getEncoder().encode(scoreOnServer)\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encodedScoreOnServer)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let (savedChildren, savedChildFiles) = try await game.ensureDeepSave()\n\n        XCTAssertEqual(savedChildren.count, 1)\n        XCTAssertEqual(savedChildFiles.count, 0)\n        var counter = 0\n        var savedChildObject: PointerType?\n        savedChildren.forEach { (_, value) in\n            XCTAssertEqual(value.className, \"GameScore\")\n            XCTAssertEqual(value.objectId, \"yarr\")\n            if counter == 0 {\n                savedChildObject = value\n            }\n            counter += 1\n        }\n\n        guard let savedChild = savedChildObject else {\n            XCTFail(\"Should have unwrapped child object\")\n            return\n        }\n\n        // Saved updated info for game\n        let encodedScore: Data\n        do {\n            encodedScore = try ParseCoding.jsonEncoder().encode(savedChild)\n            // Decode Pointer as GameScore\n            game.gameScore = try game.getDecoder().decode(GameScore.self, from: encodedScore)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        // Setup ParseObject to return from mocker\n        MockURLProtocol.removeAll()\n\n        var gameOnServer = game\n        gameOnServer.objectId = \"nice\"\n        gameOnServer.createdAt = Date()\n\n        let encodedGamed: Data\n        do {\n            encodedGamed = try game.getEncoder().encode(gameOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            gameOnServer = try game.getDecoder().decode(Game.self, from: encodedGamed)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encodedGamed, statusCode: 200, delay: 0.0)\n        }\n\n        guard let savedGame = try? game\n                .saveCommand()\n                .execute(options: [],\n                         childObjects: savedChildren,\n                         childFiles: savedChildFiles) else {\n            XCTFail(\"Should have saved game\")\n            return\n        }\n        XCTAssertEqual(savedGame.objectId, gameOnServer.objectId)\n        XCTAssertEqual(savedGame.createdAt, gameOnServer.createdAt)\n        XCTAssertEqual(savedGame.updatedAt, gameOnServer.createdAt)\n        XCTAssertEqual(savedGame.gameScore, gameOnServer.gameScore)\n    }\n\n    // swiftlint:disable:next function_body_length\n    @MainActor\n    func testDeepSaveOneDeepWithDefaultACL() async throws {\n        let user = try await loginNormally()\n        guard let userObjectId = user.objectId else {\n            XCTFail(\"Should have objectId\")\n            return\n        }\n        let defaultACL = try ParseACL.setDefaultACL(ParseACL(),\n                                                    withAccessForCurrentUser: true)\n\n        let score = GameScore(points: 10)\n        var game = Game(gameScore: score)\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n        scoreOnServer.objectId = \"yarr\"\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try GameScore.getJSONEncoder().encode(response)\n            //Get dates in correct format from ParseDecoding strategy\n            let encodedScoreOnServer = try scoreOnServer.getEncoder().encode(scoreOnServer)\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encodedScoreOnServer)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let (savedChildren, savedChildFiles) = try await game.ensureDeepSave()\n\n        XCTAssertEqual(savedChildren.count, 1)\n        XCTAssertEqual(savedChildFiles.count, 0)\n        var counter = 0\n        var savedChildObject: PointerType?\n        savedChildren.forEach { (_, value) in\n            XCTAssertEqual(value.className, \"GameScore\")\n            XCTAssertEqual(value.objectId, \"yarr\")\n            if counter == 0 {\n                savedChildObject = value\n            }\n            counter += 1\n        }\n\n        guard let savedChild = savedChildObject else {\n            XCTFail(\"Should have unwrapped child object\")\n            return\n        }\n\n        // Saved updated info for game\n        let encodedScore: Data\n        do {\n            encodedScore = try ParseCoding.jsonEncoder().encode(savedChild)\n            // Decode Pointer as GameScore\n            game.gameScore = try game.getDecoder().decode(GameScore.self, from: encodedScore)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        //Setup ParseObject to return from mocker\n        MockURLProtocol.removeAll()\n\n        var gameOnServer = game\n        gameOnServer.objectId = \"nice\"\n        gameOnServer.createdAt = Date()\n\n        let encodedGamed: Data\n        do {\n            encodedGamed = try game.getEncoder().encode(gameOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            gameOnServer = try game.getDecoder().decode(Game.self, from: encodedGamed)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encodedGamed, statusCode: 200, delay: 0.0)\n        }\n\n        guard let savedGame = try? game\n                .saveCommand()\n                .execute(options: [],\n                         childObjects: savedChildren,\n                         childFiles: savedChildFiles) else {\n            XCTFail(\"Should have saved game\")\n            return\n        }\n        XCTAssertEqual(savedGame.objectId, gameOnServer.objectId)\n        XCTAssertEqual(savedGame.createdAt, gameOnServer.createdAt)\n        XCTAssertEqual(savedGame.updatedAt, gameOnServer.createdAt)\n        XCTAssertEqual(savedGame.gameScore, gameOnServer.gameScore)\n        XCTAssertNotNil(savedGame.ACL)\n        XCTAssertEqual(savedGame.ACL?.publicRead, defaultACL.publicRead)\n        XCTAssertEqual(savedGame.ACL?.publicWrite, defaultACL.publicWrite)\n        XCTAssertTrue(defaultACL.getReadAccess(objectId: userObjectId))\n        XCTAssertTrue(defaultACL.getWriteAccess(objectId: userObjectId))\n    }\n\n    @MainActor\n    func testDeepSaveDetectCircular() async throws {\n        let score = GameScoreClass(points: 10)\n        let game = GameClass(gameScore: score)\n        game.objectId = \"nice\"\n        score.game = game\n        do {\n            _ = try await game.ensureDeepSave()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have failed with an error of detecting a circular dependency\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"circular\"))\n        }\n    }\n\n    @MainActor\n    func testAllowFieldsWithSameObject() async throws {\n        var score = GameScore(points: 10)\n        var level = Level()\n        level.objectId = \"nice\"\n        score.level = level\n        score.nextLevel = level\n        do {\n            _ = try await score.ensureDeepSave()\n        } catch {\n            XCTFail(\"Should not throw an error: \\(error.localizedDescription)\")\n        }\n    }\n\n    @MainActor\n    func testDeepSaveTwoDeep() async throws {\n        var score = GameScore(points: 10)\n        score.level = Level()\n        var game = Game(gameScore: score)\n        game.objectId = \"nice\"\n\n        var levelOnServer = score\n        levelOnServer.createdAt = Date()\n        levelOnServer.ACL = nil\n        levelOnServer.objectId = \"yarr\"\n        let pointer = try levelOnServer.toPointer()\n\n        let response = [BatchResponseItem<Pointer<GameScore>>(success: pointer, error: nil)]\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let (savedChildren, savedChildFiles) = try await game.ensureDeepSave()\n        XCTAssertEqual(savedChildFiles.count, 0)\n        XCTAssertEqual(savedChildren.count, 2)\n        let gameScore = savedChildren.compactMap { (_, value) -> PointerType? in\n            if value.className == \"GameScore\" {\n                return value\n            } else {\n                return nil\n            }\n        }\n        XCTAssertEqual(gameScore.count, 1)\n        XCTAssertEqual(gameScore.first?.className, \"GameScore\")\n        XCTAssertEqual(gameScore.first?.objectId, \"yarr\")\n\n        let level = savedChildren.compactMap { (_, value) -> PointerType? in\n            if value.className == \"Level\" {\n                return value\n            } else {\n                return nil\n            }\n        }\n        XCTAssertEqual(level.count, 1)\n        XCTAssertEqual(level.first?.className, \"Level\")\n        XCTAssertEqual(level.first?.objectId, \"yarr\") // This is because mocker is only returning 1 response\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    // swiftlint:disable:next function_body_length\n    @MainActor\n    func testDeepSaveObjectWithFile() async throws {\n        var game = Game2()\n\n        guard let cloudPath = URL(string: \"https://parseplatform.org/img/logo.svg\"),\n              // swiftlint:disable:next line_length\n              let parseURL = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n\n        let parseFile = ParseFile(name: \"profile.svg\", cloudURL: cloudPath)\n        game.profilePicture = parseFile\n\n        let fileResponse = FileUploadResponse(name: \"89d74fcfa4faa5561799e5076593f67c_\\(parseFile.name)\",\n                                              url: parseURL)\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(fileResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let (savedChildren, savedChildFiles) = try await game.ensureDeepSave()\n        XCTAssertEqual(savedChildren.count, 0)\n        XCTAssertEqual(savedChildFiles.count, 1)\n        var counter = 0\n        var savedFile: ParseFile?\n        savedChildFiles.forEach { (_, value) in\n            XCTAssertEqual(value.url, fileResponse.url)\n            XCTAssertEqual(value.name, fileResponse.name)\n            if counter == 0 {\n                savedFile = value\n            }\n            counter += 1\n        }\n\n        //Saved updated info for game\n        game.profilePicture = savedFile\n\n        //Setup ParseObject to return from mocker\n        MockURLProtocol.removeAll()\n\n        var gameOnServer = game\n        gameOnServer.objectId = \"nice\"\n        gameOnServer.createdAt = Date()\n        gameOnServer.profilePicture = savedFile\n\n        let encodedGamed: Data\n        do {\n            encodedGamed = try game.getEncoder().encode(gameOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            gameOnServer = try game.getDecoder().decode(Game2.self, from: encodedGamed)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encodedGamed, statusCode: 200, delay: 0.0)\n        }\n\n        guard let savedGame = try? game\n                .saveCommand()\n                .execute(options: [],\n                         childObjects: savedChildren,\n                         childFiles: savedChildFiles) else {\n            XCTFail(\"Should have saved game\")\n            return\n        }\n        XCTAssertEqual(savedGame.objectId, gameOnServer.objectId)\n        XCTAssertEqual(savedGame.createdAt, gameOnServer.createdAt)\n        XCTAssertEqual(savedGame.updatedAt, gameOnServer.createdAt)\n        XCTAssertEqual(savedGame.profilePicture, gameOnServer.profilePicture)\n    }\n    #endif\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseObjectBatchTests.swift",
    "content": "//\n//  ParseObjectBatchTests.swift\n//  ParseSwiftTests\n//\n//  Created by Corey Baker on 7/27/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseObjectBatchTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct GameScore: ParseObject {\n        // These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // Custom properties\n        var points: Int = 0\n        var other: Game2?\n        var otherArray: [Game2]?\n\n        //custom initializers\n        init() {\n            self.points = 5\n        }\n        init(points: Int) {\n            self.points = points\n        }\n\n        init(objectId: String?) {\n            self.objectId = objectId\n        }\n    }\n\n    struct Game2: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var name = \"Hello\"\n        var profilePicture: ParseFile?\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testEncodeEmbeddedSavedObjectWithBatching() throws {\n        var score = GameScore(points: 10)\n        score.objectId = \"yolo\"\n        score.createdAt = Date()\n        score.updatedAt = Date()\n        var game = Game2()\n        game.createdAt = Date()\n        game.updatedAt = Date()\n        game.objectId = \"brave\"\n        score.other = game\n        let command = try score.saveCommand()\n        let batch = API.Command<GameScore, GameScore>\n            .batch(commands: [command], transaction: false)\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"body\\\":{\\\"requests\\\":[{\\\"body\\\":{\\\"other\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"Game2\\\",\\\"objectId\\\":\\\"brave\\\"},\\\"points\\\":10},\\\"method\\\":\\\"PUT\\\",\\\"path\\\":\\\"\\\\/1\\\\/classes\\\\/GameScore\\\\/yolo\\\"}],\\\"transaction\\\":false},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"\\\\/batch\\\"}\"\n        let encoded = try ParseCoding.parseEncoder().encode(batch,\n                                                            batching: true)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testEncodeMutltipleEmbeddedSavedObjectWithBatching() throws {\n        var score = GameScore(points: 10)\n        score.objectId = \"yolo\"\n        score.createdAt = Date()\n        score.updatedAt = Date()\n        var game = Game2()\n        game.createdAt = Date()\n        game.updatedAt = Date()\n        game.objectId = \"brave\"\n        score.other = game\n        let command = try score.saveCommand()\n        let batch = API.Command<GameScore, GameScore>\n            .batch(commands: [command, command], transaction: false)\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"body\\\":{\\\"requests\\\":[{\\\"body\\\":{\\\"other\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"Game2\\\",\\\"objectId\\\":\\\"brave\\\"},\\\"points\\\":10},\\\"method\\\":\\\"PUT\\\",\\\"path\\\":\\\"\\\\/1\\\\/classes\\\\/GameScore\\\\/yolo\\\"},{\\\"body\\\":{\\\"other\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"Game2\\\",\\\"objectId\\\":\\\"brave\\\"},\\\"points\\\":10},\\\"method\\\":\\\"PUT\\\",\\\"path\\\":\\\"\\\\/1\\\\/classes\\\\/GameScore\\\\/yolo\\\"}],\\\"transaction\\\":false},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"\\\\/batch\\\"}\"\n        let encoded = try ParseCoding.parseEncoder().encode(batch,\n                                                            batching: true)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testSaveAllCommand() throws {\n        let score = GameScore(points: 10)\n        let score2 = GameScore(points: 20)\n\n        let objects = [score, score2]\n        let commands = try objects.map { try $0.saveCommand() }\n        let body = BatchCommand(requests: commands, transaction: false)\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"requests\\\":[{\\\"body\\\":{\\\"points\\\":10},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"\\\\/classes\\\\/GameScore\\\"},{\\\"body\\\":{\\\"points\\\":20},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"\\\\/classes\\\\/GameScore\\\"}],\\\"transaction\\\":false}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(body,\n                    collectChildren: false,\n                    objectsSavedBeforeThisOne: nil,\n                    filesSavedBeforeThisOne: nil).encoded\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testSaveAll() { // swiftlint:disable:this function_body_length cyclomatic_complexity\n        let score = GameScore(points: 10)\n        let score2 = GameScore(points: 20)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.objectId = \"yolo\"\n        scoreOnServer2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        scoreOnServer2.ACL = nil\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil),\n        BatchResponseItem<GameScore>(success: scoreOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try scoreOnServer.getJSONEncoder().encode(response)\n           // Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n           scoreOnServer2 = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n\n            let saved = try [score, score2].saveAll()\n\n            XCTAssertEqual(saved.count, 2)\n            switch saved[0] {\n\n            case .success(let first):\n                XCTAssert(first.hasSameObjectId(as: scoreOnServer))\n                guard let savedCreatedAt = first.createdAt,\n                    let savedUpdatedAt = first.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedCreatedAt, scoreOnServer.createdAt)\n                XCTAssertEqual(savedUpdatedAt, scoreOnServer.createdAt)\n                XCTAssertNil(first.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch saved[1] {\n\n            case .success(let second):\n                XCTAssert(second.hasSameObjectId(as: scoreOnServer2))\n                guard let savedCreatedAt = second.createdAt,\n                    let savedUpdatedAt = second.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedCreatedAt, scoreOnServer2.createdAt)\n                XCTAssertEqual(savedUpdatedAt, scoreOnServer2.createdAt)\n                XCTAssertNil(second.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        do {\n            let saved = try [score, score2].saveAll(transaction: true,\n                                                    options: [.installationId(\"hello\")])\n            XCTAssertEqual(saved.count, 2)\n            switch saved[0] {\n\n            case .success(let first):\n                XCTAssert(first.hasSameObjectId(as: scoreOnServer))\n                guard let savedCreatedAt = first.createdAt,\n                    let savedUpdatedAt = first.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedCreatedAt, scoreOnServer.createdAt)\n                XCTAssertEqual(savedUpdatedAt, scoreOnServer.createdAt)\n                XCTAssertNil(first.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch saved[1] {\n\n            case .success(let second):\n                XCTAssert(second.hasSameObjectId(as: scoreOnServer2))\n                guard let savedCreatedAt = second.createdAt,\n                    let savedUpdatedAt = second.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedCreatedAt, scoreOnServer2.createdAt)\n                XCTAssertEqual(savedUpdatedAt, scoreOnServer2.createdAt)\n                XCTAssertNil(second.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testSaveAllWithPointer() { // swiftlint:disable:this function_body_length cyclomatic_complexity\n        var score = GameScore(points: 10)\n        score.other = Game2()\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try scoreOnServer.getJSONEncoder().encode(response)\n           // Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n\n            let saved = try [score].saveAll()\n\n            XCTAssertEqual(saved.count, 1)\n            switch saved[0] {\n\n            case .success(let first):\n                XCTAssert(first.hasSameObjectId(as: scoreOnServer))\n                guard let savedCreatedAt = first.createdAt,\n                    let savedUpdatedAt = first.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedCreatedAt, scoreOnServer.createdAt)\n                XCTAssertEqual(savedUpdatedAt, scoreOnServer.createdAt)\n                XCTAssertNil(first.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        do {\n            _ = try [score].saveAll(transaction: true,\n                                    options: [.installationId(\"hello\")])\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.localizedDescription.contains(\"originally\"))\n        }\n    }\n\n    func testSaveAllWithPointerArray() { // swiftlint:disable:this function_body_length cyclomatic_complexity\n        var score = GameScore(points: 10)\n        score.otherArray = [Game2()]\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try scoreOnServer.getJSONEncoder().encode(response)\n           // Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n\n            let saved = try [score].saveAll()\n\n            XCTAssertEqual(saved.count, 1)\n            switch saved[0] {\n\n            case .success(let first):\n                XCTAssert(first.hasSameObjectId(as: scoreOnServer))\n                guard let savedCreatedAt = first.createdAt,\n                    let savedUpdatedAt = first.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedCreatedAt, scoreOnServer.createdAt)\n                XCTAssertEqual(savedUpdatedAt, scoreOnServer.createdAt)\n                XCTAssertNil(first.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        do {\n            _ = try [score].saveAll(transaction: true,\n                                    options: [.installationId(\"hello\")])\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.localizedDescription.contains(\"originally\"))\n        }\n    }\n\n    func testSaveAllTransaction() { // swiftlint:disable:this function_body_length cyclomatic_complexity\n        let score = GameScore(points: 10)\n        let score2 = GameScore(points: 20)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.objectId = \"yolo\"\n        scoreOnServer2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        scoreOnServer2.ACL = nil\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil),\n        BatchResponseItem<GameScore>(success: scoreOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try scoreOnServer.getJSONEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n           scoreOnServer2 = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n\n            let saved = try [score, score2].saveAll(transaction: true)\n\n            XCTAssertEqual(saved.count, 2)\n            switch saved[0] {\n\n            case .success(let first):\n                XCTAssert(first.hasSameObjectId(as: scoreOnServer))\n                guard let savedCreatedAt = first.createdAt,\n                    let savedUpdatedAt = first.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedCreatedAt, scoreOnServer.createdAt)\n                XCTAssertEqual(savedUpdatedAt, scoreOnServer.createdAt)\n                XCTAssertNil(first.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch saved[1] {\n\n            case .success(let second):\n                XCTAssert(second.hasSameObjectId(as: scoreOnServer2))\n                guard let savedCreatedAt = second.createdAt,\n                    let savedUpdatedAt = second.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedCreatedAt, scoreOnServer2.createdAt)\n                XCTAssertEqual(savedUpdatedAt, scoreOnServer2.createdAt)\n                XCTAssertNil(second.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testSaveAllTransactionErrorTooMany() {\n        let score = GameScore(points: 10)\n        let score2 = GameScore(points: 20)\n        do {\n            _ = try [score, score2].saveAll(batchLimit: 1, transaction: true)\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Error should have casted to ParseError\")\n                return\n            }\n            XCTAssertEqual(parseError.code, .unknownError)\n            XCTAssertTrue(parseError.message.contains(\"exceed\"))\n        }\n    }\n\n    func testSaveAllTransactionErrorChild() {\n        let score = GameScore(points: 10)\n        var score2 = GameScore(points: 20)\n        score2.other = Game2()\n        do {\n            _ = try [score, score2].saveAll(transaction: true)\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Error should have casted to ParseError\")\n                return\n            }\n            XCTAssertEqual(parseError.code, .unknownError)\n            XCTAssertTrue(parseError.message.contains(\"originally\"))\n        }\n    }\n\n    func testSaveAllErrorIncorrectServerResponse() {\n        let score = GameScore(points: 10)\n        let score2 = GameScore(points: 20)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.objectId = \"yolo\"\n        scoreOnServer2.createdAt = Calendar.current.date(byAdding: .init(day: -2), to: Date())\n        scoreOnServer2.ACL = nil\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode([scoreOnServer, scoreOnServer2])\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        do {\n            let saved = try [score, score2].saveAll()\n\n            XCTAssertEqual(saved.count, 2)\n            XCTAssertThrowsError(try saved[0].get())\n            XCTAssertThrowsError(try saved[1].get())\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        do {\n            let saved = try [score, score2].saveAll(transaction: true,\n                                                    options: [.useMasterKey])\n\n            XCTAssertEqual(saved.count, 2)\n            XCTAssertThrowsError(try saved[0].get())\n            XCTAssertThrowsError(try saved[1].get())\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testUpdateAllCommand() throws {\n        var score = GameScore(points: 10)\n        var score2 = GameScore(points: 20)\n\n        score.objectId = \"yarr\"\n        score.createdAt = Date()\n        score.updatedAt = score.createdAt\n        score2.objectId = \"yolo\"\n        score2.createdAt = Date()\n        score2.updatedAt = score2.createdAt\n\n        let objects = [score, score2]\n        let initialCommands = try objects.map { try $0.saveCommand() }\n        let commands = initialCommands.compactMap { (command) -> API.Command<GameScore, GameScore>? in\n            let path = ParseSwift.configuration.mountPath + command.path.urlComponent\n            guard let body = command.body else {\n                return nil\n            }\n            return API.Command<GameScore, GameScore>(method: command.method, path: .any(path),\n                                     body: body, mapper: command.mapper)\n        }\n        let body = BatchCommand(requests: commands, transaction: false)\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"requests\\\":[{\\\"body\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"yarr\\\"},\\\"method\\\":\\\"PUT\\\",\\\"path\\\":\\\"\\\\/1\\\\/classes\\\\/GameScore\\\\/yarr\\\"},{\\\"body\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"yolo\\\"},\\\"method\\\":\\\"PUT\\\",\\\"path\\\":\\\"\\\\/1\\\\/classes\\\\/GameScore\\\\/yolo\\\"}],\\\"transaction\\\":false}\"\n\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(body, collectChildren: false,\n                    objectsSavedBeforeThisOne: nil,\n                    filesSavedBeforeThisOne: nil).encoded\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testUpdateAll() { // swiftlint:disable:this function_body_length cyclomatic_complexity\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        score.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        score.ACL = nil\n        var game = Game2()\n        game.objectId = \"brave\"\n        score.other = game\n\n        var score2 = GameScore(points: 20)\n        score2.objectId = \"yolo\"\n        score2.updatedAt = Calendar.current.date(byAdding: .init(day: -2), to: Date())\n        score2.ACL = nil\n\n        var scoreOnServer = score\n        scoreOnServer.updatedAt = Date()\n        var scoreOnServer2 = score2\n        scoreOnServer2.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil),\n        BatchResponseItem<GameScore>(success: scoreOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n           scoreOnServer2 = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            let saved = try [score, score2].saveAll()\n\n            XCTAssertEqual(saved.count, 2)\n            switch saved[0] {\n\n            case .success(let first):\n\n                guard let savedUpdatedAt = first.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n                }\n                guard let originalUpdatedAt = score.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n                }\n                XCTAssertGreaterThan(savedUpdatedAt, originalUpdatedAt)\n                XCTAssertNil(first.ACL)\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch saved[1] {\n\n            case .success(let second):\n\n                guard let savedUpdatedAt2 = second.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n                }\n                guard let originalUpdatedAt2 = score2.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n                }\n\n                XCTAssertGreaterThan(savedUpdatedAt2, originalUpdatedAt2)\n                XCTAssertNil(second.ACL)\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        do {\n            let saved = try [score, score2].saveAll(transaction: true,\n                                                    options: [.useMasterKey])\n            XCTAssertEqual(saved.count, 2)\n\n            switch saved[0] {\n\n            case .success(let first):\n                guard let savedUpdatedAt = first.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n                }\n                guard let originalUpdatedAt = score.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n                }\n                XCTAssertGreaterThan(savedUpdatedAt, originalUpdatedAt)\n                XCTAssertNil(first.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch saved[1] {\n\n            case .success(let second):\n                guard let savedUpdatedAt2 = second.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n                }\n                guard let originalUpdatedAt2 = score2.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n                }\n                XCTAssertGreaterThan(savedUpdatedAt2, originalUpdatedAt2)\n                XCTAssertNil(second.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testUpdateAllErrorIncorrectServerResponse() {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        score.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        score.ACL = nil\n\n        var score2 = GameScore(points: 20)\n        score2.objectId = \"yolo\"\n        score2.updatedAt = Calendar.current.date(byAdding: .init(day: -2), to: Date())\n        score2.ACL = nil\n\n        var scoreOnServer = score\n        scoreOnServer.updatedAt = Date()\n        var scoreOnServer2 = score2\n        scoreOnServer2.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode([scoreOnServer, scoreOnServer2])\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        do {\n            let saved = try [score, score2].saveAll()\n            XCTAssertEqual(saved.count, 2)\n            XCTAssertThrowsError(try saved[0].get())\n            XCTAssertThrowsError(try saved[1].get())\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        do {\n            let saved = try [score, score2].saveAll(transaction: true,\n                                                    options: [.useMasterKey])\n\n            XCTAssertEqual(saved.count, 2)\n            XCTAssertThrowsError(try saved[0].get())\n            XCTAssertThrowsError(try saved[1].get())\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testSaveAllMixed() { // swiftlint:disable:this function_body_length cyclomatic_complexity\n        let score = GameScore(points: 10)\n        var score2 = GameScore(points: 20)\n        score2.objectId = \"yolo\"\n        score2.updatedAt = Calendar.current.date(byAdding: .init(day: -2), to: Date())\n        score2.ACL = nil\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil),\n        BatchResponseItem<GameScore>(success: scoreOnServer2, error: nil)]\n\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n           scoreOnServer2 = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            let saved = try [score, score2].saveAll()\n\n            XCTAssertEqual(saved.count, 2)\n            switch saved[0] {\n\n            case .success(let first):\n                XCTAssert(first.hasSameObjectId(as: scoreOnServer))\n                guard let savedCreatedAt = first.createdAt,\n                    let savedUpdatedAt = first.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedCreatedAt, scoreOnServer.createdAt)\n                XCTAssertEqual(savedUpdatedAt, scoreOnServer.createdAt)\n                XCTAssertNil(first.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch saved[1] {\n\n            case .success(let second):\n                guard let savedUpdatedAt = second.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedUpdatedAt, scoreOnServer2.updatedAt)\n                XCTAssertNil(second.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        do {\n            let saved = try [score, score2].saveAll(transaction: true,\n                                                    options: [.useMasterKey])\n            XCTAssertEqual(saved.count, 2)\n            switch saved[0] {\n\n            case .success(let first):\n                XCTAssertNotNil(first.createdAt)\n                XCTAssertNotNil(first.updatedAt)\n                XCTAssertNil(first.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch saved[1] {\n\n            case .success(let second):\n                XCTAssertNil(second.createdAt)\n                XCTAssertNotNil(second.updatedAt)\n                XCTAssertNil(second.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func saveAllAsync(scores: [GameScore], // swiftlint:disable:this function_body_length cyclomatic_complexity\n                      transaction: Bool = false,\n                      scoresOnServer: [GameScore], callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Save object1\")\n        guard let scoreOnServer = scoresOnServer.first,\n            let scoreOnServer2 = scoresOnServer.last else {\n            XCTFail(\"Should unwrap\")\n            expectation1.fulfill()\n            return\n        }\n\n        scores.saveAll(transaction: transaction,\n                       callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let saved):\n                XCTAssertEqual(saved.count, 2)\n                guard let firstObject = saved.first,\n                    let secondObject = saved.last else {\n                        XCTFail(\"Should unwrap\")\n                        expectation1.fulfill()\n                        return\n                }\n\n                switch firstObject {\n\n                case .success(let first):\n                    XCTAssert(first.hasSameObjectId(as: scoreOnServer))\n                    guard let savedCreatedAt = first.createdAt,\n                        let savedUpdatedAt = first.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    XCTAssertEqual(savedCreatedAt, scoreOnServer.createdAt)\n                    XCTAssertEqual(savedUpdatedAt, scoreOnServer.createdAt)\n                    XCTAssertNil(first.ACL)\n\n                case .failure(let error):\n                    XCTFail(error.localizedDescription)\n                }\n\n                switch secondObject {\n\n                case .success(let second):\n                    XCTAssert(second.hasSameObjectId(as: scoreOnServer2))\n                    guard let savedCreatedAt = second.createdAt,\n                        let savedUpdatedAt = second.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    XCTAssertEqual(savedCreatedAt, scoreOnServer2.createdAt)\n                    XCTAssertEqual(savedUpdatedAt, scoreOnServer2.createdAt)\n                    XCTAssertNil(second.ACL)\n\n                case .failure(let error):\n                    XCTFail(error.localizedDescription)\n                }\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n\n        let expectation2 = XCTestExpectation(description: \"Save object2\")\n        scores.saveAll(transaction: true,\n                       options: [.useMasterKey],\n                       callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let saved):\n                XCTAssertEqual(saved.count, 2)\n\n                guard let firstObject = saved.first,\n                    let secondObject = saved.last else {\n                        XCTFail(\"Should unwrap\")\n                        expectation2.fulfill()\n                        return\n                }\n\n                switch firstObject {\n\n                case .success(let first):\n                    guard let savedCreatedAt = first.createdAt,\n                        let savedUpdatedAt = first.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation2.fulfill()\n                            return\n                    }\n                    XCTAssertEqual(savedCreatedAt, scoreOnServer.createdAt)\n                    XCTAssertEqual(savedUpdatedAt, scoreOnServer.createdAt)\n                    XCTAssertNil(first.ACL)\n                case .failure(let error):\n                    XCTFail(error.localizedDescription)\n                }\n\n                switch secondObject {\n\n                case .success(let second):\n                    guard let savedCreatedAt = second.createdAt,\n                        let savedUpdatedAt = second.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation2.fulfill()\n                            return\n                    }\n                    XCTAssertEqual(savedCreatedAt, scoreOnServer2.createdAt)\n                    XCTAssertEqual(savedUpdatedAt, scoreOnServer2.createdAt)\n                    XCTAssertNil(second.ACL)\n                case .failure(let error):\n                    XCTFail(error.localizedDescription)\n                }\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func saveAllAsyncPointer(scores: [GameScore], // swiftlint:disable:this function_body_length cyclomatic_complexity\n                             transaction: Bool = false,\n                             scoresOnServer: [GameScore], callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Save object1\")\n        guard let scoreOnServer = scoresOnServer.first else {\n            XCTFail(\"Should unwrap\")\n            expectation1.fulfill()\n            return\n        }\n\n        scores.saveAll(transaction: transaction,\n                       callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let saved):\n                XCTAssertEqual(saved.count, 1)\n                guard let firstObject = saved.first else {\n                    XCTFail(\"Should unwrap\")\n                    expectation1.fulfill()\n                    return\n                }\n\n                switch firstObject {\n\n                case .success(let first):\n                    XCTAssert(first.hasSameObjectId(as: scoreOnServer))\n                    guard let savedCreatedAt = first.createdAt,\n                        let savedUpdatedAt = first.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    XCTAssertEqual(savedCreatedAt, scoreOnServer.createdAt)\n                    XCTAssertEqual(savedUpdatedAt, scoreOnServer.createdAt)\n                    XCTAssertNil(first.ACL)\n\n                case .failure(let error):\n                    XCTFail(error.localizedDescription)\n                }\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n\n        let expectation2 = XCTestExpectation(description: \"Save object2\")\n        scores.saveAll(transaction: true,\n                       options: [.useMasterKey],\n                       callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success:\n                XCTFail(\"Should have thrown error\")\n            case .failure(let error):\n                XCTAssertTrue(error.localizedDescription.contains(\"originally\"))\n            }\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testThreadSafeSaveAllAsync() {\n        let score = GameScore(points: 10)\n        let score2 = GameScore(points: 20)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.objectId = \"yolo\"\n        scoreOnServer2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        scoreOnServer2.ACL = nil\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil),\n        BatchResponseItem<GameScore>(success: scoreOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n           scoreOnServer2 = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        DispatchQueue.concurrentPerform(iterations: 100) {_ in\n            self.saveAllAsync(scores: [score, score2], scoresOnServer: [scoreOnServer, scoreOnServer2],\n                              callbackQueue: .global(qos: .background))\n        }\n    }\n    #endif\n\n    func testSaveAllAsyncMainQueue() {\n        let score = GameScore(points: 10)\n        let score2 = GameScore(points: 20)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.objectId = \"yolo\"\n        scoreOnServer2.createdAt = Calendar.current.date(byAdding: .init(day: -2), to: Date())\n        scoreOnServer2.ACL = nil\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil),\n        BatchResponseItem<GameScore>(success: scoreOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n           scoreOnServer2 = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        self.saveAllAsync(scores: [score, score2], scoresOnServer: [scoreOnServer, scoreOnServer2],\n                          callbackQueue: .main)\n    }\n\n    func testSaveAllAsyncPointer() {\n        var score = GameScore(points: 10)\n        score.other = Game2()\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n           // Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        self.saveAllAsyncPointer(scores: [score], scoresOnServer: [scoreOnServer],\n                                 callbackQueue: .main)\n    }\n\n    func testSaveAlreadySavedEncode() throws {\n        var score = GameScore(points: 10)\n        var game = Game2()\n        game.objectId = \"brave\"\n        score.other = game\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"other\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"Game2\\\",\\\"objectId\\\":\\\"brave\\\"},\\\"points\\\":10}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(score, collectChildren: false,\n                    objectsSavedBeforeThisOne: nil,\n                    filesSavedBeforeThisOne: nil).encoded\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testSaveAllAsyncPointerArray() {\n        var score = GameScore(points: 10)\n        score.otherArray = [Game2()]\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n           // Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        self.saveAllAsyncPointer(scores: [score], scoresOnServer: [scoreOnServer],\n                                 callbackQueue: .main)\n    }\n\n    func testSaveAllAsyncTransaction() { // swiftlint:disable:this function_body_length cyclomatic_complexity\n        let score = GameScore(points: 10)\n        let score2 = GameScore(points: 20)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.objectId = \"yolo\"\n        scoreOnServer2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        scoreOnServer2.ACL = nil\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil),\n        BatchResponseItem<GameScore>(success: scoreOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try scoreOnServer.getJSONEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n           scoreOnServer2 = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        self.saveAllAsync(scores: [score, score2],\n                          transaction: true,\n                          scoresOnServer: [scoreOnServer, scoreOnServer2],\n                          callbackQueue: .main)\n    }\n\n    func testSaveAllAsyncTransactionErrorTooMany() {\n        let score = GameScore(points: 10)\n        let score2 = GameScore(points: 20)\n        let expectation1 = XCTestExpectation(description: \"Save object1\")\n        [score, score2].saveAll(batchLimit: 1, transaction: true) { result in\n            if case .failure(let error) = result {\n                XCTAssertEqual(error.code, .unknownError)\n                XCTAssertTrue(error.message.contains(\"exceed\"))\n            } else {\n                XCTFail(\"Should have received error\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSaveAllAsyncTransactionErrorChild() {\n        let score = GameScore(points: 10)\n        var score2 = GameScore(points: 20)\n        score2.other = Game2()\n        let expectation1 = XCTestExpectation(description: \"Save object1\")\n        [score, score2].saveAll(transaction: true) { result in\n            if case .failure(let error) = result {\n                XCTAssertEqual(error.code, .unknownError)\n                XCTAssertTrue(error.message.contains(\"originally\"))\n            } else {\n                XCTFail(\"Should have received error\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    /* Note, the current batchCommand for updateAll returns the original object that was updated as\n    opposed to the latestUpdated. The objective c one just returns true/false */\n    // swiftlint:disable:next function_body_length cyclomatic_complexity\n    func updateAllAsync(scores: [GameScore], scoresOnServer: [GameScore],\n                        callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Update object1\")\n\n        scores.saveAll(callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let saved):\n                guard let firstObject = saved.first,\n                    let secondObject = saved.last else {\n                        XCTFail(\"Should unwrap\")\n                        expectation1.fulfill()\n                    return\n                }\n\n                switch firstObject {\n\n                case .success(let first):\n                    guard let savedUpdatedAt = first.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation1.fulfill()\n                        return\n                    }\n                    guard let originalUpdatedAt = scores.first?.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n\n                    XCTAssertGreaterThan(savedUpdatedAt, originalUpdatedAt)\n                    XCTAssertNil(first.ACL)\n                case .failure(let error):\n                    XCTFail(error.localizedDescription)\n                }\n\n                switch secondObject {\n\n                case .success(let second):\n                    guard let savedUpdatedAt2 = second.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation1.fulfill()\n                        return\n                    }\n                    guard let originalUpdatedAt2 = scores.last?.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation1.fulfill()\n                        return\n                    }\n\n                    XCTAssertGreaterThan(savedUpdatedAt2,\n                                         originalUpdatedAt2)\n                    XCTAssertNil(second.ACL)\n                case .failure(let error):\n                    XCTFail(error.localizedDescription)\n                }\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n\n        let expectation2 = XCTestExpectation(description: \"Update object2\")\n        scores.saveAll(transaction: true,\n                       options: [.useMasterKey],\n                       callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let saved):\n                guard let firstObject = saved.first,\n                    let secondObject = saved.last else {\n                        expectation2.fulfill()\n                        XCTFail(\"Should unwrap\")\n                    return\n                }\n\n                switch firstObject {\n\n                case .success(let first):\n                    guard let savedUpdatedAt = first.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation2.fulfill()\n                        return\n                    }\n                    guard let originalUpdatedAt = scores.first?.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation2.fulfill()\n                        return\n                    }\n\n                    XCTAssertGreaterThan(savedUpdatedAt, originalUpdatedAt)\n                    XCTAssertNil(first.ACL)\n                case .failure(let error):\n                    XCTFail(error.localizedDescription)\n                }\n\n                switch secondObject {\n\n                case .success(let second):\n                    guard let savedUpdatedAt2 = second.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation2.fulfill()\n                        return\n                    }\n                    guard let originalUpdatedAt2 = scores.last?.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation2.fulfill()\n                        return\n                    }\n\n                    XCTAssertGreaterThan(savedUpdatedAt2,\n                                         originalUpdatedAt2)\n                    XCTAssertNil(second.ACL)\n                case .failure(let error):\n                    XCTFail(error.localizedDescription)\n                }\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testThreadSafeUpdateAllAsync() {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        score.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        score.ACL = nil\n\n        var score2 = GameScore(points: 20)\n        score2.objectId = \"yolo\"\n        score2.updatedAt = Calendar.current.date(byAdding: .init(day: -2), to: Date())\n        score2.ACL = nil\n\n        var scoreOnServer = score\n        scoreOnServer.updatedAt = Date()\n        var scoreOnServer2 = score2\n        scoreOnServer2.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil),\n                        BatchResponseItem<GameScore>(success: scoreOnServer2, error: nil)]\n\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n           scoreOnServer2 = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        DispatchQueue.concurrentPerform(iterations: 100) {_ in\n            self.updateAllAsync(scores: [score, score2],\n                                scoresOnServer: [scoreOnServer, scoreOnServer2],\n                                callbackQueue: .global(qos: .background))\n        }\n    }\n\n    func testUpdateAllAsyncMainQueue() {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        score.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        score.ACL = nil\n\n        var score2 = GameScore(points: 20)\n        score2.objectId = \"yolo\"\n        score2.updatedAt = Calendar.current.date(byAdding: .init(day: -2), to: Date())\n        score2.ACL = nil\n\n        var scoreOnServer = score\n        scoreOnServer.updatedAt = Date()\n        var scoreOnServer2 = score2\n        scoreOnServer2.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil),\n                        BatchResponseItem<GameScore>(success: scoreOnServer2, error: nil)]\n\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n           scoreOnServer2 = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        self.updateAllAsync(scores: [score, score2],\n                            scoresOnServer: [scoreOnServer, scoreOnServer2],\n                            callbackQueue: .main)\n    }\n    #endif\n\n    // swiftlint:disable:next function_body_length cyclomatic_complexity\n    func testFetchAll() {\n        let score = GameScore(points: 10)\n        let score2 = GameScore(points: 20)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.objectId = \"yolo\"\n        scoreOnServer2.createdAt = Calendar.current.date(byAdding: .init(day: -2), to: Date())\n        scoreOnServer2.updatedAt = scoreOnServer2.createdAt\n        scoreOnServer2.ACL = nil\n\n        let response = QueryResponse<GameScore>(results: [scoreOnServer, scoreOnServer2], count: 2)\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n           scoreOnServer2 = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            let fetched = try [GameScore(objectId: \"yarr\"), GameScore(objectId: \"yolo\")].fetchAll()\n\n            XCTAssertEqual(fetched.count, 2)\n            guard let firstObject = try? fetched.first(where: {try $0.get().objectId == \"yarr\"}),\n                let secondObject = try? fetched.first(where: {try $0.get().objectId == \"yolo\"}) else {\n                    XCTFail(\"Should unwrap\")\n                    return\n            }\n\n            switch firstObject {\n\n            case .success(let first):\n                XCTAssert(first.hasSameObjectId(as: scoreOnServer))\n                guard let fetchedCreatedAt = first.createdAt,\n                    let fetchedUpdatedAt = first.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                guard let originalCreatedAt = scoreOnServer.createdAt,\n                    let originalUpdatedAt = scoreOnServer.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n                XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n                XCTAssertNil(first.ACL)\n                XCTAssertEqual(first.points, scoreOnServer.points)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch secondObject {\n\n            case .success(let second):\n                XCTAssert(second.hasSameObjectId(as: scoreOnServer2))\n                guard let savedCreatedAt = second.createdAt,\n                    let savedUpdatedAt = second.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                guard let originalCreatedAt = scoreOnServer2.createdAt,\n                    let originalUpdatedAt = scoreOnServer2.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n                XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n                XCTAssertNil(second.ACL)\n                XCTAssertEqual(second.points, scoreOnServer2.points)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    // swiftlint:disable:next function_body_length cyclomatic_complexity\n    func fetchAllAsync(scores: [GameScore], scoresOnServer: [GameScore],\n                       callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Fetch object1\")\n        guard let scoreOnServer = scoresOnServer.first,\n            let scoreOnServer2 = scoresOnServer.last else {\n            XCTFail(\"Should unwrap\")\n            expectation1.fulfill()\n            return\n        }\n\n        [GameScore(objectId: \"yarr\"), GameScore(objectId: \"yolo\")].fetchAll(options: [],\n                                                                            callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let fetched):\n                XCTAssertEqual(fetched.count, 2)\n                guard let firstObject = try? fetched.first(where: {try $0.get().objectId == \"yarr\"}),\n                    let secondObject = try? fetched.first(where: {try $0.get().objectId == \"yolo\"}) else {\n                        XCTFail(\"Should unwrap\")\n                        expectation1.fulfill()\n                        return\n                }\n\n                switch firstObject {\n\n                case .success(let first):\n                    XCTAssert(first.hasSameObjectId(as: scoreOnServer))\n                    guard let savedCreatedAt = first.createdAt,\n                        let savedUpdatedAt = first.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    guard let originalCreatedAt = scoreOnServer.createdAt,\n                        let originalUpdatedAt = scoreOnServer.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n                    XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n                    XCTAssertNil(first.ACL)\n                    XCTAssertEqual(first.points, scoreOnServer.points)\n                case .failure(let error):\n                    XCTFail(error.localizedDescription)\n                }\n\n                switch secondObject {\n\n                case .success(let second):\n                    XCTAssert(second.hasSameObjectId(as: scoreOnServer2))\n                    guard let savedCreatedAt = second.createdAt,\n                        let savedUpdatedAt = second.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    guard let originalCreatedAt = scoreOnServer2.createdAt,\n                        let originalUpdatedAt = scoreOnServer2.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n                    XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n                    XCTAssertNil(second.ACL)\n                    XCTAssertEqual(second.points, scoreOnServer2.points)\n                case .failure(let error):\n                    XCTFail(error.localizedDescription)\n                }\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testThreadSafeFetchAllAsync() {\n        let score = GameScore(points: 10)\n        let score2 = GameScore(points: 20)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.objectId = \"yolo\"\n        scoreOnServer2.createdAt = Calendar.current.date(byAdding: .init(day: -2), to: Date())\n        scoreOnServer2.updatedAt = scoreOnServer2.createdAt\n        scoreOnServer2.ACL = nil\n\n        let response = QueryResponse<GameScore>(results: [scoreOnServer, scoreOnServer2], count: 2)\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n           scoreOnServer2 = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        DispatchQueue.concurrentPerform(iterations: 100) {_ in\n            self.fetchAllAsync(scores: [score, score2], scoresOnServer: [scoreOnServer, scoreOnServer2],\n                              callbackQueue: .global(qos: .background))\n        }\n    }\n    #endif\n\n    func testFetchAllAsyncMainQueue() {\n        let score = GameScore(points: 10)\n        let score2 = GameScore(points: 20)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.objectId = \"yolo\"\n        scoreOnServer2.createdAt = Calendar.current.date(byAdding: .init(day: -2), to: Date())\n        scoreOnServer2.updatedAt = scoreOnServer2.createdAt\n        scoreOnServer2.ACL = nil\n\n        let response = QueryResponse<GameScore>(results: [scoreOnServer, scoreOnServer2], count: 2)\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n           scoreOnServer2 = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        self.fetchAllAsync(scores: [score, score2], scoresOnServer: [scoreOnServer, scoreOnServer2],\n                          callbackQueue: .main)\n    }\n\n    func testDeleteAll() {\n        let response = [BatchResponseItem<NoBody>(success: NoBody(), error: nil),\n                        BatchResponseItem<NoBody>(success: NoBody(), error: nil)]\n\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            let deleted = try [GameScore(objectId: \"yarr\"), GameScore(objectId: \"yolo\")].deleteAll()\n\n            XCTAssertEqual(deleted.count, 2)\n            guard let firstObject = deleted.first else {\n                    XCTFail(\"Should unwrap\")\n                    return\n            }\n\n            if case let .failure(error) = firstObject {\n                XCTFail(error.localizedDescription)\n            }\n\n            guard let lastObject = deleted.last else {\n                    XCTFail(\"Should unwrap\")\n                    return\n            }\n\n            if case let .failure(error) = lastObject {\n                XCTFail(error.localizedDescription)\n            }\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        do {\n            let deleted = try [GameScore(objectId: \"yarr\"), GameScore(objectId: \"yolo\")]\n                .deleteAll(transaction: true)\n\n            XCTAssertEqual(deleted.count, 2)\n            guard let firstObject = deleted.first else {\n                    XCTFail(\"Should unwrap\")\n                    return\n            }\n\n            if case let .failure(error) = firstObject {\n                XCTFail(error.localizedDescription)\n            }\n\n            guard let lastObject = deleted.last else {\n                    XCTFail(\"Should unwrap\")\n                    return\n            }\n\n            if case let .failure(error) = lastObject {\n                XCTFail(error.localizedDescription)\n            }\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testDeleteAllTransaction() {\n        let response = [BatchResponseItem<NoBody>(success: NoBody(), error: nil),\n                        BatchResponseItem<NoBody>(success: NoBody(), error: nil)]\n\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            let deleted = try [GameScore(objectId: \"yarr\"), GameScore(objectId: \"yolo\")].deleteAll(transaction: true)\n\n            XCTAssertEqual(deleted.count, 2)\n            guard let firstObject = deleted.first else {\n                    XCTFail(\"Should unwrap\")\n                    return\n            }\n\n            if case let .failure(error) = firstObject {\n                XCTFail(error.localizedDescription)\n            }\n\n            guard let lastObject = deleted.last else {\n                    XCTFail(\"Should unwrap\")\n                    return\n            }\n\n            if case let .failure(error) = lastObject {\n                XCTFail(error.localizedDescription)\n            }\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        do {\n            let deleted = try [GameScore(objectId: \"yarr\"), GameScore(objectId: \"yolo\")]\n                .deleteAll(transaction: true)\n\n            XCTAssertEqual(deleted.count, 2)\n            guard let firstObject = deleted.first else {\n                    XCTFail(\"Should unwrap\")\n                    return\n            }\n\n            if case let .failure(error) = firstObject {\n                XCTFail(error.localizedDescription)\n            }\n\n            guard let lastObject = deleted.last else {\n                    XCTFail(\"Should unwrap\")\n                    return\n            }\n\n            if case let .failure(error) = lastObject {\n                XCTFail(error.localizedDescription)\n            }\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testDeleteAllTransactionErrorTooMany() {\n        do {\n            _ = try [GameScore(objectId: \"yarr\"),\n                     GameScore(objectId: \"yolo\")].deleteAll(batchLimit: 1,\n                                                            transaction: true)\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Error should have casted to ParseError\")\n                return\n            }\n            XCTAssertEqual(parseError.code, .unknownError)\n            XCTAssertTrue(parseError.message.contains(\"exceed\"))\n        }\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testDeleteAllError() {\n        let parseError = ParseError(code: .objectNotFound, message: \"Object not found\")\n        let response = [BatchResponseItem<NoBody>(success: nil, error: parseError),\n                        BatchResponseItem<NoBody>(success: nil, error: parseError)]\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            let deleted = try [GameScore(objectId: \"yarr\"), GameScore(objectId: \"yolo\")].deleteAll()\n\n            XCTAssertEqual(deleted.count, 2)\n            guard let firstObject = deleted.first else {\n                    XCTFail(\"Should have thrown ParseError\")\n                    return\n            }\n\n            if case let .failure(error) = firstObject {\n                XCTAssertEqual(error.code, parseError.code)\n            } else {\n                XCTFail(\"Should have thrown ParseError\")\n            }\n\n            guard let lastObject = deleted.last else {\n                    XCTFail(\"Should have thrown ParseError\")\n                    return\n            }\n\n            if case let .failure(error) = lastObject {\n                XCTAssertEqual(error.code, parseError.code)\n            } else {\n                XCTFail(\"Should have thrown ParseError\")\n            }\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n    #endif\n\n    func deleteAllAsync(transaction: Bool = false, callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Delete object1\")\n        let expectation2 = XCTestExpectation(description: \"Delete object2\")\n\n        [GameScore(objectId: \"yarr\"), GameScore(objectId: \"yolo\")]\n            .deleteAll(transaction: transaction, callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let deleted):\n                XCTAssertEqual(deleted.count, 2)\n                guard let firstObject = deleted.first else {\n                    XCTFail(\"Should unwrap\")\n                    expectation1.fulfill()\n                    return\n                }\n\n                if case let .failure(error) = firstObject {\n                    XCTFail(error.localizedDescription)\n                }\n\n                guard let lastObject = deleted.last else {\n                    XCTFail(\"Should unwrap\")\n                    expectation1.fulfill()\n                    return\n                }\n\n                if case let .failure(error) = lastObject {\n                    XCTFail(error.localizedDescription)\n                }\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n\n        [GameScore(objectId: \"yarr\"), GameScore(objectId: \"yolo\")]\n            .deleteAll(transaction: true,\n                       callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let deleted):\n                XCTAssertEqual(deleted.count, 2)\n                guard let firstObject = deleted.first else {\n                    XCTFail(\"Should unwrap\")\n                    expectation2.fulfill()\n                    return\n                }\n\n                if case let .failure(error) = firstObject {\n                    XCTFail(error.localizedDescription)\n                }\n\n                guard let lastObject = deleted.last else {\n                    XCTFail(\"Should unwrap\")\n                    expectation2.fulfill()\n                    return\n                }\n\n                if case let .failure(error) = lastObject {\n                    XCTFail(error.localizedDescription)\n                }\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n                expectation2.fulfill()\n        }\n\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testDeleteAllAsyncMainQueue() {\n        let response = [BatchResponseItem<NoBody>(success: NoBody(), error: nil),\n                        BatchResponseItem<NoBody>(success: NoBody(), error: nil)]\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(response)\n            MockURLProtocol.mockRequests { _ in\n               return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            }\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n\n        self.deleteAllAsync(callbackQueue: .main)\n    }\n\n    func testDeleteAllAsyncMainQueueTransaction() {\n        let response = [BatchResponseItem<NoBody>(success: NoBody(), error: nil),\n                        BatchResponseItem<NoBody>(success: NoBody(), error: nil)]\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(response)\n            MockURLProtocol.mockRequests { _ in\n               return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            }\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n\n        self.deleteAllAsync(transaction: true, callbackQueue: .main)\n    }\n\n    func testDeleteAllAsyncTransactionErrorTooMany() {\n        let expectation1 = XCTestExpectation(description: \"Save object1\")\n        [GameScore(objectId: \"yarr\"),\n         GameScore(objectId: \"yolo\")].deleteAll(batchLimit: 1,\n                                                transaction: true) { result in\n            if case .failure(let error) = result {\n                XCTAssertEqual(error.code, .unknownError)\n                XCTAssertTrue(error.message.contains(\"exceed\"))\n            } else {\n                XCTFail(\"Should have received error\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func deleteAllAsyncError(parseError: ParseError, callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Delete object1\")\n\n        [GameScore(objectId: \"yarr\"), GameScore(objectId: \"yolo\")]\n            .deleteAll(callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let deleted):\n                XCTAssertEqual(deleted.count, 2)\n                guard let firstObject = deleted.first else {\n                    XCTFail(\"Should have thrown ParseError\")\n                    expectation1.fulfill()\n                    return\n                }\n\n                if case let .failure(error) = firstObject {\n                    XCTAssertEqual(error.code, parseError.code)\n                } else {\n                    XCTFail(\"Should have thrown ParseError\")\n                }\n\n                guard let lastObject = deleted.last else {\n                    XCTFail(\"Should have thrown ParseError\")\n                    expectation1.fulfill()\n                    return\n                }\n\n                if case let .failure(error) = lastObject {\n                    XCTAssertEqual(error.code, parseError.code)\n                } else {\n                    XCTFail(\"Should have thrown ParseError\")\n                }\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDeleteAllAsyncMainQueueError() {\n\n        let parseError = ParseError(code: .objectNotFound, message: \"Object not found\")\n        let response = [BatchResponseItem<NoBody>(success: nil, error: parseError),\n                        BatchResponseItem<NoBody>(success: nil, error: parseError)]\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(response)\n            MockURLProtocol.mockRequests { _ in\n               return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            }\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n\n        self.deleteAllAsyncError(parseError: parseError, callbackQueue: .main)\n    }\n}// swiftlint:disable:this file_length\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseObjectCombineTests.swift",
    "content": "//\n//  ParseObjectCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/30/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseObjectCombineTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct GameScore: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int?\n        var player: String?\n\n        //custom initializers\n        init() {}\n        init (objectId: String?) {\n            self.objectId = objectId\n        }\n        init(points: Int) {\n            self.points = points\n            self.player = \"Jen\"\n        }\n        init(points: Int, name: String) {\n            self.points = points\n            self.player = name\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testFetch() {\n        var score = GameScore(points: 10)\n        let objectId = \"yarr\"\n        score.objectId = objectId\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Fetch\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = score.fetchPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { fetched in\n\n            XCTAssert(fetched.hasSameObjectId(as: scoreOnServer))\n            guard let fetchedCreatedAt = fetched.createdAt,\n                let fetchedUpdatedAt = fetched.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalCreatedAt = scoreOnServer.createdAt,\n                let originalUpdatedAt = scoreOnServer.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n            XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(fetched.ACL)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSave() {\n        let score = GameScore(points: 10)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = score.savePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n            guard let savedCreatedAt = saved.createdAt,\n                let savedUpdatedAt = saved.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(savedCreatedAt, scoreOnServer.createdAt)\n            XCTAssertEqual(savedUpdatedAt, scoreOnServer.createdAt)\n            XCTAssertNil(saved.ACL)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testCreate() {\n        let score = GameScore(points: 10)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = score.createPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n            guard let savedCreatedAt = saved.createdAt,\n                let savedUpdatedAt = saved.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalCreatedAt = scoreOnServer.createdAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n            XCTAssertEqual(savedUpdatedAt, originalCreatedAt)\n            XCTAssertNil(saved.ACL)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUpdate() {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n\n        var scoreOnServer = score\n        scoreOnServer.updatedAt = Date()\n        scoreOnServer.ACL = nil\n\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = score.updatePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n            guard let savedUpdatedAt = saved.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalUpdatedAt = scoreOnServer.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(saved.ACL)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDelete() {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n\n        let scoreOnServer = NoBody()\n\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = score.deletePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testFetchAll() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Fetch\")\n\n        let score = GameScore(points: 10)\n        let score2 = GameScore(points: 20)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.objectId = \"yolo\"\n        scoreOnServer2.createdAt = Calendar.current.date(byAdding: .init(day: -2), to: Date())\n        scoreOnServer2.updatedAt = scoreOnServer2.createdAt\n        scoreOnServer2.ACL = nil\n\n        let response = QueryResponse<GameScore>(results: [scoreOnServer, scoreOnServer2], count: 2)\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n           scoreOnServer2 = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = [GameScore(objectId: \"yarr\"), GameScore(objectId: \"yolo\")].fetchAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { fetched in\n\n            XCTAssertEqual(fetched.count, 2)\n            guard let firstObject = try? fetched.first(where: {try $0.get().objectId == \"yarr\"}),\n                let secondObject = try? fetched.first(where: {try $0.get().objectId == \"yolo\"}) else {\n                    XCTFail(\"Should unwrap\")\n                    return\n            }\n\n            switch firstObject {\n\n            case .success(let first):\n                XCTAssert(first.hasSameObjectId(as: scoreOnServer))\n                guard let fetchedCreatedAt = first.createdAt,\n                    let fetchedUpdatedAt = first.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                guard let originalCreatedAt = scoreOnServer.createdAt,\n                    let originalUpdatedAt = scoreOnServer.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n                XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n                XCTAssertNil(first.ACL)\n                XCTAssertEqual(first.points, scoreOnServer.points)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch secondObject {\n\n            case .success(let second):\n                XCTAssert(second.hasSameObjectId(as: scoreOnServer2))\n                guard let savedCreatedAt = second.createdAt,\n                    let savedUpdatedAt = second.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                guard let originalCreatedAt = scoreOnServer2.createdAt,\n                    let originalUpdatedAt = scoreOnServer2.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n                XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n                XCTAssertNil(second.ACL)\n                XCTAssertEqual(second.points, scoreOnServer2.points)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSaveAll() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        let score = GameScore(points: 10)\n        let score2 = GameScore(points: 20)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.objectId = \"yolo\"\n        scoreOnServer2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        scoreOnServer2.ACL = nil\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil),\n        BatchResponseItem<GameScore>(success: scoreOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n           scoreOnServer2 = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = [score, score2].saveAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            XCTAssertEqual(saved.count, 2)\n            switch saved[0] {\n\n            case .success(let first):\n                XCTAssert(first.hasSameObjectId(as: scoreOnServer))\n                guard let savedCreatedAt = first.createdAt,\n                    let savedUpdatedAt = first.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedCreatedAt, scoreOnServer.createdAt)\n                XCTAssertEqual(savedUpdatedAt, scoreOnServer.createdAt)\n                XCTAssertNil(first.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch saved[1] {\n\n            case .success(let second):\n                XCTAssert(second.hasSameObjectId(as: scoreOnServer2))\n                guard let savedCreatedAt = second.createdAt,\n                    let savedUpdatedAt = second.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedCreatedAt, scoreOnServer2.createdAt)\n                XCTAssertEqual(savedUpdatedAt, scoreOnServer2.createdAt)\n                XCTAssertNil(second.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testCreateAll() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        let score = GameScore(points: 10)\n        let score2 = GameScore(points: 20)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.objectId = \"yolo\"\n        scoreOnServer2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil),\n        BatchResponseItem<GameScore>(success: scoreOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n           scoreOnServer2 = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = [score, score2].createAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            XCTAssertEqual(saved.count, 2)\n            switch saved[0] {\n\n            case .success(let first):\n                XCTAssert(first.hasSameObjectId(as: scoreOnServer))\n                guard let savedCreatedAt = first.createdAt,\n                    let savedUpdatedAt = first.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                guard let originalCreatedAt = scoreOnServer.createdAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n                XCTAssertEqual(savedUpdatedAt, originalCreatedAt)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch saved[1] {\n\n            case .success(let second):\n                XCTAssert(second.hasSameObjectId(as: scoreOnServer2))\n                guard let savedCreatedAt = second.createdAt,\n                    let savedUpdatedAt = second.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                guard let originalCreatedAt = scoreOnServer2.createdAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n                XCTAssertEqual(savedUpdatedAt, originalCreatedAt)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testReplaceAllCreate() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        var score2 = GameScore(points: 20)\n        score2.objectId = \"yolo\"\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil),\n        BatchResponseItem<GameScore>(success: scoreOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n           scoreOnServer2 = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = [score, score2].replaceAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            XCTAssertEqual(saved.count, 2)\n            switch saved[0] {\n\n            case .success(let first):\n                XCTAssert(first.hasSameObjectId(as: scoreOnServer))\n                guard let originalCreatedAt = scoreOnServer.createdAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(first.createdAt, originalCreatedAt)\n                XCTAssertEqual(first.updatedAt, originalCreatedAt)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch saved[1] {\n\n            case .success(let second):\n                XCTAssert(second.hasSameObjectId(as: scoreOnServer2))\n                guard let originalCreatedAt = scoreOnServer2.createdAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(second.createdAt, originalCreatedAt)\n                XCTAssertEqual(second.updatedAt, originalCreatedAt)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testReplaceAllUpdate() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        var score2 = GameScore(points: 20)\n        score2.objectId = \"yolo\"\n\n        var scoreOnServer = score\n        scoreOnServer.updatedAt = Date()\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil),\n        BatchResponseItem<GameScore>(success: scoreOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n           scoreOnServer2 = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = [score, score2].replaceAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            XCTAssertEqual(saved.count, 2)\n            switch saved[0] {\n\n            case .success(let first):\n                XCTAssert(first.hasSameObjectId(as: scoreOnServer))\n                guard let savedUpdatedAt = first.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                guard let originalUpdatedAt = scoreOnServer.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch saved[1] {\n\n            case .success(let second):\n                XCTAssert(second.hasSameObjectId(as: scoreOnServer2))\n                guard let savedUpdatedAt = second.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                guard let originalUpdatedAt = scoreOnServer2.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUpdateAll() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        var score2 = GameScore(points: 20)\n        score2.objectId = \"yolo\"\n\n        var scoreOnServer = score\n        scoreOnServer.updatedAt = Date()\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil),\n        BatchResponseItem<GameScore>(success: scoreOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n           scoreOnServer2 = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = [score, score2].updateAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            XCTAssertEqual(saved.count, 2)\n            switch saved[0] {\n\n            case .success(let first):\n                XCTAssert(first.hasSameObjectId(as: scoreOnServer))\n                guard let savedUpdatedAt = first.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                guard let originalUpdatedAt = scoreOnServer.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch saved[1] {\n\n            case .success(let second):\n                XCTAssert(second.hasSameObjectId(as: scoreOnServer2))\n                guard let savedUpdatedAt = second.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                guard let originalUpdatedAt = scoreOnServer2.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDeleteAll() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        let response = [BatchResponseItem<NoBody>(success: NoBody(), error: nil),\n                        BatchResponseItem<NoBody>(success: NoBody(), error: nil)]\n\n        let encoded: Data!\n        do {\n           encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = [GameScore(objectId: \"yarr\"), GameScore(objectId: \"yolo\")].deleteAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { deleted in\n            XCTAssertEqual(deleted.count, 2)\n            guard let firstObject = deleted.first else {\n                    XCTFail(\"Should unwrap\")\n                    return\n            }\n\n            if case let .failure(error) = firstObject {\n                XCTFail(error.localizedDescription)\n            }\n\n            guard let lastObject = deleted.last else {\n                    XCTFail(\"Should unwrap\")\n                    return\n            }\n\n            if case let .failure(error) = lastObject {\n                XCTFail(error.localizedDescription)\n            }\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseObjectCustomObjectIdTests.swift",
    "content": "//\n//  ParseObjectCustomObjectIdTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 3/20/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseObjectCustomObjectIdTests: XCTestCase { // swiftlint:disable:this type_body_length\n    struct Level: ParseObject {\n        var objectId: String?\n\n        var createdAt: Date?\n\n        var updatedAt: Date?\n\n        var ACL: ParseACL?\n\n        var originalData: Data?\n\n        var name = \"First\"\n    }\n\n    struct GameScore: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int?\n        var player: String?\n        var level: Level?\n        var levels: [Level]?\n\n        //custom initializers\n        init() {}\n        init (objectId: String?) {\n            self.objectId = objectId\n        }\n        init(points: Int) {\n            self.points = points\n            self.player = \"Jen\"\n        }\n        init(points: Int, name: String) {\n            self.points = points\n            self.player = name\n        }\n    }\n\n    struct Game: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var gameScore: GameScore\n        var gameScores = [GameScore]()\n        var name = \"Hello\"\n        var profilePicture: ParseFile?\n\n        //: a custom initializer\n        init() {\n            self.gameScore = GameScore()\n        }\n        init(gameScore: GameScore) {\n            self.gameScore = gameScore\n        }\n    }\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n    }\n\n    struct Installation: ParseInstallation {\n        var installationId: String?\n        var deviceType: String?\n        var deviceToken: String?\n        var badge: Int?\n        var timeZone: String?\n        var channels: [String]?\n        var appName: String?\n        var appIdentifier: String?\n        var appVersion: String?\n        var parseVersion: String?\n        var localeIdentifier: String?\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n        var customKey: String?\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              requiringCustomObjectIds: true,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n\n        guard let fileManager = ParseFileManager() else {\n            throw ParseError(code: .unknownError, message: \"Should have initialized file manage\")\n        }\n\n        let directory2 = try ParseFileManager.downloadDirectory()\n        let expectation2 = XCTestExpectation(description: \"Delete files2\")\n        fileManager.removeDirectoryContents(directory2) { _ in\n            expectation2.fulfill()\n        }\n        wait(for: [expectation2], timeout: 20.0)\n    }\n\n    func testSaveCommand() throws {\n        let objectId = \"yarr\"\n        var score = GameScore(points: 10)\n        score.objectId = objectId\n        let className = score.className\n\n        let command = try score.saveCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/classes/\\(className)\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertNil(command.params)\n\n        guard let body = command.body else {\n            XCTFail(\"Should be able to unwrap\")\n            return\n        }\n\n        let expected = \"{\\\"objectId\\\":\\\"yarr\\\",\\\"player\\\":\\\"Jen\\\",\\\"points\\\":10}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(body, collectChildren: false,\n                    objectsSavedBeforeThisOne: nil,\n                    filesSavedBeforeThisOne: nil).encoded\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testSaveUpdateCommand() throws {\n        var score = GameScore(points: 10)\n        let className = score.className\n        let objectId = \"yarr\"\n        score.objectId = objectId\n        score.createdAt = Date()\n        score.updatedAt = score.createdAt\n\n        let command = try score.saveCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/classes/\\(className)/\\(objectId)\")\n        XCTAssertEqual(command.method, API.Method.PUT)\n        XCTAssertNil(command.params)\n\n        guard let body = command.body else {\n            XCTFail(\"Should be able to unwrap\")\n            return\n        }\n\n        let expected = \"{\\\"objectId\\\":\\\"yarr\\\",\\\"player\\\":\\\"Jen\\\",\\\"points\\\":10}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(body, collectChildren: false,\n                    objectsSavedBeforeThisOne: nil,\n                    filesSavedBeforeThisOne: nil).encoded\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testSaveAllCommand() throws {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        var score2 = GameScore(points: 20)\n        score2.objectId = \"yolo\"\n\n        let objects = [score, score2]\n        let commands = try objects.map { try $0.saveCommand() }\n        let body = BatchCommand(requests: commands, transaction: false)\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"requests\\\":[{\\\"body\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"yarr\\\"},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"\\\\/classes\\\\/GameScore\\\"},{\\\"body\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"yolo\\\"},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"\\\\/classes\\\\/GameScore\\\"}],\\\"transaction\\\":false}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(body, collectChildren: false,\n                    objectsSavedBeforeThisOne: nil,\n                    filesSavedBeforeThisOne: nil).encoded\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testUpdateAllCommand() throws {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        score.createdAt = Date()\n        var score2 = GameScore(points: 20)\n        score2.objectId = \"yolo\"\n        score2.createdAt = Date()\n\n        let objects = [score, score2]\n        let commands = try objects.map { try $0.saveCommand() }\n        let body = BatchCommand(requests: commands, transaction: false)\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"requests\\\":[{\\\"body\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"yarr\\\"},\\\"method\\\":\\\"PUT\\\",\\\"path\\\":\\\"\\\\/classes\\\\/GameScore\\\\/yarr\\\"},{\\\"body\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"yolo\\\"},\\\"method\\\":\\\"PUT\\\",\\\"path\\\":\\\"\\\\/classes\\\\/GameScore\\\\/yolo\\\"}],\\\"transaction\\\":false}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(body, collectChildren: false,\n                    objectsSavedBeforeThisOne: nil,\n                    filesSavedBeforeThisOne: nil).encoded\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testUserSaveCommand() throws {\n        let objectId = \"yarr\"\n        var user = User()\n        user.objectId = objectId\n\n        let command = try user.saveCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/users\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertNil(command.params)\n\n        guard let body = command.body else {\n            XCTFail(\"Should be able to unwrap\")\n            return\n        }\n\n        let expected = \"{\\\"objectId\\\":\\\"yarr\\\"}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(body, collectChildren: false,\n                    objectsSavedBeforeThisOne: nil,\n                    filesSavedBeforeThisOne: nil).encoded\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testUserUpdateCommand() throws {\n        let objectId = \"yarr\"\n        var user = User()\n        user.objectId = objectId\n        user.createdAt = Date()\n\n        let command = try user.saveCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/users/\\(objectId)\")\n        XCTAssertEqual(command.method, API.Method.PUT)\n        XCTAssertNil(command.params)\n\n        guard let body = command.body else {\n            XCTFail(\"Should be able to unwrap\")\n            return\n        }\n\n        let expected = \"{\\\"objectId\\\":\\\"yarr\\\"}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(body, collectChildren: false,\n                    objectsSavedBeforeThisOne: nil,\n                    filesSavedBeforeThisOne: nil).encoded\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testUserSaveAllCommand() throws {\n        var user = User()\n        user.objectId = \"yarr\"\n        var user2 = User()\n        user2.objectId = \"yolo\"\n\n        let objects = [user, user2]\n        let commands = try objects.map { try $0.saveCommand() }\n        let body = BatchCommand(requests: commands, transaction: false)\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"requests\\\":[{\\\"body\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"_User\\\",\\\"objectId\\\":\\\"yarr\\\"},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"\\\\/users\\\"},{\\\"body\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"_User\\\",\\\"objectId\\\":\\\"yolo\\\"},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"\\\\/users\\\"}],\\\"transaction\\\":false}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(body, collectChildren: false,\n                    objectsSavedBeforeThisOne: nil,\n                    filesSavedBeforeThisOne: nil).encoded\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testUserUpdateAllCommand() throws {\n        var user = User()\n        user.objectId = \"yarr\"\n        user.createdAt = Date()\n        var user2 = User()\n        user2.objectId = \"yolo\"\n        user2.createdAt = Date()\n\n        let objects = [user, user2]\n        let commands = try objects.map { try $0.saveCommand() }\n        let body = BatchCommand(requests: commands, transaction: false)\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"requests\\\":[{\\\"body\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"_User\\\",\\\"objectId\\\":\\\"yarr\\\"},\\\"method\\\":\\\"PUT\\\",\\\"path\\\":\\\"\\\\/users\\\\/yarr\\\"},{\\\"body\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"_User\\\",\\\"objectId\\\":\\\"yolo\\\"},\\\"method\\\":\\\"PUT\\\",\\\"path\\\":\\\"\\\\/users\\\\/yolo\\\"}],\\\"transaction\\\":false}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(body, collectChildren: false,\n                    objectsSavedBeforeThisOne: nil,\n                    filesSavedBeforeThisOne: nil).encoded\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testInstallationSaveCommand() throws {\n        let objectId = \"yarr\"\n        var installation = Installation()\n        installation.objectId = objectId\n\n        let command = try installation.saveCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/installations\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertNil(command.params)\n\n        guard let body = command.body else {\n            XCTFail(\"Should be able to unwrap\")\n            return\n        }\n\n        let expected = \"{\\\"objectId\\\":\\\"yarr\\\"}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(body, collectChildren: false,\n                    objectsSavedBeforeThisOne: nil,\n                    filesSavedBeforeThisOne: nil).encoded\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testInstallationUpdateCommand() throws {\n        let objectId = \"yarr\"\n        var installation = Installation()\n        installation.objectId = objectId\n        installation.createdAt = Date()\n\n        let command = try installation.saveCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/installations/\\(objectId)\")\n        XCTAssertEqual(command.method, API.Method.PUT)\n        XCTAssertNil(command.params)\n\n        guard let body = command.body else {\n            XCTFail(\"Should be able to unwrap\")\n            return\n        }\n\n        let expected = \"{\\\"objectId\\\":\\\"yarr\\\"}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(body, collectChildren: false,\n                    objectsSavedBeforeThisOne: nil,\n                    filesSavedBeforeThisOne: nil).encoded\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testInstallationSaveAllCommand() throws {\n        var installation = Installation()\n        installation.objectId = \"yarr\"\n        var installation2 = Installation()\n        installation2.objectId = \"yolo\"\n\n        let objects = [installation, installation2]\n        let commands = try objects.map { try $0.saveCommand() }\n        let body = BatchCommand(requests: commands, transaction: false)\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"requests\\\":[{\\\"body\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"_Installation\\\",\\\"objectId\\\":\\\"yarr\\\"},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"\\\\/installations\\\"},{\\\"body\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"_Installation\\\",\\\"objectId\\\":\\\"yolo\\\"},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"\\\\/installations\\\"}],\\\"transaction\\\":false}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(body, collectChildren: false,\n                    objectsSavedBeforeThisOne: nil,\n                    filesSavedBeforeThisOne: nil).encoded\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testInstallationUpdateAllCommand() throws {\n        var installation = Installation()\n        installation.objectId = \"yarr\"\n        installation.createdAt = Date()\n        var installation2 = Installation()\n        installation2.objectId = \"yolo\"\n        installation2.createdAt = Date()\n\n        let objects = [installation, installation2]\n        let commands = try objects.map { try $0.saveCommand() }\n        let body = BatchCommand(requests: commands, transaction: false)\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"requests\\\":[{\\\"body\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"_Installation\\\",\\\"objectId\\\":\\\"yarr\\\"},\\\"method\\\":\\\"PUT\\\",\\\"path\\\":\\\"\\\\/installations\\\\/yarr\\\"},{\\\"body\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"_Installation\\\",\\\"objectId\\\":\\\"yolo\\\"},\\\"method\\\":\\\"PUT\\\",\\\"path\\\":\\\"\\\\/installations\\\\/yolo\\\"}],\\\"transaction\\\":false}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(body, collectChildren: false,\n                    objectsSavedBeforeThisOne: nil,\n                    filesSavedBeforeThisOne: nil).encoded\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testSaveCommandNoObjectId() throws {\n        let score = GameScore(points: 10)\n        XCTAssertThrowsError(try score.saveCommand())\n    }\n\n    func testSaveCommandNoObjectIdIgnoreConfig() throws {\n        let score = GameScore(points: 10)\n        _ = try score.saveCommand(ignoringCustomObjectIdConfig: true)\n    }\n\n    func testUpdateCommandNoObjectId() throws {\n        var score = GameScore(points: 10)\n        score.createdAt = Date()\n        XCTAssertThrowsError(try score.saveCommand())\n    }\n\n    func testUpdateCommandNoObjectIdIgnoreConfig() throws {\n        var score = GameScore(points: 10)\n        score.createdAt = Date()\n        _ = try score.saveCommand(ignoringCustomObjectIdConfig: true)\n    }\n\n    func testSaveAllNoObjectIdCommand() throws {\n        let score = GameScore(points: 10)\n        let score2 = GameScore(points: 20)\n        let objects = [score, score2]\n        XCTAssertThrowsError(try objects.map { try $0.saveCommand() })\n    }\n\n    func testUpdateAllNoObjectIdCommand() throws {\n        var score = GameScore(points: 10)\n        score.createdAt = Date()\n        var score2 = GameScore(points: 20)\n        score2.createdAt = Date()\n        let objects = [score, score2]\n        XCTAssertThrowsError(try objects.map { try $0.saveCommand() })\n    }\n\n    func testUserSaveCommandNoObjectId() throws {\n        let user = User()\n        XCTAssertThrowsError(try user.saveCommand())\n    }\n\n    func testUserSaveCommandNoObjectIdIgnoreConfig() throws {\n        let user = User()\n        _ = try user.saveCommand(ignoringCustomObjectIdConfig: true)\n    }\n\n    func testUserUpdateCommandNoObjectId() throws {\n        var user = User()\n        user.createdAt = Date()\n        XCTAssertThrowsError(try user.saveCommand())\n    }\n\n    func testUserUpdateCommandNoObjectIdIgnoreConfig() throws {\n        var user = User()\n        user.createdAt = Date()\n        _ = try user.saveCommand(ignoringCustomObjectIdConfig: true)\n    }\n\n    func testUserSaveAllNoObjectIdCommand() throws {\n        let user = User()\n        let user2 = User()\n        let objects = [user, user2]\n        XCTAssertThrowsError(try objects.map { try $0.saveCommand() })\n    }\n\n    func testUserUpdateAllNoObjectIdCommand() throws {\n        var user = GameScore(points: 10)\n        user.createdAt = Date()\n        var user2 = GameScore(points: 20)\n        user2.createdAt = Date()\n        let objects = [user, user2]\n        XCTAssertThrowsError(try objects.map { try $0.saveCommand() })\n    }\n\n    func testInstallationSaveCommandNoObjectId() throws {\n        let installation = Installation()\n        XCTAssertThrowsError(try installation.saveCommand())\n    }\n\n    func testInstallationSaveCommandNoObjectIdIgnoreConfig() throws {\n        let installation = Installation()\n        _ = try installation.saveCommand(ignoringCustomObjectIdConfig: true)\n    }\n\n    func testInstallationUpdateCommandNoObjectId() throws {\n        var installation = Installation()\n        installation.createdAt = Date()\n        XCTAssertThrowsError(try installation.saveCommand())\n    }\n\n    func testInstallationUpdateCommandNoObjectIdIgnoreConfig() throws {\n        var installation = Installation()\n        installation.createdAt = Date()\n        _ = try installation.saveCommand(ignoringCustomObjectIdConfig: true)\n    }\n\n    func testInstallationSaveAllNoObjectIdCommand() throws {\n        let installation = Installation()\n        let installation2 = Installation()\n        let objects = [installation, installation2]\n        XCTAssertThrowsError(try objects.map { try $0.saveCommand() })\n    }\n\n    func testInstallationUpdateAllNoObjectIdCommand() throws {\n        var score = GameScore(points: 10)\n        score.createdAt = Date()\n        var score2 = GameScore(points: 20)\n        score2.createdAt = Date()\n        let objects = [score, score2]\n        XCTAssertThrowsError(try objects.map { try $0.saveCommand() })\n    }\n\n    func testSave() { // swiftlint:disable:this function_body_length\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try score.save()\n            XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testSaveNoObjectId() throws {\n        let score = GameScore(points: 10)\n        XCTAssertThrowsError(try score.save())\n    }\n\n    func testSaveNoObjectIdIgnoreConfig() { // swiftlint:disable:this function_body_length\n        let score = GameScore(points: 10)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try score.save(ignoringCustomObjectIdConfig: true)\n            XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testUpdate() {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        score.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        score.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        score.ACL = nil\n\n        var scoreOnServer = score\n        scoreOnServer.updatedAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try score.save()\n            XCTAssertTrue(saved.hasSameObjectId(as: scoreOnServer))\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testUpdateNoObjectId() throws {\n        var score = GameScore(points: 10)\n        score.createdAt = Date()\n        XCTAssertThrowsError(try score.save())\n    }\n\n    func testUpdateNoObjectIdIgnoreConfig() {\n        var score = GameScore(points: 10)\n        score.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        score.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        score.ACL = nil\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.updatedAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try score.save(ignoringCustomObjectIdConfig: true)\n            XCTAssertTrue(saved.hasSameObjectId(as: scoreOnServer))\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    // swiftlint:disable:next function_body_length\n    func saveAsync(score: GameScore,\n                   scoreOnServer: GameScore,\n                   callbackQueue: DispatchQueue,\n                   ignoringCustomObjectIdConfig: Bool = false) {\n\n        let expectation1 = XCTestExpectation(description: \"Save object1\")\n\n        score.save(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                   options: [],\n                   callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let saved):\n                XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n\n        let expectation2 = XCTestExpectation(description: \"Save object2\")\n        score.save(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                   options: [.useMasterKey],\n                   callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let saved):\n                XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testSaveAsyncMainQueue() {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        self.saveAsync(score: score, scoreOnServer: scoreOnServer, callbackQueue: .main)\n    }\n\n    func testSaveNoObjectIdAsyncMainQueue() throws {\n        let score = GameScore(points: 10)\n        XCTAssertThrowsError(try score.save())\n\n        let expectation1 = XCTestExpectation(description: \"Save object2\")\n        score.save { result in\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"objectId\"))\n            } else {\n                XCTFail(\"Should have failed\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSaveNoObjectIdIgnoreConfigAsyncMainQueue() {\n        let score = GameScore(points: 10)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        self.saveAsync(score: score,\n                       scoreOnServer: scoreOnServer,\n                       callbackQueue: .main,\n                       ignoringCustomObjectIdConfig: true)\n    }\n\n    func updateAsync(score: GameScore,\n                     scoreOnServer: GameScore,\n                     ignoringCustomObjectIdConfig: Bool = false,\n                     callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Update object1\")\n\n        score.save(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                   options: [],\n                   callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let saved):\n                XCTAssertNil(saved.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n\n        let expectation2 = XCTestExpectation(description: \"Update object2\")\n        score.save(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                   options: [.useMasterKey],\n                   callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let saved):\n                XCTAssertTrue(saved.hasSameObjectId(as: scoreOnServer))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testUpdateAsyncMainQueue() {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        score.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        score.ACL = nil\n\n        var scoreOnServer = score\n        scoreOnServer.updatedAt = Date()\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        self.updateAsync(score: score, scoreOnServer: scoreOnServer, callbackQueue: .main)\n    }\n\n    func testUpdateNoObjectIdAsyncMainQueue() throws {\n        var score = GameScore(points: 10)\n        score.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        XCTAssertThrowsError(try score.save())\n\n        let expectation1 = XCTestExpectation(description: \"Save object2\")\n        score.save { result in\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"objectId\"))\n            } else {\n                XCTFail(\"Should have failed\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUpdateNoObjectIdIgnoreConfigAsyncMainQueue() {\n        var score = GameScore(points: 10)\n        score.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        score.ACL = nil\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.updatedAt = Date()\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        self.updateAsync(score: score,\n                         scoreOnServer: scoreOnServer,\n                         ignoringCustomObjectIdConfig: true,\n                         callbackQueue: .main)\n    }\n\n    func testSaveAll() { // swiftlint:disable:this function_body_length cyclomatic_complexity\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        var score2 = GameScore(points: 20)\n        score2.objectId = \"yolo\"\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        scoreOnServer2.ACL = nil\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil),\n        BatchResponseItem<GameScore>(success: scoreOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try scoreOnServer.getJSONEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n           scoreOnServer2 = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n\n            let saved = try [score, score2].saveAll()\n\n            XCTAssertEqual(saved.count, 2)\n            switch saved[0] {\n\n            case .success(let first):\n                XCTAssert(first.hasSameObjectId(as: scoreOnServer))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch saved[1] {\n\n            case .success(let second):\n                XCTAssert(second.hasSameObjectId(as: scoreOnServer2))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testSaveAllNoObjectId() throws {\n        let score = GameScore(points: 10)\n        let score2 = GameScore(points: 20)\n        XCTAssertThrowsError(try [score, score2].saveAll())\n    }\n\n    func testSaveAllNoObjectIdIgnoreConfig() { // swiftlint:disable:this function_body_length cyclomatic_complexity\n        let score = GameScore(points: 10)\n        let score2 = GameScore(points: 20)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.objectId = \"yolo\"\n        scoreOnServer2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        scoreOnServer2.ACL = nil\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil),\n        BatchResponseItem<GameScore>(success: scoreOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try scoreOnServer.getJSONEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n           scoreOnServer2 = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n\n            let saved = try [score, score2].saveAll(ignoringCustomObjectIdConfig: true)\n\n            XCTAssertEqual(saved.count, 2)\n            switch saved[0] {\n\n            case .success(let first):\n                XCTAssert(first.hasSameObjectId(as: scoreOnServer))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch saved[1] {\n\n            case .success(let second):\n                XCTAssert(second.hasSameObjectId(as: scoreOnServer2))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testSaveAllNoObjectIdAsync() throws {\n        let score = GameScore(points: 10)\n        let score2 = GameScore(points: 20)\n\n        let expectation1 = XCTestExpectation(description: \"Save object2\")\n        [score, score2].saveAll { result in\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"objectId\"))\n            } else {\n                XCTFail(\"Should have failed\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUpdateAll() { // swiftlint:disable:this function_body_length cyclomatic_complexity\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        score.createdAt = Date()\n        var score2 = GameScore(points: 20)\n        score2.objectId = \"yolo\"\n        score2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        var scoreOnServer = score\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        var scoreOnServer2 = score2\n        scoreOnServer2.updatedAt = scoreOnServer2.createdAt\n        scoreOnServer2.ACL = nil\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil),\n        BatchResponseItem<GameScore>(success: scoreOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n           encoded = try scoreOnServer.getJSONEncoder().encode(response)\n           //Get dates in correct format from ParseDecoding strategy\n           let encoded1 = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n           scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded1)\n           let encoded2 = try ParseCoding.jsonEncoder().encode(scoreOnServer2)\n           scoreOnServer2 = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n\n            let saved = try [score, score2].saveAll()\n\n            XCTAssertEqual(saved.count, 2)\n            switch saved[0] {\n\n            case .success(let first):\n                XCTAssert(first.hasSameObjectId(as: scoreOnServer))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch saved[1] {\n\n            case .success(let second):\n                XCTAssert(second.hasSameObjectId(as: scoreOnServer2))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testUpdateAllNoObjectId() throws {\n        var score = GameScore(points: 10)\n        score.createdAt = Date()\n        var score2 = GameScore(points: 20)\n        score2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        XCTAssertThrowsError(try [score, score2].saveAll())\n    }\n\n    func testUpdateAllNoObjectIdAsync() throws {\n        var score = GameScore(points: 10)\n        score.createdAt = Date()\n        var score2 = GameScore(points: 20)\n        score2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        let expectation1 = XCTestExpectation(description: \"Save object2\")\n        [score, score2].saveAll { result in\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"objectId\"))\n            } else {\n                XCTFail(\"Should have failed\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUserSave() { // swiftlint:disable:this function_body_length\n        var user = User()\n        user.objectId = \"yarr\"\n        user.ACL = nil\n\n        var userOnServer = user\n        userOnServer.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(userOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try user.save()\n            XCTAssert(saved.hasSameObjectId(as: userOnServer))\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testUserSaveNoObjectId() throws {\n        let score = GameScore(points: 10)\n        XCTAssertThrowsError(try score.save())\n    }\n\n    func testUserSaveNoObjectIdIgnoreConfig() { // swiftlint:disable:this function_body_length\n        var user = User()\n        user.ACL = nil\n\n        var userOnServer = user\n        userOnServer.objectId = \"yarr\"\n        userOnServer.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(userOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try user.save(ignoringCustomObjectIdConfig: true)\n            XCTAssert(saved.hasSameObjectId(as: userOnServer))\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testUserUpdate() {\n        var user = User()\n        user.objectId = \"yarr\"\n        user.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        user.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        user.ACL = nil\n\n        var userOnServer = user\n        userOnServer.updatedAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(userOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try user.save()\n            XCTAssertTrue(saved.hasSameObjectId(as: userOnServer))\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testUserUpdateNoObjectId() throws {\n        var user = User()\n        user.createdAt = Date()\n        XCTAssertThrowsError(try user.save())\n    }\n\n    func testUserUpdateNoObjectIdIgnoreConfig() {\n        var user = User()\n        user.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        user.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        user.ACL = nil\n\n        var userOnServer = user\n        userOnServer.objectId = \"yarr\"\n        userOnServer.updatedAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(userOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try user.save(ignoringCustomObjectIdConfig: true)\n            XCTAssertTrue(saved.hasSameObjectId(as: userOnServer))\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    // swiftlint:disable:next function_body_length\n    func saveUserAsync(user: User, userOnServer: User,\n                       ignoringCustomObjectIdConfig: Bool = false,\n                       callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Update object1\")\n\n        user.save(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                  options: [],\n                  callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let saved):\n                XCTAssertTrue(saved.hasSameObjectId(as: userOnServer))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUserSaveAsyncMainQueue() {\n        var user = User()\n        user.objectId = \"yarr\"\n        user.ACL = nil\n\n        var userOnServer = user\n        userOnServer.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(userOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        self.saveUserAsync(user: user, userOnServer: userOnServer, callbackQueue: .main)\n    }\n\n    func testUserSaveNoObjectIdAsyncMainQueue() throws {\n        let user = User()\n        XCTAssertThrowsError(try user.save())\n\n        let expectation1 = XCTestExpectation(description: \"Save object2\")\n        user.save { result in\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"objectId\"))\n            } else {\n                XCTFail(\"Should have failed\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUserSaveNoObjectIdIgnoreConfigAsyncMainQueue() {\n        var user = User()\n        user.ACL = nil\n\n        var userOnServer = user\n        userOnServer.objectId = \"yarr\"\n        userOnServer.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(userOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        self.saveUserAsync(user: user,\n                           userOnServer: userOnServer,\n                           ignoringCustomObjectIdConfig: true,\n                           callbackQueue: .main)\n    }\n\n    func updateUserAsync(user: User, userOnServer: User,\n                         ignoringCustomObjectIdConfig: Bool = false,\n                         callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Update object1\")\n\n        user.save(options: [], callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let saved):\n                XCTAssertTrue(saved.hasSameObjectId(as: userOnServer))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUserUpdateAsyncMainQueue() {\n        var user = User()\n        user.objectId = \"yarr\"\n        user.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        user.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        user.ACL = nil\n\n        var userOnServer = user\n        userOnServer.updatedAt = Date()\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(userOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        self.updateUserAsync(user: user, userOnServer: userOnServer, callbackQueue: .main)\n    }\n\n    func testUserUpdateNoObjectIdAsyncMainQueue() throws {\n        var user = User()\n        user.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        XCTAssertThrowsError(try user.save())\n\n        let expectation1 = XCTestExpectation(description: \"Save object2\")\n        user.save { result in\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"objectId\"))\n            } else {\n                XCTFail(\"Should have failed\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUserSaveAll() { // swiftlint:disable:this function_body_length cyclomatic_complexity\n        var user = User()\n        user.objectId = \"yarr\"\n\n        var user2 = User()\n        user2.objectId = \"yolo\"\n\n        var userOnServer = user\n        userOnServer.createdAt = Date()\n        userOnServer.ACL = nil\n\n        var userOnServer2 = user2\n        userOnServer2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        userOnServer2.ACL = nil\n\n        let response = [BatchResponseItem<User>(success: userOnServer, error: nil),\n        BatchResponseItem<User>(success: userOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n            encoded = try userOnServer.getJSONEncoder().encode(response)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(userOnServer)\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded1)\n            let encoded2 = try ParseCoding.jsonEncoder().encode(userOnServer2)\n            userOnServer2 = try userOnServer.getDecoder().decode(User.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n\n            let saved = try [user, user2].saveAll()\n\n            XCTAssertEqual(saved.count, 2)\n            switch saved[0] {\n\n            case .success(let first):\n                XCTAssert(first.hasSameObjectId(as: userOnServer))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch saved[1] {\n\n            case .success(let second):\n                XCTAssert(second.hasSameObjectId(as: userOnServer2))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testUserSaveAllNoObjectId() throws {\n        let user = User()\n        let user2 = User()\n        XCTAssertThrowsError(try [user, user2].saveAll())\n    }\n\n    func testUserSaveAllNoObjectIdAsync() throws {\n        let user = User()\n        let user2 = User()\n\n        let expectation1 = XCTestExpectation(description: \"SaveAll user\")\n        [user, user2].saveAll { result in\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"objectId\"))\n            } else {\n                XCTFail(\"Should have failed\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUserUpdateAll() { // swiftlint:disable:this function_body_length cyclomatic_complexity\n        var user = User()\n        user.objectId = \"yarr\"\n        user.createdAt = Date()\n        var user2 = User()\n        user2.objectId = \"yolo\"\n        user2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        var userOnServer = user\n        userOnServer.updatedAt = userOnServer.createdAt\n        userOnServer.ACL = nil\n\n        var userOnServer2 = user2\n        userOnServer2.updatedAt = userOnServer2.createdAt\n        userOnServer2.ACL = nil\n\n        let response = [BatchResponseItem<User>(success: userOnServer, error: nil),\n        BatchResponseItem<User>(success: userOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n            encoded = try userOnServer.getJSONEncoder().encode(response)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(userOnServer)\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded1)\n            let encoded2 = try ParseCoding.jsonEncoder().encode(userOnServer2)\n            userOnServer2 = try userOnServer.getDecoder().decode(User.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n\n            let saved = try [user, user2].saveAll()\n\n            XCTAssertEqual(saved.count, 2)\n            switch saved[0] {\n\n            case .success(let first):\n                XCTAssert(first.hasSameObjectId(as: userOnServer))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch saved[1] {\n\n            case .success(let second):\n                XCTAssert(second.hasSameObjectId(as: userOnServer2))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testUserUpdateAllNoObjectId() throws {\n        var user = User()\n        user.createdAt = Date()\n        var user2 = User()\n        user2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        XCTAssertThrowsError(try [user, user2].saveAll())\n    }\n\n    // swiftlint:disable:next function_body_length cyclomatic_complexity\n    func testUserUpdateAllNoObjectIdIgnoreConfig() {\n        var user = User()\n        user.createdAt = Date()\n        var user2 = User()\n        user2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        var userOnServer = user\n        userOnServer.objectId = \"yarr\"\n        userOnServer.updatedAt = userOnServer.createdAt\n        userOnServer.ACL = nil\n\n        var userOnServer2 = user2\n        userOnServer2.objectId = \"yolo\"\n        userOnServer2.updatedAt = userOnServer2.createdAt\n        userOnServer2.ACL = nil\n\n        let response = [BatchResponseItem<User>(success: userOnServer, error: nil),\n        BatchResponseItem<User>(success: userOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n            encoded = try userOnServer.getJSONEncoder().encode(response)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(userOnServer)\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded1)\n            let encoded2 = try ParseCoding.jsonEncoder().encode(userOnServer2)\n            userOnServer2 = try userOnServer.getDecoder().decode(User.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n\n            let saved = try [user, user2].saveAll(ignoringCustomObjectIdConfig: true)\n\n            XCTAssertEqual(saved.count, 2)\n            switch saved[0] {\n\n            case .success(let first):\n                XCTAssert(first.hasSameObjectId(as: userOnServer))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch saved[1] {\n\n            case .success(let second):\n                XCTAssert(second.hasSameObjectId(as: userOnServer2))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testUserUpdateAllNoObjectIdAsync() throws {\n        var user = User()\n        user.createdAt = Date()\n        var user2 = User()\n        user2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        let expectation1 = XCTestExpectation(description: \"UpdateAll user\")\n        [user, user2].saveAll { result in\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"objectId\"))\n            } else {\n                XCTFail(\"Should have failed\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testInstallationSave() { // swiftlint:disable:this function_body_length\n        var installation = Installation()\n        installation.objectId = \"yarr\"\n        installation.ACL = nil\n\n        var installationOnServer = installation\n        installationOnServer.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try installation.save()\n            XCTAssert(saved.hasSameObjectId(as: installationOnServer))\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testInstallationSaveNoObjectId() throws {\n        let score = GameScore(points: 10)\n        XCTAssertThrowsError(try score.save())\n    }\n\n    func testInstallationSaveNoObjectIdIgnoreConfig() { // swiftlint:disable:this function_body_length\n        var installation = Installation()\n        installation.ACL = nil\n\n        var installationOnServer = installation\n        installationOnServer.objectId = \"yarr\"\n        installationOnServer.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try installation.save(ignoringCustomObjectIdConfig: true)\n            XCTAssert(saved.hasSameObjectId(as: installationOnServer))\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testInstallationUpdate() {\n        var installation = Installation()\n        installation.objectId = \"yarr\"\n        installation.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        installation.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        installation.ACL = nil\n\n        var installationOnServer = installation\n        installationOnServer.updatedAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try installation.save()\n            XCTAssertTrue(saved.hasSameObjectId(as: installationOnServer))\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testInstallationUpdateNoObjectId() throws {\n        var installation = Installation()\n        installation.createdAt = Date()\n        XCTAssertThrowsError(try installation.save())\n    }\n\n    func testInstallationUpdateNoObjectIdIgnoreConfig() {\n        var installation = Installation()\n        installation.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        installation.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        installation.ACL = nil\n\n        var installationOnServer = installation\n        installationOnServer.objectId = \"yarr\"\n        installationOnServer.updatedAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try installation.save(ignoringCustomObjectIdConfig: true)\n            XCTAssertTrue(saved.hasSameObjectId(as: installationOnServer))\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    // swiftlint:disable:next function_body_length\n    func saveInstallationAsync(installation: Installation,\n                               installationOnServer: Installation,\n                               ignoringCustomObjectIdConfig: Bool = false,\n                               callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Update object1\")\n\n        installation.save(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                          options: [],\n                          callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let saved):\n                XCTAssertTrue(saved.hasSameObjectId(as: installationOnServer))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n\n        let expectation2 = XCTestExpectation(description: \"Update object2\")\n        installation.save(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                          options: [.useMasterKey],\n                          callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let saved):\n                XCTAssertTrue(saved.hasSameObjectId(as: installationOnServer))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testInstallationSaveAsyncMainQueue() {\n        var installation = Installation()\n        installation.objectId = \"yarr\"\n        installation.ACL = nil\n\n        var installationOnServer = installation\n        installationOnServer.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        self.saveInstallationAsync(installation: installation,\n                                   installationOnServer: installationOnServer,\n                                   ignoringCustomObjectIdConfig: false,\n                                   callbackQueue: .main)\n    }\n\n    func testInstallationSaveNoObjectIdAsyncMainQueue() throws {\n        let installation = Installation()\n        XCTAssertThrowsError(try installation.save())\n\n        let expectation1 = XCTestExpectation(description: \"Save object2\")\n        installation.save { result in\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"objectId\"))\n            } else {\n                XCTFail(\"Should have failed\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testInstallationSaveNoObjectIdIgnoreConfigAsyncMainQueue() {\n        var installation = Installation()\n        installation.ACL = nil\n\n        var installationOnServer = installation\n        installationOnServer.objectId = \"yarr\"\n        installationOnServer.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        self.saveInstallationAsync(installation: installation,\n                                   installationOnServer: installationOnServer,\n                                   ignoringCustomObjectIdConfig: true,\n                                   callbackQueue: .main)\n    }\n\n    func updateInstallationAsync(installation: Installation,\n                                 installationOnServer: Installation,\n                                 ignoringCustomObjectIdConfig: Bool = false,\n                                 callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Update object1\")\n\n        installation.save(ignoringCustomObjectIdConfig: ignoringCustomObjectIdConfig,\n                          options: [],\n                          callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let saved):\n                XCTAssertTrue(saved.hasSameObjectId(as: installationOnServer))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testInstallationUpdateAsyncMainQueue() {\n        var installation = Installation()\n        installation.objectId = \"yarr\"\n        installation.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        installation.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        installation.ACL = nil\n\n        var installationOnServer = installation\n        installationOnServer.updatedAt = Date()\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        self.updateInstallationAsync(installation: installation,\n                                     installationOnServer: installationOnServer,\n                                     callbackQueue: .main)\n    }\n\n    func testInstallationUpdateNoObjectIdAsyncMainQueue() throws {\n        var installation = Installation()\n        installation.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        XCTAssertThrowsError(try installation.save())\n\n        let expectation1 = XCTestExpectation(description: \"Save object2\")\n        installation.save { result in\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"objectId\"))\n            } else {\n                XCTFail(\"Should have failed\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testInstallationUpdateNoObjectIdIgnoreConfigAsyncMainQueue() {\n        var installation = Installation()\n        installation.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        installation.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        installation.ACL = nil\n\n        var installationOnServer = installation\n        installationOnServer.objectId = \"yarr\"\n        installationOnServer.updatedAt = Date()\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        self.updateInstallationAsync(installation: installation,\n                                     installationOnServer: installationOnServer,\n                                     ignoringCustomObjectIdConfig: true,\n                                     callbackQueue: .main)\n    }\n\n    func testInstallationSaveAll() { // swiftlint:disable:this function_body_length cyclomatic_complexity\n        var installation = Installation()\n        installation.objectId = \"yarr\"\n\n        var installation2 = Installation()\n        installation2.objectId = \"yolo\"\n\n        var installationOnServer = installation\n        installationOnServer.createdAt = Date()\n        installationOnServer.ACL = nil\n\n        var installationOnServer2 = installation2\n        installationOnServer2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        installationOnServer2.ACL = nil\n\n        let response = [BatchResponseItem<Installation>(success: installationOnServer, error: nil),\n        BatchResponseItem<Installation>(success: installationOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n            encoded = try installationOnServer.getJSONEncoder().encode(response)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded1)\n            let encoded2 = try ParseCoding.jsonEncoder().encode(installationOnServer2)\n            installationOnServer2 = try installationOnServer.getDecoder().decode(Installation.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n\n            let saved = try [installation, installation2].saveAll()\n\n            XCTAssertEqual(saved.count, 2)\n            switch saved[0] {\n\n            case .success(let first):\n                XCTAssert(first.hasSameObjectId(as: installationOnServer))\n                guard let savedCreatedAt = first.createdAt,\n                    let savedUpdatedAt = first.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedCreatedAt, installationOnServer.createdAt)\n                XCTAssertEqual(savedUpdatedAt, installationOnServer.createdAt)\n                XCTAssertNil(first.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch saved[1] {\n\n            case .success(let second):\n                XCTAssert(second.hasSameObjectId(as: installationOnServer2))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testInstallationSaveAllNoObjectId() throws {\n        let installation = Installation()\n        let installation2 = Installation()\n        XCTAssertThrowsError(try [installation, installation2].saveAll())\n    }\n\n    func testInstallationSaveAllIgnoreConfig() { // swiftlint:disable:this function_body_length cyclomatic_complexity\n        let installation = Installation()\n\n        let installation2 = Installation()\n\n        var installationOnServer = installation\n        installationOnServer.objectId = \"yarr\"\n        installationOnServer.createdAt = Date()\n        installationOnServer.ACL = nil\n\n        var installationOnServer2 = installation2\n        installationOnServer2.objectId = \"yolo\"\n        installationOnServer2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        installationOnServer2.ACL = nil\n\n        let response = [BatchResponseItem<Installation>(success: installationOnServer, error: nil),\n        BatchResponseItem<Installation>(success: installationOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n            encoded = try installationOnServer.getJSONEncoder().encode(response)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded1)\n            let encoded2 = try ParseCoding.jsonEncoder().encode(installationOnServer2)\n            installationOnServer2 = try installationOnServer.getDecoder().decode(Installation.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n\n            let saved = try [installation, installation2].saveAll(ignoringCustomObjectIdConfig: true)\n\n            XCTAssertEqual(saved.count, 2)\n            switch saved[0] {\n\n            case .success(let first):\n                XCTAssert(first.hasSameObjectId(as: installationOnServer))\n                guard let savedCreatedAt = first.createdAt,\n                    let savedUpdatedAt = first.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedCreatedAt, installationOnServer.createdAt)\n                XCTAssertEqual(savedUpdatedAt, installationOnServer.createdAt)\n                XCTAssertNil(first.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch saved[1] {\n\n            case .success(let second):\n                XCTAssert(second.hasSameObjectId(as: installationOnServer2))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testInstallationSaveAllNoObjectIdAsync() throws {\n        let installation = Installation()\n        let installation2 = Installation()\n\n        let expectation1 = XCTestExpectation(description: \"SaveAll installation\")\n        [installation, installation2].saveAll { result in\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"objectId\"))\n            } else {\n                XCTFail(\"Should have failed\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testInstallationUpdateAll() { // swiftlint:disable:this function_body_length cyclomatic_complexity\n        var installation = Installation()\n        installation.objectId = \"yarr\"\n        installation.createdAt = Date()\n        var installation2 = Installation()\n        installation2.objectId = \"yolo\"\n        installation2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        var installationOnServer = installation\n        installationOnServer.updatedAt = installationOnServer.createdAt\n        installationOnServer.ACL = nil\n\n        var installationOnServer2 = installation2\n        installationOnServer2.updatedAt = installationOnServer2.createdAt\n        installationOnServer2.ACL = nil\n\n        let response = [BatchResponseItem<Installation>(success: installationOnServer, error: nil),\n        BatchResponseItem<Installation>(success: installationOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n            encoded = try installationOnServer.getJSONEncoder().encode(response)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded1)\n            let encoded2 = try ParseCoding.jsonEncoder().encode(installationOnServer2)\n            installationOnServer2 = try installationOnServer.getDecoder().decode(Installation.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n\n            let saved = try [installation, installation2].saveAll()\n\n            XCTAssertEqual(saved.count, 2)\n            switch saved[0] {\n\n            case .success(let first):\n                XCTAssert(first.hasSameObjectId(as: installationOnServer))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch saved[1] {\n\n            case .success(let second):\n                XCTAssert(second.hasSameObjectId(as: installationOnServer2))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testInstallationUpdateAllNoObjectId() throws {\n        var installation = Installation()\n        installation.createdAt = Date()\n        var installation2 = Installation()\n        installation2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        XCTAssertThrowsError(try [installation, installation2].saveAll())\n    }\n\n    // swiftlint:disable:next function_body_length cyclomatic_complexity\n    func testInstallationUpdateAllNoObjectIdIgnoreConfig() {\n        var installation = Installation()\n        installation.createdAt = Date()\n        var installation2 = Installation()\n        installation2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        var installationOnServer = installation\n        installationOnServer.objectId = \"yarr\"\n        installationOnServer.updatedAt = installationOnServer.createdAt\n        installationOnServer.ACL = nil\n\n        var installationOnServer2 = installation2\n        installationOnServer2.objectId = \"yolo\"\n        installationOnServer2.updatedAt = installationOnServer2.createdAt\n        installationOnServer2.ACL = nil\n\n        let response = [BatchResponseItem<Installation>(success: installationOnServer, error: nil),\n        BatchResponseItem<Installation>(success: installationOnServer2, error: nil)]\n        let encoded: Data!\n        do {\n            encoded = try installationOnServer.getJSONEncoder().encode(response)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(installationOnServer)\n            installationOnServer = try installationOnServer.getDecoder().decode(Installation.self, from: encoded1)\n            let encoded2 = try ParseCoding.jsonEncoder().encode(installationOnServer2)\n            installationOnServer2 = try installationOnServer.getDecoder().decode(Installation.self, from: encoded2)\n\n        } catch {\n            XCTFail(\"Should have encoded/decoded. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n           return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n\n            let saved = try [installation, installation2].saveAll(ignoringCustomObjectIdConfig: true)\n\n            XCTAssertEqual(saved.count, 2)\n            switch saved[0] {\n\n            case .success(let first):\n                XCTAssert(first.hasSameObjectId(as: installationOnServer))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n            switch saved[1] {\n\n            case .success(let second):\n                XCTAssert(second.hasSameObjectId(as: installationOnServer2))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testInstallationUpdateAllNoObjectIdAsync() throws {\n        var installation = Installation()\n        installation.createdAt = Date()\n        var installation2 = Installation()\n        installation2.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        let expectation1 = XCTestExpectation(description: \"UpdateAll installation\")\n        [installation, installation2].saveAll { result in\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"objectId\"))\n            } else {\n                XCTFail(\"Should have failed\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    // swiftlint:disable:next function_body_length\n    func testFetch() {\n        var score = GameScore(points: 10)\n        let objectId = \"yarr\"\n        score.objectId = objectId\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let fetched = try score.fetch(options: [])\n            XCTAssert(fetched.hasSameObjectId(as: scoreOnServer))\n            guard let fetchedCreatedAt = fetched.createdAt,\n                let fetchedUpdatedAt = fetched.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalCreatedAt = scoreOnServer.createdAt,\n                let originalUpdatedAt = scoreOnServer.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n            XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(fetched.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testFetchUser() { // swiftlint:disable:this function_body_length\n        var user = User()\n        let objectId = \"yarr\"\n        user.objectId = objectId\n\n        var userOnServer = user\n        userOnServer.createdAt = Date()\n        userOnServer.updatedAt = userOnServer.createdAt\n        userOnServer.ACL = nil\n        let encoded: Data!\n        do {\n            encoded = try userOnServer.getEncoder().encode(userOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            let fetched = try user.fetch()\n            XCTAssert(fetched.hasSameObjectId(as: userOnServer))\n            guard let fetchedCreatedAt = fetched.createdAt,\n                let fetchedUpdatedAt = fetched.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalCreatedAt = userOnServer.createdAt,\n                let originalUpdatedAt = userOnServer.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n            XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(fetched.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseObjectTests.swift",
    "content": "//\n//  ParseObjectCommandTests.swift\n//  ParseSwiftTests\n//\n//  Created by Corey Baker on 7/19/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseObjectTests: XCTestCase { // swiftlint:disable:this type_body_length\n    struct Level: ParseObject {\n        var objectId: String?\n\n        var createdAt: Date?\n\n        var updatedAt: Date?\n\n        var ACL: ParseACL?\n\n        var name: String?\n\n        var originalData: Data?\n\n        init() {\n            name = \"First\"\n        }\n    }\n\n    struct GameScore: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int?\n        var player: String?\n        var level: Level?\n        var levels: [Level]?\n        var nextLevel: Level?\n\n        //: custom initializers\n        init() {}\n\n        init(objectId: String?) {\n            self.objectId = objectId\n        }\n        init(points: Int) {\n            self.points = points\n            self.player = \"Jen\"\n        }\n        init(points: Int, name: String) {\n            self.points = points\n            self.player = name\n        }\n\n        //: Implement your own version of merge\n        func merge(with object: Self) throws -> Self {\n            var updated = try mergeParse(with: object)\n            if updated.shouldRestoreKey(\\.points,\n                                         original: object) {\n                updated.points = object.points\n            }\n            if updated.shouldRestoreKey(\\.level,\n                                         original: object) {\n                updated.level = object.level\n            }\n            if updated.shouldRestoreKey(\\.levels,\n                                         original: object) {\n                updated.levels = object.levels\n            }\n            if updated.shouldRestoreKey(\\.nextLevel,\n                                         original: object) {\n                updated.nextLevel = object.nextLevel\n            }\n            return updated\n        }\n    }\n\n    struct Game: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var gameScore: GameScore\n        var gameScores = [GameScore]()\n        var name = \"Hello\"\n        var profilePicture: ParseFile?\n\n        //: a custom initializer\n        init() {\n            self.gameScore = GameScore()\n        }\n\n        init(gameScore: GameScore) {\n            self.gameScore = gameScore\n        }\n    }\n\n    struct GameDefaultMerge: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var gameScore: GameScore?\n        var gameScores: [GameScore]?\n        var name: String?\n        var profilePicture: ParseFile?\n    }\n\n    struct Game2: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var name = \"Hello\"\n        var profilePicture: ParseFile?\n    }\n\n    final class GameScoreClass: ParseObject {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int\n        var player = \"Jen\"\n        var level: Level?\n        var levels: [Level]?\n        var game: GameClass?\n\n        //: a custom initializer\n        required init() {\n            self.points = 5\n        }\n\n        init(points: Int) {\n            self.points = points\n        }\n\n        /**\n         Conforms to Equatable by determining if an object has the same objectId.\n         - note: You can specify a custom way of `Equatable` if a more  detailed way is needed.\n         - warning: If you use the default implementation, equatable will only work if the ParseObject\n         has been previously synced to the parse-server (has an objectId). In addition, if two\n         `ParseObject`'s have the same objectId, but were modified at different times, the\n         default implementation will still return true. In these cases you either want to use a\n         \"struct\" (value types) to make your `ParseObject`s instead of a class (reference type) or\n         provide your own implementation of `==`.\n         - parameter lhs: first object to compare\n         - parameter rhs: second object to compare\n\n         - returns: Returns a **true** if the other object has the same `objectId` or **false** if unsuccessful.\n        */\n        public static func == (lhs: ParseObjectTests.GameScoreClass,\n                               rhs: ParseObjectTests.GameScoreClass) -> Bool {\n            lhs.hasSameObjectId(as: rhs)\n        }\n\n        /**\n         Conforms to `Hashable` using objectId.\n         - note: You can specify a custom way of `Hashable` if a more  detailed way is needed.\n         - warning: If you use the default implementation, hash will only work if the ParseObject has been previously\n         synced to the parse-server (has an objectId). In addition, if two `ParseObject`'s have the same objectId,\n         but were modified at different times, the default implementation will hash to the same value. In these\n         cases you either want to use a \"struct\" (value types) to make your `ParseObject`s instead of a\n         class (reference type) or provide your own implementation of `hash`.\n\n        */\n        public func hash(into hasher: inout Hasher) {\n            hasher.combine(self.id)\n        }\n    }\n\n    final class GameClass: ParseObject {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var gameScore: GameScoreClass\n        var gameScores = [GameScore]()\n        var name = \"Hello\"\n\n        //: a custom initializer\n        required init() {\n            self.gameScore = GameScoreClass()\n        }\n\n        init(gameScore: GameScoreClass) {\n            self.gameScore = gameScore\n        }\n\n        /**\n         Conforms to Equatable by determining if an object has the same objectId.\n         - note: You can specify a custom way of `Equatable` if a more  detailed way is needed.\n         - warning: If you use the default implementation, equatable will only work if the ParseObject\n         has been previously synced to the parse-server (has an objectId). In addition, if two\n         `ParseObject`'s have the same objectId, but were modified at different times, the\n         default implementation will still return true. In these cases you either want to use a\n         \"struct\" (value types) to make your `ParseObject`s instead of a class (reference type) or\n         provide your own implementation of `==`.\n         - parameter lhs: first object to compare\n         - parameter rhs: second object to compare\n\n         - returns: Returns a **true** if the other object has the same `objectId` or **false** if unsuccessful.\n        */\n        public static func == (lhs: ParseObjectTests.GameClass, rhs: ParseObjectTests.GameClass) -> Bool {\n            lhs.hasSameObjectId(as: rhs)\n        }\n\n        /**\n         Conforms to `Hashable` using objectId.\n         - note: You can specify a custom way of `Hashable` if a more  detailed way is needed.\n         - warning: If you use the default implementation, hash will only work if the ParseObject has been previously\n         synced to the parse-server (has an objectId). In addition, if two `ParseObject`'s have the same objectId,\n         but were modified at different times, the default implementation will hash to the same value. In these\n         cases you either want to use a \"struct\" (value types) to make your `ParseObject`s instead of a\n         class (reference type) or provide your own implementation of `hash`.\n\n        */\n        public func hash(into hasher: inout Hasher) {\n            hasher.combine(self.id)\n        }\n    }\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    func loginNormally() throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let user = try User.login(username: \"parse\", password: \"user\")\n        MockURLProtocol.removeAll()\n        return user\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n\n        guard let fileManager = ParseFileManager() else {\n            throw ParseError(code: .unknownError, message: \"Should have initialized file manage\")\n        }\n\n        let directory2 = try ParseFileManager.downloadDirectory()\n        let expectation2 = XCTestExpectation(description: \"Delete files2\")\n        fileManager.removeDirectoryContents(directory2) { _ in\n            expectation2.fulfill()\n        }\n        wait(for: [expectation2], timeout: 20.0)\n    }\n\n    func testIsEqualExtension() throws {\n        let score1 = GameScore(points: 2)\n        let score2 = GameScore(points: 3)\n        XCTAssertFalse(score1.isEqual(score2))\n    }\n\n    func testId() throws {\n        var score = GameScore()\n        let objectId = \"yolo\"\n        XCTAssertNotNil(UUID(uuidString: score.id))\n        XCTAssertNotEqual(score.id, objectId)\n        score.objectId = \"yolo\"\n        XCTAssertEqual(score.id, objectId)\n    }\n\n    func testIsRestoreOriginalKey() throws {\n        let score1 = GameScore(points: 5)\n        var score2 = GameScore(points: 5, name: \"world\")\n        score2.levels = [Level()]\n        score2.nextLevel = Level()\n        XCTAssertFalse(score1.shouldRestoreKey(\\.player, original: score2))\n        XCTAssertTrue(score1.shouldRestoreKey(\\.levels, original: score2))\n        XCTAssertFalse(score1.shouldRestoreKey(\\.points, original: score2))\n        XCTAssertFalse(score1.shouldRestoreKey(\\.level, original: score2))\n        XCTAssertTrue(score1.shouldRestoreKey(\\.nextLevel, original: score2))\n    }\n\n    func testParseObjectMutable() throws {\n        var score = GameScore(points: 19, name: \"fire\")\n        XCTAssertEqual(score, score.mergeable)\n        score.objectId = \"yolo\"\n        score.createdAt = Date()\n        var empty = score.mergeable\n        XCTAssertNotNil(empty.originalData)\n        XCTAssertTrue(score.hasSameObjectId(as: empty))\n        XCTAssertEqual(score.createdAt, empty.createdAt)\n        empty.player = \"Ali\"\n        XCTAssertEqual(empty.originalData, empty.mergeable.originalData)\n    }\n\n    func testMerge() throws {\n        var score = GameScore(points: 19, name: \"fire\")\n        score.objectId = \"yolo\"\n        score.createdAt = Date()\n        score.updatedAt = Date()\n        var acl = ParseACL()\n        acl.publicRead = true\n        score.ACL = acl\n        var level = Level()\n        level.objectId = \"hello\"\n        var level2 = Level()\n        level2.objectId = \"world\"\n        score.level = level\n        score.levels = [level]\n        score.nextLevel = level2\n        var updated = score.mergeable\n        updated.updatedAt = Calendar.current.date(byAdding: .init(day: 1), to: Date())\n        updated.points = 30\n        updated.player = \"moreFire\"\n        updated.levels = [level, level2]\n        let merged = try updated.merge(with: score)\n        XCTAssertEqual(merged.points, updated.points)\n        XCTAssertEqual(merged.player, updated.player)\n        XCTAssertEqual(merged.level, score.level)\n        XCTAssertEqual(merged.levels, updated.levels)\n        XCTAssertEqual(merged.nextLevel, score.nextLevel)\n        XCTAssertEqual(merged.ACL, score.ACL)\n        XCTAssertEqual(merged.createdAt, score.createdAt)\n        XCTAssertEqual(merged.updatedAt, updated.updatedAt)\n    }\n\n    func testMergeDefaultImplementation() throws {\n        var score = GameDefaultMerge()\n        score.objectId = \"yolo\"\n        score.createdAt = Date()\n        score.updatedAt = Date()\n        var updated = score.set(\\.name, to: \"moreFire\")\n        updated.updatedAt = Calendar.current.date(byAdding: .init(day: 1), to: Date())\n        score.updatedAt = updated.updatedAt\n        score.name = updated.name\n        var merged = try updated.merge(with: score)\n        merged.originalData = nil\n        // Get dates in correct format from ParseDecoding strategy\n        let encoded = try ParseCoding.jsonEncoder().encode(score)\n        score = try ParseCoding.jsonDecoder().decode(GameDefaultMerge.self, from: encoded)\n        XCTAssertEqual(merged, score)\n    }\n\n    func testMergeDifferentObjectId() throws {\n        var score = GameScore(points: 19, name: \"fire\")\n        score.objectId = \"yolo\"\n        var score2 = score\n        score2.objectId = \"nolo\"\n        XCTAssertThrowsError(try score2.merge(with: score))\n    }\n\n    func testRevertObject() throws {\n        var score = GameScore(points: 19, name: \"fire\")\n        score.objectId = \"yolo\"\n        var mutableScore = score.mergeable\n        mutableScore.points = 50\n        mutableScore.player = \"ali\"\n        XCTAssertNotEqual(mutableScore, score)\n        mutableScore = try mutableScore.revertObject()\n        XCTAssertEqual(mutableScore, score)\n    }\n\n    func testRevertObjectMissingOriginal() throws {\n        var score = GameScore(points: 19, name: \"fire\")\n        score.objectId = \"yolo\"\n        var mutableScore = score\n        mutableScore.points = 50\n        mutableScore.player = \"ali\"\n        XCTAssertNotEqual(mutableScore, score)\n        do {\n            mutableScore = try mutableScore.revertObject()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"Missing original\"))\n        }\n    }\n\n    func testRevertObjectDiffObjectId() throws {\n        var score = GameScore(points: 19, name: \"fire\")\n        score.objectId = \"yolo\"\n        var mutableScore = score.mergeable\n        mutableScore.points = 50\n        mutableScore.player = \"ali\"\n        mutableScore.objectId = \"nolo\"\n        XCTAssertNotEqual(mutableScore, score)\n        do {\n            mutableScore = try mutableScore.revertObject()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"objectId as the original\"))\n        }\n    }\n\n    func testRevertKeyPath() throws {\n        var score = GameScore(points: 19, name: \"fire\")\n        score.objectId = \"yolo\"\n        var mutableScore = score.mergeable\n        mutableScore.points = 50\n        mutableScore.player = \"ali\"\n        XCTAssertNotEqual(mutableScore, score)\n        mutableScore = try mutableScore.revertKeyPath(\\.player)\n        XCTAssertNotEqual(mutableScore, score)\n        XCTAssertEqual(mutableScore.objectId, score.objectId)\n        XCTAssertNotEqual(mutableScore.points, score.points)\n        XCTAssertEqual(mutableScore.player, score.player)\n    }\n\n    func testRevertKeyPathUpdatedNil() throws {\n        var score = GameScore(points: 19, name: \"fire\")\n        score.objectId = \"yolo\"\n        var mutableScore = score.mergeable\n        mutableScore.points = 50\n        mutableScore.player = nil\n        XCTAssertNotEqual(mutableScore, score)\n        mutableScore = try mutableScore.revertKeyPath(\\.player)\n        XCTAssertNotEqual(mutableScore, score)\n        XCTAssertEqual(mutableScore.objectId, score.objectId)\n        XCTAssertNotEqual(mutableScore.points, score.points)\n        XCTAssertEqual(mutableScore.player, score.player)\n    }\n\n    func testRevertKeyPathOriginalNil() throws {\n        var score = GameScore(points: 19, name: \"fire\")\n        score.objectId = \"yolo\"\n        score.player = nil\n        var mutableScore = score.mergeable\n        mutableScore.points = 50\n        mutableScore.player = \"ali\"\n        XCTAssertNotEqual(mutableScore, score)\n        mutableScore = try mutableScore.revertKeyPath(\\.player)\n        XCTAssertNotEqual(mutableScore, score)\n        XCTAssertEqual(mutableScore.objectId, score.objectId)\n        XCTAssertNotEqual(mutableScore.points, score.points)\n        XCTAssertEqual(mutableScore.player, score.player)\n    }\n\n    func testRevertKeyPathMissingOriginal() throws {\n        var score = GameScore(points: 19, name: \"fire\")\n        score.objectId = \"yolo\"\n        var mutableScore = score\n        mutableScore.points = 50\n        mutableScore.player = \"ali\"\n        XCTAssertNotEqual(mutableScore, score)\n        do {\n            mutableScore = try mutableScore.revertKeyPath(\\.player)\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"Missing original\"))\n        }\n    }\n\n    func testRevertKeyPathDiffObjectId() throws {\n        var score = GameScore(points: 19, name: \"fire\")\n        score.objectId = \"yolo\"\n        var mutableScore = score.mergeable\n        mutableScore.points = 50\n        mutableScore.player = \"ali\"\n        mutableScore.objectId = \"nolo\"\n        XCTAssertNotEqual(mutableScore, score)\n        do {\n            mutableScore = try mutableScore.revertKeyPath(\\.player)\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"objectId as the original\"))\n        }\n    }\n\n    func testGet() throws {\n        let originalPoints = 10\n        let score = GameScore(points: originalPoints)\n        let points = try score.get(\\.points)\n        XCTAssertEqual(points, originalPoints)\n        do {\n            try score.get(\\.ACL)\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"unwrap\"))\n        }\n    }\n\n    func testFetchCommand() {\n        var score = GameScore(points: 10)\n        let className = score.className\n        XCTAssertThrowsError(try score.fetchCommand(include: nil))\n        let objectId = \"yarr\"\n        score.objectId = objectId\n        do {\n            let command = try score.fetchCommand(include: nil)\n            XCTAssertNotNil(command)\n            XCTAssertEqual(command.path.urlComponent, \"/classes/\\(className)/\\(objectId)\")\n            XCTAssertEqual(command.method, API.Method.GET)\n            XCTAssertNil(command.params)\n            XCTAssertNil(command.body)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testFetchIncludeCommand() {\n        var score = GameScore(points: 10)\n        let className = score.className\n        let objectId = \"yarr\"\n        score.objectId = objectId\n        let includeExpected = [\"include\": \"[\\\"yolo\\\", \\\"test\\\"]\"]\n        do {\n            let command = try score.fetchCommand(include: [\"yolo\", \"test\"])\n            XCTAssertNotNil(command)\n            XCTAssertEqual(command.path.urlComponent, \"/classes/\\(className)/\\(objectId)\")\n            XCTAssertEqual(command.method, API.Method.GET)\n            XCTAssertEqual(command.params?.keys.first, includeExpected.keys.first)\n            if let value = command.params?.values.first,\n                let includeValue = value {\n                XCTAssertTrue(includeValue.contains(\"\\\"yolo\\\"\"))\n            } else {\n                XCTFail(\"Should have unwrapped value\")\n            }\n            XCTAssertNil(command.body)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    // swiftlint:disable:next function_body_length\n    func testFetch() {\n        var score = GameScore(points: 10)\n        let objectId = \"yarr\"\n        score.objectId = objectId\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try GameScore.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let fetched = try score.fetch(options: [])\n            XCTAssert(fetched.hasSameObjectId(as: scoreOnServer))\n            guard let fetchedCreatedAt = fetched.createdAt,\n                let fetchedUpdatedAt = fetched.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalCreatedAt = scoreOnServer.createdAt,\n                let originalUpdatedAt = scoreOnServer.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n            XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(fetched.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        do {\n            let fetched = try score.fetch(options: [.useMasterKey])\n            XCTAssert(fetched.hasSameObjectId(as: scoreOnServer))\n            guard let fetchedCreatedAt = fetched.createdAt,\n                let fetchedUpdatedAt = fetched.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalCreatedAt = scoreOnServer.createdAt,\n                let originalUpdatedAt = scoreOnServer.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n            XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(fetched.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testFetchBasedOnObjectId() {\n        var score = GameScore(points: 10)\n        let objectId = \"yarr\"\n        score.objectId = objectId\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            var fetched = GameScore(objectId: score.objectId)\n            fetched = try fetched.fetch(options: [])\n            XCTAssert(fetched.hasSameObjectId(as: scoreOnServer))\n            guard let fetchedCreatedAt = fetched.createdAt,\n                let fetchedUpdatedAt = fetched.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalCreatedAt = scoreOnServer.createdAt,\n                let originalUpdatedAt = scoreOnServer.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n            XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(fetched.ACL)\n            XCTAssertEqual(fetched.points, score.points)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    // swiftlint:disable:next function_body_length\n    func fetchAsync(score: GameScore, scoreOnServer: GameScore, callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Fetch object1\")\n        score.fetch(options: [], callbackQueue: callbackQueue) { result in\n\n            switch result {\n            case .success(let fetched):\n                XCTAssert(fetched.hasSameObjectId(as: scoreOnServer))\n                guard let fetchedCreatedAt = fetched.createdAt,\n                    let fetchedUpdatedAt = fetched.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation1.fulfill()\n                        return\n                }\n                guard let originalCreatedAt = scoreOnServer.createdAt,\n                    let originalUpdatedAt = scoreOnServer.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation1.fulfill()\n                        return\n                }\n                XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n                XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n                XCTAssertNil(fetched.ACL)\n                XCTAssertEqual(fetched.points, scoreOnServer.points)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n\n        let expectation2 = XCTestExpectation(description: \"Fetch object2\")\n        score.fetch(options: [.useMasterKey], callbackQueue: callbackQueue) { result in\n\n            switch result {\n            case .success(let fetched):\n                XCTAssert(fetched.hasSameObjectId(as: scoreOnServer))\n                guard let fetchedCreatedAt = fetched.createdAt,\n                    let fetchedUpdatedAt = fetched.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation2.fulfill()\n                        return\n                }\n                guard let originalCreatedAt = scoreOnServer.createdAt,\n                    let originalUpdatedAt = scoreOnServer.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation2.fulfill()\n                        return\n                }\n                XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n                XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n                XCTAssertNil(fetched.ACL)\n                XCTAssertEqual(fetched.points, scoreOnServer.points)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testThreadSafeFetchAsync() {\n        var score = GameScore(points: 10)\n        let objectId = \"yarr\"\n        score.objectId = objectId\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        DispatchQueue.concurrentPerform(iterations: 100) {_ in\n            self.fetchAsync(score: score, scoreOnServer: scoreOnServer, callbackQueue: .global(qos: .background))\n        }\n    }\n    #endif\n\n    func testFetchAsyncMainQueue() {\n        var score = GameScore(points: 10)\n        let objectId = \"yarr\"\n        score.objectId = objectId\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        self.fetchAsync(score: score, scoreOnServer: scoreOnServer, callbackQueue: .main)\n    }\n\n    func testSaveCommand() throws {\n        let score = GameScore(points: 10)\n        let className = score.className\n\n        let command = try score.saveCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/classes/\\(className)\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertNil(command.params)\n\n        let expected = \"GameScore ({\\\"player\\\":\\\"Jen\\\",\\\"points\\\":10})\"\n        let decoded = score.debugDescription\n        XCTAssertEqual(decoded, expected)\n        let expected2 = \"GameScore ({\\\"player\\\":\\\"Jen\\\",\\\"points\\\":10})\"\n        let decoded2 = score.description\n        XCTAssertEqual(decoded2, expected2)\n    }\n\n    func testSaveUpdateCommand() throws {\n        var score = GameScore(points: 10)\n        let className = score.className\n        let objectId = \"yarr\"\n        score.objectId = objectId\n        score.createdAt = Date()\n        score.updatedAt = score.createdAt\n\n        let command = try score.saveCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/classes/\\(className)/\\(objectId)\")\n        XCTAssertEqual(command.method, API.Method.PUT)\n        XCTAssertNil(command.params)\n\n        guard let body = command.body else {\n            XCTFail(\"Should be able to unwrap\")\n            return\n        }\n\n        let expected = \"{\\\"player\\\":\\\"Jen\\\",\\\"points\\\":10}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(body, collectChildren: false,\n                    objectsSavedBeforeThisOne: nil,\n                    filesSavedBeforeThisOne: nil).encoded\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testSaveUpdateCommandParseObjectMutable() throws {\n        var score = GameScore(points: 10)\n        let className = score.className\n        let objectId = \"yarr\"\n        score.objectId = objectId\n        score.createdAt = Date()\n        score.updatedAt = score.createdAt\n\n        let command = try score.mergeable.saveCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/classes/\\(className)/\\(objectId)\")\n        XCTAssertEqual(command.method, API.Method.PUT)\n        XCTAssertNil(command.params)\n\n        guard let body = command.body else {\n            XCTFail(\"Should be able to unwrap\")\n            return\n        }\n\n        let expected = \"{}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(body, collectChildren: false,\n                    objectsSavedBeforeThisOne: nil,\n                    filesSavedBeforeThisOne: nil).encoded\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n\n        var empty = score.mergeable\n        empty.player = \"Jennifer\"\n        let command2 = try empty.saveCommand()\n        guard let body2 = command2.body else {\n            XCTFail(\"Should be able to unwrap\")\n            return\n        }\n        let expected2 = \"{\\\"player\\\":\\\"Jennifer\\\"}\"\n        let encoded2 = try ParseCoding.parseEncoder()\n            .encode(body2, collectChildren: false,\n                    objectsSavedBeforeThisOne: nil,\n                    filesSavedBeforeThisOne: nil).encoded\n        let decoded2 = try XCTUnwrap(String(data: encoded2, encoding: .utf8))\n        XCTAssertEqual(decoded2, expected2)\n    }\n\n    func testCreateCommand() throws {\n        let score = GameScore(points: 10)\n\n        let command = score.createCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/classes/\\(score.className)\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertNil(command.params)\n        XCTAssertNotNil(command.body)\n    }\n\n    func testReplaceCommand() throws {\n        var score = GameScore(points: 10)\n        XCTAssertThrowsError(try score.replaceCommand())\n        let objectId = \"yarr\"\n        score.objectId = objectId\n\n        let command = try score.replaceCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/classes/\\(score.className)/\\(objectId)\")\n        XCTAssertEqual(command.method, API.Method.PUT)\n        XCTAssertNil(command.params)\n        XCTAssertNotNil(command.body)\n    }\n\n    func testUpdateCommand() throws {\n        var score = GameScore(points: 10)\n        XCTAssertThrowsError(try score.updateCommand())\n        let objectId = \"yarr\"\n        score.objectId = objectId\n\n        let command = try score.updateCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/classes/\\(score.className)/\\(objectId)\")\n        XCTAssertEqual(command.method, API.Method.PATCH)\n        XCTAssertNil(command.params)\n        XCTAssertNotNil(command.body)\n    }\n\n    func testSave() { // swiftlint:disable:this function_body_length\n        let score = GameScore(points: 10)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try score.save()\n            XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n            guard let savedCreatedAt = saved.createdAt,\n                let savedUpdatedAt = saved.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(savedCreatedAt, scoreOnServer.createdAt)\n            XCTAssertEqual(savedUpdatedAt, scoreOnServer.createdAt)\n            XCTAssertEqual(saved.ACL, scoreOnServer.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        do {\n            let saved = try score.save(options: [.useMasterKey])\n            XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n            guard let savedCreatedAt = saved.createdAt,\n                let savedUpdatedAt = saved.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(savedCreatedAt, scoreOnServer.createdAt)\n            XCTAssertEqual(savedUpdatedAt, scoreOnServer.createdAt)\n            XCTAssertEqual(saved.ACL, scoreOnServer.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testSaveWithDefaultACL() throws { // swiftlint:disable:this function_body_length\n        let user = try loginNormally()\n        guard let userObjectId = user.objectId else {\n            XCTFail(\"Should have objectId\")\n            return\n        }\n        let defaultACL = try ParseACL.setDefaultACL(ParseACL(),\n                                                    withAccessForCurrentUser: true)\n\n        let score = GameScore(points: 10)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try score.save()\n            XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n            guard let savedCreatedAt = saved.createdAt,\n                let savedUpdatedAt = saved.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(savedCreatedAt, scoreOnServer.createdAt)\n            XCTAssertEqual(savedUpdatedAt, scoreOnServer.createdAt)\n            XCTAssertNotNil(saved.ACL)\n            XCTAssertEqual(saved.ACL?.publicRead, defaultACL.publicRead)\n            XCTAssertEqual(saved.ACL?.publicWrite, defaultACL.publicWrite)\n            XCTAssertTrue(defaultACL.getReadAccess(objectId: userObjectId))\n            XCTAssertTrue(defaultACL.getWriteAccess(objectId: userObjectId))\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testUpdate() {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        score.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        score.ACL = nil\n\n        var scoreOnServer = score\n        scoreOnServer.updatedAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try score.save()\n            guard let savedUpdatedAt = saved.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n            }\n            guard let originalUpdatedAt = score.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n            }\n            XCTAssertGreaterThan(savedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(saved.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        do {\n            let saved = try score.save(options: [.useMasterKey])\n            guard let savedUpdatedAt = saved.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n            }\n            guard let originalUpdatedAt = score.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n            }\n            XCTAssertGreaterThan(savedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(saved.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testUpdateWithDefaultACL() throws {\n        _ = try loginNormally()\n        _ = try ParseACL.setDefaultACL(ParseACL(), withAccessForCurrentUser: true)\n\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        score.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        score.ACL = nil\n\n        var scoreOnServer = score\n        scoreOnServer.updatedAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try score.save()\n            guard let savedUpdatedAt = saved.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n            }\n            guard let originalUpdatedAt = score.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n            }\n            XCTAssertGreaterThan(savedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(saved.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    // swiftlint:disable:next function_body_length\n    func saveAsync(score: GameScore, scoreOnServer: GameScore, callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Save object1\")\n\n        score.save(options: [], callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let saved):\n                XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n                guard let savedCreatedAt = saved.createdAt,\n                    let savedUpdatedAt = saved.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation1.fulfill()\n                        return\n                }\n                XCTAssertEqual(savedCreatedAt, scoreOnServer.createdAt)\n                XCTAssertEqual(savedUpdatedAt, scoreOnServer.createdAt)\n                XCTAssertEqual(saved.ACL, scoreOnServer.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n\n        let expectation2 = XCTestExpectation(description: \"Save object2\")\n        score.save(options: [.useMasterKey], callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let saved):\n                XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n                guard let savedCreatedAt = saved.createdAt,\n                    let savedUpdatedAt = saved.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation2.fulfill()\n                        return\n                }\n                XCTAssertEqual(savedCreatedAt, scoreOnServer.createdAt)\n                XCTAssertEqual(savedUpdatedAt, scoreOnServer.createdAt)\n                XCTAssertEqual(saved.ACL, scoreOnServer.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testThreadSafeSaveAsync() {\n        let score = GameScore(points: 10)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        DispatchQueue.concurrentPerform(iterations: 100) {_ in\n            self.saveAsync(score: score, scoreOnServer: scoreOnServer, callbackQueue: .global(qos: .background))\n        }\n    }\n    #endif\n\n    func testSaveAsyncMainQueue() {\n        let score = GameScore(points: 10)\n\n        var scoreOnServer = score\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        self.saveAsync(score: score, scoreOnServer: scoreOnServer, callbackQueue: .main)\n    }\n\n    func updateAsync(score: GameScore, scoreOnServer: GameScore, callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Update object1\")\n\n        score.save(options: [], callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let saved):\n                guard let savedUpdatedAt = saved.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    expectation1.fulfill()\n                    return\n                }\n                guard let originalUpdatedAt = score.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    expectation1.fulfill()\n                    return\n                }\n                XCTAssertGreaterThan(savedUpdatedAt, originalUpdatedAt)\n                XCTAssertNil(saved.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n\n        let expectation2 = XCTestExpectation(description: \"Update object2\")\n        score.save(options: [.useMasterKey], callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let saved):\n                guard let savedUpdatedAt = saved.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    expectation2.fulfill()\n                    return\n                }\n                guard let originalUpdatedAt = score.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    expectation2.fulfill()\n                    return\n                }\n                XCTAssertGreaterThan(savedUpdatedAt, originalUpdatedAt)\n                XCTAssertNil(saved.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testThreadSafeUpdateAsync() {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        score.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        score.ACL = nil\n\n        var scoreOnServer = score\n        scoreOnServer.updatedAt = Date()\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        DispatchQueue.concurrentPerform(iterations: 100) {_ in\n            self.updateAsync(score: score, scoreOnServer: scoreOnServer, callbackQueue: .global(qos: .background))\n        }\n    }\n    #endif\n\n    func testUpdateAsyncMainQueue() {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        score.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        score.ACL = nil\n\n        var scoreOnServer = score\n        scoreOnServer.updatedAt = Date()\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        self.updateAsync(score: score, scoreOnServer: scoreOnServer, callbackQueue: .main)\n    }\n\n    func testDeleteCommand() {\n        var score = GameScore(points: 10)\n        let className = score.className\n        let objectId = \"yarr\"\n        score.objectId = objectId\n        do {\n            let command = try score.deleteCommand()\n            XCTAssertNotNil(command)\n            XCTAssertEqual(command.path.urlComponent, \"/classes/\\(className)/\\(objectId)\")\n            XCTAssertEqual(command.method, API.Method.DELETE)\n            XCTAssertNil(command.body)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testDelete() {\n        var score = GameScore(points: 10)\n        let objectId = \"yarr\"\n        score.objectId = objectId\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n        let encoded: Data!\n        do {\n            encoded = try GameScore.getEncoder().encode(scoreOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            try score.delete(options: [])\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        do {\n            try score.delete(options: [.useMasterKey])\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testDeleteError() {\n        var score = GameScore(points: 10)\n        let objectId = \"yarr\"\n        score.objectId = objectId\n\n        let parseError = ParseError(code: .objectNotFound, message: \"Object not found\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(parseError)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            try score.delete(options: [])\n            XCTFail(\"Should have thrown ParseError\")\n        } catch {\n            if let error = error as? ParseError {\n                XCTAssertEqual(error.code, parseError.code)\n            } else {\n                XCTFail(\"Should have thrown ParseError\")\n            }\n        }\n\n        do {\n            try score.delete(options: [.useMasterKey])\n            XCTFail(\"Should have thrown ParseError\")\n        } catch {\n            if let error = error as? ParseError {\n                XCTAssertEqual(error.code, parseError.code)\n            } else {\n                XCTFail(\"Should have thrown ParseError\")\n            }\n        }\n    }\n\n    func deleteAsync(score: GameScore, scoreOnServer: GameScore, callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Delete object1\")\n        score.delete(options: [], callbackQueue: callbackQueue) { result in\n\n            if case let .failure(error) = result {\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n\n        let expectation2 = XCTestExpectation(description: \"Delete object2\")\n        score.delete(options: [.useMasterKey], callbackQueue: callbackQueue) { result in\n\n            if case let .failure(error) = result {\n                XCTFail(error.localizedDescription)\n            }\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testThreadSafeDeleteAsync() {\n        var score = GameScore(points: 10)\n        let objectId = \"yarr\"\n        score.objectId = objectId\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let encoded: Data!\n        do {\n            encoded = try scoreOnServer.getEncoder().encode(scoreOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        DispatchQueue.concurrentPerform(iterations: 100) {_ in\n            self.deleteAsync(score: score, scoreOnServer: scoreOnServer, callbackQueue: .global(qos: .background))\n        }\n    }\n    #endif\n\n    func testDeleteAsyncMainQueue() {\n        var score = GameScore(points: 10)\n        let objectId = \"yarr\"\n        score.objectId = objectId\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n        let encoded: Data!\n        do {\n            encoded = try scoreOnServer.getEncoder().encode(scoreOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        self.deleteAsync(score: score, scoreOnServer: scoreOnServer, callbackQueue: .main)\n    }\n\n    func deleteAsyncError(score: GameScore, parseError: ParseError, callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Delete object1\")\n        score.delete(options: [], callbackQueue: callbackQueue) { result in\n\n            if case let .failure(error) = result {\n                XCTAssertEqual(error.code, parseError.code)\n            } else {\n                XCTFail(\"Should have thrown ParseError\")\n            }\n            expectation1.fulfill()\n        }\n\n        let expectation2 = XCTestExpectation(description: \"Delete object2\")\n        score.delete(options: [.useMasterKey], callbackQueue: callbackQueue) { result in\n\n            if case let .failure(error) = result {\n                XCTAssertEqual(error.code, parseError.code)\n            } else {\n                XCTFail(\"Should have thrown ParseError\")\n            }\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testDeleteAsyncMainQueueError() {\n        var score = GameScore(points: 10)\n        let objectId = \"yarr\"\n        score.objectId = objectId\n\n        let parseError = ParseError(code: .objectNotFound, message: \"Object not found\")\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(parseError)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        self.deleteAsyncError(score: score, parseError: parseError, callbackQueue: .main)\n    }\n\n    // swiftlint:disable:next function_body_length\n    func testDeepSaveOneDeep() throws {\n        let score = GameScore(points: 10)\n        var game = Game(gameScore: score)\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n        scoreOnServer.objectId = \"yarr\"\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try GameScore.getJSONEncoder().encode(response)\n            //Get dates in correct format from ParseDecoding strategy\n            let encodedScoreOnServer = try scoreOnServer.getEncoder().encode(scoreOnServer)\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encodedScoreOnServer)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Deep save\")\n        game.ensureDeepSave { (savedChildren, savedChildFiles, parseError) in\n\n            XCTAssertEqual(savedChildren.count, 1)\n            XCTAssertEqual(savedChildFiles.count, 0)\n            var counter = 0\n            var savedChildObject: PointerType?\n            savedChildren.forEach { (_, value) in\n                XCTAssertEqual(value.className, \"GameScore\")\n                XCTAssertEqual(value.objectId, \"yarr\")\n                if counter == 0 {\n                    savedChildObject = value\n                }\n                counter += 1\n            }\n            XCTAssertNil(parseError)\n\n            guard let savedChild = savedChildObject else {\n                XCTFail(\"Should have unwrapped child object\")\n                expectation1.fulfill()\n                return\n            }\n\n            //Saved updated info for game\n            let encodedScore: Data\n            do {\n                encodedScore = try ParseCoding.jsonEncoder().encode(savedChild)\n                //Decode Pointer as GameScore\n                game.gameScore = try game.getDecoder().decode(GameScore.self, from: encodedScore)\n            } catch {\n                XCTFail(\"Should encode/decode. Error \\(error)\")\n                expectation1.fulfill()\n                return\n            }\n\n            //Setup ParseObject to return from mocker\n            MockURLProtocol.removeAll()\n\n            var gameOnServer = game\n            gameOnServer.objectId = \"nice\"\n            gameOnServer.createdAt = Date()\n\n            let encodedGamed: Data\n            do {\n                encodedGamed = try game.getEncoder().encode(gameOnServer, skipKeys: .none)\n                //Get dates in correct format from ParseDecoding strategy\n                gameOnServer = try game.getDecoder().decode(Game.self, from: encodedGamed)\n            } catch {\n                XCTFail(\"Should encode/decode. Error \\(error)\")\n                expectation1.fulfill()\n                return\n            }\n\n            MockURLProtocol.mockRequests { _ in\n                return MockURLResponse(data: encodedGamed, statusCode: 200, delay: 0.0)\n            }\n\n            guard let savedGame = try? game\n                    .saveCommand()\n                    .execute(options: [],\n                             childObjects: savedChildren,\n                             childFiles: savedChildFiles) else {\n                XCTFail(\"Should have saved game\")\n                expectation1.fulfill()\n                return\n            }\n            XCTAssertEqual(savedGame.objectId, gameOnServer.objectId)\n            XCTAssertEqual(savedGame.createdAt, gameOnServer.createdAt)\n            XCTAssertEqual(savedGame.updatedAt, gameOnServer.createdAt)\n            XCTAssertEqual(savedGame.gameScore, gameOnServer.gameScore)\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    // swiftlint:disable:next function_body_length\n    func testDeepSaveOneDeepWithDefaultACL() throws {\n        let user = try loginNormally()\n        guard let userObjectId = user.objectId else {\n            XCTFail(\"Should have objectId\")\n            return\n        }\n        let defaultACL = try ParseACL.setDefaultACL(ParseACL(),\n                                                    withAccessForCurrentUser: true)\n\n        let score = GameScore(points: 10)\n        var game = Game(gameScore: score)\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n        scoreOnServer.objectId = \"yarr\"\n\n        let response = [BatchResponseItem<GameScore>(success: scoreOnServer, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try GameScore.getJSONEncoder().encode(response)\n            //Get dates in correct format from ParseDecoding strategy\n            let encodedScoreOnServer = try scoreOnServer.getEncoder().encode(scoreOnServer)\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encodedScoreOnServer)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Deep save\")\n        game.ensureDeepSave { (savedChildren, savedChildFiles, parseError) in\n\n            XCTAssertEqual(savedChildren.count, 1)\n            XCTAssertEqual(savedChildFiles.count, 0)\n            var counter = 0\n            var savedChildObject: PointerType?\n            savedChildren.forEach { (_, value) in\n                XCTAssertEqual(value.className, \"GameScore\")\n                XCTAssertEqual(value.objectId, \"yarr\")\n                if counter == 0 {\n                    savedChildObject = value\n                }\n                counter += 1\n            }\n            XCTAssertNil(parseError)\n\n            guard let savedChild = savedChildObject else {\n                XCTFail(\"Should have unwrapped child object\")\n                expectation1.fulfill()\n                return\n            }\n\n            //Saved updated info for game\n            let encodedScore: Data\n            do {\n                encodedScore = try ParseCoding.jsonEncoder().encode(savedChild)\n                //Decode Pointer as GameScore\n                game.gameScore = try game.getDecoder().decode(GameScore.self, from: encodedScore)\n            } catch {\n                XCTFail(\"Should encode/decode. Error \\(error)\")\n                expectation1.fulfill()\n                return\n            }\n\n            //Setup ParseObject to return from mocker\n            MockURLProtocol.removeAll()\n\n            var gameOnServer = game\n            gameOnServer.objectId = \"nice\"\n            gameOnServer.createdAt = Date()\n\n            let encodedGamed: Data\n            do {\n                encodedGamed = try game.getEncoder().encode(gameOnServer, skipKeys: .none)\n                //Get dates in correct format from ParseDecoding strategy\n                gameOnServer = try game.getDecoder().decode(Game.self, from: encodedGamed)\n            } catch {\n                XCTFail(\"Should encode/decode. Error \\(error)\")\n                expectation1.fulfill()\n                return\n            }\n\n            MockURLProtocol.mockRequests { _ in\n                return MockURLResponse(data: encodedGamed, statusCode: 200, delay: 0.0)\n            }\n\n            guard let savedGame = try? game\n                    .saveCommand()\n                    .execute(options: [],\n                             childObjects: savedChildren,\n                             childFiles: savedChildFiles) else {\n                XCTFail(\"Should have saved game\")\n                expectation1.fulfill()\n                return\n            }\n            XCTAssertEqual(savedGame.objectId, gameOnServer.objectId)\n            XCTAssertEqual(savedGame.createdAt, gameOnServer.createdAt)\n            XCTAssertEqual(savedGame.updatedAt, gameOnServer.createdAt)\n            XCTAssertEqual(savedGame.gameScore, gameOnServer.gameScore)\n            XCTAssertNotNil(savedGame.ACL)\n            XCTAssertEqual(savedGame.ACL?.publicRead, defaultACL.publicRead)\n            XCTAssertEqual(savedGame.ACL?.publicWrite, defaultACL.publicWrite)\n            XCTAssertTrue(defaultACL.getReadAccess(objectId: userObjectId))\n            XCTAssertTrue(defaultACL.getWriteAccess(objectId: userObjectId))\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDeepSaveDetectCircular() throws {\n        let score = GameScoreClass(points: 10)\n        let game = GameClass(gameScore: score)\n        game.objectId = \"nice\"\n        score.game = game\n        let expectation1 = XCTestExpectation(description: \"Deep save\")\n        game.ensureDeepSave { (_, _, parseError) in\n\n            guard let error = parseError else {\n                XCTFail(\"Should have failed with an error of detecting a circular dependency\")\n                expectation1.fulfill()\n                return\n            }\n            XCTAssertTrue(error.message.contains(\"circular\"))\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testAllowFieldsWithSameObject() throws {\n        var score = GameScore(points: 10)\n        var level = Level()\n        level.objectId = \"nice\"\n        score.level = level\n        score.nextLevel = level\n        let expectation1 = XCTestExpectation(description: \"Deep save\")\n        score.ensureDeepSave { (_, _, parseError) in\n            XCTAssertNil(parseError)\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDeepSaveTwoDeep() throws {\n        var score = GameScore(points: 10)\n        score.level = Level()\n        var game = Game(gameScore: score)\n        game.objectId = \"nice\"\n\n        var levelOnServer = score\n        levelOnServer.createdAt = Date()\n        levelOnServer.ACL = nil\n        levelOnServer.objectId = \"yarr\"\n        let pointer = try levelOnServer.toPointer()\n\n        let response = [BatchResponseItem<Pointer<GameScore>>(success: pointer, error: nil)]\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(response)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        let expectation1 = XCTestExpectation(description: \"Deep save\")\n        game.ensureDeepSave { (savedChildren, savedChildFiles, parseError) in\n\n            XCTAssertEqual(savedChildFiles.count, 0)\n            XCTAssertEqual(savedChildren.count, 2)\n            let gameScore = savedChildren.compactMap { (_, value) -> PointerType? in\n                if value.className == \"GameScore\" {\n                    return value\n                } else {\n                    return nil\n                }\n            }\n            XCTAssertEqual(gameScore.count, 1)\n            XCTAssertEqual(gameScore.first?.className, \"GameScore\")\n            XCTAssertEqual(gameScore.first?.objectId, \"yarr\")\n\n            let level = savedChildren.compactMap { (_, value) -> PointerType? in\n                if value.className == \"Level\" {\n                    return value\n                } else {\n                    return nil\n                }\n            }\n            XCTAssertEqual(level.count, 1)\n            XCTAssertEqual(level.first?.className, \"Level\")\n            XCTAssertEqual(level.first?.objectId, \"yarr\") //This is because mocker is only returning 1 response\n            XCTAssertNil(parseError)\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDeepSaveOfUnsavedPointerArray() throws {\n        var score = GameScore(points: 10)\n        let newLevel = Level()\n        var newLevel2 = Level()\n        newLevel2.name = \"best\"\n        score.levels = [newLevel, newLevel]\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.ACL = nil\n        scoreOnServer.objectId = \"yarr\"\n\n        let encoded: Data!\n        do {\n            encoded = try scoreOnServer.getEncoder().encode(scoreOnServer, skipKeys: .none)\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n            XCTAssertEqual(scoreOnServer.levels?.count, score.levels?.count)\n            XCTAssertEqual(scoreOnServer.levels?.first?.objectId, score.levels?.first?.objectId)\n            XCTAssertEqual(scoreOnServer.levels?.last?.objectId, score.levels?.last?.objectId)\n        } catch {\n            XCTFail(\"Should have encoded/decoded\")\n            return\n        }\n    }\n\n    func testDeepSavePointerArray() throws {\n        var score = GameScore(points: 10)\n        var level1 = Level()\n        level1.objectId = \"level1\"\n        var level2 = Level()\n        level2.objectId = \"level2\"\n        score.levels = [level1, level2]\n\n        do {\n            let encoded = try score.getEncoder().encode(score, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            guard let scoreOnServer = try (score.getDecoder()\n                                            .decode([String: AnyCodable].self,\n                                                    from: encoded))[\"levels\"]?.value as? [[String: String]],\n                  let first = scoreOnServer.first,\n                  let second = scoreOnServer.last else {\n                XCTFail(\"Should unwrapped decoded\")\n                return\n            }\n            XCTAssertEqual(first[\"__type\"], \"Pointer\")\n            XCTAssertEqual(first[\"objectId\"], level1.objectId)\n            XCTAssertEqual(first[\"className\"], level1.className)\n            XCTAssertEqual(second[\"__type\"], \"Pointer\")\n            XCTAssertEqual(second[\"objectId\"], level2.objectId)\n            XCTAssertEqual(second[\"className\"], level2.className)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    // swiftlint:disable:next function_body_length\n    func testDeepSaveObjectWithFile() throws {\n        var game = Game2()\n\n        guard let cloudPath = URL(string: \"https://parseplatform.org/img/logo.svg\"),\n              // swiftlint:disable:next line_length\n              let parseURL = URL(string: \"http://localhost:1337/1/files/applicationId/89d74fcfa4faa5561799e5076593f67c_logo.svg\") else {\n            XCTFail(\"Should create URL\")\n            return\n        }\n\n        let parseFile = ParseFile(name: \"profile.svg\", cloudURL: cloudPath)\n        game.profilePicture = parseFile\n\n        let fileResponse = FileUploadResponse(name: \"89d74fcfa4faa5561799e5076593f67c_\\(parseFile.name)\",\n                                              url: parseURL)\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(fileResponse)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Deep save\")\n        game.ensureDeepSave { (savedChildren, savedChildFiles, parseError) in\n\n            XCTAssertEqual(savedChildren.count, 0)\n            XCTAssertEqual(savedChildFiles.count, 1)\n            var counter = 0\n            var savedFile: ParseFile?\n            savedChildFiles.forEach { (_, value) in\n                XCTAssertEqual(value.url, fileResponse.url)\n                XCTAssertEqual(value.name, fileResponse.name)\n                if counter == 0 {\n                    savedFile = value\n                }\n                counter += 1\n            }\n            XCTAssertNil(parseError)\n\n            //Saved updated info for game\n            game.profilePicture = savedFile\n\n            //Setup ParseObject to return from mocker\n            MockURLProtocol.removeAll()\n\n            var gameOnServer = game\n            gameOnServer.objectId = \"nice\"\n            gameOnServer.createdAt = Date()\n            gameOnServer.profilePicture = savedFile\n\n            let encodedGamed: Data\n            do {\n                encodedGamed = try game.getEncoder().encode(gameOnServer, skipKeys: .none)\n                //Get dates in correct format from ParseDecoding strategy\n                gameOnServer = try game.getDecoder().decode(Game2.self, from: encodedGamed)\n            } catch {\n                XCTFail(\"Should encode/decode. Error \\(error)\")\n                expectation1.fulfill()\n                return\n            }\n\n            MockURLProtocol.mockRequests { _ in\n                return MockURLResponse(data: encodedGamed, statusCode: 200, delay: 0.0)\n            }\n\n            guard let savedGame = try? game\n                    .saveCommand()\n                    .execute(options: [],\n                             childObjects: savedChildren,\n                             childFiles: savedChildFiles) else {\n                XCTFail(\"Should have saved game\")\n                expectation1.fulfill()\n                return\n            }\n            XCTAssertEqual(savedGame.objectId, gameOnServer.objectId)\n            XCTAssertEqual(savedGame.createdAt, gameOnServer.createdAt)\n            XCTAssertEqual(savedGame.updatedAt, gameOnServer.createdAt)\n            XCTAssertEqual(savedGame.profilePicture, gameOnServer.profilePicture)\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n    #endif\n}\n\n// swiftlint:disable:this file_length\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseOperationAsyncTests.swift",
    "content": "//\n//  ParseOperationAsyncTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/28/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseOperationAsyncTests: XCTestCase { // swiftlint:disable:this type_body_length\n    struct GameScore: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int?\n        var player: String?\n\n        init() { }\n        //custom initializers\n        init (objectId: String?) {\n            self.objectId = objectId\n        }\n        init(points: Int) {\n            self.points = points\n            self.player = \"Jen\"\n        }\n        init(points: Int, name: String) {\n            self.points = points\n            self.player = name\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    @MainActor\n    func testSave() async throws {\n\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        let operations = score.operation\n            .increment(\"points\", by: 1)\n\n        var scoreOnServer = score\n        scoreOnServer.points = 11\n        scoreOnServer.updatedAt = Date()\n        scoreOnServer.ACL = nil\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await operations.save()\n        XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n        guard let savedUpdatedAt = saved.updatedAt else {\n            XCTFail(\"Should unwrap dates\")\n            return\n        }\n        guard let originalUpdatedAt = scoreOnServer.updatedAt else {\n            XCTFail(\"Should unwrap dates\")\n            return\n        }\n        XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n        XCTAssertNil(saved.ACL)\n    }\n\n    @MainActor\n    func testSaveServerError() async throws {\n\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        let operations = score.operation\n            .increment(\"points\", by: 1)\n\n        let serverError = ParseError(code: .operationForbidden, message: \"Test error\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverError)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            try await operations.save()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(parseError, serverError)\n        }\n    }\n\n    @MainActor\n    func testSaveNoObjectId() async throws {\n        var score = GameScore()\n        score.points = 10\n        let operations = score.operation\n            .increment(\"points\", by: 1)\n\n        do {\n            try await operations.save()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(parseError.code, .missingObjectId)\n        }\n    }\n\n    @MainActor\n    func testSaveKeyPath() async throws { // swiftlint:disable:this function_body_length\n        var score = GameScore()\n        score.objectId = \"yarr\"\n        let operations = try score.operation\n            .set(\\.points, value: 15)\n            .set(\\.player, value: \"hello\")\n\n        var scoreOnServer = score\n        scoreOnServer.points = 15\n        scoreOnServer.player = \"hello\"\n        scoreOnServer.updatedAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try await operations.save()\n            XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n            XCTAssertEqual(saved, scoreOnServer)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    @MainActor\n    func testSaveKeyPathOtherTypeOperationsExist() async throws { // swiftlint:disable:this function_body_length\n        var score = GameScore()\n        score.objectId = \"yarr\"\n        let operations = try score.operation\n            .set(\\.points, value: 15)\n            .set((\"player\", \\.player), value: \"hello\")\n\n        do {\n            try await operations.save()\n            XCTFail(\"Should have failed\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"Cannot combine\"))\n        }\n    }\n\n    @MainActor\n    func testSaveKeyPathNilOperationsExist() async throws { // swiftlint:disable:this function_body_length\n        var score = GameScore()\n        score.objectId = \"yarr\"\n        let operations = try score.operation\n            .set(\\.points, value: 15)\n            .set((\"points\", \\.points), value: nil)\n\n        do {\n            try await operations.save()\n            XCTFail(\"Should have failed\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"Cannot combine\"))\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseOperationCombineTests.swift",
    "content": "//\n//  ParseOperationCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/30/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseOperationCombineTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct GameScore: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int?\n        var player: String?\n\n        //custom initializers\n        init() {}\n        init (objectId: String?) {\n            self.objectId = objectId\n        }\n        init(points: Int) {\n            self.points = points\n            self.player = \"Jen\"\n        }\n        init(points: Int, name: String) {\n            self.points = points\n            self.player = name\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testSave() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        let operations = score.operation\n            .increment(\"points\", by: 1)\n\n        var scoreOnServer = score\n        scoreOnServer.points = 11\n        scoreOnServer.updatedAt = Date()\n        scoreOnServer.ACL = nil\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = operations.savePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n            guard let savedUpdatedAt = saved.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n            }\n            guard let originalUpdatedAt = scoreOnServer.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n            }\n            XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(saved.ACL)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseOperationTests.swift",
    "content": "//\n//  ParseOperation.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/17/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseOperationTests: XCTestCase {\n    struct GameScore: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int?\n        var members: [String]?\n        var levels: [String]?\n        var previous: [Level]?\n        var next: [Level]?\n\n        init() {\n        }\n\n        // custom initializers\n        init(points: Int) {\n            self.points = points\n            self.next = [Level(level: 5)]\n            self.members = [String]()\n        }\n    }\n\n    // Used for deprecated operations\n    struct GameScoreDeprecated: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int\n        var members: [String]\n        var levels: [String]?\n        var previous: [Level]?\n        var next: [Level] = [Level(level: 3)]\n\n        init() {\n            self.points = 5\n            self.members = [\"hello\"]\n        }\n\n        // custom initializers\n        init(points: Int) {\n            self.points = points\n            self.next = [Level(level: 5)]\n            self.members = [String]()\n        }\n    }\n\n    struct Level: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var level: Int?\n        var members: [String]?\n\n        init() {\n        }\n\n        //custom initializers\n        init(level: Int) {\n            self.level = level\n            self.members = [String]()\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testSaveCommand() throws {\n        var score = GameScore()\n        score.points = 10\n        let objectId = \"hello\"\n        score.objectId = objectId\n        let operations = score.operation\n            .increment(\"points\", by: 1)\n        let className = score.className\n\n        let command = operations.saveCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/classes/\\(className)/\\(objectId)\")\n        XCTAssertEqual(command.method, API.Method.PUT)\n\n        guard let body = command.body else {\n            XCTFail(\"Should be able to unwrap\")\n            return\n        }\n\n        let expected = \"{\\\"points\\\":{\\\"__op\\\":\\\"Increment\\\",\\\"amount\\\":1}}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(body)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testSave() { // swiftlint:disable:this function_body_length\n        var score = GameScore()\n        score.points = 10\n        score.objectId = \"yarr\"\n        let operations = score.operation\n            .increment(\"points\", by: 1)\n\n        var scoreOnServer = score\n        scoreOnServer.points = 11\n        scoreOnServer.updatedAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try operations.save()\n            XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n            guard let savedUpdatedAt = saved.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalUpdatedAt = scoreOnServer.updatedAt,\n                  let originalPoints = scoreOnServer.points else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n            XCTAssertEqual(saved.ACL, scoreOnServer.ACL)\n            XCTAssertEqual(saved.points, originalPoints-1)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testSaveNoObjectId() {\n        var score = GameScore()\n        score.points = 10\n        let operations = score.operation\n            .increment(\"points\", by: 1)\n\n        do {\n            try operations.save()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(parseError.code, .missingObjectId)\n        }\n    }\n\n    func testSaveKeyPath() throws { // swiftlint:disable:this function_body_length\n        var score = GameScore()\n        score.objectId = \"yarr\"\n        let operations = try score.operation\n            .set(\\.points, value: 15)\n            .set(\\.levels, value: [\"hello\"])\n\n        var scoreOnServer = score\n        scoreOnServer.points = 15\n        scoreOnServer.levels = [\"hello\"]\n        scoreOnServer.updatedAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try operations.save()\n            XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n            XCTAssertEqual(saved, scoreOnServer)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testSaveKeyPathOtherTypeOperationsExist() throws { // swiftlint:disable:this function_body_length\n        var score = GameScore()\n        score.objectId = \"yarr\"\n        let operations = try score.operation\n            .set(\\.points, value: 15)\n            .set((\"levels\", \\.levels), value: [\"hello\"])\n\n        do {\n            try operations.save()\n            XCTFail(\"Should have failed\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"Cannot combine\"))\n        }\n    }\n\n    func testSaveKeyPathNilOperationsExist() throws { // swiftlint:disable:this function_body_length\n        var score = GameScore()\n        score.objectId = \"yarr\"\n        let operations = try score.operation\n            .set(\\.points, value: 15)\n            .set((\"points\", \\.points), value: nil)\n\n        do {\n            try operations.save()\n            XCTFail(\"Should have failed\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"Cannot combine\"))\n        }\n    }\n\n    func testSaveAsyncMainQueue() {\n        var score = GameScore()\n        score.points = 10\n        score.objectId = \"yarr\"\n        let operations = score.operation\n            .increment(\"points\", by: 1)\n\n        var scoreOnServer = score\n        scoreOnServer.points = 11\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Save object1\")\n\n        operations.save(options: [], callbackQueue: .main) { result in\n\n            switch result {\n\n            case .success(let saved):\n                XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n                guard let savedUpdatedAt = saved.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation1.fulfill()\n                        return\n                }\n                guard let originalUpdatedAt = scoreOnServer.updatedAt,\n                      let originalPoints = scoreOnServer.points else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation1.fulfill()\n                        return\n                }\n                XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n                XCTAssertEqual(saved.ACL, scoreOnServer.ACL)\n                XCTAssertEqual(saved.points, originalPoints-1)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSaveSet() throws { // swiftlint:disable:this function_body_length\n        var score = GameScore()\n        score.points = 10\n        score.objectId = \"yarr\"\n        let operations = score.operation\n            .set((\"points\", \\.points), value: 15)\n\n        var scoreOnServer = score\n        scoreOnServer.points = 15\n        scoreOnServer.updatedAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try operations.save()\n            XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n            guard let savedUpdatedAt = saved.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalUpdatedAt = scoreOnServer.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n            XCTAssertEqual(saved.ACL, scoreOnServer.ACL)\n            XCTAssertEqual(saved.points, scoreOnServer.points)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testSaveSetToNull() throws { // swiftlint:disable:this function_body_length\n        var score = GameScore()\n        score.points = 10\n        score.objectId = \"yarr\"\n        let operations = score.operation\n            .set((\"points\", \\.points), value: nil)\n\n        var scoreOnServer = score\n        scoreOnServer.points = nil\n        scoreOnServer.updatedAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try operations.save()\n            XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n            guard let savedUpdatedAt = saved.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalUpdatedAt = scoreOnServer.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n            XCTAssertEqual(saved.ACL, scoreOnServer.ACL)\n            XCTAssertEqual(saved.points, scoreOnServer.points)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testSaveSetAsyncMainQueue() throws {\n        var score = GameScore()\n        score.points = 10\n        score.objectId = \"yarr\"\n        let operations = score.operation\n            .set((\"points\", \\.points), value: 15)\n\n        var scoreOnServer = score\n        scoreOnServer.points = 15\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Save object1\")\n\n        operations.save(options: [], callbackQueue: .main) { result in\n\n            switch result {\n\n            case .success(let saved):\n                XCTAssert(saved.hasSameObjectId(as: scoreOnServer))\n                guard let savedUpdatedAt = saved.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation1.fulfill()\n                        return\n                }\n                guard let originalUpdatedAt = scoreOnServer.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation1.fulfill()\n                        return\n                }\n                XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n                XCTAssertEqual(saved.ACL, scoreOnServer.ACL)\n                XCTAssertEqual(saved.points, scoreOnServer.points)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testIncrement() throws {\n        let score = GameScore(points: 10)\n        let operations = score.operation\n            .increment(\"points\", by: 1)\n        let expected = \"{\\\"points\\\":{\\\"__op\\\":\\\"Increment\\\",\\\"amount\\\":1}}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(operations)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testAdd() throws {\n        let score = GameScore(points: 10)\n        let operations = score.operation\n            .add(\"test\", objects: [\"hello\"])\n        let expected = \"{\\\"test\\\":{\\\"__op\\\":\\\"Add\\\",\\\"objects\\\":[\\\"hello\\\"]}}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(operations)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testAddKeypathDeprecated() throws {\n        let score = GameScoreDeprecated()\n        let operations = score.operation\n            .add((\"test\", \\.members), objects: [\"hello\"])\n        let expected = \"{\\\"test\\\":{\\\"__op\\\":\\\"Add\\\",\\\"objects\\\":[\\\"hello\\\"]}}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(operations)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testAddKeypath() throws {\n        let score = GameScore(points: 10)\n        let operations = score.operation\n            .add((\"test\", \\.levels), objects: [\"hello\"])\n        let expected = \"{\\\"test\\\":{\\\"__op\\\":\\\"Add\\\",\\\"objects\\\":[\\\"hello\\\"]}}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(operations)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testAddUnique() throws {\n        let score = GameScore(points: 10)\n        let operations = score.operation\n            .addUnique(\"test\", objects: [\"hello\"])\n        let expected = \"{\\\"test\\\":{\\\"__op\\\":\\\"AddUnique\\\",\\\"objects\\\":[\\\"hello\\\"]}}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(operations)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testAddUniqueKeypathDeprecated() throws {\n        let score = GameScoreDeprecated()\n        let operations = score.operation\n            .addUnique((\"test\", \\.members), objects: [\"hello\"])\n        let expected = \"{\\\"test\\\":{\\\"__op\\\":\\\"AddUnique\\\",\\\"objects\\\":[\\\"hello\\\"]}}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(operations)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testAddUniqueKeypath() throws {\n        let score = GameScore(points: 10)\n        let operations = score.operation\n            .addUnique((\"test\", \\.levels), objects: [\"hello\"])\n        let expected = \"{\\\"test\\\":{\\\"__op\\\":\\\"AddUnique\\\",\\\"objects\\\":[\\\"hello\\\"]}}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(operations)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testAddRelation() throws {\n        let score = GameScore(points: 10)\n        var score2 = GameScore(points: 20)\n        score2.objectId = \"yolo\"\n        let operations = try score.operation\n            .addRelation(\"test\", objects: [score2])\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"test\\\":{\\\"__op\\\":\\\"AddRelation\\\",\\\"objects\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"yolo\\\"}]}}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(operations)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testAddRelationKeypathDeprecated() throws {\n        let score = GameScoreDeprecated()\n        var level = Level(level: 2)\n        level.objectId = \"yolo\"\n        let operations = try score.operation\n            .addRelation((\"next\", \\.next), objects: [level])\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"next\\\":{\\\"__op\\\":\\\"AddRelation\\\",\\\"objects\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"Level\\\",\\\"objectId\\\":\\\"yolo\\\"}]}}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(operations)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testAddRelationKeypath() throws {\n        let score = GameScore(points: 10)\n        var level = Level(level: 2)\n        level.objectId = \"yolo\"\n        let operations = try score.operation\n            .addRelation((\"previous\", \\.previous), objects: [level])\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"previous\\\":{\\\"__op\\\":\\\"AddRelation\\\",\\\"objects\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"Level\\\",\\\"objectId\\\":\\\"yolo\\\"}]}}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(operations)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testRemove() throws {\n        let score = GameScore(points: 10)\n        let operations = score.operation\n            .remove(\"test\", objects: [\"hello\"])\n        let expected = \"{\\\"test\\\":{\\\"__op\\\":\\\"Remove\\\",\\\"objects\\\":[\\\"hello\\\"]}}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(operations)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testRemoveKeypathDeprecated() throws {\n        let score = GameScoreDeprecated()\n        let operations = score.operation\n            .remove((\"test\", \\.members), objects: [\"hello\"])\n        let expected = \"{\\\"test\\\":{\\\"__op\\\":\\\"Remove\\\",\\\"objects\\\":[\\\"hello\\\"]}}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(operations)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testRemoveKeypath() throws {\n        let score = GameScore(points: 10)\n        let operations = score.operation\n            .remove((\"test\", \\.levels), objects: [\"hello\"])\n        let expected = \"{\\\"test\\\":{\\\"__op\\\":\\\"Remove\\\",\\\"objects\\\":[\\\"hello\\\"]}}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(operations)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testRemoveRelation() throws {\n        let score = GameScore(points: 10)\n        var score2 = GameScore(points: 20)\n        score2.objectId = \"yolo\"\n        let operations = try score.operation\n            .removeRelation(\"test\", objects: [score2])\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"test\\\":{\\\"__op\\\":\\\"RemoveRelation\\\",\\\"objects\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"yolo\\\"}]}}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(operations)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testRemoveRelationKeypathDeprecated() throws {\n        let score = GameScoreDeprecated()\n        var level = Level(level: 2)\n        level.objectId = \"yolo\"\n        let operations = try score.operation\n            .removeRelation((\"next\", \\.next), objects: [level])\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"next\\\":{\\\"__op\\\":\\\"RemoveRelation\\\",\\\"objects\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"Level\\\",\\\"objectId\\\":\\\"yolo\\\"}]}}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(operations)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testRemoveRelationKeypath() throws {\n        let score = GameScore(points: 10)\n        var level = Level(level: 2)\n        level.objectId = \"yolo\"\n        let operations = try score.operation\n            .removeRelation((\"previous\", \\.previous), objects: [level])\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"previous\\\":{\\\"__op\\\":\\\"RemoveRelation\\\",\\\"objects\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"Level\\\",\\\"objectId\\\":\\\"yolo\\\"}]}}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(operations)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testSet() throws {\n        let score = GameScore(points: 10)\n        let operations = score.operation.set((\"points\", \\.points), value: 15)\n            .set((\"levels\", \\.levels), value: [\"hello\"])\n        let expected = \"{\\\"levels\\\":[\\\"hello\\\"],\\\"points\\\":15}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(operations)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n        XCTAssertEqual(operations.target.points, 15)\n        var level = Level(level: 12)\n        level.members = [\"hello\", \"world\"]\n        let operations2 = score.operation.set((\"previous\", \\.previous), value: [level])\n        let expected2 = \"{\\\"previous\\\":[{\\\"level\\\":12,\\\"members\\\":[\\\"hello\\\",\\\"world\\\"]}]}\"\n        let encoded2 = try ParseCoding.parseEncoder()\n            .encode(operations2)\n        let decoded2 = try XCTUnwrap(String(data: encoded2, encoding: .utf8))\n        XCTAssertEqual(decoded2, expected2)\n        XCTAssertEqual(operations2.target.previous, [level])\n        let operations3 = score.operation.set((\"points\", \\.points), value: nil)\n            .set((\"levels\", \\.levels), value: [\"hello\"])\n        let expected3 = \"{\\\"levels\\\":[\\\"hello\\\"],\\\"points\\\":null}\"\n        let encoded3 = try ParseCoding.parseEncoder()\n            .encode(operations3)\n        let decoded3 = try XCTUnwrap(String(data: encoded3, encoding: .utf8))\n        XCTAssertEqual(decoded3, expected3)\n        XCTAssertNil(operations3.target.points)\n    }\n\n    func testSetKeyPath() throws {\n        var score = GameScore()\n        score.points = 10\n        score.objectId = \"yolo\"\n        var operations = try score.operation.set(\\.points, value: 15)\n            .set(\\.levels, value: [\"hello\"])\n        var expected = GameScore()\n        expected.points = 15\n        expected.objectId = \"yolo\"\n        expected.levels = [\"hello\"]\n        XCTAssertNotNil(operations.target.originalData)\n        XCTAssertNotEqual(operations.target, expected)\n        operations.target.originalData = nil\n        XCTAssertEqual(operations.target, expected)\n    }\n\n    func testSetKeyPathOtherTypeOperationsExist() throws {\n        var score = GameScore()\n        score.points = 10\n        var operations = score.operation\n            .set((\"levels\", \\.levels), value: [\"hello\"])\n        do {\n            operations = try operations.set(\\.points, value: 15)\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"Cannot combine\"))\n        }\n    }\n\n    func testSetKeyPathNilOperationsExist() throws {\n        var score = GameScore()\n        score.points = 10\n        var operations = score.operation\n            .set((\"points\", \\.points), value: nil)\n        do {\n            operations = try operations.set(\\.points, value: 15)\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"Cannot combine\"))\n        }\n    }\n\n    func testObjectIdSet() throws {\n        var score = GameScore()\n        score.objectId = \"test\"\n        score.levels = nil\n        let operations = score.operation.set((\"objectId\", \\.objectId), value: \"test\")\n        let expected = \"{}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(operations)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n        XCTAssertEqual(operations.target.objectId, \"test\")\n        var level = Level(level: 12)\n        level.members = [\"hello\", \"world\"]\n        score.previous = [level]\n        let expected2 = \"{}\"\n        let operations2 = score.operation.set((\"previous\", \\.previous), value: [level])\n        let encoded2 = try ParseCoding.parseEncoder()\n            .encode(operations2)\n        let decoded2 = try XCTUnwrap(String(data: encoded2, encoding: .utf8))\n        XCTAssertEqual(decoded2, expected2)\n        XCTAssertEqual(operations2.target.previous, [level])\n    }\n\n    func testUnchangedSet() throws {\n        let score = GameScore(points: 10)\n        let operations = score.operation.set((\"points\", \\.points), value: 10)\n        let expected = \"{}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(operations)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n        let operations2 = score.operation\n            .set((\"levels\", \\.levels), value: nil)\n        let expected2 = \"{}\"\n        let encoded2 = try ParseCoding.parseEncoder()\n            .encode(operations2)\n        let decoded2 = try XCTUnwrap(String(data: encoded2, encoding: .utf8))\n        XCTAssertEqual(decoded2, expected2)\n        XCTAssertNil(operations2.target.levels)\n    }\n\n    func testForceSet() throws {\n        let score = GameScore(points: 10)\n        let operations = score.operation.forceSet((\"points\", \\.points), value: 10)\n        let expected = \"{\\\"points\\\":10}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(operations)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n        let operations2 = score.operation\n            .forceSet((\"points\", \\.points), value: nil)\n        let expected2 = \"{\\\"points\\\":null}\"\n        let encoded2 = try ParseCoding.parseEncoder()\n            .encode(operations2)\n        let decoded2 = try XCTUnwrap(String(data: encoded2, encoding: .utf8))\n        XCTAssertEqual(decoded2, expected2)\n        XCTAssertNil(operations2.target.points)\n    }\n\n    func testUnset() throws {\n        let score = GameScore(points: 10)\n        let operations = score.operation\n            .unset(\"points\")\n        let expected = \"{\\\"points\\\":{\\\"__op\\\":\\\"Delete\\\"}}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(operations)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testUnsetKeypath() throws {\n        let score = GameScore(points: 10)\n        let operations = score.operation\n            .unset((\"points\", \\.levels))\n        let expected = \"{\\\"points\\\":{\\\"__op\\\":\\\"Delete\\\"}}\"\n        let encoded = try ParseCoding.parseEncoder()\n            .encode(operations)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParsePointerAsyncTests.swift",
    "content": "//\n//  ParsePointerAsyncTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 11/1/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParsePointerAsyncTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct GameScore: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int\n        var other: Pointer<GameScore>?\n        var others: [Pointer<GameScore>]?\n\n        //: a custom initializer\n        init() {\n            self.points = 5\n        }\n        init(points: Int) {\n            self.points = points\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            throw ParseError(code: .unknownError, message: \"Should create valid URL\")\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    @MainActor\n    func testFetch() async throws {\n        var score = GameScore(points: 10)\n        let objectId = \"yarr\"\n        score.objectId = objectId\n        let pointer = try score.toPointer()\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n        let encoded: Data!\n        do {\n            encoded = try scoreOnServer.getEncoder().encode(scoreOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let fetched = try await pointer.fetch(options: [])\n            XCTAssert(fetched.hasSameObjectId(as: scoreOnServer))\n            guard let fetchedCreatedAt = fetched.createdAt,\n                let fetchedUpdatedAt = fetched.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalCreatedAt = scoreOnServer.createdAt,\n                let originalUpdatedAt = scoreOnServer.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n            XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(fetched.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    @MainActor\n    func testDetectCircularDependency() async throws {\n        var score = GameScore(points: 10)\n        score.objectId = \"nice\"\n        score.other = try score.toPointer()\n\n        do {\n            _ = try await score.ensureDeepSave()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have failed with an error of detecting a circular dependency\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"circular\"))\n        }\n    }\n\n    @MainActor\n    func testDetectCircularDependencyArray() async throws {\n        var score = GameScore(points: 10)\n        score.objectId = \"nice\"\n        let first = try score.toPointer()\n        score.others = [first, first]\n\n        do {\n            _ = try await score.ensureDeepSave()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have failed with an error of detecting a circular dependency\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"circular\"))\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParsePointerCombineTests.swift",
    "content": "//\n//  ParsePointerCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 4/20/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParsePointerCombineTests: XCTestCase {\n\n    struct GameScore: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int\n\n        //: a custom initializer\n        init() {\n            self.points = 5\n        }\n        init(points: Int) {\n            self.points = points\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            throw ParseError(code: .unknownError, message: \"Should create valid URL\")\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testFetch() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"yarr\"\n        score.objectId = objectId\n        let pointer = try score.toPointer()\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Fetch\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(scoreOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = pointer.fetchPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { fetched in\n\n            XCTAssert(fetched.hasSameObjectId(as: scoreOnServer))\n            guard let fetchedCreatedAt = fetched.createdAt,\n                let fetchedUpdatedAt = fetched.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalCreatedAt = scoreOnServer.createdAt,\n                let originalUpdatedAt = scoreOnServer.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n            XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(fetched.ACL)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParsePointerTests.swift",
    "content": "//\n//  ParsePointerTests.swift\n//  ParseSwiftTests\n//\n//  Created by Corey Baker on 10/25/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParsePointerTests: XCTestCase {\n\n    struct GameScore: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int\n        var other: Pointer<GameScore>?\n        var others: [Pointer<GameScore>]?\n\n        //: a custom initializer\n        init() {\n            self.points = 5\n        }\n\n        init(points: Int) {\n            self.points = points\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            throw ParseError(code: .unknownError, message: \"Should create valid URL\")\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testPointer() throws {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        let pointer = try score.toPointer()\n        let initializedPointer = try Pointer(score)\n        XCTAssertEqual(pointer.className, score.className)\n        XCTAssertEqual(pointer.objectId, score.objectId)\n        XCTAssertEqual(pointer.className, initializedPointer.className)\n        XCTAssertEqual(pointer.objectId, initializedPointer.objectId)\n    }\n\n    func testDebugString() throws {\n        var score = GameScore(points: 10)\n        score.objectId = \"yarr\"\n        let pointer = try score.toPointer()\n        XCTAssertEqual(pointer.debugDescription,\n                       \"{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"yarr\\\"}\")\n        XCTAssertEqual(pointer.description,\n                       \"{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"yarr\\\"}\")\n    }\n\n    func testPointerNoObjectId() throws {\n        let score = GameScore(points: 10)\n        XCTAssertThrowsError(try Pointer(score))\n    }\n\n    func testPointerObjectId() throws {\n        let score = Pointer<GameScore>(objectId: \"yarr\")\n        var score2 = GameScore(points: 10)\n        score2.objectId = \"yarr\"\n        let pointer = try score2.toPointer()\n        XCTAssertEqual(pointer.className, score.className)\n        XCTAssertEqual(pointer.objectId, score.objectId)\n    }\n\n    func testHasSameObjectId() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"yarr\"\n        score.objectId = objectId\n        let pointer = try score.toPointer()\n        let pointer2 = pointer\n        XCTAssertTrue(pointer.hasSameObjectId(as: pointer2))\n        XCTAssertTrue(pointer.hasSameObjectId(as: score))\n        score.objectId = \"hello\"\n        let pointer3 = try score.toPointer()\n        XCTAssertFalse(pointer.hasSameObjectId(as: pointer3))\n        XCTAssertFalse(pointer.hasSameObjectId(as: score))\n    }\n\n    func testPointerEquality() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"yarr\"\n        score.objectId = objectId\n        let pointer = try score.toPointer()\n        var score2 = GameScore(points: 10)\n        score2.objectId = objectId\n        var pointer2 = try score2.toPointer()\n        XCTAssertEqual(pointer, pointer2)\n        pointer2.objectId = \"hello\"\n        XCTAssertNotEqual(pointer, pointer2)\n    }\n\n    func testDetectCircularDependency() throws {\n        var score = GameScore(points: 10)\n        score.objectId = \"nice\"\n        score.other = try score.toPointer()\n\n        score.ensureDeepSave { (_, _, parseError) in\n            guard let error = parseError else {\n                XCTFail(\"Should have failed with an error of detecting a circular dependency\")\n                return\n            }\n            XCTAssertTrue(error.message.contains(\"circular\"))\n        }\n    }\n\n    func testDetectCircularDependencyArray() throws {\n        var score = GameScore(points: 10)\n        score.objectId = \"nice\"\n        let first = try score.toPointer()\n        score.others = [first, first]\n\n        score.ensureDeepSave { (_, _, parseError) in\n            guard let error = parseError else {\n                XCTFail(\"Should have failed with an error of detecting a circular dependency\")\n                return\n            }\n            XCTAssertTrue(error.message.contains(\"circular\"))\n        }\n    }\n\n    // swiftlint:disable:next function_body_length\n    func testFetch() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"yarr\"\n        score.objectId = objectId\n        let pointer = try score.toPointer()\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n        let encoded: Data!\n        do {\n            encoded = try scoreOnServer.getEncoder().encode(scoreOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let fetched = try pointer.fetch(options: [])\n            XCTAssert(fetched.hasSameObjectId(as: scoreOnServer))\n            guard let fetchedCreatedAt = fetched.createdAt,\n                let fetchedUpdatedAt = fetched.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalCreatedAt = scoreOnServer.createdAt,\n                let originalUpdatedAt = scoreOnServer.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n            XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(fetched.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        do {\n            let fetched = try pointer.fetch(options: [.useMasterKey])\n            XCTAssert(fetched.hasSameObjectId(as: scoreOnServer))\n            guard let fetchedCreatedAt = fetched.createdAt,\n                let fetchedUpdatedAt = fetched.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalCreatedAt = scoreOnServer.createdAt,\n                let originalUpdatedAt = scoreOnServer.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n            XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(fetched.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    // swiftlint:disable:next function_body_length\n    func fetchAsync(score: Pointer<GameScore>, scoreOnServer: GameScore, callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Fetch object1\")\n        score.fetch(options: [], callbackQueue: callbackQueue) { result in\n\n            switch result {\n            case .success(let fetched):\n                XCTAssert(fetched.hasSameObjectId(as: scoreOnServer))\n                guard let fetchedCreatedAt = fetched.createdAt,\n                    let fetchedUpdatedAt = fetched.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation1.fulfill()\n                        return\n                }\n                guard let originalCreatedAt = scoreOnServer.createdAt,\n                    let originalUpdatedAt = scoreOnServer.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation1.fulfill()\n                        return\n                }\n                XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n                XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n                XCTAssertNil(fetched.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n\n        let expectation2 = XCTestExpectation(description: \"Fetch object2\")\n        score.fetch(options: [.useMasterKey], callbackQueue: callbackQueue) { result in\n\n            switch result {\n            case .success(let fetched):\n                XCTAssert(fetched.hasSameObjectId(as: scoreOnServer))\n                guard let fetchedCreatedAt = fetched.createdAt,\n                    let fetchedUpdatedAt = fetched.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation2.fulfill()\n                        return\n                }\n                guard let originalCreatedAt = scoreOnServer.createdAt,\n                    let originalUpdatedAt = scoreOnServer.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation2.fulfill()\n                        return\n                }\n                XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n                XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n                XCTAssertNil(fetched.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testEncodeEmbeddedPointer() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"yarr\"\n        score.objectId = objectId\n\n        var score2 = GameScore(points: 50)\n        score2.other = try score.toPointer()\n\n        let encoded = try score2.getEncoder().encode(score2,\n                                                     collectChildren: false,\n                                                     objectsSavedBeforeThisOne: nil,\n                                                     filesSavedBeforeThisOne: nil)\n\n        let decoded = String(data: encoded.encoded, encoding: .utf8)\n        XCTAssertEqual(decoded,\n                       // swiftlint:disable:next line_length\n                       \"{\\\"other\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"yarr\\\"},\\\"points\\\":50}\")\n        XCTAssertNil(encoded.unique)\n        XCTAssertEqual(encoded.unsavedChildren.count, 0)\n    }\n\n    func testPointerTypeEncoding() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"yarr\"\n        score.objectId = objectId\n\n        let pointerType = try PointerType(score)\n\n        let encoded = try ParseCoding.parseEncoder().encode(pointerType)\n        let decoded = String(data: encoded, encoding: .utf8)\n        XCTAssertEqual(decoded,\n                       \"{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"yarr\\\"}\")\n    }\n\n    // Thread tests randomly fail on linux\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testThreadSafeFetchAsync() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"yarr\"\n        score.objectId = objectId\n        let pointer = try score.toPointer()\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let encoded: Data!\n        do {\n            encoded = try scoreOnServer.getEncoder().encode(scoreOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        DispatchQueue.concurrentPerform(iterations: 100) {_ in\n            self.fetchAsync(score: pointer, scoreOnServer: scoreOnServer, callbackQueue: .global(qos: .background))\n        }\n    }\n    #endif\n\n    func testFetchAsyncMainQueue() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"yarr\"\n        score.objectId = objectId\n        let pointer = try score.toPointer()\n\n        var scoreOnServer = score\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n        let encoded: Data!\n        do {\n            encoded = try scoreOnServer.getEncoder().encode(scoreOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            scoreOnServer = try scoreOnServer.getDecoder().decode(GameScore.self, from: encoded)\n        } catch {\n            XCTFail(\"Should have encoded/decoded: Error: \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        self.fetchAsync(score: pointer, scoreOnServer: scoreOnServer, callbackQueue: .main)\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParsePolygonTests.swift",
    "content": "//\n//  ParsePolygonTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 7/9/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport XCTest\n@testable import ParseSwift\n\nclass ParsePolygonTests: XCTestCase {\n\n    struct FakeParsePolygon: Encodable, Hashable {\n        private let __type: String = \"Polygon\" // swiftlint:disable:this identifier_name\n        public let coordinates: [[Double]]\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n        points = [\n            try ParseGeoPoint(latitude: 0, longitude: 0),\n            try ParseGeoPoint(latitude: 0, longitude: 1),\n            try ParseGeoPoint(latitude: 1, longitude: 1),\n            try ParseGeoPoint(latitude: 1, longitude: 0),\n            try ParseGeoPoint(latitude: 0, longitude: 0)\n        ]\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    var points = [ParseGeoPoint]()\n\n    func testContainsPoint() throws {\n        let polygon = try ParsePolygon(points)\n        let inside = try ParseGeoPoint(latitude: 0.5, longitude: 0.5)\n        let outside = try ParseGeoPoint(latitude: 10, longitude: 10)\n        XCTAssertTrue(polygon.containsPoint(inside))\n        XCTAssertFalse(polygon.containsPoint(outside))\n    }\n\n    func testCheckInitializerRequiresMinPoints() throws {\n        let point = try ParseGeoPoint(latitude: 0, longitude: 0)\n        XCTAssertNoThrow(try ParsePolygon([point, point, point]))\n        XCTAssertThrowsError(try ParsePolygon([point, point]))\n        XCTAssertNoThrow(try ParsePolygon(point, point, point))\n        XCTAssertThrowsError(try ParsePolygon(point, point))\n    }\n\n    func testDecode() throws {\n        let polygon = try ParsePolygon(points)\n        let encoded = try ParseCoding.jsonEncoder().encode(polygon)\n        let decoded = try ParseCoding.jsonDecoder().decode(ParsePolygon.self, from: encoded)\n        XCTAssertEqual(decoded, polygon)\n    }\n\n    func testDecodeFailNotEnoughPoints() throws {\n        let fakePolygon = FakeParsePolygon(coordinates: [[0.0, 0.0], [0.0, 1.0]])\n        let encoded = try ParseCoding.jsonEncoder().encode(fakePolygon)\n        do {\n            _ = try ParseCoding.jsonDecoder().decode(ParsePolygon.self, from: encoded)\n            XCTFail(\"Should have failed\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have unwrapped\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"3 ParseGeoPoint\"))\n        }\n    }\n\n    func testDecodeFailWrongData() throws {\n        let fakePolygon = FakeParsePolygon(coordinates: [[0.0], [1.0]])\n        let encoded = try ParseCoding.jsonEncoder().encode(fakePolygon)\n        do {\n            _ = try ParseCoding.jsonDecoder().decode(ParsePolygon.self, from: encoded)\n            XCTFail(\"Should have failed\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have unwrapped\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"decode ParsePolygon\"))\n        }\n    }\n\n    func testDecodeFailTooMuchCoordinates() throws {\n        let fakePolygon = FakeParsePolygon(coordinates: [[0.0, 0.0, 0.0], [0.0, 1.0, 1.0]])\n        let encoded = try ParseCoding.jsonEncoder().encode(fakePolygon)\n        do {\n            _ = try ParseCoding.jsonDecoder().decode(ParsePolygon.self, from: encoded)\n            XCTFail(\"Should have failed\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have unwrapped\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"decode ParsePolygon\"))\n        }\n    }\n\n    func testDebugString() throws {\n        let polygon = try ParsePolygon(points)\n        let expected = \"{\\\"__type\\\":\\\"Polygon\\\",\\\"coordinates\\\":[[0,0],[1,0],[1,1],[0,1],[0,0]]}\"\n        XCTAssertEqual(polygon.debugDescription, expected)\n    }\n\n    func testDescription() throws {\n        let polygon = try ParsePolygon(points)\n        let expected = \"{\\\"__type\\\":\\\"Polygon\\\",\\\"coordinates\\\":[[0,0],[1,0],[1,1],[0,1],[0,0]]}\"\n        XCTAssertEqual(polygon.description, expected)\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParsePushAsyncTests.swift",
    "content": "//\n//  ParsePushAsyncTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/11/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParsePushAsyncTests: XCTestCase {\n    struct Installation: ParseInstallation {\n        var installationId: String?\n        var deviceType: String?\n        var deviceToken: String?\n        var badge: Int?\n        var timeZone: String?\n        var channels: [String]?\n        var appName: String?\n        var appIdentifier: String?\n        var appVersion: String?\n        var parseVersion: String?\n        var localeIdentifier: String?\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n        var customKey: String?\n\n        //: Implement your own version of merge\n        func merge(with object: Self) throws -> Self {\n            var updated = try mergeParse(with: object)\n            if updated.shouldRestoreKey(\\.customKey,\n                                         original: object) {\n                updated.customKey = object.customKey\n            }\n            return updated\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    @MainActor\n    func testSend() async throws {\n        let objectId = \"yolo\"\n        let appleAlert = ParsePushAppleAlert(body: \"hello world\")\n\n        let headers = [\"X-Parse-Push-Status-Id\": objectId]\n        let results = BooleanResponse(result: true)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0, headerFields: headers)\n            } catch {\n                return nil\n            }\n        }\n\n        let applePayload = ParsePushPayloadApple(alert: appleAlert)\n        let push = ParsePush(payload: applePayload)\n        let pushStatus = try await push.send()\n        XCTAssertEqual(pushStatus, objectId)\n    }\n\n    @MainActor\n    func testSendErrorServerReturnedFalse() async throws {\n        let objectId = \"yolo\"\n        let appleAlert = ParsePushAppleAlert(body: \"hello world\")\n\n        let headers = [\"X-Parse-Push-Status-Id\": objectId]\n        let results = BooleanResponse(result: false)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0, headerFields: headers)\n            } catch {\n                return nil\n            }\n        }\n\n        let applePayload = ParsePushPayloadApple(alert: appleAlert)\n        let push = ParsePush(payload: applePayload)\n        do {\n            _ = try await push.send()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"unsuccessful\"))\n        }\n    }\n\n    @MainActor\n    func testSendErrorTimeAndIntervalSet() async throws {\n        let objectId = \"yolo\"\n        let appleAlert = ParsePushAppleAlert(body: \"hello world\")\n\n        let headers = [\"X-Parse-Push-Status-Id\": objectId]\n        let results = BooleanResponse(result: true)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0, headerFields: headers)\n            } catch {\n                return nil\n            }\n        }\n\n        let applePayload = ParsePushPayloadApple(alert: appleAlert)\n        var push = ParsePush(payload: applePayload, expirationDate: Date())\n        push.expirationInterval = 7\n        do {\n            _ = try await push.send()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"expirationTime\"))\n        }\n    }\n\n    @MainActor\n    func testSendErrorQueryAndChannelsSet() async throws {\n        let objectId = \"yolo\"\n        let appleAlert = ParsePushAppleAlert(body: \"hello world\")\n\n        let headers = [\"X-Parse-Push-Status-Id\": objectId]\n        let results = BooleanResponse(result: true)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0, headerFields: headers)\n            } catch {\n                return nil\n            }\n        }\n\n        let applePayload = ParsePushPayloadApple(alert: appleAlert)\n        let installationQuery = Installation.query(isNotNull(key: \"objectId\"))\n        var push = ParsePush(payload: applePayload, query: installationQuery)\n        push.channels = [\"hello\"]\n        do {\n            _ = try await push.send()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"query\"))\n        }\n    }\n\n    @MainActor\n    func testSendErrorServerReturnedWrongType() async throws {\n        let objectId = \"yolo\"\n        let appleAlert = ParsePushAppleAlert(body: \"hello world\")\n\n        let headers = [\"X-Parse-Push-Status-Id\": objectId]\n        let results = HealthResponse(status: \"peace\")\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0, headerFields: headers)\n            } catch {\n                return nil\n            }\n        }\n\n        let applePayload = ParsePushPayloadApple(alert: appleAlert)\n        let push = ParsePush(payload: applePayload)\n        do {\n            _ = try await push.send()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"Boolean\"))\n        }\n    }\n\n    @MainActor\n    func testSendErrorServerMissingHeader() async throws {\n        let appleAlert = ParsePushAppleAlert(body: \"hello world\")\n\n        let results = BooleanResponse(result: true)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let applePayload = ParsePushPayloadApple(alert: appleAlert)\n        let push = ParsePush(payload: applePayload)\n        do {\n            _ = try await push.send()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"X-Parse-Push-Status-Id\"))\n        }\n    }\n\n    @MainActor\n    func testSendErrorServerMissingHeaderBodyFalse() async throws {\n        let appleAlert = ParsePushAppleAlert(body: \"hello world\")\n\n        let results = BooleanResponse(result: false)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let applePayload = ParsePushPayloadApple(alert: appleAlert)\n        let push = ParsePush(payload: applePayload)\n        do {\n            _ = try await push.send()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertTrue(parseError.message.contains(\"X-Parse-Push-Status-Id\"))\n        }\n    }\n\n    @MainActor\n    func testFetch() async throws {\n        let objectId = \"yolo\"\n        let appleAlert = ParsePushAppleAlert(body: \"hello world\")\n        var anyPayload = ParsePushPayloadAny()\n        anyPayload.alert = appleAlert\n        var statusOnServer = ParsePushStatus<ParsePushPayloadAny>()\n        statusOnServer.payload = anyPayload\n        statusOnServer.objectId = objectId\n        statusOnServer.createdAt = Date()\n        statusOnServer.updatedAt = statusOnServer.createdAt\n\n        let results = QueryResponse<ParsePushStatus<ParsePushPayloadAny>>(results: [statusOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let applePayload = ParsePushPayloadApple(alert: appleAlert)\n        let push = ParsePush(payload: applePayload)\n        let found = try await push.fetchStatus(objectId)\n        XCTAssert(found.hasSameObjectId(as: statusOnServer))\n        XCTAssertEqual(found.payload, anyPayload.convertToApple())\n    }\n\n    @MainActor\n    func testFetchBrokenServerResponse() async throws {\n        let objectId = \"yolo\"\n        let appleAlert = ParsePushAppleAlert(body: \"hello world\")\n        var anyPayload = ParsePushPayloadAny()\n        anyPayload.alert = appleAlert\n        let query = Installation.query(\"peace\" == \"out\")\n        var statusOnServer = try ParsePushStatusResponse()\n            .setPayload(anyPayload)\n            .setQueryWhere(query.where)\n        statusOnServer.objectId = objectId\n        statusOnServer.createdAt = Date()\n        statusOnServer.updatedAt = statusOnServer.createdAt\n\n        let results = QueryResponse<ParsePushStatusResponse>(results: [statusOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let applePayload = ParsePushPayloadApple(alert: appleAlert)\n        let push = ParsePush(payload: applePayload)\n        let found = try await push.fetchStatus(objectId)\n        XCTAssertEqual(found.objectId, objectId)\n        XCTAssertEqual(found.payload, anyPayload.convertToApple())\n        XCTAssertEqual(found.query, query.where)\n    }\n\n    @MainActor\n    func testFetchBrokenServerResponseWrongPayload() async throws {\n        let objectId = \"yolo\"\n        let appleAlert = ParsePushAppleAlert(body: \"hello world\")\n        var anyPayload = ParsePushPayloadAny()\n        anyPayload.alert = appleAlert\n        let query = Installation.query(\"peace\" == \"out\")\n        var statusOnServer = try ParsePushStatusResponse()\n            .setQueryWhere(query.where)\n        statusOnServer.payload = \"this is wrong\"\n        statusOnServer.objectId = objectId\n        statusOnServer.createdAt = Date()\n        statusOnServer.updatedAt = statusOnServer.createdAt\n\n        let results = QueryResponse<ParsePushStatusResponse>(results: [statusOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let applePayload = ParsePushPayloadApple(alert: appleAlert)\n        let push = ParsePush(payload: applePayload)\n        do {\n            _ = try await push.fetchStatus(objectId)\n        } catch {\n            XCTAssertTrue(error.equalsTo(.unknownError))\n        }\n    }\n\n    @MainActor\n    func testFetchBrokenServerResponseWrongQuery() async throws {\n        let objectId = \"yolo\"\n        let appleAlert = ParsePushAppleAlert(body: \"hello world\")\n        var anyPayload = ParsePushPayloadAny()\n        anyPayload.alert = appleAlert\n        var statusOnServer = try ParsePushStatusResponse()\n            .setPayload(anyPayload)\n        statusOnServer.query = \"this is wrong\"\n        statusOnServer.objectId = objectId\n        statusOnServer.createdAt = Date()\n        statusOnServer.updatedAt = statusOnServer.createdAt\n\n        let results = QueryResponse<ParsePushStatusResponse>(results: [statusOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let applePayload = ParsePushPayloadApple(alert: appleAlert)\n        let push = ParsePush(payload: applePayload)\n        do {\n            _ = try await push.fetchStatus(objectId)\n        } catch {\n            XCTAssertTrue(error.equalsTo(.unknownError))\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParsePushCombineTests.swift",
    "content": "//\n//  ParsePushCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/11/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParsePushCombineTests: XCTestCase {\n    struct Installation: ParseInstallation {\n        var installationId: String?\n        var deviceType: String?\n        var deviceToken: String?\n        var badge: Int?\n        var timeZone: String?\n        var channels: [String]?\n        var appName: String?\n        var appIdentifier: String?\n        var appVersion: String?\n        var parseVersion: String?\n        var localeIdentifier: String?\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n        var customKey: String?\n\n        //: Implement your own version of merge\n        func merge(with object: Self) throws -> Self {\n            var updated = try mergeParse(with: object)\n            if updated.shouldRestoreKey(\\.customKey,\n                                         original: object) {\n                updated.customKey = object.customKey\n            }\n            return updated\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testSend() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Send\")\n\n        let objectId = \"yolo\"\n        let appleAlert = ParsePushAppleAlert(body: \"hello world\")\n\n        let headers = [\"X-Parse-Push-Status-Id\": objectId]\n        let results = BooleanResponse(result: true)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0, headerFields: headers)\n            } catch {\n                return nil\n            }\n        }\n\n        let applePayload = ParsePushPayloadApple(alert: appleAlert)\n        let push = ParsePush(payload: applePayload)\n        let publisher = push.sendPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { pushStatus in\n\n            XCTAssertEqual(pushStatus, objectId)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSendErrorServerReturnedFalse() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Send\")\n\n        let objectId = \"yolo\"\n        let appleAlert = ParsePushAppleAlert(body: \"hello world\")\n\n        let headers = [\"X-Parse-Push-Status-Id\": objectId]\n        let results = BooleanResponse(result: false)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0, headerFields: headers)\n            } catch {\n                return nil\n            }\n        }\n\n        let applePayload = ParsePushPayloadApple(alert: appleAlert)\n        let push = ParsePush(payload: applePayload)\n        let publisher = push.sendPublisher()\n            .sink(receiveCompletion: { result in\n                switch result {\n                case .finished:\n                    XCTFail(\"Should have thrown ParseError\")\n                case .failure(let error):\n                    XCTAssertTrue(error.message.contains(\"unsuccessful\"))\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n\n            XCTFail(\"Should have thrown ParseError\")\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSendErrorTimeAndIntervalSet() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Send\")\n\n        let objectId = \"yolo\"\n        let appleAlert = ParsePushAppleAlert(body: \"hello world\")\n\n        let headers = [\"X-Parse-Push-Status-Id\": objectId]\n        let results = BooleanResponse(result: true)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0, headerFields: headers)\n            } catch {\n                return nil\n            }\n        }\n\n        let applePayload = ParsePushPayloadApple(alert: appleAlert)\n        var push = ParsePush(payload: applePayload, expirationDate: Date())\n        push.expirationInterval = 7\n        let publisher = push.sendPublisher()\n            .sink(receiveCompletion: { result in\n                switch result {\n                case .finished:\n                    XCTFail(\"Should have thrown ParseError\")\n                case .failure(let error):\n                    XCTAssertTrue(error.message.contains(\"expirationTime\"))\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n\n            XCTFail(\"Should have thrown ParseError\")\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSendErrorQueryAndChannelsSet() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Send\")\n\n        let objectId = \"yolo\"\n        let appleAlert = ParsePushAppleAlert(body: \"hello world\")\n\n        let headers = [\"X-Parse-Push-Status-Id\": objectId]\n        let results = BooleanResponse(result: true)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0, headerFields: headers)\n            } catch {\n                return nil\n            }\n        }\n\n        let applePayload = ParsePushPayloadApple(alert: appleAlert)\n        let installationQuery = Installation.query(isNotNull(key: \"objectId\"))\n        var push = ParsePush(payload: applePayload, query: installationQuery)\n        push.channels = [\"hello\"]\n        let publisher = push.sendPublisher()\n            .sink(receiveCompletion: { result in\n                switch result {\n                case .finished:\n                    XCTFail(\"Should have thrown ParseError\")\n                case .failure(let error):\n                    XCTAssertTrue(error.message.contains(\"query\"))\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n\n            XCTFail(\"Should have thrown ParseError\")\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSendErrorServerReturnedWrongType() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Send\")\n\n        let objectId = \"yolo\"\n        let appleAlert = ParsePushAppleAlert(body: \"hello world\")\n\n        let headers = [\"X-Parse-Push-Status-Id\": objectId]\n        let results = HealthResponse(status: \"peace\")\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0, headerFields: headers)\n            } catch {\n                return nil\n            }\n        }\n\n        let applePayload = ParsePushPayloadApple(alert: appleAlert)\n        let push = ParsePush(payload: applePayload)\n        let publisher = push.sendPublisher()\n            .sink(receiveCompletion: { result in\n                switch result {\n                case .finished:\n                    XCTFail(\"Should have thrown ParseError\")\n                case .failure(let error):\n                    XCTAssertTrue(error.message.contains(\"Boolean\"))\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n\n            XCTFail(\"Should have thrown ParseError\")\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSendErrorServerMissingHeader() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Send\")\n\n        let appleAlert = ParsePushAppleAlert(body: \"hello world\")\n\n        let results = BooleanResponse(result: true)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let applePayload = ParsePushPayloadApple(alert: appleAlert)\n        let push = ParsePush(payload: applePayload)\n        let publisher = push.sendPublisher()\n            .sink(receiveCompletion: { result in\n                switch result {\n                case .finished:\n                    XCTFail(\"Should have thrown ParseError\")\n                case .failure(let error):\n                    XCTAssertTrue(error.message.contains(\"X-Parse-Push-Status-Id\"))\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n\n            XCTFail(\"Should have thrown ParseError\")\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testFetch() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Send\")\n\n        let objectId = \"yolo\"\n        let appleAlert = ParsePushAppleAlert(body: \"hello world\")\n        var anyPayload = ParsePushPayloadAny()\n        anyPayload.alert = appleAlert\n        var statusOnServer = ParsePushStatus<ParsePushPayloadAny>()\n        statusOnServer.payload = anyPayload\n        statusOnServer.objectId = objectId\n        statusOnServer.createdAt = Date()\n        statusOnServer.updatedAt = statusOnServer.createdAt\n\n        let results = QueryResponse<ParsePushStatus<ParsePushPayloadAny>>(results: [statusOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let applePayload = ParsePushPayloadApple(alert: appleAlert)\n        let push = ParsePush(payload: applePayload)\n        let publisher = push.fetchStatusPublisher(objectId)\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { found in\n\n            XCTAssert(found.hasSameObjectId(as: statusOnServer))\n            XCTAssertEqual(found.payload, anyPayload.convertToApple())\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParsePushPayloadAnyTests.swift",
    "content": "//\n//  ParsePushPayloadAnyTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/12/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\n// swiftlint:disable line_length\n\nclass ParsePushPayloadAnyTests: XCTestCase {\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testCoding() throws {\n\n        // Setup Apple\n        let sound = ParsePushAppleSound(critical: true, name: \"hello\", volume: 7)\n        var alert = ParsePushAppleAlert(body: \"pull up\")\n        alert.titleLocKey = \"yes\"\n        alert.title = \"you\"\n        alert.locArgs = [\"mother\"]\n        alert.locKey = \"cousin\"\n        alert.action = \"to\"\n        alert.actionLocKey = \"icon\"\n        alert.subtitle = \"trip\"\n        alert.subtitleLocKey = \"far\"\n        alert.subtitleLocArgs = [\"gone\"]\n        alert.launchImage = \"it\"\n        alert.titleLocArgs = [\"arg\"]\n        alert.titleLocKey = \"it\"\n\n        // Setup Firebase\n        var notification = ParsePushFirebaseNotification(title: \"hello\", body: \"android\", icon: \"world\")\n        notification.sound = \"yes\"\n        notification.badge = \"no\"\n        notification.androidChannelId = \"you\"\n        notification.bodyLocArgs = [\"mother\"]\n        notification.bodyLocKey = \"cousin\"\n        notification.clickAction = \"to\"\n        notification.image = \"icon\"\n        notification.subtitle = \"trip\"\n        notification.tag = \"it\"\n        notification.color = \"blue\"\n        notification.titleLocArgs = [\"arg\"]\n        notification.titleLocKey = \"it\"\n\n        // Set Apple\n        var anyPayload = ParsePushPayloadAny()\n        anyPayload.alert = alert\n        anyPayload.badge = AnyCodable(1)\n        anyPayload.sound = AnyCodable(sound)\n        anyPayload.urlArgs = [\"help\"]\n        anyPayload.interruptionLevel = \"yolo\"\n        anyPayload.topic = \"naw\"\n        anyPayload.threadId = \"yep\"\n        anyPayload.collapseId = \"nope\"\n        anyPayload.pushType = .background\n        anyPayload.targetContentId = \"press\"\n        anyPayload.relevanceScore = 2.0\n        anyPayload.priority = 6\n        anyPayload.contentAvailable = 1\n        anyPayload.mutableContent = 1\n\n        // Set Firebase\n        anyPayload.notification = notification\n        anyPayload.data = [\"help\": \"you\"]\n        anyPayload.collapseKey = \"nope\"\n        anyPayload.delayWhileIdle = false\n        anyPayload.dryRun = false\n        anyPayload.title = \"peace\"\n        anyPayload.restrictedPackageName = \"geez\"\n        anyPayload.uri = URL(string: \"https://parse.org\")\n\n        // Test Apple\n        let applePayload = anyPayload.convertToApple()\n        let encoded = try ParseCoding.parseEncoder().encode(applePayload)\n        let decoded = try ParseCoding.jsonDecoder().decode(ParsePushPayloadApple.self, from: encoded)\n        XCTAssertEqual(applePayload, decoded)\n        XCTAssertEqual(applePayload.description,\n                       \"{\\\"alert\\\":{\\\"action\\\":\\\"to\\\",\\\"action-loc-key\\\":\\\"icon\\\",\\\"body\\\":\\\"pull up\\\",\\\"launch-image\\\":\\\"it\\\",\\\"loc-args\\\":[\\\"mother\\\"],\\\"loc-key\\\":\\\"cousin\\\",\\\"subtitle\\\":\\\"trip\\\",\\\"subtitle-loc-args\\\":[\\\"gone\\\"],\\\"subtitle-loc-key\\\":\\\"far\\\",\\\"title\\\":\\\"you\\\",\\\"title-loc-args\\\":[\\\"arg\\\"],\\\"title-loc-key\\\":\\\"it\\\"},\\\"badge\\\":1,\\\"collapse_id\\\":\\\"nope\\\",\\\"content-available\\\":1,\\\"interruptionLevel\\\":\\\"yolo\\\",\\\"mutable-content\\\":1,\\\"priority\\\":6,\\\"push_type\\\":\\\"background\\\",\\\"relevance-score\\\":2,\\\"sound\\\":{\\\"critical\\\":true,\\\"name\\\":\\\"hello\\\",\\\"volume\\\":7},\\\"targetContentIdentifier\\\":\\\"press\\\",\\\"threadId\\\":\\\"yep\\\",\\\"topic\\\":\\\"naw\\\",\\\"urlArgs\\\":[\\\"help\\\"]}\")\n        let decodedAny = try ParseCoding.jsonDecoder().decode(ParsePushPayloadAny.self, from: encoded).convertToApple()\n        XCTAssertEqual(decodedAny, applePayload)\n\n        // Test Firebase\n        let fcmPayload = anyPayload.convertToFirebase()\n        let encoded2 = try ParseCoding.parseEncoder().encode(fcmPayload)\n        let decoded2 = try ParseCoding.jsonDecoder().decode(ParsePushPayloadFirebase.self, from: encoded2)\n        XCTAssertEqual(fcmPayload, decoded2)\n        let decodedAny2 = try ParseCoding.jsonDecoder().decode(ParsePushPayloadAny.self, from: encoded).convertToApple()\n        XCTAssertEqual(decodedAny2, applePayload)\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        XCTAssertEqual(fcmPayload.description,\n                       \"{\\\"collapseKey\\\":\\\"nope\\\",\\\"data\\\":{\\\"help\\\":\\\"you\\\"},\\\"delayWhileIdle\\\":false,\\\"dryRun\\\":false,\\\"notification\\\":{\\\"android_channel_id\\\":\\\"you\\\",\\\"badge\\\":\\\"no\\\",\\\"body\\\":\\\"android\\\",\\\"body_loc-key\\\":\\\"cousin\\\",\\\"body-loc-args\\\":[\\\"mother\\\"],\\\"click_action\\\":\\\"to\\\",\\\"color\\\":\\\"blue\\\",\\\"icon\\\":\\\"world\\\",\\\"image\\\":\\\"icon\\\",\\\"sound\\\":\\\"yes\\\",\\\"subtitle\\\":\\\"trip\\\",\\\"tag\\\":\\\"it\\\",\\\"title\\\":\\\"hello\\\",\\\"title_loc_args\\\":[\\\"arg\\\"],\\\"title_loc_key\\\":\\\"it\\\"},\\\"restrictedPackageName\\\":\\\"geez\\\",\\\"title\\\":\\\"peace\\\",\\\"uri\\\":\\\"https:\\\\/\\\\/parse.org\\\"}\")\n        #endif\n    }\n\n    func testAppleAlertStringDecode() throws {\n        let sound = ParsePushAppleSound(critical: true, name: \"hello\", volume: 7)\n        let alert = ParsePushAppleAlert(body: \"pull up\")\n        var anyPayload = ParsePushPayloadAny()\n        anyPayload.alert = alert\n        anyPayload.badge = AnyCodable(1)\n        anyPayload.sound = AnyCodable(sound)\n        anyPayload.urlArgs = [\"help\"]\n        anyPayload.interruptionLevel = \"yolo\"\n        anyPayload.topic = \"naw\"\n        anyPayload.threadId = \"yep\"\n        anyPayload.collapseId = \"nope\"\n        anyPayload.pushType = .background\n        anyPayload.targetContentId = \"press\"\n        anyPayload.relevanceScore = 2.0\n        anyPayload.priority = 6\n        anyPayload.contentAvailable = 1\n        anyPayload.mutableContent = 1\n\n        let applePayload = anyPayload.convertToApple()\n        guard let jsonData = \"{\\\"alert\\\":\\\"pull up\\\",\\\"badge\\\":1,\\\"collapse_id\\\":\\\"nope\\\",\\\"content-available\\\":1,\\\"interruptionLevel\\\":\\\"yolo\\\",\\\"mutable-content\\\":1,\\\"priority\\\":6,\\\"push_type\\\":\\\"background\\\",\\\"relevance-score\\\":2,\\\"sound\\\":{\\\"critical\\\":true,\\\"name\\\":\\\"hello\\\",\\\"volume\\\":7},\\\"targetContentIdentifier\\\":\\\"press\\\",\\\"threadId\\\":\\\"yep\\\",\\\"topic\\\":\\\"naw\\\",\\\"urlArgs\\\":[\\\"help\\\"]}\".data(using: .utf8) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let decodedAlert = try ParseCoding.jsonDecoder().decode(ParsePushPayloadAny.self, from: jsonData).convertToApple()\n        XCTAssertEqual(decodedAlert, applePayload)\n    }\n\n    func testConvertToApple() throws {\n        let sound = ParsePushAppleSound(critical: true, name: \"hello\", volume: 7)\n        var alert = ParsePushAppleAlert(body: \"pull up\")\n        alert.titleLocKey = \"yes\"\n        alert.title = \"you\"\n        alert.locArgs = [\"mother\"]\n        alert.locKey = \"cousin\"\n        alert.action = \"to\"\n        alert.actionLocKey = \"icon\"\n        alert.subtitle = \"trip\"\n        alert.subtitleLocKey = \"far\"\n        alert.subtitleLocArgs = [\"gone\"]\n        alert.launchImage = \"it\"\n        alert.titleLocArgs = [\"arg\"]\n        alert.titleLocKey = \"it\"\n\n        var anyPayload = ParsePushPayloadAny()\n        anyPayload.alert = alert\n        anyPayload.badge = AnyCodable(1)\n        anyPayload.sound = AnyCodable(sound)\n        anyPayload.urlArgs = [\"help\"]\n        anyPayload.interruptionLevel = \"yolo\"\n        anyPayload.topic = \"naw\"\n        anyPayload.threadId = \"yep\"\n        anyPayload.collapseId = \"nope\"\n        anyPayload.pushType = .background\n        anyPayload.targetContentId = \"press\"\n        anyPayload.relevanceScore = 2.0\n        anyPayload.priority = 6\n        anyPayload.contentAvailable = 1\n        anyPayload.mutableContent = 1\n\n        let applePayload = anyPayload.convertToApple()\n        let encoded = try ParseCoding.parseEncoder().encode(applePayload)\n        let decoded = try ParseCoding.jsonDecoder().decode(ParsePushPayloadApple.self, from: encoded)\n        XCTAssertEqual(applePayload, decoded)\n        XCTAssertEqual(applePayload.description,\n                       \"{\\\"alert\\\":{\\\"action\\\":\\\"to\\\",\\\"action-loc-key\\\":\\\"icon\\\",\\\"body\\\":\\\"pull up\\\",\\\"launch-image\\\":\\\"it\\\",\\\"loc-args\\\":[\\\"mother\\\"],\\\"loc-key\\\":\\\"cousin\\\",\\\"subtitle\\\":\\\"trip\\\",\\\"subtitle-loc-args\\\":[\\\"gone\\\"],\\\"subtitle-loc-key\\\":\\\"far\\\",\\\"title\\\":\\\"you\\\",\\\"title-loc-args\\\":[\\\"arg\\\"],\\\"title-loc-key\\\":\\\"it\\\"},\\\"badge\\\":1,\\\"collapse_id\\\":\\\"nope\\\",\\\"content-available\\\":1,\\\"interruptionLevel\\\":\\\"yolo\\\",\\\"mutable-content\\\":1,\\\"priority\\\":6,\\\"push_type\\\":\\\"background\\\",\\\"relevance-score\\\":2,\\\"sound\\\":{\\\"critical\\\":true,\\\"name\\\":\\\"hello\\\",\\\"volume\\\":7},\\\"targetContentIdentifier\\\":\\\"press\\\",\\\"threadId\\\":\\\"yep\\\",\\\"topic\\\":\\\"naw\\\",\\\"urlArgs\\\":[\\\"help\\\"]}\")\n        let decoded2 = try ParseCoding.jsonDecoder().decode(ParsePushPayloadAny.self, from: encoded).convertToApple()\n        XCTAssertEqual(decoded2, applePayload)\n        var applePayload2 = applePayload\n        applePayload2.sound = AnyCodable(\"wow\")\n        let encodedSound = try ParseCoding.parseEncoder().encode(applePayload2)\n        let decodedSound = try ParseCoding.jsonDecoder().decode(ParsePushPayloadAny.self, from: encodedSound).convertToApple()\n        XCTAssertEqual(decodedSound, applePayload2)\n    }\n\n    func testConvertToFirebase() throws {\n        var notification = ParsePushFirebaseNotification(title: \"hello\", body: \"android\", icon: \"world\")\n        notification.sound = \"yes\"\n        notification.badge = \"no\"\n        notification.androidChannelId = \"you\"\n        notification.bodyLocArgs = [\"mother\"]\n        notification.bodyLocKey = \"cousin\"\n        notification.clickAction = \"to\"\n        notification.image = \"icon\"\n        notification.subtitle = \"trip\"\n        notification.tag = \"it\"\n        notification.color = \"blue\"\n        notification.titleLocArgs = [\"arg\"]\n        notification.titleLocKey = \"it\"\n\n        var anyPayload = ParsePushPayloadAny()\n        anyPayload.priority = AnyCodable(ParsePushPayloadFirebase.PushPriority.high)\n        anyPayload.contentAvailable = true\n        anyPayload.mutableContent = true\n        anyPayload.notification = notification\n        anyPayload.data = [\"help\": \"you\"]\n        anyPayload.collapseKey = \"nope\"\n        anyPayload.delayWhileIdle = false\n        anyPayload.dryRun = false\n        anyPayload.title = \"peace\"\n        anyPayload.restrictedPackageName = \"geez\"\n        anyPayload.uri = URL(string: \"https://parse.org\")\n\n        let fcmPayload = anyPayload.convertToFirebase()\n        let encoded = try ParseCoding.parseEncoder().encode(fcmPayload)\n        let decoded = try ParseCoding.jsonDecoder().decode(ParsePushPayloadFirebase.self, from: encoded)\n        XCTAssertEqual(fcmPayload, decoded)\n        let decoded2 = try ParseCoding.jsonDecoder().decode(ParsePushPayloadAny.self, from: encoded).convertToFirebase()\n        XCTAssertEqual(decoded2, fcmPayload)\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        XCTAssertEqual(fcmPayload.description,\n                       \"{\\\"collapseKey\\\":\\\"nope\\\",\\\"contentAvailable\\\":true,\\\"data\\\":{\\\"help\\\":\\\"you\\\"},\\\"delayWhileIdle\\\":false,\\\"dryRun\\\":false,\\\"mutableContent\\\":true,\\\"notification\\\":{\\\"android_channel_id\\\":\\\"you\\\",\\\"badge\\\":\\\"no\\\",\\\"body\\\":\\\"android\\\",\\\"body_loc-key\\\":\\\"cousin\\\",\\\"body-loc-args\\\":[\\\"mother\\\"],\\\"click_action\\\":\\\"to\\\",\\\"color\\\":\\\"blue\\\",\\\"icon\\\":\\\"world\\\",\\\"image\\\":\\\"icon\\\",\\\"sound\\\":\\\"yes\\\",\\\"subtitle\\\":\\\"trip\\\",\\\"tag\\\":\\\"it\\\",\\\"title\\\":\\\"hello\\\",\\\"title_loc_args\\\":[\\\"arg\\\"],\\\"title_loc_key\\\":\\\"it\\\"},\\\"priority\\\":\\\"high\\\",\\\"restrictedPackageName\\\":\\\"geez\\\",\\\"title\\\":\\\"peace\\\",\\\"uri\\\":\\\"https:\\\\/\\\\/parse.org\\\"}\")\n        #endif\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParsePushPayloadAppleTests.swift",
    "content": "//\n//  ParsePushPayloadAppleTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/11/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\n// swiftlint:disable line_length\n\nclass ParsePushPayloadAppleTests: XCTestCase {\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testInitializers() throws {\n        let body = \"Hello from ParseSwift!\"\n        var applePayload = ParsePushPayloadApple(body: body)\n        XCTAssertEqual(applePayload.description,\n                       \"{\\\"alert\\\":{\\\"body\\\":\\\"\\(body)\\\"},\\\"push_type\\\":\\\"alert\\\"}\")\n        let applePayload2 = ParsePushPayloadApple(alert: .init(body: body))\n        XCTAssertEqual(applePayload, applePayload2)\n        XCTAssertEqual(applePayload.body, body)\n        applePayload.alert = nil\n        XCTAssertNil(applePayload.body)\n        applePayload.body = body\n        XCTAssertEqual(applePayload.alert, applePayload2.alert)\n    }\n\n    func testBadge() throws {\n        let applePayload = ParsePushPayloadApple()\n            .setBadge(1)\n        XCTAssertEqual(applePayload.description,\n                       \"{\\\"badge\\\":1,\\\"push_type\\\":\\\"alert\\\"}\")\n        let applePayload2 = ParsePushPayloadApple()\n            .incrementBadge()\n        XCTAssertEqual(applePayload2.description,\n                       \"{\\\"badge\\\":{\\\"__op\\\":\\\"Increment\\\",\\\"amount\\\":1},\\\"push_type\\\":\\\"alert\\\"}\")\n    }\n\n    func testSound() throws {\n        let applePayload = ParsePushPayloadApple()\n            .setSound(\"hello\")\n        XCTAssertEqual(applePayload.description,\n                       \"{\\\"push_type\\\":\\\"alert\\\",\\\"sound\\\":\\\"hello\\\"}\")\n        let soundString: String = try applePayload.getSound()\n        XCTAssertEqual(soundString, \"hello\")\n        let sound = ParsePushAppleSound(critical: true, name: \"hello\", volume: 7)\n        let applePayload2 = ParsePushPayloadApple()\n            .setSound(sound)\n        XCTAssertEqual(applePayload2.description,\n                       \"{\\\"push_type\\\":\\\"alert\\\",\\\"sound\\\":{\\\"critical\\\":true,\\\"name\\\":\\\"hello\\\",\\\"volume\\\":7}}\")\n        let soundObject: ParsePushAppleSound = try applePayload2.getSound()\n        XCTAssertEqual(soundObject, sound)\n        XCTAssertThrowsError(try applePayload2.getSound() as String)\n    }\n\n    func testCoding() throws {\n        let sound = ParsePushAppleSound(critical: true, name: \"hello\", volume: 7)\n        var alert = ParsePushAppleAlert(body: \"pull up\")\n        alert.titleLocKey = \"yes\"\n        alert.title = \"you\"\n        alert.locArgs = [\"mother\"]\n        alert.locKey = \"cousin\"\n        alert.action = \"to\"\n        alert.actionLocKey = \"icon\"\n        alert.subtitle = \"trip\"\n        alert.subtitleLocKey = \"far\"\n        alert.subtitleLocArgs = [\"gone\"]\n        alert.launchImage = \"it\"\n        alert.titleLocArgs = [\"arg\"]\n        alert.titleLocKey = \"it\"\n        var applePayload = ParsePushPayloadApple(alert: alert)\n            .setBadge(1)\n            .setSound(sound)\n        applePayload.urlArgs = [\"help\"]\n        applePayload.interruptionLevel = \"yolo\"\n        applePayload.topic = \"naw\"\n        applePayload.threadId = \"yep\"\n        applePayload.collapseId = \"nope\"\n        applePayload.pushType = .background\n        applePayload.priority = 6\n        applePayload.contentAvailable = 1\n        applePayload.mutableContent = 1\n        applePayload.targetContentId = \"press\"\n        applePayload.relevanceScore = 2.0\n        let encoded = try ParseCoding.parseEncoder().encode(applePayload)\n        let decoded = try ParseCoding.jsonDecoder().decode(ParsePushPayloadApple.self, from: encoded)\n        XCTAssertEqual(applePayload, decoded)\n        XCTAssertEqual(applePayload.description,\n                       \"{\\\"alert\\\":{\\\"action\\\":\\\"to\\\",\\\"action-loc-key\\\":\\\"icon\\\",\\\"body\\\":\\\"pull up\\\",\\\"launch-image\\\":\\\"it\\\",\\\"loc-args\\\":[\\\"mother\\\"],\\\"loc-key\\\":\\\"cousin\\\",\\\"subtitle\\\":\\\"trip\\\",\\\"subtitle-loc-args\\\":[\\\"gone\\\"],\\\"subtitle-loc-key\\\":\\\"far\\\",\\\"title\\\":\\\"you\\\",\\\"title-loc-args\\\":[\\\"arg\\\"],\\\"title-loc-key\\\":\\\"it\\\"},\\\"badge\\\":1,\\\"collapse_id\\\":\\\"nope\\\",\\\"content-available\\\":1,\\\"interruptionLevel\\\":\\\"yolo\\\",\\\"mutable-content\\\":1,\\\"priority\\\":6,\\\"push_type\\\":\\\"background\\\",\\\"relevance-score\\\":2,\\\"sound\\\":{\\\"critical\\\":true,\\\"name\\\":\\\"hello\\\",\\\"volume\\\":7},\\\"targetContentIdentifier\\\":\\\"press\\\",\\\"threadId\\\":\\\"yep\\\",\\\"topic\\\":\\\"naw\\\",\\\"urlArgs\\\":[\\\"help\\\"]}\")\n        XCTAssertEqual(alert.description, \"{\\\"action\\\":\\\"to\\\",\\\"action-loc-key\\\":\\\"icon\\\",\\\"body\\\":\\\"pull up\\\",\\\"launch-image\\\":\\\"it\\\",\\\"loc-args\\\":[\\\"mother\\\"],\\\"loc-key\\\":\\\"cousin\\\",\\\"subtitle\\\":\\\"trip\\\",\\\"subtitle-loc-args\\\":[\\\"gone\\\"],\\\"subtitle-loc-key\\\":\\\"far\\\",\\\"title\\\":\\\"you\\\",\\\"title-loc-args\\\":[\\\"arg\\\"],\\\"title-loc-key\\\":\\\"it\\\"}\")\n        let alert2 = ParsePushAppleAlert()\n        XCTAssertNotEqual(alert, alert2)\n        XCTAssertEqual(sound.description, \"{\\\"critical\\\":true,\\\"name\\\":\\\"hello\\\",\\\"volume\\\":7}\")\n    }\n\n    func testCodingAlert() throws {\n        let body = \"Hello from ParseSwift!\"\n        var applePayload = ParsePushPayloadApple(alert: .init(body: body))\n        applePayload.body = \"stop\"\n        let encoded = try ParseCoding.parseEncoder().encode(applePayload)\n        let decoded = try ParseCoding.jsonDecoder().decode(ParsePushPayloadApple.self, from: encoded)\n        XCTAssertEqual(applePayload, decoded)\n        let anyEncodablePayload = AnyEncodable(applePayload)\n        let anyEncodablePayload2 = AnyEncodable(decoded)\n        XCTAssertEqual(anyEncodablePayload, anyEncodablePayload2)\n        let value = \"peace\"\n        let dictionary = [anyEncodablePayload: value]\n        XCTAssertEqual(dictionary[anyEncodablePayload2], value)\n    }\n\n    func testAppleAlertStringDecode() throws {\n        let sound = ParsePushAppleSound(critical: true, name: \"hello\", volume: 7)\n        let alert = ParsePushAppleAlert(body: \"pull up\")\n        var applePayload = ParsePushPayloadApple()\n        applePayload.alert = alert\n        applePayload.badge = AnyCodable(1)\n        applePayload.sound = AnyCodable(sound)\n        applePayload.urlArgs = [\"help\"]\n        applePayload.interruptionLevel = \"yolo\"\n        applePayload.topic = \"naw\"\n        applePayload.threadId = \"yep\"\n        applePayload.collapseId = \"nope\"\n        applePayload.pushType = .background\n        applePayload.targetContentId = \"press\"\n        applePayload.relevanceScore = 2.0\n        applePayload.priority = 6\n        applePayload.contentAvailable = 1\n        applePayload.mutableContent = 1\n\n        guard let jsonData = \"{\\\"alert\\\":\\\"pull up\\\",\\\"badge\\\":1,\\\"collapse_id\\\":\\\"nope\\\",\\\"content-available\\\":1,\\\"interruptionLevel\\\":\\\"yolo\\\",\\\"mutable-content\\\":1,\\\"priority\\\":6,\\\"push_type\\\":\\\"background\\\",\\\"relevance-score\\\":2,\\\"sound\\\":{\\\"critical\\\":true,\\\"name\\\":\\\"hello\\\",\\\"volume\\\":7},\\\"targetContentIdentifier\\\":\\\"press\\\",\\\"threadId\\\":\\\"yep\\\",\\\"topic\\\":\\\"naw\\\",\\\"urlArgs\\\":[\\\"help\\\"]}\".data(using: .utf8) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let decodedAlert = try ParseCoding.jsonDecoder().decode(ParsePushPayloadApple.self, from: jsonData)\n        XCTAssertEqual(decodedAlert, applePayload)\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParsePushPayloadFirebaseTests.swift",
    "content": "//\n//  ParsePushPayloadFirebaseTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/12/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\n// swiftlint:disable line_length\n\nclass ParsePushPayloadFirebaseTests: XCTestCase {\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testInitializers() throws {\n        let fcmPayload = ParsePushPayloadFirebase(notification: .init(body: \"Bye FCM\"))\n        XCTAssertEqual(fcmPayload.description, \"{\\\"notification\\\":{\\\"body\\\":\\\"Bye FCM\\\"}}\")\n        let notification = ParsePushFirebaseNotification(title: \"hello\", body: \"new\", image: \"world\")\n        XCTAssertEqual(notification.description, \"{\\\"body\\\":\\\"new\\\",\\\"image\\\":\\\"world\\\",\\\"title\\\":\\\"hello\\\"}\")\n    }\n\n    func testCoding() throws {\n        var notification = ParsePushFirebaseNotification(title: \"hello\", body: \"android\", icon: \"world\")\n        notification.sound = \"yes\"\n        notification.badge = \"no\"\n        notification.androidChannelId = \"you\"\n        notification.bodyLocArgs = [\"mother\"]\n        notification.bodyLocKey = \"cousin\"\n        notification.clickAction = \"to\"\n        notification.image = \"icon\"\n        notification.subtitle = \"trip\"\n        notification.tag = \"it\"\n        notification.color = \"blue\"\n        notification.titleLocArgs = [\"arg\"]\n        notification.titleLocKey = \"it\"\n        var fcmPayload = ParsePushPayloadFirebase(notification: notification)\n        fcmPayload.data = [\"help\": \"you\"]\n        fcmPayload.priority = .high\n        fcmPayload.contentAvailable = true\n        fcmPayload.mutableContent = true\n        fcmPayload.collapseKey = \"nope\"\n        fcmPayload.delayWhileIdle = false\n        fcmPayload.dryRun = false\n        fcmPayload.title = \"peace\"\n        fcmPayload.restrictedPackageName = \"geez\"\n        fcmPayload.uri = URL(string: \"https://parse.org\")\n        let encoded = try ParseCoding.parseEncoder().encode(fcmPayload)\n        let decoded = try ParseCoding.jsonDecoder().decode(ParsePushPayloadFirebase.self, from: encoded)\n        XCTAssertEqual(fcmPayload, decoded)\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        XCTAssertEqual(fcmPayload.description,\n                       \"{\\\"collapseKey\\\":\\\"nope\\\",\\\"contentAvailable\\\":true,\\\"data\\\":{\\\"help\\\":\\\"you\\\"},\\\"delayWhileIdle\\\":false,\\\"dryRun\\\":false,\\\"mutableContent\\\":true,\\\"notification\\\":{\\\"android_channel_id\\\":\\\"you\\\",\\\"badge\\\":\\\"no\\\",\\\"body\\\":\\\"android\\\",\\\"body_loc-key\\\":\\\"cousin\\\",\\\"body-loc-args\\\":[\\\"mother\\\"],\\\"click_action\\\":\\\"to\\\",\\\"color\\\":\\\"blue\\\",\\\"icon\\\":\\\"world\\\",\\\"image\\\":\\\"icon\\\",\\\"sound\\\":\\\"yes\\\",\\\"subtitle\\\":\\\"trip\\\",\\\"tag\\\":\\\"it\\\",\\\"title\\\":\\\"hello\\\",\\\"title_loc_args\\\":[\\\"arg\\\"],\\\"title_loc_key\\\":\\\"it\\\"},\\\"priority\\\":\\\"high\\\",\\\"restrictedPackageName\\\":\\\"geez\\\",\\\"title\\\":\\\"peace\\\",\\\"uri\\\":\\\"https:\\\\/\\\\/parse.org\\\"}\")\n        #endif\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParsePushTests.swift",
    "content": "//\n//  ParsePushTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 6/11/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\n/**\n For testing _PushStatus response of at least Parse Server 5.2.1 and below.\n - warning: This struct should be kept inline with `ParsePushStatus`\n so tests do not break.\n*/\ninternal struct ParsePushStatusResponse: ParseObject {\n\n    var originalData: Data?\n\n    var objectId: String?\n\n    var createdAt: Date?\n\n    var updatedAt: Date?\n\n    var ACL: ParseACL?\n\n    var query: String?\n\n    var pushTime: Date?\n\n    var source: String?\n\n    var payload: String?\n\n    var title: String?\n\n    var expiry: Int?\n\n    var expirationInterval: String?\n\n    var status: String?\n\n    var numSent: Int?\n\n    var numFailed: Int?\n\n    var pushHash: String?\n\n    var errorMessage: ParseError?\n\n    var sentPerType: [String: Int]?\n\n    var failedPerType: [String: Int]?\n\n    var sentPerUTCOffset: [String: Int]?\n\n    var failedPerUTCOffset: [String: Int]?\n\n    var count: Int?\n\n    init() { }\n\n    func setQueryWhere(_ query: QueryWhere) throws -> Self {\n        var mutatingResponse = self\n        let whereData = try ParseCoding.jsonEncoder().encode(query)\n        guard let whereString = String(data: whereData, encoding: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have created String\")\n        }\n        mutatingResponse.query = whereString\n        return mutatingResponse\n    }\n\n    func setPayload<V: ParsePushPayloadable>(_ payload: V) throws -> Self {\n        var mutatingResponse = self\n        let payloadData = try ParseCoding.jsonEncoder().encode(payload)\n        guard let payloadString = String(data: payloadData, encoding: .utf8) else {\n            throw ParseError(code: .unknownError, message: \"Should have created String\")\n        }\n        mutatingResponse.payload = payloadString\n        return mutatingResponse\n    }\n\n    enum CodingKeys: String, CodingKey {\n        case expirationInterval = \"expiration_interval\"\n        case objectId, createdAt, updatedAt, ACL\n        case count, failedPerUTCOffset, sentPerUTCOffset,\n             sentPerType, failedPerType, errorMessage, pushHash,\n             numFailed, numSent, status, expiry, title, source,\n             pushTime, query, payload\n    }\n}\n\nclass ParsePushTests: XCTestCase {\n\n    struct Installation: ParseInstallation {\n        var installationId: String?\n        var deviceType: String?\n        var deviceToken: String?\n        var badge: Int?\n        var timeZone: String?\n        var channels: [String]?\n        var appName: String?\n        var appIdentifier: String?\n        var appVersion: String?\n        var parseVersion: String?\n        var localeIdentifier: String?\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n        var customKey: String?\n\n        //: Implement your own version of merge\n        func merge(with object: Self) throws -> Self {\n            var updated = try mergeParse(with: object)\n            if updated.shouldRestoreKey(\\.customKey,\n                                         original: object) {\n                updated.customKey = object.customKey\n            }\n            return updated\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testInitializers() throws {\n        let applePayload = ParsePushPayloadApple(body: \"Hello from ParseSwift!\")\n        let fcmPayload = ParsePushPayloadFirebase(notification: .init(body: \"Bye FCM\"))\n        let installationQuery = Installation.query(isNotNull(key: \"objectId\"))\n\n        let push = ParsePush(payload: applePayload)\n        XCTAssertEqual(push.debugDescription,\n                       \"{\\\"data\\\":{\\\"alert\\\":{\\\"body\\\":\\\"Hello from ParseSwift!\\\"},\\\"push_type\\\":\\\"alert\\\"}}\")\n        let push2 = ParsePush(payload: applePayload, query: installationQuery)\n        XCTAssertEqual(push2.debugDescription,\n                       // swiftlint:disable:next line_length\n                       \"{\\\"data\\\":{\\\"alert\\\":{\\\"body\\\":\\\"Hello from ParseSwift!\\\"},\\\"push_type\\\":\\\"alert\\\"},\\\"where\\\":{\\\"objectId\\\":{\\\"$ne\\\":null}}}\")\n        let push3 = ParsePush(payload: applePayload, expirationInterval: 7)\n        XCTAssertEqual(push3.debugDescription,\n                       // swiftlint:disable:next line_length\n                       \"{\\\"data\\\":{\\\"alert\\\":{\\\"body\\\":\\\"Hello from ParseSwift!\\\"},\\\"push_type\\\":\\\"alert\\\"},\\\"expiration_interval\\\":7}\")\n        let push4 = ParsePush(payload: fcmPayload)\n        XCTAssertEqual(push4.debugDescription,\n                       \"{\\\"data\\\":{\\\"notification\\\":{\\\"body\\\":\\\"Bye FCM\\\"}}}\")\n        let push5 = ParsePush(payload: fcmPayload, query: installationQuery)\n        XCTAssertEqual(push5.debugDescription,\n                       \"{\\\"data\\\":{\\\"notification\\\":{\\\"body\\\":\\\"Bye FCM\\\"}},\\\"where\\\":{\\\"objectId\\\":{\\\"$ne\\\":null}}}\")\n        let push6 = ParsePush(payload: fcmPayload, query: installationQuery, expirationInterval: 7)\n        XCTAssertEqual(push6.debugDescription,\n                       // swiftlint:disable:next line_length\n                       \"{\\\"data\\\":{\\\"notification\\\":{\\\"body\\\":\\\"Bye FCM\\\"}},\\\"expiration_interval\\\":7,\\\"where\\\":{\\\"objectId\\\":{\\\"$ne\\\":null}}}\")\n    }\n\n    func testChannels() throws {\n        let currentDate = Date()\n        let currentDateInterval = currentDate.timeIntervalSince1970\n        let currentDateData = try ParseCoding.jsonEncoder().encode(currentDateInterval)\n        guard let currentDateString = String(data: currentDateData, encoding: .utf8) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let fcmPayload = ParsePushPayloadFirebase(notification: .init(body: \"Bye FCM\"))\n        var push = ParsePush(payload: fcmPayload, expirationDate: currentDate)\n        push.channels = [\"hello\"]\n        XCTAssertEqual(push.description,\n                       // swiftlint:disable:next line_length\n                       \"{\\\"channels\\\":[\\\"hello\\\"],\\\"data\\\":{\\\"notification\\\":{\\\"body\\\":\\\"Bye FCM\\\"}},\\\"expiration_time\\\":\\(currentDateString)}\")\n        guard let pushDate = push.expirationDate else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertLessThan(pushDate.timeIntervalSince(currentDate), 1)\n        push.expirationTime = nil\n        XCTAssertNil(push.expirationDate)\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseQueryAsyncTests.swift",
    "content": "//\n//  ParseQueryAsyncTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/28/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseQueryAsyncTests: XCTestCase { // swiftlint:disable:this type_body_length\n    struct GameScore: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int?\n        var player: String?\n        init() { }\n        //custom initializers\n        init (objectId: String?) {\n            self.objectId = objectId\n        }\n        init(points: Int) {\n            self.points = points\n            self.player = \"Jen\"\n        }\n        init(points: Int, name: String) {\n            self.points = points\n            self.player = name\n        }\n    }\n\n    struct AnyResultsResponse<U: Codable>: Codable {\n        let results: [U]\n    }\n\n    struct AnyResultsMongoResponse<U: Codable>: Codable {\n        let results: U\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              usingPostForQuery: true,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    @MainActor\n    func testFind() async throws {\n\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.points = 11\n        scoreOnServer.objectId = \"yolo\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query\n\n        let found = try await query.find()\n        guard let object = found.first else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssert(object.hasSameObjectId(as: scoreOnServer))\n    }\n\n    @MainActor\n    func testWithCount() async throws {\n\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.points = 11\n        scoreOnServer.objectId = \"yolo\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query\n\n        let found = try await query.withCount()\n        guard let object = found.0.first else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertTrue(object.hasSameObjectId(as: scoreOnServer))\n        XCTAssertEqual(found.1, 1)\n    }\n\n    @MainActor\n    func testWithCountMissingCount() async throws {\n\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.points = 11\n        scoreOnServer.objectId = \"yolo\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: nil)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query\n\n        let found = try await query.withCount()\n        guard let object = found.0.first else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertTrue(object.hasSameObjectId(as: scoreOnServer))\n        XCTAssertEqual(found.1, 0)\n    }\n\n    @MainActor\n    func testWithCountLimitZero() async throws {\n\n        var query = GameScore.query\n        query.limit = 0\n        let found = try await query.withCount()\n        XCTAssertEqual(found.0.count, 0)\n        XCTAssertEqual(found.1, 0)\n    }\n\n    @MainActor\n    func testFindAll() async throws {\n\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = AnyResultsResponse(results: [scoreOnServer])\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let found = try await GameScore.query.findAll()\n        guard let object = found.first else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssert(object.hasSameObjectId(as: scoreOnServer))\n    }\n\n    @MainActor\n    func testFindExplain() async throws {\n\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let queryResult: [[String: String]] = try await query.findExplain()\n        XCTAssertEqual(queryResult, json.results)\n    }\n\n    @MainActor\n    func testFindExplainMongo() async throws {\n\n        let json = AnyResultsMongoResponse(results: [\"yolo\": \"yarr\"])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let queryResult: [[String: String]] = try await query.findExplain(usingMongoDB: true)\n        XCTAssertEqual(queryResult, [json.results])\n    }\n\n    @MainActor\n    func testWithCountExplain() async throws {\n\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let queryResult: [[String: String]] = try await query.withCountExplain()\n        XCTAssertEqual(queryResult, json.results)\n    }\n\n    @MainActor\n    func testWithCountExplainMongo() async throws {\n\n        let json = AnyResultsMongoResponse(results: [\"yolo\": \"yarr\"])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let queryResult: [[String: String]] = try await query.withCountExplain(usingMongoDB: true)\n        XCTAssertEqual(queryResult, [json.results])\n    }\n\n    @MainActor\n    func testWithCountExplainLimitZero() async throws {\n\n        var query = GameScore.query\n        query.limit = 0\n        let found: [[String: String]] = try await query.withCountExplain()\n        XCTAssertEqual(found.count, 0)\n    }\n\n    @MainActor\n    func testFirst() async throws {\n\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.points = 11\n        scoreOnServer.objectId = \"yolo\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query\n        let found = try await query.first()\n        XCTAssert(found.hasSameObjectId(as: scoreOnServer))\n    }\n\n    @MainActor\n    func testFirstExplain() async throws {\n\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n\n        let queryResult: [String: String] = try await query.firstExplain()\n        XCTAssertEqual(queryResult, json.results.first)\n    }\n\n    @MainActor\n    func testFirstExplainMongo() async throws {\n\n        let json = AnyResultsMongoResponse(results: [\"yolo\": \"yarr\"])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n\n        let queryResult: [String: String] = try await query.firstExplain(usingMongoDB: true)\n        XCTAssertEqual(queryResult, json.results)\n    }\n\n    @MainActor\n    func testCount() async throws {\n\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.points = 11\n        scoreOnServer.objectId = \"yolo\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query\n\n        let found = try await query.count()\n        XCTAssertEqual(found, 1)\n    }\n\n    @MainActor\n    func testCountExplain() async throws {\n\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let queryResult: [[String: String]] = try await query.countExplain()\n        XCTAssertEqual(queryResult, json.results)\n    }\n\n    @MainActor\n    func testCountExplainMongo() async throws {\n\n        let json = AnyResultsMongoResponse(results: [\"yolo\": \"yarr\"])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let queryResult: [[String: String]] = try await query.countExplain(usingMongoDB: true)\n        XCTAssertEqual(queryResult, [json.results])\n    }\n\n    @MainActor\n    func testAggregate() async throws {\n\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query\n        let pipeline = [[String: AnyEncodable]]()\n        let found = try await query.aggregate(pipeline)\n        guard let object = found.first else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssert(object.hasSameObjectId(as: scoreOnServer))\n    }\n\n    @MainActor\n    func testAggregateExplain() async throws {\n\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let pipeline = [[String: String]]()\n        let queryResult: [[String: String]] = try await query.aggregateExplain(pipeline)\n        XCTAssertEqual(queryResult, json.results)\n    }\n\n    @MainActor\n    func testAggregateExplainMongo() async throws {\n\n        let json = AnyResultsMongoResponse(results: [\"yolo\": \"yarr\"])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let pipeline = [[String: String]]()\n        let queryResult: [[String: String]] = try await query.aggregateExplain(pipeline,\n                                                                               usingMongoDB: true)\n        XCTAssertEqual(queryResult, [json.results])\n    }\n\n    @MainActor\n    func testDistinct() async throws {\n\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query\n        let found = try await query.distinct(\"hello\")\n        guard let object = found.first else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssert(object.hasSameObjectId(as: scoreOnServer))\n    }\n\n    @MainActor\n    func testDistinctExplain() async throws {\n\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let queryResult: [[String: String]] = try await query.distinctExplain(\"hello\")\n        XCTAssertEqual(queryResult, json.results)\n    }\n\n    @MainActor\n    func testDistinctExplainMongo() async throws {\n\n        let json = AnyResultsMongoResponse(results: [\"yolo\": \"yarr\"])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let queryResult: [[String: String]] = try await query.distinctExplain(\"hello\",\n                                                                              usingMongoDB: true)\n        XCTAssertEqual(queryResult, [json.results])\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseQueryCacheTests.swift",
    "content": "//\n//  ParseQueryCacheTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 8/4/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\n// swiftlint:disable line_length\n\nclass ParseQueryCacheTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct GameScore: ParseObject, ParseQueryScorable {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var score: Double?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int\n        var isCounts: Bool?\n\n        //: a custom initializer\n        init() {\n            self.points = 5\n        }\n        init(points: Int) {\n            self.points = points\n        }\n    }\n\n    struct GameScoreBroken: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        var points: Int?\n    }\n\n    struct AnyResultsResponse<U: Codable>: Codable {\n        let results: [U]\n    }\n\n    struct AnyResultsMongoResponse<U: Codable>: Codable {\n        let results: U\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              usingEqualQueryConstraint: false,\n                              usingPostForQuery: false,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        ParseSwift.clearCache()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testQueryParameters() throws {\n        let query = GameScore.query\n            .order([.ascending(\"points\"), .descending(\"oldScore\")])\n            .exclude(\"hello\", \"world\")\n            .include(\"foo\", \"bar\")\n            .select(\"yolo\", \"nolo\")\n            .hint(\"right\")\n            .readPreference(\"now\")\n\n        let queryParameters = try query.getQueryParameters()\n        guard let whereParameter = queryParameters[\"where\"],\n            let orderParameter = queryParameters[\"order\"],\n            let skipParameter = queryParameters[\"skip\"],\n            let excludeKeysParameter = queryParameters[\"excludeKeys\"],\n            let limitParameter = queryParameters[\"limit\"],\n            let keysParameter = queryParameters[\"keys\"],\n            let includeParameter = queryParameters[\"include\"],\n            let hintParameter = queryParameters[\"hint\"],\n            let readPreferenceParameter = queryParameters[\"readPreference\"] else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertTrue(whereParameter.contains(\"{}\"))\n        XCTAssertTrue(orderParameter.contains(\"\\\"points\"))\n        XCTAssertTrue(orderParameter.contains(\"\\\"-oldScore\"))\n        XCTAssertTrue(skipParameter.contains(\"0\"))\n        XCTAssertTrue(excludeKeysParameter.contains(\"\\\"hello\"))\n        XCTAssertTrue(excludeKeysParameter.contains(\"\\\"world\"))\n        XCTAssertTrue(limitParameter.contains(\"100\"))\n        XCTAssertTrue(keysParameter.contains(\"\\\"nolo\"))\n        XCTAssertTrue(keysParameter.contains(\"\\\"yolo\"))\n        XCTAssertTrue(includeParameter.contains(\"\\\"foo\\\"\"))\n        XCTAssertTrue(includeParameter.contains(\"\\\"bar\\\"\"))\n        XCTAssertTrue(hintParameter.contains(\"\\\"right\\\"\"))\n        XCTAssertTrue(readPreferenceParameter.contains(\"\\\"now\\\"\"))\n    }\n\n    func testAggregateQueryParameters() throws {\n        var query = GameScore.query\n            .order([.ascending(\"points\"), .descending(\"oldScore\")])\n            .exclude(\"hello\", \"world\")\n            .include(\"foo\", \"bar\")\n            .select(\"yolo\", \"nolo\")\n            .hint(\"right\")\n\n        query.includeReadPreference = \"now\"\n        query.explain = true\n        query.pipeline = [[\"yo\": \"no\"]]\n\n        let aggregate = Query<GameScore>.AggregateBody(query: query)\n\n        let queryParameters = try aggregate.getQueryParameters()\n        guard let explainParameter = queryParameters[\"explain\"],\n            let pipelineParameter = queryParameters[\"pipeline\"],\n            let hintParameter = queryParameters[\"hint\"],\n            let readPreferenceParameter = queryParameters[\"includeReadPreference\"] else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertTrue(explainParameter.contains(\"true\"))\n        XCTAssertTrue(pipelineParameter.contains(\"\\\"yo\"))\n        XCTAssertTrue(pipelineParameter.contains(\"\\\"no\"))\n        XCTAssertTrue(hintParameter.contains(\"\\\"right\\\"\"))\n        XCTAssertTrue(readPreferenceParameter.contains(\"\\\"now\\\"\"))\n    }\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\n    @MainActor\n    func testFind() async throws {\n\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.points = 11\n        scoreOnServer.objectId = \"yolo\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query\n\n        let found = try await query.find()\n        guard let object = found.first else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssert(object.hasSameObjectId(as: scoreOnServer))\n    }\n\n    @MainActor\n    func testWithCount() async throws {\n\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.points = 11\n        scoreOnServer.objectId = \"yolo\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query\n\n        let found = try await query.withCount()\n        guard let object = found.0.first else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertTrue(object.hasSameObjectId(as: scoreOnServer))\n        XCTAssertEqual(found.1, 1)\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let found2 = try await query.withCount(options: [.cachePolicy(.returnCacheDataDontLoad)])\n        guard let object2 = found2.0.first else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertTrue(object2.hasSameObjectId(as: scoreOnServer))\n        XCTAssertEqual(found2.1, 1)\n    }\n\n    @MainActor\n    func testWithCountMissingCount() async throws {\n\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.points = 11\n        scoreOnServer.objectId = \"yolo\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: nil)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query\n\n        let found = try await query.withCount()\n        guard let object = found.0.first else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertTrue(object.hasSameObjectId(as: scoreOnServer))\n        XCTAssertEqual(found.1, 0)\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let found2 = try await query.withCount(options: [.cachePolicy(.returnCacheDataDontLoad)])\n        guard let object2 = found2.0.first else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertTrue(object2.hasSameObjectId(as: scoreOnServer))\n        XCTAssertEqual(found2.1, 0)\n    }\n\n    @MainActor\n    func testFindAll() async throws {\n\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = AnyResultsResponse(results: [scoreOnServer])\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let found = try await GameScore.query.findAll()\n        guard let object = found.first else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssert(object.hasSameObjectId(as: scoreOnServer))\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let found2 = try await GameScore.query.findAll(options: [.cachePolicy(.returnCacheDataDontLoad)])\n        guard let object2 = found2.first else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssert(object2.hasSameObjectId(as: scoreOnServer))\n    }\n\n    @MainActor\n    func testFindExplain() async throws {\n\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let queryResult: [[String: String]] = try await query.findExplain()\n        XCTAssertEqual(queryResult, json.results)\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let queryResult2: [[String: String]] = try await query.findExplain(options: [.cachePolicy(.returnCacheDataDontLoad)])\n        XCTAssertEqual(queryResult2, json.results)\n    }\n\n    @MainActor\n    func testFindExplainMongo() async throws {\n\n        let json = AnyResultsMongoResponse(results: [\"yolo\": \"yarr\"])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let queryResult: [[String: String]] = try await query.findExplain(usingMongoDB: true)\n        XCTAssertEqual(queryResult, [json.results])\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let queryResult2: [[String: String]] = try await query.findExplain(usingMongoDB: true,\n                                                                           options: [.cachePolicy(.returnCacheDataDontLoad)])\n        XCTAssertEqual(queryResult2, [json.results])\n    }\n\n    @MainActor\n    func testWithCountExplain() async throws {\n\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let queryResult: [[String: String]] = try await query.withCountExplain()\n        XCTAssertEqual(queryResult, json.results)\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let queryResult2: [[String: String]] = try await query.withCountExplain(options: [.cachePolicy(.returnCacheDataDontLoad)])\n        XCTAssertEqual(queryResult2, json.results)\n    }\n\n    @MainActor\n    func testWithCountExplainMongo() async throws {\n\n        let json = AnyResultsMongoResponse(results: [\"yolo\": \"yarr\"])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let queryResult: [[String: String]] = try await query.withCountExplain(usingMongoDB: true)\n        XCTAssertEqual(queryResult, [json.results])\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let queryResult2: [[String: String]] = try await query.withCountExplain(usingMongoDB: true,\n                                                                                options: [.cachePolicy(.returnCacheDataDontLoad)])\n        XCTAssertEqual(queryResult2, [json.results])\n    }\n\n    @MainActor\n    func testFirst() async throws {\n\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.points = 11\n        scoreOnServer.objectId = \"yolo\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query\n        let found = try await query.first()\n        XCTAssert(found.hasSameObjectId(as: scoreOnServer))\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let found2 = try await query.first(options: [.cachePolicy(.returnCacheDataDontLoad)])\n        XCTAssert(found2.hasSameObjectId(as: scoreOnServer))\n    }\n\n    @MainActor\n    func testFirstExplain() async throws {\n\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let queryResult: [String: String] = try await query.firstExplain()\n        XCTAssertEqual(queryResult, json.results.first)\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let queryResult2: [String: String] = try await query.firstExplain(options: [.cachePolicy(.returnCacheDataDontLoad)])\n        XCTAssertEqual(queryResult2, json.results.first)\n    }\n\n    @MainActor\n    func testFirstExplainMongo() async throws {\n\n        let json = AnyResultsMongoResponse(results: [\"yolo\": \"yarr\"])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let queryResult: [String: String] = try await query.firstExplain(usingMongoDB: true)\n        XCTAssertEqual(queryResult, json.results)\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let queryResult2: [String: String] = try await query.firstExplain(usingMongoDB: true,\n                                                                          options: [.cachePolicy(.returnCacheDataDontLoad)])\n        XCTAssertEqual(queryResult2, json.results)\n    }\n\n    @MainActor\n    func testCount() async throws {\n\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.points = 11\n        scoreOnServer.objectId = \"yolo\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query\n        let found = try await query.count()\n        XCTAssertEqual(found, 1)\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let found2 = try await query.count(options: [.cachePolicy(.returnCacheDataDontLoad)])\n        XCTAssertEqual(found2, 1)\n    }\n\n    @MainActor\n    func testCountExplain() async throws {\n\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let queryResult: [[String: String]] = try await query.countExplain()\n        XCTAssertEqual(queryResult, json.results)\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let queryResult2: [[String: String]] = try await query.countExplain(options: [.cachePolicy(.returnCacheDataDontLoad)])\n        XCTAssertEqual(queryResult2, json.results)\n    }\n\n    @MainActor\n    func testCountExplainMongo() async throws {\n\n        let json = AnyResultsMongoResponse(results: [\"yolo\": \"yarr\"])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let queryResult: [[String: String]] = try await query.countExplain(usingMongoDB: true)\n        XCTAssertEqual(queryResult, [json.results])\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let queryResult2: [[String: String]] = try await query.countExplain(usingMongoDB: true,\n                                                                            options: [.cachePolicy(.returnCacheDataDontLoad)])\n        XCTAssertEqual(queryResult2, [json.results])\n    }\n\n    @MainActor\n    func testAggregate() async throws {\n\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query\n        let pipeline = [[String: AnyEncodable]]()\n        let found = try await query.aggregate(pipeline)\n        guard let object = found.first else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssert(object.hasSameObjectId(as: scoreOnServer))\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let found2 = try await query.aggregate(pipeline,\n                                               options: [.cachePolicy(.returnCacheDataDontLoad)])\n        guard let object2 = found2.first else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssert(object2.hasSameObjectId(as: scoreOnServer))\n    }\n\n    @MainActor\n    func testAggregateExplain() async throws {\n\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let pipeline = [[String: String]]()\n        let queryResult: [[String: String]] = try await query.aggregateExplain(pipeline)\n        XCTAssertEqual(queryResult, json.results)\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let queryResult2: [[String: String]] = try await query.aggregateExplain(pipeline,\n                                                                                options: [.cachePolicy(.returnCacheDataDontLoad)])\n        XCTAssertEqual(queryResult2, json.results)\n    }\n\n    @MainActor\n    func testAggregateExplainMongo() async throws {\n\n        let json = AnyResultsMongoResponse(results: [\"yolo\": \"yarr\"])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let pipeline = [[String: String]]()\n        let queryResult: [[String: String]] = try await query.aggregateExplain(pipeline,\n                                                                               usingMongoDB: true)\n        XCTAssertEqual(queryResult, [json.results])\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let queryResult2: [[String: String]] = try await query.aggregateExplain(pipeline,\n                                                                                usingMongoDB: true,\n                                                                                options: [.cachePolicy(.returnCacheDataDontLoad)])\n        XCTAssertEqual(queryResult2, [json.results])\n    }\n\n    @MainActor\n    func testDistinct() async throws {\n\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query\n        let found = try await query.distinct(\"hello\")\n        guard let object = found.first else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssert(object.hasSameObjectId(as: scoreOnServer))\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let found2 = try await query.distinct(\"hello\",\n                                              options: [.cachePolicy(.returnCacheDataDontLoad)])\n        guard let object2 = found2.first else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssert(object2.hasSameObjectId(as: scoreOnServer))\n    }\n\n    @MainActor\n    func testDistinctExplain() async throws {\n\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let queryResult: [[String: String]] = try await query.distinctExplain(\"hello\")\n        XCTAssertEqual(queryResult, json.results)\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let queryResult2: [[String: String]] = try await query.distinctExplain(\"hello\",\n                                                                               options: [.cachePolicy(.returnCacheDataDontLoad)])\n        XCTAssertEqual(queryResult2, json.results)\n    }\n\n    @MainActor\n    func testDistinctExplainMongo() async throws {\n\n        let json = AnyResultsMongoResponse(results: [\"yolo\": \"yarr\"])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let queryResult: [[String: String]] = try await query.distinctExplain(\"hello\",\n                                                                              usingMongoDB: true)\n        XCTAssertEqual(queryResult, [json.results])\n\n        // Remove URL mocker so we can check cache\n        MockURLProtocol.removeAll()\n        let queryResult2: [[String: String]] = try await query.distinctExplain(\"hello\",\n                                                                               usingMongoDB: true,\n                                                                               options: [.cachePolicy(.returnCacheDataDontLoad)])\n        XCTAssertEqual(queryResult2, [json.results])\n    }\n#endif\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseQueryCombineTests.swift",
    "content": "//\n//  ParseQueryCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/30/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseQueryCombineTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct GameScore: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int?\n        var player: String?\n\n        //custom initializers\n        init() {}\n\n        init (objectId: String?) {\n            self.objectId = objectId\n        }\n        init(points: Int) {\n            self.points = points\n            self.player = \"Jen\"\n        }\n        init(points: Int, name: String) {\n            self.points = points\n            self.player = name\n        }\n    }\n\n    struct AnyResultsResponse<U: Codable>: Codable {\n        let results: [U]\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              usingPostForQuery: true,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testFind() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Find\")\n\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.points = 11\n        scoreOnServer.objectId = \"yolo\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query\n\n        let publisher = query.findPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { found in\n\n            guard let object = found.first else {\n                XCTFail(\"Should have unwrapped\")\n                return\n            }\n            XCTAssert(object.hasSameObjectId(as: scoreOnServer))\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testWithCount() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Find\")\n\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.points = 11\n        scoreOnServer.objectId = \"yolo\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query\n\n        let publisher = query.withCountPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { found in\n\n            guard let object = found.0.first else {\n                XCTFail(\"Should have unwrapped\")\n                return\n            }\n            XCTAssert(object.hasSameObjectId(as: scoreOnServer))\n            XCTAssertEqual(found.1, 1)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testFindAll() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"FindAll\")\n\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = AnyResultsResponse(results: [scoreOnServer])\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let query = GameScore.query\n        let publisher = query.findAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { found in\n\n            guard let object = found.first else {\n                XCTFail(\"Should have unwrapped\")\n                return\n            }\n            XCTAssert(object.hasSameObjectId(as: scoreOnServer))\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testFindExplain() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n\n        let publisher = query.findExplainPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n            }, receiveValue: { (queryResult: [[String: String]]) in\n                XCTAssertEqual(queryResult, json.results)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testWithCountExplain() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n\n        let publisher = query.withCountExplainPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n            }, receiveValue: { (queryResult: [[String: String]]) in\n                XCTAssertEqual(queryResult, json.results)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testFirst() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.points = 11\n        scoreOnServer.objectId = \"yolo\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query\n\n        let publisher = query.firstPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { found in\n\n            XCTAssert(found.hasSameObjectId(as: scoreOnServer))\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testFirstExplain() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n\n        let publisher = query.firstExplainPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n            }, receiveValue: { (queryResult: [String: String]) in\n                XCTAssertEqual(queryResult, json.results.first)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testCount() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.points = 11\n        scoreOnServer.objectId = \"yolo\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query\n\n        let publisher = query.countPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { found in\n\n            XCTAssertEqual(found, 1)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testCountExplain() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n\n        let publisher = query.countExplainPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n            }, receiveValue: { (queryResult: [[String: String]]) in\n                XCTAssertEqual(queryResult, json.results)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testAggregate() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query\n        let pipeline = [[String: AnyEncodable]]()\n        let publisher = query.aggregatePublisher(pipeline)\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { found in\n\n            guard let object = found.first else {\n                XCTFail(\"Should have unwrapped\")\n                return\n            }\n            XCTAssert(object.hasSameObjectId(as: scoreOnServer))\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testAggregateExplain() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let pipeline = [[String: String]]()\n        let publisher = query.aggregateExplainPublisher(pipeline)\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n            }, receiveValue: { (queryResult: [[String: String]]) in\n                XCTAssertEqual(queryResult, json.results)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDistinct() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query\n        let publisher = query.distinctPublisher(\"hello\")\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { found in\n\n            guard let object = found.first else {\n                XCTFail(\"Should have unwrapped\")\n                return\n            }\n            XCTAssert(object.hasSameObjectId(as: scoreOnServer))\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDistinctExplain() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query\n        let publisher = query.distinctExplainPublisher(\"hello\")\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n            }, receiveValue: { (queryResult: [[String: String]]) in\n                XCTAssertEqual(queryResult, json.results)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseQueryTests.swift",
    "content": "//\n//  ParseQueryTests.swift\n//  ParseSwiftTests\n//\n//  Created by Corey Baker on 7/26/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseQueryTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct GameScore: ParseObject, ParseQueryScorable {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var score: Double?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int\n        var isCounts: Bool?\n\n        //: a custom initializer\n        init() {\n            self.points = 5\n        }\n        init(points: Int) {\n            self.points = points\n        }\n    }\n\n    struct GameScoreBroken: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        var points: Int?\n    }\n\n    struct AnyResultsResponse<U: Codable>: Codable {\n        let results: [U]\n    }\n\n    struct AnyResultsMongoResponse<U: Codable>: Codable {\n        let results: U\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              usingEqualQueryConstraint: false,\n                              usingPostForQuery: true,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    // MARK: Initialization\n    func testConstructors() {\n        let query = Query<GameScore>()\n        XCTAssertEqual(query.className, GameScore.className)\n        XCTAssertEqual(query.`where`.constraints.values.count, 0)\n\n        let query2 = GameScore.query()\n        XCTAssertEqual(query2.className, GameScore.className)\n        XCTAssertEqual(query2.className, query.className)\n        XCTAssertEqual(query2.`where`.constraints.values.count, 0)\n\n        let query3 = GameScore.query(\"points\" > 100, \"createdAt\" > Date())\n        XCTAssertEqual(query3.className, GameScore.className)\n        XCTAssertEqual(query3.className, query.className)\n        XCTAssertEqual(query3.`where`.constraints.values.count, 2)\n\n        let query4 = GameScore.query([\"points\" > 100, \"createdAt\" > Date()])\n        XCTAssertEqual(query4.className, GameScore.className)\n        XCTAssertEqual(query4.className, query.className)\n        XCTAssertEqual(query4.`where`.constraints.values.count, 2)\n\n        let query5 = GameScore.query\n        XCTAssertEqual(query5.className, GameScore.className)\n        XCTAssertEqual(query5.className, query.className)\n        XCTAssertEqual(query5.`where`.constraints.values.count, 0)\n    }\n\n    func testDecodingQueryArrays() throws {\n        let query = GameScore.query\n            .order([.ascending(\"points\"), .descending(\"oldScore\")])\n            .exclude(\"hello\", \"world\")\n            .include(\"foo\", \"bar\")\n            .select(\"yolo\", \"nolo\")\n        // swiftlint:disable:next line_length\n        guard let encoded1 = \"{\\\"_method\\\":\\\"GET\\\",\\\"excludeKeys\\\":[\\\"hello\\\",\\\"world\\\"],\\\"include\\\":[\\\"foo\\\",\\\"bar\\\"],\\\"keys\\\":[\\\"yolo\\\",\\\"nolo\\\"],\\\"limit\\\":100,\\\"order\\\":[\\\"points\\\",\\\"-oldScore\\\"],\\\"skip\\\":0,\\\"where\\\":{}}\".data(using: .utf8) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let decoded1 = try ParseCoding.jsonDecoder().decode(Query<GameScore>.self, from: encoded1)\n        XCTAssertEqual(query, decoded1)\n        // swiftlint:disable:next line_length\n        guard let encoded2 = \"{\\\"_method\\\":\\\"GET\\\",\\\"excludeKeys\\\":\\\"hello,world\\\",\\\"include\\\":\\\"foo,bar\\\",\\\"keys\\\":\\\"yolo,nolo\\\",\\\"limit\\\":100,\\\"order\\\":\\\"points,-oldScore\\\",\\\"skip\\\":0,\\\"where\\\":{}}\".data(using: .utf8) else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let decoded2 = try ParseCoding.jsonDecoder().decode(Query<GameScore>.self, from: encoded2)\n        XCTAssertEqual(query, decoded2)\n    }\n\n    func testCompareQueries() {\n\n        let query1 = GameScore.query(\"points\" > 100, \"createdAt\" > Date())\n        let query2 = GameScore.query([containsString(key: \"hello\",\n                                                     substring: \"world\"),\n                                      \"points\" > 100,\n                                      \"createdAt\" > Date()])\n        let query3 = GameScore.query([containsString(key: \"hello\",\n                                                     substring: \"world\"),\n                                      \"points\" > 101,\n                                      \"createdAt\" > Date()])\n        let query4 = GameScore.query([containsString(key: \"hello\",\n                                                     substring: \"world\"),\n                                      \"points\" > 101,\n                                      \"createdAt\" > Date(),\n                                      isNull(key: \"points\")])\n        let query5 = GameScore.query(isNull(key: \"points\"))\n        let query6 = GameScore.query(isNull(key: \"hello\"))\n        XCTAssertEqual(query1, query1)\n        XCTAssertEqual(query2, query2)\n        XCTAssertNotEqual(query1, query2)\n        XCTAssertNotEqual(query2, query3)\n        XCTAssertNotEqual(query3, query4)\n        XCTAssertEqual(query5, query5)\n        XCTAssertNotEqual(query5, query6)\n    }\n\n    func testEndPoints() {\n        let query = Query<GameScore>()\n        let userQuery = Query<BaseParseUser>()\n        let installationQuery = Query<BaseParseInstallation>()\n        XCTAssertEqual(query.endpoint.urlComponent, \"/classes/GameScore\")\n        XCTAssertEqual(userQuery.endpoint.urlComponent, \"/users\")\n        XCTAssertEqual(installationQuery.endpoint.urlComponent, \"/installations\")\n    }\n\n    func testStaticProperties() {\n        XCTAssertEqual(Query<GameScore>.className, GameScore.className)\n    }\n\n    func testSkip() {\n        let query = GameScore.query\n        XCTAssertEqual(query.skip, 0)\n        let query2 = GameScore.query.skip(1)\n        XCTAssertEqual(query2.skip, 1)\n    }\n\n    func testLimit() {\n        var query = GameScore.query\n        XCTAssertEqual(query.limit, 100)\n        query = query.limit(10)\n        XCTAssertEqual(query.limit, 10)\n    }\n\n    func testOrder() {\n        let query = GameScore.query\n        XCTAssertNil(query.order)\n        let query2 = GameScore.query.order(.ascending(\"yolo\"))\n        XCTAssertNotNil(query2.order)\n    }\n\n    func testReadPreferences() {\n        let query = GameScore.query\n        XCTAssertNil(query.readPreference)\n        XCTAssertNil(query.includeReadPreference)\n        XCTAssertNil(query.subqueryReadPreference)\n        let query2 = GameScore.query.readPreference(\"PRIMARY\",\n                                                      includeReadPreference: \"SECONDARY\",\n                                                      subqueryReadPreference: \"SECONDARY_PREFERRED\")\n        XCTAssertNotNil(query2.readPreference)\n        XCTAssertNotNil(query2.includeReadPreference)\n        XCTAssertNotNil(query2.subqueryReadPreference)\n    }\n\n    func testIncludeKeys() {\n        let query = GameScore.query\n        XCTAssertNil(query.include)\n        var query2 = GameScore.query.include([\"yolo\"])\n        XCTAssertEqual(query2.include?.count, 1)\n        XCTAssertEqual(query2.include?.first, \"yolo\")\n        query2 = query2.include([\"hello\", \"wow\"])\n        XCTAssertEqual(query2.include?.count, 3)\n        XCTAssertEqual(query2.include, Set([\"yolo\", \"hello\", \"wow\"]))\n    }\n\n    func testIncludeKeysVariadic() {\n        let query = GameScore.query\n        XCTAssertNil(query.include)\n        var query2 = GameScore.query.include(\"yolo\")\n        XCTAssertEqual(query2.include?.count, 1)\n        XCTAssertEqual(query2.include?.first, \"yolo\")\n        query2 = query2.include(\"hello\", \"wow\")\n        XCTAssertEqual(query2.include?.count, 3)\n        XCTAssertEqual(query2.include, Set([\"yolo\", \"hello\", \"wow\"]))\n    }\n\n    func testIncludeAllKeys() {\n        let query = GameScore.query\n        XCTAssertNil(query.include)\n        let query2 = GameScore.query.includeAll()\n        XCTAssertEqual(query2.include?.count, 1)\n        XCTAssertEqual(query2.include, [\"*\"])\n        let query3 = GameScore.query\n            .include(\"hello\")\n            .includeAll()\n        XCTAssertEqual(query3.include?.count, 2)\n        XCTAssertEqual(query3.include, Set([\"hello\", \"*\"]))\n    }\n\n    func testExcludeKeys() throws {\n        let query = GameScore.query\n        XCTAssertNil(query.excludeKeys)\n        var query2 = GameScore.query.exclude([\"yolo\"])\n        XCTAssertEqual(query2.excludeKeys, [\"yolo\"])\n        let encoded = try ParseCoding.jsonEncoder().encode(query2)\n        let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n        guard let decodedKeys = decodedDictionary[\"excludeKeys\"],\n            let decodedValues = decodedKeys.value as? [String] else {\n            XCTFail(\"Should have casted\")\n            return\n        }\n        XCTAssertEqual(decodedValues, [\"yolo\"])\n\n        query2 = query2.exclude([\"hello\", \"wow\"])\n        XCTAssertEqual(query2.excludeKeys, [\"yolo\", \"hello\", \"wow\"])\n        let encoded2 = try ParseCoding.jsonEncoder().encode(query2)\n        let decodedDictionary2 = try JSONDecoder().decode([String: AnyCodable].self, from: encoded2)\n        guard let decodedKeys2 = decodedDictionary2[\"excludeKeys\"],\n            let decodedValues2 = decodedKeys2.value as? [String] else {\n            XCTFail(\"Should have casted\")\n            return\n        }\n        XCTAssertEqual(Set(decodedValues2), Set([\"yolo\", \"hello\", \"wow\"]))\n    }\n\n    func testExcludeKeysVariadic() throws {\n        let query = GameScore.query\n        XCTAssertNil(query.excludeKeys)\n        var query2 = GameScore.query.exclude(\"yolo\")\n        XCTAssertEqual(query2.excludeKeys, [\"yolo\"])\n        let encoded = try ParseCoding.jsonEncoder().encode(query2)\n        let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n        guard let decodedKeys = decodedDictionary[\"excludeKeys\"],\n            let decodedValues = decodedKeys.value as? [String] else {\n            XCTFail(\"Should have casted\")\n            return\n        }\n        XCTAssertEqual(decodedValues, [\"yolo\"])\n\n        query2 = query2.exclude(\"hello\", \"wow\")\n        XCTAssertEqual(query2.excludeKeys, [\"yolo\", \"hello\", \"wow\"])\n        let encoded2 = try ParseCoding.jsonEncoder().encode(query2)\n        let decodedDictionary2 = try JSONDecoder().decode([String: AnyCodable].self, from: encoded2)\n        guard let decodedKeys2 = decodedDictionary2[\"excludeKeys\"],\n            let decodedValues2 = decodedKeys2.value as? [String] else {\n            XCTFail(\"Should have casted\")\n            return\n        }\n        XCTAssertEqual(Set(decodedValues2), Set([\"yolo\", \"hello\", \"wow\"]))\n    }\n\n    func testSelectKeys() throws {\n        let query = GameScore.query\n        XCTAssertNil(query.keys)\n\n        var query2 = GameScore.query.select([\"yolo\"])\n        XCTAssertEqual(query2.keys?.count, 1)\n        XCTAssertEqual(query2.keys?.first, \"yolo\")\n        let encoded = try ParseCoding.jsonEncoder().encode(query2)\n        let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n        guard let decodedKeys = decodedDictionary[\"keys\"],\n            let decodedValues = decodedKeys.value as? [String] else {\n            XCTFail(\"Should have casted\")\n            return\n        }\n        XCTAssertEqual(decodedValues, [\"yolo\"])\n\n        query2 = query2.select([\"hello\", \"wow\"])\n        XCTAssertEqual(query2.keys?.count, 3)\n        XCTAssertEqual(query2.keys, [\"yolo\", \"hello\", \"wow\"])\n        let encoded2 = try ParseCoding.jsonEncoder().encode(query2)\n        let decodedDictionary2 = try JSONDecoder().decode([String: AnyCodable].self, from: encoded2)\n        guard let decodedKeys2 = decodedDictionary2[\"keys\"],\n            let decodedValues2 = decodedKeys2.value as? [String] else {\n            XCTFail(\"Should have casted\")\n            return\n        }\n        XCTAssertEqual(Set(decodedValues2), Set([\"yolo\", \"hello\", \"wow\"]))\n    }\n\n    func testSelectKeysVariadic() throws {\n        let query = GameScore.query\n        XCTAssertNil(query.keys)\n\n        var query2 = GameScore.query.select(\"yolo\")\n        XCTAssertEqual(query2.keys?.count, 1)\n        XCTAssertEqual(query2.keys?.first, \"yolo\")\n        let encoded = try ParseCoding.jsonEncoder().encode(query2)\n        let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n        guard let decodedKeys = decodedDictionary[\"keys\"],\n            let decodedValues = decodedKeys.value as? [String] else {\n            XCTFail(\"Should have casted\")\n            return\n        }\n        XCTAssertEqual(decodedValues, [\"yolo\"])\n\n        query2 = query2.select(\"hello\", \"wow\")\n        XCTAssertEqual(query2.keys?.count, 3)\n        XCTAssertEqual(query2.keys, [\"yolo\", \"hello\", \"wow\"])\n        let encoded2 = try ParseCoding.jsonEncoder().encode(query2)\n        let decodedDictionary2 = try JSONDecoder().decode([String: AnyCodable].self, from: encoded2)\n        guard let decodedKeys2 = decodedDictionary2[\"keys\"],\n            let decodedValues2 = decodedKeys2.value as? [String] else {\n            XCTFail(\"Should have casted\")\n            return\n        }\n        XCTAssertEqual(Set(decodedValues2), Set([\"yolo\", \"hello\", \"wow\"]))\n    }\n\n    func testSortByTextScore() throws {\n        let query = GameScore.query\n        XCTAssertNil(query.keys)\n\n        let expectedOrder = Query<GameScore>.Order.ascending(\"$score\")\n        var query2 = GameScore.query.sortByTextScore()\n        XCTAssertEqual(query2.keys?.count, 1)\n        XCTAssertEqual(query2.keys?.first, \"$score\")\n        XCTAssertEqual(query2.order?.first, expectedOrder)\n        let encoded = try ParseCoding.jsonEncoder().encode(query2)\n        let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n        guard let decodedKeys = decodedDictionary[\"keys\"],\n            let decodedValues = decodedKeys.value as? [String],\n            let decodedOrder = decodedDictionary[\"order\"],\n            let decodedOrderValue = decodedOrder.value as? [String] else {\n            XCTFail(\"Should have casted\")\n            return\n        }\n        XCTAssertEqual(decodedValues, [\"$score\"])\n        XCTAssertEqual(decodedOrderValue, [\"$score\"])\n\n        query2 = query2.select([\"hello\", \"wow\"])\n        XCTAssertEqual(query2.keys?.count, 3)\n        XCTAssertEqual(query2.keys, [\"$score\", \"hello\", \"wow\"])\n        let encoded2 = try ParseCoding.jsonEncoder().encode(query2)\n        let decodedDictionary2 = try JSONDecoder().decode([String: AnyCodable].self, from: encoded2)\n        guard let decodedKeys2 = decodedDictionary2[\"keys\"],\n            let decodedValues2 = decodedKeys2.value as? [String] else {\n            XCTFail(\"Should have casted\")\n            return\n        }\n        XCTAssertEqual(Set(decodedValues2), Set([\"$score\", \"hello\", \"wow\"]))\n\n        query2 = query2.sortByTextScore()\n        XCTAssertEqual(query2.keys?.count, 3)\n        XCTAssertEqual(query2.keys, [\"$score\", \"hello\", \"wow\"])\n        let encoded3 = try ParseCoding.jsonEncoder().encode(query2)\n        let decodedDictionary3 = try JSONDecoder().decode([String: AnyCodable].self, from: encoded3)\n        guard let decodedKeys3 = decodedDictionary3[\"keys\"],\n            let decodedValues3 = decodedKeys3.value as? [String] else {\n            XCTFail(\"Should have casted\")\n            return\n        }\n        XCTAssertEqual(Set(decodedValues3), Set([\"$score\", \"hello\", \"wow\"]))\n    }\n\n    func testAddingConstraints() {\n        var query = GameScore.query\n        XCTAssertEqual(query.className, GameScore.className)\n        XCTAssertEqual(query.className, query.className)\n        XCTAssertEqual(query.`where`.constraints.values.count, 0)\n\n        query = query.`where`(\"points\" > 100, \"createdAt\" > Date())\n        XCTAssertEqual(query.`where`.constraints.values.count, 2)\n    }\n\n    func testFindCommand() throws {\n        let query = GameScore.query\n        let command = try query.findCommand()\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"body\\\":{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{}},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"\\\\/classes\\\\/GameScore\\\"}\"\n        let encoded = try ParseCoding.jsonEncoder()\n            .encode(command)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testQueryEncoding() throws {\n        let query = GameScore.query\n        let expected = \"{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{}}\"\n        XCTAssertEqual(query.debugDescription, expected)\n        XCTAssertEqual(query.description, expected)\n    }\n\n    func testFindExplainCommand() throws {\n        let query = GameScore.query()\n        let command: API.NonParseBodyCommand<Query<ParseQueryTests.GameScore>,\n                                             [GameScore]> = try query.findExplainCommand()\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"body\\\":{\\\"_method\\\":\\\"GET\\\",\\\"explain\\\":true,\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{}},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"\\\\/classes\\\\/GameScore\\\"}\"\n        let encoded = try ParseCoding.jsonEncoder()\n            .encode(command)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    // MARK: Querying Parse Server\n    func testFind() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query()\n        do {\n\n            guard let score = try query.find(options: []).first else {\n                XCTFail(\"Should unwrap first object found\")\n                return\n            }\n            XCTAssert(score.hasSameObjectId(as: scoreOnServer))\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n    }\n\n    func testFindLimit() {\n        let query = GameScore.query()\n            .limit(0)\n        do {\n            let scores = try query.find(options: [])\n            XCTAssert(scores.isEmpty)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    // MARK: Querying Parse Server\n    func testFindEncoded() throws {\n\n        let afterDate = Date().addingTimeInterval(-300)\n        let query = GameScore.query(\"createdAt\" > afterDate)\n        let encodedJSON = try ParseCoding.jsonEncoder().encode(query)\n        let decodedJSON = try ParseCoding.jsonDecoder().decode([String: AnyCodable].self, from: encodedJSON)\n        let encodedParse = try ParseCoding.jsonEncoder().encode(query)\n        let decodedParse = try ParseCoding.jsonDecoder().decode([String: AnyCodable].self, from: encodedParse)\n\n        guard let jsonSkipAny = decodedJSON[\"skip\"],\n              let jsonSkip = jsonSkipAny.value as? Int,\n              let jsonMethodAny = decodedJSON[\"_method\"],\n              let jsonMethod = jsonMethodAny.value as? String,\n              let jsonLimitAny = decodedJSON[\"limit\"],\n              let jsonLimit = jsonLimitAny.value as? Int,\n              let jsonWhereAny = decodedJSON[\"where\"],\n              let jsonWhere = jsonWhereAny.value as? [String: [String: [String: String]]] else {\n            XCTFail(\"Should have casted all\")\n            return\n        }\n\n        guard let parseSkipAny = decodedParse[\"skip\"],\n              let parseSkip = parseSkipAny.value as? Int,\n              let parseMethodAny = decodedParse[\"_method\"],\n              let parseMethod = parseMethodAny.value as? String,\n              let parseLimitAny = decodedParse[\"limit\"],\n              let parseLimit = parseLimitAny.value as? Int,\n              let parseWhereAny = decodedParse[\"where\"],\n              let parseWhere = parseWhereAny.value as? [String: [String: [String: String]]] else {\n            XCTFail(\"Should have casted all\")\n            return\n        }\n\n        XCTAssertEqual(jsonSkip, parseSkip, \"Parse shoud always match JSON\")\n        XCTAssertEqual(jsonMethod, parseMethod, \"Parse shoud always match JSON\")\n        XCTAssertEqual(jsonLimit, parseLimit, \"Parse shoud always match JSON\")\n        XCTAssertEqual(jsonWhere, parseWhere, \"Parse shoud always match JSON\")\n    }\n\n    func findAsync(scoreOnServer: GameScore, callbackQueue: DispatchQueue) {\n        let query = GameScore.query()\n        let expectation = XCTestExpectation(description: \"Count object1\")\n        query.find(options: [], callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let found):\n                guard let score = found.first else {\n                    XCTFail(\"Should unwrap score count\")\n                    expectation.fulfill()\n                    return\n                }\n                XCTAssert(score.hasSameObjectId(as: scoreOnServer))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testThreadSafeFindAsync() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        DispatchQueue.concurrentPerform(iterations: 100) {_ in\n            findAsync(scoreOnServer: scoreOnServer, callbackQueue: .global(qos: .background))\n        }\n    }\n    #endif\n\n    func testFindAsyncMainQueue() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        findAsync(scoreOnServer: scoreOnServer, callbackQueue: .main)\n    }\n\n    func testFindLimitAsync() {\n        let query = GameScore.query()\n            .limit(0)\n        let expectation = XCTestExpectation(description: \"Count object1\")\n        query.find { results in\n            switch results {\n\n            case .success(let scores):\n                XCTAssert(scores.isEmpty)\n            case .failure(let error):\n                XCTFail(error.description)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testFindAllAsync() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = AnyResultsResponse(results: [scoreOnServer])\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let query = GameScore.query()\n        let expectation = XCTestExpectation(description: \"Count object1\")\n        query.findAll { result in\n\n            switch result {\n\n            case .success(let found):\n                guard let score = found.first else {\n                    XCTFail(\"Should unwrap score count\")\n                    expectation.fulfill()\n                    return\n                }\n                XCTAssert(score.hasSameObjectId(as: scoreOnServer))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testFindAllAsyncErrorSkip() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = AnyResultsResponse(results: [scoreOnServer])\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        var query = GameScore.query()\n        query.skip = 10\n        let expectation = XCTestExpectation(description: \"Count object1\")\n        query.findAll { result in\n\n            switch result {\n\n            case .success:\n                XCTFail(\"Should have failed\")\n            case .failure(let error):\n                XCTAssertTrue(error.message.contains(\"Cannot iterate\"))\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testFindAllAsyncErrorOrder() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = AnyResultsResponse(results: [scoreOnServer])\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let query = GameScore.query()\n            .order([.ascending(\"points\")])\n        let expectation = XCTestExpectation(description: \"Count object1\")\n        query.findAll { result in\n\n            switch result {\n\n            case .success:\n                XCTFail(\"Should have failed\")\n            case .failure(let error):\n                XCTAssertTrue(error.message.contains(\"Cannot iterate\"))\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testFindAllAsyncErrorLimit() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = AnyResultsResponse(results: [scoreOnServer])\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        var query = GameScore.query()\n        query.limit = 10\n        let expectation = XCTestExpectation(description: \"Count object1\")\n        query.findAll { result in\n\n            switch result {\n\n            case .success:\n                XCTFail(\"Should have failed\")\n            case .failure(let error):\n                XCTAssertTrue(error.message.contains(\"Cannot iterate\"))\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testFindAllLimit() {\n        let query = GameScore.query()\n            .limit(0)\n        let expectation = XCTestExpectation(description: \"Count object1\")\n        query.findAll { results in\n            switch results {\n\n            case .success(let scores):\n                XCTAssert(scores.isEmpty)\n            case .failure(let error):\n                XCTFail(error.description)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testFirstCommand() throws {\n        let query = GameScore.query()\n        let command = try query.firstCommand()\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"body\\\":{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":1,\\\"skip\\\":0,\\\"where\\\":{}},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"\\\\/classes\\\\/GameScore\\\"}\"\n        let encoded = try ParseCoding.jsonEncoder()\n            .encode(command)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testFirstExplainCommand() throws {\n        let query = GameScore.query()\n        let command: API.NonParseBodyCommand<Query<ParseQueryTests.GameScore>,\n                                             GameScore> = try query.firstExplainCommand()\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"body\\\":{\\\"_method\\\":\\\"GET\\\",\\\"explain\\\":true,\\\"limit\\\":1,\\\"skip\\\":0,\\\"where\\\":{}},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"\\\\/classes\\\\/GameScore\\\"}\"\n        let encoded = try ParseCoding.jsonEncoder()\n            .encode(command)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testFirst() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query()\n        do {\n            let score = try query.first(options: [])\n            XCTAssert(score.hasSameObjectId(as: scoreOnServer))\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testFirstThrowDecodingError() {\n        var scoreOnServer = GameScoreBroken()\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScoreBroken>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query()\n        do {\n            _ = try query.first(options: [])\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let error = error as? ParseError else {\n                XCTFail(\"Should have casted as ParseError\")\n                return\n            }\n            #if !os(Linux) && !os(Android) && !os(Windows)\n            // swiftlint:disable:next line_length\n            XCTAssertEqual(error.message, \"Invalid struct: No value associated with key CodingKeys(stringValue: \\\"points\\\", intValue: nil) (\\\"points\\\").\")\n            XCTAssertEqual(error.code, .unknownError)\n            #endif\n        }\n        XCTAssertThrowsError(try query.first(options: []))\n    }\n\n    func testFirstNoObjectFound() {\n\n        let results = QueryResponse<GameScore>(results: [GameScore](), count: 0)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query()\n        do {\n            _ = try query.first(options: [])\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let error = error as? ParseError else {\n                XCTFail(\"Should have casted as ParseError\")\n                return\n            }\n            XCTAssertEqual(error.code, .objectNotFound)\n        }\n\n    }\n\n    func testFirstLimit() {\n        let query = GameScore.query()\n            .limit(0)\n        XCTAssertThrowsError(try query.first())\n    }\n\n    func firstAsyncNoObjectFound(scoreOnServer: GameScore, callbackQueue: DispatchQueue) {\n        let query = GameScore.query()\n        let expectation = XCTestExpectation(description: \"Count object1\")\n        query.first(options: [], callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success:\n                XCTFail(\"Should have failed\")\n\n            case .failure(let error):\n                XCTAssertEqual(error.code, .objectNotFound)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func firstAsync(scoreOnServer: GameScore, callbackQueue: DispatchQueue) {\n        let query = GameScore.query()\n        let expectation = XCTestExpectation(description: \"Count object1\")\n        query.first(options: [], callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let score):\n                XCTAssert(score.hasSameObjectId(as: scoreOnServer))\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testThreadSafeFirstAsync() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        DispatchQueue.concurrentPerform(iterations: 100) {_ in\n            firstAsync(scoreOnServer: scoreOnServer, callbackQueue: .global(qos: .background))\n        }\n    }\n    #endif\n\n    func testFirstAsyncMainQueue() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        firstAsync(scoreOnServer: scoreOnServer, callbackQueue: .main)\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testThreadSafeFirstAsyncNoObjectFound() {\n        let scoreOnServer = GameScore(points: 10)\n        let results = QueryResponse<GameScore>(results: [GameScore](), count: 0)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        DispatchQueue.concurrentPerform(iterations: 100) {_ in\n            firstAsyncNoObjectFound(scoreOnServer: scoreOnServer, callbackQueue: .global(qos: .background))\n        }\n    }\n    #endif\n\n    func testFirstAsyncNoObjectFoundMainQueue() {\n        let scoreOnServer = GameScore(points: 10)\n        let results = QueryResponse<GameScore>(results: [GameScore](), count: 0)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        firstAsyncNoObjectFound(scoreOnServer: scoreOnServer, callbackQueue: .main)\n    }\n\n    func testFirstAsyncLimit() {\n        let query = GameScore.query()\n            .limit(0)\n        let expectation = XCTestExpectation(description: \"Find object1\")\n        query.first { results in\n            switch results {\n\n            case .success:\n                XCTFail(\"Should have thrown error.\")\n            case .failure(let error):\n                XCTAssertEqual(error.code, .objectNotFound)\n\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testCountCommand() throws {\n        let query = GameScore.query()\n        let command = try query.countCommand()\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"body\\\":{\\\"_method\\\":\\\"GET\\\",\\\"count\\\":true,\\\"limit\\\":1,\\\"skip\\\":0,\\\"where\\\":{}},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"\\\\/classes\\\\/GameScore\\\"}\"\n        let encoded = try ParseCoding.jsonEncoder()\n            .encode(command)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testCountExplainCommand() throws {\n        let query = GameScore.query()\n        let command: API.NonParseBodyCommand<Query<ParseQueryTests.GameScore>,\n                                             [Int]> = try query.countExplainCommand()\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"body\\\":{\\\"_method\\\":\\\"GET\\\",\\\"count\\\":true,\\\"explain\\\":true,\\\"limit\\\":1,\\\"skip\\\":0,\\\"where\\\":{}},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"\\\\/classes\\\\/GameScore\\\"}\"\n        let encoded = try ParseCoding.jsonEncoder()\n            .encode(command)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testCount() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query()\n        do {\n\n            let scoreCount = try query.count(options: [])\n            XCTAssertEqual(scoreCount, 1)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n    }\n\n    func testCountLimit() throws {\n        let query = GameScore.query()\n            .limit(0)\n        let count = try query.count()\n        XCTAssertEqual(count, 0)\n    }\n\n    func countAsync(scoreOnServer: GameScore, callbackQueue: DispatchQueue) {\n        let query = GameScore.query()\n        let expectation = XCTestExpectation(description: \"Count object1\")\n        query.count(options: [], callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let scoreCount):\n                XCTAssertEqual(scoreCount, 1)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testThreadSafeCountAsync() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        DispatchQueue.concurrentPerform(iterations: 100) {_ in\n            countAsync(scoreOnServer: scoreOnServer, callbackQueue: .global(qos: .background))\n        }\n    }\n    #endif\n\n    func testCountAsyncMainQueue() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        countAsync(scoreOnServer: scoreOnServer, callbackQueue: .main)\n    }\n\n    func testCountAsyncLimit() throws {\n        let query = GameScore.query()\n            .limit(0)\n        let expectation = XCTestExpectation(description: \"Count object1\")\n        query.count { result in\n            switch result {\n\n            case .success(let count):\n                XCTAssertEqual(count, 0)\n            case .failure(let error):\n                XCTFail(error.description)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    // MARK: Standard Conditions\n    func testWhereKeyExists() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$exists\": true]\n        ]\n        let constraint = exists(key: \"yolo\")\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: Bool],\n                  let decodedValues = decodedDictionary.values.first?.value as? [String: Bool] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyDoesNotExist() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$exists\": false]\n        ]\n        let constraint = doesNotExist(key: \"yolo\")\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: Bool],\n                  let decodedValues = decodedDictionary.values.first?.value as? [String: Bool] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyEqualTo() {\n        let expected: [String: String] = [\n            \"yolo\": \"yarr\"\n        ]\n        let query = GameScore.query(\"yolo\" == \"yarr\")\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decoded = try JSONDecoder().decode([String: String].self, from: encoded)\n\n            XCTAssertEqual(expected, decoded)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyEqualToParseObjectError() throws {\n        let compareObject = GameScore(points: 11)\n        XCTAssertThrowsError(try GameScore.query(\"yolo\" == compareObject))\n    }\n\n    func testWhereKeyEqualToBool() throws {\n        let query = GameScore.query(\"isCounts\" == true)\n        let expected = \"{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{\\\"isCounts\\\":true}}\"\n        XCTAssertEqual(query.debugDescription, expected)\n        XCTAssertEqual(query.description, expected)\n        let encoded = try ParseCoding.jsonEncoder().encode(query)\n        let decoded = try ParseCoding.jsonDecoder().decode(Query<GameScore>.self, from: encoded)\n        XCTAssertEqual(query, decoded)\n    }\n\n    func testWhereKeyEqualToBoolEQ() throws {\n        let query = GameScore.query(equalTo(key: \"isCounts\", value: true, usingEqComparator: true))\n        let expected = \"{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{\\\"isCounts\\\":{\\\"$eq\\\":true}}}\"\n        XCTAssertEqual(query.debugDescription, expected)\n        XCTAssertEqual(query.description, expected)\n        let encoded = try ParseCoding.jsonEncoder().encode(query)\n        let decoded = try ParseCoding.jsonDecoder().decode(Query<GameScore>.self, from: encoded)\n        XCTAssertEqual(query, decoded)\n    }\n\n    func testWhereKeyEqualToParseObject() throws {\n        var compareObject = GameScore(points: 11)\n        compareObject.objectId = \"hello\"\n        let query = try GameScore.query(\"yolo\" == compareObject)\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{\\\"yolo\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"hello\\\"}}}\"\n        XCTAssertEqual(query.debugDescription, expected)\n        let encoded = try ParseCoding.jsonEncoder().encode(query)\n        let decoded = try ParseCoding.jsonDecoder().decode(Query<GameScore>.self, from: encoded)\n        XCTAssertEqual(query, decoded)\n    }\n\n    func testWhereKeyEqualToParseObjectEQ() throws {\n        var compareObject = GameScore(points: 11)\n        compareObject.objectId = \"hello\"\n        let query = try GameScore.query(equalTo(key: \"yolo\", value: compareObject, usingEqComparator: true))\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{\\\"yolo\\\":{\\\"$eq\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"hello\\\"}}}}\"\n        XCTAssertEqual(query.debugDescription, expected)\n        let encoded = try ParseCoding.jsonEncoder().encode(query)\n        let decoded = try ParseCoding.jsonDecoder().decode(Query<GameScore>.self, from: encoded)\n        XCTAssertEqual(query, decoded)\n    }\n\n    func testWhereKeyEqualToParseObjectDuplicateConstraint() throws {\n        var compareObject = GameScore(points: 11)\n        compareObject.objectId = \"hello\"\n        let query = try GameScore.query(\"yolo\" == compareObject,\n                                        \"yolo\" == compareObject)\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{\\\"yolo\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"hello\\\"}}}\"\n        XCTAssertEqual(query.debugDescription, expected)\n        let encoded = try ParseCoding.jsonEncoder().encode(query)\n        let decoded = try ParseCoding.jsonDecoder().decode(Query<GameScore>.self, from: encoded)\n        XCTAssertEqual(query, decoded)\n    }\n\n    func testWhereKeyEqualToParseObjectPointer() throws {\n        var compareObject = GameScore(points: 11)\n        compareObject.objectId = \"hello\"\n        let pointer = try compareObject.toPointer()\n        let query = GameScore.query(\"yolo\" == pointer)\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{\\\"yolo\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"hello\\\"}}}\"\n        XCTAssertEqual(query.debugDescription, expected)\n        let encoded = try ParseCoding.jsonEncoder().encode(query)\n        let decoded = try ParseCoding.jsonDecoder().decode(Query<GameScore>.self, from: encoded)\n        XCTAssertEqual(query, decoded)\n    }\n\n    func testWhereKeyNotEqualToParseObject() throws {\n        var compareObject = GameScore(points: 11)\n        compareObject.objectId = \"hello\"\n        let query = try GameScore.query(\"yolo\" != compareObject)\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{\\\"yolo\\\":{\\\"$ne\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"hello\\\"}}}}\"\n        XCTAssertEqual(query.debugDescription, expected)\n        let encoded = try ParseCoding.jsonEncoder().encode(query)\n        let decoded = try ParseCoding.jsonDecoder().decode(Query<GameScore>.self, from: encoded)\n        XCTAssertEqual(query, decoded)\n    }\n\n    func testWhereKeyIsNull() throws {\n        var compareObject = GameScore(points: 11)\n        compareObject.objectId = \"hello\"\n        let query = GameScore.query(isNull(key: \"yolo\"))\n            .order(.ascending(\"yolo\"), .descending(\"points\"))\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"order\\\":[\\\"yolo\\\",\\\"-points\\\"],\\\"skip\\\":0,\\\"where\\\":{\\\"yolo\\\":null}}\"\n        XCTAssertEqual(query.debugDescription, expected)\n        let encoded = try ParseCoding.jsonEncoder().encode(query)\n        let decoded = try ParseCoding.jsonDecoder().decode(Query<GameScore>.self, from: encoded)\n        XCTAssertEqual(query, decoded)\n    }\n\n    func testWhereKeyNotNull() throws {\n        var compareObject = GameScore(points: 11)\n        compareObject.objectId = \"hello\"\n        let query = GameScore.query(isNotNull(key: \"yolo\"))\n        let expected = \"{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{\\\"yolo\\\":{\\\"$ne\\\":null}}}\"\n        XCTAssertEqual(query.debugDescription, expected)\n        let encoded = try ParseCoding.jsonEncoder().encode(query)\n        let decoded = try ParseCoding.jsonDecoder().decode(Query<GameScore>.self, from: encoded)\n        XCTAssertEqual(query, decoded)\n    }\n\n    func testWhereKeyIsNullDuplicateConstraint() throws {\n        var compareObject = GameScore(points: 11)\n        compareObject.objectId = \"hello\"\n        let query = GameScore.query(isNull(key: \"yolo\"),\n                                    isNull(key: \"yolo\"))\n        let expected = \"{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{\\\"yolo\\\":null}}\"\n        XCTAssertEqual(query.debugDescription, expected)\n        let encoded = try ParseCoding.jsonEncoder().encode(query)\n        let decoded = try ParseCoding.jsonDecoder().decode(Query<GameScore>.self, from: encoded)\n        XCTAssertEqual(query, decoded)\n    }\n\n    func testWhereKeyIsNullMultipleKey() throws {\n        var compareObject = GameScore(points: 11)\n        compareObject.objectId = \"hello\"\n        let query = GameScore.query(isNull(key: \"yolo\"),\n                                    isNull(key: \"hello\"))\n        let expected = \"{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{\\\"hello\\\":null,\\\"yolo\\\":null}}\"\n        XCTAssertEqual(query.debugDescription, expected)\n        let encoded = try ParseCoding.jsonEncoder().encode(query)\n        let decoded = try ParseCoding.jsonDecoder().decode(Query<GameScore>.self, from: encoded)\n        XCTAssertEqual(query, decoded)\n    }\n\n    func testWhereKeyComparatorMultipleSameKey() throws {\n        var compareObject = GameScore(points: 11)\n        compareObject.objectId = \"hello\"\n        let query = GameScore.query(\"yolo\" >= 5,\n                                    \"yolo\" <= 10)\n        let expected = \"{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{\\\"yolo\\\":{\\\"$gte\\\":5,\\\"$lte\\\":10}}}\"\n        XCTAssertEqual(query.debugDescription, expected)\n        let encoded = try ParseCoding.jsonEncoder().encode(query)\n        let decoded = try ParseCoding.jsonDecoder().decode(Query<GameScore>.self, from: encoded)\n        XCTAssertEqual(query, decoded)\n    }\n\n    func testWhereKeyComparatorMultipleSameKeyDuplicate() throws {\n        var compareObject = GameScore(points: 11)\n        compareObject.objectId = \"hello\"\n        let query = GameScore.query(\"yolo\" >= 5,\n                                    \"yolo\" >= 5,\n                                    \"yolo\" <= 10)\n        let expected = \"{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{\\\"yolo\\\":{\\\"$gte\\\":5,\\\"$lte\\\":10}}}\"\n        XCTAssertEqual(query.debugDescription, expected)\n        let encoded = try ParseCoding.jsonEncoder().encode(query)\n        let decoded = try ParseCoding.jsonDecoder().decode(Query<GameScore>.self, from: encoded)\n        XCTAssertEqual(query, decoded)\n    }\n\n    func testWhereKeyNotEqualTo() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$ne\": \"yarr\"]\n        ]\n        let query = GameScore.query(\"yolo\" != \"yarr\")\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: String],\n                  let decodedValues = decodedDictionary.values.first?.value as? [String: String] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyLessThan() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$lt\": \"yarr\"]\n        ]\n        let query = GameScore.query(\"yolo\" < \"yarr\")\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: String],\n                  let decodedValues = decodedDictionary.values.first?.value as? [String: String] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyLessThanOrEqualTo() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$lte\": \"yarr\"]\n        ]\n        let query = GameScore.query(\"yolo\" <= \"yarr\")\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: String],\n                  let decodedValues = decodedDictionary.values.first?.value as? [String: String] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyGreaterThan() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$gt\": \"yarr\"]\n        ]\n        let query = GameScore.query(\"yolo\" > \"yarr\")\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: String],\n                  let decodedValues = decodedDictionary.values.first?.value as? [String: String] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyGreaterThanOrEqualTo() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$gte\": \"yarr\"]\n        ]\n        let query = GameScore.query(\"yolo\" >= \"yarr\")\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: String],\n                  let decodedValues = decodedDictionary.values.first?.value as? [String: String] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyMatchesText() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$text\": [\"$search\": [\"$term\": \"yarr\"]]]\n        ]\n        let constraint = matchesText(key: \"yolo\", text: \"yarr\")\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: [String: [String: String]]],\n                  let decodedValues = decodedDictionary.values.first?.value as?\n                    [String: [String: [String: String]]] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyMatchesTextNoOptions() throws {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$text\": [\"$search\": [\"$term\": \"yarr\"]]]\n        ]\n        let constraint = try matchesText(key: \"yolo\", text: \"yarr\", options: [:])\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: [String: [String: String]]],\n                  let decodedValues = decodedDictionary.values.first?.value as?\n                    [String: [String: [String: String]]] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyMatchesTextWithOptions() throws {\n        let expected: [String: [String: [String: [String: AnyCodable]]]] = [\n            \"yolo\": [\"$text\": [\"$search\": [\n                \"$term\": \"yarr\",\n                \"$caseSensitive\": true,\n                \"$diacriticSensitive\": true\n            ]]]\n        ]\n        let options: [ParseTextOption: Encodable] = [\n            ParseTextOption.language: \"brew\",\n            ParseTextOption.caseSensitive: true,\n            ParseTextOption.diacriticSensitive: true\n        ]\n        let constraint = try matchesText(key: \"yolo\", text: \"yarr\", options: options)\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: [String: [String: [String: AnyCodable]]]].self,\n                                                             from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected[\"yolo\"]?[\"$text\"]?[\"$search\"],\n                  let expectedTerm = expectedValues[\"$term\"]?.value as? String,\n                  let expectedCaseSensitive = expectedValues[\"$caseSensitive\"]?.value as? Bool,\n                  let expectedDiacriticSensitive = expectedValues[\"$diacriticSensitive\"]?.value as? Bool,\n                  let decodedValues = decodedDictionary[\"yolo\"]?[\"$text\"]?[\"$search\"],\n                  let decodedTerm = decodedValues[\"$term\"]?.value as? String,\n                  let decodedCaseSensitive = decodedValues[\"$caseSensitive\"]?.value as? Bool,\n                  let decodedDiacriticSensitive = decodedValues[\"$diacriticSensitive\"]?.value as? Bool else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedTerm, decodedTerm)\n            XCTAssertEqual(expectedCaseSensitive, decodedCaseSensitive)\n            XCTAssertEqual(expectedDiacriticSensitive, decodedDiacriticSensitive)\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyMatchesTextBadOptions() throws {\n        XCTAssertThrowsError(try matchesText(key: \"yolo\", text: \"yarr\", options: [.language: true]))\n        XCTAssertThrowsError(try matchesText(key: \"yolo\", text: \"yarr\", options: [.caseSensitive: \"yolo\"]))\n        XCTAssertThrowsError(try matchesText(key: \"yolo\", text: \"yarr\", options: [.diacriticSensitive: \"yolo\"]))\n    }\n\n    func testWhereKeyMatchesRegex() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$regex\": \"yarr\"]\n        ]\n        let constraint = matchesRegex(key: \"yolo\", regex: \"yarr\")\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: String],\n                  let decodedValues = decodedDictionary.values.first?.value as? [String: String] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyMatchesRegexModifiers() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\n                \"$regex\": \"yarr\",\n                \"$options\": \"i\"\n            ]\n        ]\n        let constraint = matchesRegex(key: \"yolo\", regex: \"yarr\", modifiers: \"i\")\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: String],\n                  let decodedValues = decodedDictionary.values.first?.value as? [String: String] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyContainsString() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$regex\": \"\\\\Qyarr\\\\E\"]\n        ]\n        let constraint = containsString(key: \"yolo\", substring: \"yarr\")\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: String],\n                  let decodedValues = decodedDictionary.values.first?.value as? [String: String] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyContainsStringModifier() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$regex\": \"\\\\Qyarr\\\\E\",\n                     \"$options\": \"i\"]\n        ]\n        let constraint = containsString(key: \"yolo\", substring: \"yarr\", modifiers: \"i\")\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: String],\n                  let decodedValues = decodedDictionary.values.first?.value as? [String: String] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyHasPrefix() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$regex\": \"^\\\\Qyarr\\\\E\"]\n        ]\n        let constraint = hasPrefix(key: \"yolo\", prefix: \"yarr\")\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: String],\n                  let decodedValues = decodedDictionary.values.first?.value as? [String: String] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyHasPrefixModifier() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$regex\": \"^\\\\Qyarr\\\\E\",\n                     \"$options\": \"i\"]\n        ]\n        let constraint = hasPrefix(key: \"yolo\", prefix: \"yarr\", modifiers: \"i\")\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: String],\n                  let decodedValues = decodedDictionary.values.first?.value as? [String: String] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyHasSuffix() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$regex\": \"\\\\Qyarr\\\\E$\"]\n        ]\n        let constraint = hasSuffix(key: \"yolo\", suffix: \"yarr\")\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: String],\n                  let decodedValues = decodedDictionary.values.first?.value as? [String: String] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyHasSuffixModifier() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$regex\": \"\\\\Qyarr\\\\E$\",\n                     \"$options\": \"i\"]\n        ]\n        let constraint = hasSuffix(key: \"yolo\", suffix: \"yarr\", modifiers: \"i\")\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: String],\n                  let decodedValues = decodedDictionary.values.first?.value as? [String: String] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testOrQuery() {\n        let expected: [String: AnyCodable] = [\n            \"$or\": [\n                [\"points\": [\"$lte\": 50]],\n                [\"points\": [\"$lte\": 200]]\n            ]\n        ]\n        let query1 = GameScore.query(\"points\" <= 50)\n        let query2 = GameScore.query(\"points\" <= 200)\n        let constraint = or(queries: query1, query2)\n        let query = Query<GameScore>(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [[String: [String: Int]]],\n                  let decodedValues = decodedDictionary.values.first?.value as? [[String: [String: Int]]] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testNorQuery() {\n        let expected: [String: AnyCodable] = [\n            \"$nor\": [\n                [\"points\": [\"$lte\": 50]],\n                [\"points\": [\"$lte\": 200]]\n            ]\n        ]\n        let query1 = GameScore.query(\"points\" <= 50)\n        let query2 = GameScore.query(\"points\" <= 200)\n        let constraint = nor(queries: query1, query2)\n        let query = Query<GameScore>(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [[String: [String: Int]]],\n                  let decodedValues = decodedDictionary.values.first?.value as? [[String: [String: Int]]] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testAndQuery() {\n        let expected: [String: AnyCodable] = [\n            \"$and\": [\n                [\"points\": [\"$lte\": 50]],\n                [\"points\": [\"$lte\": 200]]\n            ]\n        ]\n        let query1 = GameScore.query(\"points\" <= 50)\n        let query2 = GameScore.query(\"points\" <= 200)\n        let constraint = and(queries: query1, query2)\n        let query = Query<GameScore>(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [[String: [String: Int]]],\n                  let decodedValues = decodedDictionary.values.first?.value as? [[String: [String: Int]]] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyMatchesKeyInQuery() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\n                \"$select\": [\n                    \"query\": [\"where\": [\"test\": [\"$lte\": \"awk\"]]],\n                    \"key\": \"yolo1\"\n                ]\n            ]\n        ]\n        let inQuery = GameScore.query(\"test\" <= \"awk\")\n        let constraint = matchesKeyInQuery(key: \"yolo\", queryKey: \"yolo1\", query: inQuery)\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: [String: Any]],\n                  let expectedSelect = expectedValues[\"$select\"],\n                  let expectedKeyValue = expectedSelect[\"key\"] as? String,\n                  let expectedKeyQuery = expectedSelect[\"query\"] as? [String: Any],\n                  let expectedKeyWhere = expectedKeyQuery[\"where\"] as? [String: [String: String]] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            guard let decodedValues = decodedDictionary.values.first?.value as? [String: [String: Any]],\n                  let decodedSelect = decodedValues[\"$select\"],\n                  let decodedKeyValue = decodedSelect[\"key\"] as? String,\n                  let decodedKeyQuery = decodedSelect[\"query\"] as? [String: Any],\n                  let decodedKeyWhere = decodedKeyQuery[\"where\"] as? [String: [String: String]] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            XCTAssertEqual(expectedKeyValue, decodedKeyValue)\n            XCTAssertEqual(expectedKeyWhere, decodedKeyWhere)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyDoesNotMatchKeyInQuery() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\n                \"$dontSelect\": [\n                    \"query\": [\"where\": [\"test\": [\"$lte\": \"awk\"]]],\n                    \"key\": \"yolo1\"\n                ]\n            ]\n        ]\n        let inQuery = GameScore.query(\"test\" <= \"awk\")\n        let constraint = doesNotMatchKeyInQuery(key: \"yolo\", queryKey: \"yolo1\", query: inQuery)\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: [String: Any]],\n                  let expectedSelect = expectedValues[\"$dontSelect\"],\n                  let expectedKeyValue = expectedSelect[\"key\"] as? String,\n                  let expectedKeyQuery = expectedSelect[\"query\"] as? [String: Any],\n                  let expectedKeyWhere = expectedKeyQuery[\"where\"] as? [String: [String: String]] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            guard let decodedValues = decodedDictionary.values.first?.value as? [String: [String: Any]],\n                  let decodedSelect = decodedValues[\"$dontSelect\"],\n                  let decodedKeyValue = decodedSelect[\"key\"] as? String,\n                  let decodedKeyQuery = decodedSelect[\"query\"] as? [String: Any],\n                  let decodedKeyWhere = decodedKeyQuery[\"where\"] as? [String: [String: String]] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            XCTAssertEqual(expectedKeyValue, decodedKeyValue)\n            XCTAssertEqual(expectedKeyWhere, decodedKeyWhere)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyMatchesQuery() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\n                \"$inQuery\": [\n                    \"where\": [\"test\": [\"$lte\": \"awk\"]]\n                ]\n            ]\n        ]\n        let inQuery = GameScore.query(\"test\" <= \"awk\")\n        let query = GameScore.query(\"yolo\" == inQuery)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: [String: Any]],\n                  let expectedInQuery = expectedValues[\"$inQuery\"],\n                  let expectedKeyWhere = expectedInQuery[\"where\"] as? [String: [String: String]] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            guard let decodedValues = decodedDictionary.values.first?.value as? [String: [String: Any]],\n                  let decodedInQuery = decodedValues[\"$inQuery\"],\n                  let decodedKeyWhere = decodedInQuery[\"where\"] as? [String: [String: String]] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            XCTAssertEqual(expectedKeyWhere, decodedKeyWhere)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyDoesNotMatchQuery() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\n                \"$notInQuery\": [\n                    \"where\": [\"test\": [\"$lte\": \"awk\"]]\n                ]\n            ]\n        ]\n        let inQuery = GameScore.query(\"test\" <= \"awk\")\n        let query = GameScore.query(\"yolo\" != inQuery)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: [String: Any]],\n                  let expectedInQuery = expectedValues[\"$notInQuery\"],\n                  let expectedKeyWhere = expectedInQuery[\"where\"] as? [String: [String: String]] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            guard let decodedValues = decodedDictionary.values.first?.value as? [String: [String: Any]],\n                  let decodedInQuery = decodedValues[\"$notInQuery\"],\n                  let decodedKeyWhere = decodedInQuery[\"where\"] as? [String: [String: String]] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            XCTAssertEqual(expectedKeyWhere, decodedKeyWhere)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereContainedIn() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$in\": [\"yarr\"]]\n        ]\n        let constraint = containedIn(key: \"yolo\", array: [\"yarr\"])\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: [String]],\n                  let decodedValues = decodedDictionary.values.first?.value as? [String: [String]] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereContainedInParseObject() throws {\n        var compareObject = GameScore(points: 11)\n        compareObject.objectId = \"hello\"\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"yolo\\\":{\\\"$in\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"hello\\\"}]}}\"\n        let constraint = try containedIn(key: \"yolo\", array: [compareObject])\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            guard let decoded = String(data: encoded, encoding: .utf8) else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expected, decoded)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereNotContainedInParseObject() throws {\n        var compareObject = GameScore(points: 11)\n        compareObject.objectId = \"hello\"\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"yolo\\\":{\\\"$nin\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"hello\\\"}]}}\"\n        let constraint = try notContainedIn(key: \"yolo\", array: [compareObject])\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            guard let decoded = String(data: encoded, encoding: .utf8) else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expected, decoded)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereContainedByParseObject() throws {\n        var compareObject = GameScore(points: 11)\n        compareObject.objectId = \"hello\"\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"yolo\\\":{\\\"$containedBy\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"hello\\\"}]}}\"\n        let constraint = try containedBy(key: \"yolo\", array: [compareObject])\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            guard let decoded = String(data: encoded, encoding: .utf8) else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expected, decoded)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereContainsAllParseObject() throws {\n        var compareObject = GameScore(points: 11)\n        compareObject.objectId = \"hello\"\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"yolo\\\":{\\\"$all\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"hello\\\"}]}}\"\n        let constraint = try containsAll(key: \"yolo\", array: [compareObject])\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            guard let decoded = String(data: encoded, encoding: .utf8) else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expected, decoded)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereContainedBy() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$containedBy\": [\"yarr\"]]\n        ]\n        let constraint = containedBy(key: \"yolo\", array: [\"yarr\"])\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: [String]],\n                  let decodedValues = decodedDictionary.values.first?.value as? [String: [String]] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereNotContainedIn() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$nin\": [\"yarr\"]]\n        ]\n        let constraint = notContainedIn(key: \"yolo\", array: [\"yarr\"])\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: [String]],\n                  let decodedValues = decodedDictionary.values.first?.value as? [String: [String]] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereContainsAll() {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$all\": [\"yarr\"]]\n        ]\n        let constraint = containsAll(key: \"yolo\", array: [\"yarr\"])\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: [String]],\n                  let decodedValues = decodedDictionary.values.first?.value as? [String: [String]] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedValues, decodedValues)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyRelated() throws {\n        let expected: [String: AnyCodable] = [\n            \"$relatedTo\": [\n                \"key\": \"yolo\",\n                \"object\": [\"__type\": \"Pointer\",\n                           \"className\": \"GameScore\",\n                           \"objectId\": \"hello\"]\n            ]\n        ]\n        var object = GameScore(points: 50)\n        object.objectId = \"hello\"\n        let constraint = try related(key: \"yolo\", object: object)\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: Any],\n                  let expectedKey = expectedValues[\"key\"] as? String,\n                  let expectedObject = expectedValues[\"object\"] as? [String: String] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            guard let decodedValues = decodedDictionary.values.first?.value as? [String: Any],\n                  let decodedKey = decodedValues[\"key\"] as? String,\n                  let decodedObject = decodedValues[\"object\"] as? [String: String] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            XCTAssertEqual(expectedKey, decodedKey)\n            XCTAssertEqual(expectedObject, decodedObject)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyRelatedNoObject() throws {\n        let expected: [String: AnyCodable] = [\n            \"$relatedTo\": [\n                \"key\": \"yolo\"\n            ]\n        ]\n        var object = GameScore(points: 50)\n        object.objectId = \"hello\"\n        let constraint = related(key: \"yolo\")\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: Any],\n                  let expectedKey = expectedValues[\"key\"] as? String else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            guard let decodedValues = decodedDictionary.values.first?.value as? [String: Any],\n                  let decodedKey = decodedValues[\"key\"] as? String else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            XCTAssertEqual(expectedKey, decodedKey)\n            XCTAssertNil(decodedValues[\"object\"])\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyRelatedPointer() throws {\n        let expected: [String: AnyCodable] = [\n            \"$relatedTo\": [\n                \"key\": \"yolo\",\n                \"object\": [\"__type\": \"Pointer\",\n                           \"className\": \"GameScore\",\n                           \"objectId\": \"hello\"]\n            ]\n        ]\n        var object = GameScore(points: 50)\n        object.objectId = \"hello\"\n        let constraint = related(key: \"yolo\", object: try object.toPointer())\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: Any],\n                  let expectedKey = expectedValues[\"key\"] as? String,\n                  let expectedObject = expectedValues[\"object\"] as? [String: String] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            guard let decodedValues = decodedDictionary.values.first?.value as? [String: Any],\n                  let decodedKey = decodedValues[\"key\"] as? String,\n                  let decodedObject = decodedValues[\"object\"] as? [String: String] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            XCTAssertEqual(expectedKey, decodedKey)\n            XCTAssertEqual(expectedObject, decodedObject)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyRelatedPointerNoKey() throws {\n        let expected: [String: AnyCodable] = [\n            \"$relatedTo\": [\n                \"object\": [\"__type\": \"Pointer\",\n                           \"className\": \"GameScore\",\n                           \"objectId\": \"hello\"]\n            ]\n        ]\n        var object = GameScore(points: 50)\n        object.objectId = \"hello\"\n        let constraint = related(object: try object.toPointer())\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: Any],\n                  let expectedObject = expectedValues[\"object\"] as? [String: String] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            guard let decodedValues = decodedDictionary.values.first?.value as? [String: Any],\n                  let decodedObject = decodedValues[\"object\"] as? [String: String] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            XCTAssertNil(decodedValues[\"key\"])\n            XCTAssertEqual(expectedObject, decodedObject)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyRelatedObject() throws {\n        let expected: [String: AnyCodable] = [\n            \"$relatedTo\": [\n                \"key\": \"yolo\",\n                \"object\": [\"__type\": \"Pointer\",\n                           \"className\": \"GameScore\",\n                           \"objectId\": \"hello\"]\n            ]\n        ]\n        var object = GameScore(points: 50)\n        object.objectId = \"hello\"\n        let constraint = try related(key: \"yolo\", object: object)\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: Any],\n                  let expectedKey = expectedValues[\"key\"] as? String,\n                  let expectedObject = expectedValues[\"object\"] as? [String: String] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            guard let decodedValues = decodedDictionary.values.first?.value as? [String: Any],\n                  let decodedKey = decodedValues[\"key\"] as? String,\n                  let decodedObject = decodedValues[\"object\"] as? [String: String] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            XCTAssertEqual(expectedKey, decodedKey)\n            XCTAssertEqual(expectedObject, decodedObject)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyRelatedObjectNoKey() throws {\n        let expected: [String: AnyCodable] = [\n            \"$relatedTo\": [\n                \"object\": [\"__type\": \"Pointer\",\n                           \"className\": \"GameScore\",\n                           \"objectId\": \"hello\"]\n            ]\n        ]\n        var object = GameScore(points: 50)\n        object.objectId = \"hello\"\n        let constraint = try related(object: object)\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: Any],\n                  let expectedObject = expectedValues[\"object\"] as? [String: String] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            guard let decodedValues = decodedDictionary.values.first?.value as? [String: Any],\n                  let decodedObject = decodedValues[\"object\"] as? [String: String] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            XCTAssertNil(decodedValues[\"key\"])\n            XCTAssertEqual(expectedObject, decodedObject)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyRelativeToTime() throws {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\n                \"$gte\": [\"$relativeTime\": \"3 days ago\"]\n            ]\n        ]\n        var object = GameScore(points: 50)\n        object.objectId = \"hello\"\n        let constraint = relative(\"yolo\" >= \"3 days ago\")\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected\n                    .values\n                    .first?.value as? [String: [String: String]] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            guard let decodedValues = decodedDictionary\n                    .values\n                    .first?.value as? [String: [String: String]] else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            XCTAssertEqual(expectedValues, decodedValues)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    // MARK: GeoPoint\n    func testWhereKeyNearGeoPoint() throws {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$nearSphere\": [\"latitude\": 10, \"longitude\": 20, \"__type\": \"GeoPoint\"]]\n        ]\n        let geoPoint = try ParseGeoPoint(latitude: 10, longitude: 20)\n        let constraint = near(key: \"yolo\", geoPoint: geoPoint)\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: [String: Any]],\n                  let expectedLongitude = expectedValues[\"$nearSphere\"]?[\"longitude\"] as? Int,\n                  let expectedLatitude = expectedValues[\"$nearSphere\"]?[\"latitude\"] as? Int,\n                  let expectedType = expectedValues[\"$nearSphere\"]?[\"__type\"] as? String else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            guard let decodedValues = decodedDictionary.values.first?.value as? [String: [String: Any]],\n                  let decodedLongitude = decodedValues[\"$nearSphere\"]?[\"longitude\"] as? Int,\n                  let decodedLatitude = decodedValues[\"$nearSphere\"]?[\"latitude\"] as? Int,\n                  let decodedType = decodedValues[\"$nearSphere\"]?[\"__type\"] as? String else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedLongitude, decodedLongitude)\n            XCTAssertEqual(expectedLatitude, decodedLatitude)\n            XCTAssertEqual(expectedType, decodedType)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyNearGeoPointWithinMiles() throws {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$nearSphere\": [\"latitude\": 10, \"longitude\": 20, \"__type\": \"GeoPoint\"],\n                     \"$maxDistance\": 1\n            ]\n        ]\n        let geoPoint = try ParseGeoPoint(latitude: 10, longitude: 20)\n        let constraint = withinMiles(key: \"yolo\", geoPoint: geoPoint, distance: 3958.8)\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: Any],\n                  let expectedNear = expectedValues[\"$nearSphere\"] as? [String: Any],\n                  let expectedLongitude = expectedNear[\"longitude\"] as? Int,\n                  let expectedLatitude = expectedNear[\"latitude\"] as? Int,\n                  let expectedType = expectedNear[\"__type\"] as? String,\n                  let expectedDistance = expectedValues[\"$maxDistance\"] as? Int else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            guard let decodedValues = decodedDictionary.values.first?.value as? [String: Any],\n                  let decodedNear = decodedValues[\"$nearSphere\"] as? [String: Any],\n                  let decodedLongitude = decodedNear[\"longitude\"] as? Int,\n                  let decodedLatitude = decodedNear[\"latitude\"] as? Int,\n                  let decodedType = decodedNear[\"__type\"] as? String,\n                  let decodedDistance = decodedValues[\"$maxDistance\"] as? Int else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedLongitude, decodedLongitude)\n            XCTAssertEqual(expectedLatitude, decodedLatitude)\n            XCTAssertEqual(expectedType, decodedType)\n            XCTAssertEqual(expectedDistance, decodedDistance)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyNearGeoPointWithinMilesNotSorted() throws {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$centerSphere\": [\"latitude\": 10, \"longitude\": 20, \"__type\": \"GeoPoint\"],\n                     \"$geoWithin\": 1\n            ]\n        ]\n        let geoPoint = try ParseGeoPoint(latitude: 10, longitude: 20)\n        let constraint = withinMiles(key: \"yolo\",\n                                     geoPoint: geoPoint,\n                                     distance: 3958.8,\n                                     sorted: false)\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: Any],\n                  let expectedNear = expectedValues[\"$centerSphere\"] as? [String: Any],\n                  let expectedLongitude = expectedNear[\"longitude\"] as? Int,\n                  let expectedLatitude = expectedNear[\"latitude\"] as? Int,\n                  let expectedType = expectedNear[\"__type\"] as? String,\n                  let expectedDistance = expectedValues[\"$geoWithin\"] as? Int else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            guard let decodedValues = decodedDictionary.values.first?.value as? [String: Any],\n                  let decodedNear = decodedValues[\"$centerSphere\"] as? [String: Any],\n                  let decodedLongitude = decodedNear[\"longitude\"] as? Int,\n                  let decodedLatitude = decodedNear[\"latitude\"] as? Int,\n                  let decodedType = decodedNear[\"__type\"] as? String,\n                  let decodedDistance = decodedValues[\"$geoWithin\"] as? Int else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedLongitude, decodedLongitude)\n            XCTAssertEqual(expectedLatitude, decodedLatitude)\n            XCTAssertEqual(expectedType, decodedType)\n            XCTAssertEqual(expectedDistance, decodedDistance)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyNearGeoPointWithinKilometers() throws {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$nearSphere\": [\"latitude\": 10, \"longitude\": 20, \"__type\": \"GeoPoint\"],\n                     \"$maxDistance\": 1\n            ]\n        ]\n        let geoPoint = try ParseGeoPoint(latitude: 10, longitude: 20)\n        let constraint = withinKilometers(key: \"yolo\", geoPoint: geoPoint, distance: 6371.0)\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: Any],\n                  let expectedNear = expectedValues[\"$nearSphere\"] as? [String: Any],\n                  let expectedLongitude = expectedNear[\"longitude\"] as? Int,\n                  let expectedLatitude = expectedNear[\"latitude\"] as? Int,\n                  let expectedType = expectedNear[\"__type\"] as? String,\n                  let expectedDistance = expectedValues[\"$maxDistance\"] as? Int else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            guard let decodedValues = decodedDictionary.values.first?.value as? [String: Any],\n                  let decodedNear = decodedValues[\"$nearSphere\"] as? [String: Any],\n                  let decodedLongitude = decodedNear[\"longitude\"] as? Int,\n                  let decodedLatitude = decodedNear[\"latitude\"] as? Int,\n                  let decodedType = decodedNear[\"__type\"] as? String,\n                  let decodedDistance = decodedValues[\"$maxDistance\"] as? Int else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedLongitude, decodedLongitude)\n            XCTAssertEqual(expectedLatitude, decodedLatitude)\n            XCTAssertEqual(expectedType, decodedType)\n            XCTAssertEqual(expectedDistance, decodedDistance)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyNearGeoPointWithinKilometersNotSorted() throws {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$centerSphere\": [\"latitude\": 10, \"longitude\": 20, \"__type\": \"GeoPoint\"],\n                     \"$geoWithin\": 1\n            ]\n        ]\n        let geoPoint = try ParseGeoPoint(latitude: 10, longitude: 20)\n        let constraint = withinKilometers(key: \"yolo\",\n                                          geoPoint: geoPoint,\n                                          distance: 6371.0,\n                                          sorted: false)\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: Any],\n                  let expectedNear = expectedValues[\"$centerSphere\"] as? [String: Any],\n                  let expectedLongitude = expectedNear[\"longitude\"] as? Int,\n                  let expectedLatitude = expectedNear[\"latitude\"] as? Int,\n                  let expectedType = expectedNear[\"__type\"] as? String,\n                  let expectedDistance = expectedValues[\"$geoWithin\"] as? Int else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            guard let decodedValues = decodedDictionary.values.first?.value as? [String: Any],\n                  let decodedNear = decodedValues[\"$centerSphere\"] as? [String: Any],\n                  let decodedLongitude = decodedNear[\"longitude\"] as? Int,\n                  let decodedLatitude = decodedNear[\"latitude\"] as? Int,\n                  let decodedType = decodedNear[\"__type\"] as? String,\n                  let decodedDistance = decodedValues[\"$geoWithin\"] as? Int else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedLongitude, decodedLongitude)\n            XCTAssertEqual(expectedLatitude, decodedLatitude)\n            XCTAssertEqual(expectedType, decodedType)\n            XCTAssertEqual(expectedDistance, decodedDistance)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyNearGeoPointWithinRadians() throws {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$nearSphere\": [\"latitude\": 10, \"longitude\": 20, \"__type\": \"GeoPoint\"],\n                     \"$maxDistance\": 10\n            ]\n        ]\n        let geoPoint = try ParseGeoPoint(latitude: 10, longitude: 20)\n        let constraint = withinRadians(key: \"yolo\", geoPoint: geoPoint, distance: 10.0)\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: Any],\n                  let expectedNear = expectedValues[\"$nearSphere\"] as? [String: Any],\n                  let expectedLongitude = expectedNear[\"longitude\"] as? Int,\n                  let expectedLatitude = expectedNear[\"latitude\"] as? Int,\n                  let expectedType = expectedNear[\"__type\"] as? String,\n                  let expectedDistance = expectedValues[\"$maxDistance\"] as? Int else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            guard let decodedValues = decodedDictionary.values.first?.value as? [String: Any],\n                  let decodedNear = decodedValues[\"$nearSphere\"] as? [String: Any],\n                  let decodedLongitude = decodedNear[\"longitude\"] as? Int,\n                  let decodedLatitude = decodedNear[\"latitude\"] as? Int,\n                  let decodedType = decodedNear[\"__type\"] as? String,\n                  let decodedDistance = decodedValues[\"$maxDistance\"] as? Int else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedLongitude, decodedLongitude)\n            XCTAssertEqual(expectedLatitude, decodedLatitude)\n            XCTAssertEqual(expectedType, decodedType)\n            XCTAssertEqual(expectedDistance, decodedDistance)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    func testWhereKeyNearGeoPointWithinRadiansNotSorted() throws {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$centerSphere\": [\"latitude\": 10, \"longitude\": 20, \"__type\": \"GeoPoint\"],\n                     \"$geoWithin\": 10\n            ]\n        ]\n        let geoPoint = try ParseGeoPoint(latitude: 10, longitude: 20)\n        let constraint = withinRadians(key: \"yolo\", geoPoint: geoPoint, distance: 10.0, sorted: false)\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: Any],\n                  let expectedNear = expectedValues[\"$centerSphere\"] as? [String: Any],\n                  let expectedLongitude = expectedNear[\"longitude\"] as? Int,\n                  let expectedLatitude = expectedNear[\"latitude\"] as? Int,\n                  let expectedType = expectedNear[\"__type\"] as? String,\n                  let expectedDistance = expectedValues[\"$geoWithin\"] as? Int else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            guard let decodedValues = decodedDictionary.values.first?.value as? [String: Any],\n                  let decodedNear = decodedValues[\"$centerSphere\"] as? [String: Any],\n                  let decodedLongitude = decodedNear[\"longitude\"] as? Int,\n                  let decodedLatitude = decodedNear[\"latitude\"] as? Int,\n                  let decodedType = decodedNear[\"__type\"] as? String,\n                  let decodedDistance = decodedValues[\"$geoWithin\"] as? Int else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedLongitude, decodedLongitude)\n            XCTAssertEqual(expectedLatitude, decodedLatitude)\n            XCTAssertEqual(expectedType, decodedType)\n            XCTAssertEqual(expectedDistance, decodedDistance)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    // swiftlint:disable:next function_body_length\n    func testWhereKeyNearGeoBox() throws {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$within\": [\"$box\": [\n                                    [\"latitude\": 10, \"longitude\": 20, \"__type\": \"GeoPoint\"],\n                                    [\"latitude\": 20, \"longitude\": 30, \"__type\": \"GeoPoint\"]]\n                                ]\n            ]\n        ]\n        let geoPoint1 = try ParseGeoPoint(latitude: 10, longitude: 20)\n        let geoPoint2 = try ParseGeoPoint(latitude: 20, longitude: 30)\n        let constraint = withinGeoBox(key: \"yolo\", fromSouthWest: geoPoint1, toNortheast: geoPoint2)\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: [String: [[String: Any]]]],\n                  let expectedBox = expectedValues[\"$within\"]?[\"$box\"],\n                  let expectedLongitude = expectedBox.first?[\"longitude\"] as? Int,\n                  let expectedLatitude = expectedBox.first?[\"latitude\"] as? Int,\n                  let expectedType = expectedBox.first?[\"__type\"] as? String,\n                  let expectedLongitude2 = expectedBox.last?[\"longitude\"] as? Int,\n                  let expectedLatitude2 = expectedBox.last?[\"latitude\"] as? Int,\n                  let expectedType2 = expectedBox.last?[\"__type\"] as? String else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            guard let decodedValues = decodedDictionary.values.first?.value as? [String: [String: [[String: Any]]]],\n                  let decodedBox = decodedValues[\"$within\"]?[\"$box\"],\n                  let decodedLongitude = decodedBox.first?[\"longitude\"] as? Int,\n                  let decodedLatitude = decodedBox.first?[\"latitude\"] as? Int,\n                  let decodedType = decodedBox.first?[\"__type\"] as? String,\n                  let decodedLongitude2 = decodedBox.last?[\"longitude\"] as? Int,\n                  let decodedLatitude2 = decodedBox.last?[\"latitude\"] as? Int,\n                  let decodedType2 = decodedBox.last?[\"__type\"] as? String else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n            XCTAssertEqual(expectedLongitude, decodedLongitude)\n            XCTAssertEqual(expectedLatitude, decodedLatitude)\n            XCTAssertEqual(expectedType, decodedType)\n            XCTAssertEqual(expectedLongitude2, decodedLongitude2)\n            XCTAssertEqual(expectedLatitude2, decodedLatitude2)\n            XCTAssertEqual(expectedType2, decodedType2)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    // swiftlint:disable:next function_body_length\n    func testWhereKeyWithinPolygonPoints() throws {\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"yolo\\\":{\\\"$geoWithin\\\":{\\\"$polygon\\\":[{\\\"__type\\\":\\\"GeoPoint\\\",\\\"latitude\\\":10.1,\\\"longitude\\\":20.100000000000001},{\\\"__type\\\":\\\"GeoPoint\\\",\\\"latitude\\\":20.100000000000001,\\\"longitude\\\":30.100000000000001},{\\\"__type\\\":\\\"GeoPoint\\\",\\\"latitude\\\":30.100000000000001,\\\"longitude\\\":40.100000000000001}]}}}\"\n        let geoPoint1 = try ParseGeoPoint(latitude: 10.1, longitude: 20.1)\n        let geoPoint2 = try ParseGeoPoint(latitude: 20.1, longitude: 30.1)\n        let geoPoint3 = try ParseGeoPoint(latitude: 30.1, longitude: 40.1)\n        let polygon = [geoPoint1, geoPoint2, geoPoint3]\n        let constraint = withinPolygon(key: \"yolo\", points: polygon)\n        let query = GameScore.query(constraint)\n        XCTAssertEqual(query.where.description, expected)\n    }\n\n    // swiftlint:disable:next function_body_length\n    func testWhereKeyWithinPolygon() throws {\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"yolo\\\":{\\\"$geoWithin\\\":{\\\"$polygon\\\":{\\\"__type\\\":\\\"Polygon\\\",\\\"coordinates\\\":[[20.100000000000001,10.1],[30.100000000000001,20.100000000000001],[40.100000000000001,30.100000000000001]]}}}}\"\n        let geoPoint1 = try ParseGeoPoint(latitude: 10.1, longitude: 20.1)\n        let geoPoint2 = try ParseGeoPoint(latitude: 20.1, longitude: 30.1)\n        let geoPoint3 = try ParseGeoPoint(latitude: 30.1, longitude: 40.1)\n        let polygon = try ParsePolygon(geoPoint1, geoPoint2, geoPoint3)\n        let constraint = withinPolygon(key: \"yolo\", polygon: polygon)\n        let query = GameScore.query(constraint)\n        XCTAssertEqual(query.where.description, expected)\n    }\n    #endif\n\n    func testWhereKeyPolygonContains() throws {\n        let expected: [String: AnyCodable] = [\n            \"yolo\": [\"$geoIntersects\": [\"$point\":\n                                    [\"latitude\": 10, \"longitude\": 20, \"__type\": \"GeoPoint\"]\n                                ]\n            ]\n        ]\n        let geoPoint = try ParseGeoPoint(latitude: 10, longitude: 20)\n        let constraint = polygonContains(key: \"yolo\", point: geoPoint)\n        let query = GameScore.query(constraint)\n        let queryWhere = query.`where`\n\n        do {\n            let encoded = try ParseCoding.jsonEncoder().encode(queryWhere)\n            let decodedDictionary = try JSONDecoder().decode([String: AnyCodable].self, from: encoded)\n            XCTAssertEqual(expected.keys, decodedDictionary.keys)\n\n            guard let expectedValues = expected.values.first?.value as? [String: [String: [String: Any]]],\n                  let expectedNear = expectedValues[\"$geoIntersects\"]?[\"$point\"],\n                  let expectedLongitude = expectedNear[\"longitude\"] as? Int,\n                  let expectedLatitude = expectedNear[\"latitude\"] as? Int,\n                  let expectedType = expectedNear[\"__type\"] as? String else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            guard let decodedValues = decodedDictionary.values.first?.value as? [String: [String: [String: Any]]],\n                  let decodedNear = decodedValues[\"$geoIntersects\"]?[\"$point\"],\n                  let decodedLongitude = decodedNear[\"longitude\"] as? Int,\n                  let decodedLatitude = decodedNear[\"latitude\"] as? Int,\n                  let decodedType = decodedNear[\"__type\"] as? String else {\n                XCTFail(\"Should have casted\")\n                return\n            }\n\n            XCTAssertEqual(expectedLongitude, decodedLongitude)\n            XCTAssertEqual(expectedLatitude, decodedLatitude)\n            XCTAssertEqual(expectedType, decodedType)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n            return\n        }\n    }\n\n    // MARK: JSON Responses\n    func testExplainFindSynchronous() {\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query()\n        do {\n            let queryResult: [[String: String]] = try query.findExplain()\n            XCTAssertEqual(queryResult, json.results)\n        } catch {\n            XCTFail(\"Error: \\(error)\")\n        }\n    }\n\n    func testExplainMongoFindSynchronous() {\n        let json = AnyResultsMongoResponse(results: [\"yolo\": \"yarr\"])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query()\n        do {\n            let queryResult: [[String: String]] = try query.findExplain(usingMongoDB: true)\n            XCTAssertEqual(queryResult, [json.results])\n        } catch {\n            XCTFail(\"Error: \\(error)\")\n        }\n    }\n\n    func testExplainFindLimitSynchronous() {\n        let query = GameScore.query()\n            .limit(0)\n        do {\n            let queryResult: [[String: String]] = try query.findExplain()\n            XCTAssertTrue(queryResult.isEmpty)\n        } catch {\n            XCTFail(\"Error: \\(error)\")\n        }\n    }\n\n    func testExplainFindAsynchronous() {\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation = XCTestExpectation(description: \"Fetch object\")\n        let query = GameScore.query()\n        query.findExplain(callbackQueue: .main) { (result: Result<[[String: String]], ParseError>) in\n            switch result {\n\n            case .success(let queryResult):\n                XCTAssertEqual(queryResult, json.results)\n            case .failure(let error):\n                XCTFail(\"Error: \\(error)\")\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testExplainFindLimitAsynchronous() {\n\n        let expectation = XCTestExpectation(description: \"Fetch object\")\n        let query = GameScore.query()\n            .limit(0)\n        query.findExplain(callbackQueue: .main) { (result: Result<[[String: String]], ParseError>) in\n            switch result {\n\n            case .success(let queryResult):\n                XCTAssertTrue(queryResult.isEmpty)\n            case .failure(let error):\n                XCTFail(\"Error: \\(error)\")\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testExplainFirstSynchronous() {\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query()\n        do {\n            let queryResult: [String: String] = try query.firstExplain()\n            XCTAssertEqual(queryResult, json.results.first)\n        } catch {\n            XCTFail(\"Error: \\(error)\")\n        }\n    }\n\n    func testExplainMongoFirstSynchronous() {\n        let json = AnyResultsMongoResponse(results: [\"yolo\": \"yarr\"])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query()\n        do {\n            let queryResult: [String: String] = try query.firstExplain(usingMongoDB: true)\n            XCTAssertEqual(queryResult, json.results)\n        } catch {\n            XCTFail(\"Error: \\(error)\")\n        }\n    }\n\n    func testExplainFirstLimitSynchronous() {\n        let query = GameScore.query()\n            .limit(0)\n        do {\n            let _: [[String: String]] = try query.firstExplain()\n            XCTFail(\"Should have produced error\")\n        } catch {\n            guard let error = error as? ParseError else {\n                XCTFail(\"Should have casted as ParseError\")\n                return\n            }\n            XCTAssertEqual(error.code, .objectNotFound)\n        }\n    }\n\n    func testExplainFirstAsynchronous() {\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation = XCTestExpectation(description: \"Fetch object\")\n        let query = GameScore.query()\n        query.firstExplain(callbackQueue: .main) { (result: Result<[String: String], ParseError>) in\n            switch result {\n\n            case .success(let queryResult):\n                XCTAssertEqual(queryResult, json.results.first)\n            case .failure(let error):\n                XCTFail(\"Error: \\(error)\")\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testExplainFirstLimitAsynchronous() {\n\n        let expectation = XCTestExpectation(description: \"Fetch object\")\n        let query = GameScore.query()\n            .limit(0)\n        query.firstExplain(callbackQueue: .main) { (result: Result<[String: String], ParseError>) in\n            switch result {\n\n            case .success:\n                XCTFail(\"Should have produced error\")\n            case .failure(let error):\n                XCTAssertEqual(error.code, .objectNotFound)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testExplainCountSynchronous() {\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query()\n        do {\n            let queryResult: [[String: String]] = try query.countExplain()\n            XCTAssertEqual(queryResult, json.results)\n        } catch {\n            XCTFail(\"Error: \\(error)\")\n        }\n    }\n\n    func testExplainMongoCountSynchronous() {\n        let json = AnyResultsMongoResponse(results: [\"yolo\": \"yarr\"])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query()\n        do {\n            let queryResult: [[String: String]] = try query.countExplain(usingMongoDB: true)\n            XCTAssertEqual(queryResult, [json.results])\n        } catch {\n            XCTFail(\"Error: \\(error)\")\n        }\n    }\n\n    func testExplainCountLimitSynchronous() {\n\n        let query = GameScore.query()\n            .limit(0)\n        do {\n            let queryResult: [[String: String]] = try query.countExplain()\n            XCTAssertTrue(queryResult.isEmpty)\n        } catch {\n            XCTFail(\"Error: \\(error)\")\n        }\n    }\n\n    func testExplainCountAsynchronous() {\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation = XCTestExpectation(description: \"Fetch object\")\n        let query = GameScore.query()\n        query.countExplain(callbackQueue: .main) { (result: Result<[[String: String]], ParseError>) in\n            switch result {\n\n            case .success(let queryResult):\n                XCTAssertEqual(queryResult, json.results)\n            case .failure(let error):\n                XCTFail(\"Error: \\(error)\")\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testExplainCountLimitAsynchronous() {\n\n        let expectation = XCTestExpectation(description: \"Fetch object\")\n        let query = GameScore.query()\n            .limit(0)\n        query.countExplain(callbackQueue: .main) { (result: Result<[[String: String]], ParseError>) in\n            switch result {\n\n            case .success(let queryResult):\n                XCTAssertTrue(queryResult.isEmpty)\n            case .failure(let error):\n                XCTFail(\"Error: \\(error)\")\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testHintFindSynchronous() {\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query()\n            .hint(\"_id_\")\n        do {\n            let queryResult: [[String: String]] = try query.findExplain()\n            XCTAssertEqual(queryResult, json.results)\n        } catch {\n            XCTFail(\"Error: \\(error)\")\n        }\n    }\n\n    func testHintFindAsynchronous() {\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation = XCTestExpectation(description: \"Fetch object\")\n        let query = GameScore.query()\n            .hint(\"_id_\")\n        query.findExplain(callbackQueue: .main) { (result: Result<[[String: String]], ParseError>) in\n            switch result {\n\n            case .success(let queryResult):\n                XCTAssertEqual(queryResult, json.results)\n            case .failure(let error):\n                XCTFail(\"Error: \\(error)\")\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testHintFirstSynchronous() {\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query()\n            .hint(\"_id_\")\n        do {\n            let queryResult: [String: String] = try query.firstExplain()\n            XCTAssertEqual(queryResult, json.results.first)\n        } catch {\n            XCTFail(\"Error: \\(error)\")\n        }\n    }\n\n    func testHintFirstAsynchronous() {\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation = XCTestExpectation(description: \"Fetch object\")\n        let query = GameScore.query()\n            .hint(\"_id_\")\n        query.firstExplain(callbackQueue: .main) { (result: Result<[String: String], ParseError>) in\n            switch result {\n\n            case .success(let queryResult):\n                XCTAssertEqual(queryResult, json.results.first)\n            case .failure(let error):\n                XCTFail(\"Error: \\(error)\")\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testHintCountSynchronous() {\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query()\n            .hint(\"_id_\")\n        do {\n            let queryResult: [[String: String]] = try query.countExplain()\n            XCTAssertEqual(queryResult, json.results)\n        } catch {\n            XCTFail(\"Error: \\(error)\")\n        }\n    }\n\n    func testHintCountAsynchronous() {\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation = XCTestExpectation(description: \"Fetch object\")\n        let query = GameScore.query()\n            .hint(\"_id_\")\n        query.countExplain(callbackQueue: .main) { (result: Result<[[String: String]], ParseError>) in\n            switch result {\n\n            case .success(let queryResult):\n                XCTAssertEqual(queryResult, json.results)\n            case .failure(let error):\n                XCTFail(\"Error: \\(error)\")\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testAggregateCommand() throws {\n        var query = GameScore.query()\n        let value = AnyCodable(\"world\")\n        query.pipeline = [[\"hello\": value]]\n        let aggregate = try query.aggregateCommand()\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"body\\\":{\\\"pipeline\\\":[{\\\"hello\\\":\\\"\\(value)\\\"}]},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"\\\\/aggregate\\\\/GameScore\\\"}\"\n        let encoded = try ParseCoding.jsonEncoder()\n            .encode(aggregate)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testAggregateExplainCommand() throws {\n        let query = GameScore.query()\n        let command: API.NonParseBodyCommand<Query<GameScore>.AggregateBody<GameScore>,\n                                             [String]> = try query.aggregateExplainCommand()\n        let expected = \"{\\\"body\\\":{\\\"explain\\\":true},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"\\\\/aggregate\\\\/GameScore\\\"}\"\n        let encoded = try ParseCoding.jsonEncoder()\n            .encode(command)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testDistinctCommand() throws {\n        let query = GameScore.query()\n        let aggregate = try query.distinctCommand(key: \"hello\")\n        let expected = \"{\\\"body\\\":{\\\"distinct\\\":\\\"hello\\\"},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"\\\\/aggregate\\\\/GameScore\\\"}\"\n        let encoded = try ParseCoding.jsonEncoder()\n            .encode(aggregate)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testDistinctExplainCommand() throws {\n        let query = GameScore.query()\n        let command: API.NonParseBodyCommand<Query<GameScore>.DistinctBody<GameScore>,\n                                             [String]> = try query.distinctExplainCommand(key: \"hello\")\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"body\\\":{\\\"distinct\\\":\\\"hello\\\",\\\"explain\\\":true},\\\"method\\\":\\\"POST\\\",\\\"path\\\":\\\"\\\\/aggregate\\\\/GameScore\\\"}\"\n        let encoded = try ParseCoding.jsonEncoder()\n            .encode(command)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testAggregate() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query()\n        do {\n            let pipeline = [[\"hello\": \"world\"]]\n            guard let score = try query.aggregate(pipeline).first else {\n                XCTFail(\"Should unwrap first object found\")\n                return\n            }\n            XCTAssert(score.hasSameObjectId(as: scoreOnServer))\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testAggregateWithWhere() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query(\"points\" > 9)\n        do {\n            let pipeline = [[String: String]]()\n            guard let score = try query.aggregate(pipeline).first else {\n                XCTFail(\"Should unwrap first object found\")\n                return\n            }\n            XCTAssert(score.hasSameObjectId(as: scoreOnServer))\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testAggregateLimit() {\n\n        let query = GameScore.query()\n            .limit(0)\n        do {\n            let pipeline = [[\"hello\": \"world\"]]\n            let scores = try query.aggregate(pipeline)\n            XCTAssertTrue(scores.isEmpty)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testAggregateExplainWithWhere() {\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query(\"points\" > 9)\n        do {\n            let pipeline = [[String: String]]()\n            guard let score: [String: String] = try query.aggregateExplain(pipeline).first else {\n                XCTFail(\"Should unwrap first object found\")\n                return\n            }\n            XCTAssertEqual(score, json.results.first)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testAggregateExplainMongoWithWhere() {\n        let json = AnyResultsMongoResponse(results: [\"yolo\": \"yarr\"])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query(\"points\" > 9)\n        do {\n            let pipeline = [[String: String]]()\n            guard let score: [String: String] = try query.aggregateExplain(pipeline,\n                                                                           usingMongoDB: true).first else {\n                XCTFail(\"Should unwrap first object found\")\n                return\n            }\n            XCTAssertEqual(score, json.results)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testAggregateExplainWithWhereLimit() {\n\n        let query = GameScore.query(\"points\" > 9)\n            .limit(0)\n        do {\n            let pipeline = [[String: String]]()\n            let scores: [[String: String]] = try query.aggregateExplain(pipeline)\n            XCTAssertTrue(scores.isEmpty)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testAggregateAsyncMainQueue() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = Date()\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let query = GameScore.query()\n        let expectation = XCTestExpectation(description: \"Count object1\")\n        let pipeline = [[String: AnyEncodable]]()\n        query.aggregate(pipeline, options: [], callbackQueue: .main) { result in\n\n            switch result {\n\n            case .success(let found):\n                guard let score = found.first else {\n                    XCTFail(\"Should unwrap score count\")\n                    expectation.fulfill()\n                    return\n                }\n                XCTAssert(score.hasSameObjectId(as: scoreOnServer))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testAggregateWhereAsyncMainQueue() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let query = GameScore.query(\"points\" > 9)\n        let expectation = XCTestExpectation(description: \"Aggregate object1\")\n        let pipeline = [[String: AnyEncodable]]()\n        query.aggregate(pipeline, options: [], callbackQueue: .main) { result in\n\n            switch result {\n\n            case .success(let found):\n                guard let score = found.first else {\n                    XCTFail(\"Should unwrap score count\")\n                    expectation.fulfill()\n                    return\n                }\n                XCTAssert(score.hasSameObjectId(as: scoreOnServer))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testAggregateAsyncMainQueueLimit() {\n\n        let query = GameScore.query()\n            .limit(0)\n        let expectation = XCTestExpectation(description: \"Count object1\")\n        let pipeline = [[String: AnyEncodable]]()\n        query.aggregate(pipeline, options: [], callbackQueue: .main) { result in\n\n            switch result {\n\n            case .success(let found):\n                XCTAssertTrue(found.isEmpty)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testAggregateExplainAsyncMainQueue() {\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        let expectation = XCTestExpectation(description: \"Aggregate object1\")\n        let pipeline = [[String: String]]()\n        let query = GameScore.query(\"points\" > 9)\n        query.aggregateExplain(pipeline,\n                               options: [],\n                               callbackQueue: .main) { (result: Result<[[String: String]], ParseError>) in\n\n            switch result {\n\n            case .success(let found):\n                guard let score = found.first else {\n                    XCTFail(\"Should unwrap score count\")\n                    expectation.fulfill()\n                    return\n                }\n                XCTAssertEqual(score, json.results.first)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testAggregateExplainAsyncMainQueueLimit() {\n\n        let expectation = XCTestExpectation(description: \"Aggregate object1\")\n        let pipeline = [[String: String]]()\n        let query = GameScore.query(\"points\" > 9)\n            .limit(0)\n        query.aggregateExplain(pipeline,\n                               options: [],\n                               callbackQueue: .main) { (result: Result<[[String: String]], ParseError>) in\n\n            switch result {\n\n            case .success(let found):\n                XCTAssertTrue(found.isEmpty)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testDistinct() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let query = GameScore.query(\"points\" > 9)\n        do {\n            guard let score = try query.distinct(\"hello\").first else {\n                XCTFail(\"Should unwrap first object found\")\n                return\n            }\n            XCTAssert(score.hasSameObjectId(as: scoreOnServer))\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testDistinctLimit() {\n\n        let query = GameScore.query(\"points\" > 9)\n            .limit(0)\n        do {\n            let scores = try query.distinct(\"hello\")\n            XCTAssertTrue(scores.isEmpty)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testDistinctExplain() {\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query(\"points\" > 9)\n        do {\n            guard let score: [String: String] = try query.distinctExplain(\"hello\").first else {\n                XCTFail(\"Should unwrap first object found\")\n                return\n            }\n            XCTAssertEqual(score, json.results.first)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testDistinctExplainMongo() {\n        let json = AnyResultsMongoResponse(results: [\"yolo\": \"yarr\"])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let query = GameScore.query(\"points\" > 9)\n        do {\n            guard let score: [String: String] = try query.distinctExplain(\"hello\",\n                                                                          usingMongoDB: true).first else {\n                XCTFail(\"Should unwrap first object found\")\n                return\n            }\n            XCTAssertEqual(score, json.results)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testDistinctExplainLimit() {\n\n        let query = GameScore.query(\"points\" > 9)\n            .limit(0)\n        do {\n            let scores: [[String: String]] = try query.distinctExplain(\"hello\")\n            XCTAssertTrue(scores.isEmpty)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testDistinctAsyncMainQueue() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let query = GameScore.query(\"points\" > 9)\n        let expectation = XCTestExpectation(description: \"Distinct object1\")\n        query.distinct(\"hello\", options: [], callbackQueue: .main) { result in\n\n            switch result {\n\n            case .success(let found):\n                guard let score = found.first else {\n                    XCTFail(\"Should unwrap score count\")\n                    expectation.fulfill()\n                    return\n                }\n                XCTAssert(score.hasSameObjectId(as: scoreOnServer))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testDistinctAsyncMainQueueLimit() {\n        let query = GameScore.query(\"points\" > 9)\n            .limit(0)\n        let expectation = XCTestExpectation(description: \"Distinct object1\")\n        query.distinct(\"hello\", options: [], callbackQueue: .main) { result in\n\n            switch result {\n\n            case .success(let found):\n                XCTAssertTrue(found.isEmpty)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testDistinctExplainAsyncMainQueue() {\n        let json = AnyResultsResponse(results: [[\"yolo\": \"yarr\"]])\n\n        let encoded: Data!\n        do {\n            encoded = try JSONEncoder().encode(json)\n        } catch {\n            XCTFail(\"Should encode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        let expectation = XCTestExpectation(description: \"Aggregate object1\")\n        let query = GameScore.query(\"points\" > 9)\n        query.distinctExplain(\"hello\",\n                              options: [],\n                              callbackQueue: .main) { (result: Result<[[String: String]], ParseError>) in\n\n            switch result {\n\n            case .success(let found):\n                guard let score = found.first else {\n                    XCTFail(\"Should unwrap score count\")\n                    expectation.fulfill()\n                    return\n                }\n                XCTAssertEqual(score, json.results.first)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testDistinctExplainAsyncMainQueueLimit() {\n        let expectation = XCTestExpectation(description: \"Aggregate object1\")\n        let query = GameScore.query(\"points\" > 9)\n            .limit(0)\n        query.distinctExplain(\"hello\",\n                              options: [],\n                              callbackQueue: .main) { (result: Result<[[String: String]], ParseError>) in\n\n            switch result {\n\n            case .success(let found):\n                XCTAssertTrue(found.isEmpty)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n}\n// swiftlint:disable:this file_length\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseQueryViewModelTests.swift",
    "content": "//\n//  ParseQueryViewModelTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 7/3/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(SwiftUI)\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseQueryViewModelTests: XCTestCase {\n    struct GameScore: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int = 0\n\n        //custom initializer\n        init() {}\n        init(points: Int) {\n            self.points = points\n        }\n\n        init(objectId: String?) {\n            self.objectId = objectId\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              usingPostForQuery: true,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        try KeychainStore.shared.deleteAll()\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testFind() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let viewModel = GameScore.query\n            .viewModel\n        viewModel.error = ParseError(code: .unknownError, message: \"error\")\n        viewModel.find()\n        let expectation = XCTestExpectation(description: \"Find objects\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {\n\n            guard let score = viewModel.results.first else {\n                XCTFail(\"Should unwrap score count\")\n                expectation.fulfill()\n                return\n            }\n            XCTAssertTrue(score.hasSameObjectId(as: scoreOnServer))\n            XCTAssertEqual(viewModel.count, 1)\n            XCTAssertNil(viewModel.error)\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testFindError() {\n\n        let results = ParseError(code: .unknownError, message: \"Custom error\")\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let viewModel = GameScore.query\n            .viewModel\n        viewModel.results = [GameScore(points: 10)]\n        viewModel.count = 1\n        viewModel.find()\n        let expectation = XCTestExpectation(description: \"Find objects\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {\n\n            XCTAssertTrue(viewModel.results.isEmpty)\n            XCTAssertEqual(viewModel.count, 0)\n            XCTAssertNotNil(viewModel.error)\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testViewModelStatic() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let query = GameScore.query\n        let viewModel = Query.viewModel(query)\n        viewModel.error = ParseError(code: .unknownError, message: \"error\")\n        viewModel.find()\n        let expectation = XCTestExpectation(description: \"Find objects\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {\n\n            guard let score = viewModel.results.first else {\n                XCTFail(\"Should unwrap score count\")\n                expectation.fulfill()\n                return\n            }\n            XCTAssertTrue(score.hasSameObjectId(as: scoreOnServer))\n            XCTAssertEqual(viewModel.count, 1)\n            XCTAssertNil(viewModel.error)\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testFindAll() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let viewModel = GameScore.query\n            .viewModel\n        viewModel.error = ParseError(code: .unknownError, message: \"error\")\n        viewModel.findAll()\n        let expectation = XCTestExpectation(description: \"Find objects\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {\n\n            guard let score = viewModel.results.first else {\n                XCTFail(\"Should unwrap score count\")\n                expectation.fulfill()\n                return\n            }\n            XCTAssertTrue(score.hasSameObjectId(as: scoreOnServer))\n            XCTAssertEqual(viewModel.count, 1)\n            XCTAssertNil(viewModel.error)\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testFindAllError() {\n\n        let results = ParseError(code: .unknownError, message: \"Custom error\")\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let viewModel = GameScore.query\n            .viewModel\n        viewModel.results = [GameScore(points: 10)]\n        viewModel.count = 1\n        viewModel.findAll()\n        let expectation = XCTestExpectation(description: \"Find objects\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {\n\n            XCTAssertTrue(viewModel.results.isEmpty)\n            XCTAssertEqual(viewModel.count, 0)\n            XCTAssertNotNil(viewModel.error)\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testFirst() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let viewModel = GameScore.query\n            .viewModel\n        viewModel.error = ParseError(code: .unknownError, message: \"error\")\n        viewModel.first()\n        let expectation = XCTestExpectation(description: \"Find objects\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {\n\n            guard let score = viewModel.results.first else {\n                XCTFail(\"Should unwrap score count\")\n                expectation.fulfill()\n                return\n            }\n            XCTAssertTrue(score.hasSameObjectId(as: scoreOnServer))\n            XCTAssertEqual(viewModel.count, 1)\n            XCTAssertNil(viewModel.error)\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testFirstError() {\n\n        let results = ParseError(code: .unknownError, message: \"Custom error\")\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let viewModel = GameScore.query\n            .viewModel\n        viewModel.results = [GameScore(points: 10)]\n        viewModel.count = 1\n        viewModel.first()\n        let expectation = XCTestExpectation(description: \"Find objects\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {\n\n            XCTAssertTrue(viewModel.results.isEmpty)\n            XCTAssertEqual(viewModel.count, 0)\n            XCTAssertNotNil(viewModel.error)\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testCount() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let viewModel = GameScore.query\n            .viewModel\n        viewModel.results = [GameScore(points: 10), GameScore(points: 12)]\n        viewModel.count()\n        let expectation = XCTestExpectation(description: \"Find objects\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {\n\n            XCTAssertEqual(viewModel.results.count, 2)\n            XCTAssertEqual(viewModel.count, 1)\n            XCTAssertNil(viewModel.error)\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testCountError() {\n\n        let results = ParseError(code: .unknownError, message: \"Custom error\")\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let viewModel = GameScore.query\n            .viewModel\n        viewModel.results = [GameScore(points: 10)]\n        viewModel.count = 1\n        viewModel.count()\n        let expectation = XCTestExpectation(description: \"Find objects\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {\n\n            XCTAssertTrue(viewModel.results.isEmpty)\n            XCTAssertEqual(viewModel.count, 0)\n            XCTAssertNotNil(viewModel.error)\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testAggregate() {\n        var scoreOnServer = GameScore(points: 10)\n        scoreOnServer.objectId = \"yarr\"\n        scoreOnServer.createdAt = Date()\n        scoreOnServer.updatedAt = scoreOnServer.createdAt\n        scoreOnServer.ACL = nil\n\n        let results = QueryResponse<GameScore>(results: [scoreOnServer], count: 1)\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let viewModel = GameScore.query\n            .viewModel\n        viewModel.error = ParseError(code: .unknownError, message: \"error\")\n        viewModel.aggregate([[\"hello\": \"world\"]])\n        let expectation = XCTestExpectation(description: \"Find objects\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {\n\n            guard let score = viewModel.results.first else {\n                XCTFail(\"Should unwrap score count\")\n                expectation.fulfill()\n                return\n            }\n            XCTAssertTrue(score.hasSameObjectId(as: scoreOnServer))\n            XCTAssertEqual(viewModel.count, 1)\n            XCTAssertNil(viewModel.error)\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n\n    func testAggregateError() {\n\n        let results = ParseError(code: .unknownError, message: \"Custom error\")\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(results)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let viewModel = GameScore.query.viewModel\n        viewModel.results = [GameScore(points: 10)]\n        viewModel.count = 1\n        viewModel.aggregate([[\"hello\": \"world\"]])\n        let expectation = XCTestExpectation(description: \"Find objects\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {\n\n            XCTAssertTrue(viewModel.results.isEmpty)\n            XCTAssertEqual(viewModel.count, 0)\n            XCTAssertNotNil(viewModel.error)\n            expectation.fulfill()\n        }\n        wait(for: [expectation], timeout: 20.0)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseRelationTests.swift",
    "content": "//\n//  ParseRelationTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/20/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseRelationTests: XCTestCase {\n    struct GameScore: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int\n        var members = [String]()\n        var levels: ParseRelation<Self>?\n\n        //custom initializers\n        init() {\n            self.points = 5\n        }\n        init(points: Int) {\n            self.points = points\n        }\n    }\n\n    struct GameScore2: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int\n        var members = [String]()\n        var levels: ParseRelation<Self>?\n\n        //custom initializers\n        init() {\n            self.points = 5\n        }\n        init(points: Int) {\n            self.points = points\n        }\n    }\n\n    struct Level: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var level: Int\n        var members = [String]()\n\n        //custom initializers\n        init() {\n            self.level = 5\n        }\n\n        init(level: Int) {\n            self.level = level\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testEncoding() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"hello\"\n        score.objectId = objectId\n        guard var relation = score.relation else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        let expected = \"{\\\"__type\\\":\\\"Relation\\\"}\"\n        let encoded = try ParseCoding.jsonEncoder().encode(relation)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n\n        relation.className = \"hello\"\n        let expected2 = \"{\\\"__type\\\":\\\"Relation\\\",\\\"className\\\":\\\"hello\\\"}\"\n        let encoded2 = try ParseCoding.jsonEncoder().encode(relation)\n        let decoded2 = try XCTUnwrap(String(data: encoded2, encoding: .utf8))\n        XCTAssertEqual(decoded2, expected2)\n        XCTAssertEqual(relation.debugDescription,\n                       \"{\\\"__type\\\":\\\"Relation\\\",\\\"className\\\":\\\"hello\\\"}\")\n        XCTAssertEqual(relation.description,\n                       \"{\\\"__type\\\":\\\"Relation\\\",\\\"className\\\":\\\"hello\\\"}\")\n    }\n\n    func testParseObjectRelation() throws {\n        var score = GameScore(points: 10)\n        var level = Level(level: 1)\n        level.objectId = \"nice\"\n\n        // Should not produce a relation without an objectId.\n        XCTAssertThrowsError(try score.relation(\"yolo\", child: level))\n\n        let objectId = \"hello\"\n        score.objectId = objectId\n        var relation = try score.relation(\"yolo\", child: level)\n\n        let expected = \"{\\\"__type\\\":\\\"Relation\\\",\\\"className\\\":\\\"Level\\\"}\"\n        let encoded = try ParseCoding.jsonEncoder().encode(relation)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n\n        relation.className = \"hello\"\n        let expected2 = \"{\\\"__type\\\":\\\"Relation\\\",\\\"className\\\":\\\"hello\\\"}\"\n        let encoded2 = try ParseCoding.jsonEncoder().encode(relation)\n        let decoded2 = try XCTUnwrap(String(data: encoded2, encoding: .utf8))\n        XCTAssertEqual(decoded2, expected2)\n\n        var relation2 = try score.relation(\"yolo\", className: \"Level\")\n\n        let expected3 = \"{\\\"__type\\\":\\\"Relation\\\",\\\"className\\\":\\\"Level\\\"}\"\n        let encoded3 = try ParseCoding.jsonEncoder().encode(relation2)\n        let decoded3 = try XCTUnwrap(String(data: encoded3, encoding: .utf8))\n        XCTAssertEqual(decoded3, expected3)\n\n        relation2.className = \"hello\"\n        let expected4 = \"{\\\"__type\\\":\\\"Relation\\\",\\\"className\\\":\\\"hello\\\"}\"\n        let encoded4 = try ParseCoding.jsonEncoder().encode(relation2)\n        let decoded4 = try XCTUnwrap(String(data: encoded4, encoding: .utf8))\n        XCTAssertEqual(decoded4, expected4)\n    }\n\n    func testInitWithChild() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"hello\"\n        score.objectId = objectId\n\n        var level = Level(level: 1)\n        level.objectId = \"nice\"\n        var relation = try ParseRelation<GameScore>(parent: score, child: level)\n\n        let expected = \"{\\\"__type\\\":\\\"Relation\\\",\\\"className\\\":\\\"Level\\\"}\"\n        let encoded = try ParseCoding.jsonEncoder().encode(relation)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n\n        relation.className = \"hello\"\n        let expected2 = \"{\\\"__type\\\":\\\"Relation\\\",\\\"className\\\":\\\"hello\\\"}\"\n        let encoded2 = try ParseCoding.jsonEncoder().encode(relation)\n        let decoded2 = try XCTUnwrap(String(data: encoded2, encoding: .utf8))\n        XCTAssertEqual(decoded2, expected2)\n\n        _ = try ParseRelation<GameScore>(parent: score,\n                                         key: \"yolo\",\n                                         child: try level.toPointer())\n    }\n\n    func testAddIncorrectClassError() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"hello\"\n        score.objectId = objectId\n        guard var relation = score.relation else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        relation.className = \"hello\"\n        var level = Level(level: 1)\n        level.objectId = \"nice\"\n        XCTAssertThrowsError(try relation.add(\"level\", objects: [level]))\n    }\n\n    func testAddIncorrectKeyError() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"hello\"\n        score.objectId = objectId\n        guard var relation = score.relation else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        relation.className = \"Level\"\n        relation.key = \"test\"\n        var level = Level(level: 1)\n        level.objectId = \"nice\"\n        XCTAssertThrowsError(try relation.add(\"level\", objects: [level]))\n    }\n\n    func testAddOperation() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"hello\"\n        score.objectId = objectId\n        guard var relation = score.relation else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        var level = Level(level: 1)\n        level.objectId = \"nice\"\n        relation.className = level.className\n\n        let operation = try relation.add(\"level\", objects: [level])\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"level\\\":{\\\"__op\\\":\\\"AddRelation\\\",\\\"objects\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"Level\\\",\\\"objectId\\\":\\\"nice\\\"}]}}\"\n        let encoded = try ParseCoding.jsonEncoder().encode(operation)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testAddOpperationNoObjectId() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"hello\"\n        score.objectId = objectId\n\n        var relation = try ParseRelation(parent: score, key: \"yolo\")\n        relation.parent = nil // This will happen with decoded ParseRelations\n\n        var level = Level(level: 1)\n        level.objectId = \"nice\"\n        relation.className = level.className\n\n        // Should not produce a relation without an objectId.\n        XCTAssertThrowsError(try relation.add([level]))\n        XCTAssertThrowsError(try relation.add(\"yolo\", objects: [level]))\n    }\n\n    func testAddOperationNoKey() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"hello\"\n        score.objectId = objectId\n        guard var relation = score.relation else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        var level = Level(level: 1)\n        level.objectId = \"nice\"\n        relation.className = level.className\n\n        XCTAssertThrowsError(try relation.add([level]))\n        relation.key = \"level\"\n        let operation = try relation.add([level])\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"level\\\":{\\\"__op\\\":\\\"AddRelation\\\",\\\"objects\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"Level\\\",\\\"objectId\\\":\\\"nice\\\"}]}}\"\n        let encoded = try ParseCoding.jsonEncoder().encode(operation)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testAddOperationKeyCheck() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"hello\"\n        score.objectId = objectId\n        guard var relation = score.relation else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        var level = Level(level: 1)\n        level.objectId = \"nice\"\n        relation.className = level.className\n        relation.key = \"level\"\n\n        let operation = try relation.add(\"level\", objects: [level])\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"level\\\":{\\\"__op\\\":\\\"AddRelation\\\",\\\"objects\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"Level\\\",\\\"objectId\\\":\\\"nice\\\"}]}}\"\n        let encoded = try ParseCoding.jsonEncoder().encode(operation)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testIsSameClassNone() throws {\n        var score = GameScore(points: 10)\n        score.objectId = \"yolo\"\n        guard let relation = score.relation else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertFalse(relation.isSameClass([GameScore]()))\n    }\n\n    func testRemoveIncorrectClassError() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"hello\"\n        score.objectId = objectId\n        guard var relation = score.relation else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        relation.className = \"hello\"\n        var level = Level(level: 1)\n        level.objectId = \"nice\"\n        XCTAssertThrowsError(try relation.remove(\"level\", objects: [level]))\n    }\n\n    func testRemoveIncorrectKeyError() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"hello\"\n        score.objectId = objectId\n        guard var relation = score.relation else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        relation.className = \"Level\"\n        relation.key = \"test\"\n        var level = Level(level: 1)\n        level.objectId = \"nice\"\n        XCTAssertThrowsError(try relation.remove(\"level\", objects: [level]))\n    }\n\n    func testRemoveOperations() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"hello\"\n        score.objectId = objectId\n        guard var relation = score.relation else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        var level = Level(level: 1)\n        level.objectId = \"nice\"\n        relation.className = level.className\n\n        let operation = try relation.remove(\"level\", objects: [level])\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"level\\\":{\\\"__op\\\":\\\"RemoveRelation\\\",\\\"objects\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"Level\\\",\\\"objectId\\\":\\\"nice\\\"}]}}\"\n        let encoded = try ParseCoding.jsonEncoder().encode(operation)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testRemoveOpperationNoObjectId() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"hello\"\n        score.objectId = objectId\n\n        var relation = try ParseRelation(parent: score, key: \"yolo\")\n        relation.parent = nil // This will happen with decoded ParseRelations\n\n        var level = Level(level: 1)\n        level.objectId = \"nice\"\n        relation.className = level.className\n\n        // Should not produce a relation without an objectId.\n        XCTAssertThrowsError(try relation.remove([level]))\n        XCTAssertThrowsError(try relation.remove(\"yolo\", objects: [level]))\n    }\n\n    func testRemoveOperationsNoKey() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"hello\"\n        score.objectId = objectId\n        guard var relation = score.relation else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        var level = Level(level: 1)\n        level.objectId = \"nice\"\n        relation.className = level.className\n\n        XCTAssertThrowsError(try relation.remove([level]))\n        relation.key = \"level\"\n        let operation = try relation.remove([level])\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"level\\\":{\\\"__op\\\":\\\"RemoveRelation\\\",\\\"objects\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"Level\\\",\\\"objectId\\\":\\\"nice\\\"}]}}\"\n        let encoded = try ParseCoding.jsonEncoder().encode(operation)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testRemoveOperationsKeyCheck() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"hello\"\n        score.objectId = objectId\n        guard var relation = score.relation else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        var level = Level(level: 1)\n        level.objectId = \"nice\"\n        relation.className = level.className\n        relation.key = \"level\"\n\n        let operation = try relation.remove(\"level\", objects: [level])\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"level\\\":{\\\"__op\\\":\\\"RemoveRelation\\\",\\\"objects\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"Level\\\",\\\"objectId\\\":\\\"nice\\\"}]}}\"\n        let encoded = try ParseCoding.jsonEncoder().encode(operation)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testQuery() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"hello\"\n        score.objectId = objectId\n        guard var relation = score.relation else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        var level = Level(level: 1)\n        level.objectId = \"nice\"\n        relation.className = level.className\n\n        // No Key, this should throw\n        do {\n            let _: Query<Level> = try relation.query()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.containedIn([.unknownError]))\n        }\n\n        do {\n            let _: Query<GameScore> = try relation.query()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.containedIn([.unknownError]))\n        }\n\n        // Wrong child for the relation, should throw\n        relation.key = \"naw\"\n        do {\n            let _: Query<GameScore> = try relation.query()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.containedIn([.unknownError]))\n        }\n\n        relation.key = \"levels\"\n        do {\n            let query: Query<Level> = try relation.query()\n            // swiftlint:disable:next line_length\n            let expected = \"{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{\\\"$relatedTo\\\":{\\\"key\\\":\\\"levels\\\",\\\"object\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"hello\\\"}}}}\"\n            let encoded = try ParseCoding.jsonEncoder().encode(query)\n            let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n            XCTAssertEqual(decoded, expected)\n\n            let query2: Query<Level> = try relation.query(\"wow\")\n            // swiftlint:disable:next line_length\n            let expected2 = \"{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{\\\"$relatedTo\\\":{\\\"key\\\":\\\"wow\\\",\\\"object\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"hello\\\"}}}}\"\n            let encoded2 = try ParseCoding.jsonEncoder().encode(query2)\n            let decoded2 = try XCTUnwrap(String(data: encoded2, encoding: .utf8))\n            XCTAssertEqual(decoded2, expected2)\n\n            guard let query3 = try level.relation?.query(\"levels\", parent: score) else {\n                XCTFail(\"Should have unwrapped\")\n                return\n            }\n            // swiftlint:disable:next line_length\n            let expected3 = \"{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{\\\"$relatedTo\\\":{\\\"key\\\":\\\"levels\\\",\\\"object\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"hello\\\"}}}}\"\n            let encoded3 = try ParseCoding.jsonEncoder().encode(query3)\n            let decoded3 = try XCTUnwrap(String(data: encoded3, encoding: .utf8))\n            XCTAssertEqual(decoded3, expected3)\n        } catch {\n            XCTFail(\"Should not have thrown error\")\n        }\n    }\n\n    func testQueryNoObjectId() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"hello\"\n        score.objectId = objectId\n\n        var relation = try ParseRelation(parent: score, key: \"yolo\")\n        relation.parent = nil // This will happen with decoded ParseRelations\n\n        var level = Level(level: 1)\n        level.objectId = \"nice\"\n        relation.className = level.className\n\n        // Should not produce a relation without an objectId.\n        do {\n            let _: Query<Level> = try relation.query()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.containedIn([.unknownError]))\n        }\n        do {\n            let _: Query<Level> = try relation.query(\"yolo\")\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.containedIn([.unknownError]))\n        }\n    }\n\n    func testQueryStoredRelationParentSelf() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"hello\"\n        score.objectId = objectId\n\n        var relation = try ParseRelation(parent: score)\n        relation.parent = nil // This will happen with decoded ParseRelations\n\n        var level = Level(level: 1)\n        level.objectId = \"nice\"\n        relation.className = level.className\n\n        do {\n            let usableStoredRelation = try score.relation(relation, key: \"levels\")\n            let query: Query<Level> = try usableStoredRelation.query()\n            // swiftlint:disable:next line_length\n            let expected = \"{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{\\\"$relatedTo\\\":{\\\"key\\\":\\\"levels\\\",\\\"object\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"hello\\\"}}}}\"\n            let encoded = try ParseCoding.jsonEncoder().encode(query)\n            let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n            XCTAssertEqual(decoded, expected)\n        } catch {\n            XCTFail(\"Should not have thrown error\")\n        }\n    }\n\n    func testQueryStoredRelation() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"hello\"\n        score.objectId = objectId\n\n        var score2 = GameScore2(points: 15)\n        let objectId2 = \"yolo\"\n        score2.objectId = objectId2\n\n        var relation = try ParseRelation(parent: score2)\n        relation.parent = nil // This will happen with decoded ParseRelations\n\n        var level = Level(level: 1)\n        level.objectId = \"nice\"\n        relation.className = level.className\n\n        XCTAssertThrowsError(try score.relation(nil, key: \"levels\", with: score2))\n\n        do {\n            let usableStoredRelation = try score.relation(relation, key: \"levels\", with: score2)\n            let query: Query<Level> = try usableStoredRelation.query()\n            // swiftlint:disable:next line_length\n            let expected = \"{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{\\\"$relatedTo\\\":{\\\"key\\\":\\\"levels\\\",\\\"object\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore2\\\",\\\"objectId\\\":\\\"yolo\\\"}}}}\"\n            let encoded = try ParseCoding.jsonEncoder().encode(query)\n            let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n            XCTAssertEqual(decoded, expected)\n        } catch {\n            XCTFail(\"Should not have thrown error\")\n        }\n    }\n\n    func testQueryStatic() throws {\n        var score = GameScore(points: 10)\n        let objectId = \"hello\"\n        score.objectId = objectId\n\n        let query = Level.queryRelations(\"levels\", parent: try score.toPointer())\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{\\\"$relatedTo\\\":{\\\"key\\\":\\\"levels\\\",\\\"object\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"hello\\\"}}}}\"\n        let encoded = try ParseCoding.jsonEncoder().encode(query)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n\n        let query2 = try Level.queryRelations(\"levels\", parent: score)\n        // swiftlint:disable:next line_length\n        let expected2 = \"{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{\\\"$relatedTo\\\":{\\\"key\\\":\\\"levels\\\",\\\"object\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"GameScore\\\",\\\"objectId\\\":\\\"hello\\\"}}}}\"\n        let encoded2 = try ParseCoding.jsonEncoder().encode(query2)\n        let decoded2 = try XCTUnwrap(String(data: encoded2, encoding: .utf8))\n        XCTAssertEqual(decoded2, expected2)\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseRoleTests.swift",
    "content": "//\n//  ParseRoleTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/18/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseRoleTests: XCTestCase {\n    struct GameScore: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int\n        var members = [String]()\n        var levels: [String]?\n\n        //custom initializers\n        init() {\n            self.points = 5\n        }\n\n        init(points: Int) {\n            self.points = points\n        }\n    }\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n    }\n\n    struct Role<RoleUser: ParseUser>: ParseRole {\n\n        // required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // provided by Role\n        var name: String?\n    }\n\n    struct Level: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        //: Your own properties\n        var level: Int\n        var members = [String]()\n\n        //custom initializers\n        init() {\n            self.level = 5\n        }\n\n        init(level: Int) {\n            self.level = level\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testName() throws {\n        let role1 = try Role<User>(name: \"Hello9_- \")\n        let role2 = try Role<User>(name: \"Hello10_- \", acl: ParseACL())\n        let roles = [role1: \"hello\",\n                     role2: \"world\"]\n        XCTAssertEqual(role1, role1)\n        XCTAssertNotEqual(role1, role2)\n        XCTAssertEqual(roles[role1], \"hello\")\n        XCTAssertEqual(roles[role2], \"world\")\n        XCTAssertThrowsError(try Role<User>(name: \"Hello9!\"))\n        XCTAssertThrowsError(try Role<User>(name: \"Hello10!\", acl: ParseACL()))\n    }\n\n    func testEndPoint() throws {\n        var role = try Role<User>(name: \"Administrator\")\n        XCTAssertEqual(role.endpoint.urlComponent, \"/roles\")\n        role.objectId = \"me\"\n        XCTAssertEqual(role.endpoint.urlComponent, \"/roles/me\")\n    }\n\n    func testUserAddIncorrectClassKeyError() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        role.objectId = \"yolo\"\n        guard let userRoles = role.users else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        var level = Level(level: 1)\n        level.objectId = \"nice\"\n        XCTAssertThrowsError(try userRoles.add(\"users\", objects: [level]))\n    }\n\n    func testUserAddIncorrectKeyError() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        role.objectId = \"yolo\"\n        guard let userRoles = role.users else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        var user = User()\n        user.objectId = \"heel\"\n        XCTAssertThrowsError(try userRoles.add(\"level\", objects: [user]))\n    }\n\n    func testUserAddOperation() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        XCTAssertNil(role.users) // Should not produce a relation without an objectId.\n        role.objectId = \"yolo\"\n        guard let userRoles = role.users else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let expected = \"{\\\"__type\\\":\\\"Relation\\\",\\\"className\\\":\\\"_User\\\"}\"\n        let encoded = try ParseCoding.jsonEncoder().encode(userRoles)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n        XCTAssertEqual(userRoles.key, \"users\")\n\n        var user = User()\n        user.objectId = \"heel\"\n        let operation = try userRoles.add([user])\n\n        // swiftlint:disable:next line_length\n        let expected2 = \"{\\\"users\\\":{\\\"__op\\\":\\\"AddRelation\\\",\\\"objects\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"_User\\\",\\\"objectId\\\":\\\"heel\\\"}]}}\"\n        let encoded2 = try ParseCoding.jsonEncoder().encode(operation)\n        let decoded2 = try XCTUnwrap(String(data: encoded2, encoding: .utf8))\n        XCTAssertEqual(decoded2, expected2)\n    }\n\n    func testUserAddOperationNoKey() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        role.objectId = \"yolo\"\n        guard var userRoles = role.users else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        userRoles.key = nil\n        let expected = \"{\\\"__type\\\":\\\"Relation\\\",\\\"className\\\":\\\"_User\\\"}\"\n        let encoded = try ParseCoding.jsonEncoder().encode(userRoles)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n        XCTAssertNil(userRoles.key)\n\n        var user = User()\n        user.objectId = \"heel\"\n        let operation = try userRoles.add([user])\n\n        // swiftlint:disable:next line_length\n        let expected2 = \"{\\\"users\\\":{\\\"__op\\\":\\\"AddRelation\\\",\\\"objects\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"_User\\\",\\\"objectId\\\":\\\"heel\\\"}]}}\"\n        let encoded2 = try ParseCoding.jsonEncoder().encode(operation)\n        let decoded2 = try XCTUnwrap(String(data: encoded2, encoding: .utf8))\n        XCTAssertEqual(decoded2, expected2)\n    }\n\n    func testUserRemoveIncorrectClassKeyError() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        role.objectId = \"yolo\"\n        guard let userRoles = role.users else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        var level = Level(level: 1)\n        level.objectId = \"nice\"\n        XCTAssertThrowsError(try userRoles.remove(\"users\", objects: [level]))\n    }\n\n    func testUserRemoveIncorrectKeyError() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        role.objectId = \"yolo\"\n        guard let userRoles = role.users else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        var user = User()\n        user.objectId = \"heel\"\n        XCTAssertThrowsError(try userRoles.remove(\"level\", objects: [user]))\n    }\n\n    func testUserRemoveOperation() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        role.objectId = \"yolo\"\n        guard let userRoles = role.users else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let expected = \"{\\\"__type\\\":\\\"Relation\\\",\\\"className\\\":\\\"_User\\\"}\"\n        let encoded = try ParseCoding.jsonEncoder().encode(userRoles)\n        let decoded = String(data: encoded, encoding: .utf8)\n        XCTAssertEqual(decoded, expected)\n        XCTAssertEqual(userRoles.key, \"users\")\n\n        var user = User()\n        user.objectId = \"heel\"\n        let operation = try userRoles.remove([user])\n\n        // swiftlint:disable:next line_length\n        let expected2 = \"{\\\"users\\\":{\\\"__op\\\":\\\"RemoveRelation\\\",\\\"objects\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"_User\\\",\\\"objectId\\\":\\\"heel\\\"}]}}\"\n        let encoded2 = try ParseCoding.jsonEncoder().encode(operation)\n        let decoded2 = try XCTUnwrap(try XCTUnwrap(String(data: encoded2, encoding: .utf8)))\n        XCTAssertEqual(decoded2, expected2)\n    }\n\n    func testUserRemoveOperationNoKey() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        role.objectId = \"yolo\"\n        guard var userRoles = role.users else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        userRoles.key = nil\n        let expected = \"{\\\"__type\\\":\\\"Relation\\\",\\\"className\\\":\\\"_User\\\"}\"\n        let encoded = try ParseCoding.jsonEncoder().encode(userRoles)\n        let decoded = String(data: encoded, encoding: .utf8)\n        XCTAssertEqual(decoded, expected)\n        XCTAssertNil(userRoles.key)\n\n        var user = User()\n        user.objectId = \"heel\"\n        let operation = try userRoles.remove([user])\n\n        // swiftlint:disable:next line_length\n        let expected2 = \"{\\\"users\\\":{\\\"__op\\\":\\\"RemoveRelation\\\",\\\"objects\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"_User\\\",\\\"objectId\\\":\\\"heel\\\"}]}}\"\n        let encoded2 = try ParseCoding.jsonEncoder().encode(operation)\n        let decoded2 = try XCTUnwrap(try XCTUnwrap(String(data: encoded2, encoding: .utf8)))\n        XCTAssertEqual(decoded2, expected2)\n    }\n\n    func testRoleAddIncorrectClassKeyError() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        role.objectId = \"yolo\"\n        guard let roles = role.roles else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        var level = Level(level: 1)\n        level.objectId = \"nice\"\n        XCTAssertThrowsError(try roles.add(\"roles\", objects: [level]))\n    }\n\n    func testRoleAddIncorrectKeyError() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        role.objectId = \"yolo\"\n        guard let roles = role.roles else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        var newRole = try Role<User>(name: \"Moderator\", acl: acl)\n        newRole.objectId = \"heel\"\n        XCTAssertThrowsError(try roles.add(\"level\", objects: [newRole]))\n    }\n\n    func testRoleAddOperation() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        XCTAssertNil(role.roles) // Should not produce a relation without an objectId.\n        role.objectId = \"yolo\"\n        guard let roles = role.roles else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let expected = \"{\\\"__type\\\":\\\"Relation\\\",\\\"className\\\":\\\"_Role\\\"}\"\n        let encoded = try ParseCoding.jsonEncoder().encode(roles)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n        XCTAssertEqual(roles.key, \"roles\")\n\n        var newRole = try Role<User>(name: \"Moderator\", acl: acl)\n        newRole.objectId = \"heel\"\n        let operation = try roles.add([newRole])\n\n        // swiftlint:disable:next line_length\n        let expected2 = \"{\\\"roles\\\":{\\\"__op\\\":\\\"AddRelation\\\",\\\"objects\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"_Role\\\",\\\"objectId\\\":\\\"heel\\\"}]}}\"\n        let encoded2 = try ParseCoding.jsonEncoder().encode(operation)\n        let decoded2 = try XCTUnwrap(String(data: encoded2, encoding: .utf8))\n        XCTAssertEqual(decoded2, expected2)\n    }\n\n    func testRoleAddOperationSaveSynchronous() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        role.createdAt = Date()\n        role.updatedAt = Date()\n        XCTAssertNil(role.roles) // Should not produce a relation without an objectId.\n        role.objectId = \"yolo\"\n        guard let roles = role.roles else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        var newRole = try Role<User>(name: \"Moderator\", acl: acl)\n        newRole.objectId = \"heel\"\n        let operation = try roles.add([newRole])\n\n        var serverResponse = role\n        serverResponse.createdAt = nil\n        serverResponse.updatedAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n            //Get dates in correct format from ParseDecoding strategy\n            serverResponse = try serverResponse.getDecoder().decode(Role<User>.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let updatedRole = try operation.save()\n        XCTAssertEqual(updatedRole.updatedAt, serverResponse.updatedAt)\n        XCTAssertTrue(updatedRole.hasSameObjectId(as: serverResponse))\n    }\n\n    func testRoleAddOperationSaveSynchronousError() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        role.createdAt = Date()\n        role.updatedAt = Date()\n        XCTAssertNil(role.roles) // Should not produce a relation without an objectId.\n        role.objectId = \"yolo\"\n        guard let roles = role.roles else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        var newRole = try Role<User>(name: \"Moderator\", acl: acl)\n        newRole.objectId = \"heel\"\n        var operation = try roles.add([newRole])\n        operation.target.objectId = nil\n\n        do {\n            _ = try operation.save()\n            XCTFail(\"Should have failed\")\n        } catch {\n            XCTAssertTrue(error.containedIn([.missingObjectId]))\n        }\n    }\n\n    func testRoleAddOperationSaveSynchronousCustomObjectId() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        Parse.configuration.isRequiringCustomObjectIds = true\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        role.createdAt = Date()\n        role.updatedAt = Date()\n        XCTAssertNil(role.roles) // Should not produce a relation without an objectId.\n        role.objectId = \"yolo\"\n        guard let roles = role.roles else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        var newRole = try Role<User>(name: \"Moderator\", acl: acl)\n        newRole.objectId = \"heel\"\n        let operation = try roles.add([newRole])\n\n        var serverResponse = role\n        serverResponse.createdAt = nil\n        serverResponse.updatedAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n            //Get dates in correct format from ParseDecoding strategy\n            serverResponse = try serverResponse.getDecoder().decode(Role<User>.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let updatedRole = try operation.save()\n        XCTAssertEqual(updatedRole.updatedAt, serverResponse.updatedAt)\n        XCTAssertTrue(updatedRole.hasSameObjectId(as: serverResponse))\n    }\n\n    func testRoleAddOperationSaveSynchronousCustomObjectIdError() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        Parse.configuration.isRequiringCustomObjectIds = true\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        role.createdAt = Date()\n        role.updatedAt = Date()\n        XCTAssertNil(role.roles) // Should not produce a relation without an objectId.\n        role.objectId = \"yolo\"\n        guard let roles = role.roles else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        var newRole = try Role<User>(name: \"Moderator\", acl: acl)\n        newRole.objectId = \"heel\"\n        var operation = try roles.add([newRole])\n        operation.target.objectId = nil\n\n        do {\n            _ = try operation.save()\n            XCTFail(\"Should have failed\")\n        } catch {\n            XCTAssertTrue(error.containedIn([.missingObjectId]))\n        }\n    }\n\n    func testRoleAddOperationSaveAsynchronous() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        role.createdAt = Date()\n        role.updatedAt = Date()\n        XCTAssertNil(role.roles) // Should not produce a relation without an objectId.\n        role.objectId = \"yolo\"\n        guard let roles = role.roles else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        var newRole = try Role<User>(name: \"Moderator\", acl: acl)\n        newRole.objectId = \"heel\"\n        let operation = try roles.add([newRole])\n\n        var serverResponse = role\n        serverResponse.createdAt = nil\n        serverResponse.updatedAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n            //Get dates in correct format from ParseDecoding strategy\n            serverResponse = try serverResponse.getDecoder().decode(Role<User>.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Save object1\")\n        operation.save { result in\n            switch result {\n            case .success(let updatedRole):\n                XCTAssertEqual(updatedRole.updatedAt, serverResponse.updatedAt)\n                XCTAssertTrue(updatedRole.hasSameObjectId(as: serverResponse))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testRoleAddOperationSaveAsynchronousError() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        Parse.configuration.isRequiringCustomObjectIds = true\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        role.createdAt = Date()\n        role.updatedAt = Date()\n        XCTAssertNil(role.roles) // Should not produce a relation without an objectId.\n        role.objectId = \"yolo\"\n        guard let roles = role.roles else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        var newRole = try Role<User>(name: \"Moderator\", acl: acl)\n        newRole.objectId = \"heel\"\n        var operation = try roles.add([newRole])\n        operation.target.objectId = nil\n\n        let expectation1 = XCTestExpectation(description: \"Save object1\")\n        operation.save { result in\n            switch result {\n            case .success:\n                XCTFail(\"Should have failed\")\n            case .failure(let error):\n                XCTAssertEqual(error.code, .missingObjectId)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testRoleAddOperationSaveAsynchronousCustomObjectId() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        Parse.configuration.isRequiringCustomObjectIds = true\n        XCTAssertEqual(Parse.configuration.isAllowingCustomObjectIds,\n                       Parse.configuration.isRequiringCustomObjectIds)\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        role.createdAt = Date()\n        role.updatedAt = Date()\n        XCTAssertNil(role.roles) // Should not produce a relation without an objectId.\n        role.objectId = \"yolo\"\n        guard let roles = role.roles else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        var newRole = try Role<User>(name: \"Moderator\", acl: acl)\n        newRole.objectId = \"heel\"\n        let operation = try roles.add([newRole])\n\n        var serverResponse = role\n        serverResponse.createdAt = nil\n        serverResponse.updatedAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n            //Get dates in correct format from ParseDecoding strategy\n            serverResponse = try serverResponse.getDecoder().decode(Role<User>.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Save object1\")\n        operation.save { result in\n            switch result {\n            case .success(let updatedRole):\n                XCTAssertEqual(updatedRole.updatedAt, serverResponse.updatedAt)\n                XCTAssertTrue(updatedRole.hasSameObjectId(as: serverResponse))\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testRoleAddOperationSaveAsynchronousCustomObjectIdError() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        role.createdAt = Date()\n        role.updatedAt = Date()\n        XCTAssertNil(role.roles) // Should not produce a relation without an objectId.\n        role.objectId = \"yolo\"\n        guard let roles = role.roles else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        var newRole = try Role<User>(name: \"Moderator\", acl: acl)\n        newRole.objectId = \"heel\"\n        var operation = try roles.add([newRole])\n        operation.target.objectId = nil\n\n        let expectation1 = XCTestExpectation(description: \"Save object1\")\n        operation.save { result in\n            switch result {\n            case .success:\n                XCTFail(\"Should have failed\")\n            case .failure(let error):\n                XCTAssertEqual(error.code, .missingObjectId)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testRoleAddOperationNoKey() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        role.objectId = \"yolo\"\n        guard var roles = role.roles else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        roles.key = nil\n        let expected = \"{\\\"__type\\\":\\\"Relation\\\",\\\"className\\\":\\\"_Role\\\"}\"\n        let encoded = try ParseCoding.jsonEncoder().encode(roles)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n        XCTAssertNil(roles.key)\n\n        var newRole = try Role<User>(name: \"Moderator\", acl: acl)\n        newRole.objectId = \"heel\"\n        let operation = try roles.add([newRole])\n\n        // swiftlint:disable:next line_length\n        let expected2 = \"{\\\"roles\\\":{\\\"__op\\\":\\\"AddRelation\\\",\\\"objects\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"_Role\\\",\\\"objectId\\\":\\\"heel\\\"}]}}\"\n        let encoded2 = try ParseCoding.jsonEncoder().encode(operation)\n        let decoded2 = try XCTUnwrap(String(data: encoded2, encoding: .utf8))\n        XCTAssertEqual(decoded2, expected2)\n    }\n\n    func testRoleRemoveIncorrectClassKeyError() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        role.objectId = \"yolo\"\n        guard let roles = role.roles else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        var level = Level(level: 1)\n        level.objectId = \"nice\"\n        XCTAssertThrowsError(try roles.remove(\"users\", objects: [level]))\n    }\n\n    func testRoleRemoveIncorrectKeyError() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        role.objectId = \"yolo\"\n        guard let roles = role.roles else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        var user = User()\n        user.objectId = \"heel\"\n        XCTAssertThrowsError(try roles.remove(\"level\", objects: [user]))\n    }\n\n    func testRoleRemoveOperation() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        role.objectId = \"yolo\"\n        guard let roles = role.roles else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let expected = \"{\\\"__type\\\":\\\"Relation\\\",\\\"className\\\":\\\"_Role\\\"}\"\n        let encoded = try ParseCoding.jsonEncoder().encode(roles)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n        XCTAssertEqual(roles.key, \"roles\")\n\n        var newRole = try Role<User>(name: \"Moderator\", acl: acl)\n        newRole.objectId = \"heel\"\n        let operation = try roles.remove([newRole])\n\n        // swiftlint:disable:next line_length\n        let expected2 = \"{\\\"roles\\\":{\\\"__op\\\":\\\"RemoveRelation\\\",\\\"objects\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"_Role\\\",\\\"objectId\\\":\\\"heel\\\"}]}}\"\n        let encoded2 = try ParseCoding.jsonEncoder().encode(operation)\n        let decoded2 = try XCTUnwrap(String(data: encoded2, encoding: .utf8))\n        XCTAssertEqual(decoded2, expected2)\n    }\n\n    func testRoleRemoveOperationNoKey() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        role.objectId = \"yolo\"\n        guard var roles = role.roles else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        roles.key = nil\n        let expected = \"{\\\"__type\\\":\\\"Relation\\\",\\\"className\\\":\\\"_Role\\\"}\"\n        let encoded = try ParseCoding.jsonEncoder().encode(roles)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n        XCTAssertNil(roles.key)\n\n        var newRole = try Role<User>(name: \"Moderator\", acl: acl)\n        newRole.objectId = \"heel\"\n        let operation = try roles.remove([newRole])\n\n        // swiftlint:disable:next line_length\n        let expected2 = \"{\\\"roles\\\":{\\\"__op\\\":\\\"RemoveRelation\\\",\\\"objects\\\":[{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"_Role\\\",\\\"objectId\\\":\\\"heel\\\"}]}}\"\n        let encoded2 = try ParseCoding.jsonEncoder().encode(operation)\n        let decoded2 = try XCTUnwrap(String(data: encoded2, encoding: .utf8))\n        XCTAssertEqual(decoded2, expected2)\n    }\n\n    func testUserQuery() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        var user = User()\n        user.objectId = \"heel\"\n\n        var userRoles = try Role<User>(name: \"Administrator\", acl: acl)\n        XCTAssertThrowsError(try userRoles.queryUsers())\n        userRoles.objectId = \"yolo\"\n        let query = try userRoles.queryUsers()\n\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{\\\"$relatedTo\\\":{\\\"key\\\":\\\"users\\\",\\\"object\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"_Role\\\",\\\"objectId\\\":\\\"yolo\\\"}}}}\"\n        let encoded = try ParseCoding.jsonEncoder().encode(query)\n        let decoded = try XCTUnwrap(String(data: encoded, encoding: .utf8))\n        XCTAssertEqual(decoded, expected)\n    }\n\n    func testRoleQuery() throws {\n        var acl = ParseACL()\n        acl.publicWrite = false\n        acl.publicRead = true\n\n        var role = try Role<User>(name: \"Administrator\", acl: acl)\n        XCTAssertThrowsError(try role.queryRoles())\n        role.objectId = \"yolo\"\n\n        var newRole = try Role<User>(name: \"Moderator\", acl: acl)\n        newRole.objectId = \"heel\"\n        let query: Query<Role> = try role.queryRoles()\n\n        // swiftlint:disable:next line_length\n        let expected2 = \"{\\\"_method\\\":\\\"GET\\\",\\\"limit\\\":100,\\\"skip\\\":0,\\\"where\\\":{\\\"$relatedTo\\\":{\\\"key\\\":\\\"roles\\\",\\\"object\\\":{\\\"__type\\\":\\\"Pointer\\\",\\\"className\\\":\\\"_Role\\\",\\\"objectId\\\":\\\"yolo\\\"}}}}\"\n        let encoded2 = try ParseCoding.jsonEncoder().encode(query)\n        let decoded2 = try XCTUnwrap(String(data: encoded2, encoding: .utf8))\n        XCTAssertEqual(decoded2, expected2)\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseSchemaAsyncTests.swift",
    "content": "//\n//  ParseSchemaAsyncTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 5/29/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseSchemaAsyncTests: XCTestCase { // swiftlint:disable:this type_body_length\n    struct GameScore: ParseObject, ParseQueryScorable {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var score: Double?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int\n        var isCounts: Bool?\n\n        //: a custom initializer\n        init() {\n            self.points = 5\n        }\n        init(points: Int) {\n            self.points = points\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func createDummySchema() -> ParseSchema<GameScore> {\n        ParseSchema<GameScore>()\n            .addField(\"a\",\n                      type: .string,\n                      options: ParseFieldOptions<String>(required: false, defauleValue: nil))\n            .addField(\"b\",\n                      type: .number,\n                      options: ParseFieldOptions<Int>(required: false, defauleValue: 2))\n            .deleteField(\"c\")\n            .addIndex(\"hello\", field: \"world\", index: \"yolo\")\n    }\n\n    @MainActor\n    func testCreate() async throws {\n\n        let schema = createDummySchema()\n\n        var serverResponse = schema\n        serverResponse.indexes = schema.pendingIndexes\n        serverResponse.pendingIndexes.removeAll()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let saved = try await schema.create()\n        XCTAssertEqual(saved.fields, serverResponse.fields)\n        XCTAssertEqual(saved.indexes, serverResponse.indexes)\n        XCTAssertEqual(saved.classLevelPermissions, serverResponse.classLevelPermissions)\n        XCTAssertEqual(saved.className, serverResponse.className)\n        XCTAssertTrue(saved.pendingIndexes.isEmpty)\n    }\n\n    @MainActor\n    func testCreateError() async throws {\n\n        let schema = createDummySchema()\n\n        let parseError = ParseError(code: .invalidSchemaOperation,\n                                    message: \"Problem with schema\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(parseError)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        do {\n            _ = try await schema.create()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(.invalidSchemaOperation))\n        }\n    }\n\n    @MainActor\n    func testUpdate() async throws {\n\n        let schema = createDummySchema()\n\n        var serverResponse = schema\n        serverResponse.indexes = schema.pendingIndexes\n        serverResponse.pendingIndexes.removeAll()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let saved = try await schema.update()\n        XCTAssertEqual(saved.fields, serverResponse.fields)\n        XCTAssertEqual(saved.indexes, serverResponse.indexes)\n        XCTAssertEqual(saved.classLevelPermissions, serverResponse.classLevelPermissions)\n        XCTAssertEqual(saved.className, serverResponse.className)\n        XCTAssertTrue(saved.pendingIndexes.isEmpty)\n    }\n\n    @MainActor\n    func testUpdateOldIndexes() async throws {\n\n        var schema = createDummySchema()\n        schema.indexes = [\n            \"meta\": [\"world\": \"peace\"],\n            \"stop\": [\"being\": \"greedy\"]\n        ]\n        schema.pendingIndexes.removeAll()\n\n        let serverResponse = schema\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let saved = try await schema.update()\n        XCTAssertEqual(saved.fields, serverResponse.fields)\n        XCTAssertEqual(saved.indexes, serverResponse.indexes)\n        XCTAssertEqual(saved.classLevelPermissions, serverResponse.classLevelPermissions)\n        XCTAssertEqual(saved.className, serverResponse.className)\n        XCTAssertTrue(saved.pendingIndexes.isEmpty)\n    }\n\n    @MainActor\n    func testUpdateError() async throws {\n\n        let schema = createDummySchema()\n\n        let parseError = ParseError(code: .invalidSchemaOperation,\n                                    message: \"Problem with schema\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(parseError)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        do {\n            _ = try await schema.update()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(.invalidSchemaOperation))\n        }\n    }\n\n    @MainActor\n    func testFetch() async throws {\n\n        let schema = createDummySchema()\n\n        var serverResponse = schema\n        serverResponse.indexes = schema.pendingIndexes\n        serverResponse.pendingIndexes.removeAll()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let saved = try await schema.fetch()\n        XCTAssertEqual(saved.fields, serverResponse.fields)\n        XCTAssertEqual(saved.indexes, serverResponse.indexes)\n        XCTAssertEqual(saved.classLevelPermissions, serverResponse.classLevelPermissions)\n        XCTAssertEqual(saved.className, serverResponse.className)\n        XCTAssertTrue(saved.pendingIndexes.isEmpty)\n    }\n\n    @MainActor\n    func testFetchError() async throws {\n\n        let schema = createDummySchema()\n\n        let parseError = ParseError(code: .invalidSchemaOperation,\n                                    message: \"Problem with schema\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(parseError)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        do {\n            _ = try await schema.fetch()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(.invalidSchemaOperation))\n        }\n    }\n\n    @MainActor\n    func testPurge() async throws {\n\n        let schema = createDummySchema()\n\n        let serverResponse = NoBody()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        try await schema.purge()\n    }\n\n    @MainActor\n    func testPurgeError() async throws {\n\n        let schema = createDummySchema()\n\n        let parseError = ParseError(code: .invalidSchemaOperation,\n                                    message: \"Problem with schema\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(parseError)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        do {\n            _ = try await schema.purge()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(.invalidSchemaOperation))\n        }\n    }\n\n    @MainActor\n    func testDelete() async throws {\n\n        let schema = createDummySchema()\n\n        let serverResponse = NoBody()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        try await schema.delete()\n    }\n\n    @MainActor\n    func testDeleteError() async throws {\n\n        let schema = createDummySchema()\n\n        let parseError = ParseError(code: .invalidSchemaOperation,\n                                    message: \"Problem with schema\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(parseError)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        do {\n            _ = try await schema.delete()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            XCTAssertTrue(error.equalsTo(.invalidSchemaOperation))\n        }\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseSchemaCombineTests.swift",
    "content": "//\n//  ParseSchemaCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 5/29/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseSchemaCombineTests: XCTestCase { // swiftlint:disable:this type_body_length\n    struct GameScore: ParseObject, ParseQueryScorable {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var score: Double?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int\n        var isCounts: Bool?\n\n        //: a custom initializer\n        init() {\n            self.points = 5\n        }\n        init(points: Int) {\n            self.points = points\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func createDummySchema() -> ParseSchema<GameScore> {\n        ParseSchema<GameScore>()\n            .addField(\"a\",\n                      type: .string,\n                      options: ParseFieldOptions<String>(required: false, defauleValue: nil))\n            .addField(\"b\",\n                      type: .number,\n                      options: ParseFieldOptions<Int>(required: false, defauleValue: 2))\n            .deleteField(\"c\")\n            .addIndex(\"hello\", field: \"world\", index: \"yolo\")\n    }\n\n    func testCreate() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let schema = createDummySchema()\n\n        var serverResponse = schema\n        serverResponse.indexes = schema.pendingIndexes\n        serverResponse.pendingIndexes.removeAll()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Save schema\")\n        let publisher = schema.createPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            XCTAssertEqual(saved.fields, serverResponse.fields)\n            XCTAssertEqual(saved.indexes, serverResponse.indexes)\n            XCTAssertEqual(saved.classLevelPermissions, serverResponse.classLevelPermissions)\n            XCTAssertEqual(saved.className, serverResponse.className)\n            XCTAssertTrue(saved.pendingIndexes.isEmpty)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testCreateError() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let schema = createDummySchema()\n\n        let parseError = ParseError(code: .invalidSchemaOperation,\n                                    message: \"Problem with schema\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(parseError)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Create schema\")\n        let publisher = schema.createPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case .finished = result {\n                    XCTFail(\"Should have thrown ParseError\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown ParseError\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUpdate() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let schema = createDummySchema()\n\n        var serverResponse = schema\n        serverResponse.indexes = schema.pendingIndexes\n        serverResponse.pendingIndexes.removeAll()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Update schema\")\n        let publisher = schema.updatePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            XCTAssertEqual(saved.fields, serverResponse.fields)\n            XCTAssertEqual(saved.indexes, serverResponse.indexes)\n            XCTAssertEqual(saved.classLevelPermissions, serverResponse.classLevelPermissions)\n            XCTAssertEqual(saved.className, serverResponse.className)\n            XCTAssertTrue(saved.pendingIndexes.isEmpty)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUpdateError() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let schema = createDummySchema()\n\n        let parseError = ParseError(code: .invalidSchemaOperation,\n                                    message: \"Problem with schema\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(parseError)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Update schema\")\n        let publisher = schema.updatePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case .finished = result {\n                    XCTFail(\"Should have thrown ParseError\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown ParseError\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testFetch() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let schema = createDummySchema()\n\n        var serverResponse = schema\n        serverResponse.indexes = schema.pendingIndexes\n        serverResponse.pendingIndexes.removeAll()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Fetch schema\")\n        let publisher = schema.fetchPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            XCTAssertEqual(saved.fields, serverResponse.fields)\n            XCTAssertEqual(saved.indexes, serverResponse.indexes)\n            XCTAssertEqual(saved.classLevelPermissions, serverResponse.classLevelPermissions)\n            XCTAssertEqual(saved.className, serverResponse.className)\n            XCTAssertTrue(saved.pendingIndexes.isEmpty)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testFetchError() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let schema = createDummySchema()\n\n        let parseError = ParseError(code: .invalidSchemaOperation,\n                                    message: \"Problem with schema\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(parseError)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Fetch schema\")\n        let publisher = schema.fetchPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case .finished = result {\n                    XCTFail(\"Should have thrown ParseError\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown ParseError\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testPurge() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let schema = createDummySchema()\n\n        var serverResponse = schema\n        serverResponse.indexes = schema.pendingIndexes\n        serverResponse.pendingIndexes.removeAll()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Purge schema\")\n        let publisher = schema.purgePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testPurgeError() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let schema = createDummySchema()\n\n        let parseError = ParseError(code: .invalidSchemaOperation,\n                                    message: \"Problem with schema\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(parseError)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Purge schema\")\n        let publisher = schema.purgePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case .finished = result {\n                    XCTFail(\"Should have thrown ParseError\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown ParseError\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDelete() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let schema = createDummySchema()\n\n        var serverResponse = schema\n        serverResponse.indexes = schema.pendingIndexes\n        serverResponse.pendingIndexes.removeAll()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Delete schema\")\n        let publisher = schema.deletePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDeleteError() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let schema = createDummySchema()\n\n        let parseError = ParseError(code: .invalidSchemaOperation,\n                                    message: \"Problem with schema\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(parseError)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Delete schema\")\n        let publisher = schema.deletePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case .finished = result {\n                    XCTFail(\"Should have thrown ParseError\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown ParseError\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseSchemaTests.swift",
    "content": "//\n//  ParseSchemaTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 5/29/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseSchemaTests: XCTestCase { // swiftlint:disable:this type_body_length\n    struct GameScore: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var score: Double?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int?\n\n        //: a custom initializer\n        init() { }\n        init(points: Int) {\n            self.points = points\n        }\n    }\n\n    struct GameScore2: ParseObject {\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var score: Double?\n        var originalData: Data?\n\n        //: Your own properties\n        var points: Int?\n\n        //: a custom initializer\n        init() { }\n        init(points: Int) {\n            self.points = points\n        }\n        init(objectId: String, points: Int) {\n            self.objectId = objectId\n            self.points = points\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func createDummySchema() -> ParseSchema<GameScore> {\n        let fields = Set<String>([\"world\"])\n        let clp = ParseCLP()\n            .setPointerFields(fields, on: .create)\n            .setWriteAccessPublic(true, canAddField: true)\n\n        let schema = ParseSchema<GameScore>(classLevelPermissions: clp)\n            .addField(\"a\",\n                      type: .string,\n                      options: ParseFieldOptions<String>(required: false, defauleValue: nil))\n            .addField(\"b\",\n                      type: .number,\n                      options: ParseFieldOptions<Int>(required: false, defauleValue: 2))\n            .deleteField(\"c\")\n            .addIndex(\"hello\", field: \"world\", index: \"yolo\")\n        return schema\n    }\n\n    func testInitializer() throws {\n        let clp = ParseCLP(requiresAuthentication: true, publicAccess: true)\n        let schema = ParseSchema<GameScore>(classLevelPermissions: clp)\n        XCTAssertEqual(schema.className, GameScore.className)\n        XCTAssertEqual(ParseSchema<GameScore>.className, GameScore.className)\n        XCTAssertEqual(schema.classLevelPermissions, clp)\n    }\n\n    func testParseFieldOptionsEncode() {\n        let options = ParseFieldOptions<Int>(required: false, defauleValue: 2)\n        XCTAssertEqual(options.description,\n                       \"{\\\"defaultValue\\\":2,\\\"required\\\":false}\")\n    }\n\n    func testSchemaEncode() throws {\n        let schema = createDummySchema()\n        // swiftlint:disable:next line_length\n        let expected = \"{\\\"classLevelPermissions\\\":{\\\"addField\\\":{\\\"*\\\":true},\\\"create\\\":{\\\"*\\\":true,\\\"pointerFields\\\":[\\\"world\\\"]},\\\"delete\\\":{\\\"*\\\":true},\\\"update\\\":{\\\"*\\\":true}},\\\"className\\\":\\\"GameScore\\\",\\\"fields\\\":{\\\"a\\\":{\\\"required\\\":false,\\\"type\\\":\\\"String\\\"},\\\"b\\\":{\\\"defaultValue\\\":2,\\\"required\\\":false,\\\"type\\\":\\\"Number\\\"},\\\"c\\\":{\\\"__op\\\":\\\"Delete\\\"}}}\"\n        XCTAssertEqual(schema.description, expected)\n    }\n\n    func testAddField() throws {\n        let options = try ParseFieldOptions<GameScore2>(required: false, defauleValue: nil)\n        let schema = try ParseSchema<GameScore>()\n            .addField(\"a\",\n                      type: .string,\n                      options: ParseFieldOptions<String>(required: false, defauleValue: nil))\n            .addField(\"b\",\n                      type: .pointer,\n                      options: options)\n            .addField(\"c\",\n                      type: .date,\n                      options: ParseFieldOptions<String>(required: false, defauleValue: nil))\n            .addField(\"d\",\n                      type: .acl,\n                      options: ParseFieldOptions<String>(required: false, defauleValue: nil))\n            .addField(\"e\",\n                      type: .array,\n                      options: ParseFieldOptions<String>(required: false, defauleValue: nil))\n            .addField(\"f\",\n                      type: .bytes,\n                      options: ParseFieldOptions<String>(required: false, defauleValue: nil))\n            .addField(\"g\",\n                      type: .object,\n                      options: ParseFieldOptions<String>(required: false, defauleValue: nil))\n            .addField(\"h\",\n                      type: .file,\n                      options: ParseFieldOptions<String>(required: false, defauleValue: nil))\n            .addField(\"i\",\n                      type: .geoPoint,\n                      options: ParseFieldOptions<String>(required: false, defauleValue: nil))\n            .addField(\"j\",\n                      type: .relation,\n                      options: options)\n            .addField(\"k\",\n                      type: .polygon,\n                      options: ParseFieldOptions<String>(required: false, defauleValue: nil))\n            .addField(\"l\",\n                      type: .boolean,\n                      options: ParseFieldOptions<String>(required: false, defauleValue: nil))\n            .addField(\"m\",\n                      type: .number,\n                      options: ParseFieldOptions<String>(required: false, defauleValue: nil))\n        XCTAssertEqual(schema.fields?[\"a\"]?.type, .string)\n        XCTAssertEqual(schema.fields?[\"b\"]?.type, .pointer)\n        XCTAssertEqual(schema.fields?[\"c\"]?.type, .date)\n        XCTAssertEqual(schema.fields?[\"d\"]?.type, .acl)\n        XCTAssertEqual(schema.fields?[\"e\"]?.type, .array)\n        XCTAssertEqual(schema.fields?[\"f\"]?.type, .bytes)\n        XCTAssertEqual(schema.fields?[\"g\"]?.type, .object)\n        XCTAssertEqual(schema.fields?[\"h\"]?.type, .file)\n        XCTAssertEqual(schema.fields?[\"i\"]?.type, .geoPoint)\n        XCTAssertEqual(schema.fields?[\"j\"]?.type, .relation)\n        XCTAssertEqual(schema.fields?[\"k\"]?.type, .polygon)\n        XCTAssertEqual(schema.fields?[\"l\"]?.type, .boolean)\n        XCTAssertEqual(schema.fields?[\"m\"]?.type, .number)\n    }\n\n    func testAddFieldWrongOptionsError() throws {\n        let options = try ParseFieldOptions<GameScore2>(required: false, defauleValue: nil)\n        XCTAssertThrowsError(try ParseSchema<GameScore>()\n            .addField(\"b\",\n                      type: .string,\n                      options: options))\n    }\n\n    func testGetFields() throws {\n        let schema = ParseSchema<GameScore>()\n            .addField(\"a\",\n                      type: .string,\n                      options: ParseFieldOptions<String>(required: false, defauleValue: nil))\n            .addField(\"b\",\n                      type: .number,\n                      options: ParseFieldOptions<Int>(required: false, defauleValue: 2))\n        let fields = schema.getFields()\n        XCTAssertEqual(fields[\"a\"], \"{\\\"required\\\":false,\\\"type\\\":\\\"String\\\"}\")\n        XCTAssertEqual(fields[\"b\"], \"{\\\"defaultValue\\\":2,\\\"required\\\":false,\\\"type\\\":\\\"Number\\\"}\")\n    }\n\n    func testAddPointer() throws {\n        let gameScore2 = GameScore2(objectId: \"yolo\", points: 12)\n        let options = try ParseFieldOptions<GameScore2>(required: false, defauleValue: gameScore2)\n        let schema = ParseSchema<GameScore>()\n            .addPointer(\"a\",\n                        options: options)\n        XCTAssertEqual(schema.fields?[\"a\"]?.type, .pointer)\n        XCTAssertEqual(schema.fields?[\"a\"]?.targetClass, gameScore2.className)\n        guard let value = schema.fields?[\"a\"]?.defaultValue?.value as? GameScore2 else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertEqual(try value.toPointer(), try gameScore2.toPointer())\n\n        let schema2 = schema.addPointer(\"b\",\n                                        options: options)\n        XCTAssertEqual(schema2.fields?[\"b\"]?.type, .pointer)\n        XCTAssertEqual(schema2.fields?[\"b\"]?.targetClass, gameScore2.className)\n        guard let value2 = schema2.fields?[\"b\"]?.defaultValue?.value as? GameScore2 else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertEqual(try value2.toPointer(), try gameScore2.toPointer())\n    }\n\n    func testAddRelation() throws {\n        let options = try ParseFieldOptions<GameScore2>(required: false, defauleValue: nil)\n        let schema = ParseSchema<GameScore>()\n            .addRelation(\"a\",\n                         options: options)\n        XCTAssertEqual(schema.fields?[\"a\"]?.type, .relation)\n        XCTAssertEqual(schema.fields?[\"a\"]?.targetClass, GameScore2.className)\n\n        let schema2 = schema.addRelation(\"b\",\n                                         options: options)\n        XCTAssertEqual(schema2.fields?[\"b\"]?.type, .relation)\n        XCTAssertEqual(schema2.fields?[\"b\"]?.targetClass, GameScore2.className)\n    }\n\n    func testDeleteField() throws {\n        var schema = ParseSchema<GameScore>()\n            .deleteField(\"a\")\n        let delete = ParseField(operation: .delete)\n        XCTAssertEqual(schema.fields?[\"a\"], delete)\n\n        schema = schema.deleteField(\"b\")\n        XCTAssertEqual(schema.fields?[\"a\"], delete)\n        XCTAssertEqual(schema.fields?[\"b\"], delete)\n    }\n\n    func testAddIndexes() throws {\n        let schema = ParseSchema<GameScore>()\n            .addIndex(\"hello\", field: \"world\", index: \"yolo\")\n            .addIndex(\"next\", field: \"place\", index: \"home\")\n        let indexes = schema.getIndexes()\n        guard let firstIndex = indexes[\"hello\"]?[\"world\"],\n            let secondIndex = indexes[\"next\"]?[\"place\"] else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertEqual(firstIndex, \"yolo\")\n        XCTAssertEqual(secondIndex, \"home\")\n\n        let alreadyStoredIndexes: [String: [String: AnyCodable]] = [\n            \"meta\": [\"world\": \"peace\"],\n            \"stop\": [\"being\": \"greedy\"]\n        ]\n        var schema2 = ParseSchema<GameScore>()\n        schema2.indexes = alreadyStoredIndexes\n        let indexes2 = schema2.getIndexes()\n        guard let firstIndex2 = indexes2[\"meta\"]?[\"world\"],\n            let secondIndex2 = indexes2[\"stop\"]?[\"being\"] else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertEqual(firstIndex2, \"peace\")\n        XCTAssertEqual(secondIndex2, \"greedy\")\n\n        schema2 = schema2\n            .addIndex(\"hello\", field: \"world\", index: \"yolo\")\n            .addIndex(\"next\", field: \"place\", index: \"home\")\n        let indexes3 = schema2.getIndexes()\n        guard let firstIndex3 = indexes3[\"meta\"]?[\"world\"],\n            let secondIndex3 = indexes3[\"stop\"]?[\"being\"],\n            let thirdIndex3 = indexes[\"hello\"]?[\"world\"],\n            let fourthIndex3 = indexes[\"next\"]?[\"place\"] else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertEqual(firstIndex3, \"peace\")\n        XCTAssertEqual(secondIndex3, \"greedy\")\n        XCTAssertEqual(thirdIndex3, \"yolo\")\n        XCTAssertEqual(fourthIndex3, \"home\")\n    }\n\n    func testDeleteIndexes() throws {\n        let schema = ParseSchema<GameScore>()\n            .deleteIndex(\"hello\")\n            .addIndex(\"next\", field: \"place\", index: \"home\")\n        let indexes = schema.getIndexes()\n        guard let firstIndex = indexes[\"hello\"]?[\"__op\"],\n            let secondIndex = indexes[\"next\"]?[\"place\"] else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        XCTAssertEqual(firstIndex, \"Delete\")\n        XCTAssertEqual(secondIndex, \"home\")\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseSessionTests.swift",
    "content": "//\n//  ParseSessionTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/17/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\n\nimport XCTest\n@testable import ParseSwift\n\nclass ParseSessionTests: XCTestCase {\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct Session<SessionUser: ParseUser>: ParseSession {\n\n        var sessionToken: String\n        var user: ParseSessionTests.User\n        var restricted: Bool?\n        var createdWith: [String: String]\n        var installationId: String\n        var expiresAt: Date\n        var originalData: Data?\n\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n\n        init() {\n            sessionToken = \"hello\"\n            user = User()\n            restricted = false\n            createdWith = [\"yolo\": \"yaw\"]\n            installationId = \"yes\"\n            expiresAt = Date()\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: false) // Set to false for codecov\n\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n        Parse.configuration = nil\n    }\n\n    func testFetchCommand() throws {\n        var session = Session<User>()\n        XCTAssertThrowsError(try session.fetchCommand(include: nil))\n        session.objectId = \"me\"\n        do {\n            let command = try session.fetchCommand(include: nil)\n            XCTAssertNotNil(command)\n            //Generates this component because fetchCommand is at the Objective protocol level\n            XCTAssertEqual(command.path.urlComponent, \"/classes/_Session/me\")\n            XCTAssertEqual(command.method, API.Method.GET)\n            XCTAssertNil(command.params)\n            XCTAssertNil(command.body)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testEndPoint() throws {\n        var session = Session<User>()\n        XCTAssertEqual(session.endpoint.urlComponent, \"/sessions\")\n        session.objectId = \"me\"\n        XCTAssertEqual(session.endpoint.urlComponent, \"/sessions/me\")\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testParseURLSession() throws {\n        XCTAssertEqual(URLSession.parse.configuration.requestCachePolicy,\n                       ParseSwift.configuration.requestCachePolicy)\n        XCTAssertEqual(URLSession.parse.configuration.httpAdditionalHeaders?.count,\n                       ParseSwift.configuration.httpAdditionalHeaders?.count)\n        guard let delegate = URLSession.parse.delegate as? ParseURLSessionDelegate else {\n            XCTFail(\"Should have casted\")\n            return\n        }\n        XCTAssertEqual(delegate, Parse.sessionDelegate)\n    }\n\n    func testParseURLSessionDefaultCertificatePinning() throws {\n        let expectation1 = XCTestExpectation(description: \"Authentication\")\n        URLSession.parse.delegate?.urlSession?(URLSession.parse,\n                                               didReceive: .init()) { (challenge, credential) -> Void in\n            XCTAssertEqual(challenge, .performDefaultHandling)\n            XCTAssertNil(credential)\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 10.0)\n    }\n\n    func testParseURLSessionCustomCertificatePinning() throws {\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              // swiftlint:disable:next line_length\n                              testing: false) {(_: URLAuthenticationChallenge, completion: (_: URLSession.AuthChallengeDisposition, _: URLCredential?) -> Void) in\n            completion(.cancelAuthenticationChallenge, .none)\n        }\n        let expectation1 = XCTestExpectation(description: \"Authentication\")\n        URLSession.parse.delegate?.urlSession?(URLSession.parse,\n                                               didReceive: .init()) { (challenge, credential) -> Void in\n            XCTAssertEqual(challenge, .cancelAuthenticationChallenge)\n            XCTAssertEqual(credential, .none)\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 10.0)\n    }\n\n    func testParseURLSessionUpdateCertificatePinning() throws {\n        // swiftlint:disable:next line_length\n        ParseSwift.updateAuthentication({(_: URLAuthenticationChallenge, completion: (_: URLSession.AuthChallengeDisposition, _: URLCredential?) -> Void) in\n            completion(.cancelAuthenticationChallenge, .none)\n        })\n        let expectation1 = XCTestExpectation(description: \"Authentication\")\n        URLSession.parse.delegate?.urlSession?(URLSession.parse,\n                                               didReceive: .init()) { (challenge, credential) -> Void in\n            XCTAssertEqual(challenge, .cancelAuthenticationChallenge)\n            XCTAssertEqual(credential, .none)\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 10.0)\n    }\n    #endif\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseSpotifyAsyncTests.swift",
    "content": "//\n//  ParseSpotifyAsyncTests.swift\n//  ParseSwift\n//\n//  Created by Ulaş Sancak on 06/21/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseSpotifyAsyncTests: XCTestCase { // swiftlint:disable:this type_body_length\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    @MainActor\n    func testLogin() async throws {\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.spotify.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.spotify.login(id: \"testing\", accessToken: \"access_token\")\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.spotify.isLinked)\n    }\n\n    @MainActor\n    func testLoginAuthData() async throws {\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.spotify.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.spotify.login(authData: [\"id\": \"testing\",\n                                                         \"access_token\": \"access_token\"])\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.spotify.isLinked)\n    }\n\n    func loginNormally() async throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try await User.login(username: \"parse\", password: \"user\")\n    }\n\n    @MainActor\n    func testLink() async throws {\n        _ = try await loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.spotify.link(id: \"testing\", accessToken: \"access_token\")\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.spotify.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testLinkAuthData() async throws {\n        _ = try await loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.spotify.link(authData: [\"id\": \"testing\",\n                                                          \"access_token\": \"access_token\"])\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.spotify.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testUnlink() async throws {\n        _ = try await loginNormally()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseSpotify<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"access_token\")\n        User.current?.authData = [User.spotify.__type: authData]\n        XCTAssertTrue(User.spotify.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.spotify.unlink()\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertFalse(user.spotify.isLinked)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseSpotifyCombineTests.swift",
    "content": "//\n//  ParseSpotifyCombineTests.swift\n//  ParseSwift\n//\n//  Created by Ulaş Sancak on 06/21/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseSpotifyCombineTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testLogin() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.spotify.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.spotify.loginPublisher(id: \"testing\", accessToken: \"access_token\")\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user, userOnServer)\n            XCTAssertEqual(user.username, \"hello\")\n            XCTAssertEqual(user.password, \"world\")\n            XCTAssertTrue(user.spotify.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginAuthData() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.spotify.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.spotify.loginPublisher(authData: [\"id\": \"testing\",\n                                                               \"access_token\": \"access_token\"])\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user, userOnServer)\n            XCTAssertEqual(user.username, \"hello\")\n            XCTAssertEqual(user.password, \"world\")\n            XCTAssertTrue(user.spotify.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func loginNormally() throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try User.login(username: \"parse\", password: \"user\")\n    }\n\n    func testLink() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.spotify.linkPublisher(id: \"testing\", accessToken: \"access_token\")\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertTrue(user.spotify.isLinked)\n            XCTAssertFalse(user.anonymous.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkAuthData() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.spotify.linkPublisher(authData: [\"id\": \"testing\",\n                                                              \"access_token\": \"access_token\"])\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertTrue(user.spotify.isLinked)\n            XCTAssertFalse(user.anonymous.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUnlink() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseSpotify<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"access_token\")\n        User.current?.authData = [User.spotify.__type: authData]\n        XCTAssertTrue(User.spotify.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.spotify.unlinkPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertFalse(user.spotify.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseSpotifyTests.swift",
    "content": "//\n//  ParseSpotifyTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 06/21/22.\n//  Copyright © 2022 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseSpotifyTests: XCTestCase {\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func loginNormally() throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try User.login(username: \"parse\", password: \"user\")\n    }\n\n    func testAuthenticationKeys() throws {\n        let authData = ParseSpotify<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"access_token\")\n        XCTAssertEqual(authData, [\"id\": \"testing\", \"access_token\": \"access_token\"])\n    }\n\n    func testAuthenticationWithOptinalKeys() throws {\n        let authData = ParseSpotify<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"access_token\",\n                                                  expiresIn: 10,\n                                                  refreshToken: \"refresh_token\")\n        guard let dateString = authData[\"expiration_date\"] else {\n            XCTFail(\"Should have found date\")\n            return\n        }\n        XCTAssertEqual(authData, [\"id\": \"testing\",\n                                  \"access_token\": \"access_token\",\n                                  \"expiration_date\": dateString,\n                                  \"refresh_token\": \"refresh_token\"])\n    }\n\n    func testVerifyMandatoryKeys() throws {\n        let authData = [\"id\": \"testing\", \"access_token\": \"access_token\"]\n        let authDataWrong = [\"id\": \"testing\", \"hello\": \"test\"]\n        XCTAssertTrue(ParseSpotify<User>\n                        .AuthenticationKeys.id.verifyMandatoryKeys(authData: authData))\n        XCTAssertFalse(ParseSpotify<User>\n                        .AuthenticationKeys.id.verifyMandatoryKeys(authData: authDataWrong))\n    }\n\n    func testLogin() throws {\n        var serverResponse = LoginSignupResponse()\n\n        let authData = ParseSpotify<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"access_token\")\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.spotify.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.spotify.login(id: \"testing\", accessToken: \"access_token\") { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user, userOnServer)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.spotify.isLinked)\n\n                //Test stripping\n                user.spotify.strip()\n                XCTAssertFalse(user.spotify.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginAuthData() throws {\n        var serverResponse = LoginSignupResponse()\n\n        let authData = ParseSpotify<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"access_token\")\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.spotify.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.spotify.login(authData: authData) { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user, userOnServer)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.spotify.isLinked)\n\n                //Test stripping\n                user.spotify.strip()\n                XCTAssertFalse(user.spotify.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginWrongKeys() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.spotify.login(authData: [\"hello\": \"world\"]) { result in\n\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"consisting of keys\"))\n            } else {\n                XCTFail(\"Should have returned error\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func loginAnonymousUser() throws {\n        let authData = [\"id\": \"yolo\"]\n\n        //: Convert the anonymous user to a real new user.\n        var serverResponse = LoginSignupResponse()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.anonymous.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try User.anonymous.login()\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.anonymous.isLinked)\n    }\n\n    func testReplaceAnonymousWithSpotify() throws {\n        try loginAnonymousUser()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseSpotify<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"access_token\")\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.spotify.__type: authData,\n                                   serverResponse.anonymous.__type: nil]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.spotify.login(id: \"testing\", accessToken: \"access_token\") { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.authData, userOnServer.authData)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.spotify.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testReplaceAnonymousWithLinkedSpotify() throws {\n        try loginAnonymousUser()\n        MockURLProtocol.removeAll()\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.spotify.link(id: \"testing\", accessToken: \"access_token\") { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.spotify.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkLoggedInUserWithSpotify() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.sessionToken = nil\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.spotify.link(id: \"testing\", accessToken: \"access_token\") { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello10\")\n                XCTAssertNil(user.password)\n                XCTAssertTrue(user.spotify.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n                XCTAssertEqual(User.current?.sessionToken, \"myToken\")\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkLoggedInAuthData() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.sessionToken = nil\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        let authData = ParseSpotify<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"access_token\")\n\n        User.spotify.link(authData: authData) { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello10\")\n                XCTAssertNil(user.password)\n                XCTAssertTrue(user.spotify.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n                XCTAssertEqual(User.current?.sessionToken, \"myToken\")\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkLoggedInUserWrongKeys() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.spotify.link(authData: [\"hello\": \"world\"]) { result in\n\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"consisting of keys\"))\n            } else {\n                XCTFail(\"Should have returned error\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUnlink() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseSpotify<User>\n            .AuthenticationKeys.id.makeDictionary(id: \"testing\",\n                                                  accessToken: \"access_token\")\n        User.current?.authData = [User.spotify.__type: authData]\n        XCTAssertTrue(User.spotify.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.spotify.unlink { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello10\")\n                XCTAssertNil(user.password)\n                XCTAssertFalse(user.spotify.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseTwitterAsyncTests.swift",
    "content": "//\n//  ParseTwitterAsyncTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 9/28/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseTwitterAsyncTests: XCTestCase { // swiftlint:disable:this type_body_length\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    @MainActor\n    func testLogin() async throws {\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.twitter.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.twitter.login(userId: \"testing\", screenName: \"screenName\",\n                                                consumerKey: \"consumerKey\", consumerSecret: \"consumerSecret\",\n                                                authToken: \"tokenData\", authTokenSecret: \"authTokenSecret\")\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.twitter.isLinked)\n    }\n\n    @MainActor\n    func testLoginAuthData() async throws {\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.twitter.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let twitterAuthData = ParseTwitter<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  screenName: \"screenName\",\n                                                  consumerKey: \"consumerKey\",\n                                                  consumerSecret: \"consumerSecret\",\n                                                  authToken: \"authToken\",\n                                                  authTokenSecret: \"authTokenSecret\")\n\n        let user = try await User.twitter.login(authData: twitterAuthData)\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.twitter.isLinked)\n    }\n\n    func loginNormally() async throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try await User.login(username: \"parse\", password: \"user\")\n    }\n\n    @MainActor\n    func testLink() async throws {\n\n        _ = try await loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.twitter.link(userId: \"testing\",\n                                               screenName: \"screenName\",\n                                               consumerKey: \"consumerKey\",\n                                               consumerSecret: \"consumerSecret\",\n                                               authToken: \"tokenData\",\n                                               authTokenSecret: \"authTokenSecret\")\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.twitter.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testLinkAuthData() async throws {\n\n        _ = try await loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let twitterAuthData = ParseTwitter<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  screenName: \"screenName\",\n                                                  consumerKey: \"consumerKey\",\n                                                  consumerSecret: \"consumerSecret\",\n                                                  authToken: \"authToken\",\n                                                  authTokenSecret: \"authTokenSecret\")\n        let user = try await User.twitter.link(authData: twitterAuthData)\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertTrue(user.twitter.isLinked)\n        XCTAssertFalse(user.anonymous.isLinked)\n    }\n\n    @MainActor\n    func testUnlink() async throws {\n\n        _ = try await loginNormally()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseTwitter<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  screenName: \"screenName\",\n                                                  consumerKey: \"consumerKey\",\n                                                  consumerSecret: \"consumerSecret\",\n                                                  authToken: \"tokenData\",\n                                                  authTokenSecret: \"authTokenSecret\")\n        User.current?.authData = [User.twitter.__type: authData]\n        XCTAssertTrue(User.twitter.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try await User.twitter.unlink()\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n        XCTAssertEqual(user.username, \"hello10\")\n        XCTAssertNil(user.password)\n        XCTAssertFalse(user.twitter.isLinked)\n    }\n}\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseTwitterCombineTests.swift",
    "content": "//\n//  ParseTwitterCombineTests.swift\n//  ParseSwift\n//\n//  Created by Abdulaziz Alhomaidhi on 3/19/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseTwitterCombineTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testLogin() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.twitter.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.twitter.loginPublisher(userId: \"testing\", screenName: \"screenName\",\n                                                    consumerKey: \"consumerKey\", consumerSecret: \"consumerSecret\",\n                                                    authToken: \"tokenData\", authTokenSecret: \"authTokenSecret\")\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user, userOnServer)\n            XCTAssertEqual(user.username, \"hello\")\n            XCTAssertEqual(user.password, \"world\")\n            XCTAssertTrue(user.twitter.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginAuthData() {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var serverResponse = LoginSignupResponse()\n        let authData = ParseAnonymous<User>.AuthenticationKeys.id.makeDictionary()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.twitter.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let twitterAuthData = ParseTwitter<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  screenName: \"screenName\",\n                                                  consumerKey: \"consumerKey\",\n                                                  consumerSecret: \"consumerSecret\",\n                                                  authToken: \"authToken\",\n                                                  authTokenSecret: \"authTokenSecret\")\n\n        let publisher = User.twitter.loginPublisher(authData: twitterAuthData)\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user, userOnServer)\n            XCTAssertEqual(user.username, \"hello\")\n            XCTAssertEqual(user.password, \"world\")\n            XCTAssertTrue(user.twitter.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func loginNormally() throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try User.login(username: \"parse\", password: \"user\")\n    }\n\n    func testLink() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.twitter.linkPublisher(userId: \"testing\",\n                                                   screenName: \"screenName\",\n                                                   consumerKey: \"consumerKey\",\n                                                   consumerSecret: \"consumerSecret\",\n                                                   authToken: \"tokenData\",\n                                                   authTokenSecret: \"authTokenSecret\")\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertTrue(user.twitter.isLinked)\n            XCTAssertFalse(user.anonymous.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkAuthData() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let twitterAuthData = ParseTwitter<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  screenName: \"screenName\",\n                                                  consumerKey: \"consumerKey\",\n                                                  consumerSecret: \"consumerSecret\",\n                                                  authToken: \"authToken\",\n                                                  authTokenSecret: \"authTokenSecret\")\n        let publisher = User.twitter.linkPublisher(authData: twitterAuthData)\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertTrue(user.twitter.isLinked)\n            XCTAssertFalse(user.anonymous.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUnlink() throws {\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseTwitter<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  screenName: \"screenName\",\n                                                  consumerKey: \"consumerKey\",\n                                                  consumerSecret: \"consumerSecret\",\n                                                  authToken: \"tokenData\",\n                                                  authTokenSecret: \"authTokenSecret\")\n        User.current?.authData = [User.twitter.__type: authData]\n        XCTAssertTrue(User.twitter.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = User.twitter.unlinkPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { user in\n\n            XCTAssertEqual(user, User.current)\n            XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n            XCTAssertEqual(user.username, \"hello10\")\n            XCTAssertNil(user.password)\n            XCTAssertFalse(user.twitter.isLinked)\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseTwitterTests.swift",
    "content": "//\n//  ParseTwitterTests.swift\n//  ParseSwift\n//\n//  Created by Abdulaziz Alhomaidhi on 3/17/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseTwitterTests: XCTestCase {\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func loginNormally() throws -> User {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        return try User.login(username: \"parse\", password: \"user\")\n    }\n\n    func testAuthenticationKeys() throws {\n\n        let authData = ParseTwitter<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  screenName: \"screenName\",\n                                                  consumerKey: \"consumerKey\",\n                                                  consumerSecret: \"consumerSecret\",\n                                                  authToken: \"authToken\",\n                                                  authTokenSecret: \"authTokenSecret\")\n        XCTAssertEqual(authData, [\"id\": \"testing\",\n                                  \"screen_name\": \"screenName\",\n                                  \"consumer_key\": \"consumerKey\",\n                                  \"consumer_secret\": \"consumerSecret\",\n                                  \"auth_token\": \"authToken\",\n                                  \"auth_token_secret\": \"authTokenSecret\"])\n    }\n\n    func testVerifyMandatoryKeys() throws {\n        let authData = [\"id\": \"testing\",\n                        \"screen_name\": \"screenName\",\n                        \"consumer_key\": \"consumerKey\",\n                        \"consumer_secret\": \"consumerSecret\",\n                        \"auth_token\": \"authToken\",\n                        \"auth_token_secret\": \"authTokenSecret\"]\n        let authDataWrong = [\"id\": \"testing\",\n                             \"screenName\": \"screenName\",\n                             \"consumerKey\": \"consumerKey\",\n                             \"consumerSecret\": \"consumerSecret\",\n                             \"authToken\": \"authToken\",\n                             \"hello\": \"authTokenSecret\"]\n        XCTAssertTrue(ParseTwitter<User>\n                        .AuthenticationKeys.id.verifyMandatoryKeys(authData: authData))\n        XCTAssertFalse(ParseTwitter<User>\n                        .AuthenticationKeys.id.verifyMandatoryKeys(authData: authDataWrong))\n    }\n\n    func testLogin() throws {\n        var serverResponse = LoginSignupResponse()\n\n        let authData = ParseTwitter<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  screenName: \"screenName\",\n                                                  consumerKey: \"consumerKey\",\n                                                  consumerSecret: \"consumerSecret\",\n                                                  authToken: \"authToken\",\n                                                  authTokenSecret: \"authTokenSecret\")\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.twitter.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.twitter.login(userId: \"testing\", screenName: \"screenName\",\n                           authToken: \"consumerKey\", authTokenSecret: \"consumerSecret\",\n                           consumerKey: \"this\", consumerSecret: \"authTokenSecret\") { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user, userOnServer)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.twitter.isLinked)\n\n                //Test stripping\n                user.twitter.strip()\n                XCTAssertFalse(user.twitter.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginAuthData() throws {\n        var serverResponse = LoginSignupResponse()\n\n        let authData = ParseTwitter<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  screenName: \"screenName\",\n                                                  consumerKey: \"consumerKey\",\n                                                  consumerSecret: \"consumerSecret\",\n                                                  authToken: \"authToken\",\n                                                  authTokenSecret: \"authTokenSecret\")\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.twitter.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n        User.twitter.login(authData: authData) { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user, userOnServer)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.twitter.isLinked)\n\n                //Test stripping\n                user.twitter.strip()\n                XCTAssertFalse(user.twitter.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginWrongKeys() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.twitter.login(authData: [\"hello\": \"world\"]) { result in\n\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"consisting of keys\"))\n            } else {\n                XCTFail(\"Should have returned error\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func loginAnonymousUser() throws {\n        let authData = [\"id\": \"yolo\"]\n\n        //: Convert the anonymous user to a real new user.\n        var serverResponse = LoginSignupResponse()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.anonymous.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let user = try User.anonymous.login()\n        XCTAssertEqual(user, User.current)\n        XCTAssertEqual(user, userOnServer)\n        XCTAssertEqual(user.username, \"hello\")\n        XCTAssertEqual(user.password, \"world\")\n        XCTAssertTrue(user.anonymous.isLinked)\n    }\n\n    func testReplaceAnonymousWithTwitter() throws {\n        try loginAnonymousUser()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseTwitter<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  screenName: \"screenName\",\n                                                  consumerKey: \"consumerSecret\",\n                                                  consumerSecret: \"consumerSecret\",\n                                                  authToken: \"this\",\n                                                  authTokenSecret: \"authTokenSecret\")\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.username = \"hello\"\n        serverResponse.password = \"world\"\n        serverResponse.objectId = \"yarr\"\n        serverResponse.sessionToken = \"myToken\"\n        serverResponse.authData = [serverResponse.twitter.__type: authData]\n        serverResponse.createdAt = Date()\n        serverResponse.updatedAt = serverResponse.createdAt?.addingTimeInterval(+300)\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.twitter.login(userId: \"testing\", screenName: \"screenName\",\n                           authToken: \"this\", authTokenSecret: \"authTokenSecret\",\n                           consumerKey: \"consumerKey\", consumerSecret: \"consumerSecret\") { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.twitter.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testReplaceAnonymousWithLinkedTwitter() throws {\n        try loginAnonymousUser()\n        MockURLProtocol.removeAll()\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.twitter.link(userId: \"testing\", screenName: \"screenName\",\n                          consumerKey: \"consumerKey\", consumerSecret: \"consumerSecret\",\n                          authToken: \"this\", authTokenSecret: \"authTokenSecret\") { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello\")\n                XCTAssertEqual(user.password, \"world\")\n                XCTAssertTrue(user.twitter.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkLoggedInUserWithTwitter() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.sessionToken = nil\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.twitter.link(userId: \"testing\", screenName: \"screenName\",\n                          consumerKey: \"consumerKey\", consumerSecret: \"consumerSecret\",\n                          authToken: \"this\", authTokenSecret: \"authTokenSecret\") { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello10\")\n                XCTAssertNil(user.password)\n                XCTAssertTrue(user.twitter.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n                XCTAssertEqual(User.current?.sessionToken, \"myToken\")\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkLoggedInAuthData() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.sessionToken = nil\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        let authData = ParseTwitter<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  screenName: \"screenName\",\n                                                  consumerKey: \"consumerKey\",\n                                                  consumerSecret: \"consumerSecret\",\n                                                  authToken: \"authToken\",\n                                                  authTokenSecret: \"authTokenSecret\")\n        User.twitter.link(authData: authData) { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello10\")\n                XCTAssertNil(user.password)\n                XCTAssertTrue(user.twitter.isLinked)\n                XCTAssertFalse(user.anonymous.isLinked)\n                XCTAssertEqual(User.current?.sessionToken, \"myToken\")\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLinkWrongKeys() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.twitter.link(authData: [\"hello\": \"world\"]) { result in\n\n            if case let .failure(error) = result {\n                XCTAssertTrue(error.message.contains(\"consisting of keys\"))\n            } else {\n                XCTFail(\"Should have returned error\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUnlink() throws {\n        _ = try loginNormally()\n        MockURLProtocol.removeAll()\n\n        let authData = ParseTwitter<User>\n            .AuthenticationKeys.id.makeDictionary(userId: \"testing\",\n                                                  screenName: \"screenNAme\",\n                                                  consumerKey: \"consumerKey\",\n                                                  consumerSecret: \"consumerSecret\",\n                                                  authToken: \"this\",\n                                                  authTokenSecret: \"authTokenSecret\")\n        User.current?.authData = [User.twitter.__type: authData]\n        XCTAssertTrue(User.twitter.isLinked)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = Date()\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login\")\n\n        User.twitter.unlink { result in\n            switch result {\n\n            case .success(let user):\n                XCTAssertEqual(user, User.current)\n                XCTAssertEqual(user.updatedAt, userOnServer.updatedAt)\n                XCTAssertEqual(user.username, \"hello10\")\n                XCTAssertNil(user.password)\n                XCTAssertFalse(user.twitter.isLinked)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseUserAsyncTests.swift",
    "content": "//\n//  ParseUserAsyncTests.swift\n//  ParseUserAsyncTests\n//\n//  Created by Corey Baker on 8/6/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if compiler(>=5.5.2) && canImport(_Concurrency)\nimport Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\nimport XCTest\n@testable import ParseSwift\n\nclass ParseUserAsyncTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        //: Implement your own version of merge\n        func merge(with object: Self) throws -> Self {\n            var updated = try mergeParse(with: object)\n            if updated.shouldRestoreKey(\\.customKey,\n                                         original: object) {\n                updated.customKey = object.customKey\n            }\n            return updated\n        }\n    }\n\n    struct UserDefaultMerge: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n    }\n\n    struct UserDefault: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    let loginUserName = \"hello10\"\n    let loginPassword = \"world\"\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testOriginalDataNeverSavesToKeychain() async throws {\n        // Signup current User\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        User.current?.originalData = Data()\n        let original = User.current\n        User.saveCurrentContainerToKeychain()\n\n        let expectation1 = XCTestExpectation(description: \"Original installation1\")\n        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n            guard let original = original,\n                let saved = User.current else {\n                XCTFail(\"Should have a new current installation\")\n                expectation1.fulfill()\n                return\n            }\n            XCTAssertTrue(saved.hasSameObjectId(as: original))\n            XCTAssertNotNil(original.originalData)\n            XCTAssertNil(saved.originalData)\n            XCTAssertEqual(saved.customKey, original.customKey)\n            XCTAssertEqual(saved.email, original.email)\n            XCTAssertEqual(saved.username, original.username)\n            XCTAssertEqual(saved.emailVerified, original.emailVerified)\n            XCTAssertEqual(saved.password, original.password)\n            XCTAssertEqual(saved.authData, original.authData)\n            XCTAssertEqual(saved.createdAt, original.createdAt)\n            XCTAssertEqual(saved.updatedAt, original.updatedAt)\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    @MainActor\n    func testSignup() async throws {\n        let loginResponse = LoginSignupResponse()\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let signedUp = try await User.signup(username: loginUserName, password: loginUserName)\n        XCTAssertNotNil(signedUp)\n        XCTAssertNotNil(signedUp.createdAt)\n        XCTAssertNotNil(signedUp.updatedAt)\n        XCTAssertNotNil(signedUp.email)\n        XCTAssertNotNil(signedUp.username)\n        XCTAssertNil(signedUp.password)\n        XCTAssertNotNil(signedUp.objectId)\n        XCTAssertNotNil(signedUp.sessionToken)\n        XCTAssertNotNil(signedUp.customKey)\n        XCTAssertNil(signedUp.ACL)\n\n        guard let userFromKeychain = BaseParseUser.current else {\n            XCTFail(\"Could not get CurrentUser from Keychain\")\n            return\n        }\n\n        XCTAssertNotNil(userFromKeychain.createdAt)\n        XCTAssertNotNil(userFromKeychain.updatedAt)\n        XCTAssertNotNil(userFromKeychain.email)\n        XCTAssertNotNil(userFromKeychain.username)\n        XCTAssertNil(userFromKeychain.password)\n        XCTAssertNotNil(userFromKeychain.objectId)\n        XCTAssertNotNil(userFromKeychain.sessionToken)\n        XCTAssertNil(userFromKeychain.ACL)\n    }\n\n    @MainActor\n    func testSignupInstance() async throws {\n        let loginResponse = LoginSignupResponse()\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        var user = User()\n        user.username = loginUserName\n        user.password = loginPassword\n        user.email = \"parse@parse.com\"\n        user.customKey = \"blah\"\n        let signedUp = try await user.signup()\n        XCTAssertNotNil(signedUp)\n        XCTAssertNotNil(signedUp.createdAt)\n        XCTAssertNotNil(signedUp.updatedAt)\n        XCTAssertNotNil(signedUp.email)\n        XCTAssertNotNil(signedUp.username)\n        XCTAssertNil(signedUp.password)\n        XCTAssertNotNil(signedUp.objectId)\n        XCTAssertNotNil(signedUp.sessionToken)\n        XCTAssertNotNil(signedUp.customKey)\n        XCTAssertNil(signedUp.ACL)\n\n        guard let userFromKeychain = BaseParseUser.current else {\n            XCTFail(\"Could not get CurrentUser from Keychain\")\n            return\n        }\n\n        XCTAssertNotNil(userFromKeychain.createdAt)\n        XCTAssertNotNil(userFromKeychain.updatedAt)\n        XCTAssertNotNil(userFromKeychain.email)\n        XCTAssertNotNil(userFromKeychain.username)\n        XCTAssertNil(userFromKeychain.password)\n        XCTAssertNotNil(userFromKeychain.objectId)\n        XCTAssertNotNil(userFromKeychain.sessionToken)\n        XCTAssertNil(userFromKeychain.ACL)\n    }\n\n    @MainActor\n    func testLogin() async throws {\n        let loginResponse = LoginSignupResponse()\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let signedUp = try await User.login(username: loginUserName, password: loginUserName)\n        XCTAssertNotNil(signedUp)\n        XCTAssertNotNil(signedUp.createdAt)\n        XCTAssertNotNil(signedUp.updatedAt)\n        XCTAssertNotNil(signedUp.email)\n        XCTAssertNotNil(signedUp.username)\n        XCTAssertNil(signedUp.password)\n        XCTAssertNotNil(signedUp.objectId)\n        XCTAssertNotNil(signedUp.sessionToken)\n        XCTAssertNotNil(signedUp.customKey)\n        XCTAssertNil(signedUp.ACL)\n\n        guard let userFromKeychain = BaseParseUser.current else {\n            XCTFail(\"Could not get CurrentUser from Keychain\")\n            return\n        }\n\n        XCTAssertNotNil(userFromKeychain.createdAt)\n        XCTAssertNotNil(userFromKeychain.updatedAt)\n        XCTAssertNotNil(userFromKeychain.email)\n        XCTAssertNotNil(userFromKeychain.username)\n        XCTAssertNil(userFromKeychain.password)\n        XCTAssertNotNil(userFromKeychain.objectId)\n        XCTAssertNotNil(userFromKeychain.sessionToken)\n        XCTAssertNil(userFromKeychain.ACL)\n    }\n\n    func login() {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        do {\n            _ = try User.login(username: loginUserName, password: loginPassword)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    @MainActor\n    func testBecome() async throws {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        guard let user = User.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = User.current?.updatedAt?.addingTimeInterval(+300)\n        serverResponse.sessionToken = \"newValue\"\n        serverResponse.username = \"stop\"\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        guard let sessionToken = serverResponse.sessionToken else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        let signedUp = try await user.become(sessionToken: sessionToken)\n        XCTAssertNotNil(signedUp)\n        XCTAssertNotNil(signedUp.updatedAt)\n        XCTAssertNotNil(signedUp.email)\n        XCTAssertNotNil(signedUp.username)\n        XCTAssertNil(signedUp.password)\n        XCTAssertNotNil(signedUp.objectId)\n        XCTAssertNotNil(signedUp.sessionToken)\n        XCTAssertNotNil(signedUp.customKey)\n        XCTAssertNil(signedUp.ACL)\n\n        guard let userFromKeychain = BaseParseUser.current else {\n            XCTFail(\"Could not get CurrentUser from Keychain\")\n            return\n        }\n\n        XCTAssertNotNil(userFromKeychain.createdAt)\n        XCTAssertNotNil(userFromKeychain.updatedAt)\n        XCTAssertNotNil(userFromKeychain.email)\n        XCTAssertNotNil(userFromKeychain.username)\n        XCTAssertNil(userFromKeychain.password)\n        XCTAssertNotNil(userFromKeychain.objectId)\n        XCTAssertNotNil(userFromKeychain.sessionToken)\n        XCTAssertNil(userFromKeychain.ACL)\n    }\n\n    @MainActor\n    func testLogout() async throws {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        let serverResponse = NoBody()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        guard let oldInstallationId = BaseParseInstallation.current?.installationId else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        _ = try await User.logout()\n\n        if let userFromKeychain = BaseParseUser.current {\n            XCTFail(\"\\(userFromKeychain) was not deleted from Keychain during logout\")\n        }\n\n        if let installationFromMemory: CurrentInstallationContainer<BaseParseInstallation>\n            = try? ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentInstallation) {\n            if installationFromMemory.installationId == oldInstallationId\n                || installationFromMemory.installationId == nil {\n                XCTFail(\"\\(installationFromMemory) was not deleted and recreated in memory during logout\")\n            }\n        } else {\n            XCTFail(\"Should have a new installation\")\n        }\n\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        if let installationFromKeychain: CurrentInstallationContainer<BaseParseInstallation>\n            = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) {\n            if installationFromKeychain.installationId == oldInstallationId\n                || installationFromKeychain.installationId == nil {\n                XCTFail(\"\\(installationFromKeychain) was not deleted & recreated in Keychain during logout\")\n            }\n        } else {\n            XCTFail(\"Should have a new installation\")\n        }\n        #endif\n    }\n\n    @MainActor\n    func testLogoutError() async throws {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        let serverResponse = ParseError(code: .internalServer, message: \"Object not found\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        guard let oldInstallationId = BaseParseInstallation.current?.installationId else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n\n        do {\n            _ = try await User.logout()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let error = error as? ParseError else {\n                XCTFail(\"Should be ParseError\")\n                return\n            }\n            XCTAssertEqual(error.message, serverResponse.message)\n        }\n\n        if let userFromKeychain = BaseParseUser.current {\n            XCTFail(\"\\(userFromKeychain) was not deleted from Keychain during logout\")\n        }\n\n        if let installationFromMemory: CurrentInstallationContainer<BaseParseInstallation>\n            = try? ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentInstallation) {\n                if installationFromMemory.installationId == oldInstallationId\n                    || installationFromMemory.installationId == nil {\n                    XCTFail(\"\\(installationFromMemory) was not deleted & recreated in memory during logout\")\n                }\n        } else {\n            XCTFail(\"Should have a new installation\")\n        }\n\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        if let installationFromKeychain: CurrentInstallationContainer<BaseParseInstallation>\n            = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) {\n                if installationFromKeychain.installationId == oldInstallationId\n                    || installationFromKeychain.installationId == nil {\n                    XCTFail(\"\\(installationFromKeychain) was not deleted & recreated in Keychain during logout\")\n                }\n        } else {\n            XCTFail(\"Should have a new installation\")\n        }\n        #endif\n\n    }\n\n    @MainActor\n    func testPasswordReset() async throws {\n        let serverResponse = NoBody()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        _ = try await User.passwordReset(email: \"hello@parse.org\")\n    }\n\n    @MainActor\n    func testPasswordResetError() async throws {\n        let parseError = ParseError(code: .internalServer, message: \"Object not found\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(parseError)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        do {\n            try await User.passwordReset(email: \"hello@parse.org\")\n        } catch {\n            guard let error = error as? ParseError else {\n                XCTFail(\"Should be ParseError\")\n                return\n            }\n            XCTAssertEqual(error.code, parseError.code)\n        }\n    }\n\n    @MainActor\n    func testVerifyPasswordLoggedIn() async throws {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.sessionToken = nil\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let currentUser = try await User.verifyPassword(password: \"world\", usingPost: true)\n        XCTAssertNotNil(currentUser)\n        XCTAssertNotNil(currentUser.createdAt)\n        XCTAssertNotNil(currentUser.updatedAt)\n        XCTAssertNotNil(currentUser.email)\n        XCTAssertNotNil(currentUser.username)\n        XCTAssertNil(currentUser.password)\n        XCTAssertNotNil(currentUser.objectId)\n        XCTAssertNotNil(currentUser.sessionToken)\n        XCTAssertNotNil(currentUser.customKey)\n        XCTAssertNil(currentUser.ACL)\n\n        guard let userFromKeychain = BaseParseUser.current else {\n            XCTFail(\"Could not get CurrentUser from Keychain\")\n            return\n        }\n\n        XCTAssertNotNil(userFromKeychain.createdAt)\n        XCTAssertNotNil(userFromKeychain.updatedAt)\n        XCTAssertNotNil(userFromKeychain.email)\n        XCTAssertNotNil(userFromKeychain.username)\n        XCTAssertNil(userFromKeychain.password)\n        XCTAssertNotNil(userFromKeychain.objectId)\n        XCTAssertNotNil(userFromKeychain.sessionToken)\n        XCTAssertNil(userFromKeychain.ACL)\n    }\n\n    func testVerifyPasswordLoggedInGET() async throws {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.sessionToken = nil\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let currentUser = try await User.verifyPassword(password: \"world\", usingPost: false)\n        XCTAssertNotNil(currentUser)\n        XCTAssertNotNil(currentUser.createdAt)\n        XCTAssertNotNil(currentUser.updatedAt)\n        XCTAssertNotNil(currentUser.email)\n        XCTAssertNotNil(currentUser.username)\n        XCTAssertNil(currentUser.password)\n        XCTAssertNotNil(currentUser.objectId)\n        XCTAssertNotNil(currentUser.sessionToken)\n        XCTAssertNotNil(currentUser.customKey)\n        XCTAssertNil(currentUser.ACL)\n\n        guard let userFromKeychain = BaseParseUser.current else {\n            XCTFail(\"Could not get CurrentUser from Keychain\")\n            return\n        }\n\n        XCTAssertNotNil(userFromKeychain.createdAt)\n        XCTAssertNotNil(userFromKeychain.updatedAt)\n        XCTAssertNotNil(userFromKeychain.email)\n        XCTAssertNotNil(userFromKeychain.username)\n        XCTAssertNil(userFromKeychain.password)\n        XCTAssertNotNil(userFromKeychain.objectId)\n        XCTAssertNotNil(userFromKeychain.sessionToken)\n        XCTAssertNil(userFromKeychain.ACL)\n    }\n\n    @MainActor\n    func testVerifyPasswordNotLoggedIn() async throws {\n        let serverResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let currentUser = try await User.verifyPassword(password: \"world\")\n        XCTAssertNotNil(currentUser)\n        XCTAssertNotNil(currentUser.createdAt)\n        XCTAssertNotNil(currentUser.updatedAt)\n        XCTAssertNotNil(currentUser.email)\n        XCTAssertNotNil(currentUser.username)\n        XCTAssertNil(currentUser.password)\n        XCTAssertNotNil(currentUser.objectId)\n        XCTAssertNotNil(currentUser.sessionToken)\n        XCTAssertNotNil(currentUser.customKey)\n        XCTAssertNil(currentUser.ACL)\n\n        guard let userFromKeychain = BaseParseUser.current else {\n            XCTFail(\"Could not get CurrentUser from Keychain\")\n            return\n        }\n\n        XCTAssertNotNil(userFromKeychain.createdAt)\n        XCTAssertNotNil(userFromKeychain.updatedAt)\n        XCTAssertNotNil(userFromKeychain.email)\n        XCTAssertNotNil(userFromKeychain.username)\n        XCTAssertNil(userFromKeychain.password)\n        XCTAssertNotNil(userFromKeychain.objectId)\n        XCTAssertNotNil(userFromKeychain.sessionToken)\n        XCTAssertNil(userFromKeychain.ACL)\n    }\n\n    @MainActor\n    func testVerifyPasswordLoggedInError() async throws {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        let parseError = ParseError(code: .userWithEmailNotFound,\n                                    message: \"User email is not verified.\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(parseError)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        do {\n            _ = try await User.verifyPassword(password: \"blue\")\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let error = error as? ParseError else {\n                XCTFail(\"Should be ParseError\")\n                return\n            }\n            XCTAssertEqual(error.code, parseError.code)\n        }\n    }\n\n    @MainActor\n    func testVerificationEmail() async throws {\n        let serverResponse = NoBody()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        _ = try await User.verificationEmail(email: \"hello@parse.org\")\n    }\n\n    @MainActor\n    func testVerificationEmailError() async throws {\n        let parseError = ParseError(code: .internalServer, message: \"Object not found\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(parseError)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        do {\n            _ = try await User.verificationEmail(email: \"hello@parse.org\")\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let error = error as? ParseError else {\n                XCTFail(\"Should be ParseError\")\n                return\n            }\n            XCTAssertEqual(error.code, parseError.code)\n        }\n    }\n\n    @MainActor\n    func testFetch() async throws {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        guard let user = User.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.createdAt = User.current?.createdAt\n        serverResponse.updatedAt = User.current?.updatedAt?.addingTimeInterval(+300)\n        serverResponse.sessionToken = \"newValue\"\n        serverResponse.username = \"stop\"\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let fetched = try await user.fetch()\n        XCTAssertEqual(fetched.objectId, serverResponse.objectId)\n\n        guard let userFromKeychain = BaseParseUser.current else {\n            XCTFail(\"Could not get CurrentUser from Keychain\")\n            return\n        }\n\n        XCTAssertEqual(userFromKeychain.objectId, serverResponse.objectId)\n    }\n\n    @MainActor\n    func testSaveCurrent() async throws {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        guard var user = User.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n        user.username = \"stop\"\n\n        var serverResponse = user\n        serverResponse.updatedAt = User.current?.updatedAt?.addingTimeInterval(+300)\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let saved = try await user.save()\n        XCTAssertEqual(saved.objectId, serverResponse.objectId)\n\n        guard let userFromKeychain = BaseParseUser.current else {\n            XCTFail(\"Could not get CurrentUser from Keychain\")\n            return\n        }\n\n        XCTAssertEqual(userFromKeychain.objectId, serverResponse.objectId)\n    }\n\n    @MainActor\n    func testSave() async throws {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        var user = User()\n        user.username = \"stop\"\n\n        var serverResponse = user\n        serverResponse.objectId = \"yolo\"\n        serverResponse.createdAt = User.current?.createdAt\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let saved = try await user.save()\n        XCTAssertEqual(saved.objectId, serverResponse.objectId)\n    }\n\n    @MainActor\n    func testCreate() async throws {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        var user = User()\n        user.username = \"stop\"\n\n        var serverResponse = user\n        serverResponse.objectId = \"yolo\"\n        serverResponse.createdAt = Date()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                serverResponse = try serverResponse.getDecoder().decode(User.self, from: encoded)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let saved = try await user.create()\n        XCTAssertEqual(saved.objectId, serverResponse.objectId)\n        XCTAssertEqual(saved.createdAt, serverResponse.createdAt)\n        XCTAssertEqual(saved.updatedAt, serverResponse.createdAt)\n    }\n\n    @MainActor\n    func testReplaceCreate() async throws {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        var user = User()\n        user.username = \"stop\"\n        user.objectId = \"yolo\"\n\n        var serverResponse = user\n        serverResponse.createdAt = Date()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                serverResponse = try serverResponse.getDecoder().decode(User.self, from: encoded)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let saved = try await user.replace()\n        XCTAssertEqual(saved.objectId, serverResponse.objectId)\n        XCTAssertEqual(saved.createdAt, serverResponse.createdAt)\n        XCTAssertEqual(saved.updatedAt, serverResponse.createdAt)\n    }\n\n    @MainActor\n    func testReplaceUpdate() async throws {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        var user = User()\n        user.username = \"stop\"\n        user.objectId = \"yolo\"\n\n        var serverResponse = user\n        serverResponse.updatedAt = Date()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                serverResponse = try serverResponse.getDecoder().decode(User.self, from: encoded)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let saved = try await user.replace()\n        XCTAssertEqual(saved.objectId, serverResponse.objectId)\n        XCTAssertEqual(saved.updatedAt, serverResponse.updatedAt)\n    }\n\n    @MainActor\n    func testReplaceClientMissingObjectId() async throws {\n        var user = User()\n        user.customKey = \"123\"\n        do {\n            _ = try await user.replace()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted to ParseError\")\n                return\n            }\n            XCTAssertEqual(parseError.code, .missingObjectId)\n        }\n    }\n\n    @MainActor\n    func testUpdate() async throws {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        var user = User()\n        user.username = \"stop\"\n        user.objectId = \"yolo\"\n\n        var serverResponse = user\n        serverResponse.updatedAt = Date()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                serverResponse = try serverResponse.getDecoder().decode(User.self, from: encoded)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let saved = try await user.update()\n        XCTAssertEqual(saved.objectId, serverResponse.objectId)\n        XCTAssertEqual(saved.updatedAt, serverResponse.updatedAt)\n    }\n\n    @MainActor\n    func testUpdateDefaultMerge() async throws {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        var user = UserDefaultMerge()\n        user.username = \"stop\"\n        user.objectId = \"yolo\"\n\n        var serverResponse = user\n        serverResponse.updatedAt = Date()\n        serverResponse.customKey = \"be\"\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                serverResponse = try serverResponse.getDecoder().decode(UserDefaultMerge.self, from: encoded)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        user = user.set(\\.customKey, to: \"be\")\n        let saved = try await user.update()\n        XCTAssertEqual(saved.objectId, serverResponse.objectId)\n        XCTAssertEqual(saved.updatedAt, serverResponse.updatedAt)\n    }\n\n    @MainActor\n    func testUpdateClientMissingObjectId() async throws {\n        var user = User()\n        user.customKey = \"123\"\n        do {\n            _ = try await user.update()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let parseError = error as? ParseError else {\n                XCTFail(\"Should have casted to ParseError\")\n                return\n            }\n            XCTAssertEqual(parseError.code, .missingObjectId)\n        }\n    }\n\n    func testUpdateMutableMergeCurrentUser() async throws {\n        // Signup current User\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        guard let original = User.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n        var originalResponse = original.mergeable\n        originalResponse.createdAt = nil\n        originalResponse.updatedAt = Calendar.current.date(byAdding: .init(day: 1), to: Date())\n\n        let encoded: Data!\n        do {\n            encoded = try originalResponse.getEncoder().encode(originalResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            originalResponse = try originalResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        let response = originalResponse\n        var originalUpdated = original.mergeable\n        originalUpdated.customKey = \"beast\"\n        originalUpdated.username = \"mode\"\n        let updated = originalUpdated\n\n        do {\n            let saved = try await updated.update()\n            let expectation1 = XCTestExpectation(description: \"Update installation1\")\n            DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n                guard let newCurrentUser = User.current else {\n                    XCTFail(\"Should have a new current installation\")\n                    expectation1.fulfill()\n                    return\n                }\n                XCTAssertTrue(saved.hasSameObjectId(as: newCurrentUser))\n                XCTAssertTrue(saved.hasSameObjectId(as: response))\n                XCTAssertEqual(saved.customKey, updated.customKey)\n                XCTAssertEqual(saved.email, original.email)\n                XCTAssertEqual(saved.username, updated.username)\n                XCTAssertEqual(saved.emailVerified, original.emailVerified)\n                XCTAssertEqual(saved.password, original.password)\n                XCTAssertEqual(saved.authData, original.authData)\n                XCTAssertEqual(saved.createdAt, original.createdAt)\n                XCTAssertEqual(saved.updatedAt, response.updatedAt)\n                XCTAssertNil(saved.originalData)\n                XCTAssertEqual(saved.customKey, newCurrentUser.customKey)\n                XCTAssertEqual(saved.email, newCurrentUser.email)\n                XCTAssertEqual(saved.username, newCurrentUser.username)\n                XCTAssertEqual(saved.emailVerified, newCurrentUser.emailVerified)\n                XCTAssertEqual(saved.password, newCurrentUser.password)\n                XCTAssertEqual(saved.authData, newCurrentUser.authData)\n                XCTAssertEqual(saved.createdAt, newCurrentUser.createdAt)\n                XCTAssertEqual(saved.updatedAt, newCurrentUser.updatedAt)\n                expectation1.fulfill()\n            }\n            wait(for: [expectation1], timeout: 20.0)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testUpdateMutableMergeCurrentUserDefault() async throws {\n        // Signup current User\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(UserDefault.current?.objectId)\n\n        guard let original = UserDefault.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n        var originalResponse = original.mergeable\n        originalResponse.createdAt = nil\n        originalResponse.updatedAt = Calendar.current.date(byAdding: .init(day: 1), to: Date())\n\n        let encoded: Data!\n        do {\n            encoded = try originalResponse.getEncoder().encode(originalResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            originalResponse = try originalResponse.getDecoder().decode(UserDefault.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        let response = originalResponse\n        var originalUpdated = original.mergeable\n        originalUpdated.username = \"mode\"\n        let updated = originalUpdated\n\n        do {\n            let saved = try await updated.update()\n            let expectation1 = XCTestExpectation(description: \"Update installation1\")\n            DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n                guard let newCurrentUser = User.current else {\n                    XCTFail(\"Should have a new current installation\")\n                    expectation1.fulfill()\n                    return\n                }\n                XCTAssertTrue(saved.hasSameObjectId(as: newCurrentUser))\n                XCTAssertTrue(saved.hasSameObjectId(as: response))\n                XCTAssertEqual(saved.email, original.email)\n                XCTAssertEqual(saved.username, updated.username)\n                XCTAssertEqual(saved.emailVerified, original.emailVerified)\n                XCTAssertEqual(saved.password, original.password)\n                XCTAssertEqual(saved.authData, original.authData)\n                XCTAssertEqual(saved.createdAt, original.createdAt)\n                XCTAssertEqual(saved.updatedAt, response.updatedAt)\n                XCTAssertNil(saved.originalData)\n                XCTAssertEqual(saved.email, newCurrentUser.email)\n                XCTAssertEqual(saved.username, newCurrentUser.username)\n                XCTAssertEqual(saved.emailVerified, newCurrentUser.emailVerified)\n                XCTAssertEqual(saved.password, newCurrentUser.password)\n                XCTAssertEqual(saved.authData, newCurrentUser.authData)\n                XCTAssertEqual(saved.createdAt, newCurrentUser.createdAt)\n                XCTAssertEqual(saved.updatedAt, newCurrentUser.updatedAt)\n                expectation1.fulfill()\n            }\n            wait(for: [expectation1], timeout: 20.0)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    @MainActor\n    func testDelete() async throws {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        guard let user = User.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n\n        let serverResponse = NoBody()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        _ = try await user.delete()\n        if BaseParseUser.current != nil {\n            XCTFail(\"Could not get CurrentUser from Keychain\")\n        }\n    }\n\n    @MainActor\n    func testDeleteError() async throws {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        guard let user = User.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n\n        let serverResponse = ParseError(code: .objectNotFound, message: \"Not found\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        do {\n            _ = try await user.delete()\n            XCTFail(\"Should have thrown error\")\n        } catch {\n            guard let error = error as? ParseError else {\n                XCTFail(\"Should be ParseError\")\n                return\n            }\n            XCTAssertEqual(error.message, serverResponse.message)\n        }\n        XCTAssertNotNil(BaseParseUser.current)\n    }\n\n    @MainActor\n    func testFetchAll() async throws {\n        login()\n        MockURLProtocol.removeAll()\n        let expectation1 = XCTestExpectation(description: \"Fetch\")\n\n        guard var user = User.current else {\n                XCTFail(\"Should unwrap dates\")\n            expectation1.fulfill()\n                return\n        }\n\n        user.updatedAt = user.updatedAt?.addingTimeInterval(+300)\n        user.customKey = \"newValue\"\n        let userOnServer = QueryResponse<User>(results: [user], count: 1)\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(userOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(user)\n            user = try user.getDecoder().decode(User.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let fetched = try await [user].fetchAll()\n        fetched.forEach {\n            switch $0 {\n            case .success(let fetched):\n                XCTAssert(fetched.hasSameObjectId(as: user))\n                guard let fetchedCreatedAt = fetched.createdAt,\n                    let fetchedUpdatedAt = fetched.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation1.fulfill()\n                        return\n                }\n                guard let originalCreatedAt = user.createdAt,\n                    let originalUpdatedAt = user.updatedAt,\n                    let serverUpdatedAt = user.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation1.fulfill()\n                        return\n                }\n                XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n                XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n                XCTAssertEqual(fetchedUpdatedAt, serverUpdatedAt)\n                XCTAssertEqual(User.current?.customKey, user.customKey)\n\n                //Should be updated in memory\n                guard let updatedCurrentDate = User.current?.updatedAt else {\n                    XCTFail(\"Should unwrap current date\")\n                    expectation1.fulfill()\n                    return\n                }\n                XCTAssertEqual(updatedCurrentDate, serverUpdatedAt)\n\n                #if !os(Linux) && !os(Android) && !os(Windows)\n                //Should be updated in Keychain\n                guard let keychainUser: CurrentUserContainer<BaseParseUser>\n                    = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser),\n                    let keychainUpdatedCurrentDate = keychainUser.currentUser?.updatedAt else {\n                        XCTFail(\"Should get object from Keychain\")\n                        expectation1.fulfill()\n                    return\n                }\n                XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt)\n                #endif\n            case .failure(let error):\n                XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n            }\n        }\n    }\n\n    @MainActor\n    func testSaveAll() async throws {\n        login()\n        MockURLProtocol.removeAll()\n\n        guard var user = User.current else {\n            XCTFail(\"Should unwrap dates\")\n            return\n        }\n        user.createdAt = nil\n        user.updatedAt = user.updatedAt?.addingTimeInterval(+300)\n        user.customKey = \"newValue\"\n        let userOnServer = [BatchResponseItem<User>(success: user, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(userOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(user)\n            user = try user.getDecoder().decode(User.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await [user].saveAll()\n        saved.forEach {\n            switch $0 {\n            case .success(let saved):\n                XCTAssert(saved.hasSameObjectId(as: user))\n                guard let savedUpdatedAt = saved.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                guard let originalUpdatedAt = user.updatedAt,\n                    let serverUpdatedAt = user.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n                XCTAssertEqual(savedUpdatedAt, serverUpdatedAt)\n                XCTAssertEqual(User.current?.customKey, user.customKey)\n\n                //Should be updated in memory\n                guard let updatedCurrentDate = User.current?.updatedAt else {\n                    XCTFail(\"Should unwrap current date\")\n                    return\n                }\n                XCTAssertEqual(updatedCurrentDate, serverUpdatedAt)\n\n                #if !os(Linux) && !os(Android) && !os(Windows)\n                //Should be updated in Keychain\n                guard let keychainUser: CurrentUserContainer<BaseParseUser>\n                    = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser),\n                    let keychainUpdatedCurrentDate = keychainUser.currentUser?.updatedAt else {\n                        XCTFail(\"Should get object from Keychain\")\n                    return\n                }\n                XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt)\n                #endif\n            case .failure(let error):\n                XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n            }\n        }\n    }\n\n    @MainActor\n    func testCreateAll() async throws {\n        login()\n        MockURLProtocol.removeAll()\n\n        var user = User()\n        user.username = \"stop\"\n\n        var userOnServer = user\n        userOnServer.objectId = \"yolo\"\n        userOnServer.createdAt = Date()\n\n        let serverResponse = [BatchResponseItem<User>(success: userOnServer, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(userOnServer)\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await [user].createAll()\n        saved.forEach {\n            switch $0 {\n            case .success(let saved):\n                XCTAssert(saved.hasSameObjectId(as: userOnServer))\n                guard let savedCreatedAt = saved.createdAt,\n                    let savedUpdatedAt = saved.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                guard let originalCreatedAt = userOnServer.createdAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n                XCTAssertEqual(savedUpdatedAt, originalCreatedAt)\n\n            case .failure(let error):\n                XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n            }\n        }\n    }\n\n    @MainActor\n    func testReplaceAllCreate() async throws {\n        login()\n        MockURLProtocol.removeAll()\n\n        var user = User()\n        user.username = \"stop\"\n        user.objectId = \"yolo\"\n\n        var userOnServer = user\n        userOnServer.createdAt = Date()\n\n        let serverResponse = [BatchResponseItem<User>(success: userOnServer, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(userOnServer)\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await [user].replaceAll()\n        saved.forEach {\n            switch $0 {\n            case .success(let saved):\n                XCTAssert(saved.hasSameObjectId(as: userOnServer))\n                XCTAssertEqual(saved.createdAt, userOnServer.createdAt)\n                XCTAssertEqual(saved.updatedAt, userOnServer.createdAt)\n                XCTAssertEqual(saved.username, userOnServer.username)\n\n            case .failure(let error):\n                XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n            }\n        }\n    }\n\n    @MainActor\n    func testReplaceAllUpdate() async throws {\n        login()\n        MockURLProtocol.removeAll()\n\n        var user = User()\n        user.username = \"stop\"\n        user.objectId = \"yolo\"\n\n        var userOnServer = user\n        userOnServer.updatedAt = Date()\n\n        let serverResponse = [BatchResponseItem<User>(success: userOnServer, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(userOnServer)\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await [user].replaceAll()\n        saved.forEach {\n            switch $0 {\n            case .success(let saved):\n                XCTAssert(saved.hasSameObjectId(as: userOnServer))\n                guard let savedUpdatedAt = saved.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                guard let originalUpdatedAt = userOnServer.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n                XCTAssertEqual(saved.username, userOnServer.username)\n\n            case .failure(let error):\n                XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n            }\n        }\n    }\n\n    @MainActor\n    func testUpdateAll() async throws {\n        login()\n        MockURLProtocol.removeAll()\n\n        var user = User()\n        user.username = \"stop\"\n        user.objectId = \"yolo\"\n\n        var userOnServer = user\n        userOnServer.updatedAt = Date()\n\n        let serverResponse = [BatchResponseItem<User>(success: userOnServer, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(userOnServer)\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let saved = try await [user].updateAll()\n        saved.forEach {\n            switch $0 {\n            case .success(let saved):\n                XCTAssert(saved.hasSameObjectId(as: userOnServer))\n                guard let savedUpdatedAt = saved.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                guard let originalUpdatedAt = userOnServer.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        return\n                }\n                XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n                XCTAssertEqual(saved.username, userOnServer.username)\n\n            case .failure(let error):\n                XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n            }\n        }\n    }\n\n    @MainActor\n    func testDeleteAll() async throws {\n        login()\n        MockURLProtocol.removeAll()\n\n        guard let user = User.current else {\n            XCTFail(\"Should unwrap dates\")\n            return\n        }\n\n        let userOnServer = [BatchResponseItem<NoBody>(success: NoBody(), error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(userOnServer)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        try await [user].deleteAll()\n            .forEach {\n                if case let .failure(error) = $0 {\n                    XCTFail(\"Should have deleted: \\(error.localizedDescription)\")\n                }\n        }\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseUserCombineTests.swift",
    "content": "//\n//  ParseUserCombineTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 1/29/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\n#if canImport(Combine)\n\nimport Foundation\nimport XCTest\nimport Combine\n@testable import ParseSwift\n\nclass ParseUserCombineTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n        }\n    }\n\n    let loginUserName = \"hello10\"\n    let loginPassword = \"world\"\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testSignup() {\n        let loginResponse = LoginSignupResponse()\n        var subscriptions = Set<AnyCancellable>()\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Signup user1\")\n        let publisher = User.signupPublisher(username: loginUserName, password: loginUserName)\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { signedUp in\n            XCTAssertNotNil(signedUp)\n            XCTAssertNotNil(signedUp.createdAt)\n            XCTAssertNotNil(signedUp.updatedAt)\n            XCTAssertNotNil(signedUp.email)\n            XCTAssertNotNil(signedUp.username)\n            XCTAssertNil(signedUp.password)\n            XCTAssertNotNil(signedUp.objectId)\n            XCTAssertNotNil(signedUp.sessionToken)\n            XCTAssertNotNil(signedUp.customKey)\n            XCTAssertNil(signedUp.ACL)\n\n            guard let userFromKeychain = BaseParseUser.current else {\n                XCTFail(\"Could not get CurrentUser from Keychain\")\n                return\n            }\n\n            XCTAssertNotNil(userFromKeychain.createdAt)\n            XCTAssertNotNil(userFromKeychain.updatedAt)\n            XCTAssertNotNil(userFromKeychain.email)\n            XCTAssertNotNil(userFromKeychain.username)\n            XCTAssertNil(userFromKeychain.password)\n            XCTAssertNotNil(userFromKeychain.objectId)\n            XCTAssertNotNil(userFromKeychain.sessionToken)\n            XCTAssertNil(userFromKeychain.ACL)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSignupInstance() {\n        let loginResponse = LoginSignupResponse()\n        var subscriptions = Set<AnyCancellable>()\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Signup user1\")\n        var user = User()\n        user.username = loginUserName\n        user.password = loginPassword\n        user.email = \"parse@parse.com\"\n        user.customKey = \"blah\"\n        let publisher = user.signupPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { signedUp in\n            XCTAssertNotNil(signedUp)\n            XCTAssertNotNil(signedUp.createdAt)\n            XCTAssertNotNil(signedUp.updatedAt)\n            XCTAssertNotNil(signedUp.email)\n            XCTAssertNotNil(signedUp.username)\n            XCTAssertNil(signedUp.password)\n            XCTAssertNotNil(signedUp.objectId)\n            XCTAssertNotNil(signedUp.sessionToken)\n            XCTAssertNotNil(signedUp.customKey)\n            XCTAssertNil(signedUp.ACL)\n\n            guard let userFromKeychain = BaseParseUser.current else {\n                XCTFail(\"Could not get CurrentUser from Keychain\")\n                return\n            }\n\n            XCTAssertNotNil(userFromKeychain.createdAt)\n            XCTAssertNotNil(userFromKeychain.updatedAt)\n            XCTAssertNotNil(userFromKeychain.email)\n            XCTAssertNotNil(userFromKeychain.username)\n            XCTAssertNil(userFromKeychain.password)\n            XCTAssertNotNil(userFromKeychain.objectId)\n            XCTAssertNotNil(userFromKeychain.sessionToken)\n            XCTAssertNil(userFromKeychain.ACL)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLogin() {\n        let loginResponse = LoginSignupResponse()\n        var subscriptions = Set<AnyCancellable>()\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Login user1\")\n        let publisher = User.loginPublisher(username: loginUserName, password: loginUserName)\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { signedUp in\n            XCTAssertNotNil(signedUp)\n            XCTAssertNotNil(signedUp.createdAt)\n            XCTAssertNotNil(signedUp.updatedAt)\n            XCTAssertNotNil(signedUp.email)\n            XCTAssertNotNil(signedUp.username)\n            XCTAssertNil(signedUp.password)\n            XCTAssertNotNil(signedUp.objectId)\n            XCTAssertNotNil(signedUp.sessionToken)\n            XCTAssertNotNil(signedUp.customKey)\n            XCTAssertNil(signedUp.ACL)\n\n            guard let userFromKeychain = BaseParseUser.current else {\n                XCTFail(\"Could not get CurrentUser from Keychain\")\n                return\n            }\n\n            XCTAssertNotNil(userFromKeychain.createdAt)\n            XCTAssertNotNil(userFromKeychain.updatedAt)\n            XCTAssertNotNil(userFromKeychain.email)\n            XCTAssertNotNil(userFromKeychain.username)\n            XCTAssertNil(userFromKeychain.password)\n            XCTAssertNotNil(userFromKeychain.objectId)\n            XCTAssertNotNil(userFromKeychain.sessionToken)\n            XCTAssertNil(userFromKeychain.ACL)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func login() {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        do {\n            _ = try User.login(username: loginUserName, password: loginPassword)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testBecome() {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        guard let user = User.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.createdAt = User.current?.createdAt\n        serverResponse.updatedAt = User.current?.updatedAt?.addingTimeInterval(+300)\n        serverResponse.sessionToken = \"newValue\"\n        serverResponse.username = \"stop\"\n\n        var subscriptions = Set<AnyCancellable>()\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Become user1\")\n        let publisher = user.becomePublisher(sessionToken: serverResponse.sessionToken)\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { signedUp in\n            XCTAssertNotNil(signedUp)\n            XCTAssertNotNil(signedUp.createdAt)\n            XCTAssertNotNil(signedUp.updatedAt)\n            XCTAssertNotNil(signedUp.email)\n            XCTAssertNotNil(signedUp.username)\n            XCTAssertNil(signedUp.password)\n            XCTAssertNotNil(signedUp.objectId)\n            XCTAssertNotNil(signedUp.sessionToken)\n            XCTAssertNotNil(signedUp.customKey)\n            XCTAssertNil(signedUp.ACL)\n\n            guard let userFromKeychain = BaseParseUser.current else {\n                XCTFail(\"Could not get CurrentUser from Keychain\")\n                return\n            }\n\n            XCTAssertNotNil(userFromKeychain.createdAt)\n            XCTAssertNotNil(userFromKeychain.updatedAt)\n            XCTAssertNotNil(userFromKeychain.email)\n            XCTAssertNotNil(userFromKeychain.username)\n            XCTAssertNil(userFromKeychain.password)\n            XCTAssertNotNil(userFromKeychain.objectId)\n            XCTAssertNotNil(userFromKeychain.sessionToken)\n            XCTAssertNil(userFromKeychain.ACL)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLogout() {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        let serverResponse = NoBody()\n\n        var subscriptions = Set<AnyCancellable>()\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Logout user1\")\n        guard let oldInstallationId = BaseParseInstallation.current?.installationId else {\n            XCTFail(\"Should have unwrapped\")\n            expectation1.fulfill()\n            return\n        }\n        let publisher = User.logoutPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                if let userFromKeychain = BaseParseUser.current {\n                    XCTFail(\"\\(userFromKeychain) was not deleted from Keychain during logout\")\n                }\n                DispatchQueue.main.asyncAfter(deadline: .now() + 1) {\n                    if let installationFromMemory: CurrentInstallationContainer<BaseParseInstallation>\n                        = try? ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentInstallation) {\n                        if installationFromMemory.installationId == oldInstallationId\n                            || installationFromMemory.installationId == nil {\n                            XCTFail(\"\\(installationFromMemory) was not deleted and recreated in memory during logout\")\n                        }\n                    } else {\n                        XCTFail(\"Should have a new installation\")\n                    }\n\n                    #if !os(Linux) && !os(Android) && !os(Windows)\n                    if let installationFromKeychain: CurrentInstallationContainer<BaseParseInstallation>\n                        = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) {\n                        if installationFromKeychain.installationId == oldInstallationId\n                            || installationFromKeychain.installationId == nil {\n                            XCTFail(\"\\(installationFromKeychain) was not deleted & recreated in Keychain during logout\")\n                        }\n                    } else {\n                        XCTFail(\"Should have a new installation\")\n                    }\n                    #endif\n                    expectation1.fulfill()\n                }\n\n        }, receiveValue: { _ in })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLogoutError() {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        let serverResponse = ParseError(code: .internalServer, message: \"Object not found\")\n\n        var subscriptions = Set<AnyCancellable>()\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Logout user1\")\n        guard let oldInstallationId = BaseParseInstallation.current?.installationId else {\n            XCTFail(\"Should have unwrapped\")\n            expectation1.fulfill()\n            return\n        }\n        let publisher = User.logoutPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case .finished = result {\n                    XCTFail(\"Should have thrown ParseError\")\n                }\n\n                if let userFromKeychain = BaseParseUser.current {\n                    XCTFail(\"\\(userFromKeychain) was not deleted from Keychain during logout\")\n                }\n                DispatchQueue.main.asyncAfter(deadline: .now() + 1) {\n                    if let installationFromMemory: CurrentInstallationContainer<BaseParseInstallation>\n                        = try? ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentInstallation) {\n                            if installationFromMemory.installationId == oldInstallationId\n                                || installationFromMemory.installationId == nil {\n                                XCTFail(\"\\(installationFromMemory) was not deleted & recreated in memory during logout\")\n                            }\n                    } else {\n                        XCTFail(\"Should have a new installation\")\n                    }\n\n                    #if !os(Linux) && !os(Android) && !os(Windows)\n                    if let installationFromKeychain: CurrentInstallationContainer<BaseParseInstallation>\n                        = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) {\n                            if installationFromKeychain.installationId == oldInstallationId\n                                || installationFromKeychain.installationId == nil {\n                                // swiftlint:disable:next line_length\n                                XCTFail(\"\\(installationFromKeychain) was not deleted & recreated in Keychain during logout\")\n                            }\n                    } else {\n                        XCTFail(\"Should have a new installation\")\n                    }\n                    #endif\n                    expectation1.fulfill()\n                }\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown ParseError\")\n            expectation1.fulfill()\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testPasswordReset() {\n        let serverResponse = NoBody()\n\n        var subscriptions = Set<AnyCancellable>()\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Password user1\")\n        let publisher = User.passwordResetPublisher(email: \"hello@parse.org\")\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testPasswordResetError() {\n        let parseError = ParseError(code: .internalServer, message: \"Object not found\")\n\n        var subscriptions = Set<AnyCancellable>()\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(parseError)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Password user1\")\n        let publisher = User.passwordResetPublisher(email: \"hello@parse.org\")\n            .sink(receiveCompletion: { result in\n\n                if case .finished = result {\n                    XCTFail(\"Should have thrown ParseError\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown ParseError\")\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testVerifyPassword() {\n        let serverResponse = LoginSignupResponse()\n\n        var subscriptions = Set<AnyCancellable>()\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Verify password user1\")\n        let publisher = User.verifyPasswordPublisher(password: \"world\")\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { currentUser in\n\n            XCTAssertNotNil(currentUser)\n            XCTAssertNotNil(currentUser.createdAt)\n            XCTAssertNotNil(currentUser.updatedAt)\n            XCTAssertNotNil(currentUser.email)\n            XCTAssertNotNil(currentUser.username)\n            XCTAssertNil(currentUser.password)\n            XCTAssertNotNil(currentUser.objectId)\n            XCTAssertNotNil(currentUser.sessionToken)\n            XCTAssertNotNil(currentUser.customKey)\n            XCTAssertNil(currentUser.ACL)\n\n            guard let userFromKeychain = BaseParseUser.current else {\n                XCTFail(\"Could not get CurrentUser from Keychain\")\n                return\n            }\n\n            XCTAssertNotNil(userFromKeychain.createdAt)\n            XCTAssertNotNil(userFromKeychain.updatedAt)\n            XCTAssertNotNil(userFromKeychain.email)\n            XCTAssertNotNil(userFromKeychain.username)\n            XCTAssertNil(userFromKeychain.password)\n            XCTAssertNotNil(userFromKeychain.objectId)\n            XCTAssertNotNil(userFromKeychain.sessionToken)\n            XCTAssertNil(userFromKeychain.ACL)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testVerifyPasswordError() {\n        let parseError = ParseError(code: .userWithEmailNotFound,\n                                    message: \"User email is not verified.\")\n\n        var subscriptions = Set<AnyCancellable>()\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(parseError)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Verify password user1\")\n        let publisher = User.verifyPasswordPublisher(password: \"world\")\n            .sink(receiveCompletion: { result in\n\n                if case .finished = result {\n                    XCTFail(\"Should have thrown ParseError\")\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown ParseError\")\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testVerificationEmail() {\n        let serverResponse = NoBody()\n\n        var subscriptions = Set<AnyCancellable>()\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Verification user1\")\n        let publisher = User.verificationEmailPublisher(email: \"hello@parse.org\")\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testVerificationEmailError() {\n        let parseError = ParseError(code: .internalServer, message: \"Object not found\")\n\n        var subscriptions = Set<AnyCancellable>()\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(parseError)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Verification user1\")\n        let publisher = User.verificationEmailPublisher(email: \"hello@parse.org\")\n            .sink(receiveCompletion: { result in\n\n                if case .failure(let error) = result {\n                    XCTAssertEqual(error.message, parseError.message)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n            XCTFail(\"Should have thrown ParseError\")\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testFetch() {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        guard let user = User.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.createdAt = User.current?.createdAt\n        serverResponse.updatedAt = User.current?.updatedAt?.addingTimeInterval(+300)\n        serverResponse.sessionToken = \"newValue\"\n        serverResponse.username = \"stop\"\n\n        var subscriptions = Set<AnyCancellable>()\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Become user1\")\n        let publisher = user.fetchPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { fetched in\n\n            XCTAssertEqual(fetched.objectId, serverResponse.objectId)\n\n            guard let userFromKeychain = BaseParseUser.current else {\n                XCTFail(\"Could not get CurrentUser from Keychain\")\n                return\n            }\n\n            XCTAssertEqual(userFromKeychain.objectId, serverResponse.objectId)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSave() {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        guard let user = User.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.createdAt = User.current?.createdAt\n        serverResponse.updatedAt = User.current?.updatedAt?.addingTimeInterval(+300)\n        serverResponse.sessionToken = \"newValue\"\n        serverResponse.username = \"stop\"\n\n        var subscriptions = Set<AnyCancellable>()\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Become user1\")\n        let publisher = user.savePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            XCTAssertEqual(saved.objectId, serverResponse.objectId)\n\n            guard let userFromKeychain = BaseParseUser.current else {\n                XCTFail(\"Could not get CurrentUser from Keychain\")\n                return\n            }\n\n            XCTAssertEqual(userFromKeychain.objectId, serverResponse.objectId)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testCreate() {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        var user = User()\n        user.username = \"stop\"\n\n        var serverResponse = user\n        serverResponse.objectId = \"yolo\"\n        serverResponse.createdAt = Date()\n\n        var subscriptions = Set<AnyCancellable>()\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                serverResponse = try user.getDecoder().decode(User.self, from: encoded)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Become user1\")\n        let publisher = user.createPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            XCTAssertTrue(saved.hasSameObjectId(as: serverResponse))\n            XCTAssertEqual(saved.username, serverResponse.username)\n            XCTAssertEqual(saved.createdAt, serverResponse.createdAt)\n            XCTAssertEqual(saved.updatedAt, serverResponse.createdAt)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUpdate() {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        var user = User()\n        user.username = \"stop\"\n        user.objectId = \"yolo\"\n\n        var serverResponse = user\n        serverResponse.updatedAt = Date()\n\n        var subscriptions = Set<AnyCancellable>()\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n                serverResponse = try user.getDecoder().decode(User.self, from: encoded)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Become user1\")\n        let publisher = user.updatePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            XCTAssertTrue(saved.hasSameObjectId(as: serverResponse))\n            XCTAssertEqual(saved.username, serverResponse.username)\n            XCTAssertEqual(saved.updatedAt, serverResponse.updatedAt)\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n    func testDelete() {\n        login()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        guard let user = User.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n\n        let serverResponse = NoBody()\n\n        var subscriptions = Set<AnyCancellable>()\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(serverResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Become user1\")\n        let publisher = user.deletePublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { _ in\n\n            if BaseParseUser.current != nil {\n                XCTFail(\"Could not get CurrentUser from Keychain\")\n            }\n        })\n        publisher.store(in: &subscriptions)\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testFetchAll() {\n        login()\n        MockURLProtocol.removeAll()\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Fetch\")\n\n        guard var user = User.current else {\n                XCTFail(\"Should unwrap dates\")\n            expectation1.fulfill()\n                return\n        }\n\n        user.updatedAt = user.updatedAt?.addingTimeInterval(+300)\n        user.customKey = \"newValue\"\n        let userOnServer = QueryResponse<User>(results: [user], count: 1)\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(userOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(user)\n            user = try user.getDecoder().decode(User.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = [user].fetchAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { fetched in\n\n            fetched.forEach {\n                switch $0 {\n                case .success(let fetched):\n                    XCTAssert(fetched.hasSameObjectId(as: user))\n                    guard let fetchedCreatedAt = fetched.createdAt,\n                        let fetchedUpdatedAt = fetched.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    guard let originalCreatedAt = user.createdAt,\n                        let originalUpdatedAt = user.updatedAt,\n                        let serverUpdatedAt = user.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n                    XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n                    XCTAssertEqual(fetchedUpdatedAt, serverUpdatedAt)\n                    XCTAssertEqual(User.current?.customKey, user.customKey)\n\n                    //Should be updated in memory\n                    guard let updatedCurrentDate = User.current?.updatedAt else {\n                        XCTFail(\"Should unwrap current date\")\n                        expectation1.fulfill()\n                        return\n                    }\n                    XCTAssertEqual(updatedCurrentDate, serverUpdatedAt)\n\n                    #if !os(Linux) && !os(Android) && !os(Windows)\n                    //Should be updated in Keychain\n                    guard let keychainUser: CurrentUserContainer<BaseParseUser>\n                        = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser),\n                        let keychainUpdatedCurrentDate = keychainUser.currentUser?.updatedAt else {\n                            XCTFail(\"Should get object from Keychain\")\n                            expectation1.fulfill()\n                        return\n                    }\n                    XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt)\n                    #endif\n                case .failure(let error):\n                    XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                }\n            }\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSaveAll() {\n        login()\n        MockURLProtocol.removeAll()\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        guard var user = User.current else {\n                XCTFail(\"Should unwrap dates\")\n            expectation1.fulfill()\n                return\n        }\n        user.createdAt = nil\n        user.updatedAt = user.updatedAt?.addingTimeInterval(+300)\n        user.customKey = \"newValue\"\n        let userOnServer = [BatchResponseItem<User>(success: user, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(userOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(user)\n            user = try user.getDecoder().decode(User.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = [user].saveAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            saved.forEach {\n                switch $0 {\n                case .success(let saved):\n                    XCTAssert(saved.hasSameObjectId(as: user))\n                    guard let savedUpdatedAt = saved.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    guard let originalUpdatedAt = user.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n                    XCTAssertEqual(User.current?.customKey, user.customKey)\n\n                    //Should be updated in memory\n                    guard let updatedCurrentDate = User.current?.updatedAt else {\n                        XCTFail(\"Should unwrap current date\")\n                        expectation1.fulfill()\n                        return\n                    }\n                    XCTAssertEqual(updatedCurrentDate, originalUpdatedAt)\n\n                    #if !os(Linux) && !os(Android) && !os(Windows)\n                    //Should be updated in Keychain\n                    guard let keychainUser: CurrentUserContainer<BaseParseUser>\n                        = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser),\n                        let keychainUpdatedCurrentDate = keychainUser.currentUser?.updatedAt else {\n                            XCTFail(\"Should get object from Keychain\")\n                            expectation1.fulfill()\n                        return\n                    }\n                    XCTAssertEqual(keychainUpdatedCurrentDate, originalUpdatedAt)\n                    #endif\n                case .failure(let error):\n                    XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                }\n            }\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testCreateAll() {\n        login()\n        MockURLProtocol.removeAll()\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var user = User()\n        user.username = \"stop\"\n\n        var serverResponse = user\n        serverResponse.objectId = \"yolo\"\n        serverResponse.createdAt = Date()\n        let userOnServer = [BatchResponseItem<User>(success: serverResponse, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(userOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(serverResponse)\n            serverResponse = try user.getDecoder().decode(User.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = [user].createAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            saved.forEach {\n                switch $0 {\n                case .success(let saved):\n                    XCTAssertTrue(saved.hasSameObjectId(as: serverResponse))\n                    guard let savedCreatedAt = saved.createdAt,\n                        let savedUpdatedAt = saved.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    guard let originalCreatedAt = serverResponse.createdAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n                    XCTAssertEqual(savedUpdatedAt, originalCreatedAt)\n\n                case .failure(let error):\n                    XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                }\n            }\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testReplaceAllCreate() {\n        login()\n        MockURLProtocol.removeAll()\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var user = User()\n        user.username = \"stop\"\n        user.objectId = \"yolo\"\n\n        var serverResponse = user\n        serverResponse.createdAt = Date()\n        let userOnServer = [BatchResponseItem<User>(success: serverResponse, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(userOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(serverResponse)\n            serverResponse = try user.getDecoder().decode(User.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = [user].replaceAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            saved.forEach {\n                switch $0 {\n                case .success(let saved):\n                    XCTAssertTrue(saved.hasSameObjectId(as: serverResponse))\n                    XCTAssertEqual(saved.createdAt, serverResponse.createdAt)\n                    XCTAssertEqual(saved.updatedAt, serverResponse.createdAt)\n\n                case .failure(let error):\n                    XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                }\n            }\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testReplaceAllUpdate() {\n        login()\n        MockURLProtocol.removeAll()\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var user = User()\n        user.username = \"stop\"\n        user.objectId = \"yolo\"\n\n        var serverResponse = user\n        serverResponse.updatedAt = Date()\n        let userOnServer = [BatchResponseItem<User>(success: serverResponse, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(userOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(serverResponse)\n            serverResponse = try user.getDecoder().decode(User.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = [user].replaceAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            saved.forEach {\n                switch $0 {\n                case .success(let saved):\n                    XCTAssertTrue(saved.hasSameObjectId(as: serverResponse))\n                    guard let savedUpdatedAt = saved.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    guard let originalUpdatedAt = serverResponse.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n\n                case .failure(let error):\n                    XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                }\n            }\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUpdateAll() {\n        login()\n        MockURLProtocol.removeAll()\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        var user = User()\n        user.username = \"stop\"\n        user.objectId = \"yolo\"\n\n        var serverResponse = user\n        serverResponse.updatedAt = Date()\n        let userOnServer = [BatchResponseItem<User>(success: serverResponse, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(userOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(serverResponse)\n            serverResponse = try user.getDecoder().decode(User.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = [user].updateAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { saved in\n\n            saved.forEach {\n                switch $0 {\n                case .success(let saved):\n                    XCTAssertTrue(saved.hasSameObjectId(as: serverResponse))\n                    guard let savedUpdatedAt = saved.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    guard let originalUpdatedAt = serverResponse.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            expectation1.fulfill()\n                            return\n                    }\n                    XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n\n                case .failure(let error):\n                    XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                }\n            }\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testDeleteAll() {\n        login()\n        MockURLProtocol.removeAll()\n        var subscriptions = Set<AnyCancellable>()\n        let expectation1 = XCTestExpectation(description: \"Save\")\n\n        guard let user = User.current else {\n                XCTFail(\"Should unwrap dates\")\n                expectation1.fulfill()\n                return\n        }\n\n        let userOnServer = [BatchResponseItem<NoBody>(success: NoBody(), error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(userOnServer)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let publisher = [user].deleteAllPublisher()\n            .sink(receiveCompletion: { result in\n\n                if case let .failure(error) = result {\n                    XCTFail(error.localizedDescription)\n                }\n                expectation1.fulfill()\n\n        }, receiveValue: { deleted in\n            deleted.forEach {\n                if case let .failure(error) = $0 {\n                    XCTFail(\"Should have deleted: \\(error.localizedDescription)\")\n                }\n            }\n        })\n        publisher.store(in: &subscriptions)\n\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n\n#endif\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseUserTests.swift",
    "content": "//\n//  ParseUserTests.swift\n//  ParseSwiftTests\n//\n//  Created by Corey Baker on 7/21/20.\n//  Copyright © 2020 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseUserTests: XCTestCase { // swiftlint:disable:this type_body_length\n\n    struct User: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        //: Implement your own version of merge\n        func merge(with object: Self) throws -> Self {\n            var updated = try mergeParse(with: object)\n            if updated.shouldRestoreKey(\\.customKey,\n                                         original: object) {\n                updated.customKey = object.customKey\n            }\n            return updated\n        }\n    }\n\n    struct UserDefaultMerge: ParseUser {\n\n        //: These are required by ParseObject\n        var objectId: String?\n        var createdAt: Date?\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n    }\n\n    struct LoginSignupResponse: ParseUser {\n\n        var objectId: String?\n        var createdAt: Date?\n        var sessionToken: String\n        var updatedAt: Date?\n        var ACL: ParseACL?\n        var originalData: Data?\n\n        // These are required by ParseUser\n        var username: String?\n        var email: String?\n        var emailVerified: Bool?\n        var password: String?\n        var authData: [String: [String: String]?]?\n\n        // Your custom keys\n        var customKey: String?\n\n        init() {\n            let date = Date()\n            self.createdAt = date\n            self.updatedAt = date\n            self.objectId = \"yarr\"\n            self.ACL = nil\n            self.customKey = \"blah\"\n            self.sessionToken = \"myToken\"\n            self.username = \"hello10\"\n            self.email = \"hello@parse.com\"\n            self.emailVerified = false\n        }\n\n        func createUser() -> User {\n            var user = User()\n            user.objectId = objectId\n            user.ACL = ACL\n            user.customKey = customKey\n            user.username = username\n            user.email = email\n            return user\n        }\n    }\n\n    let loginUserName = \"hello10\"\n    let loginPassword = \"world\"\n\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testMerge() throws {\n        // Signup current User\n        XCTAssertNil(User.current?.objectId)\n        try userSignUp()\n        XCTAssertNotNil(User.current?.objectId)\n\n        guard var original = User.current else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        original.objectId = \"yolo\"\n        original.createdAt = Date()\n        original.updatedAt = Date()\n        original.authData = [\"hello\": [\"world\": \"yolo\"]]\n        var acl = ParseACL()\n        acl.publicRead = true\n        original.ACL = acl\n\n        var updated = original.mergeable\n        updated.updatedAt = Calendar.current.date(byAdding: .init(day: 1), to: Date())\n        updated.email = \"swift@parse.com\"\n        updated.username = \"12345\"\n        updated.customKey = \"newKey\"\n        let merged = try updated.merge(with: original)\n        XCTAssertEqual(merged.customKey, updated.customKey)\n        XCTAssertEqual(merged.email, updated.email)\n        XCTAssertEqual(merged.emailVerified, original.emailVerified)\n        XCTAssertEqual(merged.username, updated.username)\n        XCTAssertEqual(merged.authData, original.authData)\n        XCTAssertEqual(merged.ACL, original.ACL)\n        XCTAssertEqual(merged.createdAt, original.createdAt)\n        XCTAssertEqual(merged.updatedAt, updated.updatedAt)\n    }\n\n    func testMerge2() throws {\n        // Signup current User\n        XCTAssertNil(User.current?.objectId)\n        try userSignUp()\n        XCTAssertNotNil(User.current?.objectId)\n\n        guard var original = User.current else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        original.objectId = \"yolo\"\n        original.createdAt = Date()\n        original.updatedAt = Date()\n        var acl = ParseACL()\n        acl.publicRead = true\n        original.ACL = acl\n\n        var updated = original.mergeable\n        updated.updatedAt = Calendar.current.date(byAdding: .init(day: 1), to: Date())\n        updated.customKey = \"newKey\"\n        let merged = try updated.merge(with: original)\n        XCTAssertEqual(merged.customKey, updated.customKey)\n        XCTAssertEqual(merged.email, original.email)\n        XCTAssertEqual(merged.emailVerified, original.emailVerified)\n        XCTAssertEqual(merged.username, original.username)\n        XCTAssertEqual(merged.authData, original.authData)\n        XCTAssertEqual(merged.ACL, original.ACL)\n        XCTAssertEqual(merged.createdAt, original.createdAt)\n        XCTAssertEqual(merged.updatedAt, updated.updatedAt)\n    }\n\n    func testMergeDefaultImplementation() throws {\n        // Signup current User\n        XCTAssertNil(User.current?.objectId)\n        try userSignUp()\n        XCTAssertNotNil(User.current?.objectId)\n\n        guard let currentUser = User.current else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        var original = UserDefaultMerge()\n        original.username = currentUser.username\n        original.email = currentUser.email\n        original.customKey = currentUser.customKey\n        original.objectId = \"yolo\"\n        original.createdAt = Date()\n        original.updatedAt = Date()\n        var acl = ParseACL()\n        acl.publicRead = true\n        original.ACL = acl\n\n        var updated = original.set(\\.customKey, to: \"newKey\")\n        updated.updatedAt = Calendar.current.date(byAdding: .init(day: 1), to: Date())\n        original.customKey = updated.customKey\n        original.updatedAt = updated.updatedAt\n        var merged = try updated.merge(with: original)\n        merged.originalData = nil\n        // Get dates in correct format from ParseDecoding strategy\n        let encoded = try ParseCoding.jsonEncoder().encode(original)\n        original = try ParseCoding.jsonDecoder().decode(UserDefaultMerge.self, from: encoded)\n        XCTAssertEqual(merged, original)\n    }\n\n    func testMergeDifferentObjectId() throws {\n        var user = User()\n        user.objectId = \"yolo\"\n        var user2 = user\n        user2.objectId = \"nolo\"\n        XCTAssertThrowsError(try user2.merge(with: user))\n    }\n\n    func testFetchCommand() {\n        var user = User()\n        XCTAssertThrowsError(try user.fetchCommand(include: nil))\n        let objectId = \"yarr\"\n        user.objectId = objectId\n        do {\n            let command = try user.fetchCommand(include: nil)\n            XCTAssertNotNil(command)\n            XCTAssertEqual(command.path.urlComponent, \"/users/\\(objectId)\")\n            XCTAssertEqual(command.method, API.Method.GET)\n            XCTAssertNil(command.params)\n            XCTAssertNil(command.body)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        let user2 = User()\n        XCTAssertThrowsError(try user2.fetchCommand(include: nil))\n    }\n\n    func testFetchIncludeCommand() {\n        var user = User()\n        let objectId = \"yarr\"\n        user.objectId = objectId\n        let includeExpected = [\"include\": \"[\\\"yolo\\\", \\\"test\\\"]\"]\n        do {\n            let command = try user.fetchCommand(include: [\"yolo\", \"test\"])\n            XCTAssertNotNil(command)\n            XCTAssertEqual(command.path.urlComponent, \"/users/\\(objectId)\")\n            XCTAssertEqual(command.method, API.Method.GET)\n            XCTAssertEqual(command.params?.keys.first, includeExpected.keys.first)\n            if let value = command.params?.values.first,\n                let includeValue = value {\n                XCTAssertTrue(includeValue.contains(\"\\\"yolo\\\"\"))\n            } else {\n                XCTFail(\"Should have unwrapped value\")\n            }\n            XCTAssertNil(command.body)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        let user2 = User()\n        XCTAssertThrowsError(try user2.fetchCommand(include: nil))\n    }\n\n    func testFetch() { // swiftlint:disable:this function_body_length\n        var user = User()\n        let objectId = \"yarr\"\n        user.objectId = objectId\n\n        var userOnServer = user\n        userOnServer.createdAt = Date()\n        userOnServer.updatedAt = userOnServer.createdAt\n        userOnServer.ACL = nil\n        let encoded: Data!\n        do {\n            encoded = try userOnServer.getEncoder().encode(userOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            let fetched = try user.fetch()\n            XCTAssert(fetched.hasSameObjectId(as: userOnServer))\n            guard let fetchedCreatedAt = fetched.createdAt,\n                let fetchedUpdatedAt = fetched.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalCreatedAt = userOnServer.createdAt,\n                let originalUpdatedAt = userOnServer.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n            XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(fetched.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        do {\n            let fetched = try user.fetch(options: [.useMasterKey])\n            XCTAssert(fetched.hasSameObjectId(as: userOnServer))\n            guard let fetchedCreatedAt = fetched.createdAt,\n                let fetchedUpdatedAt = fetched.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalCreatedAt = userOnServer.createdAt,\n                let originalUpdatedAt = userOnServer.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n            XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(fetched.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testFetchAndUpdateCurrentUser() { // swiftlint:disable:this function_body_length\n        testLogin()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        guard let user = User.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n\n        var userOnServer = user\n        userOnServer.createdAt = User.current?.createdAt\n        userOnServer.updatedAt = User.current?.updatedAt?.addingTimeInterval(+300)\n        userOnServer.customKey = \"newValue\"\n\n        let encoded: Data!\n        do {\n            encoded = try userOnServer.getEncoder().encode(userOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            let fetched = try user.fetch(options: [.useMasterKey])\n            XCTAssert(fetched.hasSameObjectId(as: userOnServer))\n            guard let fetchedCreatedAt = fetched.createdAt,\n                let fetchedUpdatedAt = fetched.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalCreatedAt = user.createdAt,\n                let originalUpdatedAt = user.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n            XCTAssertGreaterThan(fetchedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(fetched.ACL)\n            XCTAssertEqual(fetched.customKey, userOnServer.customKey)\n\n            //Should be updated in memory\n            XCTAssertEqual(User.current?.updatedAt, fetchedUpdatedAt)\n            XCTAssertEqual(User.current?.customKey, userOnServer.customKey)\n\n            //Should be updated in Keychain\n            #if !os(Linux) && !os(Android) && !os(Windows)\n            guard let keychainUser: CurrentUserContainer<BaseParseUser>\n                = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser) else {\n                    XCTFail(\"Should get object from Keychain\")\n                return\n            }\n            XCTAssertEqual(keychainUser.currentUser?.updatedAt, fetchedUpdatedAt)\n            #endif\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testFetchAsyncAndUpdateCurrentUser() { // swiftlint:disable:this function_body_length\n        XCTAssertNil(User.current?.objectId)\n        testLogin()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        guard let user = User.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n\n        var userOnServer = user\n        userOnServer.createdAt = User.current?.createdAt\n        userOnServer.updatedAt = User.current?.updatedAt?.addingTimeInterval(+300)\n        userOnServer.customKey = \"newValue\"\n\n        let encoded: Data!\n        do {\n            encoded = try userOnServer.getEncoder().encode(userOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Fetch user1\")\n        user.fetch(options: [], callbackQueue: .global(qos: .background)) { result in\n\n            switch result {\n            case .success(let fetched):\n                XCTAssert(fetched.hasSameObjectId(as: userOnServer))\n                guard let fetchedCreatedAt = fetched.createdAt,\n                    let fetchedUpdatedAt = fetched.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                    expectation1.fulfill()\n                        return\n                }\n                guard let originalCreatedAt = user.createdAt,\n                    let originalUpdatedAt = user.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                    expectation1.fulfill()\n                        return\n                }\n                XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n                XCTAssertGreaterThan(fetchedUpdatedAt, originalUpdatedAt)\n                XCTAssertNil(fetched.ACL)\n                XCTAssertEqual(User.current?.customKey, userOnServer.customKey)\n\n                //Should be updated in memory\n                XCTAssertEqual(User.current?.updatedAt, fetchedUpdatedAt)\n\n                #if !os(Linux) && !os(Android) && !os(Windows)\n                //Should be updated in Keychain\n                guard let keychainUser: CurrentUserContainer<BaseParseUser>\n                    = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser) else {\n                        XCTFail(\"Should get object from Keychain\")\n                        expectation1.fulfill()\n                    return\n                }\n                XCTAssertEqual(keychainUser.currentUser?.updatedAt, fetchedUpdatedAt)\n                #endif\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    // swiftlint:disable:next function_body_length\n    func fetchAsync(user: User, userOnServer: User) {\n\n        let expectation1 = XCTestExpectation(description: \"Fetch user1\")\n        user.fetch(options: [], callbackQueue: .global(qos: .background)) { result in\n\n            switch result {\n\n            case .success(let fetched):\n                XCTAssert(fetched.hasSameObjectId(as: userOnServer))\n                guard let fetchedCreatedAt = fetched.createdAt,\n                    let fetchedUpdatedAt = fetched.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation1.fulfill()\n                        return\n                }\n                guard let originalCreatedAt = userOnServer.createdAt,\n                    let originalUpdatedAt = userOnServer.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation1.fulfill()\n                        return\n                }\n                XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n                XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n                XCTAssertNil(fetched.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n\n        let expectation2 = XCTestExpectation(description: \"Fetch user2\")\n        user.fetch(options: [.sessionToken(\"\")], callbackQueue: .global(qos: .background)) { result in\n\n            switch result {\n\n            case .success(let fetched):\n                XCTAssert(fetched.hasSameObjectId(as: userOnServer))\n                guard let fetchedCreatedAt = fetched.createdAt,\n                    let fetchedUpdatedAt = fetched.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation2.fulfill()\n                        return\n                }\n                guard let originalCreatedAt = userOnServer.createdAt,\n                    let originalUpdatedAt = userOnServer.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                        expectation2.fulfill()\n                        return\n                }\n                XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n                XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n                XCTAssertNil(fetched.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testThreadSafeFetchAsync() {\n        var user = User()\n        let objectId = \"yarr\"\n        user.objectId = objectId\n\n        var userOnServer = user\n        userOnServer.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        userOnServer.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        userOnServer.ACL = nil\n        let encoded: Data!\n        do {\n            encoded = try userOnServer.getEncoder().encode(userOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        DispatchQueue.concurrentPerform(iterations: 100) {_ in\n            self.fetchAsync(user: user, userOnServer: userOnServer)\n        }\n    }\n    #endif\n\n    func testSaveCommand() throws {\n        let user = User()\n\n        let command = try user.saveCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/users\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertNil(command.params)\n        XCTAssertNotNil(command.body)\n    }\n\n    func testSaveUpdateCommand() throws {\n        var user = User()\n        let objectId = \"yarr\"\n        user.objectId = objectId\n\n        let command = try user.saveCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/users/\\(objectId)\")\n        XCTAssertEqual(command.method, API.Method.PUT)\n        XCTAssertNil(command.params)\n        XCTAssertNotNil(command.body)\n    }\n\n    func testCreateCommand() throws {\n        let user = User()\n\n        let command = user.createCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/users\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertNil(command.params)\n        XCTAssertNotNil(command.body)\n    }\n\n    func testReplaceCommand() throws {\n        var user = User()\n        XCTAssertThrowsError(try user.replaceCommand())\n        let objectId = \"yarr\"\n        user.objectId = objectId\n\n        let command = try user.replaceCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/users/\\(objectId)\")\n        XCTAssertEqual(command.method, API.Method.PUT)\n        XCTAssertNil(command.params)\n        XCTAssertNotNil(command.body)\n    }\n\n    func testUpdateCommand() throws {\n        var user = User()\n        XCTAssertThrowsError(try user.updateCommand())\n        let objectId = \"yarr\"\n        user.objectId = objectId\n\n        let command = try user.updateCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/users/\\(objectId)\")\n        XCTAssertEqual(command.method, API.Method.PATCH)\n        XCTAssertNil(command.params)\n        XCTAssertNotNil(command.body)\n    }\n\n    func userSignUp() throws {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        _ = try loginResponse.createUser().signup()\n        MockURLProtocol.removeAll()\n        guard let currentUser = User.current else {\n            XCTFail(\"Should have a current user after signup\")\n            return\n        }\n        XCTAssertEqual(currentUser.objectId, loginResponse.objectId)\n        XCTAssertEqual(currentUser.username, loginResponse.username)\n        XCTAssertEqual(currentUser.email, loginResponse.email)\n        XCTAssertEqual(currentUser.ACL, loginResponse.ACL)\n        XCTAssertEqual(currentUser.customKey, loginResponse.customKey)\n    }\n\n    func testUpdateCommandUnmodifiedEmail() throws {\n        try userSignUp()\n        guard let user = User.current,\n              let objectId = user.objectId else {\n            XCTFail(\"Should have current user.\")\n            return\n        }\n        XCTAssertNotNil(user.email)\n        let command = try user.saveCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/users/\\(objectId)\")\n        XCTAssertEqual(command.method, API.Method.PUT)\n        XCTAssertNil(command.params)\n        XCTAssertNotNil(command.body)\n        XCTAssertNil(command.body?.email)\n    }\n\n    func testUpdateCommandModifiedEmail() throws {\n        try userSignUp()\n        guard var user = User.current,\n              let objectId = user.objectId else {\n            XCTFail(\"Should have current user.\")\n            return\n        }\n        let email = \"peace@parse.com\"\n        user.email = email\n        XCTAssertNotNil(user.email)\n        let command = try user.saveCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/users/\\(objectId)\")\n        XCTAssertEqual(command.method, API.Method.PUT)\n        XCTAssertNil(command.params)\n        XCTAssertNotNil(command.body)\n        XCTAssertEqual(command.body?.email, email)\n    }\n\n    func testUpdateCommandNotCurrentModifiedEmail() throws {\n        try userSignUp()\n        var user = User()\n        let objectId = \"yarr\"\n        user.objectId = objectId\n        let email = \"peace@parse.com\"\n        user.email = email\n        XCTAssertNotNil(user.email)\n        let command = try user.saveCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/users/\\(objectId)\")\n        XCTAssertEqual(command.method, API.Method.PUT)\n        XCTAssertNil(command.params)\n        XCTAssertNotNil(command.body)\n        XCTAssertEqual(command.body?.email, email)\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testUpdateCommandCurrentUserModifiedEmail() throws {\n        try userSignUp()\n        guard let user = User.current,\n              let objectId = user.objectId else {\n            XCTFail(\"Should have current user.\")\n            return\n        }\n        let email = \"peace@parse.com\"\n        User.current?.email = email\n        XCTAssertNotNil(User.current?.email)\n        let command = try User.current?.saveCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command?.path.urlComponent, \"/users/\\(objectId)\")\n        XCTAssertEqual(command?.method, API.Method.PUT)\n        XCTAssertNil(command?.params)\n        XCTAssertNotNil(command?.body)\n        XCTAssertEqual(command?.body?.email, email)\n    }\n\n    func testUpdateCommandCurrentUserNotCurrentModifiedEmail() throws {\n        try userSignUp()\n        guard let user = User.current,\n              let objectId = user.objectId else {\n            XCTFail(\"Should have current user.\")\n            return\n        }\n        let email = \"peace@parse.com\"\n        User.current?.email = email\n        XCTAssertNotNil(User.current?.email)\n        let command = try User.current?.saveCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command?.path.urlComponent, \"/users/\\(objectId)\")\n        XCTAssertEqual(command?.method, API.Method.PUT)\n        XCTAssertNil(command?.params)\n        XCTAssertNotNil(command?.body)\n        XCTAssertEqual(command?.body?.email, email)\n    }\n    #endif\n\n    func testSaveAndUpdateCurrentUser() throws { // swiftlint:disable:this function_body_length\n        XCTAssertNil(User.current?.objectId)\n        try userSignUp()\n        XCTAssertNotNil(User.current?.objectId)\n\n        guard let user = User.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n        XCTAssertNotNil(user.email)\n        var userOnServer = user\n        userOnServer.createdAt = nil\n        userOnServer.updatedAt = User.current?.updatedAt?.addingTimeInterval(+300)\n\n        let encoded: Data!\n        do {\n            encoded = try userOnServer.getEncoder().encode(userOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            let saved = try user.save(options: [.useMasterKey])\n            XCTAssert(saved.hasSameObjectId(as: userOnServer))\n            XCTAssertEqual(saved.email, user.email)\n            guard let savedCreatedAt = saved.createdAt,\n                let savedUpdatedAt = saved.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(savedCreatedAt, user.createdAt)\n            XCTAssertEqual(savedUpdatedAt, userOnServer.updatedAt)\n            XCTAssertNil(saved.ACL)\n\n            //Should be updated in memory\n            XCTAssertEqual(User.current?.updatedAt, savedUpdatedAt)\n            XCTAssertEqual(User.current?.email, user.email)\n\n            #if !os(Linux) && !os(Android) && !os(Windows)\n            //Should be updated in Keychain\n            guard let keychainUser: CurrentUserContainer<BaseParseUser>\n                = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser) else {\n                    XCTFail(\"Should get object from Keychain\")\n                return\n            }\n            XCTAssertEqual(keychainUser.currentUser?.updatedAt, savedUpdatedAt)\n            XCTAssertEqual(keychainUser.currentUser?.email, user.email)\n            #endif\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testSaveAndUpdateCurrentUserModifiedEmail() throws { // swiftlint:disable:this function_body_length\n        XCTAssertNil(User.current?.objectId)\n        try userSignUp()\n        XCTAssertNotNil(User.current?.objectId)\n\n        guard var user = User.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n        user.email = \"pease@parse.com\"\n        XCTAssertNotEqual(User.current?.email, user.email)\n        var userOnServer = user\n        userOnServer.createdAt = nil\n        userOnServer.updatedAt = User.current?.updatedAt?.addingTimeInterval(+300)\n\n        let encoded: Data!\n        do {\n            encoded = try userOnServer.getEncoder().encode(userOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            let saved = try user.save(options: [.useMasterKey])\n            XCTAssert(saved.hasSameObjectId(as: userOnServer))\n            XCTAssertEqual(saved.email, user.email)\n            guard let savedCreatedAt = saved.createdAt,\n                let savedUpdatedAt = saved.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(savedCreatedAt, user.createdAt)\n            XCTAssertEqual(savedUpdatedAt, userOnServer.updatedAt)\n            XCTAssertNil(saved.ACL)\n\n            //Should be updated in memory\n            XCTAssertEqual(User.current?.updatedAt, savedUpdatedAt)\n            XCTAssertEqual(User.current?.email, user.email)\n\n            #if !os(Linux) && !os(Android) && !os(Windows)\n            //Should be updated in Keychain\n            guard let keychainUser: CurrentUserContainer<BaseParseUser>\n                = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser) else {\n                    XCTFail(\"Should get object from Keychain\")\n                return\n            }\n            XCTAssertEqual(keychainUser.currentUser?.updatedAt, savedUpdatedAt)\n            XCTAssertEqual(keychainUser.currentUser?.email, user.email)\n            #endif\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testSaveMutableMergeCurrentUser() throws {\n        // Signup current User\n        XCTAssertNil(User.current?.objectId)\n        try userSignUp()\n        XCTAssertNotNil(User.current?.objectId)\n\n        guard let original = User.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n        var response = original.mergeable\n        response.createdAt = nil\n        response.updatedAt = Calendar.current.date(byAdding: .init(day: 1), to: Date())\n\n        let encoded: Data!\n        do {\n            encoded = try response.getEncoder().encode(response, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            response = try response.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        var updated = original.mergeable\n        updated.customKey = \"beast\"\n        updated.username = \"mode\"\n\n        do {\n            let saved = try updated.save()\n            let expectation1 = XCTestExpectation(description: \"Update installation1\")\n            DispatchQueue.main.asyncAfter(deadline: .now() + 2) {\n                guard let newCurrentUser = User.current else {\n                    XCTFail(\"Should have a new current installation\")\n                    expectation1.fulfill()\n                    return\n                }\n                XCTAssertTrue(saved.hasSameObjectId(as: newCurrentUser))\n                XCTAssertTrue(saved.hasSameObjectId(as: response))\n                XCTAssertEqual(saved.customKey, updated.customKey)\n                XCTAssertEqual(saved.email, original.email)\n                XCTAssertEqual(saved.username, updated.username)\n                XCTAssertEqual(saved.emailVerified, original.emailVerified)\n                XCTAssertEqual(saved.password, original.password)\n                XCTAssertEqual(saved.authData, original.authData)\n                XCTAssertEqual(saved.createdAt, original.createdAt)\n                XCTAssertEqual(saved.updatedAt, response.updatedAt)\n                XCTAssertNil(saved.originalData)\n                XCTAssertEqual(saved.customKey, newCurrentUser.customKey)\n                XCTAssertEqual(saved.email, newCurrentUser.email)\n                XCTAssertEqual(saved.username, newCurrentUser.username)\n                XCTAssertEqual(saved.emailVerified, newCurrentUser.emailVerified)\n                XCTAssertEqual(saved.password, newCurrentUser.password)\n                XCTAssertEqual(saved.authData, newCurrentUser.authData)\n                XCTAssertEqual(saved.createdAt, newCurrentUser.createdAt)\n                XCTAssertEqual(saved.updatedAt, newCurrentUser.updatedAt)\n                expectation1.fulfill()\n            }\n            wait(for: [expectation1], timeout: 20.0)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testSaveAsyncAndUpdateCurrentUser() throws { // swiftlint:disable:this function_body_length\n        XCTAssertNil(User.current?.objectId)\n        try userSignUp()\n        XCTAssertNotNil(User.current?.objectId)\n\n        guard let user = User.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n        XCTAssertNotNil(user.email)\n        var userOnServer = user\n        userOnServer.createdAt = nil\n        userOnServer.updatedAt = User.current?.updatedAt?.addingTimeInterval(+300)\n\n        let encoded: Data!\n        do {\n            encoded = try userOnServer.getEncoder().encode(userOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Fetch user1\")\n        user.save(options: [], callbackQueue: .global(qos: .background)) { result in\n\n            switch result {\n            case .success(let saved):\n                XCTAssert(saved.hasSameObjectId(as: userOnServer))\n                XCTAssertEqual(saved.email, user.email)\n                guard let savedCreatedAt = saved.createdAt,\n                    let savedUpdatedAt = saved.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                    expectation1.fulfill()\n                        return\n                }\n                XCTAssertEqual(savedCreatedAt, user.createdAt)\n                XCTAssertEqual(savedUpdatedAt, userOnServer.updatedAt)\n                XCTAssertNil(saved.ACL)\n\n                //Should be updated in memory\n                XCTAssertEqual(User.current?.updatedAt, savedUpdatedAt)\n                XCTAssertEqual(User.current?.email, user.email)\n\n                #if !os(Linux) && !os(Android) && !os(Windows)\n                //Should be updated in Keychain\n                guard let keychainUser: CurrentUserContainer<BaseParseUser>\n                    = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser) else {\n                        XCTFail(\"Should get object from Keychain\")\n                    return\n                }\n                XCTAssertEqual(keychainUser.currentUser?.updatedAt, savedUpdatedAt)\n                XCTAssertEqual(keychainUser.currentUser?.email, user.email)\n                #endif\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSaveAsyncAndUpdateCurrentUserModifiedEmail() throws { // swiftlint:disable:this function_body_length\n        XCTAssertNil(User.current?.objectId)\n        try userSignUp()\n        XCTAssertNotNil(User.current?.objectId)\n\n        guard var user = User.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n        user.email = \"pease@parse.com\"\n        XCTAssertNotEqual(User.current?.email, user.email)\n        var userOnServer = user\n        userOnServer.createdAt = nil\n        userOnServer.updatedAt = User.current?.updatedAt?.addingTimeInterval(+300)\n\n        let encoded: Data!\n        do {\n            encoded = try userOnServer.getEncoder().encode(userOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Fetch user1\")\n        user.save(options: [], callbackQueue: .global(qos: .background)) { result in\n\n            switch result {\n            case .success(let saved):\n                XCTAssert(saved.hasSameObjectId(as: userOnServer))\n                XCTAssertEqual(saved.email, user.email)\n                guard let savedCreatedAt = saved.createdAt,\n                    let savedUpdatedAt = saved.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                    expectation1.fulfill()\n                        return\n                }\n                XCTAssertEqual(savedCreatedAt, user.createdAt)\n                XCTAssertEqual(savedUpdatedAt, userOnServer.updatedAt)\n                XCTAssertNil(saved.ACL)\n\n                //Should be updated in memory\n                XCTAssertEqual(User.current?.updatedAt, savedUpdatedAt)\n                XCTAssertEqual(User.current?.email, user.email)\n\n                #if !os(Linux) && !os(Android) && !os(Windows)\n                //Should be updated in Keychain\n                guard let keychainUser: CurrentUserContainer<BaseParseUser>\n                    = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser) else {\n                        XCTFail(\"Should get object from Keychain\")\n                    return\n                }\n                XCTAssertEqual(keychainUser.currentUser?.updatedAt, savedUpdatedAt)\n                XCTAssertEqual(keychainUser.currentUser?.email, user.email)\n                #endif\n\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testUpdate() { // swiftlint:disable:this function_body_length\n        var user = User()\n        let objectId = \"yarr\"\n        user.objectId = objectId\n        user.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        user.ACL = nil\n\n        var userOnServer = user\n        userOnServer.updatedAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try userOnServer.getEncoder().encode(userOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try user.save()\n            guard let savedUpdatedAt = saved.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n            }\n            guard let originalUpdatedAt = user.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n            }\n            XCTAssertGreaterThan(savedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(saved.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        do {\n            let saved = try user.save(options: [.useMasterKey])\n            guard let savedUpdatedAt = saved.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n            }\n            guard let originalUpdatedAt = user.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n            }\n            XCTAssertGreaterThan(savedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(saved.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testSaveWithDefaultACL() throws { // swiftlint:disable:this function_body_length\n        try userSignUp()\n        guard let userObjectId = User.current?.objectId else {\n            XCTFail(\"Should have objectId\")\n            return\n        }\n        let defaultACL = try ParseACL.setDefaultACL(ParseACL(),\n                                                    withAccessForCurrentUser: true)\n\n        let user = User()\n        var userOnServer = user\n        userOnServer.objectId = \"hello\"\n        userOnServer.createdAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n\n        let encoded: Data!\n        do {\n            encoded = try userOnServer.getEncoder().encode(userOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            let saved = try user.save(options: [.useMasterKey])\n            XCTAssert(saved.hasSameObjectId(as: userOnServer))\n            guard let savedCreatedAt = saved.createdAt,\n                let savedUpdatedAt = saved.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalCreatedAt = userOnServer.createdAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertEqual(savedCreatedAt, originalCreatedAt)\n            XCTAssertEqual(savedUpdatedAt, originalCreatedAt)\n            XCTAssertNotNil(saved.ACL)\n            XCTAssertEqual(saved.ACL?.publicRead, defaultACL.publicRead)\n            XCTAssertEqual(saved.ACL?.publicWrite, defaultACL.publicWrite)\n            XCTAssertTrue(defaultACL.getReadAccess(objectId: userObjectId))\n            XCTAssertTrue(defaultACL.getWriteAccess(objectId: userObjectId))\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testUpdateWithDefaultACL() throws { // swiftlint:disable:this function_body_length\n        try userSignUp()\n        _ = try ParseACL.setDefaultACL(ParseACL(),\n                                                    withAccessForCurrentUser: true)\n        var user = User()\n        let objectId = \"yarr\"\n        user.objectId = objectId\n        user.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        user.ACL = nil\n\n        var userOnServer = user\n        userOnServer.updatedAt = Date()\n\n        let encoded: Data!\n        do {\n            encoded = try userOnServer.getEncoder().encode(userOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            let saved = try user.save()\n            guard let savedUpdatedAt = saved.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n            }\n            guard let originalUpdatedAt = user.updatedAt else {\n                XCTFail(\"Should unwrap dates\")\n                return\n            }\n            XCTAssertGreaterThan(savedUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(saved.ACL)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func updateAsync(user: User, userOnServer: User, callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Update user1\")\n        user.save(options: [], callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let saved):\n                guard let savedUpdatedAt = saved.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    expectation1.fulfill()\n                    return\n                }\n                guard let originalUpdatedAt = user.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    expectation1.fulfill()\n                    return\n                }\n                XCTAssertGreaterThan(savedUpdatedAt, originalUpdatedAt)\n                XCTAssertNil(saved.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n\n        let expectation2 = XCTestExpectation(description: \"Update user2\")\n        user.save(options: [.useMasterKey], callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let saved):\n                guard let savedUpdatedAt = saved.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    expectation2.fulfill()\n                    return\n                }\n                guard let originalUpdatedAt = user.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    expectation2.fulfill()\n                    return\n                }\n\n                XCTAssertGreaterThan(savedUpdatedAt, originalUpdatedAt)\n                XCTAssertNil(saved.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testThreadSafeUpdateAsync() {\n        var user = User()\n        let objectId = \"yarr\"\n        user.objectId = objectId\n        user.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        user.ACL = nil\n\n        var userOnServer = user\n        userOnServer.updatedAt = Date()\n        let encoded: Data!\n        do {\n            encoded = try userOnServer.getEncoder().encode(userOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        DispatchQueue.concurrentPerform(iterations: 100) {_ in\n            self.updateAsync(user: user, userOnServer: userOnServer, callbackQueue: .global(qos: .background))\n        }\n    }\n\n    func testUpdateAsyncMainQueue() {\n        var user = User()\n        let objectId = \"yarr\"\n        user.objectId = objectId\n        user.updatedAt = Calendar.current.date(byAdding: .init(day: -1), to: Date())\n        user.ACL = nil\n\n        var userOnServer = user\n        userOnServer.updatedAt = Date()\n        let encoded: Data!\n        do {\n            encoded = try userOnServer.getEncoder().encode(userOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        self.updateAsync(user: user, userOnServer: userOnServer, callbackQueue: .main)\n    }\n    #endif\n\n    func testSignupCommandWithBody() throws {\n        let body = SignupLoginBody(username: \"test\", password: \"user\")\n        let command = try User.signupCommand(body: body)\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/users\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertEqual(command.body?.username, body.username)\n        XCTAssertEqual(command.body?.password, body.password)\n    }\n\n    func testSignupCommandNoBody() throws {\n        var user = User()\n        user.username = \"test\"\n        user.password = \"user\"\n        user.customKey = \"hello\"\n        let command = try user.signupCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/users\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertEqual(command.body?.username, \"test\")\n        XCTAssertEqual(command.body?.password, \"user\")\n        XCTAssertEqual(command.body?.customKey, \"hello\")\n    }\n\n    func testUserSignUp() {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        do {\n           let signedUp = try User.signup(username: loginUserName, password: loginPassword)\n            XCTAssertNotNil(signedUp)\n            XCTAssertNotNil(signedUp.createdAt)\n            XCTAssertNotNil(signedUp.updatedAt)\n            XCTAssertNotNil(signedUp.email)\n            XCTAssertNotNil(signedUp.emailVerified)\n            XCTAssertNotNil(signedUp.username)\n            XCTAssertNil(signedUp.password)\n            XCTAssertNotNil(signedUp.objectId)\n            XCTAssertNotNil(signedUp.sessionToken)\n            XCTAssertNotNil(signedUp.customKey)\n            XCTAssertNil(signedUp.ACL)\n\n            guard let userFromKeychain = BaseParseUser.current else {\n                XCTFail(\"Could not get CurrentUser from Keychain\")\n                return\n            }\n\n            XCTAssertNotNil(userFromKeychain.createdAt)\n            XCTAssertNotNil(userFromKeychain.updatedAt)\n            XCTAssertNotNil(userFromKeychain.email)\n            XCTAssertNotNil(userFromKeychain.username)\n            XCTAssertNil(userFromKeychain.password)\n            XCTAssertNotNil(userFromKeychain.objectId)\n            XCTAssertNotNil(userFromKeychain.sessionToken)\n            XCTAssertNil(userFromKeychain.ACL)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testUserSignUpNoBody() {\n        var loginResponse = LoginSignupResponse()\n        loginResponse.email = nil\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        do {\n            var user = User()\n            user.username = loginUserName\n            user.password = loginPassword\n            user.customKey = \"blah\"\n            let signedUp = try user.signup()\n            XCTAssertNotNil(signedUp)\n            XCTAssertNotNil(signedUp.createdAt)\n            XCTAssertNotNil(signedUp.updatedAt)\n            XCTAssertNil(signedUp.email)\n            XCTAssertNotNil(signedUp.username)\n            XCTAssertNil(signedUp.password)\n            XCTAssertNotNil(signedUp.objectId)\n            XCTAssertNotNil(signedUp.sessionToken)\n            XCTAssertNotNil(signedUp.customKey)\n            XCTAssertNil(signedUp.ACL)\n\n            guard let userFromKeychain = BaseParseUser.current else {\n                XCTFail(\"Could not get CurrentUser from Keychain\")\n                return\n            }\n\n            XCTAssertNotNil(userFromKeychain.createdAt)\n            XCTAssertNotNil(userFromKeychain.updatedAt)\n            XCTAssertNil(userFromKeychain.email)\n            XCTAssertNotNil(userFromKeychain.username)\n            XCTAssertNil(userFromKeychain.password)\n            XCTAssertNotNil(userFromKeychain.objectId)\n            XCTAssertNotNil(userFromKeychain.sessionToken)\n            XCTAssertNil(userFromKeychain.ACL)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func signUpAsync(loginResponse: LoginSignupResponse, callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Signup user1\")\n        User.signup(username: loginUserName, password: loginPassword,\n                    callbackQueue: callbackQueue) { result in\n            switch result {\n\n            case .success(let signedUp):\n                XCTAssertNotNil(signedUp.createdAt)\n                XCTAssertNotNil(signedUp.updatedAt)\n                XCTAssertNotNil(signedUp.email)\n                XCTAssertNotNil(signedUp.username)\n                XCTAssertNil(signedUp.password)\n                XCTAssertNotNil(signedUp.objectId)\n                XCTAssertNotNil(signedUp.sessionToken)\n                XCTAssertNotNil(signedUp.customKey)\n                XCTAssertNil(signedUp.ACL)\n\n                guard let userFromKeychain = BaseParseUser.current else {\n                    XCTFail(\"Could not get CurrentUser from Keychain\")\n                    expectation1.fulfill()\n                    return\n                }\n\n                XCTAssertNotNil(userFromKeychain.createdAt)\n                XCTAssertNotNil(userFromKeychain.updatedAt)\n                XCTAssertNotNil(userFromKeychain.email)\n                XCTAssertNotNil(userFromKeychain.username)\n                XCTAssertNil(userFromKeychain.password)\n                XCTAssertNotNil(userFromKeychain.objectId)\n                XCTAssertNotNil(userFromKeychain.sessionToken)\n                XCTAssertNil(userFromKeychain.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSignUpAsyncMainQueue() {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        self.signUpAsync(loginResponse: loginResponse, callbackQueue: .main)\n    }\n\n    func signUpAsyncNoBody(loginResponse: LoginSignupResponse, callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Signup user1\")\n        var user = User()\n        user.username = loginUserName\n        user.password = loginPassword\n        user.customKey = \"blah\"\n        user.signup(callbackQueue: callbackQueue) { result in\n            switch result {\n\n            case .success(let signedUp):\n                XCTAssertNotNil(signedUp.createdAt)\n                XCTAssertNotNil(signedUp.updatedAt)\n                XCTAssertNil(signedUp.email)\n                XCTAssertNotNil(signedUp.username)\n                XCTAssertNil(signedUp.password)\n                XCTAssertNotNil(signedUp.objectId)\n                XCTAssertNotNil(signedUp.sessionToken)\n                XCTAssertNotNil(signedUp.customKey)\n                XCTAssertNil(signedUp.ACL)\n\n                guard let userFromKeychain = BaseParseUser.current else {\n                    XCTFail(\"Could not get CurrentUser from Keychain\")\n                    expectation1.fulfill()\n                    return\n                }\n\n                XCTAssertNotNil(userFromKeychain.createdAt)\n                XCTAssertNotNil(userFromKeychain.updatedAt)\n                XCTAssertNil(userFromKeychain.email)\n                XCTAssertNotNil(userFromKeychain.username)\n                XCTAssertNil(userFromKeychain.password)\n                XCTAssertNotNil(userFromKeychain.objectId)\n                XCTAssertNotNil(userFromKeychain.sessionToken)\n                XCTAssertNil(userFromKeychain.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testSignUpAsyncMainQueueNoBody() {\n        var loginResponse = LoginSignupResponse()\n        loginResponse.email = nil\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        self.signUpAsyncNoBody(loginResponse: loginResponse, callbackQueue: .main)\n    }\n\n    func testLoginCommand() {\n        let command = User.loginCommand(username: \"test\", password: \"user\")\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/login\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertNotNil(command.body)\n    }\n\n    func testLogin() {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        do {\n            let loggedIn = try User.login(username: loginUserName, password: loginPassword)\n            XCTAssertNotNil(loggedIn)\n            XCTAssertNotNil(loggedIn.createdAt)\n            XCTAssertNotNil(loggedIn.updatedAt)\n            XCTAssertNotNil(loggedIn.email)\n            XCTAssertNotNil(loggedIn.username)\n            XCTAssertNil(loggedIn.password)\n            XCTAssertNotNil(loggedIn.objectId)\n            XCTAssertNotNil(loggedIn.sessionToken)\n            XCTAssertNotNil(loggedIn.customKey)\n            XCTAssertNil(loggedIn.ACL)\n\n            guard let userFromKeychain = BaseParseUser.current else {\n                XCTFail(\"Could not get CurrentUser from Keychain\")\n                return\n            }\n\n            XCTAssertNotNil(userFromKeychain.createdAt)\n            XCTAssertNotNil(userFromKeychain.updatedAt)\n            XCTAssertNotNil(userFromKeychain.email)\n            XCTAssertNotNil(userFromKeychain.username)\n            XCTAssertNil(userFromKeychain.password)\n            XCTAssertNotNil(userFromKeychain.objectId)\n            XCTAssertNotNil(userFromKeychain.sessionToken)\n            XCTAssertNil(userFromKeychain.ACL)\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func loginAsync(loginResponse: LoginSignupResponse, callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Login user\")\n        User.login(username: loginUserName, password: loginPassword,\n                   callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success(let loggedIn):\n                XCTAssertNotNil(loggedIn.createdAt)\n                XCTAssertNotNil(loggedIn.updatedAt)\n                XCTAssertNotNil(loggedIn.email)\n                XCTAssertNotNil(loggedIn.username)\n                XCTAssertNil(loggedIn.password)\n                XCTAssertNotNil(loggedIn.objectId)\n                XCTAssertNotNil(loggedIn.sessionToken)\n                XCTAssertNotNil(loggedIn.customKey)\n                XCTAssertNil(loggedIn.ACL)\n\n                guard let userFromKeychain = BaseParseUser.current else {\n                    XCTFail(\"Could not get CurrentUser from Keychain\")\n                    expectation1.fulfill()\n                    return\n                }\n\n                XCTAssertNotNil(userFromKeychain.createdAt)\n                XCTAssertNotNil(userFromKeychain.updatedAt)\n                XCTAssertNotNil(userFromKeychain.email)\n                XCTAssertNotNil(userFromKeychain.username)\n                XCTAssertNil(userFromKeychain.password)\n                XCTAssertNotNil(userFromKeychain.objectId)\n                XCTAssertNotNil(userFromKeychain.sessionToken)\n                XCTAssertNil(userFromKeychain.ACL)\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLoginAsyncMainQueue() {\n        let loginResponse = LoginSignupResponse()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try loginResponse.getEncoder().encode(loginResponse, skipKeys: .none)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        self.loginAsync(loginResponse: loginResponse, callbackQueue: .main)\n    }\n\n    func testLogutCommand() {\n        let command = User.logoutCommand()\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/logout\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertNil(command.body)\n    }\n\n    func testLogout() {\n        testLogin()\n        MockURLProtocol.removeAll()\n\n        let logoutResponse = NoBody()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(logoutResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        let expectation1 = XCTestExpectation(description: \"Logout user1\")\n        guard let oldInstallationId = BaseParseInstallation.current?.installationId else {\n            XCTFail(\"Should have unwrapped\")\n            expectation1.fulfill()\n            return\n        }\n        do {\n            try User.logout()\n            if let userFromKeychain = BaseParseUser.current {\n                XCTFail(\"\\(userFromKeychain) was not deleted from Keychain during logout\")\n            }\n\n            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {\n                if let installationFromKeychain = BaseParseInstallation.current {\n\n                        if installationFromKeychain.installationId == oldInstallationId\n                            || installationFromKeychain.installationId == nil {\n                            XCTFail(\"\"\"\n                                \"\\(installationFromKeychain) was not deleted then created in\n                                Keychain during logout\n                            \"\"\")\n                        }\n\n                } else {\n                    XCTFail(\"Should have a new installation\")\n                }\n                expectation1.fulfill()\n            }\n        } catch {\n            XCTFail(error.localizedDescription)\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func logoutAsync(callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Logout user1\")\n\n        guard let oldInstallationId = BaseParseInstallation.current?.installationId else {\n            XCTFail(\"Should have unwrapped\")\n            expectation1.fulfill()\n            return\n        }\n\n        User.logout(callbackQueue: callbackQueue) { result in\n\n            switch result {\n\n            case .success:\n                if let userFromKeychain = BaseParseUser.current {\n                    XCTFail(\"\\(userFromKeychain) was not deleted from Keychain during logout\")\n                }\n                DispatchQueue.main.asyncAfter(deadline: .now() + 1) {\n                    if let installationFromMemory: CurrentInstallationContainer<BaseParseInstallation>\n                        = try? ParseStorage.shared.get(valueFor: ParseStorage.Keys.currentInstallation) {\n\n                            if installationFromMemory.installationId == oldInstallationId\n                                || installationFromMemory.installationId == nil {\n                                XCTFail(\"\\(installationFromMemory) was not deleted & recreated in memory during logout\")\n                            }\n                    } else {\n                        XCTFail(\"Should have a new installation\")\n                    }\n\n                    #if !os(Linux) && !os(Android) && !os(Windows)\n                    if let installationFromKeychain: CurrentInstallationContainer<BaseParseInstallation>\n                        = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentInstallation) {\n                            if installationFromKeychain.installationId == oldInstallationId\n                                || installationFromKeychain.installationId == nil {\n                                // swiftlint:disable:next line_length\n                                XCTFail(\"\\(installationFromKeychain) was not deleted & recreated in Keychain during logout\")\n                            }\n                    } else {\n                        XCTFail(\"Should have a new installation\")\n                    }\n                    #endif\n                    expectation1.fulfill()\n                }\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n                expectation1.fulfill()\n            }\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    func testLogoutAsyncMainQueue() {\n        testLogin()\n        MockURLProtocol.removeAll()\n\n        let logoutResponse = NoBody()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(logoutResponse)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        self.logoutAsync(callbackQueue: .main)\n    }\n\n    func testPasswordResetCommand() throws {\n        let body = EmailBody(email: \"hello@parse.org\")\n        let command = User.passwordResetCommand(email: body.email)\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/requestPasswordReset\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertEqual(command.body?.email, body.email)\n    }\n\n    func testPasswordReset() {\n        let response = NoBody()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(response)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        do {\n            try User.passwordReset(email: \"hello@parse.org\")\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testPasswordResetError() {\n\n        let parseError = ParseError(code: .internalServer, message: \"Object not found\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(parseError)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            try User.passwordReset(email: \"hello@parse.org\")\n            XCTFail(\"Should have thrown ParseError\")\n        } catch {\n            if let error = error as? ParseError {\n                XCTAssertEqual(error.code, parseError.code)\n            } else {\n                XCTFail(\"Should have thrown ParseError\")\n            }\n        }\n    }\n\n    func passwordResetAsync(callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Logout user1\")\n        User.passwordReset(email: \"hello@parse.org\", callbackQueue: callbackQueue) { result in\n\n            if case let .failure(error) = result {\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 10.0)\n    }\n\n    func testPasswordResetMainQueue() {\n        let response = NoBody()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(response)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        self.passwordResetAsync(callbackQueue: .main)\n    }\n\n    func passwordResetAsyncError(parseError: ParseError, callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Logout user1\")\n        User.passwordReset(email: \"hello@parse.org\", callbackQueue: callbackQueue) { result in\n\n            if case let .failure(error) = result {\n                XCTAssertEqual(error.code, parseError.code)\n            } else {\n                XCTFail(\"Should have thrown ParseError\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 10.0)\n    }\n\n    func testPasswordResetMainQueueError() {\n        let parseError = ParseError(code: .internalServer, message: \"Object not found\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(parseError)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        self.passwordResetAsyncError(parseError: parseError, callbackQueue: .main)\n    }\n\n    func testVerifyPasswordCommandPOST() throws {\n        let username = \"hello\"\n        let password = \"world\"\n        let command = User.verifyPasswordCommand(username: username,\n                                                 password: password,\n                                                 method: .POST)\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/verifyPassword\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertEqual(command.body?.username, username)\n        XCTAssertEqual(command.body?.password, password)\n        XCTAssertNil(command.params)\n    }\n\n    func testVerifyPasswordCommandGET() throws {\n        let username = \"hello\"\n        let password = \"world\"\n        let params = [\"username\": username,\n                      \"password\": password]\n        let command = User.verifyPasswordCommand(username: username,\n                                                 password: password,\n                                                 method: .GET)\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/verifyPassword\")\n        XCTAssertEqual(command.method, API.Method.GET)\n        XCTAssertNil(command.body)\n        XCTAssertEqual(command.params, params)\n    }\n\n    func testVerificationEmailRequestCommand() throws {\n        let body = EmailBody(email: \"hello@parse.org\")\n        let command = User.verificationEmailCommand(email: body.email)\n        XCTAssertNotNil(command)\n        XCTAssertEqual(command.path.urlComponent, \"/verificationEmailRequest\")\n        XCTAssertEqual(command.method, API.Method.POST)\n        XCTAssertEqual(command.body?.email, body.email)\n    }\n\n    func testVerificationEmailRequestReset() {\n        let response = NoBody()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(response)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n        do {\n            try User.verificationEmail(email: \"hello@parse.org\")\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testVerificationEmailRequestError() {\n\n        let parseError = ParseError(code: .internalServer, message: \"Object not found\")\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(parseError)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n        do {\n            try User.verificationEmail(email: \"hello@parse.org\")\n            XCTFail(\"Should have thrown ParseError\")\n        } catch {\n            if let error = error as? ParseError {\n                XCTAssertEqual(error.code, parseError.code)\n            } else {\n                XCTFail(\"Should have thrown ParseError\")\n            }\n        }\n    }\n\n    func verificationEmailAsync(callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Logout user1\")\n        User.verificationEmail(email: \"hello@parse.org\", callbackQueue: callbackQueue) { result in\n\n            if case let .failure(error) = result {\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 10.0)\n    }\n\n    func testVerificationEmailRequestMainQueue() {\n        let response = NoBody()\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(response)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        self.verificationEmailAsync(callbackQueue: .main)\n    }\n\n    func verificationEmailAsyncError(parseError: ParseError, callbackQueue: DispatchQueue) {\n\n        let expectation1 = XCTestExpectation(description: \"Logout user1\")\n        User.verificationEmail(email: \"hello@parse.org\", callbackQueue: callbackQueue) { result in\n\n            if case let .failure(error) = result {\n                XCTAssertEqual(error.code, parseError.code)\n            } else {\n                XCTFail(\"Should have thrown ParseError\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 10.0)\n    }\n\n    func testVerificationEmailRequestMainQueueError() {\n        let parseError = ParseError(code: .internalServer, message: \"Object not found\")\n\n        MockURLProtocol.mockRequests { _ in\n            do {\n                let encoded = try ParseCoding.jsonEncoder().encode(parseError)\n                return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n            } catch {\n                return nil\n            }\n        }\n\n        self.verificationEmailAsyncError(parseError: parseError, callbackQueue: .main)\n    }\n\n    func testUserCustomValuesSavedToKeychain() {\n        testLogin()\n        let customField = \"Changed\"\n        User.current?.customKey = customField\n        User.saveCurrentContainerToKeychain()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        guard let keychainUser: CurrentUserContainer<User>\n            = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser) else {\n                XCTFail(\"Should get object from Keychain\")\n            return\n        }\n        XCTAssertEqual(keychainUser.currentUser?.customKey, customField)\n        #endif\n    }\n\n    func testDeleteCommand() {\n        var user = User()\n        let objectId = \"yarr\"\n        user.objectId = objectId\n        do {\n            let command = try user.deleteCommand()\n            XCTAssertNotNil(command)\n            XCTAssertEqual(command.path.urlComponent, \"/users/\\(objectId)\")\n            XCTAssertEqual(command.method, API.Method.DELETE)\n            XCTAssertNil(command.body)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        let user2 = User()\n        XCTAssertThrowsError(try user2.deleteCommand())\n    }\n\n    func testDeleteCurrent() {\n        testLogin()\n        let expectation1 = XCTestExpectation(description: \"Delete user\")\n        guard let user = User.current else {\n                XCTFail(\"Should unwrap dates\")\n            expectation1.fulfill()\n                return\n        }\n\n        do {\n            try user.delete(options: [])\n            XCTAssertNil(User.current)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        do {\n            try user.delete(options: [.useMasterKey])\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testDeleteCurrentAsyncMainQueue() {\n        testLogin()\n        MockURLProtocol.removeAll()\n\n        let expectation1 = XCTestExpectation(description: \"Delete installation1\")\n        guard let user = User.current else {\n            XCTFail(\"Should unwrap\")\n            expectation1.fulfill()\n            return\n        }\n\n        var userOnServer = user\n        userOnServer.updatedAt = user.updatedAt?.addingTimeInterval(+300)\n\n        let encoded: Data!\n        do {\n            encoded = try userOnServer.getEncoder().encode(userOnServer, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try userOnServer.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        user.delete { result in\n            if case let .failure(error) = result {\n                XCTFail(error.localizedDescription)\n            }\n            XCTAssertNil(User.current)\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    // swiftlint:disable:next function_body_length\n    func testFetchAllCurrent() {\n        testLogin()\n        MockURLProtocol.removeAll()\n\n        guard var user = User.current else {\n            XCTFail(\"Should unwrap dates\")\n            return\n        }\n\n        user.updatedAt = user.updatedAt?.addingTimeInterval(+300)\n        user.customKey = \"newValue\"\n        let userOnServer = QueryResponse<User>(results: [user], count: 1)\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(userOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(user)\n            user = try user.getDecoder().decode(User.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            let fetched = try [user].fetchAll()\n            fetched.forEach {\n                switch $0 {\n                case .success(let fetched):\n                    XCTAssert(fetched.hasSameObjectId(as: user))\n                    guard let fetchedCreatedAt = fetched.createdAt,\n                        let fetchedUpdatedAt = fetched.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            return\n                    }\n                    guard let originalCreatedAt = user.createdAt,\n                        let originalUpdatedAt = user.updatedAt,\n                        let serverUpdatedAt = user.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            return\n                    }\n                    XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n                    XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n                    XCTAssertEqual(fetchedUpdatedAt, serverUpdatedAt)\n                    XCTAssertEqual(User.current?.customKey, user.customKey)\n\n                    //Should be updated in memory\n                    guard let updatedCurrentDate = User.current?.updatedAt else {\n                        XCTFail(\"Should unwrap current date\")\n                        return\n                    }\n                    XCTAssertEqual(updatedCurrentDate, serverUpdatedAt)\n\n                    #if !os(Linux) && !os(Android) && !os(Windows)\n                    //Should be updated in Keychain\n                    guard let keychainUser: CurrentUserContainer<BaseParseUser>\n                        = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser),\n                        let keychainUpdatedCurrentDate = keychainUser.currentUser?.updatedAt else {\n                            XCTFail(\"Should get object from Keychain\")\n                        return\n                    }\n                    XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt)\n                    #endif\n                case .failure(let error):\n                    XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                }\n            }\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    // swiftlint:disable:next function_body_length\n    func testFetchAllAsyncMainQueueCurrent() {\n        testLogin()\n        MockURLProtocol.removeAll()\n\n        let expectation1 = XCTestExpectation(description: \"Fetch user1\")\n        guard var user = User.current else {\n            XCTFail(\"Should unwrap\")\n            expectation1.fulfill()\n            return\n        }\n\n        user.updatedAt = user.updatedAt?.addingTimeInterval(+300)\n        user.customKey = \"newValue\"\n        let userOnServer = QueryResponse<User>(results: [user], count: 1)\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(userOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(user)\n            user = try user.getDecoder().decode(User.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        [user].fetchAll { results in\n            switch results {\n\n            case .success(let fetched):\n                fetched.forEach {\n                    switch $0 {\n                    case .success(let fetched):\n                        XCTAssert(fetched.hasSameObjectId(as: user))\n                        guard let fetchedCreatedAt = fetched.createdAt,\n                            let fetchedUpdatedAt = fetched.updatedAt else {\n                                XCTFail(\"Should unwrap dates\")\n                                expectation1.fulfill()\n                                return\n                        }\n                        guard let originalCreatedAt = user.createdAt,\n                            let originalUpdatedAt = user.updatedAt,\n                            let serverUpdatedAt = user.updatedAt else {\n                                XCTFail(\"Should unwrap dates\")\n                                expectation1.fulfill()\n                                return\n                        }\n                        XCTAssertEqual(fetchedCreatedAt, originalCreatedAt)\n                        XCTAssertEqual(fetchedUpdatedAt, originalUpdatedAt)\n                        XCTAssertEqual(fetchedUpdatedAt, serverUpdatedAt)\n                        XCTAssertEqual(User.current?.customKey, user.customKey)\n\n                        //Should be updated in memory\n                        guard let updatedCurrentDate = User.current?.updatedAt else {\n                            XCTFail(\"Should unwrap current date\")\n                            expectation1.fulfill()\n                            return\n                        }\n                        XCTAssertEqual(updatedCurrentDate, serverUpdatedAt)\n\n                        #if !os(Linux) && !os(Android) && !os(Windows)\n                        //Should be updated in Keychain\n                        guard let keychainUser: CurrentUserContainer<BaseParseUser>\n                            = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser),\n                            let keychainUpdatedCurrentDate = keychainUser.currentUser?.updatedAt else {\n                                XCTFail(\"Should get object from Keychain\")\n                                expectation1.fulfill()\n                            return\n                        }\n                        XCTAssertEqual(keychainUpdatedCurrentDate, serverUpdatedAt)\n                        #endif\n                    case .failure(let error):\n                        XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                    }\n                }\n            case .failure(let error):\n                XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n\n    // swiftlint:disable:next function_body_length\n    func testSaveAllCurrent() {\n        testLogin()\n        MockURLProtocol.removeAll()\n\n        guard var user = User.current else {\n            XCTFail(\"Should unwrap dates\")\n            return\n        }\n        user.createdAt = nil\n        var user2 = user\n        user2.customKey = \"oldValue\"\n        user.updatedAt = user.updatedAt?.addingTimeInterval(+300)\n        user.customKey = \"newValue\"\n        let userOnServer = [BatchResponseItem<User>(success: user, error: nil),\n                            BatchResponseItem<User>(success: user2, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(userOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(user)\n            user = try user.getDecoder().decode(User.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            let saved = try [user].saveAll()\n            saved.forEach {\n                switch $0 {\n                case .success(let saved):\n                    XCTAssert(saved.hasSameObjectId(as: user))\n                    guard let savedUpdatedAt = saved.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            return\n                    }\n                    guard let originalUpdatedAt = user.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            return\n                    }\n                    XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n                    XCTAssertEqual(User.current?.customKey, user.customKey)\n\n                    //Should be updated in memory\n                    guard let updatedCurrentDate = User.current?.updatedAt else {\n                        XCTFail(\"Should unwrap current date\")\n                        return\n                    }\n                    XCTAssertEqual(updatedCurrentDate, originalUpdatedAt)\n\n                    #if !os(Linux) && !os(Android) && !os(Windows)\n                    //Should be updated in Keychain\n                    guard let keychainUser: CurrentUserContainer<BaseParseUser>\n                        = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser),\n                        let keychainUpdatedCurrentDate = keychainUser.currentUser?.updatedAt else {\n                            XCTFail(\"Should get object from Keychain\")\n                        return\n                    }\n                    XCTAssertEqual(keychainUpdatedCurrentDate, originalUpdatedAt)\n                    #endif\n                case .failure(let error):\n                    XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                }\n            }\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        do {\n            let saved = try [user].saveAll(transaction: true)\n            saved.forEach {\n                switch $0 {\n                case .success(let saved):\n                    XCTAssert(saved.hasSameObjectId(as: user))\n                    guard let savedUpdatedAt = saved.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            return\n                    }\n                    guard let originalUpdatedAt = user.updatedAt else {\n                            XCTFail(\"Should unwrap dates\")\n                            return\n                    }\n                    XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n                    XCTAssertEqual(User.current?.customKey, user.customKey)\n\n                    //Should be updated in memory\n                    guard let updatedCurrentDate = User.current?.updatedAt else {\n                        XCTFail(\"Should unwrap current date\")\n                        return\n                    }\n                    XCTAssertEqual(updatedCurrentDate, originalUpdatedAt)\n\n                    #if !os(Linux) && !os(Android) && !os(Windows)\n                    //Should be updated in Keychain\n                    guard let keychainUser: CurrentUserContainer<BaseParseUser>\n                        = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser),\n                        let keychainUpdatedCurrentDate = keychainUser.currentUser?.updatedAt else {\n                            XCTFail(\"Should get object from Keychain\")\n                        return\n                    }\n                    XCTAssertEqual(keychainUpdatedCurrentDate, originalUpdatedAt)\n                    #endif\n                case .failure(let error):\n                    XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                }\n            }\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    // swiftlint:disable:next function_body_length\n    func testSaveAllAsyncMainQueueCurrent() {\n        testLogin()\n        MockURLProtocol.removeAll()\n\n        let expectation1 = XCTestExpectation(description: \"Save user1\")\n        let expectation2 = XCTestExpectation(description: \"Save user2\")\n\n        guard var user = User.current else {\n            XCTFail(\"Should unwrap\")\n            expectation1.fulfill()\n            expectation2.fulfill()\n            return\n        }\n        user.createdAt = nil\n        var user2 = user\n        user2.customKey = \"oldValue\"\n        user.updatedAt = user.updatedAt?.addingTimeInterval(+300)\n        user.customKey = \"newValue\"\n        let userOnServer = [BatchResponseItem<User>(success: user, error: nil),\n                            BatchResponseItem<User>(success: user2, error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(userOnServer)\n            //Get dates in correct format from ParseDecoding strategy\n            let encoded1 = try ParseCoding.jsonEncoder().encode(user)\n            user = try user.getDecoder().decode(User.self, from: encoded1)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            expectation2.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        [user].saveAll { results in\n            switch results {\n\n            case .success(let saved):\n                saved.forEach {\n                    switch $0 {\n                    case .success(let saved):\n                        XCTAssert(saved.hasSameObjectId(as: user))\n                        guard let savedUpdatedAt = saved.updatedAt else {\n                                XCTFail(\"Should unwrap dates\")\n                                expectation1.fulfill()\n                                return\n                        }\n                        guard let originalUpdatedAt = user.updatedAt else {\n                                XCTFail(\"Should unwrap dates\")\n                                expectation1.fulfill()\n                                return\n                        }\n                        XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n                        XCTAssertEqual(User.current?.customKey, user.customKey)\n\n                        //Should be updated in memory\n                        guard let updatedCurrentDate = User.current?.updatedAt else {\n                            XCTFail(\"Should unwrap current date\")\n                            expectation1.fulfill()\n                            return\n                        }\n                        XCTAssertEqual(updatedCurrentDate, originalUpdatedAt)\n\n                        #if !os(Linux) && !os(Android) && !os(Windows)\n                        //Should be updated in Keychain\n                        guard let keychainUser: CurrentUserContainer<BaseParseUser>\n                            = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser),\n                            let keychainUpdatedCurrentDate = keychainUser.currentUser?.updatedAt else {\n                                XCTFail(\"Should get object from Keychain\")\n                                expectation1.fulfill()\n                            return\n                        }\n                        XCTAssertEqual(keychainUpdatedCurrentDate, originalUpdatedAt)\n                        #endif\n                    case .failure(let error):\n                        XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                    }\n                }\n            case .failure(let error):\n                XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n            }\n            expectation1.fulfill()\n        }\n\n        [user].saveAll(transaction: true) { results in\n            switch results {\n\n            case .success(let saved):\n                saved.forEach {\n                    switch $0 {\n                    case .success(let saved):\n                        XCTAssert(saved.hasSameObjectId(as: user))\n                        guard let savedUpdatedAt = saved.updatedAt else {\n                                XCTFail(\"Should unwrap dates\")\n                                expectation2.fulfill()\n                                return\n                        }\n                        guard let originalUpdatedAt = user.updatedAt else {\n                                XCTFail(\"Should unwrap dates\")\n                                expectation2.fulfill()\n                                return\n                        }\n                        XCTAssertEqual(savedUpdatedAt, originalUpdatedAt)\n                        XCTAssertEqual(User.current?.customKey, user.customKey)\n\n                        //Should be updated in memory\n                        guard let updatedCurrentDate = User.current?.updatedAt else {\n                            XCTFail(\"Should unwrap current date\")\n                            expectation2.fulfill()\n                            return\n                        }\n                        XCTAssertEqual(updatedCurrentDate, originalUpdatedAt)\n\n                        #if !os(Linux) && !os(Android) && !os(Windows)\n                        //Should be updated in Keychain\n                        guard let keychainUser: CurrentUserContainer<BaseParseUser>\n                            = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser),\n                            let keychainUpdatedCurrentDate = keychainUser.currentUser?.updatedAt else {\n                                XCTFail(\"Should get object from Keychain\")\n                                expectation2.fulfill()\n                            return\n                        }\n                        XCTAssertEqual(keychainUpdatedCurrentDate, originalUpdatedAt)\n                        #endif\n                    case .failure(let error):\n                        XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n                    }\n                }\n            case .failure(let error):\n                XCTFail(\"Should have fetched: \\(error.localizedDescription)\")\n            }\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testDeleteAllCurrent() {\n        testLogin()\n        MockURLProtocol.removeAll()\n\n        guard let user = User.current else {\n            XCTFail(\"Should unwrap dates\")\n            return\n        }\n\n        let userOnServer = [BatchResponseItem<NoBody>(success: NoBody(), error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(userOnServer)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            let deleted = try [user].deleteAll()\n            deleted.forEach {\n                if case let .failure(error) = $0 {\n                    XCTFail(\"Should have deleted: \\(error.localizedDescription)\")\n                }\n                XCTAssertNil(User.current)\n            }\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n\n        do {\n            let deleted = try [user].deleteAll(transaction: true)\n            deleted.forEach {\n                if case let .failure(error) = $0 {\n                    XCTFail(\"Should have deleted: \\(error.localizedDescription)\")\n                }\n            }\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testDeleteAllAsyncMainQueueCurrent() {\n        testLogin()\n        MockURLProtocol.removeAll()\n\n        let expectation1 = XCTestExpectation(description: \"Delete user1\")\n        let expectation2 = XCTestExpectation(description: \"Delete user2\")\n\n        guard let user = User.current else {\n            XCTFail(\"Should unwrap\")\n            expectation1.fulfill()\n            expectation2.fulfill()\n            return\n        }\n\n        let userOnServer = [BatchResponseItem<NoBody>(success: NoBody(), error: nil)]\n\n        let encoded: Data!\n        do {\n            encoded = try ParseCoding.jsonEncoder().encode(userOnServer)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            expectation1.fulfill()\n            expectation2.fulfill()\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        [user].deleteAll { results in\n            switch results {\n\n            case .success(let deleted):\n                deleted.forEach {\n                    if case let .failure(error) = $0 {\n                        XCTFail(\"Should have deleted: \\(error.localizedDescription)\")\n                    }\n                    XCTAssertNil(User.current)\n                }\n            case .failure(let error):\n                XCTFail(\"Should have deleted: \\(error.localizedDescription)\")\n            }\n            expectation1.fulfill()\n        }\n\n        [user].deleteAll(transaction: true) { results in\n            switch results {\n\n            case .success(let deleted):\n                deleted.forEach {\n                    if case let .failure(error) = $0 {\n                        XCTFail(\"Should have deleted: \\(error.localizedDescription)\")\n                    }\n                }\n            case .failure(let error):\n                XCTFail(\"Should have deleted: \\(error.localizedDescription)\")\n            }\n            expectation2.fulfill()\n        }\n        wait(for: [expectation1, expectation2], timeout: 20.0)\n    }\n\n    func testMeCommand() {\n        var user = User()\n        user.objectId = \"me\"\n        do {\n            let command = try user.meCommand(sessionToken: \"yolo\")\n            XCTAssertNotNil(command)\n            XCTAssertEqual(command.path.urlComponent, \"/users/me\")\n            XCTAssertEqual(command.method, API.Method.GET)\n            XCTAssertNil(command.params)\n            XCTAssertNil(command.body)\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testBecome() { // swiftlint:disable:this function_body_length\n        testLogin()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        guard let user = User.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = User.current?.updatedAt?.addingTimeInterval(+300)\n        serverResponse.sessionToken = \"newValue\"\n        serverResponse.username = \"stop\"\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        do {\n            let become = try user.become(sessionToken: \"newValue\")\n            XCTAssert(become.hasSameObjectId(as: userOnServer))\n            guard let becomeUpdatedAt = become.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            guard let originalUpdatedAt = user.updatedAt else {\n                    XCTFail(\"Should unwrap dates\")\n                    return\n            }\n            XCTAssertGreaterThan(becomeUpdatedAt, originalUpdatedAt)\n            XCTAssertNil(become.ACL)\n\n            //Should be updated in memory\n            XCTAssertEqual(User.current?.updatedAt, becomeUpdatedAt)\n\n            //Should be updated in Keychain\n            #if !os(Linux) && !os(Android) && !os(Windows)\n            guard let keychainUser: CurrentUserContainer<BaseParseUser>\n                = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser) else {\n                    XCTFail(\"Should get object from Keychain\")\n                return\n            }\n            XCTAssertEqual(keychainUser.currentUser?.updatedAt, becomeUpdatedAt)\n            #endif\n\n        } catch {\n            XCTFail(error.localizedDescription)\n        }\n    }\n\n    func testBecomeAsync() { // swiftlint:disable:this function_body_length\n        XCTAssertNil(User.current?.objectId)\n        testLogin()\n        MockURLProtocol.removeAll()\n        XCTAssertNotNil(User.current?.objectId)\n\n        guard let user = User.current else {\n            XCTFail(\"Should unwrap\")\n            return\n        }\n\n        var serverResponse = LoginSignupResponse()\n        serverResponse.updatedAt = User.current?.updatedAt?.addingTimeInterval(+300)\n        serverResponse.sessionToken = \"newValue\"\n        serverResponse.username = \"stop\"\n        serverResponse.password = \"this\"\n\n        var userOnServer: User!\n\n        let encoded: Data!\n        do {\n            encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)\n            //Get dates in correct format from ParseDecoding strategy\n            userOnServer = try serverResponse.getDecoder().decode(User.self, from: encoded)\n        } catch {\n            XCTFail(\"Should encode/decode. Error \\(error)\")\n            return\n        }\n        MockURLProtocol.mockRequests { _ in\n            return MockURLResponse(data: encoded, statusCode: 200, delay: 0.0)\n        }\n\n        let expectation1 = XCTestExpectation(description: \"Fetch user1\")\n        user.become(sessionToken: \"newValue\") { result in\n\n            switch result {\n            case .success(let become):\n                XCTAssert(become.hasSameObjectId(as: userOnServer))\n                guard let becomeUpdatedAt = become.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                    expectation1.fulfill()\n                        return\n                }\n                guard let originalUpdatedAt = user.updatedAt else {\n                        XCTFail(\"Should unwrap dates\")\n                    expectation1.fulfill()\n                        return\n                }\n                XCTAssertGreaterThan(becomeUpdatedAt, originalUpdatedAt)\n                XCTAssertNil(become.ACL)\n\n                //Should be updated in memory\n                XCTAssertEqual(User.current?.updatedAt, becomeUpdatedAt)\n\n                #if !os(Linux) && !os(Android) && !os(Windows)\n                //Should be updated in Keychain\n                guard let keychainUser: CurrentUserContainer<BaseParseUser>\n                    = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.currentUser) else {\n                        XCTFail(\"Should get object from Keychain\")\n                    expectation1.fulfill()\n                    return\n                }\n                XCTAssertEqual(keychainUser.currentUser?.updatedAt, becomeUpdatedAt)\n                #endif\n            case .failure(let error):\n                XCTFail(error.localizedDescription)\n            }\n            expectation1.fulfill()\n        }\n        wait(for: [expectation1], timeout: 20.0)\n    }\n}\n// swiftlint:disable:this file_length\n"
  },
  {
    "path": "Tests/ParseSwiftTests/ParseVersionTests.swift",
    "content": "//\n//  ParseVersionTests.swift\n//  ParseSwift\n//\n//  Created by Corey Baker on 7/2/21.\n//  Copyright © 2021 Parse Community. All rights reserved.\n//\n\nimport Foundation\nimport XCTest\n@testable import ParseSwift\n\nclass ParseVersionTests: XCTestCase {\n    override func setUpWithError() throws {\n        try super.setUpWithError()\n        guard let url = URL(string: \"http://localhost:1337/1\") else {\n            XCTFail(\"Should create valid URL\")\n            return\n        }\n        ParseSwift.initialize(applicationId: \"applicationId\",\n                              clientKey: \"clientKey\",\n                              masterKey: \"masterKey\",\n                              serverURL: url,\n                              testing: true)\n    }\n\n    override func tearDownWithError() throws {\n        try super.tearDownWithError()\n        MockURLProtocol.removeAll()\n        #if !os(Linux) && !os(Android) && !os(Windows)\n        try KeychainStore.shared.deleteAll()\n        #endif\n        try ParseStorage.shared.deleteAll()\n    }\n\n    func testGetSet() throws {\n        XCTAssertEqual(ParseVersion.current, ParseConstants.version)\n        ParseVersion.current = \"1.0.0\"\n        XCTAssertEqual(ParseVersion.current, \"1.0.0\")\n    }\n\n    func testDebug() throws {\n        let version = try ParseVersion(\"1.0.0\")\n        XCTAssertEqual(version.debugDescription,\n                       \"{\\\"string\\\":\\\"1.0.0\\\"}\")\n        XCTAssertEqual(version.description,\n                       \"{\\\"string\\\":\\\"1.0.0\\\"}\")\n    }\n\n    func testCantInitializeWithNil() throws {\n        XCTAssertThrowsError(try ParseVersion(nil))\n    }\n\n    func testDeleteFromKeychain() throws {\n        XCTAssertEqual(ParseVersion.current, ParseConstants.version)\n        ParseVersion.deleteCurrentContainerFromKeychain()\n        XCTAssertNil(ParseVersion.current)\n        ParseVersion.current = \"1.0.0\"\n        XCTAssertEqual(ParseVersion.current, \"1.0.0\")\n    }\n\n    #if !os(Linux) && !os(Android) && !os(Windows)\n    func testCanRetrieveFromKeychain() throws {\n        guard let original = ParseVersion.current else {\n            XCTFail(\"Should have unwrapped\")\n            return\n        }\n        try ParseStorage.shared.delete(valueFor: ParseStorage.Keys.currentVersion)\n        XCTAssertEqual(ParseVersion.current, original)\n    }\n    #endif\n\n    func testEqualTo() throws {\n        let version1 = try ParseVersion(\"1.0.0\")\n        let version2 = try ParseVersion(\"0.9.0\")\n        XCTAssertTrue(version1 == version1)\n        XCTAssertFalse(version1 == version2)\n    }\n\n    func testLessThan() throws {\n        let version1 = try ParseVersion(\"1.0.0\")\n        var version2 = try ParseVersion(\"2.0.0\")\n        XCTAssertFalse(version1 < version1)\n        XCTAssertTrue(version1 < version2)\n        XCTAssertFalse(version2 < version1)\n        version2 = try ParseVersion(\"1.1.0\")\n        XCTAssertTrue(version1 < version2)\n        XCTAssertFalse(version2 < version1)\n        version2 = try ParseVersion(\"1.0.1\")\n        XCTAssertTrue(version1 < version2)\n        XCTAssertFalse(version2 < version1)\n    }\n\n    func testLessThanEqual() throws {\n        let version1 = try ParseVersion(\"1.0.0\")\n        var version2 = version1\n        XCTAssertTrue(version1 <= version2)\n        version2 = try ParseVersion(\"0.9.0\")\n        XCTAssertFalse(version1 <= version2)\n        version2 = try ParseVersion(\"2.0.0\")\n        XCTAssertTrue(version1 <= version2)\n        XCTAssertFalse(version2 <= version1)\n        version2 = try ParseVersion(\"1.1.0\")\n        XCTAssertTrue(version1 <= version2)\n        XCTAssertFalse(version2 <= version1)\n        version2 = try ParseVersion(\"1.0.1\")\n        XCTAssertTrue(version1 <= version2)\n        XCTAssertFalse(version2 <= version1)\n    }\n\n    func testGreaterThan() throws {\n        let version1 = try ParseVersion(\"1.0.0\")\n        var version2 = try ParseVersion(\"2.0.0\")\n        XCTAssertFalse(version1 > version1)\n        XCTAssertTrue(version2 > version1)\n        XCTAssertFalse(version1 > version2)\n        version2 = try ParseVersion(\"1.1.0\")\n        XCTAssertTrue(version2 > version1)\n        XCTAssertFalse(version1 > version2)\n        version2 = try ParseVersion(\"1.0.1\")\n        XCTAssertTrue(version2 > version1)\n        XCTAssertFalse(version1 > version2)\n    }\n\n    func testGreaterThanEqual() throws {\n        let version1 = try ParseVersion(\"1.0.0\")\n        var version2 = version1\n        //XCTAssertTrue(version1 >= version2)\n        version2 = try ParseVersion(\"0.9.0\")\n        XCTAssertFalse(version2 >= version1)\n        version2 = try ParseVersion(\"2.0.0\")\n        XCTAssertTrue(version2 >= version1)\n        XCTAssertFalse(version1 >= version2)\n        version2 = try ParseVersion(\"1.1.0\")\n        XCTAssertTrue(version2 >= version1)\n        XCTAssertFalse(version1 >= version2)\n        version2 = try ParseVersion(\"1.0.1\")\n        XCTAssertTrue(version2 >= version1)\n        XCTAssertFalse(version1 >= version2)\n    }\n}\n"
  }
]