view_test.v

5.0 KB · raw

1module view23import src.events4import src.fmt5import src.history6import src.snapshot78fn save(id string, message string, checkpoint bool) history.Save {9	return history.Save{10		id:            id11		message:       message12		created_at:    179000000013		size_bytes:    102414		is_checkpoint: checkpoint15	}16}1718fn line_map(ids []string) map[string]bool {19	mut out := map[string]bool{}20	for id in ids {21		out[id] = true22	}23	return out24}2526fn test_tabs_filter_by_what_is_on_the_line() {27	// A combine replays the local save `bbb` as `ddd`: the copy is on the line,28	// the original is not.29	on_the_line := line_map(['aaa', 'ccc', 'ddd'])30	mut copy := save('ddd', 'my work, replayed', false)31	copy.replayed_from = 'bbb'32	items := [save('aaa', 'first', false), save('bbb', 'my work', false),33		save('ccc', 'before things', true), copy]3435	assert filter_saves(items, .all, on_the_line, '').len == 436	// The replayed-away original exists in history but is on neither live list;37	// the copy that replaced it is an ordinary save on the line.38	assert filter_saves(items, .saves, on_the_line, '').map(it.id) == ['aaa', 'ccc', 'ddd']39	assert filter_saves(items, .checkpoints, on_the_line, '').map(it.id) == ['ccc']40}4142fn test_only_the_replayed_away_original_is_marked() {43	on_the_line := line_map(['ddd'])44	mut copy := save('ddd', 'my work, replayed', false)45	copy.replayed_from = 'bbb'46	screen := Screen{47		on_line: on_the_line48	}49	assert fmt.strip_ansi(save_mark(save('bbb', 'my work', false), screen)) == '↪'50	assert fmt.strip_ansi(save_mark(copy, screen)) == ' '51	assert entry_line(save('bbb', 'my work', false), false, screen).contains('replayed away')52	assert !entry_line(copy, false, screen).contains('replayed away')53}5455fn test_search_is_case_insensitive_across_the_fields() {56	on_the_line := line_map(['aaa', 'bbb', 'ccc'])57	mut with_agent := save('bbb', 'fix chunk boundary', false)58	with_agent.agent = 'DeepSeek/Flash'59	mut with_session := save('ccc', 'other work', false)60	with_session.session = 'phase one'61	items := [save('aaa', 'add storage', false), with_agent, with_session]6263	assert filter_saves(items, .all, on_the_line, 'STORAGE').map(it.id) == ['aaa']64	assert filter_saves(items, .all, on_the_line, 'chunk').map(it.id) == ['bbb']65	assert filter_saves(items, .all, on_the_line, 'deepseek').map(it.id) == ['bbb']66	assert filter_saves(items, .all, on_the_line, 'PHASE').map(it.id) == ['ccc']67	assert filter_saves(items, .all, on_the_line, 'nothing here').len == 068}6970fn test_move_selection_clamps_at_both_ends() {71	assert move_selection(0, 1, 3) == 172	assert move_selection(2, 1, 3) == 273	assert move_selection(0, -1, 3) == 074	assert move_selection(0, 0, 0) == 075	assert move_selection(5, 1, 0) == 076	// G asks for a move past the end and lands on the last entry.77	assert move_selection(3, -1, 3) == 278}7980fn test_detail_lists_files_with_stats_and_notes_binaries() {81	target := save('aaa', 'change two files', false)82	flag := events.Flag{83		save_id: 'aaa'84		flagged: true85		reason:  'sketchy'86	}87	deltas := [88		snapshot.Delta{89			path:    'src/main.v'90			kind:    'modified'91			added:   492			removed: 293		},94		snapshot.Delta{95			path:   'logo.png'96			kind:   'added'97			binary: true98		},99	]100	text := detail_lines(target, deltas, flag).join('\n')101	assert text.contains('checksum  aaa')102	assert text.contains('flag      sketchy')103	assert text.contains('src/main.v')104	assert text.contains('+4')105	assert text.contains('-2')106	assert text.contains('logo.png')107	assert text.contains('(binary)')108	assert text.contains('2 files changed against the parent')109}110111fn test_detail_says_so_when_nothing_changed() {112	target := save('aaa', 'first save', false)113	text := detail_lines(target, [], events.Flag{114		save_id: 'aaa'115	}).join('\n')116	assert text.contains('nothing changed against the parent')117}118119fn test_frame_shows_counts_the_selected_entry_and_the_status_bar() {120	on_the_line := line_map(['aaa', 'ccc'])121	items := [save('aaa', 'first', false), save('ccc', 'before storage', true)]122	screen := Screen{123		tab:      .all124		items:    items125		selected: 1126		on_line:  on_the_line127		counts:   count_tabs(items, on_the_line)128		rows:     24129		cols:     100130		status:   '3 shown'131	}132	text := frame_lines(screen).join('\n')133	assert text.contains('all (2)')134	assert text.contains('checkpoints (1)')135	assert text.contains('before storage')136	assert text.contains('aaa')137	// The selected entry carries its extra line.138	assert text.contains('agent')139	assert text.contains('◐')140	assert text.contains('3 shown')141}142143fn test_frame_says_no_results_when_the_search_matches_nothing() {144	screen := Screen{145		tab:    .all146		rows:   24147		cols:   80148		query:  'nothing matches this'149		counts: TabCounts{}150	}151	text := frame_lines(screen).join('\n')152	assert text.contains('no results')153	assert text.contains('/nothing matches this')154}155156fn test_render_clears_each_line_before_drawing_it() {157	screen := Screen{158		tab:  .saves159		rows: 6160		cols: 60161	}162	frame := render(screen)163	assert frame.starts_with('\x1b[H')164	// One line-clear per row drawn, so a shorter frame cannot leave the tail of165	// a longer one behind.166	assert frame.count('\x1b[2K') == frame_lines(screen).len167}