Skip to content

Commit 484976d

Browse files
fix single file evaluate
1 parent 0f196c5 commit 484976d

File tree

1 file changed

+64
-37
lines changed

1 file changed

+64
-37
lines changed

src/main.rs

+64-37
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ struct Exercise {
1111
path: String,
1212
#[serde(rename = "type")]
1313
exercise_type: String,
14-
score: i32, // Added: Each exercise score
14+
score: i32,
1515
}
1616

1717
#[derive(Serialize, Deserialize, Debug)]
@@ -25,15 +25,15 @@ struct ExerciseConfig {
2525
struct ExerciseResult {
2626
name: String,
2727
result: bool,
28-
score: i32, // Store score for each exercise
28+
score: i32,
2929
}
3030

3131
#[derive(Serialize, Deserialize, Debug)]
3232
struct Statistics {
3333
total_exercises: usize,
3434
total_successes: usize,
3535
total_failures: usize,
36-
total_score: i32, // Total score for the assessment
36+
total_score: i32,
3737
total_time: u64,
3838
}
3939

@@ -53,7 +53,7 @@ fn main() {
5353
let mode = &args[1];
5454
let start_time = Instant::now();
5555

56-
// Load the exercise config
56+
5757
let config = match load_exercise_config("exercise_config.json") {
5858
Ok(cfg) => cfg,
5959
Err(e) => {
@@ -68,54 +68,52 @@ fn main() {
6868
total_exercises: 0,
6969
total_successes: 0,
7070
total_failures: 0,
71-
total_score: 0, // Initialize total score to 0
71+
total_score: 0,
7272
total_time: 0,
7373
},
7474
};
7575

76-
// Evaluate exercises from config
76+
7777
evaluate_exercises_from_config(mode, config, &mut report);
7878

79-
// Calculate total time
79+
8080
report.statistics.total_time = start_time.elapsed().as_secs();
8181
report.statistics.total_exercises = report.statistics.total_successes + report.statistics.total_failures;
8282

83-
// Output summary
83+
8484
println!("\nSummary:");
8585
println!("Total exercises: {}", report.statistics.total_exercises);
8686
println!("Total successes: {}", report.statistics.total_successes);
8787
println!("Total failures: {}", report.statistics.total_failures);
88-
println!("Total score: {}", report.statistics.total_score); // Output the total score
88+
println!("Total score: {}", report.statistics.total_score);
8989

90-
// Save the report to a JSON file
90+
9191
if let Err(e) = save_report_to_json("report.json", &report) {
9292
eprintln!("Error saving report: {}", e);
9393
}
9494
}
9595

96-
// Load exercise configuration from JSON
96+
9797
fn load_exercise_config(file_path: &str) -> Result<ExerciseConfig, io::Error> {
9898
let file = File::open(file_path)?;
9999
let config: ExerciseConfig = serde_json::from_reader(file)?;
100100
Ok(config)
101101
}
102102

103-
// Evaluate all exercises from the configuration
103+
104104
fn evaluate_exercises_from_config(mode: &str, config: ExerciseConfig, report: &mut Report) {
105105
let all_exercises = [config.easy, config.normal, config.hard].concat();
106-
106+
107107
for exercise in all_exercises {
108108
println!("\nEvaluating {}: {}", exercise.exercise_type, exercise.name);
109109
let result = evaluate_exercise(&exercise);
110110

111-
// Calculate score based on result
112111
let score = if result { exercise.score } else { 0 };
113112

114-
// Add result to the report
115113
report.exercises.push(ExerciseResult {
116114
name: exercise.name.clone(),
117115
result,
118-
score,
116+
score,
119117
});
120118

121119
if result {
@@ -124,7 +122,6 @@ fn evaluate_exercises_from_config(mode: &str, config: ExerciseConfig, report: &m
124122
report.statistics.total_failures += 1;
125123
}
126124

127-
// Add score to total score
128125
report.statistics.total_score += score;
129126

130127
if mode == "watch" && !ask_to_continue() {
@@ -133,7 +130,7 @@ fn evaluate_exercises_from_config(mode: &str, config: ExerciseConfig, report: &m
133130
}
134131
}
135132

136-
// Evaluate a single exercise
133+
137134
fn evaluate_exercise(exercise: &Exercise) -> bool {
138135
let exercise_path = PathBuf::from(&format!("./exercises/{}", exercise.path));
139136
match exercise.exercise_type.as_str() {
@@ -146,30 +143,61 @@ fn evaluate_exercise(exercise: &Exercise) -> bool {
146143
}
147144
}
148145

149-
// Evaluate a single file Rust exercise
146+
// 评测单文件 Rust 习题(使用 rustc --test 并执行测试)
150147
fn evaluate_single_file(file_path: &PathBuf) -> bool {
151-
let output = Command::new("rustc")
148+
// 获取文件名(不带扩展名)
149+
let test_binary = file_path.with_extension("");
150+
151+
// 编译测试文件
152+
let compile_output = Command::new("rustc")
153+
.arg("--test") // 使用 rustc --test 进行编译
152154
.arg(file_path)
155+
.arg("-o")
156+
.arg(&test_binary) // 指定输出文件
153157
.output();
154158

155-
match output {
156-
Ok(out) => {
157-
if out.status.success() {
158-
println!("\x1b[32m{}: PASSED\x1b[0m", file_path.display());
159-
true
159+
if let Ok(output) = compile_output {
160+
if output.status.success() {
161+
// 编译成功,运行测试二进制文件
162+
let test_output = Command::new(&test_binary)
163+
.output();
164+
165+
let test_passed = match test_output {
166+
Ok(test_run) => {
167+
if test_run.status.success() {
168+
println!("\x1b[32m{}: TEST PASSED\x1b[0m", file_path.display());
169+
true
170+
} else {
171+
println!("\x1b[31m{}: TEST FAILED\x1b[0m", file_path.display());
172+
false
173+
}
174+
}
175+
Err(_) => {
176+
eprintln!("Error running test executable for {}", file_path.display());
177+
false
178+
}
179+
};
180+
181+
// 删除测试二进制文件
182+
if let Err(e) = fs::remove_file(&test_binary) {
183+
eprintln!("Failed to remove test binary {}: {}", test_binary.display(), e);
160184
} else {
161-
println!("\x1b[31m{}: FAILED\x1b[0m", file_path.display());
162-
false
185+
println!("Successfully removed test binary: {}", test_binary.display());
163186
}
187+
188+
return test_passed;
189+
} else {
190+
// 编译失败
191+
eprintln!("\x1b[31m{}: COMPILATION FAILED\x1b[0m", file_path.display());
192+
return false;
164193
}
165-
Err(_) => {
166-
eprintln!("Error executing rustc for {}", file_path.display());
167-
false
168-
}
194+
} else {
195+
eprintln!("Error executing rustc --test for {}", file_path.display());
196+
return false;
169197
}
170198
}
171199

172-
// Evaluate a cargo project
200+
// 评测 Cargo 项目
173201
fn evaluate_cargo_project(proj_path: &PathBuf) -> bool {
174202
let build_success = run_cargo_command(proj_path, "build");
175203
let test_success = run_cargo_command(proj_path, "test");
@@ -183,13 +211,12 @@ fn evaluate_cargo_project(proj_path: &PathBuf) -> bool {
183211
println!("\x1b[31m{}: FAILED\x1b[0m", proj_path.display());
184212
}
185213

186-
// Clean up the target directory after evaluation
187214
clean_target_directory(proj_path);
188215

189216
passed
190217
}
191218

192-
// Run a cargo command (build, test, clippy)
219+
// 运行 Cargo 命令
193220
fn run_cargo_command(proj_path: &PathBuf, command: &str) -> bool {
194221
let output = Command::new("cargo")
195222
.arg(command)
@@ -202,7 +229,7 @@ fn run_cargo_command(proj_path: &PathBuf, command: &str) -> bool {
202229
}
203230
}
204231

205-
// Clean up the target directory after evaluating a cargo project
232+
// 清理 target 目录
206233
fn clean_target_directory(proj_path: &PathBuf) {
207234
let target_dir = proj_path.join("target");
208235

@@ -215,15 +242,15 @@ fn clean_target_directory(proj_path: &PathBuf) {
215242
}
216243
}
217244

218-
// Ask the user whether to continue after each evaluation
245+
// 用户确认是否继续
219246
fn ask_to_continue() -> bool {
220247
let mut input = String::new();
221248
println!("\nPress any key to continue, or 'q' to quit.");
222249
io::stdin().read_line(&mut input).unwrap();
223250
input.trim().to_lowercase() != "q"
224251
}
225252

226-
// Save the report to a JSON file
253+
// 保存评测报告
227254
fn save_report_to_json(file_name: &str, report: &Report) -> io::Result<()> {
228255
let file = File::create(file_name)?;
229256
serde_json::to_writer_pretty(file, report)?;

0 commit comments

Comments
 (0)