Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Union test mock generator #2298

Merged
merged 7 commits into from
Jun 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 18 additions & 2 deletions Apollo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,10 @@
E61DD76526D60C1800C41614 /* SQLiteDotSwiftDatabaseBehaviorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E61DD76426D60C1800C41614 /* SQLiteDotSwiftDatabaseBehaviorTests.swift */; };
E61EF713275EC99A00191DA7 /* ApolloCodegenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E61EF712275EC99A00191DA7 /* ApolloCodegenTests.swift */; };
E61F4BF827A8FC8E0049886A /* FragmentFileGeneratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E61F4BF727A8FC8E0049886A /* FragmentFileGeneratorTests.swift */; };
E6203342284F1C9600A291D1 /* MockUnionFileGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6203341284F1C9600A291D1 /* MockUnionFileGenerator.swift */; };
E6203344284F1D1100A291D1 /* MockUnionTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6203343284F1D1100A291D1 /* MockUnionTemplate.swift */; };
E6203346284F252A00A291D1 /* MockUnionFileGeneratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6203345284F252A00A291D1 /* MockUnionFileGeneratorTests.swift */; };
E6203348284F25DF00A291D1 /* MockUnionTemplateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6203347284F25DF00A291D1 /* MockUnionTemplateTests.swift */; };
E623FD2A2797A6F4008B4CED /* InterfaceTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E623FD292797A6F4008B4CED /* InterfaceTemplate.swift */; };
E64F7EB827A0854E0059C021 /* UnionTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E64F7EB727A0854E0059C021 /* UnionTemplate.swift */; };
E64F7EBA27A085D90059C021 /* UnionTemplateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = E64F7EB927A085D90059C021 /* UnionTemplateTests.swift */; };
Expand Down Expand Up @@ -1287,6 +1291,10 @@
E61DD76426D60C1800C41614 /* SQLiteDotSwiftDatabaseBehaviorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SQLiteDotSwiftDatabaseBehaviorTests.swift; sourceTree = "<group>"; };
E61EF712275EC99A00191DA7 /* ApolloCodegenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApolloCodegenTests.swift; sourceTree = "<group>"; };
E61F4BF727A8FC8E0049886A /* FragmentFileGeneratorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FragmentFileGeneratorTests.swift; sourceTree = "<group>"; };
E6203341284F1C9600A291D1 /* MockUnionFileGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUnionFileGenerator.swift; sourceTree = "<group>"; };
E6203343284F1D1100A291D1 /* MockUnionTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUnionTemplate.swift; sourceTree = "<group>"; };
E6203345284F252A00A291D1 /* MockUnionFileGeneratorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUnionFileGeneratorTests.swift; sourceTree = "<group>"; };
E6203347284F25DF00A291D1 /* MockUnionTemplateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUnionTemplateTests.swift; sourceTree = "<group>"; };
E623FD292797A6F4008B4CED /* InterfaceTemplate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InterfaceTemplate.swift; sourceTree = "<group>"; };
E623FD2B2797A700008B4CED /* InterfaceTemplateTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InterfaceTemplateTests.swift; sourceTree = "<group>"; };
E64F7EB727A0854E0059C021 /* UnionTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnionTemplate.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2332,6 +2340,8 @@
DE5FD60A276970FC0033EE23 /* FragmentTemplate.swift */,
E69BEDA42798B86D00000D10 /* InputObjectTemplate.swift */,
E623FD292797A6F4008B4CED /* InterfaceTemplate.swift */,
DE9CEAEE282C62B700959AF9 /* MockObjectTemplate.swift */,
E6203343284F1D1100A291D1 /* MockUnionTemplate.swift */,
E64F7EC027A122300059C021 /* ObjectTemplate.swift */,
DE5FD5FC2769222D0033EE23 /* OperationDefinitionTemplate.swift */,
E6EE62F027DBE6F200627257 /* SchemaModuleNamespaceTemplate.swift */,
Expand All @@ -2340,7 +2350,6 @@
E6B42D0827A472A700A3BD58 /* SwiftPackageManagerModuleTemplate.swift */,
E60AE2ED27E3FC6C003C093A /* TemplateRenderer.swift */,
E64F7EB727A0854E0059C021 /* UnionTemplate.swift */,
DE9CEAEE282C62B700959AF9 /* MockObjectTemplate.swift */,
);
path = Templates;
sourceTree = "<group>";
Expand All @@ -2356,6 +2365,7 @@
E623FD2B2797A700008B4CED /* InterfaceTemplateTests.swift */,
E64F7EC227A1243A0059C021 /* ObjectTemplateTests.swift */,
DE9CEAF0282C632B00959AF9 /* MockObjectTemplateTests.swift */,
E6203347284F25DF00A291D1 /* MockUnionTemplateTests.swift */,
DE6D07FA27BC3BE9009F5F33 /* OperationDefinition_VariableDefinition_Tests.swift */,
DE09F9C5270269F800795949 /* OperationDefinitionTemplate_DocumentType_Tests.swift */,
DE09066E27A4713F00211300 /* OperationDefinitionTemplateTests.swift */,
Expand Down Expand Up @@ -2920,6 +2930,7 @@
E610D8DC278EB1500023E495 /* InterfaceFileGeneratorTests.swift */,
E66F8896276C136B0000BDA8 /* ObjectFileGeneratorTests.swift */,
DE0D38F1282ECF9700AFCC84 /* MockObjectFileGeneratorTests.swift */,
E6203345284F252A00A291D1 /* MockUnionFileGeneratorTests.swift */,
E607AD8D27A88F340026742A /* OperationFileGeneratorTests.swift */,
E6D90D0C278FFE35009CAC5D /* SchemaFileGeneratorTests.swift */,
E6B42D0A27A4746800A3BD58 /* SchemaModuleFileGeneratorTests.swift */,
Expand Down Expand Up @@ -2957,8 +2968,9 @@
DE4D54E827A3518100D26B68 /* FragmentFileGenerator.swift */,
E6D90D06278FA595009CAC5D /* InputObjectFileGenerator.swift */,
E610D8DA278EB0900023E495 /* InterfaceFileGenerator.swift */,
E66F8898276C15580000BDA8 /* ObjectFileGenerator.swift */,
DE0D38EF282ECA6D00AFCC84 /* MockObjectFileGenerator.swift */,
E6203341284F1C9600A291D1 /* MockUnionFileGenerator.swift */,
E66F8898276C15580000BDA8 /* ObjectFileGenerator.swift */,
DE4D54E627A3504B00D26B68 /* OperationFileGenerator.swift */,
E6D90D0A278FFDDA009CAC5D /* SchemaFileGenerator.swift */,
E68D824627A228A80040A46F /* SchemaModuleFileGenerator.swift */,
Expand Down Expand Up @@ -3810,6 +3822,7 @@
E610D8DF278F8F1E0023E495 /* UnionFileGenerator.swift in Sources */,
DEE2DAA227BAF00500EC0607 /* GraphQLType+Rendered.swift in Sources */,
DE223C2D2721FCE8004A0148 /* ScopedSelectionSetHashable.swift in Sources */,
E6203344284F1D1100A291D1 /* MockUnionTemplate.swift in Sources */,
DE79642D27699A6A00978A03 /* IR+NamedFragmentBuilder.swift in Sources */,
9B47518D2575AA850001FB87 /* Pluralizer.swift in Sources */,
E6D90D0B278FFDDA009CAC5D /* SchemaFileGenerator.swift in Sources */,
Expand All @@ -3824,6 +3837,7 @@
E610D8DB278EB0900023E495 /* InterfaceFileGenerator.swift in Sources */,
9B7B6F69233C2C0C00F32205 /* FileManager+Apollo.swift in Sources */,
E674DB41274C0A9B009BB90E /* Glob.swift in Sources */,
E6203342284F1C9600A291D1 /* MockUnionFileGenerator.swift in Sources */,
DE6D07F927BC3B6D009F5F33 /* GraphQLInputField+Rendered.swift in Sources */,
9F1A966C258F34BB00A06EEB /* GraphQLSchema.swift in Sources */,
9BE74D3D23FB4A8E006D354F /* FileFinder.swift in Sources */,
Expand Down Expand Up @@ -3900,7 +3914,9 @@
9B8C3FB5248DA3E000707B13 /* URLExtensionsTests.swift in Sources */,
E64F7EBA27A085D90059C021 /* UnionTemplateTests.swift in Sources */,
E610D8D9278EA2560023E495 /* EnumFileGeneratorTests.swift in Sources */,
E6203348284F25DF00A291D1 /* MockUnionTemplateTests.swift in Sources */,
9FDE0731258F3AA100DC0CA5 /* SchemaLoadingTests.swift in Sources */,
E6203346284F252A00A291D1 /* MockUnionFileGeneratorTests.swift in Sources */,
E6908E55282694630054682B /* ApolloCodegenConfigurationCodableTests.swift in Sources */,
DE223C3327221144004A0148 /* IRMatchers.swift in Sources */,
E64F7EBF27A11B110059C021 /* GraphQLNamedType+SwiftTests.swift in Sources */,
Expand Down
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Change Log

