diff --git a/Sources/ApolloCodegenLib/Templates/MockObjectTemplate.swift b/Sources/ApolloCodegenLib/Templates/MockObjectTemplate.swift index cb8d1dd56..61ff93560 100644 --- a/Sources/ApolloCodegenLib/Templates/MockObjectTemplate.swift +++ b/Sources/ApolloCodegenLib/Templates/MockObjectTemplate.swift @@ -76,6 +76,8 @@ struct MockObjectTemplate: TemplateRenderer { private func mockFunctionDescriptor(_ graphQLType: GraphQLType) -> String { switch graphQLType { + case .list(.nonNull(.scalar(_))): + return "ScalarList" case .list(_): return "List" case .scalar(_), .enum(_): @@ -95,7 +97,7 @@ struct MockObjectTemplate: TemplateRenderer { \(if: $0.propertyName.isConflictingTestMockFieldName, """ var \($0.propertyName): \($0.mockType)? { get { _data["\($0.propertyName)"] as? \($0.mockType) } - set { _set(newValue, for: \\.\($0.propertyName)) } + set { _set\(mockFunctionDescriptor($0.type))(newValue, for: \\.\($0.propertyName)) } } """) """ }, separator: "\n", terminator: "\n") diff --git a/Sources/ApolloTestSupport/TestMock.swift b/Sources/ApolloTestSupport/TestMock.swift index 656af374a..8211a3736 100644 --- a/Sources/ApolloTestSupport/TestMock.swift +++ b/Sources/ApolloTestSupport/TestMock.swift @@ -75,6 +75,26 @@ public class Mock: AnyMock, Hashable { _data[field.key.description] = value?._unsafelyConvertToMockValue() } + public subscript( + dynamicMember keyPath: KeyPath>> + ) -> [T]? { + get { + let field = O._mockFields[keyPath: keyPath] + return _data[field.key.description] as? [T] + } + set { + _setScalarList(newValue, for: keyPath) + } + } + + public func _setScalarList( + _ value: [T]?, + for keyPath: KeyPath>> + ) { + let field = O._mockFields[keyPath: keyPath] + _data[field.key.description] = value?._unsafelyConvertToMockValue() + } + public var _selectionSetMockData: JSONObject { _data.mapValues { if let mock = $0 as? AnyMock { diff --git a/Tests/ApolloCodegenTests/CodeGeneration/Templates/MockObjectTemplateTests.swift b/Tests/ApolloCodegenTests/CodeGeneration/Templates/MockObjectTemplateTests.swift index 182a73f00..a25db3341 100644 --- a/Tests/ApolloCodegenTests/CodeGeneration/Templates/MockObjectTemplateTests.swift +++ b/Tests/ApolloCodegenTests/CodeGeneration/Templates/MockObjectTemplateTests.swift @@ -462,7 +462,7 @@ class MockObjectTemplateTests: XCTestCase { let expected = """ var hash: String? { get { _data["hash"] as? String } - set { _set(newValue, for: \\.hash) } + set { _setScalar(newValue, for: \\.hash) } } """ @@ -487,6 +487,7 @@ class MockObjectTemplateTests: XCTestCase { subject.graphqlObject.fields = [ "string": .mock("string", type: .nonNull(.string())), "customScalar": .mock("customScalar", type: .nonNull(.scalar(.mock(name: "CustomScalar")))), + "customScalarList": .mock("customScalarList", type: .list(.nonNull(.scalar(.mock(name: "CustomScalar"))))), "optionalString": .mock("optionalString", type: .string()), "object": .mock("object", type: Cat), "objectList": .mock("objectList", type: .list(.nonNull(Cat))), @@ -516,6 +517,7 @@ class MockObjectTemplateTests: XCTestCase { public extension Mock where O == Dog { convenience init( customScalar: TestSchema.CustomScalar? = nil, + customScalarList: [TestSchema.CustomScalar]? = nil, enumType: GraphQLEnum? = nil, interface: AnyMock? = nil, interfaceList: [AnyMock]? = nil, @@ -534,6 +536,7 @@ class MockObjectTemplateTests: XCTestCase { ) { self.init() _setScalar(customScalar, for: \\.customScalar) + _setScalarList(customScalarList, for: \\.customScalarList) _setScalar(enumType, for: \\.enumType) _setEntity(interface, for: \\.interface) _setList(interfaceList, for: \\.interfaceList) diff --git a/Tests/CodegenIntegrationTests/Tests/3120-listOfCustomScalarsNeedsSetScalarList/README.MD b/Tests/CodegenIntegrationTests/Tests/3120-listOfCustomScalarsNeedsSetScalarList/README.MD new file mode 100644 index 000000000..6b46dc939 --- /dev/null +++ b/Tests/CodegenIntegrationTests/Tests/3120-listOfCustomScalarsNeedsSetScalarList/README.MD @@ -0,0 +1,10 @@ +# Overview + +When a field has a list type containing custom scalars, the generated initializer for mock objects should use a version of the `_set` function that is appropriate for that type. +Previously, the `_setList` function was used for all lists of objects, even if it would not compile since custom scalars do not conform to `GraphQLField`. + +## Reference Issue: https://github.com/apollographql/apollo-ios/pull/3120 + +## Solution + +All properties that are lists of scalars should use the `_setScalarList` function when initialized inside mock objects. diff --git a/Tests/CodegenIntegrationTests/Tests/3120-listOfCustomScalarsNeedsSetScalarList/operation.graphql b/Tests/CodegenIntegrationTests/Tests/3120-listOfCustomScalarsNeedsSetScalarList/operation.graphql new file mode 100644 index 000000000..f45ed1954 --- /dev/null +++ b/Tests/CodegenIntegrationTests/Tests/3120-listOfCustomScalarsNeedsSetScalarList/operation.graphql @@ -0,0 +1,6 @@ +query TestMeWithMocks { + testMeWithMocks { + scalarList + nullableScalarList + } +} diff --git a/Tests/CodegenIntegrationTests/Tests/3120-listOfCustomScalarsNeedsSetScalarList/schema.graphqls b/Tests/CodegenIntegrationTests/Tests/3120-listOfCustomScalarsNeedsSetScalarList/schema.graphqls new file mode 100644 index 000000000..d996243cd --- /dev/null +++ b/Tests/CodegenIntegrationTests/Tests/3120-listOfCustomScalarsNeedsSetScalarList/schema.graphqls @@ -0,0 +1,10 @@ +type Query { + testMeWithMocks: Event! +} + +type Event { + scalarList: [Text!]! + nullableScalarList: [Text]! +} + +scalar Text