Skip to content

Commit f5d8110

Browse files
committed
Finalizada Implementação do Interpretador de Testes
Testes agora armazenam TestResult no environment. A função run_tests no interpretador recebe um programa, executa ele por inteiro e depois roda todos os testes presentes no programa, retornando um Vec<TestResult> Testes definidos em um programa são armazenados no escopo no hashmap tests. Vec<TestResult> ainda não está sendo armazenado no environment. Mas é possível implementar de maneira indolor. Interpretador de Asserts finalizada, agora eles retornam Computation::Continue ou Err(e), com a string de erro presente dentro do Assert. Cargo.toml agora requer uso de IndexMap para armazenar TestResults ordenados na ordem de definição dos testes.
1 parent 44909f9 commit f5d8110

4 files changed

Lines changed: 262 additions & 2 deletions

File tree

Cargo.lock

Lines changed: 23 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ edition = "2021"
77
nom = "7.0"
88
approx = "0.5.1"
99
once_cell = "1.10"
10+
indexmap = "2.2"

src/environment/environment.rs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::ir::ast::Function;
22
use crate::ir::ast::Name;
33
use crate::ir::ast::ValueConstructor;
4+
use indexmap::IndexMap;
45
use std::collections::HashMap;
56
use std::collections::LinkedList;
67

@@ -9,7 +10,7 @@ pub struct Scope<A> {
910
pub variables: HashMap<Name, (bool, A)>,
1011
pub functions: HashMap<Name, Function>,
1112
pub adts: HashMap<Name, Vec<ValueConstructor>>,
12-
pub tests: HashMap<Name, Function>,
13+
pub tests: IndexMap<Name, Function>,
1314
}
1415

1516
impl<A: Clone> Scope<A> {
@@ -18,7 +19,7 @@ impl<A: Clone> Scope<A> {
1819
variables: HashMap::new(),
1920
functions: HashMap::new(),
2021
adts: HashMap::new(),
21-
tests: HashMap::new(),
22+
tests: IndexMap::new(),
2223
}
2324
}
2425

@@ -130,6 +131,19 @@ impl<A: Clone> Environment<A> {
130131
self.globals.lookup_test(name)
131132
}
132133

