diff --git a/Sources/ApolloCodegenLib/Frontend/GraphQLSchema.swift b/Sources/ApolloCodegenLib/Frontend/GraphQLSchema.swift index 224652a56e..da673b5068 100644 --- a/Sources/ApolloCodegenLib/Frontend/GraphQLSchema.swift +++ b/Sources/ApolloCodegenLib/Frontend/GraphQLSchema.swift @@ -31,6 +31,10 @@ public class GraphQLSchema: JavaScriptObject { public class GraphQLNamedType: JavaScriptObject, Hashable { lazy var name: String = self["name"] + + var formattedName: String { + swiftName + } lazy var documentation: String? = self["description"] @@ -66,10 +70,26 @@ public class GraphQLScalarType: GraphQLNamedType { return false } } + + override var formattedName: String { + if !isCustomScalar { + return swiftName + } + + let uppercasedName = swiftName.firstUppercased + return SwiftKeywords.TypeNamesToSuffix.contains(uppercasedName) ? + "\(uppercasedName)_Scalar" : uppercasedName + } } public class GraphQLEnumType: GraphQLNamedType { lazy var values: [GraphQLEnumValue] = try! invokeMethod("getValues") + + override var formattedName: String { + let uppercasedName = swiftName.firstUppercased + return SwiftKeywords.TypeNamesToSuffix.contains(uppercasedName) ? + "\(uppercasedName)_Enum" : uppercasedName + } } public class GraphQLEnumValue: JavaScriptObject { @@ -91,6 +111,12 @@ typealias GraphQLInputFieldDictionary = OrderedDictionary = [ + static let TypeNamesToSuffix: Set = [ "Any", "DataDict", "DocumentType", @@ -72,6 +78,7 @@ enum SwiftKeywords { "Double", "ID", "Type", + "Error", "_", ] diff --git a/Sources/ApolloCodegenLib/Templates/SchemaMetadataTemplate.swift b/Sources/ApolloCodegenLib/Templates/SchemaMetadataTemplate.swift index 67e23eda3f..ef3db1a3b6 100644 --- a/Sources/ApolloCodegenLib/Templates/SchemaMetadataTemplate.swift +++ b/Sources/ApolloCodegenLib/Templates/SchemaMetadataTemplate.swift @@ -56,7 +56,7 @@ struct SchemaMetadataTemplate: TemplateRenderer { static func objectType(forTypename typename: String) -> Object? { switch typename { \(schema.referencedTypes.objects.map { - "case \"\($0.name)\": return \(schemaNamespace).Objects.\($0.name.firstUppercased)" + "case \"\($0.name)\": return \(schemaNamespace).Objects.\($0.formattedName)" }, separator: "\n") default: return nil } diff --git a/Sources/ApolloCodegenLib/Templates/SelectionSetTemplate.swift b/Sources/ApolloCodegenLib/Templates/SelectionSetTemplate.swift index 6b962bfd8c..d8db150e6b 100644 --- a/Sources/ApolloCodegenLib/Templates/SelectionSetTemplate.swift +++ b/Sources/ApolloCodegenLib/Templates/SelectionSetTemplate.swift @@ -84,7 +84,7 @@ struct SelectionSetTemplate { pluralizer: config.pluralizer)) \(if: config.options.schemaDocumentation == .include, """ /// - /// Parent Type: `\(selectionSet.parentType.name.firstUppercased)` + /// Parent Type: `\(selectionSet.parentType.formattedName)` """) """ } @@ -162,7 +162,7 @@ struct SelectionSetTemplate { } private func GeneratedSchemaTypeReference(_ type: GraphQLCompositeType) -> TemplateString { - "\(config.schemaNamespace.firstUppercased).\(type.schemaTypesNamespace).\(type.name.firstUppercased)" + "\(config.schemaNamespace.firstUppercased).\(type.schemaTypesNamespace).\(type.formattedName)" } // MARK: - Selections @@ -285,7 +285,7 @@ struct SelectionSetTemplate { private func FragmentSelectionTemplate(_ fragment: IR.FragmentSpread) -> TemplateString { """ - .fragment(\(fragment.definition.name.firstUppercased).self) + .fragment(\(fragment.definition.name.asFragmentName).self) """ } @@ -380,7 +380,7 @@ struct SelectionSetTemplate { ) -> TemplateString { let name = fragment.definition.name let propertyName = name.firstLowercased - let typeName = name.firstUppercased + let typeName = name.asFragmentName let isOptional = fragment.inclusionConditions != nil && !scope.matches(fragment.inclusionConditions.unsafelyUnwrapped) @@ -505,7 +505,7 @@ struct SelectionSetTemplate { !selectionSet.typeInfo.scope.matches(conditions) { continue } - fulfilledFragments.append(fragment.definition.name.firstUppercased) + fulfilledFragments.append(fragment.definition.name.asFragmentName) } return """ @@ -838,7 +838,7 @@ fileprivate extension IR.ScopeCondition { var selectionSetNameComponent: String { return TemplateString(""" - \(ifLet: type, { "As\($0.name.firstUppercased)" })\ + \(ifLet: type, { "As\($0.formattedName)" })\ \(ifLet: conditions, { "If\($0.typeNameComponents)"}) """).description } diff --git a/Sources/ApolloCodegenLib/Templates/UnionTemplate.swift b/Sources/ApolloCodegenLib/Templates/UnionTemplate.swift index 2681152983..d1476b31ab 100644 --- a/Sources/ApolloCodegenLib/Templates/UnionTemplate.swift +++ b/Sources/ApolloCodegenLib/Templates/UnionTemplate.swift @@ -14,7 +14,7 @@ struct UnionTemplate: TemplateRenderer { TemplateString( """ \(documentation: graphqlUnion.documentation, config: config) - static let \(graphqlUnion.name.firstUppercased) = Union( + static let \(graphqlUnion.formattedName) = Union( name: "\(graphqlUnion.name)", possibleTypes: \(PossibleTypesTemplate()) ) @@ -31,7 +31,7 @@ struct UnionTemplate: TemplateRenderer { ) -> TemplateString { """ \(if: !config.output.schemaTypes.isInModule, "\(config.schemaNamespace.firstUppercased).")\ - Objects.\(type.name.firstUppercased).self + Objects.\(type.formattedName).self """ } diff --git a/Tests/ApolloCodegenTests/CodeGeneration/FileGenerators/EnumFileGeneratorTests.swift b/Tests/ApolloCodegenTests/CodeGeneration/FileGenerators/EnumFileGeneratorTests.swift index 2d399826b3..9fdb0c1867 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/FileGenerators/EnumFileGeneratorTests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/FileGenerators/EnumFileGeneratorTests.swift @@ -34,7 +34,7 @@ class EnumFileGeneratorTests: XCTestCase { // given buildSubject() - let expected = graphqlEnum.name.firstUppercased + let expected = graphqlEnum.formattedName // then expect(self.subject.fileName).to(equal(expected)) diff --git a/Tests/ApolloCodegenTests/CodeGeneration/Templates/CustomScalarTemplateTests.swift b/Tests/ApolloCodegenTests/CodeGeneration/Templates/CustomScalarTemplateTests.swift index cd4476ae90..394a0216ac 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/Templates/CustomScalarTemplateTests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/Templates/CustomScalarTemplateTests.swift @@ -214,4 +214,27 @@ class CustomScalarTemplateTests: XCTestCase { // then expect(rendered).to(equalLineByLine(expected)) } + + // MARK: - Reserved Keyword Tests + + func test__render__givenCustomScalar_usingReservedKeyword_shouldRenderAsEscaped() throws { + let keywords = ["Type", "type"] + + keywords.forEach { keyword in + // given + buildSubject(name: keyword) + + let expected = """ + typealias \(keyword.firstUppercased)_Scalar = String + + """ + + // when + let rendered = renderSubject() + + // then + expect(rendered).to(equalLineByLine(expected)) + } + } + } diff --git a/Tests/ApolloCodegenTests/CodeGeneration/Templates/EnumTemplateTests.swift b/Tests/ApolloCodegenTests/CodeGeneration/Templates/EnumTemplateTests.swift index af3c7db96a..24b7d44fad 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/Templates/EnumTemplateTests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/Templates/EnumTemplateTests.swift @@ -461,4 +461,26 @@ class EnumTemplateTests: XCTestCase { // then expect(rendered).to(equalLineByLine(expected)) } + + // MARK: - Reserved Keyword Tests + + func test_render_givenReservedKeywordType_AsEscapedType() { + let keywords = ["Type", "type"] + + keywords.forEach { keyword in + // given + buildSubject(name: keyword) + + let expected = """ + enum \(keyword.firstUppercased)_Enum: String, EnumType { + """ + + // when + let actual = renderSubject() + + // then + expect(actual).to(equalLineByLine(expected, ignoringExtraLines: true)) + } + } + } diff --git a/Tests/ApolloCodegenTests/CodeGeneration/Templates/FragmentTemplateTests.swift b/Tests/ApolloCodegenTests/CodeGeneration/Templates/FragmentTemplateTests.swift index 63fa453245..bc2b76ce62 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/Templates/FragmentTemplateTests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/Templates/FragmentTemplateTests.swift @@ -723,4 +723,42 @@ class FragmentTemplateTests: XCTestCase { expect(actual).to(equalLineByLine(expected, ignoringExtraLines: true)) } + + // MARK: - Reserved Keyword Tests + + func test__render__givenFragmentReservedKeywordName_rendersEscapedName() throws { + let keywords = ["Type", "type"] + + try keywords.forEach { keyword in + // given + schemaSDL = """ + type Query { + getUser(id: String): User + } + + type User { + id: String! + name: String! + } + """ + + document = """ + fragment \(keyword) on User { + name + } + """ + + let expected = """ + struct \(keyword.firstUppercased)_Fragment: TestSchema.SelectionSet, Fragment { + """ + + // when + try buildSubjectAndFragment(named: keyword) + let actual = renderSubject() + + // then + expect(actual).to(equalLineByLine(expected, ignoringExtraLines: true)) + } + } + } diff --git a/Tests/ApolloCodegenTests/CodeGeneration/Templates/InputObjectTemplateTests.swift b/Tests/ApolloCodegenTests/CodeGeneration/Templates/InputObjectTemplateTests.swift index fc4a9dd90b..72c26fc43d 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/Templates/InputObjectTemplateTests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/Templates/InputObjectTemplateTests.swift @@ -2438,4 +2438,34 @@ class InputObjectTemplateTests: XCTestCase { // then expect(actual).to(equalLineByLine(expected, atLine: 8, ignoringExtraLines: true)) } + + // MARK: - Reserved Keyword Tests + + func test__render__generatesInputObject_usingReservedKeyword_asEscapedType() throws { + let keywords = ["Type", "type"] + + keywords.forEach { keyword in + // given + buildSubject( + name: keyword, + fields: [GraphQLInputField.mock("field", type: .scalar(.integer()), defaultValue: nil)] + ) + + let expected = """ + public struct \(keyword.firstUppercased)_InputObject: InputObject { + public private(set) var __data: InputDict + + public init(_ data: InputDict) { + __data = data + } + """ + + // when + let actual = renderSubject() + + // then + expect(actual).to(equalLineByLine(expected, ignoringExtraLines: true)) + } + } + } diff --git a/Tests/ApolloCodegenTests/CodeGeneration/Templates/InterfaceTemplateTests.swift b/Tests/ApolloCodegenTests/CodeGeneration/Templates/InterfaceTemplateTests.swift index 1c0091a738..f5483ae635 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/Templates/InterfaceTemplateTests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/Templates/InterfaceTemplateTests.swift @@ -92,4 +92,26 @@ class InterfaceTemplateTests: XCTestCase { // then expect(rendered).to(equalLineByLine(expected, ignoringExtraLines: true)) } + + // MARK: - Reserved Keyword Tests + + func test_render_givenSchemaInterfaceUsingReservedKeyword_generatesWithEscapedType() throws { + let keywords = ["Type", "type"] + + keywords.forEach { keyword in + // given + buildSubject(name: keyword) + + let expected = """ + static let \(keyword.firstUppercased)_Interface = Interface(name: "\(keyword)") + """ + + // when + let actual = renderSubject() + + // then + expect(actual).to(equalLineByLine(expected)) + } + } + } diff --git a/Tests/ApolloCodegenTests/CodeGeneration/Templates/MockInterfacesTemplateTests.swift b/Tests/ApolloCodegenTests/CodeGeneration/Templates/MockInterfacesTemplateTests.swift index 0b7c2f94be..9a626286af 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/Templates/MockInterfacesTemplateTests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/Templates/MockInterfacesTemplateTests.swift @@ -136,4 +136,29 @@ class MockInterfacesTemplateTests: XCTestCase { // then expect(actual).to(equalLineByLine(expected, ignoringExtraLines: true)) } + + // MARK: - Reserved Keyword Tests + + func test__render__usingReservedKeyword__generatesTypeWithSuffix() { + let keywords = ["Type", "type"] + + keywords.forEach { keyword in + // given + let interface = GraphQLInterfaceType.mock(keyword) + buildSubject(interfaces: [interface]) + + let expected = """ + public extension MockObject { + typealias \(keyword.firstUppercased)_Interface = Interface + } + """ + + // when + let actual = renderSubject() + + // then + expect(actual).to(equalLineByLine(expected, ignoringExtraLines: true)) + } + } + } diff --git a/Tests/ApolloCodegenTests/CodeGeneration/Templates/MockObjectTemplateTests.swift b/Tests/ApolloCodegenTests/CodeGeneration/Templates/MockObjectTemplateTests.swift index 7dac93919e..d3f8638fde 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/Templates/MockObjectTemplateTests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/Templates/MockObjectTemplateTests.swift @@ -951,5 +951,53 @@ class MockObjectTemplateTests: XCTestCase { // then expect(actual).to(equalLineByLine(expected, atLine: 6, ignoringExtraLines: true)) } + + // MARK: - Reserved Keyword Tests + + func test__render__givenObjectUsingReservedKeyword_generatesTypeWithSuffix() { + let keywords = ["Type", "type"] + + keywords.forEach { keyword in + // given + buildSubject(name: keyword, moduleType: .swiftPackageManager) + + subject.graphqlObject.fields = [ + "name": .mock("string", type: .nonNull(.string())), + ] + + ir.fieldCollector.add( + fields: subject.graphqlObject.fields.values.map { + .mock($0.name, type: $0.type) + }, + to: subject.graphqlObject + ) + + let expected = """ + public class \(keyword.firstUppercased)_Object: MockObject { + public static let objectType: Object = TestSchema.Objects.\(keyword.firstUppercased)_Object + public static let _mockFields = MockFields() + public typealias MockValueCollectionType = Array> + + public struct MockFields { + @Field("string") public var string + } + } + + public extension Mock where O == \(keyword.firstUppercased)_Object { + convenience init( + string: String? = nil + ) { + self.init() + _set(string, for: \\.string) + } + } + """ + // when + let actual = renderSubject() + + // then + expect(actual).to(equalLineByLine(expected, ignoringExtraLines: true)) + } + } } diff --git a/Tests/ApolloCodegenTests/CodeGeneration/Templates/MockUnionsTemplateTests.swift b/Tests/ApolloCodegenTests/CodeGeneration/Templates/MockUnionsTemplateTests.swift index 2e44fb7b1c..0392a165e2 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/Templates/MockUnionsTemplateTests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/Templates/MockUnionsTemplateTests.swift @@ -133,4 +133,29 @@ class MockUnionsTemplateTests: XCTestCase { // then expect(actual).to(equalLineByLine(expected, ignoringExtraLines: true)) } + + // MARK: - Reserved Keyword Tests + + func test__render__usingReservedKeyword__generatesTypeWithSuffix() { + let keywords = ["Type", "type"] + + keywords.forEach { keyword in + // given + let union = GraphQLUnionType.mock(keyword) + buildSubject(unions: [union]) + + let expected = """ + public extension MockObject { + typealias \(keyword.firstUppercased)_Union = Union + } + """ + + // when + let actual = renderSubject() + + // then + expect(actual).to(equalLineByLine(expected, ignoringExtraLines: true)) + } + } + } diff --git a/Tests/ApolloCodegenTests/CodeGeneration/Templates/ObjectTemplateTests.swift b/Tests/ApolloCodegenTests/CodeGeneration/Templates/ObjectTemplateTests.swift index daae18e9c7..4cbfcc6a90 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/Templates/ObjectTemplateTests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/Templates/ObjectTemplateTests.swift @@ -169,4 +169,26 @@ class ObjectTemplateTests: XCTestCase { expect(rendered).to(equalLineByLine(expected, ignoringExtraLines: true)) } + // MARK: - Reserved Keyword Tests + + func test_render_usingReservedKeyword_shouldHaveSuffixedType() { + let keywords = ["Type", "type"] + + keywords.forEach { keyword in + // given + buildSubject(name: keyword) + + let expected = """ + static let \(keyword.firstUppercased)_Object = Object( + typename: "\(keyword)", + """ + + // when + let actual = renderSubject() + + // then + expect(actual).to(equalLineByLine(expected, ignoringExtraLines: true)) + } + } + } diff --git a/Tests/ApolloCodegenTests/CodeGeneration/Templates/OperationDefinitionTemplateTests.swift b/Tests/ApolloCodegenTests/CodeGeneration/Templates/OperationDefinitionTemplateTests.swift index a65ccf27c2..4bbf16c194 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/Templates/OperationDefinitionTemplateTests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/Templates/OperationDefinitionTemplateTests.swift @@ -933,4 +933,50 @@ class OperationDefinitionTemplateTests: XCTestCase { // then expect(actual).to(equalLineByLine(expected, atLine: 15, ignoringExtraLines: true)) } + + // MARK: - Reserved Keyword Tests + + func test__generate__givenInputObjectUsingReservedKeyword_rendersAsEscapedType() throws { + // given + schemaSDL = """ + input Type { + id: String! + } + + type Query { + getUser(type: Type!): User + } + + type User { + id: String! + name: String! + role: String! + } + """ + + document = """ + query TestOperation($type: Type!) { + getUser(type: $type) { + name + } + } + """ + + let expectedOne = """ + public var type: Type_InputObject + """ + + let expectedTwo = """ + public init(type: Type_InputObject) { + """ + + // when + try buildSubjectAndOperation() + let actual = renderSubject() + + // then + expect(actual).to(equalLineByLine(expectedOne, atLine: 15, ignoringExtraLines: true)) + expect(actual).to(equalLineByLine(expectedTwo, atLine: 17, ignoringExtraLines: true)) + } + } diff --git a/Tests/ApolloCodegenTests/CodeGeneration/Templates/SelectionSet/SelectionSetTemplateTests.swift b/Tests/ApolloCodegenTests/CodeGeneration/Templates/SelectionSet/SelectionSetTemplateTests.swift index 6499e5482a..f1f0630552 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/Templates/SelectionSet/SelectionSetTemplateTests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/Templates/SelectionSet/SelectionSetTemplateTests.swift @@ -5776,7 +5776,7 @@ class SelectionSetTemplateTests: XCTestCase { // MARK: Nested Selection Sets - Reserved Keywords + Special Names func test__render_nestedSelectionSet__givenEntityFieldWithSwiftKeywordAndApolloReservedTypeNames_rendersSelectionSetWithNameSuffixed() throws { - let fieldNames = SwiftKeywords.SelectionSetTypeNamesToSuffix + let fieldNames = SwiftKeywords.TypeNamesToSuffix for fieldName in fieldNames { // given schemaSDL = """ @@ -6625,4 +6625,280 @@ class SelectionSetTemplateTests: XCTestCase { // then expect(actual).to(equalLineByLine(expected, atLine: 7, ignoringExtraLines: true)) } + + // MARK: - Reserved Keyword Type Tests + + func test__render_enumType__usingReservedKeyword_rendersAsSuffixedType() throws { + // given + schemaSDL = """ + type Query { + getUser: User + } + + type User { + id: String! + name: String! + type: Type! + } + + enum Type { + ADMIN + MEMBER + } + """ + + document = """ + query TestOperation { + getUser { + type + } + } + """ + + let expectedOne = """ + .field("type", GraphQLEnum.self), + """ + + let expectedTwo = """ + public var type: GraphQLEnum { __data["type"] } + """ + + // when + try buildSubjectAndOperation() + let user = try XCTUnwrap( + operation[field: "query"]?[field: "getUser"] as? IR.EntityField + ) + + let actual = subject.render(field: user) + + // then + expect(actual).to(equalLineByLine(expectedOne, atLine: 9, ignoringExtraLines: true)) + expect(actual).to(equalLineByLine(expectedTwo, atLine: 12, ignoringExtraLines: true)) + } + + func test__render_NamedFragmentType__usingReservedKeyword_rendersAsSuffixedType() throws { + // given + schemaSDL = """ + type Query { + getUser: User + } + + type User { + id: String! + name: String! + type: UserRole! + } + + enum UserRole { + ADMIN + MEMBER + } + """ + + document = """ + query TestOperation { + getUser { + ...Type + } + } + + fragment Type on User { + name + type + } + """ + + let expectedOne = """ + .fragment(Type_Fragment.self), + """ + + let expectedTwo = """ + public var type: Type_Fragment { _toFragment() } + """ + + // when + try buildSubjectAndOperation() + let user = try XCTUnwrap( + operation[field: "query"]?[field: "getUser"] as? IR.EntityField + ) + + let actual = subject.render(field: user) + + // then + expect(actual).to(equalLineByLine(expectedOne, atLine: 9, ignoringExtraLines: true)) + expect(actual).to(equalLineByLine(expectedTwo, atLine: 19, ignoringExtraLines: true)) + } + + func test__render_CustomScalarType__usingReservedKeyword_rendersAsSuffixedType() throws { + // given + schemaSDL = """ + scalar Type + + type Query { + getUser: User + } + + type User { + id: String! + name: String! + type: Type! + } + """ + + document = """ + query TestOperation { + getUser { + type + } + } + """ + + let expectedOne = """ + .field("type", TestSchema.Type_Scalar.self), + """ + + let expectedTwo = """ + public var type: TestSchema.Type_Scalar { __data["type"] } + """ + + // when + try buildSubjectAndOperation() + let user = try XCTUnwrap( + operation[field: "query"]?[field: "getUser"] as? IR.EntityField + ) + + let actual = subject.render(field: user) + + // then + expect(actual).to(equalLineByLine(expectedOne, atLine: 9, ignoringExtraLines: true)) + expect(actual).to(equalLineByLine(expectedTwo, atLine: 12, ignoringExtraLines: true)) + } + + func test__render_InterfaceType__usingReservedKeyword_rendersAsSuffixedType() throws { + // given + schemaSDL = """ + interface Type { + name: String! + } + + type Query { + getUser: Type + } + + type User implements Type { + id: String! + } + """ + + document = """ + query TestOperation { + getUser { + name + } + } + """ + + let expected = """ + public static var __parentType: ApolloAPI.ParentType { TestSchema.Interfaces.Type_Interface } + """ + + // when + try buildSubjectAndOperation() + let user = try XCTUnwrap( + operation[field: "query"]?[field: "getUser"] as? IR.EntityField + ) + + let actual = subject.render(field: user) + + // then + expect(actual).to(equalLineByLine(expected, atLine: 6, ignoringExtraLines: true)) + } + + func test__render_UnionType__usingReservedKeyword_rendersAsSuffixedType() throws { + // given + schemaSDL = """ + union Type = User | Admin + + type Query { + getUser: Type + } + + type User { + id: String! + name: String! + } + + type Admin { + id: String! + role: String! + } + """ + + document = """ + query TestOperation { + getUser { + ... on User { + name + } + ... on Admin { + role + } + } + } + + """ + + let expected = """ + public static var __parentType: ApolloAPI.ParentType { TestSchema.Unions.Type_Union } + """ + + // when + try buildSubjectAndOperation() + let user = try XCTUnwrap( + operation[field: "query"]?[field: "getUser"] as? IR.EntityField + ) + + let actual = subject.render(field: user) + + // then + expect(actual).to(equalLineByLine(expected, atLine: 6, ignoringExtraLines: true)) + } + + func test__render_ObjectType__usingReservedKeyword_rendersAsSuffixedType() throws { + // given + schemaSDL = """ + type Query { + getType: Type + } + + type Type { + id: String! + name: String! + } + """ + + document = """ + query TestOperation { + getType { + name + } + } + """ + + let expected = """ + public static var __parentType: ApolloAPI.ParentType { TestSchema.Objects.Type_Object } + """ + + // when + try buildSubjectAndOperation() + let user = try XCTUnwrap( + operation[field: "query"]?[field: "getType"] as? IR.EntityField + ) + + let actual = subject.render(field: user) + + // then + expect(actual).to(equalLineByLine(expected, atLine: 6, ignoringExtraLines: true)) + } + } diff --git a/Tests/ApolloCodegenTests/CodeGeneration/Templates/UnionTemplateTests.swift b/Tests/ApolloCodegenTests/CodeGeneration/Templates/UnionTemplateTests.swift index accaf78cdd..900087b9e5 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/Templates/UnionTemplateTests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/Templates/UnionTemplateTests.swift @@ -257,4 +257,27 @@ class UnionTemplateTests: XCTestCase { // then expect(actual).to(equalLineByLine(expected, ignoringExtraLines: true)) } + + // MARK: - Reserved Keyword Tests + + func test_render_usingReservedKeyword_shouldHaveSuffixedType() throws { + let keywords = ["Type", "type"] + + keywords.forEach { keyword in + // given + buildSubject(name: keyword) + + let expected = """ + static let \(keyword.firstUppercased)_Union = Union( + name: "\(keyword)", + """ + + // when + let actual = renderSubject() + + // then + expect(actual).to(equalLineByLine(expected, ignoringExtraLines: true)) + } + } + }