1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
package coffee.liz.rookery
import coffee.liz.rookery.importer.CsTimerImport
import coffee.liz.rookery.importer.Importer
import coffee.liz.rookery.importer.LetterPairGymImport
import coffee.liz.rookery.model.Event
import coffee.liz.rookery.model.Penalty
import coffee.liz.rookery.store.MemoryBlobStore
import coffee.liz.rookery.store.MemoryLogStorage
import coffee.liz.rookery.store.Repo
import coffee.liz.rookery.store.Store
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
class ImportTest {
private val csTimer = """
{"session1":[
[[0,114010],"Uw' L2 D L' R2 Dw D' R' F D Bw2 B2 Lw2 D2 Rw' Dw2 Lw' U' Dw' F2 B2 Rw D' Dw2 Lw2 R2 B2 Dw' Fw' Rw B2 Lw2 Uw' D F' Bw2 U Uw Bw2 F' R Dw2 Uw Rw' Dw D2 U Uw Lw' B2 F R' Uw2 B' R Lw2 B Lw L2 B'","",1794373390],
[[0,25058],"B' R' F2 U2 L2 F2 U2 B' L2 B2 U2 F' R2 U' F2 L D' L' B L2 F","",1794526179,["U'@0 L'@200","333"]],
[[2000,14039],"R U F","nice",1794526518],
[[-1,14245],"D2 F","",1794534484]],
"session2":[[[0,4000],"R U R' U'","",1794534500]],
"properties":{"sessionData":"{\"1\":{\"name\":1,\"opt\":{}},\"2\":{\"name\":\"pyra\",\"opt\":{\"scrType\":\"pyrso\"}}}","giiMacMap":"{\"null\":\"AA:BB:CC:DD:EE:FF\"}"}}
""".trimIndent()
@Test fun parsesCsTimer() {
val r = CsTimerImport.parse(csTimer)
assertEquals(5, r.solves.size)
val events = r.solves.map { it.event }
assertEquals(listOf(Event.E555, Event.E333, Event.E333, Event.E333, Event.PYRAM), events)
assertEquals(listOf(Penalty.NONE, Penalty.NONE, Penalty.PLUS2, Penalty.DNF), r.solves.take(4).map { it.penalty })
assertEquals("U'@0 L'@200", r.solves[1].moves)
assertEquals(1794373390_000, r.solves[0].at)
assertEquals(3, r.sessions.size)
assertTrue(r.sessions.any { it.name == "csTimer 1 (5x5)" })
assertEquals("AA:BB:CC:DD:EE:FF", r.devices.single().mac)
}
@Test fun importIsIdempotent() {
val repo = Repo(Store("t", MemoryLogStorage(), MemoryBlobStore()) { 1 })
Importer(repo).csTimer(csTimer)
Importer(repo).csTimer(csTimer)
assertEquals(5, repo.solves().size)
assertEquals(3, repo.sessions().size)
assertEquals(1, repo.devices().size)
}
private val gym = """
{"app":"letter-pair-gym","v":1,"at":"2026-11-13T03:28:27.903Z",
"settings":{"edgeScheme":"ABCDQRSTEFGHIJKLMNOPUVWX","eBuf":2},
"words":{"AB":"abacus","AD":"adelie","XW":""},
"notes":{"AD":"adelie penguin"},
"wordHist":[{"d":1794519658205,"from":"Peg","p":"PG","to":"Postgres"}],
"stats":{"AB":{"k":1,"l":[689],"m":5,"ms":61704.39,"n":11,"r":"gsmmsg","s":4}},
"memoHist":[{"d":1794505722395,"ms":154339,"ok":8,"p":10}],
"solves":[],
"images":{"AB":"images/AB - abacus.jpg","AD":"images/AD - missing.jpg"}}
""".trimIndent()
@Test fun importsLetterPairGym() {
val parsed = LetterPairGymImport.parse(gym)
assertEquals(mapOf("AB" to "abacus", "AD" to "adelie"), parsed.words)
assertEquals(listOf(689L), parsed.stats.getValue("AB").latenciesMs)
val repo = Repo(Store("t", MemoryLogStorage(), MemoryBlobStore()) { 1 })
val summary = Importer(repo).letterPairGym(gym) { path -> if (path.startsWith("images/AB")) byteArrayOf(1, 2, 3) else null }
val pairs = repo.letterPairs()
assertEquals("abacus", pairs.getValue("AB").primary)
assertEquals("adelie penguin", pairs.getValue("AD").note)
assertTrue(pairs.getValue("AB").image!!.endsWith(".jpg"))
assertEquals(1, summary.warnings.size)
assertEquals("Postgres", repo.wordHistory().single().to)
assertEquals(1, repo.memoSessions().size)
}
}
|