@@ -11,7 +11,7 @@ struct Exercise {
11
11
path : String ,
12
12
#[ serde( rename = "type" ) ]
13
13
exercise_type : String ,
14
- score : i32 , // Added: Each exercise score
14
+ score : i32 ,
15
15
}
16
16
17
17
#[ derive( Serialize , Deserialize , Debug ) ]
@@ -25,15 +25,15 @@ struct ExerciseConfig {
25
25
struct ExerciseResult {
26
26
name : String ,
27
27
result : bool ,
28
- score : i32 , // Store score for each exercise
28
+ score : i32 ,
29
29
}
30
30
31
31
#[ derive( Serialize , Deserialize , Debug ) ]
32
32
struct Statistics {
33
33
total_exercises : usize ,
34
34
total_successes : usize ,
35
35
total_failures : usize ,
36
- total_score : i32 , // Total score for the assessment
36
+ total_score : i32 ,
37
37
total_time : u64 ,
38
38
}
39
39
@@ -53,7 +53,7 @@ fn main() {
53
53
let mode = & args[ 1 ] ;
54
54
let start_time = Instant :: now ( ) ;
55
55
56
- // Load the exercise config
56
+
57
57
let config = match load_exercise_config ( "exercise_config.json" ) {
58
58
Ok ( cfg) => cfg,
59
59
Err ( e) => {
@@ -68,54 +68,52 @@ fn main() {
68
68
total_exercises : 0 ,
69
69
total_successes : 0 ,
70
70
total_failures : 0 ,
71
- total_score : 0 , // Initialize total score to 0
71
+ total_score : 0 ,
72
72
total_time : 0 ,
73
73
} ,
74
74
} ;
75
75
76
- // Evaluate exercises from config
76
+
77
77
evaluate_exercises_from_config ( mode, config, & mut report) ;
78
78
79
- // Calculate total time
79
+
80
80
report. statistics . total_time = start_time. elapsed ( ) . as_secs ( ) ;
81
81
report. statistics . total_exercises = report. statistics . total_successes + report. statistics . total_failures ;
82
82
83
- // Output summary
83
+
84
84
println ! ( "\n Summary:" ) ;
85
85
println ! ( "Total exercises: {}" , report. statistics. total_exercises) ;
86
86
println ! ( "Total successes: {}" , report. statistics. total_successes) ;
87
87
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) ;
89
89
90
- // Save the report to a JSON file
90
+
91
91
if let Err ( e) = save_report_to_json ( "report.json" , & report) {
92
92
eprintln ! ( "Error saving report: {}" , e) ;
93
93
}
94
94
}
95
95
96
- // Load exercise configuration from JSON
96
+
97
97
fn load_exercise_config ( file_path : & str ) -> Result < ExerciseConfig , io:: Error > {
98
98
let file = File :: open ( file_path) ?;
99
99
let config: ExerciseConfig = serde_json:: from_reader ( file) ?;
100
100
Ok ( config)
101
101
}
102
102
103
- // Evaluate all exercises from the configuration
103
+
104
104
fn evaluate_exercises_from_config ( mode : & str , config : ExerciseConfig , report : & mut Report ) {
105
105
let all_exercises = [ config. easy , config. normal , config. hard ] . concat ( ) ;
106
-
106
+
107
107
for exercise in all_exercises {
108
108
println ! ( "\n Evaluating {}: {}" , exercise. exercise_type, exercise. name) ;
109
109
let result = evaluate_exercise ( & exercise) ;
110
110
111
- // Calculate score based on result
112
111
let score = if result { exercise. score } else { 0 } ;
113
112
114
- // Add result to the report
115
113
report. exercises . push ( ExerciseResult {
116
114
name : exercise. name . clone ( ) ,
117
115
result,
118
- score,
116
+ score,
119
117
} ) ;
120
118
121
119
if result {
@@ -124,7 +122,6 @@ fn evaluate_exercises_from_config(mode: &str, config: ExerciseConfig, report: &m
124
122
report. statistics . total_failures += 1 ;
125
123
}
126
124
127
- // Add score to total score
128
125
report. statistics . total_score += score;
129
126
130
127
if mode == "watch" && !ask_to_continue ( ) {
@@ -133,7 +130,7 @@ fn evaluate_exercises_from_config(mode: &str, config: ExerciseConfig, report: &m
133
130
}
134
131
}
135
132
136
- // Evaluate a single exercise
133
+
137
134
fn evaluate_exercise ( exercise : & Exercise ) -> bool {
138
135
let exercise_path = PathBuf :: from ( & format ! ( "./exercises/{}" , exercise. path) ) ;
139
136
match exercise. exercise_type . as_str ( ) {
@@ -146,30 +143,61 @@ fn evaluate_exercise(exercise: &Exercise) -> bool {
146
143
}
147
144
}
148
145
149
- // Evaluate a single file Rust exercise
146
+ // 评测单文件 Rust 习题(使用 rustc --test 并执行测试)
150
147
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 进行编译
152
154
. arg ( file_path)
155
+ . arg ( "-o" )
156
+ . arg ( & test_binary) // 指定输出文件
153
157
. output ( ) ;
154
158
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) ;
160
184
} else {
161
- println ! ( "\x1b [31m{}: FAILED\x1b [0m" , file_path. display( ) ) ;
162
- false
185
+ println ! ( "Successfully removed test binary: {}" , test_binary. display( ) ) ;
163
186
}
187
+
188
+ return test_passed;
189
+ } else {
190
+ // 编译失败
191
+ eprintln ! ( "\x1b [31m{}: COMPILATION FAILED\x1b [0m" , file_path. display( ) ) ;
192
+ return false ;
164
193
}
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 ;
169
197
}
170
198
}
171
199
172
- // Evaluate a cargo project
200
+ // 评测 Cargo 项目
173
201
fn evaluate_cargo_project ( proj_path : & PathBuf ) -> bool {
174
202
let build_success = run_cargo_command ( proj_path, "build" ) ;
175
203
let test_success = run_cargo_command ( proj_path, "test" ) ;
@@ -183,13 +211,12 @@ fn evaluate_cargo_project(proj_path: &PathBuf) -> bool {
183
211
println ! ( "\x1b [31m{}: FAILED\x1b [0m" , proj_path. display( ) ) ;
184
212
}
185
213
186
- // Clean up the target directory after evaluation
187
214
clean_target_directory ( proj_path) ;
188
215
189
216
passed
190
217
}
191
218
192
- // Run a cargo command (build, test, clippy)
219
+ // 运行 Cargo 命令
193
220
fn run_cargo_command ( proj_path : & PathBuf , command : & str ) -> bool {
194
221
let output = Command :: new ( "cargo" )
195
222
. arg ( command)
@@ -202,7 +229,7 @@ fn run_cargo_command(proj_path: &PathBuf, command: &str) -> bool {
202
229
}
203
230
}
204
231
205
- // Clean up the target directory after evaluating a cargo project
232
+ // 清理 target 目录
206
233
fn clean_target_directory ( proj_path : & PathBuf ) {
207
234
let target_dir = proj_path. join ( "target" ) ;
208
235
@@ -215,15 +242,15 @@ fn clean_target_directory(proj_path: &PathBuf) {
215
242
}
216
243
}
217
244
218
- // Ask the user whether to continue after each evaluation
245
+ // 用户确认是否继续
219
246
fn ask_to_continue ( ) -> bool {
220
247
let mut input = String :: new ( ) ;
221
248
println ! ( "\n Press any key to continue, or 'q' to quit." ) ;
222
249
io:: stdin ( ) . read_line ( & mut input) . unwrap ( ) ;
223
250
input. trim ( ) . to_lowercase ( ) != "q"
224
251
}
225
252
226
- // Save the report to a JSON file
253
+ // 保存评测报告
227
254
fn save_report_to_json ( file_name : & str , report : & Report ) -> io:: Result < ( ) > {
228
255
let file = File :: create ( file_name) ?;
229
256
serde_json:: to_writer_pretty ( file, report) ?;
0 commit comments