@@ -3,7 +3,6 @@ package org.modelix.model.sync
3
3
import org.junit.jupiter.api.BeforeAll
4
4
import org.junit.jupiter.api.Test
5
5
import org.junit.jupiter.api.assertDoesNotThrow
6
- import org.modelix.model.api.IBranch
7
6
import org.modelix.model.api.PBranch
8
7
import org.modelix.model.api.getRootNode
9
8
import org.modelix.model.api.serialize
@@ -12,19 +11,19 @@ import org.modelix.model.data.ModelData
12
11
import org.modelix.model.data.NodeData
13
12
import org.modelix.model.lazy.CLTree
14
13
import org.modelix.model.lazy.ObjectStoreCache
14
+ import org.modelix.model.operations.*
15
15
import org.modelix.model.persistent.MapBaseStore
16
16
import org.modelix.model.test.RandomModelChangeGenerator
17
17
import java.io.File
18
18
import kotlin.random.Random
19
19
import kotlin.test.assertEquals
20
- import kotlin.test.fail
21
20
22
21
class ModelImporterTest {
23
22
24
23
companion object {
25
24
private lateinit var model: ModelData
26
25
private lateinit var newModel: ModelData
27
- private lateinit var branch: IBranch
26
+ private lateinit var branch: OTBranch
28
27
private lateinit var importer: ModelImporter
29
28
30
29
@JvmStatic
@@ -34,14 +33,20 @@ class ModelImporterTest {
34
33
val newModelFile = File (" src/jvmTest/resources/newmodel.json" )
35
34
newModel = ModelData .fromJson(newModelFile.readText())
36
35
37
- val tree = CLTree (ObjectStoreCache (MapBaseStore ()))
38
- branch = PBranch (tree, IdGenerator .getInstance(1 ))
36
+ val store = ObjectStoreCache (MapBaseStore ())
37
+ val tree = CLTree (store)
38
+ val idGenerator = IdGenerator .getInstance(1 )
39
+ val pBranch = PBranch (tree, idGenerator)
40
+
41
+ pBranch.runWrite {
42
+ model.load(pBranch)
43
+ }
44
+ branch = OTBranch (pBranch, idGenerator, store)
39
45
40
46
branch.runWrite {
41
- model.load(branch)
42
47
// println("PRE-SPEC ${model.toJson()}")
43
48
// println("PRE-LOADED ${branch.getRootNode().toJson()}")
44
- importer = ModelImporter (branch.getRootNode(), ImportStats () ).apply { import(newModelFile) }
49
+ importer = ModelImporter (branch.getRootNode()).apply { import(newModelFile) }
45
50
// println("POST-SPEC ${newModel.root.toJson()}")
46
51
// println("POST-LOADED ${branch.getRootNode().toJson()}")
47
52
}
@@ -91,17 +96,22 @@ class ModelImporterTest {
91
96
92
97
@Test
93
98
fun `uses minimal amount of operations` () {
94
- val stats = importer.stats ? : fail(" No import stats found." )
95
- assertEquals(1 , stats.additions.size)
96
- assertEquals(1 , stats.deletions.size)
97
- assertEquals(5 , stats.moves.size)
98
- assertEquals(4 , stats.propertyChanges.size)
99
- assertEquals(3 , stats.referenceChanges.size)
99
+ val operations = branch.operationsAndTree.first
100
+
101
+ val numOps = operations.numOpsByType()
102
+ val numPropertyChangesIgnoringOriginalId =
103
+ numOps[AddNewChildOp ::class ]?.let { numOps[SetPropertyOp ::class ]?.minus(it) } ? : 0
104
+
105
+ assertEquals(1 , numOps[AddNewChildOp ::class ])
106
+ assertEquals(1 , numOps[DeleteNodeOp ::class ])
107
+ assertEquals(5 , numOps[MoveNodeOp ::class ])
108
+ assertEquals(4 , numPropertyChangesIgnoringOriginalId)
109
+ assertEquals(3 , numOps[SetReferenceOp ::class ])
100
110
}
101
111
102
112
@Test
103
113
fun `operations do not overlap` () {
104
- assertNoOverlappingOperations(importer.stats )
114
+ assertNoOverlappingOperations(branch.operationsAndTree.first )
105
115
}
106
116
107
117
@Test
@@ -125,13 +135,13 @@ class ModelImporterTest {
125
135
println (" Seed for random change test: $seed " )
126
136
lateinit var initialState: NodeData
127
137
lateinit var specification: NodeData
128
- val numChanges = 50
138
+ val numChanges = 200
129
139
130
140
branch0.runWrite {
131
141
val rootNode = branch0.getRootNode()
132
142
rootNode.setPropertyValue(NodeData .idPropertyKey, rootNode.reference.serialize())
133
143
val grower = RandomModelChangeGenerator (rootNode, Random (seed)).growingOperationsOnly()
134
- for (i in 1 .. 20 ) {
144
+ for (i in 1 .. 1000 ) {
135
145
grower.applyRandomChange()
136
146
}
137
147
initialState = rootNode.asExported()
@@ -143,28 +153,31 @@ class ModelImporterTest {
143
153
specification = rootNode.asExported()
144
154
}
145
155
146
- val tree1 = CLTree (ObjectStoreCache (MapBaseStore ()))
147
- val branch1 = PBranch (tree1, IdGenerator .getInstance(1 ))
156
+ val store = ObjectStoreCache (MapBaseStore ())
157
+ val tree1 = CLTree (store)
158
+ val idGenerator = IdGenerator .getInstance(1 )
159
+ val branch1 = PBranch (tree1, idGenerator)
148
160
149
161
branch1.runWrite {
150
- val importer = ModelImporter (branch1.getRootNode(), ImportStats () )
162
+ val importer = ModelImporter (branch1.getRootNode())
151
163
importer.import(ModelData (root = initialState))
164
+ }
165
+ val otBranch = OTBranch (branch1, idGenerator, store)
166
+
167
+ otBranch.runWrite {
168
+ val importer = ModelImporter (otBranch.getRootNode())
152
169
importer.import(ModelData (root = specification))
153
170
154
- // println("INITIAL")
155
- // println(initialState.toJson())
156
- //
157
- // println("SPEC")
158
- // println(specification.toJson())
159
- //
160
- // println("ACTUAL")
161
- // println(branch1.getRootNode().toJson())
162
-
163
- assertAllNodesConformToSpec(specification, branch1.getRootNode())
164
- assertNoOverlappingOperations(importer.stats)
165
- assert (importer.stats!! .getTotal() <= numChanges) {
166
- " expected operations: <= $numChanges , actual: ${importer.stats!! .getTotal()} "
167
- }
171
+ assertAllNodesConformToSpec(specification, otBranch.getRootNode())
172
+ }
173
+ val operations = otBranch.operationsAndTree.first
174
+ assertNoOverlappingOperations(operations)
175
+
176
+ val numSetOriginalIdOps = specification.countNodes()
177
+ val expectedNumOps = numChanges + numSetOriginalIdOps
178
+
179
+ assert (operations.size <= expectedNumOps ) {
180
+ " expected operations: <= $expectedNumOps , actual: ${operations.size} "
168
181
}
169
182
}
170
183
}
0 commit comments