import XCTest @testable import LCFeatureControl @testable import LCEssentials final class FeatureControlErrorTests: XCTestCase { private var api = API.lce_featureControlTestInstance() override func tearDown() { StubURLProtocol.reset() super.tearDown() } private func makeManager() -> FeatureControlManager { let config = FeatureControlConfiguration(baseURL: "https://api.example.com", environment: "production", auth: FeatureControlHeaderAuth(headers: [:])) return FeatureControlManager(configuration: config, api: api) } private func context() -> FeatureControlContext { FeatureControlContext(subjectType: .customer, subjectId: "cust_1") } private func expectMappedError(status: Int, bodyCode: String) async throws -> FeatureControlError { StubURLProtocol.setStub(.init(statusCode: status, body: Data(#"{"code":"\#(bodyCode)"}"#.utf8))) let manager = makeManager() do { _ = try await manager.evaluateOrThrow(keys: ["x"], context: context()) XCTFail("expected FeatureControlError") throw FeatureControlError.transport(message: "unreachable") } catch let error as FeatureControlError { return error } } func testMaps400ToInvalidContext() async throws { let error = try await expectMappedError(status: 400, bodyCode: "FEATURE_CONTROL_CONTEXT_INVALID") XCTAssertEqual(error, .invalidContext(code: "FEATURE_CONTROL_CONTEXT_INVALID")) } func testMaps401ToUnauthorized() async throws { let error = try await expectMappedError(status: 401, bodyCode: "FEATURE_CONTROL_MISSING_AUTH") XCTAssertEqual(error, .unauthorized(code: "FEATURE_CONTROL_MISSING_AUTH")) } func testMaps403ToForbidden() async throws { let error = try await expectMappedError(status: 403, bodyCode: "FEATURE_CONTROL_PANEL_ROLE_REQUIRED") XCTAssertEqual(error, .forbidden(code: "FEATURE_CONTROL_PANEL_ROLE_REQUIRED")) } func testMaps429ToRateLimited() async throws { let error = try await expectMappedError(status: 429, bodyCode: "FEATURE_CONTROL_RATE_LIMIT") XCTAssertEqual(error, .rateLimited(code: "FEATURE_CONTROL_RATE_LIMIT")) } func testMaps500ToServerWithStatusCode() async throws { let error = try await expectMappedError(status: 500, bodyCode: "FEATURE_CONTROL_ERROR") XCTAssertEqual(error, .server(code: "FEATURE_CONTROL_ERROR", status: 500)) } func testDecodingFailureMapsToTransport() async { StubURLProtocol.setStub(.init(statusCode: 200, body: Data("not json at all".utf8))) let manager = makeManager() do { _ = try await manager.evaluateOrThrow(keys: ["x"], context: context()) XCTFail("expected throw") } catch let error as FeatureControlError { guard case .transport = error else { return XCTFail("expected .transport, got \(error)") } } catch { XCTFail("expected FeatureControlError, got \(error)") } } }