Skip to content

Commit 8a09143

Browse files
committed
test(model-sync-lib): extended tests
1 parent ed3fafe commit 8a09143

File tree

5 files changed

+126
-19
lines changed

5 files changed

+126
-19
lines changed

model-sync-lib/src/test/kotlin/org/modelix/model/sync/ModelExporterTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class ModelExporterTest {
2222

2323
@JvmStatic
2424
@BeforeAll
25-
fun `initialize model and branch`(): Unit {
25+
fun `initialize model and branch`() {
2626
model = ModelData.fromJson(File("src/test/resources/newmodel.json").readText())
2727

2828
val tree = CLTree(ObjectStoreCache(MapBaseStore()))

model-sync-lib/src/test/kotlin/org/modelix/model/sync/ModelImporterTest.kt

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package org.modelix.model.sync
22

3-
import org.junit.jupiter.api.Assertions.assertEquals
43
import org.junit.jupiter.api.BeforeAll
54
import org.junit.jupiter.api.Test
65
import org.junit.jupiter.api.assertDoesNotThrow
@@ -9,19 +8,20 @@ import org.modelix.model.api.PBranch
98
import org.modelix.model.api.getRootNode
109
import org.modelix.model.client.IdGenerator
1110
import org.modelix.model.data.ModelData
12-
import org.modelix.model.data.NodeData
13-
import org.modelix.model.data.asData
1411
import org.modelix.model.lazy.CLTree
1512
import org.modelix.model.lazy.ObjectStoreCache
1613
import org.modelix.model.persistent.MapBaseStore
1714
import java.io.File
15+
import kotlin.test.assertEquals
16+
import kotlin.test.fail
1817

1918
class ModelImporterTest {
2019

2120
companion object {
2221
private lateinit var model: ModelData
2322
private lateinit var newModel: ModelData
2423
private lateinit var branch: IBranch
24+
private lateinit var importer: ModelImporter
2525

2626
@JvmStatic
2727
@BeforeAll
@@ -37,7 +37,7 @@ class ModelImporterTest {
3737
model.load(branch)
3838
// println("PRE-SPEC ${model.toJson()}")
3939
// println("PRE-LOADED ${branch.getRootNode().toJson()}")
40-
ModelImporter(branch.getRootNode()).import(newModelFile)
40+
importer = ModelImporter(branch.getRootNode(), ImportStats()).apply { import(newModelFile) }
4141
// println("POST-SPEC ${newModel.root.toJson()}")
4242
// println("POST-LOADED ${branch.getRootNode().toJson()}")
4343
}
@@ -48,10 +48,8 @@ class ModelImporterTest {
4848
fun `can sync properties`() {
4949
branch.runRead {
5050
val expectedNode = newModel.root.children[0]
51-
val expectedProperties = expectedNode.properties
52-
val actualProperties = branch.getRootNode().allChildren.first().asData().properties
53-
assertEquals(expectedProperties, actualProperties.filterKeys { it != NodeData.idPropertyKey })
54-
assertEquals(expectedNode.id, actualProperties[NodeData.idPropertyKey])
51+
val actualNode = branch.getRootNode().allChildren.first()
52+
assertNodePropertiesConformToSpec(expectedNode, actualNode)
5553
}
5654
}
5755

@@ -60,24 +58,55 @@ class ModelImporterTest {
6058
branch.runRead {
6159
val node0 = branch.getRootNode().allChildren.first()
6260
val node1 = branch.getRootNode().allChildren.toList()[1]
61+
val node1Spec = newModel.root.children[1]
6362

6463
assertEquals(node1, node0.getReferenceTarget("sibling"))
6564
assertEquals(node0, node1.getReferenceTarget("sibling"))
6665
assertEquals(branch.getRootNode(), node1.getReferenceTarget("root"))
66+
67+
assertNodeReferencesConformToSpec(node1Spec, node1)
6768
}
6869
}
6970

7071
@Test
7172
fun `can sync children`() {
7273
branch.runRead {
7374
val index = 2
74-
val node = branch.getRootNode().allChildren.toList()[index]
75-
val specifiedOrder = newModel.root.children[index].children.map { it.properties[NodeData.idPropertyKey] ?: it.id }
76-
val actualOrder = node.allChildren.map { it.getPropertyValue(NodeData.idPropertyKey) }
77-
assertEquals(specifiedOrder, actualOrder)
75+
val actualNode = branch.getRootNode().allChildren.toList()[index]
76+
val specifiedNode = newModel.root.children[index]
77+
assertNodeChildOrderConformsToSpec(specifiedNode, actualNode)
7878
}
7979
}
8080

81+
@Test
82+
fun `model conforms to spec`() {
83+
branch.runRead {
84+
assertAllNodeConformToSpec(newModel.root, branch.getRootNode())
85+
}
86+
}
87+
88+
@Test
89+
fun `uses minimal amount of operations`() {
90+
val stats = importer.stats ?: fail("No import stats found.")
91+
assertEquals(1, stats.additions.size)
92+
assertEquals(1, stats.deletions.size)
93+
assertEquals(4, stats.moves.size)
94+
assertEquals(4, stats.propertyChanges.size)
95+
assertEquals(3, stats.referenceChanges.size)
96+
}
97+
98+
@Test
99+
fun `operations do not overlap`() {
100+
val stats = importer.stats ?: fail("No import stats found.")
101+
val additionsSet = stats.additions.toSet()
102+
val deletionsSet = stats.deletions.toSet()
103+
val movesSet = stats.moves.toSet()
104+
105+
assert(additionsSet.intersect(deletionsSet).isEmpty())
106+
assert(deletionsSet.intersect(movesSet).isEmpty())
107+
assert(movesSet.intersect(additionsSet).isEmpty())
108+
}
109+
81110
@Test
82111
fun `can bulk import`() {
83112
val tree = CLTree(ObjectStoreCache(MapBaseStore()))

model-sync-lib/src/test/kotlin/org/modelix/model/sync/SyncTestUtil.kt

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ package org.modelix.model.sync
33
import kotlinx.serialization.encodeToString
44
import kotlinx.serialization.json.Json
55
import org.modelix.model.api.INode
6+
import org.modelix.model.api.serialize
67
import org.modelix.model.data.NodeData
78
import org.modelix.model.data.asData
9+
import org.modelix.model.data.associateWithNotNull
10+
import kotlin.test.assertEquals
811

912
object SyncTestUtil {
1013
val json = Json { prettyPrint = true }
@@ -16,4 +19,38 @@ fun INode.toJson() : String {
1619

1720
fun NodeData.toJson() : String {
1821
return SyncTestUtil.json.encodeToString(this)
22+
}
23+
24+
internal fun assertAllNodeConformToSpec(expectedRoot: NodeData, actualRoot: INode) {
25+
assertNodeConformsToSpec(expectedRoot, actualRoot)
26+
for ((expectedChild, actualChild) in expectedRoot.children zip actualRoot.allChildren) {
27+
assertNodeConformsToSpec(expectedChild, actualChild)
28+
}
29+
}
30+
31+
internal fun assertNodeConformsToSpec(expected: NodeData, actual: INode) {
32+
assertNodePropertiesConformToSpec(expected, actual)
33+
assertNodeReferencesConformToSpec(expected, actual)
34+
assertNodeChildOrderConformsToSpec(expected, actual)
35+
}
36+
37+
internal fun assertNodePropertiesConformToSpec(expected: NodeData, actual: INode) {
38+
val actualProperties = actual.getPropertyRoles().associateWithNotNull { actual.getPropertyValue(it) }
39+
assertEquals(expected.properties, actualProperties.filterKeys { it != NodeData.idPropertyKey })
40+
assertEquals(expected.id, actualProperties[NodeData.idPropertyKey])
41+
}
42+
43+
internal fun assertNodeReferencesConformToSpec(expected: NodeData, actual: INode) {
44+
val actualReferences = actual.getReferenceRoles().associateWithNotNull {
45+
actual.getReferenceTarget(it)?.let { node ->
46+
node.getPropertyValue(NodeData.idPropertyKey) ?: node.reference.serialize()
47+
}
48+
}
49+
assertEquals(expected.references, actualReferences)
50+
}
51+
52+
internal fun assertNodeChildOrderConformsToSpec(expected: NodeData, actual: INode) {
53+
val specifiedOrder = expected.children.map { it.properties[NodeData.idPropertyKey] ?: it.id }
54+
val actualOrder = actual.allChildren.map { it.getPropertyValue(NodeData.idPropertyKey) }
55+
assertEquals(specifiedOrder, actualOrder)
1956
}

model-sync-lib/src/test/resources/model.json

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,27 @@
55
{
66
"id": "node:002",
77
"properties": {
8+
"purpose" : "property sync test",
89
"name": "nameValue",
9-
"description": "descriptionValue"
10+
"description": "descriptionValue",
11+
"optional" : "toBeDeleted"
1012
}
1113
},
1214
{
1315
"id": "node:003",
16+
"properties": {
17+
"purpose": "reference sync test"
18+
},
1419
"references": {
15-
"root": "node:001"
20+
"root": "node:001",
21+
"self": "node:003"
1622
}
1723
},
1824
{
1925
"id": "node:010",
26+
"properties": {
27+
"purpose": "child sync test"
28+
},
2029
"children": [
2130
{
2231
"id": "node:011"
@@ -32,8 +41,20 @@
3241
},
3342
{
3443
"id": "node:015"
44+
},
45+
{
46+
"id": "node:004",
47+
"properties": {
48+
"purpose": "move across parents"
49+
}
3550
}
3651
]
52+
},
53+
{
54+
"id": "node:005",
55+
"properties": {
56+
"purpose": "move across parents"
57+
}
3758
}
3859
]
3960
}

model-sync-lib/src/test/resources/newmodel.json

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,39 +5,59 @@
55
{
66
"id": "node:002",
77
"properties": {
8+
"purpose" : "property sync test",
89
"name": "newNameValue",
9-
"description": "newDescriptionValue"
10+
"description": "newDescriptionValue",
11+
"newProperty": "newProperty"
1012
},
1113
"references": {
1214
"sibling": "node:003"
1315
}
1416
},
1517
{
1618
"id": "node:003",
19+
"properties": {
20+
"purpose": "reference sync test"
21+
},
1722
"references": {
1823
"root": "node:001",
1924
"sibling": "node:002"
2025
}
2126
},
2227
{
2328
"id": "node:010",
29+
"properties": {
30+
"purpose": "child sync test"
31+
},
2432
"children": [
2533
{
26-
"id": "node:013"
34+
"id": "node:011"
2735
},
2836
{
29-
"id": "node:015"
37+
"id": "node:013"
3038
},
3139
{
32-
"id": "node:011"
40+
"id": "node:015"
3341
},
3442
{
3543
"id": "node:014"
3644
},
3745
{
3846
"id": "node:016"
47+
},
48+
{
49+
"id": "node:005",
50+
"properties": {
51+
"purpose": "move across parents"
52+
}
3953
}
4054
]
55+
},
56+
{
57+
"id": "node:004",
58+
"properties": {
59+
"purpose": "move across parents"
60+
}
4161
}
4262
]
4363
}

0 commit comments

Comments
 (0)