1module cli23import os4import src.history5import src.snapshot6import src.storage789fn testsuite_begin() {10 os.setenv('HOME', os.join_path(os.temp_dir(), 'koh3-test-home-${os.getpid()}'), true)11}12131415fn test_restore_now_refuses_to_overwrite_unsaved_work() {16 dir := os.join_path(os.temp_dir(), 'koh3_cli_restore_now_${os.getpid()}')17 os.rmdir_all(dir) or {}18 os.mkdir_all(dir)!19 defer {20 os.rmdir_all(dir) or {}21 }22 store := storage.create(dir)!23 defer {24 store.close()25 }26 path := os.join_path(dir, 'a.txt')27 os.write_file(path, 'one\n')!28 first := history.save_worktree(store, dir, snapshot.load(dir), history.SaveInput{29 message: 'one'30 })!31 os.write_file(path, 'two\n')!32 history.save_worktree(store, dir, snapshot.load(dir), history.SaveInput{33 message: 'two'34 })!35 os.write_file(path, 'unsaved\n')!36 if _ := restore_now(store, first, 'load') {37 assert false, 'restore_now overwrote unsaved work'38 } else {39 assert err.msg() == unsaved_changes40 }41 assert os.read_file(path)! == 'unsaved\n'42}4344fn test_a_peek_is_old_only_after_more_than_a_day() {45 now := i64(1_000_000)46 assert !peek_is_old(now, now)47 assert !peek_is_old(now - peek_age, now)48 assert peek_is_old(now - peek_age - 1, now)49}50515253fn test_a_restore_is_marked_before_its_save_is_recorded() {54 dir := os.join_path(os.temp_dir(), 'koh3_cli_mark_first_${os.getpid()}')55 os.rmdir_all(dir) or {}56 os.mkdir_all(dir)!57 defer {58 os.rmdir_all(dir) or {}59 }60 store := storage.create(dir)!61 defer {62 store.close()63 }64 os.write_file(os.join_path(dir, 'a.txt'), 'one\n')!65 first := history.save_worktree(store, dir, snapshot.load(dir), history.SaveInput{66 message: 'one'67 })!68 os.write_file(os.join_path(dir, 'a.txt'), 'two\n')!69 history.save_worktree(store, dir, snapshot.load(dir), history.SaveInput{70 message: 'two'71 })!72 73 store.db.exec("CREATE TEMP TRIGGER mark_first BEFORE INSERT ON saves74 WHEN NOT EXISTS (SELECT 1 FROM state WHERE key = 'restoring')75 BEGIN SELECT RAISE(ABORT, 'save recorded before the mark'); END")!76 apply_restore(store, first, 'load', plan_restore(store, first)!, false)!77 assert snapshot.restore_pending(store)78}79808182fn test_a_failed_restore_keeps_an_earlier_mark() {83 dir := os.join_path(os.temp_dir(), 'koh3_cli_keep_mark_${os.getpid()}')84 os.rmdir_all(dir) or {}85 os.mkdir_all(dir)!86 defer {87 os.rmdir_all(dir) or {}88 }89 store := storage.create(dir)!90 defer {91 store.close()92 }93 os.write_file(os.join_path(dir, 'a.txt'), 'one\n')!94 first := history.save_worktree(store, dir, snapshot.load(dir), history.SaveInput{95 message: 'one'96 })!97 snapshot.mark_restore(store)!98 99 broken := RestorePlan{100 files: [snapshot.FileEntry{101 path: 'a.txt'102 hash: 'not-an-object'103 }]104 }105 if _ := apply_restore(store, first, 'revert', broken, false) {106 assert false, 'recording a save with a missing object should fail'107 }108 assert snapshot.restore_pending(store)109}110111fn test_ignore_write_refuses_stale_rules_and_preserves_permissions() {112 dir := os.join_path(os.temp_dir(), 'koh3_cli_ignore_${os.getpid()}')113 os.mkdir_all(dir)!114 defer { os.rmdir_all(dir) or {} }115 file := os.join_path(dir, '.kohignore')116 os.write_file(file, '# changed\n')!117 if _ := write_ignore(file, '# original\n', '/cache/\n') {118 assert false, 'stale preview replaced changed rules'119 }120 assert os.read_file(file)! == '# changed\n'121 os.chmod(file, 0o600)!122 write_ignore(file, '# changed\n', '# changed\n/cache/\n')!123 assert os.stat(file)!.mode & 0o777 == 0o600124 assert os.read_file(file)! == '# changed\n/cache/\n'125 assert os.ls(dir)! == ['.kohignore']126}