Skip to content

Commit 07ba626

Browse files
committed
add flatten adjacently tagged enum test
1 parent e19acfb commit 07ba626

2 files changed

Lines changed: 70 additions & 1 deletion

File tree

Sources/MacroCodableKit/Macros/TaggedAnnotations.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public enum TaggedCodableCaseStyle {
2929
/// ```json
3030
/// {"intent": "SCROLL"}
3131
/// ```
32-
@attached(extension, conformances: Decodable, Encodable, names: named(CodingKeys), named(init(from:)), named(encode(to:)))
32+
@attached(extension, conformances: Decodable, Encodable, names: arbitrary)
3333
public macro TaggedCodable() = #externalMacro(module: "Macro", type: "TaggedCodableMacro")
3434

3535
/// Specifies the discriminator key name and case-name transformation style
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import Foundation
2+
import MacroCodableKit
3+
import XCTest
4+
5+
// MARK: - Types
6+
7+
@TaggedCodable
8+
@CodedAt("type", caseStyle: .screamingSnakeCase)
9+
@ContentAt("params")
10+
private enum Command {
11+
case ping
12+
case fetch(url: String)
13+
}
14+
15+
// Case A: @AllOfCodable with a single TaggedCodable property
16+
@AllOfCodable
17+
private struct EnvelopeAllOf {
18+
let command: Command
19+
}
20+
21+
// Case B: plain @Codable (control group — expected to nest)
22+
@Codable
23+
private struct EnvelopeCodable {
24+
let command: Command
25+
}
26+
27+
// MARK: - Tests
28+
29+
final class TaggedEnumFlattenTests: XCTestCase {
30+
31+
private let encoder: JSONEncoder = {
32+
let e = JSONEncoder()
33+
e.outputFormatting = [.sortedKeys]
34+
return e
35+
}()
36+
37+
// Expected: {"params":{"url":"https://example.com"},"type":"FETCH"}
38+
// i.e. type + params are sibling keys at the top level
39+
func test_allOf_flattens_taggedEnum() throws {
40+
let value = EnvelopeAllOf(command: .fetch(url: "https://example.com"))
41+
let data = try encoder.encode(value)
42+
let json = String(data: data, encoding: .utf8)!
43+
44+
let obj = try JSONSerialization.jsonObject(with: data) as! [String: Any]
45+
46+
// Should be flat — "type" and "params" at root, no extra nesting
47+
XCTAssertEqual(obj["type"] as? String, "FETCH",
48+
"Expected 'type' as sibling key, got: \(json)")
49+
let params = obj["params"] as? [String: Any]
50+
XCTAssertEqual(params?["url"] as? String, "https://example.com",
51+
"Expected 'params' as sibling key, got: \(json)")
52+
XCTAssertNil(obj["command"] as? [String: Any],
53+
"Should NOT be nested object under 'command'")
54+
}
55+
56+
// Control: @Codable nests under "command" key as expected
57+
func test_codable_nests_taggedEnum() throws {
58+
let value = EnvelopeCodable(command: .fetch(url: "https://example.com"))
59+
let data = try encoder.encode(value)
60+
let json = String(data: data, encoding: .utf8)!
61+
62+
let obj = try JSONSerialization.jsonObject(with: data) as! [String: Any]
63+
64+
// Should be nested under "command"
65+
let nested = obj["command"] as? [String: Any]
66+
XCTAssertNotNil(nested, "Expected nesting under 'command', got: \(json)")
67+
XCTAssertEqual(nested?["type"] as? String, "FETCH")
68+
}
69+
}

0 commit comments

Comments
 (0)