UUID in state initializer

@mbrandonw pointed out the solution to an almost identical question in this thread: It's possible to use dependencies in eagerly evaluated closures.

I followed the solution in the other thread, put the closure at the top level and overwrote it from the initializer with a test value:

public let id: UUID = {
    @Dependency(\.uuid) var uuid: UUIDGenerator
    return uuid()
}()

public init(id: UUID? = nil, _ content: Content, folder: URL? = nil) {
    if let id {
        self.id = id
    }
    self.content = content
}

The problem with this is, that it runs on every initialization, producing "dependency not implemented" errors when creating the expected test result state.

(Identifiable forbids making it a lazy variable, a function cannot be executed from init and having it return a UUIDGenerator instead of a UUID makes State no longer conform to Equatable.)

What worked for me was putting the closure into the initializer:

public init(
    id: UUID = {
        @Dependency(\.uuid) var uuid: UUIDGenerator
        return uuid()
    }(),
    _ content: Content,
) {
    self.id = id
    self.content = content
}

Or in a static helper method:

public init(
    id: UUID = getUUID(),
    _ content: Content
) {
    self.id = id
    self.content = content
}

public static func getUUID() -> UUID {
    @Dependency(\.uuid) var uuid: UUIDGenerator
    return uuid()
}

This lets me test the parent feature.

Problem is with the parent of the parent where I don’t have direct access to the initializer anymore. So when I create an expected test state of the grandparent I would need to pipe the expected UUID of the grandchild through the object in the middle.

If I don’t do that my test doesn’t only fail because of the UUID mismatch, but also because of the not implemented UUID dependency (creating the expected state happens outside the store).

So my parent initializer looks like this (irrelevant parts omitted):

public init(
    paragraphUUIDs: [UUID]? = nil
) {
    let paragraphs = ((try? Content.parser.parse(entry.content)) ?? [])
    let finalParagraphs: [ContentFeature.State]
    if let paragraphUUIDs { // used in test
        finalParagraphs = zip(paragraphUUIDs, paragraphs)
            .map { (uuid, content) in
                ContentFeature.State(
                    id: uuid,
                    content
                )
            }
    } else { // used in production
        finalParagraphs = paragraphs
            .map { content in
                ContentFeature.State(
                    content
                )
            }
    }
    self.paragraphs = IdentifiedArrayOf(uniqueElements: finalParagraphs)
}

This passes the tests but it looks very hacky.