134+
pub fn scrape_tests(&self) -> Vec<Function> {
135+
let mut tests = Vec::new();
136+
for scope in self.stack.iter() {
137+
for test in scope.tests.values() {
138+
tests.push(test.clone());
139+
}
140+
}
141+
for test in self.globals.tests.values() {
142+
tests.push(test.clone());
143+
}
144+
tests
145+
}
146+
133147
pub fn lookup_adt(&self, name: &Name) -> Option<&Vec<ValueConstructor>> {
134148
for scope in self.stack.iter() {
135149
if let Some(cons) = scope.lookup_adt(name) {
@@ -174,6 +188,22 @@ impl<A: Clone> Environment<A> {
174188
}
175189
}
176190

191+
pub struct TestResult {
192+
pub name: Name,
193+
pub result: bool,
194+
pub error: Option<String>,
195+
}
196+
197+
impl TestResult {
198+
pub fn new(name: Name, result: bool, error: Option<String>) -> Self {
199+
TestResult {
200+
name,
201+
result,
202+
error,
203+
}
204+
}
205+
}
206+
177207
#[cfg(test)]
178208
mod tests {
179209
use super::*;

src/interpreter/statement_execute.rs

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use super::expression_eval::{eval, ExpressionResult};
22
use crate::environment::environment::Environment;
3+
use crate::environment::environment::TestResult;
34
use crate::ir::ast::{Expression, Statement};
45

56
pub enum Computation {
@@ -32,6 +33,42 @@ pub fn run(
3233
}
3334
}
3435

36+
pub fn run_tests(stmt: &Statement) -> Result<Vec<TestResult>, String> {
37+
let env = match run(stmt.clone(), &Environment::new()) {
38+
Ok(env) => env,
39+
Err(e) => return Err(e),
40+
};
41+
42+
let mut results = Vec::new();
43+
44+
for test in env.scrape_tests() {
45+
let test_env = env.clone();
46+
47+
let stmt = match &test.body {
48+
Some(body) => *body.clone(),
49+
None => continue,
50+
};
51+
52+
match execute(stmt, &test_env) {
53+
Ok(Computation::Continue(_)) | Ok(Computation::Return(_, _)) => {
54+
results.push(TestResult::new(test.name.clone(), true, None));
55+
}
56+
Err(e) => {
57+
results.push(TestResult::new(test.name.clone(), false, Some(e)));
58+
}
59+
Ok(Computation::PropagateError(e, _)) => {
60+
results.push(TestResult::new(
61+
test.name.clone(),
62+
false,
63+
Some(format!("Propagated error: {:?}", e)),
64+
));
65+
}
66+
}
67+
}
68+
69+
Ok(results)
70+
}
71+
3572
pub fn execute(stmt: Statement, env: &Environment<Expression>) -> Result<Computation, String> {
3673
let mut new_env = env.clone();
3774

@@ -1127,4 +1164,173 @@ mod tests {
11271164
}
11281165
}
11291166
}
1167+
mod run_tests_tests {
1168+
1169+
use super::*;
1170+
1171+
#[test]
1172+
fn test_run_tests() {
1173+
let test_def = Statement::TestDef(Function {
1174+
name: "test_example".to_string(),
1175+
kind: Type::TVoid,
1176+
params: Vec::new(),
1177+
body: Some(Box::new(Statement::Block(vec![Statement::Assert(
1178+
Box::new(Expression::CTrue),
1179+
Box::new(Expression::CString("Test passed".to_string())),
1180+
)]))),
1181+
});
1182+
let programa = Statement::Block(vec![test_def.clone()]);
1183+
match run_tests(&programa) {
1184+
Ok(resultados) => {
1185+
assert_eq!(resultados.len(), 1);
1186+
assert_eq!(resultados[0].name, "test_example");
1187+
assert!(resultados[0].result);
1188+
assert!(resultados[0].error.is_none());
1189+
}
1190+
_ => panic!("Test execution failed"),
1191+
}
1192+
}
1193+
1194+
#[test]
1195+
fn test_run_tests_scope() {
1196+
let test_def = Statement::TestDef(Function {
1197+
name: "test_example".to_string(),
1198+
kind: Type::TVoid,
1199+
params: Vec::new(),
1200+
body: Some(Box::new(Statement::Block(vec![Statement::Assert(
1201+
Box::new(Expression::CTrue),
1202+
Box::new(Expression::CString("Test passed".to_string())),
1203+
)]))),
1204+
});
1205+
1206+
let teste_def2 = Statement::TestDef(Function {
1207+
name: "test_example2".to_string(),
1208+
kind: Type::TVoid,
1209+
params: Vec::new(),
1210+
body: Some(Box::new(Statement::Block(vec![Statement::Assert(
1211+
Box::new(Expression::CTrue),
1212+
Box::new(Expression::CString("Test 2 passed".to_string())),
1213+
)]))),
1214+
});
1215+
1216+
let assign1 = Statement::Assignment("x".to_string(), Box::new(Expression::CInt(10)));
1217+
let assign2 = Statement::Assignment("y".to_string(), Box::new(Expression::CInt(20)));
1218+
1219+
let ifelse = Statement::IfThenElse(
1220+
Box::new(Expression::CTrue),
1221+
Box::new(test_def),
1222+
Some(Box::new(teste_def2)),
1223+
);
1224+
1225+
let programa = Statement::Block(vec![assign1, assign2, ifelse]);
1226+
1227+
let resultado_final = match run_tests(&programa) {
1228+
Ok(resultados) => resultados,
1229+
Err(e) => panic!("Test execution failed: {}", e),
1230+
};
1231+
1232+
assert_eq!(resultado_final.len(), 1);
1233+
assert_eq!(resultado_final[0].name, "test_example");
1234+
assert_eq!(resultado_final[0].result, true);
1235+
}
1236+
1237+
#[test]
1238+
fn test_run_tests_with_assert_fail() {
1239+
let teste1 = Statement::TestDef(Function {
1240+
name: "test_fail".to_string(),
1241+
kind: Type::TVoid,
1242+
params: Vec::new(),
1243+
body: Some(Box::new(Statement::Block(vec![Statement::Assert(
1244+
Box::new(Expression::CFalse),
1245+
Box::new(Expression::CString("This test should fail".to_string())),
1246+
)]))),
1247+
});
1248+
let programa = Statement::Block(vec![teste1]);
1249+
match run_tests(&programa) {
1250+
Ok(resultados) => {
1251+
assert_eq!(resultados.len(), 1);
1252+
assert_eq!(resultados[0].name, "test_fail");
1253+
assert!(!resultados[0].result);
1254+
assert_eq!(
1255+
resultados[0].error,
1256+
Some("This test should fail".to_string())
1257+
);
1258+
}
1259+
Err(e) => panic!("Test execution failed: {}", e),
1260+
}
1261+
}
1262+
1263+
#[test]
1264+
fn test_run_tests_without_asserts() {
1265+
let teste = Statement::TestDef(Function {
1266+
name: "test_no_assert".to_string(),
1267+
kind: Type::TVoid,
1268+
params: Vec::new(),
1269+
body: Some(Box::new(Statement::Block(vec![Statement::VarDeclaration(
1270+
"x".to_string(),
1271+
Box::new(Expression::CInt(42)),
1272+
)]))),
1273+
});
1274+
let programa = Statement::Block(vec![teste]);
1275+
match run_tests(&programa) {
1276+
Ok(resultados) => {
1277+
assert_eq!(resultados.len(), 1);
1278+
assert_eq!(resultados[0].name, "test_no_assert");
1279+
assert!(resultados[0].result);
1280+
assert!(resultados[0].error.is_none());
1281+
}
1282+
Err(e) => panic!("Test execution failed: {}", e),
1283+
}
1284+
}
1285+
1286+
#[test]
1287+
fn test_run_tests_with_multiple_tests() {
1288+
let teste1 = Statement::TestDef(Function {
1289+
name: "test_one".to_string(),
1290+
kind: Type::TVoid,
1291+
params: Vec::new(),
1292+
body: Some(Box::new(Statement::Block(vec![Statement::Assert(
1293+
Box::new(Expression::CTrue),
1294+
Box::new(Expression::CString("Test one passed".to_string())),
1295+
)]))),
1296+
});
1297+
let teste2 = Statement::TestDef(Function {
1298+
name: "test_two".to_string(),
1299+
kind: Type::TVoid,
1300+
params: Vec::new(),
1301+
body: Some(Box::new(Statement::Block(vec![Statement::Assert(
1302+
Box::new(Expression::CFalse),
1303+
Box::new(Expression::CString("Test two failed".to_string())),
1304+
)]))),
1305+
});
1306+
let teste3 = Statement::TestDef(Function {
1307+
name: "test_three".to_string(),
1308+
kind: Type::TVoid,
1309+
params: Vec::new(),
1310+
body: Some(Box::new(Statement::Block(vec![Statement::Assert(
1311+
Box::new(Expression::CTrue),
1312+
Box::new(Expression::CString("Test three passed".to_string())),
1313+
)]))),
1314+
});
1315+
let programa = Statement::Block(vec![teste1, teste2, teste3]);
1316+
1317+
match run_tests(&programa) {
1318+
Ok(resultados) => {
1319+
assert_eq!(resultados.len(), 3);
1320+
assert_eq!(resultados[0].name, "test_one");
1321+
assert!(resultados[0].result);
1322+
assert!(resultados[0].error.is_none());
1323+
1324+
assert_eq!(resultados[1].name, "test_two");
1325+
assert!(!resultados[1].result);
1326+
assert_eq!(resultados[1].error, Some("Test two failed".to_string()));
1327+
1328+
assert_eq!(resultados[2].name, "test_three");
1329+
assert!(resultados[2].result);
1330+
assert!(resultados[2].error.is_none());
1331+
}
1332+
Err(e) => panic!("Test execution failed: {}", e),
1333+
}
1334+
}
1335+
}
11301336
}

0 commit comments

Comments
 (0)