Skip to content

Commit 44be8e9

Browse files
committed
More SceneEditorRepository tests
Fixed SceneEditorRepository ReId, geez, were they all broken?!
1 parent 6774948 commit 44be8e9

File tree

4 files changed

+312
-6
lines changed

4 files changed

+312
-6
lines changed

common/src/commonMain/kotlin/com/darkrockstudios/apps/hammer/common/data/sceneeditorrepository/SceneEditorRepository.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ abstract class SceneEditorRepository(
292292
abstract fun getLastOrderNumber(parentPath: HPath): Int
293293
abstract suspend fun updateSceneOrder(parentId: Int)
294294
abstract suspend fun moveScene(moveRequest: MoveRequest)
295-
abstract suspend fun renameScene(sceneItem: SceneItem, newName: String)
295+
abstract suspend fun renameScene(sceneItem: SceneItem, newName: String): Boolean
296296

297297
fun getSceneSummaries(): SceneSummary {
298298
return SceneSummary(

common/src/commonMain/kotlin/com/darkrockstudios/apps/hammer/common/data/sceneeditorrepository/SceneEditorRepositoryOkio.kt

+16-5
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,19 @@ class SceneEditorRepositoryOkio(
147147

148148
val oldScene = getSceneItemFromId(oldId) ?: throw IOException("Scene $oldId does not exist")
149149
val newScene = oldScene.copy(id = newId)
150-
val newPath = getSceneFilePath(newScene)
150+
val newFileName = getSceneFileName(newScene)
151+
val parent = oldPath.toOkioPath().parent ?: error("Scene ID $oldId path had not parent")
152+
val newPath = parent / newFileName
151153

152-
fileSystem.atomicMove(oldPath.toOkioPath(), newPath.toOkioPath())
154+
fileSystem.atomicMove(oldPath.toOkioPath(), newPath)
153155

154156
metadataDatasource.reIdSceneMetadata(oldId, newId)
157+
158+
// Update the in-tree representation
159+
val node = getSceneNodeFromId(oldId) ?: error("reIdScene: Failed to get node for ID $oldId")
160+
node.value = node.value.copy(
161+
id = newId
162+
)
155163
}
156164

157165
override fun getSceneDirectory() = sceneDatasource.getSceneDirectory()
@@ -169,7 +177,8 @@ class SceneEditorRepositoryOkio(
169177
override fun getSceneFilePath(sceneItem: SceneItem, isNewScene: Boolean): HPath {
170178
val scenePathSegment = getSceneDirectory().toOkioPath()
171179

172-
val pathSegments: MutableList<String> = sceneTree.getBranch(true) { it.id == sceneItem.id }
180+
val pathSegments: MutableList<String> = sceneTree
181+
.getBranch(true) { it.id == sceneItem.id }
173182
.map { node -> node.value }
174183
.filter { scene -> !scene.isRootScene }
175184
.map { scene -> getSceneFileName(scene) }
@@ -866,8 +875,8 @@ class SceneEditorRepositoryOkio(
866875
return numScenes
867876
}
868877

869-
override suspend fun renameScene(sceneItem: SceneItem, newName: String) {
870-
markForSynchronization(sceneItem)
878+
override suspend fun renameScene(sceneItem: SceneItem, newName: String): Boolean {
879+
if (validateSceneName(newName).isFailure) return false
871880

872881
val cleanedNamed = newName.trim()
873882

@@ -881,8 +890,10 @@ class SceneEditorRepositoryOkio(
881890
val newPath = getSceneFilePath(newDef).toOkioPath()
882891

883892
fileSystem.atomicMove(oldPath, newPath)
893+
markForSynchronization(sceneItem)
884894

885895
reloadScenes()
896+
return true
886897
}
887898
}
888899

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
package repositories.sceneeditor
2+
3+
import PROJECT_1_NAME
4+
import com.darkrockstudios.apps.hammer.common.data.ProjectDef
5+
import com.darkrockstudios.apps.hammer.common.data.SceneBuffer
6+
import com.darkrockstudios.apps.hammer.common.data.SceneContent
7+
import com.darkrockstudios.apps.hammer.common.data.SceneItem
8+
import com.darkrockstudios.apps.hammer.common.data.UpdateSource
9+
import com.darkrockstudios.apps.hammer.common.data.id.IdRepository
10+
import com.darkrockstudios.apps.hammer.common.data.projectmetadata.ProjectMetadataDatasource
11+
import com.darkrockstudios.apps.hammer.common.data.projectsync.ClientProjectSynchronizer
12+
import com.darkrockstudios.apps.hammer.common.data.sceneeditorrepository.SceneDatasource
13+
import com.darkrockstudios.apps.hammer.common.data.sceneeditorrepository.SceneEditorRepository
14+
import com.darkrockstudios.apps.hammer.common.data.sceneeditorrepository.SceneEditorRepositoryOkio
15+
import com.darkrockstudios.apps.hammer.common.data.sceneeditorrepository.scenemetadata.SceneMetadataDatasource
16+
import com.darkrockstudios.apps.hammer.common.dependencyinjection.createTomlSerializer
17+
import createProject
18+
import getProject1Def
19+
import io.mockk.MockKAnnotations
20+
import io.mockk.Runs
21+
import io.mockk.coEvery
22+
import io.mockk.coVerify
23+
import io.mockk.impl.annotations.MockK
24+
import io.mockk.just
25+
import io.mockk.mockk
26+
import io.mockk.slot
27+
import kotlinx.coroutines.cancelAndJoin
28+
import kotlinx.coroutines.test.advanceUntilIdle
29+
import kotlinx.coroutines.test.runTest
30+
import net.peanuuutz.tomlkt.Toml
31+
import okio.fakefilesystem.FakeFileSystem
32+
import org.junit.jupiter.api.BeforeEach
33+
import org.junit.jupiter.api.Test
34+
import utils.BaseTest
35+
import kotlin.test.assertEquals
36+
import kotlin.test.assertFalse
37+
import kotlin.test.assertTrue
38+
39+
class SceneEditorRepositoryBufferTest : BaseTest() {
40+
41+
private lateinit var ffs: FakeFileSystem
42+
private lateinit var toml: Toml
43+
44+
@MockK
45+
private lateinit var projectSynchronizer: ClientProjectSynchronizer
46+
47+
@MockK
48+
private lateinit var idRepository: IdRepository
49+
50+
@MockK
51+
private lateinit var projectMetadataDatasource: ProjectMetadataDatasource
52+
53+
private lateinit var sceneMetadataDatasource: SceneMetadataDatasource
54+
private lateinit var sceneDatasource: SceneDatasource
55+
56+
@BeforeEach
57+
override fun setup() {
58+
super.setup()
59+
ffs = FakeFileSystem()
60+
toml = createTomlSerializer()
61+
projectMetadataDatasource = ProjectMetadataDatasource(ffs, toml)
62+
MockKAnnotations.init(this, relaxUnitFun = true)
63+
setupKoin()
64+
65+
coEvery { projectMetadataDatasource.loadMetadata(any()) } returns mockk(relaxed = true)
66+
coEvery { projectSynchronizer.isServerSynchronized() } returns false
67+
coEvery { projectSynchronizer.isEntityDirty(any()) } returns false
68+
coEvery { projectSynchronizer.markEntityAsDirty(any(), any()) } just Runs
69+
}
70+
71+
private fun createDatasource(projectDef: ProjectDef): SceneMetadataDatasource {
72+
return SceneMetadataDatasource(ffs, toml, projectDef)
73+
}
74+
75+
private fun createSceneDatasource(projectDef: ProjectDef): SceneDatasource {
76+
return SceneDatasource(projectDef, ffs)
77+
}
78+
79+
private fun createRepository(projectDef: ProjectDef): SceneEditorRepository {
80+
sceneMetadataDatasource = createDatasource(projectDef)
81+
sceneDatasource = createSceneDatasource(projectDef)
82+
return SceneEditorRepositoryOkio(
83+
projectDef = projectDef,
84+
projectSynchronizer = projectSynchronizer,
85+
fileSystem = ffs,
86+
idRepository = idRepository,
87+
projectMetadataDatasource = projectMetadataDatasource,
88+
sceneMetadataDatasource = sceneMetadataDatasource,
89+
sceneDatasource = sceneDatasource,
90+
)
91+
}
92+
93+
@Test
94+
fun `Subscribe to Buffer Updates`() = runTest(mainTestDispatcher) {
95+
val projDef = getProject1Def()
96+
createProject(ffs, PROJECT_1_NAME)
97+
98+
val repo = createRepository(projDef)
99+
repo.initializeSceneEditor()
100+
101+
val newContent = SceneContent(
102+
scene = SceneItem(
103+
projectDef = getProject1Def(),
104+
type = SceneItem.Type.Scene,
105+
id = 1,
106+
name = "Scene ID 1",
107+
order = 0
108+
),
109+
markdown = "New Content!!"
110+
)
111+
112+
val onBufferUpdate: (suspend (SceneBuffer) -> Unit) = mockk()
113+
val sceneBufferSlot = slot<SceneBuffer>()
114+
coEvery { onBufferUpdate(capture(sceneBufferSlot)) } just Runs
115+
116+
val subJob = repo.subscribeToBufferUpdates(null, scope, onBufferUpdate)
117+
118+
repo.onContentChanged(newContent, UpdateSource.Editor)
119+
advanceUntilIdle()
120+
subJob.cancelAndJoin()
121+
coVerify(exactly = 1) { onBufferUpdate(any()) }
122+
123+
assertTrue(sceneBufferSlot.isCaptured)
124+
val updated = sceneBufferSlot.captured
125+
assertEquals(newContent.scene, updated.content.scene)
126+
assertEquals(UpdateSource.Editor, updated.source)
127+
assertEquals(newContent.markdown, updated.content.markdown)
128+
}
129+
130+
@Test
131+
fun `Subscribe to Buffer Updates for one scene`() = runTest(mainTestDispatcher) {
132+
val projDef = getProject1Def()
133+
createProject(ffs, PROJECT_1_NAME)
134+
135+
val repo = createRepository(projDef)
136+
repo.initializeSceneEditor()
137+
138+
val sceneItem2 = SceneItem(
139+
projectDef = getProject1Def(),
140+
type = SceneItem.Type.Scene,
141+
id = 3,
142+
name = "Scene ID 3",
143+
order = 0
144+
)
145+
146+
val newContent = SceneContent(
147+
scene = SceneItem(
148+
projectDef = getProject1Def(),
149+
type = SceneItem.Type.Scene,
150+
id = 1,
151+
name = "Scene ID 1",
152+
order = 0
153+
),
154+
markdown = "New Content!!"
155+
)
156+
157+
val onBufferUpdate: (suspend (SceneBuffer) -> Unit) = mockk()
158+
coEvery { onBufferUpdate(any()) } just Runs
159+
160+
val subJob = repo.subscribeToBufferUpdates(sceneItem2, scope, onBufferUpdate)
161+
repo.onContentChanged(newContent, UpdateSource.Editor)
162+
advanceUntilIdle()
163+
subJob.cancelAndJoin()
164+
coVerify(exactly = 0) { onBufferUpdate(any()) }
165+
}
166+
167+
@Test
168+
fun `Store Scene Buffer when no buffer is loaded`() = runTest(mainTestDispatcher) {
169+
val projDef = getProject1Def()
170+
createProject(ffs, PROJECT_1_NAME)
171+
172+
val repo = createRepository(projDef)
173+
repo.initializeSceneEditor()
174+
175+
val sceneItem = SceneItem(
176+
projectDef = getProject1Def(),
177+
type = SceneItem.Type.Scene,
178+
id = 3,
179+
name = "Scene ID 3",
180+
order = 0
181+
)
182+
183+
val stored = repo.storeSceneBuffer(sceneItem)
184+
assertFalse(stored)
185+
}
186+
187+
@Test
188+
fun `Load Scene Buffer, then store it`() = runTest(mainTestDispatcher) {
189+
val projDef = getProject1Def()
190+
createProject(ffs, PROJECT_1_NAME)
191+
192+
val repo = createRepository(projDef)
193+
repo.initializeSceneEditor()
194+
195+
val sceneItem = SceneItem(
196+
projectDef = getProject1Def(),
197+
type = SceneItem.Type.Scene,
198+
id = 3,
199+
name = "Scene ID 3",
200+
order = 0
201+
)
202+
203+
val buffer = repo.loadSceneBuffer(sceneItem)
204+
assertEquals(sceneItem, buffer.content.scene)
205+
assertEquals("Content of scene id 3", buffer.content.markdown)
206+
207+
val stored = repo.storeSceneBuffer(sceneItem)
208+
assertTrue(stored)
209+
}
210+
}

common/src/desktopTest/kotlin/repositories/sceneeditor/SceneEditorRepositoryOtherTest.kt

+85
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import com.darkrockstudios.apps.hammer.common.fileio.okio.toHPath
2727
import com.darkrockstudios.apps.hammer.common.fileio.okio.toOkioPath
2828
import com.darkrockstudios.apps.hammer.common.getDefaultRootDocumentDirectory
2929
import createProject
30+
import getProject1Def
3031
import io.mockk.coEvery
3132
import io.mockk.every
3233
import io.mockk.mockk
@@ -424,4 +425,88 @@ class SceneEditorRepositoryOtherTest : BaseTest() {
424425
val groupPostDelete = repo.getSceneItemFromId(groupId)
425426
assertNull(groupPostDelete, "Group still existed in tree")
426427
}
428+
429+
@Test
430+
fun `Rename Scene`() = runTest {
431+
configure(PROJECT_1_NAME)
432+
433+
every { ProjectsRepository.validateFileName(any()) } returns CResult.success()
434+
435+
repo.initializeSceneEditor()
436+
437+
val newSceneName = "New Scene Name"
438+
val sceneItem = SceneItem(
439+
projectDef = getProject1Def(),
440+
type = SceneItem.Type.Scene,
441+
id = 1,
442+
name = "Scene ID 1",
443+
order = 0
444+
)
445+
446+
val success = repo.renameScene(sceneItem, newSceneName)
447+
assertTrue(success)
448+
449+
val renamedScene = repo.getSceneItemFromId(sceneItem.id)
450+
assertEquals(newSceneName, renamedScene?.name)
451+
452+
val path = repo.getSceneFilePath(sceneItem.id)
453+
val loadedScene = repo.getSceneFromFilename(path)
454+
assertEquals(newSceneName, loadedScene.name)
455+
assertTrue(ffs.exists(path.toOkioPath()))
456+
}
457+
458+
@Test
459+
fun `Rename Scene with invalid name`() = runTest {
460+
configure(PROJECT_1_NAME)
461+
462+
every { ProjectsRepository.validateFileName(any()) } returns CResult.failure(
463+
ValidationFailedException(MR.strings.create_project_error_blank)
464+
)
465+
466+
repo.initializeSceneEditor()
467+
468+
val newSceneName = ""
469+
val sceneItem = SceneItem(
470+
projectDef = getProject1Def(),
471+
type = SceneItem.Type.Scene,
472+
id = 1,
473+
name = "Scene ID 1",
474+
order = 0
475+
)
476+
477+
val success = repo.renameScene(sceneItem, newSceneName)
478+
assertFalse(success)
479+
480+
val renamedScene = repo.getSceneItemFromId(sceneItem.id)
481+
assertNotEquals(newSceneName, renamedScene?.name)
482+
}
483+
484+
@Test
485+
fun `ReId Scene`() = runTest {
486+
configure(PROJECT_1_NAME)
487+
488+
every { ProjectsRepository.validateFileName(any()) } returns CResult.success()
489+
490+
repo.initializeSceneEditor()
491+
492+
val oldId = 7
493+
val newId = 8
494+
495+
val sceneItem = SceneItem(
496+
projectDef = getProject1Def(),
497+
type = SceneItem.Type.Scene,
498+
id = 7,
499+
name = "Scene ID 7",
500+
order = 3
501+
)
502+
503+
val oldScene = repo.getSceneFilePath(sceneItem).toOkioPath()
504+
assertTrue(ffs.exists(oldScene))
505+
506+
repo.reIdScene(oldId = oldId, newId = newId)
507+
508+
assertFalse(ffs.exists(oldScene))
509+
val newScene = repo.getSceneFilePath(sceneItem.copy(id = newId)).toOkioPath()
510+
assertTrue(ffs.exists(newScene))
511+
}
427512
}

0 commit comments

Comments
 (0)