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

Mock that contains an array of Union type crashes on access #3023

Closed
jabeattie opened this issue May 17, 2023 · 8 comments · Fixed by #3089
Closed

Mock that contains an array of Union type crashes on access #3023

jabeattie opened this issue May 17, 2023 · 8 comments · Fixed by #3089
Assignees
Labels
bug Generally incorrect behavior

Comments

@jabeattie
Copy link

Summary

Hey folks,

I'm unsure if this is a problem of us "holding it wrong" or something that is an issue, so we appreciate any comments or advice.

We have an issue where after migrating from version 1.1.2 to 1.2.0 of Apollo, we see crashes when accessing specific values on mocks.

These crashes always occur when accessing properties that have a type that is an array of a union type. We do not see similar crashes when accessing array properties that use a solid type, only those that are part of a union.

Version

1.2.0

Steps to reproduce the behavior

In our schema we have a union type called UILine, defined as the following in our generated code:

public extension Unions {
  static let UILine = Union(
    name: "UILine",
    possibleTypes: [
      Objects.UITitleLine.self,
      Objects.UITextLine.self
    ]
  )
}

Multiple types utilise this union type, often as an array. An example of this is a UICard type.
I don't know if this matters, but the UICard type is also part of a Union.

For the UICard type the codegen step creates this Mock object (I've removed all other properties for brevity):

public class UICard: MockObject {
  public static let objectType: Object = MenuGQL.Objects.UICard
  public static let _mockFields = MockFields()
  public typealias MockValueCollectionType = Array<Mock<UICard>>

  public struct MockFields {
    @Field<[UILine]>("ui_lines") public var ui_lines
  }
}

public extension Mock where O == UICard {
  convenience init(
    ui_lines: [AnyMock]? = nil
  ) {
    self.init()
    _set(ui_lines, for: \.ui_lines)
  }
}

Also generated are these Mock objects:

public extension MockObject {
  typealias UILine = Union
}

public class UITitleLine: MockObject {
  public static let objectType: Object = MenuGQL.Objects.UITitleLine
  public static let _mockFields = MockFields()
  public typealias MockValueCollectionType = Array<Mock<UITitleLine>>

  public struct MockFields {
    @Field<String>("text") public var text
  }
}

public extension Mock where O == UITitleLine {
  convenience init(
    text: String? = nil
  ) {
    self.init()
    _set(text, for: \.text)
  }
}

These are used to attempt to create a Mock and then instantiate our UiBlockFields fragment.

let uiCard = Mock<UICard>.init(
  ui_lines: [Mock<UITitleLine>.init(text: "text")]
)
let block = Blocks.CardBlock(uiCard: UiBlockFields.from(uiCard).asUICard!)

This leads to a crash on this final line, with the actual error occurring here:
Screenshot 2023-05-17 at 7 12 03 pm

Something I did find when attempting to debug this was that in the Mock init, when the _set(_:,for:) function is called, the (value as? AnyHashable) always resolves to nil.

public func _set<T: MockFieldValue>(
  _ value: T.MockValueCollectionType.Element?,
  for keyPath: KeyPath<O.MockFields, Field<T>>
) {
  let field = O._mockFields[keyPath: keyPath]
  _data[field.key.description] = (value as? AnyHashable)
}

Logs

#0	0x000000018bfa78e0 in _swift_runtime_on_report ()
#1	0x000000018c034580 in _swift_stdlib_reportFatalErrorInFile ()
#2	0x000000018bce32a8 in closure #1 in closure #1 in _assertionFailure(_:_:file:line:flags:) ()
#3	0x000000018bce216c in _assertionFailure(_:_:file:line:flags:) ()
#4	0x000000015883d228 in Array<τ_0_0>.init(_fieldData:) at /SourcePackages/checkouts/apollo-ios/Sources/ApolloAPI/DataDict.swift:181
#5	0x000000015883d77c in protocol witness for SelectionSetEntityValue.init(_fieldData:) in conformance <τ_0_0> [τ_0_0] ()
#6	0x000000015883a878 in DataDict.subscript.getter at /SourcePackages/checkouts/apollo-ios/Sources/ApolloAPI/DataDict.swift:71
#7	0x0000000158f27eec in UiBlockFields.AsUICard.ui_lines.getter at /Sources/MenuGQL/Fragments/UiBlockFields.graphql.swift:2084
#8	0x0000000159383cd0 in Blocks.CardBlock.init(uiCard:) at /Sources/Menu/GraphQL/Adapters/BlockAdapter.swift:175
#9	0x0000000158124860 in BlockAdapterTests.testCardCard() at Tests/MenuTests/GraphQL/Adapters/BlockAdapterTests.swift:267

Anything else?

No response

@jabeattie jabeattie added bug Generally incorrect behavior needs investigation labels May 17, 2023
@AnthonyMDev AnthonyMDev added this to the Patch Releases (1.1.x) milestone May 17, 2023
@AnthonyMDev
Copy link
Contributor

Definitely looks like a bug! Thanks for bringing it to our attention. We'll add this to our list of fixes to be prioritized for coming patch releases.

@jabeattie
Copy link
Author

Thanks @AnthonyMDev, please let me know if you need any extra information.

@danielob
Copy link

danielob commented May 18, 2023

I found similar issue, although mine happens with mocking inline fragments. It all narrows down to not be able to cast Array<AnyMock> to AnyHashable in the _set operation.

@BobaFetters
Copy link
Member

The fix for this has been merged into main and will go out with our next patch release.

@jabeattie
Copy link
Author

@BobaFetters do you know if there are any plans for a patch release/minor release version soon that would contain #3089?

We believe that's the final blocker that will allow us to update from our current version of 1.1.2 and get some of the solid performance improvements that shipped in 1.2.0

@AnthonyMDev
Copy link
Contributor

We had some other things slated for a patch, but I think they won't be ready for release for long than I anticipated, so maybe we should just release a 1.3.1 patch with this fix in it.

@jabeattie
Copy link
Author

That would definitely be appreciated on our side

@calvincestari
Copy link
Member

This is now available in the latest release 1.3.1 that was published yesterday.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Generally incorrect behavior
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants