From d0392f17ff9d6f3d2d7d15fe0184c366d5d726be Mon Sep 17 00:00:00 2001 From: Zach FettersMoore Date: Mon, 30 Oct 2023 12:51:05 -0400 Subject: [PATCH 1/5] Adding back xcbeautify (apollographql/apollo-ios-dev#108) --- .github/actions/build-and-run-unit-tests/action.yml | 7 ++++++- .github/workflows/ci-tests.yml | 4 ++++ .github/workflows/release-check.yml | 4 ++++ .../Other-CocoaPods/test-project.sh | 2 +- .../Other-CustomTarget/test-project.sh | 2 +- .../SPMInXcodeProject/test-project.sh | 2 +- 6 files changed, 17 insertions(+), 4 deletions(-) diff --git a/.github/actions/build-and-run-unit-tests/action.yml b/.github/actions/build-and-run-unit-tests/action.yml index 0f71ffc12..bbbe59a58 100644 --- a/.github/actions/build-and-run-unit-tests/action.yml +++ b/.github/actions/build-and-run-unit-tests/action.yml @@ -13,7 +13,12 @@ inputs: runs: using: "composite" steps: + # Look into caching the xcbeautify installation to instead of installing for each test + - name: Install XCBeautify + shell: bash + run: | + HOMEBREW_NO_AUTO_UPDATE=1 brew install xcbeautify - name: Build and Test shell: bash run: | - xcodebuild clean test -resultBundlePath TestResults/ResultBundle.xcresult -derivedDataPath DerivedData -workspace "ApolloDev.xcworkspace" -scheme "${{ inputs.scheme }}" -destination "${{ inputs.destination }}" -testPlan "${{ inputs.test-plan }}" \ No newline at end of file + xcodebuild clean test -resultBundlePath TestResults/ResultBundle.xcresult -derivedDataPath DerivedData -workspace "ApolloDev.xcworkspace" -scheme "${{ inputs.scheme }}" -destination "${{ inputs.destination }}" -testPlan "${{ inputs.test-plan }}" | xcbeautify \ No newline at end of file diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index bb9e1b6f9..738f7e2b2 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -152,6 +152,10 @@ jobs: xcode-version: ${{ env.XCODE_VERSION }} - name: Checkout Repo uses: actions/checkout@v3 + - name: Install XCBeautify + shell: bash + run: | + HOMEBREW_NO_AUTO_UPDATE=1 brew install xcbeautify - name: Test Codegen Configurations shell: bash run: | diff --git a/.github/workflows/release-check.yml b/.github/workflows/release-check.yml index d38f287e7..cbac3fc83 100644 --- a/.github/workflows/release-check.yml +++ b/.github/workflows/release-check.yml @@ -230,6 +230,10 @@ jobs: xcode-version: ${{ env.XCODE_VERSION }} - name: Checkout Repo uses: actions/checkout@v3 + - name: Install XCBeautify + shell: bash + run: | + HOMEBREW_NO_AUTO_UPDATE=1 brew install xcbeautify - name: Test Codegen Configurations shell: bash run: | diff --git a/Tests/TestCodeGenConfigurations/Other-CocoaPods/test-project.sh b/Tests/TestCodeGenConfigurations/Other-CocoaPods/test-project.sh index 6144cea41..ef229c63e 100755 --- a/Tests/TestCodeGenConfigurations/Other-CocoaPods/test-project.sh +++ b/Tests/TestCodeGenConfigurations/Other-CocoaPods/test-project.sh @@ -1,4 +1,4 @@ #!/bin/bash pod install -set -o pipefail && xcodebuild test -workspace CocoaPodsProject.xcworkspace -scheme CocoaPodsProject -destination platform=macOS -quiet +set -o pipefail && xcodebuild test -workspace CocoaPodsProject.xcworkspace -scheme CocoaPodsProject -destination platform=macOS -quiet | xcbeautify --is-ci diff --git a/Tests/TestCodeGenConfigurations/Other-CustomTarget/test-project.sh b/Tests/TestCodeGenConfigurations/Other-CustomTarget/test-project.sh index 409a8b9dc..02ad8c39b 100755 --- a/Tests/TestCodeGenConfigurations/Other-CustomTarget/test-project.sh +++ b/Tests/TestCodeGenConfigurations/Other-CustomTarget/test-project.sh @@ -1,3 +1,3 @@ #!/bin/bash -set -o pipefail && xcodebuild test -scheme CustomTargetProject -destination platform=macOS -quiet +set -o pipefail && xcodebuild test -scheme CustomTargetProject -destination platform=macOS -quiet | xcbeautify --is-ci diff --git a/Tests/TestCodeGenConfigurations/SPMInXcodeProject/test-project.sh b/Tests/TestCodeGenConfigurations/SPMInXcodeProject/test-project.sh index 95cc8b004..ab3a6e1e9 100755 --- a/Tests/TestCodeGenConfigurations/SPMInXcodeProject/test-project.sh +++ b/Tests/TestCodeGenConfigurations/SPMInXcodeProject/test-project.sh @@ -1,3 +1,3 @@ #!/bin/bash -set -o pipefail && xcodebuild test -scheme SPMInXcodeProject -destination platform=macOS -quiet +set -o pipefail && xcodebuild test -scheme SPMInXcodeProject -destination platform=macOS -quiet | xcbeautify --is-ci From 470a9aed5de459d9e44e0faacde9d728114f04cf Mon Sep 17 00:00:00 2001 From: Zach FettersMoore Date: Mon, 30 Oct 2023 17:27:24 -0400 Subject: [PATCH 2/5] Updating docs publish job (apollographql/apollo-ios-dev#110) --- .github/workflows/docs-publish.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docs-publish.yml b/.github/workflows/docs-publish.yml index c599edcd4..559c79537 100644 --- a/.github/workflows/docs-publish.yml +++ b/.github/workflows/docs-publish.yml @@ -1,17 +1,19 @@ name: Deploy docs to production on: - push: + pull_request_target: branches: - main paths: - docs/** + types: [closed] permissions: contents: read jobs: publish: + if: ${{ github.event.pull_request.merged }} permissions: contents: read uses: apollographql/docs/.github/workflows/publish.yml@main From 31f91e28fac17900a18f3505b704f9b6f1882734 Mon Sep 17 00:00:00 2001 From: Anthony Miller Date: Mon, 30 Oct 2023 15:07:58 -0700 Subject: [PATCH 3/5] Escape quotation marks in operation manifest body (apollographql/apollo-ios-dev#111) --- ...ueriesOperationManifestTemplateTests.swift | 42 +++++++ .../OperationDescriptor.swift | 109 ++++++++++++------ .../OperationIdentifierFactory.swift | 2 +- .../LegacyAPQOperationManifestTemplate.swift | 2 +- ...stedQueriesOperationManifestTemplate.swift | 2 +- 5 files changed, 116 insertions(+), 41 deletions(-) diff --git a/Tests/ApolloCodegenTests/CodeGeneration/Templates/PersistedQueriesOperationManifestTemplateTests.swift b/Tests/ApolloCodegenTests/CodeGeneration/Templates/PersistedQueriesOperationManifestTemplateTests.swift index 6ea4ae45f..eeaf20152 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/Templates/PersistedQueriesOperationManifestTemplateTests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/Templates/PersistedQueriesOperationManifestTemplateTests.swift @@ -245,4 +245,46 @@ class PersistedQueriesOperationManifestTemplateTests: XCTestCase { expect(rendered).to(equalLineByLine(expected)) } + + // MARK: Character Escaping Tests + + func test__render__givenOperationWithQuotationMarks_shouldEscapeQuotes() async throws { + // given + let operation = CompilationResult.OperationDefinition.mock( + name: "TestQuery", + type: .query, + source: """ + query TestQuery { + test(param: "string") + } + """ + ) + + let expected = #""" + { + "format": "apollo-persisted-query-manifest", + "version": 1, + "operations": [ + { + "id": "acb5e747550912f7afd3f0a8d11430c4fd50741d1fd7c8d42e5dfcaf96cf8dc1", + "body": "query TestQuery { test(param: \"string\") }", + "name": "TestQuery", + "type": "query" + } + ] + } + """# + + let operations = try await [operation].asyncMap { + OperationManifestTemplate.OperationManifestItem( + operation: OperationDescriptor($0), + identifier: try await self.operationIdentiferFactory.identifier(for: $0) + ) + } + + // when + let rendered = subject.render(operations: operations) + + expect(rendered).to(equalLineByLine(expected)) + } } diff --git a/apollo-ios-codegen/Sources/ApolloCodegenLib/OperationDescriptor.swift b/apollo-ios-codegen/Sources/ApolloCodegenLib/OperationDescriptor.swift index 4ece27c63..1b39743f4 100644 --- a/apollo-ios-codegen/Sources/ApolloCodegenLib/OperationDescriptor.swift +++ b/apollo-ios-codegen/Sources/ApolloCodegenLib/OperationDescriptor.swift @@ -1,29 +1,6 @@ import IR import GraphQLCompiler -private func formatFragmentForRawSourceText(_ fragment: CompilationResult.FragmentDefinition) -> String { - "\n\(fragment.source.convertedToSingleLine())" -} - -private func formatFragmentForManifestJSONBody(_ fragment: CompilationResult.FragmentDefinition) -> String { - #"\n\#(fragment.source.convertedToSingleLine())"# -} - -private func append( - to source: inout String, - set: inout Set, - fragments: [CompilationResult.FragmentDefinition], - format: (CompilationResult.FragmentDefinition) -> String -) { - for fragment in fragments { - if !set.contains(fragment.name) { - set.insert(fragment.name) - source += format(fragment) - append(to: &source, set: &set, fragments: fragment.referencedFragments, format: format) - } - } -} - public struct OperationDescriptor: Sendable { public enum OperationType: String, Hashable { case query @@ -31,6 +8,27 @@ public struct OperationDescriptor: Sendable { case subscription } + public enum SourceFormat { + /// The source text for the operation formatted exactly as it will be sent via network + /// transport when executed by an `ApolloClient`. This value should be used to calculate + /// the operation identifier for a persisted queries manifest. + /// + /// This format includes: + /// - The operation's source, minimized to a single line + /// - The source of each fragment referenced by the operation, each minimized to a + /// single line. There will be a `\n` character between the operation and each + /// fragment. + case rawSource + + /// The source text formatted for inclusion as the "body" field in a JSON object + /// written into a `OperationManifestTemplate`. It provides the + /// exact data that will be sent by the Apollo network transport when the + /// operation is executed in a format that can be written to a file. + /// + /// This escapes the newline characters between fragments. + case manifestJSONBody + } + let underlyingDefinition: CompilationResult.OperationDefinition public var name: String { underlyingDefinition.name } @@ -44,13 +42,6 @@ public struct OperationDescriptor: Sendable { return type } - private func formattedSourceText(_ format: (CompilationResult.FragmentDefinition) -> String) -> String { - var source = underlyingDefinition.source.convertedToSingleLine() - var set = Set() - append(to: &source, set: &set, fragments: underlyingDefinition.referencedFragments, format: format) - return source - } - /// The source text for the operation formatted exactly as it will be sent via network /// transport when executed by an `ApolloClient`. This value should be used to calculate /// the operation identifier for a persisted queries manifest. @@ -60,7 +51,9 @@ public struct OperationDescriptor: Sendable { /// - The source of each fragment referenced by the operation, each minimized to a /// single line. There will be a `\n` character between the operation and each /// fragment. - public var rawSourceText: String { formattedSourceText(formatFragmentForRawSourceText) } + public var rawSourceText: String { + sourceText(withFormat: .rawSource) + } // MARK: - Internal @@ -68,12 +61,52 @@ public struct OperationDescriptor: Sendable { self.underlyingDefinition = operation } - /// The source text formatted for inclusion as the "body" field in a JSON object - /// written into a `OperationManifestTemplate`. It provides the - /// exact data that will be sent by the Apollo network transport when the - /// operation is executed in a format that can be written to a file. - /// - /// This escapes the newline characters between fragments. - var sourceTextFormattedForManifestJSONBody: String { formattedSourceText(formatFragmentForManifestJSONBody) } + func sourceText(withFormat format: SourceFormat) -> String { + format.formatted(underlyingDefinition) + } + +} + +// MARK: - Formatting + +fileprivate extension OperationDescriptor.SourceFormat { + func formatted(_ operation: CompilationResult.OperationDefinition) -> String { + var source = operation.source.convertedToSingleLine() + var set = Set() + append( + to: &source, + set: &set, + fragments: operation.referencedFragments + ) + switch self { + case .rawSource: + return source + case .manifestJSONBody: + return source.replacingOccurrences(of: #"""#, with: #"\""#) + } + } + private func append( + to source: inout String, + set: inout Set, + fragments: [CompilationResult.FragmentDefinition] + ) { + for fragment in fragments { + if !set.contains(fragment.name) { + set.insert(fragment.name) + source += formatted(fragment) + append(to: &source, set: &set, fragments: fragment.referencedFragments) + } + } + } + + private func formatted(_ fragment: CompilationResult.FragmentDefinition) -> String { + switch self { + case .rawSource: + return "\n\(fragment.source.convertedToSingleLine())" + + case .manifestJSONBody: + return #"\n\#(fragment.source.convertedToSingleLine())"# + } + } } diff --git a/apollo-ios-codegen/Sources/ApolloCodegenLib/OperationIdentifierFactory.swift b/apollo-ios-codegen/Sources/ApolloCodegenLib/OperationIdentifierFactory.swift index 301f9c0e5..4c49e8222 100644 --- a/apollo-ios-codegen/Sources/ApolloCodegenLib/OperationIdentifierFactory.swift +++ b/apollo-ios-codegen/Sources/ApolloCodegenLib/OperationIdentifierFactory.swift @@ -56,7 +56,7 @@ let DefaultOperationIdentifierProvider = hasher.update(bufferPointer: UnsafeRawBufferPointer(buffer)) }) } - var definitionSource = operation.rawSourceText + var definitionSource = operation.sourceText(withFormat: .rawSource) updateHash(with: &definitionSource) let digest = hasher.finalize() diff --git a/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/LegacyAPQOperationManifestTemplate.swift b/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/LegacyAPQOperationManifestTemplate.swift index 1fc49c632..4f4f8f726 100644 --- a/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/LegacyAPQOperationManifestTemplate.swift +++ b/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/LegacyAPQOperationManifestTemplate.swift @@ -16,7 +16,7 @@ struct LegacyAPQOperationManifestTemplate: OperationManifestTemplate { return """ "\($0.identifier)" : { "name": "\($0.operation.name)", - "source": "\($0.operation.sourceTextFormattedForManifestJSONBody)" + "source": "\($0.operation.sourceText(withFormat: .manifestJSONBody))" } """ }) diff --git a/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/PersistedQueriesOperationManifestTemplate.swift b/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/PersistedQueriesOperationManifestTemplate.swift index 7a0ca0826..201a5a202 100644 --- a/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/PersistedQueriesOperationManifestTemplate.swift +++ b/apollo-ios-codegen/Sources/ApolloCodegenLib/Templates/PersistedQueriesOperationManifestTemplate.swift @@ -22,7 +22,7 @@ struct PersistedQueriesOperationManifestTemplate: OperationManifestTemplate { return """ { "id": "\($0.identifier)", - "body": "\($0.operation.sourceTextFormattedForManifestJSONBody)", + "body": "\($0.operation.sourceText(withFormat: .manifestJSONBody))", "name": "\($0.operation.name)", "type": "\($0.operation.type.rawValue)" } From aac0fbb0e9e1072061e09978a84a459f50a4167e Mon Sep 17 00:00:00 2001 From: gh-action-runner Date: Mon, 30 Oct 2023 22:08:47 +0000 Subject: [PATCH 4/5] Squashed 'apollo-ios-codegen/' changes from 72467475..21cacc4d 21cacc4d Escape quotation marks in operation manifest body (apollographql/apollo-ios-dev#111) git-subtree-dir: apollo-ios-codegen git-subtree-split: 21cacc4d5eabe49479d82f8c521b1d9f55da1ae4 --- .../OperationDescriptor.swift | 109 ++++++++++++------ .../OperationIdentifierFactory.swift | 2 +- .../LegacyAPQOperationManifestTemplate.swift | 2 +- ...stedQueriesOperationManifestTemplate.swift | 2 +- 4 files changed, 74 insertions(+), 41 deletions(-) diff --git a/Sources/ApolloCodegenLib/OperationDescriptor.swift b/Sources/ApolloCodegenLib/OperationDescriptor.swift index 4ece27c63..1b39743f4 100644 --- a/Sources/ApolloCodegenLib/OperationDescriptor.swift +++ b/Sources/ApolloCodegenLib/OperationDescriptor.swift @@ -1,29 +1,6 @@ import IR import GraphQLCompiler -private func formatFragmentForRawSourceText(_ fragment: CompilationResult.FragmentDefinition) -> String { - "\n\(fragment.source.convertedToSingleLine())" -} - -private func formatFragmentForManifestJSONBody(_ fragment: CompilationResult.FragmentDefinition) -> String { - #"\n\#(fragment.source.convertedToSingleLine())"# -} - -private func append( - to source: inout String, - set: inout Set, - fragments: [CompilationResult.FragmentDefinition], - format: (CompilationResult.FragmentDefinition) -> String -) { - for fragment in fragments { - if !set.contains(fragment.name) { - set.insert(fragment.name) - source += format(fragment) - append(to: &source, set: &set, fragments: fragment.referencedFragments, format: format) - } - } -} - public struct OperationDescriptor: Sendable { public enum OperationType: String, Hashable { case query @@ -31,6 +8,27 @@ public struct OperationDescriptor: Sendable { case subscription } + public enum SourceFormat { + /// The source text for the operation formatted exactly as it will be sent via network + /// transport when executed by an `ApolloClient`. This value should be used to calculate + /// the operation identifier for a persisted queries manifest. + /// + /// This format includes: + /// - The operation's source, minimized to a single line + /// - The source of each fragment referenced by the operation, each minimized to a + /// single line. There will be a `\n` character between the operation and each + /// fragment. + case rawSource + + /// The source text formatted for inclusion as the "body" field in a JSON object + /// written into a `OperationManifestTemplate`. It provides the + /// exact data that will be sent by the Apollo network transport when the + /// operation is executed in a format that can be written to a file. + /// + /// This escapes the newline characters between fragments. + case manifestJSONBody + } + let underlyingDefinition: CompilationResult.OperationDefinition public var name: String { underlyingDefinition.name } @@ -44,13 +42,6 @@ public struct OperationDescriptor: Sendable { return type } - private func formattedSourceText(_ format: (CompilationResult.FragmentDefinition) -> String) -> String { - var source = underlyingDefinition.source.convertedToSingleLine() - var set = Set() - append(to: &source, set: &set, fragments: underlyingDefinition.referencedFragments, format: format) - return source - } - /// The source text for the operation formatted exactly as it will be sent via network /// transport when executed by an `ApolloClient`. This value should be used to calculate /// the operation identifier for a persisted queries manifest. @@ -60,7 +51,9 @@ public struct OperationDescriptor: Sendable { /// - The source of each fragment referenced by the operation, each minimized to a /// single line. There will be a `\n` character between the operation and each /// fragment. - public var rawSourceText: String { formattedSourceText(formatFragmentForRawSourceText) } + public var rawSourceText: String { + sourceText(withFormat: .rawSource) + } // MARK: - Internal @@ -68,12 +61,52 @@ public struct OperationDescriptor: Sendable { self.underlyingDefinition = operation } - /// The source text formatted for inclusion as the "body" field in a JSON object - /// written into a `OperationManifestTemplate`. It provides the - /// exact data that will be sent by the Apollo network transport when the - /// operation is executed in a format that can be written to a file. - /// - /// This escapes the newline characters between fragments. - var sourceTextFormattedForManifestJSONBody: String { formattedSourceText(formatFragmentForManifestJSONBody) } + func sourceText(withFormat format: SourceFormat) -> String { + format.formatted(underlyingDefinition) + } + +} + +// MARK: - Formatting + +fileprivate extension OperationDescriptor.SourceFormat { + func formatted(_ operation: CompilationResult.OperationDefinition) -> String { + var source = operation.source.convertedToSingleLine() + var set = Set() + append( + to: &source, + set: &set, + fragments: operation.referencedFragments + ) + switch self { + case .rawSource: + return source + case .manifestJSONBody: + return source.replacingOccurrences(of: #"""#, with: #"\""#) + } + } + private func append( + to source: inout String, + set: inout Set, + fragments: [CompilationResult.FragmentDefinition] + ) { + for fragment in fragments { + if !set.contains(fragment.name) { + set.insert(fragment.name) + source += formatted(fragment) + append(to: &source, set: &set, fragments: fragment.referencedFragments) + } + } + } + + private func formatted(_ fragment: CompilationResult.FragmentDefinition) -> String { + switch self { + case .rawSource: + return "\n\(fragment.source.convertedToSingleLine())" + + case .manifestJSONBody: + return #"\n\#(fragment.source.convertedToSingleLine())"# + } + } } diff --git a/Sources/ApolloCodegenLib/OperationIdentifierFactory.swift b/Sources/ApolloCodegenLib/OperationIdentifierFactory.swift index 301f9c0e5..4c49e8222 100644 --- a/Sources/ApolloCodegenLib/OperationIdentifierFactory.swift +++ b/Sources/ApolloCodegenLib/OperationIdentifierFactory.swift @@ -56,7 +56,7 @@ let DefaultOperationIdentifierProvider = hasher.update(bufferPointer: UnsafeRawBufferPointer(buffer)) }) } - var definitionSource = operation.rawSourceText + var definitionSource = operation.sourceText(withFormat: .rawSource) updateHash(with: &definitionSource) let digest = hasher.finalize() diff --git a/Sources/ApolloCodegenLib/Templates/LegacyAPQOperationManifestTemplate.swift b/Sources/ApolloCodegenLib/Templates/LegacyAPQOperationManifestTemplate.swift index 1fc49c632..4f4f8f726 100644 --- a/Sources/ApolloCodegenLib/Templates/LegacyAPQOperationManifestTemplate.swift +++ b/Sources/ApolloCodegenLib/Templates/LegacyAPQOperationManifestTemplate.swift @@ -16,7 +16,7 @@ struct LegacyAPQOperationManifestTemplate: OperationManifestTemplate { return """ "\($0.identifier)" : { "name": "\($0.operation.name)", - "source": "\($0.operation.sourceTextFormattedForManifestJSONBody)" + "source": "\($0.operation.sourceText(withFormat: .manifestJSONBody))" } """ }) diff --git a/Sources/ApolloCodegenLib/Templates/PersistedQueriesOperationManifestTemplate.swift b/Sources/ApolloCodegenLib/Templates/PersistedQueriesOperationManifestTemplate.swift index 7a0ca0826..201a5a202 100644 --- a/Sources/ApolloCodegenLib/Templates/PersistedQueriesOperationManifestTemplate.swift +++ b/Sources/ApolloCodegenLib/Templates/PersistedQueriesOperationManifestTemplate.swift @@ -22,7 +22,7 @@ struct PersistedQueriesOperationManifestTemplate: OperationManifestTemplate { return """ { "id": "\($0.identifier)", - "body": "\($0.operation.sourceTextFormattedForManifestJSONBody)", + "body": "\($0.operation.sourceText(withFormat: .manifestJSONBody))", "name": "\($0.operation.name)", "type": "\($0.operation.type.rawValue)" } From d7fa3443d9e4ed3b31707016695e39ec2145e72e Mon Sep 17 00:00:00 2001 From: Anthony Miller Date: Mon, 30 Oct 2023 15:37:55 -0700 Subject: [PATCH 5/5] Test isolation fixes (apollographql/apollo-ios-dev#112) --- .../MockFileManager.swift | 60 ++-- .../ApolloCodegenTests.swift | 300 +++++++++--------- .../ApolloSchemaDownloaderInternalTests.swift | 12 +- .../FileGenerators/FileGeneratorTests.swift | 8 +- .../OperationManifestFileGeneratorTests.swift | 1 + .../SchemaModuleFileGeneratorTests.swift | 9 +- .../FileManagerExtensionTests.swift | 2 +- 7 files changed, 228 insertions(+), 164 deletions(-) diff --git a/Tests/ApolloCodegenInternalTestHelpers/MockFileManager.swift b/Tests/ApolloCodegenInternalTestHelpers/MockFileManager.swift index 50404cd22..a313627ee 100644 --- a/Tests/ApolloCodegenInternalTestHelpers/MockFileManager.swift +++ b/Tests/ApolloCodegenInternalTestHelpers/MockFileManager.swift @@ -24,20 +24,33 @@ public class MockApolloFileManager: ApolloFileManager { } } - /// If `true` then all called closures must be mocked otherwise the call will fail. When `false` any called closure - /// that is not mocked will fall through to `super`. As a byproduct of `false`, all mocked closures must be called otherwise - /// the test will fail. + /// If `true` then any function on the file manager called that is not mocked will + /// result in a test failure. If `false`, any called closure that is not mocked will fall + /// through to `super`. Defaults to `true`. var strict: Bool { _base.strict } + + /// If `true` all mocked closures must be called otherwise the test + /// will fail. Defaults to `true`. + var requireAllClosuresCalled: Bool { _base.requireAllClosuresCalled } + var _base: MockFileManager { unsafeDowncast(base, to: MockFileManager.self) } /// Designated initializer. /// /// - Parameters: - /// - strict: If `true` then all called closures must be mocked otherwise the call will fail. - /// When `false` any called closure that is not mocked will fall through to `super`. As a - /// byproduct of `false`, all mocked closures must be called otherwise the test will fail. - public init(strict: Bool = true) { - super.init(base: MockFileManager(strict: strict)) + /// - strict: If `true` then any function on the file manager called that is not mocked will + /// result in a test failure. If `false`, any called closure that is not mocked will fall + /// through to `super`. Defaults to `true`. + /// - requireAllClosuresCalled: If `true` all mocked closures must be called otherwise the test + /// will fail. Defaults to `true`. + public init( + strict: Bool = true, + requireAllClosuresCalled: Bool = true + ) { + super.init(base: MockFileManager( + strict: strict, + requireAllClosuresCalled: requireAllClosuresCalled + )) } /// Provide a mock closure for the `FileManager` function. @@ -58,21 +71,26 @@ public class MockApolloFileManager: ApolloFileManager { class MockFileManager: FileManager { + private let lock = NSLock() + fileprivate var closures: [String: Closure] = [:] fileprivate var closuresToBeCalled: Set = [] - /// If `true` then all called closures must be mocked otherwise the call will fail. When `false` any called closure - /// that is not mocked will fall through to `super`. As a byproduct of `false`, all mocked closures must be called otherwise - /// the test will fail. let strict: Bool - fileprivate init(strict: Bool = true) { + let requireAllClosuresCalled: Bool + + fileprivate init( + strict: Bool = true, + requireAllClosuresCalled: Bool = true + ) { self.strict = strict + self.requireAllClosuresCalled = requireAllClosuresCalled } deinit { - if strict == false && allClosuresCalled == false { - XCTFail("Non-strict mode requires that all mocked closures are called! Check \(closuresToBeCalled) in your MockFileManager instance.") + if requireAllClosuresCalled && !allClosuresCalled { + XCTFail("`requireAllClosuresCalled` is `true`, but not all mocked closures are called! Check \(closuresToBeCalled) in your MockFileManager instance.") } } @@ -80,17 +98,23 @@ public class MockApolloFileManager: ApolloFileManager { /// /// - Parameter closure: The mocked function closure. fileprivate func mock(closure: Closure) { - closures[closure.description] = closure - closuresToBeCalled.insert(closure.description) + lock.withLock { + closures[closure.description] = closure + closuresToBeCalled.insert(closure.description) + } } fileprivate func didCall(closure: Closure) { - closuresToBeCalled.remove(closure.description) + lock.withLock { + _ = closuresToBeCalled.remove(closure.description) + } } /// Check whether all mocked closures were called during the lifetime of an instance. fileprivate var allClosuresCalled: Bool { - return closuresToBeCalled.isEmpty + return lock.withLock { + return closuresToBeCalled.isEmpty + } } // MARK: FileManager overrides diff --git a/Tests/ApolloCodegenTests/ApolloCodegenTests.swift b/Tests/ApolloCodegenTests/ApolloCodegenTests.swift index b2090e335..1662efa60 100644 --- a/Tests/ApolloCodegenTests/ApolloCodegenTests.swift +++ b/Tests/ApolloCodegenTests/ApolloCodegenTests.swift @@ -10,14 +10,14 @@ class ApolloCodegenTests: XCTestCase { private var directoryURL: URL { testFileManager.directoryURL } private var testFileManager: TestIsolatedFileManager! - override func setUpWithError() throws { + override func setUpWithError() throws { + try super.setUpWithError() testFileManager = try testIsolatedFileManager() - - testFileManager.fileManager.changeCurrentDirectoryPath(directoryURL.path) } override func tearDownWithError() throws { testFileManager = nil + try super.tearDownWithError() } // MARK: Helpers @@ -304,12 +304,12 @@ class ApolloCodegenTests: XCTestCase { // then await expect { try await subject.compileGraphQLResult().operations } .to(throwError { error in - guard let error = error as? GraphQLError else { - fail("Expected .graphQLSourceValidationFailure because we attempted to compile a document that uses CCN without CCN enabled, got \(error)") - return - } - expect(error.message).to(equal("Syntax Error: Expected Name, found \"!\".")) - }) + guard let error = error as? GraphQLError else { + fail("Expected .graphQLSourceValidationFailure because we attempted to compile a document that uses CCN without CCN enabled, got \(error)") + return + } + expect(error.message).to(equal("Syntax Error: Expected Name, found \"!\".")) + }) } func test_compileResults_givenRelativeSchemaSearchPath_relativeToRootURL_shouldReturnSchemaRelativeToRoot() async throws { @@ -507,7 +507,7 @@ class ApolloCodegenTests: XCTestCase { let introspectionJSON = try String( contentsOf: ApolloCodegenInternalTestHelpers.Resources.StarWars.JSONSchema ) - + try createFile(body: introspectionJSON, filename: "schemaJSON.json") try createFile( @@ -743,7 +743,7 @@ class ApolloCodegenTests: XCTestCase { directoryURL.appendingPathComponent("Sources/Schema/CustomScalars/CustomDate.swift").path, directoryURL.appendingPathComponent("Sources/Schema/CustomScalars/Object.swift").path, - + directoryURL.appendingPathComponent("Sources/Operations/Queries/AllAnimalsQuery.graphql.swift").path, directoryURL.appendingPathComponent("Sources/Operations/Queries/AllAnimalsIncludeSkipQuery.graphql.swift").path, directoryURL.appendingPathComponent("Sources/Operations/Queries/ClassroomPetsQuery.graphql.swift").path, @@ -1612,7 +1612,7 @@ class ApolloCodegenTests: XCTestCase { expect(ApolloFileManager.default.doesFileExist(atPath: testUserFileInChildPath)).to(beTrue()) expect(ApolloFileManager.default.doesFileExist(atPath: testUserFileInNestedChildPath)).to(beTrue()) } - + func test__fileDeletion__inOperationRelativeDirectory__whenSymlinkIsUsed() async throws { // given try createFile(containing: schemaData, named: "schema.graphqls") @@ -1621,7 +1621,7 @@ class ApolloCodegenTests: XCTestCase { let codeDirectory = "code" let relativeSubPath = "Operations" let operationFilename = "TestQuery.graphql" - + try createOperationFile( type: .query, named: "TestQuery", @@ -1632,11 +1632,11 @@ class ApolloCodegenTests: XCTestCase { let symLinkURL = directoryURL.appendingPathComponent("/\(codeDirectory)/\(relativeSubPath)/") let symLinkDestURL = directoryURL.appendingPathComponent("\(schemaDirectory)/Sources/Operations/") let fileValidationPath = symLinkDestURL.appendingPathComponent("\(operationFilename).swift").path - + //setup symlink folder try testFileManager.fileManager.createDirectory(at: symLinkDestURL, withIntermediateDirectories: true) try testFileManager.fileManager.createSymbolicLink(at: symLinkURL, withDestinationURL: symLinkDestURL) - + // when let config = ApolloCodegenConfiguration.mock( input: .init( @@ -1654,14 +1654,14 @@ class ApolloCodegenTests: XCTestCase { ) // then - + // running codegen multiple times to validate symlink related file creation/deletion bug try await ApolloCodegen.build(with: config, withRootURL: directoryURL) expect(ApolloFileManager.default.doesFileExist(atPath: fileValidationPath)).to(beTrue()) - + try await ApolloCodegen.build(with: config, withRootURL: directoryURL) expect(ApolloFileManager.default.doesFileExist(atPath: fileValidationPath)).to(beTrue()) - + try await ApolloCodegen.build(with: config, withRootURL: directoryURL) expect(ApolloFileManager.default.doesFileExist(atPath: fileValidationPath)).to(beTrue()) @@ -2363,11 +2363,11 @@ class ApolloCodegenTests: XCTestCase { .to(throwError(ApolloCodegen.Error.schemaNameConflict(name: config.schemaNamespace))) } } - + func test__validation__givenTargetName_matchingDisallowedTargetName_shouldThrow() throws { // given let disallowedNames = ["apollo", "Apollo", "apolloapi", "ApolloAPI"] - + // when for name in disallowedNames { let config = ApolloCodegenConfiguration.mock( @@ -2375,7 +2375,7 @@ class ApolloCodegenTests: XCTestCase { moduleType: .embeddedInTarget(name: name) ) ) - + // then expect(try ApolloCodegen._validate(config: config)) .to(throwError(ApolloCodegen.Error.targetNameConflict(name: name))) @@ -2486,7 +2486,7 @@ class ApolloCodegenTests: XCTestCase { // then expect(try ApolloCodegen._validate(config: config)).notTo(throwError()) } - + func test__validation__selectionSet_typeConflicts_shouldThrowError() async throws { let schemaDefData: Data = { """ @@ -2511,7 +2511,7 @@ class ApolloCodegenTests: XCTestCase { } """ }().data(using: .utf8)! - + let operationData: Data = """ query ConflictingQuery { @@ -2532,10 +2532,10 @@ class ApolloCodegenTests: XCTestCase { } } """.data(using: .utf8)! - + try createFile(containing: schemaDefData, named: "schema.graphqls") try createFile(containing: operationData, named: "operation.graphql") - + let config = ApolloCodegenConfiguration.mock( input: .init( schemaSearchPaths: ["schema*.graphqls"], @@ -2547,19 +2547,21 @@ class ApolloCodegenTests: XCTestCase { operations: .inSchemaModule ) ) - - await expect { try await ApolloCodegen.build(with: config) } - .to(throwError { error in - guard case let ApolloCodegen.Error.typeNameConflict(name, conflictingName, containingObject) = error else { - fail("Expected .typeNameConflict, got .\(error)") - return - } - expect(name).to(equal("value")) - expect(conflictingName).to(equal("values")) - expect(containingObject).to(equal("ConflictingQuery")) - }) + + await expect { + try await ApolloCodegen.build(with: config, withRootURL: self.directoryURL) + } + .to(throwError { error in + guard case let ApolloCodegen.Error.typeNameConflict(name, conflictingName, containingObject) = error else { + fail("Expected .typeNameConflict, got .\(error)") + return + } + expect(name).to(equal("value")) + expect(conflictingName).to(equal("values")) + expect(containingObject).to(equal("ConflictingQuery")) + }) } - + func test__validation__selectionSet_typeConflicts_withDirectInlineFragment_shouldThrowError() async throws { let schemaDefData: Data = { """ @@ -2584,7 +2586,7 @@ class ApolloCodegenTests: XCTestCase { } """ }().data(using: .utf8)! - + let operationData: Data = """ query ConflictingQuery { @@ -2606,10 +2608,10 @@ class ApolloCodegenTests: XCTestCase { } } """.data(using: .utf8)! - + try createFile(containing: schemaDefData, named: "schema.graphqls") try createFile(containing: operationData, named: "operation.graphql") - + let config = ApolloCodegenConfiguration.mock( input: .init( schemaSearchPaths: ["schema*.graphqls"], @@ -2621,19 +2623,21 @@ class ApolloCodegenTests: XCTestCase { operations: .inSchemaModule ) ) - - await expect { try await ApolloCodegen.build(with: config) } - .to(throwError { error in - guard case let ApolloCodegen.Error.typeNameConflict(name, conflictingName, containingObject) = error else { - fail("Expected .typeNameConflict, got .\(error)") - return - } - expect(name).to(equal("values")) - expect(conflictingName).to(equal("value")) - expect(containingObject).to(equal("ConflictingQuery")) - }) + + await expect { + try await ApolloCodegen.build(with: config, withRootURL: self.directoryURL) + } + .to(throwError { error in + guard case let ApolloCodegen.Error.typeNameConflict(name, conflictingName, containingObject) = error else { + fail("Expected .typeNameConflict, got .\(error)") + return + } + expect(name).to(equal("values")) + expect(conflictingName).to(equal("value")) + expect(containingObject).to(equal("ConflictingQuery")) + }) } - + func test__validation__selectionSet_typeConflicts_withMergedInlineFragment_shouldThrowError() async throws { let schemaDefData: Data = { """ @@ -2661,7 +2665,7 @@ class ApolloCodegenTests: XCTestCase { } """ }().data(using: .utf8)! - + let operationData: Data = """ query ConflictingQuery { @@ -2687,10 +2691,10 @@ class ApolloCodegenTests: XCTestCase { } } """.data(using: .utf8)! - + try createFile(containing: schemaDefData, named: "schema.graphqls") try createFile(containing: operationData, named: "operation.graphql") - + let config = ApolloCodegenConfiguration.mock( input: .init( schemaSearchPaths: ["schema*.graphqls"], @@ -2702,19 +2706,21 @@ class ApolloCodegenTests: XCTestCase { operations: .inSchemaModule ) ) - - await expect { try await ApolloCodegen.build(with: config) } - .to(throwError { error in - guard case let ApolloCodegen.Error.typeNameConflict(name, conflictingName, containingObject) = error else { - fail("Expected .typeNameConflict, got .\(error)") - return - } - expect(name).to(equal("values")) - expect(conflictingName).to(equal("value")) - expect(containingObject).to(equal("ConflictingQuery")) - }) + + await expect { + try await ApolloCodegen.build(with: config, withRootURL: self.directoryURL) + } + .to(throwError { error in + guard case let ApolloCodegen.Error.typeNameConflict(name, conflictingName, containingObject) = error else { + fail("Expected .typeNameConflict, got .\(error)") + return + } + expect(name).to(equal("values")) + expect(conflictingName).to(equal("value")) + expect(containingObject).to(equal("ConflictingQuery")) + }) } - + func test__validation__selectionSet_typeConflicts_withDirectNamedFragment_shouldThrowError() async throws { let schemaDefData: Data = { """ @@ -2737,7 +2743,7 @@ class ApolloCodegenTests: XCTestCase { } """ }().data(using: .utf8)! - + let operationData: Data = """ query ConflictingQuery { @@ -2753,7 +2759,7 @@ class ApolloCodegenTests: XCTestCase { } } } - + fragment ContainerFields on Container { values { propertyA @@ -2761,10 +2767,10 @@ class ApolloCodegenTests: XCTestCase { } } """.data(using: .utf8)! - + try createFile(containing: schemaDefData, named: "schema.graphqls") try createFile(containing: operationData, named: "operation.graphql") - + let config = ApolloCodegenConfiguration.mock( input: .init( schemaSearchPaths: ["schema*.graphqls"], @@ -2776,19 +2782,21 @@ class ApolloCodegenTests: XCTestCase { operations: .inSchemaModule ) ) - - await expect { try await ApolloCodegen.build(with: config) } - .to(throwError { error in - guard case let ApolloCodegen.Error.typeNameConflict(name, conflictingName, containingObject) = error else { - fail("Expected .typeNameConflict, got .\(error)") - return - } - expect(name).to(equal("value")) - expect(conflictingName).to(equal("values")) - expect(containingObject).to(equal("ConflictingQuery")) - }) + + await expect { + try await ApolloCodegen.build(with: config, withRootURL: self.directoryURL) + } + .to(throwError { error in + guard case let ApolloCodegen.Error.typeNameConflict(name, conflictingName, containingObject) = error else { + fail("Expected .typeNameConflict, got .\(error)") + return + } + expect(name).to(equal("value")) + expect(conflictingName).to(equal("values")) + expect(containingObject).to(equal("ConflictingQuery")) + }) } - + func test__validation__selectionSet_typeConflicts_withNamedFragment_shouldThrowError() async throws { let schemaDefData: Data = { """ @@ -2811,7 +2819,7 @@ class ApolloCodegenTests: XCTestCase { } """ }().data(using: .utf8)! - + let operationData: Data = """ fragment ContainerFields on Container { @@ -2827,10 +2835,10 @@ class ApolloCodegenTests: XCTestCase { } } """.data(using: .utf8)! - + try createFile(containing: schemaDefData, named: "schema.graphqls") try createFile(containing: operationData, named: "operation.graphql") - + let config = ApolloCodegenConfiguration.mock( input: .init( schemaSearchPaths: ["schema*.graphqls"], @@ -2842,19 +2850,21 @@ class ApolloCodegenTests: XCTestCase { operations: .inSchemaModule ) ) - - await expect { try await ApolloCodegen.build(with: config) } - .to(throwError { error in - guard case let ApolloCodegen.Error.typeNameConflict(name, conflictingName, containingObject) = error else { - fail("Expected .typeNameConflict, got .\(error)") - return - } - expect(name).to(equal("value")) - expect(conflictingName).to(equal("values")) - expect(containingObject).to(equal("ContainerFields")) - }) + + await expect { + try await ApolloCodegen.build(with: config, withRootURL: self.directoryURL) + } + .to(throwError { error in + guard case let ApolloCodegen.Error.typeNameConflict(name, conflictingName, containingObject) = error else { + fail("Expected .typeNameConflict, got .\(error)") + return + } + expect(name).to(equal("value")) + expect(conflictingName).to(equal("values")) + expect(containingObject).to(equal("ContainerFields")) + }) } - + func test__validation__selectionSet_typeConflicts_withNamedFragmentFieldCollisionWithinInlineFragment_shouldThrowError() async throws { let schemaDefData: Data = { """ @@ -2884,7 +2894,7 @@ class ApolloCodegenTests: XCTestCase { } """ }().data(using: .utf8)! - + let operationData: Data = """ query ConflictingQuery { @@ -2910,10 +2920,10 @@ class ApolloCodegenTests: XCTestCase { } } """.data(using: .utf8)! - + try createFile(containing: schemaDefData, named: "schema.graphqls") try createFile(containing: operationData, named: "operation.graphql") - + let config = ApolloCodegenConfiguration.mock( input: .init( schemaSearchPaths: ["schema*.graphqls"], @@ -2925,19 +2935,21 @@ class ApolloCodegenTests: XCTestCase { operations: .inSchemaModule ) ) - - await expect { try await ApolloCodegen.build(with: config) } - .to(throwError { error in - guard case let ApolloCodegen.Error.typeNameConflict(name, conflictingName, containingObject) = error else { - fail("Expected .typeNameConflict, got .\(error)") - return - } - expect(name).to(equal("value")) - expect(conflictingName).to(equal("values")) - expect(containingObject).to(equal("ConflictingQuery")) - }) + + await expect { + try await ApolloCodegen.build(with: config, withRootURL: self.directoryURL) + } + .to(throwError { error in + guard case let ApolloCodegen.Error.typeNameConflict(name, conflictingName, containingObject) = error else { + fail("Expected .typeNameConflict, got .\(error)") + return + } + expect(name).to(equal("value")) + expect(conflictingName).to(equal("values")) + expect(containingObject).to(equal("ConflictingQuery")) + }) } - + func test__validation__selectionSet_typeConflicts_withNamedFragmentWithinInlineFragmentTypeCollision_shouldThrowError() async throws { let schemaDefData: Data = { """ @@ -2973,7 +2985,7 @@ class ApolloCodegenTests: XCTestCase { } """ }().data(using: .utf8)! - + let operationData: Data = """ query ConflictingQuery { @@ -2998,10 +3010,10 @@ class ApolloCodegenTests: XCTestCase { description } """.data(using: .utf8)! - + try createFile(containing: schemaDefData, named: "schema.graphqls") try createFile(containing: operationData, named: "operation.graphql") - + let config = ApolloCodegenConfiguration.mock( input: .init( schemaSearchPaths: ["schema*.graphqls"], @@ -3013,19 +3025,21 @@ class ApolloCodegenTests: XCTestCase { operations: .inSchemaModule ) ) - - await expect { try await ApolloCodegen.build(with: config) } - .to(throwError { error in - guard case let ApolloCodegen.Error.typeNameConflict(name, conflictingName, containingObject) = error else { - fail("Expected .typeNameConflict, got .\(error)") - return - } - expect(name).to(equal("value")) - expect(conflictingName).to(equal("value")) - expect(containingObject).to(equal("ConflictingQuery")) - }) + + await expect { + try await ApolloCodegen.build(with: config, withRootURL: self.directoryURL) + } + .to(throwError { error in + guard case let ApolloCodegen.Error.typeNameConflict(name, conflictingName, containingObject) = error else { + fail("Expected .typeNameConflict, got .\(error)") + return + } + expect(name).to(equal("value")) + expect(conflictingName).to(equal("value")) + expect(containingObject).to(equal("ConflictingQuery")) + }) } - + func test__validation__selectionSet_typeConflicts_withFieldUsingNamedFragmentCollision_shouldThrowError() async throws { let schemaDefData: Data = { """ @@ -3049,7 +3063,7 @@ class ApolloCodegenTests: XCTestCase { } """ }().data(using: .utf8)! - + let operationData: Data = """ query ConflictingQuery { @@ -3068,10 +3082,10 @@ class ApolloCodegenTests: XCTestCase { propertyD } """.data(using: .utf8)! - + try createFile(containing: schemaDefData, named: "schema.graphqls") try createFile(containing: operationData, named: "operation.graphql") - + let config = ApolloCodegenConfiguration.mock( input: .init( schemaSearchPaths: ["schema*.graphqls"], @@ -3083,17 +3097,19 @@ class ApolloCodegenTests: XCTestCase { operations: .inSchemaModule ) ) - - await expect { try await ApolloCodegen.build(with: config) } - .to(throwError { error in - guard case let ApolloCodegen.Error.typeNameConflict(name, conflictingName, containingObject) = error else { - fail("Expected .typeNameConflict, got .\(error)") - return - } - expect(name).to(equal("info")) - expect(conflictingName).to(equal("Info")) - expect(containingObject).to(equal("ConflictingQuery")) - }) + + await expect { + try await ApolloCodegen.build(with: config, withRootURL: self.directoryURL) + } + .to(throwError { error in + guard case let ApolloCodegen.Error.typeNameConflict(name, conflictingName, containingObject) = error else { + fail("Expected .typeNameConflict, got .\(error)") + return + } + expect(name).to(equal("info")) + expect(conflictingName).to(equal("Info")) + expect(containingObject).to(equal("ConflictingQuery")) + }) } // MARK: Path Match Exclusion Tests diff --git a/Tests/ApolloCodegenTests/ApolloSchemaDownloaderInternalTests.swift b/Tests/ApolloCodegenTests/ApolloSchemaDownloaderInternalTests.swift index 4a52bb662..f087c78f9 100644 --- a/Tests/ApolloCodegenTests/ApolloSchemaDownloaderInternalTests.swift +++ b/Tests/ApolloCodegenTests/ApolloSchemaDownloaderInternalTests.swift @@ -5,7 +5,17 @@ import ApolloCodegenInternalTestHelpers @testable import GraphQLCompiler class ApolloSchemaDownloaderInternalTests: XCTestCase { - let mockFileManager = MockApolloFileManager(strict: true) + var mockFileManager: MockApolloFileManager! + + override func setUp() { + super.setUp() + mockFileManager = MockApolloFileManager(strict: true) + } + + override func tearDown() { + mockFileManager = nil + super.tearDown() + } // MARK: Conversion Tests diff --git a/Tests/ApolloCodegenTests/CodeGeneration/FileGenerators/FileGeneratorTests.swift b/Tests/ApolloCodegenTests/CodeGeneration/FileGenerators/FileGeneratorTests.swift index 61196687d..d25a16a04 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/FileGenerators/FileGeneratorTests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/FileGenerators/FileGeneratorTests.swift @@ -4,18 +4,24 @@ import Nimble @testable import ApolloCodegenInternalTestHelpers class FileGeneratorTests: XCTestCase { - let fileManager = MockApolloFileManager(strict: false) + var fileManager: MockApolloFileManager! var config: ApolloCodegen.ConfigurationContext! var fileTarget: FileTarget! var template: MockFileTemplate! var subject: MockFileGenerator! + override func setUp() { + super.setUp() + fileManager = MockApolloFileManager(strict: false) + } + override func tearDown() { template = nil subject = nil fileTarget = nil config = nil + fileManager = nil super.tearDown() } diff --git a/Tests/ApolloCodegenTests/CodeGeneration/FileGenerators/OperationManifestFileGeneratorTests.swift b/Tests/ApolloCodegenTests/CodeGeneration/FileGenerators/OperationManifestFileGeneratorTests.swift index 67b520931..5aeea32ec 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/FileGenerators/OperationManifestFileGeneratorTests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/FileGenerators/OperationManifestFileGeneratorTests.swift @@ -16,6 +16,7 @@ class OperationManifestFileGeneratorTests: XCTestCase { override func tearDown() { subject = nil fileManager = nil + super.tearDown() } // MARK: Test Helpers diff --git a/Tests/ApolloCodegenTests/CodeGeneration/FileGenerators/SchemaModuleFileGeneratorTests.swift b/Tests/ApolloCodegenTests/CodeGeneration/FileGenerators/SchemaModuleFileGeneratorTests.swift index 5157e50ae..2c026c776 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/FileGenerators/SchemaModuleFileGeneratorTests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/FileGenerators/SchemaModuleFileGeneratorTests.swift @@ -5,7 +5,7 @@ import ApolloInternalTestHelpers import Nimble class SchemaModuleFileGeneratorTests: XCTestCase { - let mockFileManager = MockApolloFileManager(strict: false) + var mockFileManager: MockApolloFileManager! var testFilePathBuilder: TestFilePathBuilder! @@ -14,10 +14,12 @@ class SchemaModuleFileGeneratorTests: XCTestCase { override func setUp() { super.setUp() testFilePathBuilder = TestFilePathBuilder(test: self) + mockFileManager = MockApolloFileManager(strict: false) } override func tearDown() { testFilePathBuilder = nil + mockFileManager = nil super.tearDown() } @@ -120,6 +122,11 @@ class SchemaModuleFileGeneratorTests: XCTestCase { func test__generate__givenModuleType_other_shouldNotGenerateFile() async throws { // given + mockFileManager = MockApolloFileManager( + strict: false, + requireAllClosuresCalled: false + ) + let configuration = ApolloCodegen.ConfigurationContext(config: ApolloCodegenConfiguration.mock( .other, to: rootURL.path diff --git a/Tests/ApolloCodegenTests/FileManagerExtensionTests.swift b/Tests/ApolloCodegenTests/FileManagerExtensionTests.swift index a840c6e00..8d6659120 100644 --- a/Tests/ApolloCodegenTests/FileManagerExtensionTests.swift +++ b/Tests/ApolloCodegenTests/FileManagerExtensionTests.swift @@ -525,7 +525,7 @@ class FileManagerExtensionTests: XCTestCase { // given let filePath = URL(fileURLWithPath: self.uniquePath).path let directoryPath = URL(fileURLWithPath: self.uniquePath).deletingLastPathComponent().path - let mocked = MockApolloFileManager(strict: true) + let mocked = MockApolloFileManager(strict: true, requireAllClosuresCalled: false) mocked.mock(closure: .fileExists({ path, isDirectory in switch path {