cmd_back_test.v

4.0 KB · raw

1module cli23import os4import src.history5import src.snapshot6import src.storage78// The history view's `l` key goes through restore_now, which a CLI test cannot9// reach without a terminal, so it is checked here directly.10// Global rules must not make source fixtures depend on the developer’s home.11fn testsuite_begin() {12	os.setenv('HOME', os.join_path(os.temp_dir(), 'koh3-test-home-${os.getpid()}'), true)13}1415fn 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}5051// The restore's save is recorded before its files are written. A kill between52// the two must still leave the mark, so the mark goes down first.53fn 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	// Any save recorded while the mark is missing aborts the restore.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}7980// A revert finishing an earlier restore must not lift that restore's mark when81// it fails to record anything itself.82fn 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	// An object the store does not have makes recording the save fail.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}