Skip to content

Commit 29009dc

Browse files
committed
RecursiveDiff: better nil-Handling, deal with components of collections (#)
1 parent abe3c71 commit 29009dc

File tree

2 files changed

+46
-27
lines changed

2 files changed

+46
-27
lines changed

Sources/LoggerMiddleware/LoggerMiddleware.swift

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -150,9 +150,23 @@ extension LoggerMiddleware {
150150
diff(prefix: prefixLines, name: stateName, lhs: before, rhs: after)?.trimmingCharacters(in: .whitespacesAndNewlines)
151151
}
152152

153-
private static func diff<A>(prefix: String, name: String, level: Int = 0, lhs: A, rhs: A) -> String? {
154-
let leftMirror = Mirror(reflecting: lhs)
155-
let rightMirror = Mirror(reflecting: rhs)
153+
private static func diff<A>(prefix: String, name: String, level: Int = 0, lhs: A?, rhs: A?) -> String? {
154+
155+
guard let rightHandSide = rhs, let leftHandSide = lhs else {
156+
if let rightHandSide = rhs {
157+
return "\(prefix).\(name): nil → \(rightHandSide)"
158+
}
159+
160+
if let leftHandSide = lhs {
161+
return "\(prefix).\(name): \(leftHandSide) → nil"
162+
}
163+
164+
// nil == lhs == rhs
165+
return nil
166+
}
167+
168+
let leftMirror = Mirror(reflecting: leftHandSide)
169+
let rightMirror = Mirror(reflecting: rightHandSide)
156170

157171
// special handling for Dictionaries
158172
if let left = lhs as? Dictionary<AnyHashable, Any>, let right = rhs as? Dictionary<AnyHashable, Any> {
@@ -188,28 +202,21 @@ extension LoggerMiddleware {
188202

189203
// if there are no children, compare lhs and rhs directly
190204
if 0 == leftMirror.children.count {
191-
if "\(lhs)" == "\(rhs)" {
205+
if "\(leftHandSide)" == "\(rightHandSide)" {
192206
return nil
193207
} else {
194-
return "\(prefix).\(name): \(lhs)\(rhs)"
208+
return "\(prefix).\(name): \(leftHandSide)\(rightHandSide)"
195209
}
196210
}
197211

198212
// there are children -> diff the object graph recursively
199213
let strings: [String] = leftMirror.children.map({ leftChild in
200-
guard let rightChild = rightMirror.children.first(where: { $0.label == leftChild.label }) else {
201-
return nil
202-
}
203-
204-
let leftValue = leftChild.value
205-
let rightValue = rightChild.value
206-
207-
let dot = (level > 0) ? "." : " "
208-
return Self.diff(prefix: "\(prefix)\(dot)\(name)",
209-
name: leftChild.label ?? "",
214+
let toDotOrNotToDot = (level > 0) ? "." : " "
215+
return Self.diff(prefix: "\(prefix)\(toDotOrNotToDot)\(name)",
216+
name: leftChild.label ?? "#", // label might be missing for items in collections
210217
level: level + 1,
211-
lhs: leftValue,
212-
rhs: rightValue)
218+
lhs: leftChild.value,
219+
rhs: rightMirror.children.first(where: { $0.label == leftChild.label })?.value)
213220
}).compactMap { $0 }
214221

215222
if strings.count > 0 {

Tests/LoggerMiddlewareTests/LoggerMiddlewareTests.swift

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,14 @@ struct TestState: Equatable {
66
public let a: Substate
77
public let b: [Int]
88
public let c: String
9+
public let d: String?
10+
public let e: String?
911
}
1012

1113
struct Substate: Equatable {
1214
public let x: Set<String>
13-
public let y: [String: Int]
15+
public let y1: [String: Int]
16+
public let y2: [String: Int?]
1417
public let z: Bool
1518
}
1619

@@ -31,26 +34,35 @@ final class LoggerMiddlewareTests: XCTestCase {
3134
func testStateDiff() {
3235
// given
3336
let beforeState: LoggerMiddleware<TestMiddleware>.StateType = TestState(a: Substate(x: ["SetB", "SetA"],
34-
y: ["one": 1, "eleven": 11],
37+
y1: ["one": 1, "eleven": 11],
38+
y2: ["one": 1, "eleven": 11, "zapp": 42],
3539
z: true),
3640
b: [0, 1],
37-
c: "Foo")
41+
c: "Foo",
42+
d: "",
43+
e: nil)
3844
let afterState: LoggerMiddleware<TestMiddleware>.StateType = TestState(a: Substate(x: ["SetB", "SetC"],
39-
y: ["one": 1, "twelve": 12],
45+
y1: ["one": 1, "twelve": 12],
46+
y2: ["one": 1, "twelve": 12, "zapp": nil],
4047
z: false),
4148
b: [0],
42-
c: "Bar")
49+
c: "Bar",
50+
d: nil,
51+
e: "🥚")
4352

4453
// when
4554
let result: String? = LoggerMiddleware<TestMiddleware>.recursiveDiff(prefixLines: "🏛", stateName: "TestState", before: beforeState, after: afterState)
4655

4756
// then
4857
let expected = """
49-
🏛 TestState.some.a.x: 📦 <SetA, SetB> → <SetB, SetC>
50-
🏛 TestState.some.a.y: 📦 [eleven: 11, one: 1] → [one: 1, twelve: 12]
51-
🏛 TestState.some.a.z: true → false
52-
🏛 TestState.some.b: 📦 [0, 1] → [0]
53-
🏛 TestState.some.c: Foo → Bar
58+
🏛 TestState.a.x: 📦 <SetA, SetB> → <SetB, SetC>
59+
🏛 TestState.a.y1: 📦 [eleven: 11, one: 1] → [one: 1, twelve: 12]
60+
🏛 TestState.a.y2: 📦 [eleven: Optional(11), one: Optional(1), zapp: Optional(42)] → [one: Optional(1), twelve: Optional(12), zapp: nil]
61+
🏛 TestState.a.z: true → false
62+
🏛 TestState.b.#: 1 → 0
63+
🏛 TestState.c: Foo → Bar
64+
🏛 TestState.d.some: ✨ → nil
65+
🏛 TestState.e: nil → Optional("🥚")
5466
"""
5567
XCTAssertEqual(result, expected)
5668
}

0 commit comments

Comments
 (0)