Skip to content

Commit 4f1ad36

Browse files
feat(reorder): improve move unit tests with folded result verification
1 parent 3fc4a12 commit 4f1ad36

File tree

3 files changed

+105
-37
lines changed

3 files changed

+105
-37
lines changed

README.md

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,7 @@ addItems(items, itemChildren: { $0.subitems }, to: listTreeDataSource)
5252
Fold (inorder traversal + map into final result):
5353
Use case: changes were made and we need final tree.
5454
```
55-
let folded = listTreeDataSource.fold({ ResultItem(item: $0) }) { item, subitems in
56-
ResultItem(identifier: item.identifier, title: item.title, subitems: subitems)
57-
}
58-
59-
// Or Fold with Identity (when element already hierarchical item):
60-
let folded = sut.fold({ $0 }) { root, _ in root }
55+
let folded = listTreeDataSource.fold(ResultItem(leaf:), cons: ResultItem(item:children:))
6156
```
6257

6358
Add/Insert/Delete/Move - More grannular control:

Tests/Shared/Model.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,16 +44,22 @@ public struct NodeTestItem: Hashable {
4444
public let identifier: UUID
4545
public let title: String
4646
public var subitems: [NodeTestItem]
47-
public init(identifier: UUID, title: String, subitems: [NodeTestItem]) {
47+
public init(identifier: UUID, title: String, subitems: [NodeTestItem] = []) {
4848
self.identifier = identifier
4949
self.title = title
5050
self.subitems = subitems
5151
}
5252
}
5353
extension NodeTestItem {
54+
public init(leaf: NodeTestItem) {
55+
self.init(identifier: leaf.identifier, title: leaf.title, subitems: [])
56+
}
5457
public init(_ item: NodeTestItem) {
5558
self.init(identifier: item.identifier, title: item.title, subitems: item.subitems)
5659
}
60+
public init(_ item: NodeTestItem, children: [NodeTestItem]) {
61+
self.init(identifier: item.identifier, title: item.title, subitems: children)
62+
}
5763
public init(outline: OutlineItem) {
5864
identifier = outline.identifier
5965
title = outline.title

Tests/SwiftListTreeDataSourceTests/ListTreeDataSource+BasicTests.swift

Lines changed: 97 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class ListTreeDataSourceTests: XCTestCase {
3232
addItems(dataSet, to: sut)
3333
sut.reload()
3434

35-
let folded = sut.fold(NodeTestItem.init) { item, subitems in
35+
let folded = sut.fold(NodeTestItem.init(leaf:)) { item, subitems in
3636
NodeTestItem(identifier: item.identifier, title: item.title, subitems: subitems)
3737
}
3838
XCTAssertEqual(dataSet, folded)
@@ -86,26 +86,47 @@ class ListTreeDataSourceTests: XCTestCase {
8686
}
8787

8888
func test_move_withTwoElementsToNilParent_shouldSecondBecomeFirst() throws {
89-
sut = ListTreeDataSource<OutlineItem>() // start from clean state
89+
let sut = ListTreeDataSource<NodeTestItem>() // start from clean state
9090

91-
let root = OutlineItem(title: "Root")
92-
let root2 = OutlineItem(title: "Root2")
93-
sut.append([root, root2], to: nil)
91+
let dummyId = UUID(uuidString: "00000000-0000-0000-0000-000000000000")!
92+
let dataSet: [NodeTestItem] = [
93+
OutlineItem(identifier: dummyId, title: "Root"),
94+
OutlineItem(identifier: dummyId, title: "Root2")
95+
].map(NodeTestItem.init)
96+
97+
let root = dataSet[0]; let root2 = dataSet[1]
98+
99+
addItems(dataSet, to: sut)
94100
sut.reload()
95101

96102
sut.move(root2, toIndex: 0, inParent: nil)
97103

98104
XCTAssertEqual(sut.backingStore.map(\.parent), [nil, nil])
99105
XCTAssertEqual(sut.backingStore.map(\.value), [root2, root])
100106
XCTAssertEqual(sut.backingStore.map(\.level), [0, 0])
107+
108+
// Verify folded result
109+
let folded = sut.fold(NodeTestItem.init(leaf:), cons: NodeTestItem.init)
110+
XCTAssertEqual(
111+
folded, [
112+
NodeTestItem(identifier: dummyId, title: "Root2"),
113+
NodeTestItem(identifier: dummyId, title: "Root")
114+
]
115+
)
101116
}
102117

103118
func test_move_withTwoElementsToNilParent_shouldSecondBecomeChildOfFirst() throws {
104-
sut = ListTreeDataSource<OutlineItem>() // start from clean state
119+
let sut = ListTreeDataSource<NodeTestItem>() // start from clean state
105120

106-
let root = OutlineItem(title: "Root")
107-
let root2 = OutlineItem(title: "Root2")
108-
sut.append([root, root2], to: nil)
121+
let dummyId = UUID(uuidString: "00000000-0000-0000-0000-000000000000")!
122+
let dataSet: [NodeTestItem] = [
123+
OutlineItem(identifier: dummyId, title: "Root"),
124+
OutlineItem(identifier: dummyId, title: "Root2")
125+
].map(NodeTestItem.init)
126+
127+
let root = dataSet[0]; let root2 = dataSet[1]
128+
129+
addItems(dataSet, to: sut)
109130
sut.reload()
110131

111132
sut.move(root2, toIndex: 0, inParent: root)
@@ -119,14 +140,30 @@ class ListTreeDataSourceTests: XCTestCase {
119140
XCTAssertEqual(head.subitems.map(\.parent), [head])
120141
XCTAssertEqual(head.subitems.map(\.value), [root2])
121142
XCTAssertEqual(head.subitems.map(\.level), [1])
143+
144+
// Verify folded result
145+
let folded = sut.fold(NodeTestItem.init(leaf:), cons: NodeTestItem.init)
146+
XCTAssertEqual(
147+
folded, [
148+
NodeTestItem(identifier: dummyId, title: "Root", subitems: [
149+
NodeTestItem(identifier: dummyId, title: "Root2")
150+
])
151+
]
152+
)
122153
}
123154

124-
func test_move_withOneElementToParent_shouldAppendElementToParent() throws {
125-
sut = ListTreeDataSource<OutlineItem>() // start from clean state
126-
let root = OutlineItem(title: "Root")
127-
let child = OutlineItem(title: "Child")
128-
sut.append([root], to: nil)
129-
sut.append([child], to: root)
155+
func test_move_withOneElementToParent_shouldChildBecomeSecondRoot() throws {
156+
let sut = ListTreeDataSource<NodeTestItem>() // start from clean state
157+
let dummyId = UUID(uuidString: "00000000-0000-0000-0000-000000000000")!
158+
let dataSet: [NodeTestItem] = [
159+
OutlineItem(identifier: dummyId, title: "Root", subitems: [
160+
OutlineItem(identifier: dummyId, title: "Child")
161+
])
162+
].map(NodeTestItem.init)
163+
164+
let root = dataSet[0]; let child = root.subitems[0]
165+
166+
addItems(dataSet, to: sut)
130167
sut.reload()
131168

132169
XCTAssertEqual(try XCTUnwrap(sut.lookup(root)?.level), 0)
@@ -138,23 +175,36 @@ class ListTreeDataSourceTests: XCTestCase {
138175
XCTAssertEqual(sut.backingStore.map(\.value), [root, child])
139176
XCTAssertEqual(sut.backingStore.map(\.level), [0, 0])
140177
XCTAssertEqual(sut.backingStore.flatMap(\.subitems), [])
141-
}
142178

143-
func test_move_withRootElementAndChildren_shouldAppendElementsToParents() throws {
144-
sut = ListTreeDataSource<OutlineItem>() // start from clean state
145-
let root1 = OutlineItem(title: "Root1")
146-
let root1Child1 = OutlineItem(title: "Root1.Child1")
147-
sut.append([root1], to: nil)
148-
sut.append([root1Child1], to: root1)
149-
150-
let root2 = OutlineItem(title: "Root2")
151-
let root2Child1 = OutlineItem(title: "Root2.Child1")
152-
let root2Child2 = OutlineItem(title: "Root2.Child2")
153-
let root2Child2Child1 = OutlineItem(title: "Root2.Child2.Child1")
154-
sut.append([root2], to: nil)
155-
sut.append([root2Child1, root2Child2], to: root2)
156-
sut.append([root2Child2Child1], to: root2Child2)
179+
// Verify folded result
180+
let folded = sut.fold(NodeTestItem.init(leaf:), cons: NodeTestItem.init)
181+
XCTAssertEqual(
182+
folded, [
183+
NodeTestItem(identifier: dummyId, title: "Root"),
184+
NodeTestItem(identifier: dummyId, title: "Child")
185+
]
186+
)
187+
}
188+
189+
func test_move_withRootElementAndChildren_shouldRoot2Child2MoveToRoot1Child1() throws {
190+
let sut = ListTreeDataSource<NodeTestItem>() // start from clean state
191+
let dummyId = UUID(uuidString: "00000000-0000-0000-0000-000000000000")!
192+
let dataSet: [NodeTestItem] = [
193+
OutlineItem(identifier: dummyId, title: "Root1", subitems: [
194+
OutlineItem(identifier: dummyId, title: "Root1.Child1")
195+
]),
196+
OutlineItem(identifier: dummyId, title: "Root2", subitems: [
197+
OutlineItem(identifier: dummyId, title: "Root2.Child1"),
198+
OutlineItem(identifier: dummyId, title: "Root2.Child2", subitems: [
199+
OutlineItem(identifier: dummyId, title: "Root2.Child2.Child1")
200+
])
201+
])
202+
].map(NodeTestItem.init(outline:))
203+
204+
let root1 = dataSet[0]; let root1Child1 = root1.subitems[0]
205+
let root2 = dataSet[1]; let root2Child2 = root2.subitems[1]
157206

207+
addItems(dataSet, to: sut)
158208
sut.reload()
159209

160210
let root2Node = try XCTUnwrap(sut.lookup(root2))
@@ -208,6 +258,23 @@ class ListTreeDataSourceTests: XCTestCase {
208258
XCTAssertEqual(subchildAfter.level, subchildBefore.level + 1) // moved +1 level deeper
209259
XCTAssertEqual(subchildAfter.value, subchildBefore.value)
210260
}
261+
262+
// Verify folded result
263+
let folded = sut.fold(NodeTestItem.init(leaf:), cons: NodeTestItem.init)
264+
XCTAssertEqual(
265+
folded, [
266+
NodeTestItem(identifier: dummyId, title: "Root1", subitems: [
267+
NodeTestItem(identifier: dummyId, title: "Root1.Child1", subitems: [
268+
NodeTestItem(identifier: dummyId, title: "Root2.Child2", subitems: [
269+
NodeTestItem(identifier: dummyId, title: "Root2.Child2.Child1")
270+
])
271+
])
272+
]),
273+
NodeTestItem(identifier: dummyId, title: "Root2", subitems: [
274+
NodeTestItem(identifier: dummyId, title: "Root2.Child1")
275+
])
276+
]
277+
)
211278
}
212279

213280
func test_append_withOneElementToParent_shouldAppendElementToParent() throws {

0 commit comments

Comments
 (0)