Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 41 additions & 1 deletion src/pipeline/store_reducer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1962,6 +1962,7 @@ fn finalize_source_dependencies(
WHERE is_active = 1
AND language_id = 'go'
AND relative_path IS NOT NULL
ORDER BY relative_path
",
)
.map_err(StoreReducerError::WriteDatabase)?;
Expand Down Expand Up @@ -2277,7 +2278,8 @@ fn materialize_file_facts(
GROUP BY source_path
) source_out
ON file_analysis.relative_path = source_out.source_path
WHERE file_analysis.is_active = 1;
WHERE file_analysis.is_active = 1
ORDER BY file_analysis.relative_path;

INSERT OR REPLACE INTO stage_metadata (key, value)
VALUES
Expand Down Expand Up @@ -3648,6 +3650,44 @@ mod tests {
);
}

#[test]
fn materializes_source_packages_and_file_facts_in_relative_path_order() {
let fixture = Fixture::new("deterministic-file-lists");
write_fixture_file(&fixture.path, "b.go");
write_fixture_file(&fixture.path, "a.go");

let (event_sender, _event_receiver) = mpsc::channel();
let reducer =
StoreReducer::start(&fixture.path, StoreReducerOptions::default(), event_sender)
.expect("reducer should start");
let handle = reducer.handle();

handle
.store_file_analysis(file_result_with_imports(fixture.path.join("b.go"), &[]))
.expect("b file should enqueue");
handle
.store_file_analysis(file_result_with_imports(fixture.path.join("a.go"), &[]))
.expect("a file should enqueue");

reducer.finish().expect("reducer should finish");

let connection = Connection::open(fixture.db_path()).expect("db should open");
assert_eq!(
scalar_text(
&connection,
"SELECT GROUP_CONCAT(file_path, ',') FROM source_file_packages",
),
"a.go,b.go"
);
assert_eq!(
scalar_text(
&connection,
"SELECT GROUP_CONCAT(relative_path, ',') FROM file_facts",
),
"a.go,b.go"
);
}

#[test]
fn materializes_file_facts_without_git_as_zero_metrics() {
let fixture = Fixture::new("file-facts-no-git");
Expand Down
30 changes: 29 additions & 1 deletion src/tui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -869,7 +869,7 @@ fn load_risk_rows(connection: &Connection) -> rusqlite::Result<Vec<RiskRow>> {
FROM file_risk_scores score
LEFT JOIN file_facts facts
ON facts.relative_path = score.relative_path
ORDER BY score.rank ASC
ORDER BY score.score DESC, score.relative_path ASC
",
)?;
let rows = statement.query_map([], |row| {
Expand Down Expand Up @@ -1664,6 +1664,34 @@ mod tests {
assert_eq!(snapshot.rows[0].owners.len(), 1);
}

#[test]
fn loads_risk_rows_by_score_desc_then_path_asc() {
let fixture = Fixture::new("risk-sort");
create_tui_db(&fixture.db_path());
let connection = Connection::open(fixture.db_path()).expect("db should open");
connection
.execute_batch(
"
UPDATE file_risk_scores
SET rank = 2, score = 0.9
WHERE relative_path = 'src/risky.go';
UPDATE file_risk_scores
SET rank = 1, score = 0.9
WHERE relative_path = 'src/safe.go';
",
)
.expect("fixture rows should update");

let snapshot = TuiDatabaseSnapshot::load_from_dir(&fixture.path);

let paths = snapshot
.rows
.iter()
.map(|row| row.relative_path.as_str())
.collect::<Vec<_>>();
assert_eq!(paths, vec!["src/risky.go", "src/safe.go"]);
}

#[test]
fn empty_risk_tables_return_scored_go_empty_state() {
let fixture = Fixture::new("empty-risk");
Expand Down
Loading