## v1.0.0-alpha.6

This is the sixth Alpha Release of Apollo iOS 1.0. This first major version will include a new code generation engine, better generated models, and many syntax and performance improvements across the entire library. The primary goal of Apollo iOS 1.0 is to stabilize the API of the model layer and provide a foundation for future feature additions and evolution of the library.

* **New: Objects and InputObjects are now equatable:** Many objects now conform to `AnyHashable` bringing with them the ability to conform to `Equatable`, this should make tests easier to write.
* **Change: GraphQLOperation fields are now static:** Previously an instance of a GraphQLOperation was required to query any of it's properties, you can do that on the type now.
* **Fixed - Nested fragment type cases:** Nested fragment type cases were not being generated causing a crash in selection set generation.
* **New - Code generation now has a CLI:** A new command line executable has been built and will be available on Homebrew very soon! Check it out [here](https://github.com/apollographql/apollo-ios/tree/release/1.0/CodegenCLI).
* **Fixed - SelectionSet and InlineFragment protocol definitions:** These were incorrectly being generated within the namespace when a module of type `.embeddedInTarget` was being used.
* **Fixed - Test mock convenience initializers:** These were incorrectly definining parameter types for Interface and Union fields and the generated package could not successfully build.

## v1.0.0-alpha.5

This is the fifth Alpha Release of Apollo iOS 1.0. This first major version will include a new code generation engine, better generated models, and many syntax and performance improvements across the entire library. The primary goal of Apollo iOS 1.0 is to stabilize the API of the model layer and provide a foundation for future feature additions and evolution of the library.
Expand Down
2 changes: 1 addition & 1 deletion Configuration/Shared/Project-Version.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1 @@
CURRENT_PROJECT_VERSION = 1.0.0-alpha.5
CURRENT_PROJECT_VERSION = 1.0.0-alpha.6
2 changes: 1 addition & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ These are the three guiding principles we aim for in each major release:

## 1.0 - _Continuing with Alpha releases_

[Alpha 1 is available](https://github.com/apollographql/apollo-ios/releases/tag/1.0.0-alpha.1), please try it and give us your feedback.
Check out the [latest alpha release](https://github.com/apollographql/apollo-ios/releases), try it and give us your feedback.

These are the major initiatives planned for 1.0/1.x:
- **Swift-based Codegen**: The code generation is being rewritten with a Swift-first approach instead of relying on scripting and Typescript. This will allow easier community contribution to code generation and provide the opportunity to improve various characteristics such as generated code size and performance.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// @generated
// This file was automatically generated and should not be edited.

import ApolloTestSupport
import AnimalKingdomAPI

extension ClassroomPet: MockFieldValue {
public typealias MockValueCollectionType = Array<AnyMock>
}
11 changes: 11 additions & 0 deletions Sources/ApolloCodegenLib/ApolloCodegen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,17 @@ public class ApolloCodegen {
forConfig: config,
fileManager: fileManager
)

if config.output.testMocks != .none {
try MockUnionFileGenerator(
graphqlUnion: graphQLUnion,
ir: ir,
config: config
).generate(
forConfig: config,
fileManager: fileManager
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Foundation
import ApolloUtils

/// Generates a file providing the ability to mock a GraphQLUnionType for testing purposes.
struct MockUnionFileGenerator: FileGenerator {
/// Source GraphQL union.
let graphqlUnion: GraphQLUnionType

let ir: IR

let config: ReferenceWrapped<ApolloCodegenConfiguration>

var template: TemplateRenderer {
MockUnionTemplate(
graphqlUnion: graphqlUnion,
config: config,
ir: ir
)
}

var target: FileTarget { .testMock }
var fileName: String { "\(graphqlUnion.name)+Mock.swift" }
}
24 changes: 24 additions & 0 deletions Sources/ApolloCodegenLib/Templates/MockUnionTemplate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Foundation
import ApolloUtils

struct MockUnionTemplate: TemplateRenderer {
/// IR representation of source [GraphQL Union](https://spec.graphql.org/draft/#sec-Unions).
let graphqlUnion: GraphQLUnionType

/// Shared codegen configuration.
let config: ReferenceWrapped<ApolloCodegenConfiguration>

let ir: IR

let target: TemplateTarget = .testMockFile

var template: TemplateString {
TemplateString("""
extension \
\(if: !config.output.schemaTypes.isInModule, "\(ir.schema.name.firstUppercased).")\
\(graphqlUnion.name.firstUppercased): MockFieldValue {
public typealias MockValueCollectionType = Array<AnyMock>
}
""")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,30 @@ struct SwiftPackageManagerModuleTemplate: TemplateRenderer {
let headerTemplate: TemplateString? = nil

var template: TemplateString {
TemplateString("""
let casedModuleName = moduleName.firstUppercased

return TemplateString("""
// swift-tools-version:5.3

import PackageDescription

let package = Package(
name: "\(moduleName.firstUppercased)",
name: "\(casedModuleName)",
platforms: [
.iOS(.v12),
.macOS(.v10_14),
.tvOS(.v12),
.watchOS(.v5),
],
products: [
.library(name: "\(moduleName.firstUppercased)", targets: ["\(moduleName.firstUppercased)"]),
.library(name: "\(casedModuleName)", targets: ["\(casedModuleName)"]),
],
dependencies: [
.package(url: "https://github.com/apollographql/apollo-ios.git", from: "1.0.0-alpha.5"),
.package(url: "https://github.com/apollographql/apollo-ios.git", from: "1.0.0-alpha.6"),
],
targets: [
.target(
name: "\(moduleName.firstUppercased)",
name: "\(casedModuleName)",
dependencies: [
.product(name: "ApolloAPI", package: "apollo-ios"),
],
Expand All @@ -45,6 +47,7 @@ struct SwiftPackageManagerModuleTemplate: TemplateRenderer {
name: "\($0.targetName)",
dependencies: [
.product(name: "ApolloTestSupport", package: "apollo-ios"),
.target(name: "\(casedModuleName)"),
],
path: "\($0.path)"
),
Expand Down
1 change: 1 addition & 0 deletions Tests/ApolloCodegenTests/ApolloCodegenTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,7 @@ class ApolloCodegenTests: XCTestCase {
directoryURL.appendingPathComponent("TestMocks/Dog+Mock.swift").path,
directoryURL.appendingPathComponent("TestMocks/Fish+Mock.swift").path,
directoryURL.appendingPathComponent("TestMocks/Crocodile+Mock.swift").path,
directoryURL.appendingPathComponent("TestMocks/ClassroomPet+Mock.swift").path,
]

// when
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import XCTest
import Nimble
@testable import ApolloCodegenLib
import ApolloUtils

class MockUnionFileGeneratorTests: XCTestCase {
let graphqlUnion = GraphQLUnionType.mock("MockUnion", types: [])

var subject: MockUnionFileGenerator!

override func tearDown() {
subject = nil
}

// MARK: Test Helpers

private func buildSubject() {
subject = MockUnionFileGenerator(
graphqlUnion: graphqlUnion,
ir: .mock(compilationResult: .mock()),
config: ReferenceWrapped(value: .mock(.other))
)
}

// MARK: Property Tests

func test__properties__shouldReturnTargetType_testMock() {
// given
buildSubject()

// then
expect(self.subject.target).to(equal(.testMock))
}

func test__properties__givenGraphQLUnion_shouldReturnFileName_matchingUnionName() {
// given
buildSubject()

let expected = "\(graphqlUnion.name)+Mock.swift"

// then
expect(self.subject.fileName).to(equal(expected))
}

func test__properties__givenGraphQLUnion_shouldOverwrite() {
// given
buildSubject()

// then
expect(self.subject.overwrite).to(beTrue())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import XCTest
import Nimble
@testable import ApolloCodegenLib
import ApolloCodegenInternalTestHelpers
import ApolloUtils

class MockUnionTemplateTests: XCTestCase {
var ir: IR!
var subject: MockUnionTemplate!

override func tearDown() {
subject = nil

super.tearDown()
}

// MARK: Helpers

private func buildSubject(
name: String = "Pet",
types: [GraphQLObjectType] = [],
moduleType: ApolloCodegenConfiguration.SchemaTypesFileOutput.ModuleType = .swiftPackageManager
) {
let config = ApolloCodegenConfiguration.mock(moduleType)
ir = IR.mock(compilationResult: .mock())

subject = MockUnionTemplate(
graphqlUnion: GraphQLUnionType.mock(name, types: types),
config: ReferenceWrapped(value: config),
ir: ir
)
}

private func renderSubject() -> String {
subject.template.description
}

// MARK: Boilerplate tests

func test__target__isTestMockFile() {
buildSubject()

expect(self.subject.target).to(equal(.testMockFile))
}

func test_render_givenSchemaType_generatesExtensionWithTypealias() {
// given
buildSubject(name: "Pet")

let expected = """
extension Pet: MockFieldValue {
public typealias MockValueCollectionType = Array<AnyMock>
}
"""

// when
let actual = renderSubject()

// then
expect(actual).to(equalLineByLine(expected))
}

func test_render_givenConfig_SchemaTypeOutputNone_generatesExtensionWithSchemaNamespace() {
// given
buildSubject(name: "Pet", moduleType: .embeddedInTarget(name: "MockApplication"))

let expected = """
extension TestSchema.Pet: MockFieldValue {
"""

// when
let actual = renderSubject()

// then
expect(actual).to(equalLineByLine(expected, ignoringExtraLines: true))
}
}
Loading