Skip to content

Commit a164baf

Browse files
committed
refactor: split eval runner execution helpers
Separate fixture preparation and result assembly from the main eval runner so execution changes stay easier to isolate and verify. Made-with: Cursor
1 parent 0399371 commit a164baf

3 files changed

Lines changed: 183 additions & 97 deletions

File tree

Lines changed: 20 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,40 @@
1+
#[path = "execute/loading.rs"]
2+
mod loading;
3+
#[path = "execute/result.rs"]
4+
mod result;
5+
16
use anyhow::Result;
2-
use std::path::{Path, PathBuf};
37

48
use crate::config;
5-
use crate::core::eval_benchmarks::FixtureResult as BenchmarkFixtureResult;
69
use crate::review::review_diff_content_raw;
710

11+
use self::loading::prepare_fixture_execution;
12+
use self::result::{append_total_comment_failures, build_benchmark_metrics, build_fixture_result};
813
use super::super::{EvalFixtureResult, LoadedEvalFixture};
914
use super::matching::evaluate_fixture_expectations;
1015

1116
pub(in super::super) async fn run_eval_fixture(
1217
config: &config::Config,
1318
loaded_fixture: LoadedEvalFixture,
1419
) -> Result<EvalFixtureResult> {
15-
let LoadedEvalFixture {
16-
fixture_path,
17-
fixture,
18-
suite_name,
19-
suite_thresholds,
20-
difficulty,
21-
} = loaded_fixture;
22-
let fixture_name = fixture.name.clone().unwrap_or_else(|| {
23-
fixture_path
24-
.file_name()
25-
.and_then(|value| value.to_str())
26-
.unwrap_or("fixture")
27-
.to_string()
28-
});
29-
let fixture_dir = fixture_path
30-
.parent()
31-
.map(Path::to_path_buf)
32-
.unwrap_or_else(|| PathBuf::from("."));
33-
34-
let diff_content = match (fixture.diff.clone(), fixture.diff_file.clone()) {
35-
(Some(diff), _) => diff,
36-
(None, Some(diff_file)) => {
37-
let path = if diff_file.is_absolute() {
38-
diff_file
39-
} else {
40-
fixture_dir.join(diff_file)
41-
};
42-
std::fs::read_to_string(path)?
43-
}
44-
(None, None) => anyhow::bail!(
45-
"Fixture '{}' must define either diff or diff_file",
46-
fixture_name
47-
),
48-
};
49-
50-
let repo_path = fixture
51-
.repo_path
52-
.clone()
53-
.map(|path| {
54-
if path.is_absolute() {
55-
path
56-
} else {
57-
fixture_dir.join(path)
58-
}
59-
})
60-
.unwrap_or_else(|| PathBuf::from("."));
61-
62-
let review_result = review_diff_content_raw(&diff_content, config.clone(), &repo_path).await?;
20+
let prepared = prepare_fixture_execution(loaded_fixture)?;
21+
let review_result =
22+
review_diff_content_raw(&prepared.diff_content, config.clone(), &prepared.repo_path)
23+
.await?;
6324
let comments = review_result.comments;
6425
let total_comments = comments.len();
65-
let match_summary = evaluate_fixture_expectations(&fixture.expect, &comments);
66-
let mut failures = match_summary.failures;
67-
68-
if let Some(min_total) = fixture.expect.min_total {
69-
if total_comments < min_total {
70-
failures.push(format!(
71-
"Expected at least {} comments, got {}",
72-
min_total, total_comments
73-
));
74-
}
75-
}
76-
if let Some(max_total) = fixture.expect.max_total {
77-
if total_comments > max_total {
78-
failures.push(format!(
79-
"Expected at most {} comments, got {}",
80-
max_total, total_comments
81-
));
82-
}
83-
}
26+
let match_summary = evaluate_fixture_expectations(&prepared.fixture.expect, &comments);
27+
let mut failures = match_summary.failures.clone();
8428

85-
let benchmark_metrics = suite_name.as_ref().map(|_| {
86-
let accounted_for = match_summary
87-
.used_comment_indices
88-
.union(&match_summary.unexpected_comment_indices)
89-
.count();
90-
let extra_findings = total_comments.saturating_sub(accounted_for);
91-
let mut result = BenchmarkFixtureResult::compute(
92-
&fixture_name,
93-
fixture.expect.must_find.len(),
94-
fixture.expect.must_not_find.len(),
95-
match_summary.required_matches,
96-
match_summary.unexpected_comment_indices.len(),
97-
extra_findings,
98-
);
99-
result.details = failures.clone();
100-
result
101-
});
29+
append_total_comment_failures(&mut failures, total_comments, &prepared.fixture.expect);
30+
let benchmark_metrics =
31+
build_benchmark_metrics(&prepared, total_comments, &match_summary, &failures);
10232

103-
Ok(EvalFixtureResult {
104-
fixture: fixture_name,
105-
suite: suite_name,
106-
passed: failures.is_empty(),
33+
Ok(build_fixture_result(
34+
prepared,
10735
total_comments,
108-
required_matches: match_summary.required_matches,
109-
required_total: match_summary.required_total,
36+
match_summary,
11037
benchmark_metrics,
111-
suite_thresholds,
112-
difficulty,
113-
rule_metrics: match_summary.rule_metrics,
114-
rule_summary: match_summary.rule_summary,
11538
failures,
116-
})
39+
))
11740
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
use anyhow::Result;
2+
use std::path::{Path, PathBuf};
3+
4+
use crate::core::eval_benchmarks::{BenchmarkThresholds, Difficulty};
5+
6+
use super::super::super::{EvalFixture, LoadedEvalFixture};
7+
8+
pub(super) struct PreparedFixtureExecution {
9+
pub(super) fixture_name: String,
10+
pub(super) fixture: EvalFixture,
11+
pub(super) suite_name: Option<String>,
12+
pub(super) suite_thresholds: Option<BenchmarkThresholds>,
13+
pub(super) difficulty: Option<Difficulty>,
14+
pub(super) diff_content: String,
15+
pub(super) repo_path: PathBuf,
16+
}
17+
18+
pub(super) fn prepare_fixture_execution(
19+
loaded_fixture: LoadedEvalFixture,
20+
) -> Result<PreparedFixtureExecution> {
21+
let LoadedEvalFixture {
22+
fixture_path,
23+
fixture,
24+
suite_name,
25+
suite_thresholds,
26+
difficulty,
27+
} = loaded_fixture;
28+
let fixture_name = fixture.name.clone().unwrap_or_else(|| {
29+
fixture_path
30+
.file_name()
31+
.and_then(|value| value.to_str())
32+
.unwrap_or("fixture")
33+
.to_string()
34+
});
35+
let fixture_dir = fixture_path
36+
.parent()
37+
.map(Path::to_path_buf)
38+
.unwrap_or_else(|| PathBuf::from("."));
39+
let diff_content = load_diff_content(&fixture_name, &fixture_dir, &fixture)?;
40+
let repo_path = resolve_repo_path(&fixture_dir, &fixture);
41+
42+
Ok(PreparedFixtureExecution {
43+
fixture_name,
44+
fixture,
45+
suite_name,
46+
suite_thresholds,
47+
difficulty,
48+
diff_content,
49+
repo_path,
50+
})
51+
}
52+
53+
fn load_diff_content(
54+
fixture_name: &str,
55+
fixture_dir: &Path,
56+
fixture: &EvalFixture,
57+
) -> Result<String> {
58+
match (fixture.diff.clone(), fixture.diff_file.clone()) {
59+
(Some(diff), _) => Ok(diff),
60+
(None, Some(diff_file)) => {
61+
let path = if diff_file.is_absolute() {
62+
diff_file
63+
} else {
64+
fixture_dir.join(diff_file)
65+
};
66+
Ok(std::fs::read_to_string(path)?)
67+
}
68+
(None, None) => anyhow::bail!(
69+
"Fixture '{}' must define either diff or diff_file",
70+
fixture_name
71+
),
72+
}
73+
}
74+
75+
fn resolve_repo_path(fixture_dir: &Path, fixture: &EvalFixture) -> PathBuf {
76+
fixture
77+
.repo_path
78+
.clone()
79+
.map(|path| {
80+
if path.is_absolute() {
81+
path
82+
} else {
83+
fixture_dir.join(path)
84+
}
85+
})
86+
.unwrap_or_else(|| PathBuf::from("."))
87+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
use crate::core::eval_benchmarks::FixtureResult as BenchmarkFixtureResult;
2+
3+
use super::super::super::{EvalExpectations, EvalFixtureResult};
4+
use super::super::matching::FixtureMatchSummary;
5+
use super::loading::PreparedFixtureExecution;
6+
7+
pub(super) fn append_total_comment_failures(
8+
failures: &mut Vec<String>,
9+
total_comments: usize,
10+
expectations: &EvalExpectations,
11+
) {
12+
if let Some(min_total) = expectations.min_total {
13+
if total_comments < min_total {
14+
failures.push(format!(
15+
"Expected at least {} comments, got {}",
16+
min_total, total_comments
17+
));
18+
}
19+
}
20+
if let Some(max_total) = expectations.max_total {
21+
if total_comments > max_total {
22+
failures.push(format!(
23+
"Expected at most {} comments, got {}",
24+
max_total, total_comments
25+
));
26+
}
27+
}
28+
}
29+
30+
pub(super) fn build_benchmark_metrics(
31+
prepared: &PreparedFixtureExecution,
32+
total_comments: usize,
33+
match_summary: &FixtureMatchSummary,
34+
failures: &[String],
35+
) -> Option<BenchmarkFixtureResult> {
36+
prepared.suite_name.as_ref().map(|_| {
37+
let accounted_for = match_summary
38+
.used_comment_indices
39+
.union(&match_summary.unexpected_comment_indices)
40+
.count();
41+
let extra_findings = total_comments.saturating_sub(accounted_for);
42+
let mut result = BenchmarkFixtureResult::compute(
43+
&prepared.fixture_name,
44+
prepared.fixture.expect.must_find.len(),
45+
prepared.fixture.expect.must_not_find.len(),
46+
match_summary.required_matches,
47+
match_summary.unexpected_comment_indices.len(),
48+
extra_findings,
49+
);
50+
result.details = failures.to_vec();
51+
result
52+
})
53+
}
54+
55+
pub(super) fn build_fixture_result(
56+
prepared: PreparedFixtureExecution,
57+
total_comments: usize,
58+
match_summary: FixtureMatchSummary,
59+
benchmark_metrics: Option<BenchmarkFixtureResult>,
60+
failures: Vec<String>,
61+
) -> EvalFixtureResult {
62+
EvalFixtureResult {
63+
fixture: prepared.fixture_name,
64+
suite: prepared.suite_name,
65+
passed: failures.is_empty(),
66+
total_comments,
67+
required_matches: match_summary.required_matches,
68+
required_total: match_summary.required_total,
69+
benchmark_metrics,
70+
suite_thresholds: prepared.suite_thresholds,
71+
difficulty: prepared.difficulty,
72+
rule_metrics: match_summary.rule_metrics,
73+
rule_summary: match_summary.rule_summary,
74+
failures,
75+
}
76+
}

0 commit comments

Comments
 (0)