package org.the_jk.cleversync.io import com.google.common.truth.Truth.assertThat import org.junit.Assume import org.junit.Before import org.junit.Test abstract class BaseVerifierTest { private lateinit var src: ModifiableTree private lateinit var tgt: ModifiableTree private val memory = FakeMemory() @Before fun setUp() { src = source() tgt = target() } @Test fun empty() { assertThat(Verifier.calculate(tgt, src, memory)).isEmpty() assertThat(memory.isEmpty()).isTrue() } @Test fun contentMatchNoMemory() { val sourceFoo = src.createFile("foo") sourceFoo.write().use { it.write(CONTENT1) } val targetFoo = tgt.createFile("foo") targetFoo.write().use { it.write(CONTENT1) } assertThat(Verifier.calculate(tgt, src, memory)).isEmpty() assertThat(memory.get("/foo")).isEqualTo(HASH1) } @Test fun contentMatchMemory() { memory.put("/foo", HASH1) val sourceFoo = src.createFile("foo") // Intentionally wrong, to show that source is not read when memory hash matches sourceFoo.write().use { it.write(0) } val targetFoo = tgt.createFile("foo") targetFoo.write().use { it.write(CONTENT1) } assertThat(Verifier.calculate(tgt, src, memory)).isEmpty() } @Test fun contentMatchMemoryOldFormat() { Assume.assumeTrue(Hasher.DEFAULT != Hasher.Format.SHA160) memory.put("/foo", HASH1_OLD) val sourceFoo = src.createFile("foo") // Intentionally wrong, to show that source is not read when memory hash matches sourceFoo.write().use { it.write(0) } val targetFoo = tgt.createFile("foo") targetFoo.write().use { it.write(CONTENT1) } assertThat(Verifier.calculate(tgt, src, memory)).isEmpty() } @Test fun contentMismatchNoMemory() { val sourceFoo = src.createFile("foo") sourceFoo.write().use { it.write(CONTENT1) } val targetFoo = tgt.createFile("foo") targetFoo.write().use { it.write(CONTENT2) } val actions = Verifier.calculate(tgt, src, memory) assertThat(actions).containsExactly(Action.Copy(name = "foo", overwrite = true)) assertThat(Modifier.apply(tgt, src, actions, memory = memory)).isEmpty() assertThat(memory.get("/foo")).isEqualTo(HASH1) assertThat(targetFoo.read().use { it.readBytes() }) .isEqualTo(CONTENT1) } @Test fun contentMismatchMemory() { memory.put("/foo", HASH1) val sourceFoo = src.createFile("foo") sourceFoo.write().use { it.write(CONTENT1) } val targetFoo = tgt.createFile("foo") targetFoo.write().use { it.write(CONTENT2) } val actions = Verifier.calculate(tgt, src, memory) assertThat(actions).containsExactly(Action.Copy(name = "foo", overwrite = true)) assertThat(Modifier.apply(tgt, src, actions, memory = memory)).isEmpty() assertThat(memory.get("/foo")).isEqualTo(HASH1) assertThat(targetFoo.read().use { it.readBytes() }) .isEqualTo(CONTENT1) } @Test fun contentMismatchMemoryOldFormat() { memory.put("/foo", HASH1_OLD) val sourceFoo = src.createFile("foo") sourceFoo.write().use { it.write(CONTENT1) } val targetFoo = tgt.createFile("foo") targetFoo.write().use { it.write(CONTENT2) } val actions = Verifier.calculate(tgt, src, memory) assertThat(actions).containsExactly(Action.Copy(name = "foo", overwrite = true)) assertThat(Modifier.apply(tgt, src, actions, memory = memory)).isEmpty() assertThat(memory.get("/foo")).isEqualTo(HASH1) assertThat(targetFoo.read().use { it.readBytes() }) .isEqualTo(CONTENT1) } @Test fun contentMismatchBadMemory() { memory.put("/foo", "".toByteArray().inputStream().use { Hasher.hash(it)!! }) val sourceFoo = src.createFile("foo") sourceFoo.write().use { it.write(CONTENT1) } val targetFoo = tgt.createFile("foo") targetFoo.write().use { it.write(CONTENT2) } val actions = Verifier.calculate(tgt, src, memory) assertThat(actions).containsExactly(Action.Copy(name = "foo", overwrite = true)) assertThat(Modifier.apply(tgt, src, actions, memory = memory)).isEmpty() assertThat(memory.get("/foo")).isEqualTo(HASH1) assertThat(targetFoo.read().use { it.readBytes() }) .isEqualTo(CONTENT1) } @Test fun contentMismatchBadMemory2() { memory.put("/foo", HASH2) val sourceFoo = src.createFile("foo") sourceFoo.write().use { it.write(CONTENT1) } val targetFoo = tgt.createFile("foo") targetFoo.write().use { it.write(CONTENT2) } // We trust memory, so source will not be read and the difference // will not be noticed. Remember that this is used together with merge. assertThat(Verifier.calculate(tgt, src, memory)).isEmpty() } @Test fun contentMismatchNoSource() { val targetFoo = tgt.createFile("foo") targetFoo.write().use { it.write(CONTENT2) } assertThat(Verifier.calculate(tgt, src, memory)).isEmpty() } @Test fun contentMismatchMemoryNoSource() { memory.put("/foo", HASH1) val targetFoo = tgt.createFile("foo") targetFoo.write().use { it.write(CONTENT2) } assertThat(Verifier.calculate(tgt, src, memory)).isEmpty() } @Test fun dirContentMatchMemory() { memory.put("/foo/bar", HASH1) val sourceFoo = src.createDirectory("foo").createFile("bar") // Intentionally wrong, to show that source is not read when memory hash matches sourceFoo.write().use { it.write(0) } val targetFoo = tgt.createDirectory("foo").createFile("bar") targetFoo.write().use { it.write(CONTENT1) } assertThat(Verifier.calculate(tgt, src, memory)).isEmpty() } @Test fun dirContentMismatchNoMemory() { val sourceFoo = src.createDirectory("foo").createFile("bar") sourceFoo.write().use { it.write(CONTENT1) } val targetFoo = tgt.createDirectory("foo").createFile("bar") targetFoo.write().use { it.write(CONTENT2) } val actions = Verifier.calculate(tgt, src, memory) assertThat(actions).containsExactly( Action.ChangeDir( name = "foo", actions = listOf(Action.Copy(name = "bar", overwrite = true)), ), ) assertThat(Modifier.apply(tgt, src, actions, memory = memory)).isEmpty() assertThat(memory.get("/foo/bar")).isEqualTo(HASH1) assertThat(targetFoo.read().use { it.readBytes() }) .isEqualTo(CONTENT1) } @Test fun dirContentMismatchMemory() { memory.put("/foo/bar", HASH1) val sourceFoo = src.createDirectory("foo").createFile("bar") sourceFoo.write().use { it.write(CONTENT1) } val targetFoo = tgt.createDirectory("foo").createFile("bar") targetFoo.write().use { it.write(CONTENT2) } val actions = Verifier.calculate(tgt, src, memory) assertThat(actions).containsExactly( Action.ChangeDir( name = "foo", actions = listOf(Action.Copy(name = "bar", overwrite = true)), ), ) assertThat(Modifier.apply(tgt, src, actions, memory = memory)).isEmpty() assertThat(memory.get("/foo/bar")).isEqualTo(HASH1) assertThat(targetFoo.read().use { it.readBytes() }) .isEqualTo(CONTENT1) } abstract fun source(): ModifiableTree abstract fun target(): ModifiableTree private class FakeMemory : Verifier.Memory { private val data = mutableMapOf() override fun get(path: String) = data[path] override fun put(path: String, hash: String) { data[path] = hash } fun isEmpty() = data.isEmpty() } private companion object { val CONTENT1 = "Hello world".toByteArray() val HASH1 = CONTENT1.inputStream().use { Hasher.hash(it)!! } val HASH1_OLD = CONTENT1.inputStream().use { Hasher.hash(it, Hasher.Format.SHA160)!! } val CONTENT2 = "Goodbye world".toByteArray() val HASH2 = CONTENT2.inputStream().use { Hasher.hash(it)!! } } }