apps\online\src\test\java\cn\nfarms\online\MergeTest.kt¶
源码路径:
apps\online\src\test\java\cn\nfarms\online\MergeTest.kt· 97 行
package cn.nfarms.online
import cn.nfarms.online.data.Merge
import cn.nfarms.online.data.MergeResult
import cn.nfarms.online.data.Ticket
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
/**
* 三路合并。
*
* 这四条分支(只有远端改 / 只有本地改 / 都改且一样 / 都改且不同)
* 就是「冲突合并」的全部逻辑;真机上看到"冲突弹窗"只是它的表现。
*/
class MergeTest {
private val base = Ticket(
id = "T-1",
title = "打印机卡纸",
body = "二楼东侧",
status = "open",
updatedAt = 1_000,
rev = 3,
)
@Test
fun only_remote_changed_takes_remote() {
val local = base
val remote = base.copy(title = "打印机卡纸(已派人)", rev = 4)
val r = Merge.merge(local, remote, base)
assertTrue(r is MergeResult.TookRemote)
assertEquals("打印机卡纸(已派人)", (r as MergeResult.TookRemote).ticket.title)
}
@Test
fun only_local_changed_keeps_local() {
val local = base.copy(body = "三楼西侧")
val remote = base
val r = Merge.merge(local, remote, base)
assertTrue(r is MergeResult.KeptLocal)
}
@Test
fun both_changed_to_the_same_content_is_not_a_conflict() {
val local = base.copy(title = "已修好")
val remote = base.copy(title = "已修好", rev = 5)
val r = Merge.merge(local, remote, base)
// 内容一致 → 不是冲突;保留本地内容。
// 之所以不是 TookRemote:结论虽然一样,但"这次改动是谁的"要留给审计。
assertTrue(r is MergeResult.KeptLocal)
}
@Test
fun both_changed_differently_is_a_conflict() {
val local = base.copy(title = "我改的")
val remote = base.copy(title = "他改的", rev = 6)
val r = Merge.merge(local, remote, base)
assertTrue(r is MergeResult.Conflict)
val c = r as MergeResult.Conflict
assertEquals("我改的", c.local.title)
assertEquals("他改的", c.remote.title)
assertEquals(base.rev, c.base?.rev)
}
/** 没有基线时不能瞎猜:内容一致就合并,不一致就必须报冲突。 */
@Test
fun missing_base_falls_back_to_conservative_behaviour() {
val a = base.copy(rev = 0)
assertEquals(MergeResult.Identical, Merge.merge(a, a, null))
val b = a.copy(title = "x")
assertTrue(Merge.merge(a, b, null) is MergeResult.Conflict)
}
/** 「用我的」必须把 rev 对齐到远端,否则下次同步又会被判冲突。 */
@Test
fun take_mine_aligns_rev_with_remote() {
val local = base.copy(title = "我改的")
val remote = base.copy(title = "他改的", rev = 9)
val mine = Merge.takeMine(local, remote)
assertEquals(9, mine.rev)
assertEquals("我改的", mine.title)
}
/** 附件也算内容:只有附件变了同样要能识别成"本地改了"。 */
@Test
fun attachment_change_counts_as_content_change() {
val withAttach = base.copy(
attachments = listOf(
cn.nfarms.online.data.Attachment("A1", "a.png", 100, "abc"),
),
)
val r = Merge.merge(withAttach, base, base)
assertTrue("只有本地加了附件,应当是 KeptLocal", r is MergeResult.KeptLocal)
}
}