pointfreeco / swift-composable-architecture

A library for building applications in a consistent and understandable way, with composition, testing, and ergonomics in mind.
https://www.pointfree.co/collections/composable-architecture
MIT License
12.07k stars 1.41k forks source link

CRASH: Could not cast value of type 'Observation.ObservationRegistrar' to 'Perception._PerceptionRegistrar' #3112

Closed iharandreyev closed 3 months ago

iharandreyev commented 3 months ago

Description

The error in question happens when I'm trying to test the following feature

import ComposableArchitecture
import Foundation

@ObservableState
enum RemoteResourceState<Value> {
    case none
    case loading
    case loaded(Value)
    case failed(Error)
}

extension RemoteResourceState: Equatable where Value: Equatable {
    static func == (lhs: Self, rhs: Self) -> Bool {
        switch (lhs, rhs) {
        case (.none, .none): return true
        case (.loading, .loading): return true
        case let (.loaded(lhs), .loaded(rhs)):
            return lhs == rhs
        case let (.failed(lhs), .failed(rhs)):
            return "\(lhs)" == "\(rhs)"
        default:
            return false
        }
    }
}

enum RemoteResourceAction<Value> {
    case load
    case succeed(Value)
    case fail(Error)
}

extension RemoteResourceAction: Equatable where Value: Equatable {
    static func == (lhs: Self, rhs: Self) -> Bool {
        switch (lhs, rhs) {
        case (.load, .load): return true
        case let (.succeed(lhs), .succeed(rhs)):
            return lhs == rhs
        case let (.fail(lhs), .fail(rhs)):
            return "\(lhs)" == "\(rhs)"
        default:
            return false
        }
    }
}

struct RemoteResource<Value>: Reducer {
    typealias State = RemoteResourceState<Value>
    typealias Action = RemoteResourceAction<Value>

    var body: some ReducerOf<Self> {
        EmptyReducer()
    }
}

with a test below

import XCTest
import ComposableArchitecture
@testable import MyApp

final class RemoteResourceTests: XCTestCase {
    func testLoadFirst() async {
        typealias SUT = RemoteResource<TestResource>

        let store = TestStoreOf<SUT>(
            initialState: .none,
            reducer: SUT.init
        )

        await store.send(.load) { state in
            state = .loading
        }
    }
}

// MARK: - Helpers

private struct TestResource: Identifiable, Equatable {
    let id: Int = UUID().hashValue
}

Checklist

Expected behavior

Test fails with an invalid behavior error

Actual behavior

Test crashes with Could not cast value of type 'Observation.ObservationRegistrar' to 'Perception._PerceptionRegistrar' error in Perception/PerceptionRegistrar.swift:52

Steps to reproduce

Run the code in the description

The Composable Architecture version information

1.10.4

Destination operating system

iOS 15.0

Xcode version information

15.4

Swift Compiler version information

swift-driver version: 1.90.11.1 Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4)
Target: arm64-apple-macosx14.0
iharandreyev commented 3 months ago

The issue occurs when I use iOS 17.5 simulator as a test run destination. When running on iOS 15.5 simulator, there's no crash

mbrandonw commented 3 months ago

Hi @iharandreyev, I am not able to reproduce this. I have run it in a variety of simulators and it all seems to work fine. Can you please provide a project that demonstrates the problem?

I am also going to convert this to a discussion for the time being because it's not clear there is an actual issue with the library. Let's continue the conversation over there.