Skip to content

Commit ccd905f

Browse files
author
Grant Wuerker
committed
Test logging.
1 parent 0fed181 commit ccd905f

10 files changed

Lines changed: 248 additions & 47 deletions

File tree

Cargo.lock

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

crates/abi/src/types.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,9 @@ impl Serialize for AbiType {
143143

144144
#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
145145
pub struct AbiTupleField {
146-
name: String,
146+
pub name: String,
147147
#[serde(flatten)]
148-
ty: AbiType,
148+
pub ty: AbiType,
149149
}
150150

151151
impl AbiTupleField {

crates/codegen/src/db.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@
22
use std::rc::Rc;
33

44
use fe_abi::{contract::AbiContract, event::AbiEvent, function::AbiFunction, types::AbiType};
5-
use fe_analyzer::{db::AnalyzerDbStorage, namespace::items::ContractId, AnalyzerDb};
5+
use fe_analyzer::{
6+
db::AnalyzerDbStorage,
7+
namespace::items::{ContractId, ModuleId},
8+
AnalyzerDb,
9+
};
610
use fe_common::db::{SourceDb, SourceDbStorage, Upcast, UpcastMut};
711
use fe_mir::{
812
db::{MirDb, MirDbStorage},
@@ -31,6 +35,8 @@ pub trait CodegenDb: MirDb + Upcast<dyn MirDb> + UpcastMut<dyn MirDb> {
3135
fn codegen_abi_event(&self, ty: TypeId) -> AbiEvent;
3236
#[salsa::invoke(queries::abi::abi_contract)]
3337
fn codegen_abi_contract(&self, contract: ContractId) -> AbiContract;
38+
#[salsa::invoke(queries::abi::abi_module_events)]
39+
fn codegen_abi_module_events(&self, module: ModuleId) -> Vec<AbiEvent>;
3440
#[salsa::invoke(queries::abi::abi_type_maximum_size)]
3541
fn codegen_abi_type_maximum_size(&self, ty: TypeId) -> usize;
3642
#[salsa::invoke(queries::abi::abi_type_minimum_size)]

crates/codegen/src/db/queries/abi.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use fe_abi::{
77
use fe_analyzer::{
88
constants::INDEXED,
99
namespace::{
10-
items::ContractId,
10+
items::{ContractId, ModuleId},
1111
types::{CtxDecl, SelfDecl},
1212
},
1313
};
@@ -32,8 +32,14 @@ pub fn abi_contract(db: &dyn CodegenDb, contract: ContractId) -> AbiContract {
3232
}
3333
}
3434

35+
let events = abi_module_events(db, contract.module(db.upcast()));
36+
37+
AbiContract::new(funcs, events)
38+
}
39+
40+
pub fn abi_module_events(db: &dyn CodegenDb, module: ModuleId) -> Vec<AbiEvent> {
3541
let mut events = vec![];
36-
for &s in db.module_structs(contract.module(db.upcast())).as_ref() {
42+
for &s in db.module_structs(module).as_ref() {
3743
let struct_ty = s.as_type(db.upcast());
3844
// TODO: This is a hack to avoid generating an ABI for non-`emittable` structs.
3945
if struct_ty.is_emittable(db.upcast()) {
@@ -43,7 +49,7 @@ pub fn abi_contract(db: &dyn CodegenDb, contract: ContractId) -> AbiContract {
4349
}
4450
}
4551

46-
AbiContract::new(funcs, events)
52+
events
4753
}
4854

4955
pub fn abi_function(db: &dyn CodegenDb, function: FunctionId) -> AbiFunction {

crates/driver/src/lib.rs

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
#![allow(unused_imports, dead_code)]
22

3+
use fe_abi::event::AbiEvent;
4+
use fe_abi::types::{AbiTupleField, AbiType};
35
pub use fe_codegen::db::{CodegenDb, Db};
46

57
use fe_analyzer::namespace::items::{ContractId, FunctionId, IngotId, IngotMode, ModuleId};
68
use fe_common::diagnostics::Diagnostic;
79
use fe_common::files::FileKind;
810
use fe_common::{db::Upcast, utils::files::BuildFiles};
911
use fe_parser::ast::SmolStr;
12+
use fe_test_runner::ethabi::{Event, EventParam, ParamType};
1013
use fe_test_runner::TestSink;
1114
use indexmap::{indexmap, IndexMap};
1215
use serde_json::Value;
@@ -31,20 +34,70 @@ pub struct CompiledContract {
3134
#[derive(Debug, Clone, PartialEq, Eq)]
3235
pub struct CompiledTest {
3336
pub name: SmolStr,
37+
events: Vec<AbiEvent>,
3438
bytecode: String,
3539
}
3640

3741
#[cfg(feature = "solc-backend")]
3842
impl CompiledTest {
39-
pub fn new(name: SmolStr, bytecode: String) -> Self {
40-
Self { name, bytecode }
43+
pub fn new(name: SmolStr, events: Vec<AbiEvent>, bytecode: String) -> Self {
44+
Self {
45+
name,
46+
events,
47+
bytecode,
48+
}
4149
}
4250

4351
pub fn execute(&self, sink: &mut TestSink) -> bool {
44-
fe_test_runner::execute(&self.name, &self.bytecode, sink)
52+
let events = map_abi_events(&self.events);
53+
fe_test_runner::execute(&self.name, &events, &self.bytecode, sink)
54+
}
55+
}
56+
57+
fn map_abi_events(events: &[AbiEvent]) -> Vec<Event> {
58+
events.iter().map(map_abi_event).collect()
59+
}
60+
61+
fn map_abi_event(event: &AbiEvent) -> Event {
62+
let inputs = event
63+
.inputs
64+
.iter()
65+
.map(|input| {
66+
let kind = map_abi_type(&input.ty);
67+
EventParam {
68+
name: input.name.to_owned(),
69+
kind,
70+
indexed: input.indexed,
71+
}
72+
})
73+
.collect();
74+
Event {
75+
name: event.name.to_owned(),
76+
inputs,
77+
anonymous: event.anonymous,
4578
}
4679
}
4780

81+
fn map_abi_type(typ: &AbiType) -> ParamType {
82+
match typ {
83+
AbiType::UInt(value) => ParamType::Uint(*value),
84+
AbiType::Int(value) => ParamType::Int(*value),
85+
AbiType::Address => ParamType::Address,
86+
AbiType::Bool => ParamType::Bool,
87+
AbiType::Function => panic!("function cannot be mapped to an actual ABI value type"),
88+
AbiType::Array { elem_ty, len } => {
89+
ParamType::FixedArray(Box::new(map_abi_type(elem_ty)), *len)
90+
}
91+
AbiType::Tuple(params) => ParamType::Tuple(map_abi_types(params)),
92+
AbiType::Bytes => ParamType::Bytes,
93+
AbiType::String => ParamType::String,
94+
}
95+
}
96+
97+
fn map_abi_types(fields: &[AbiTupleField]) -> Vec<ParamType> {
98+
fields.iter().map(|field| map_abi_type(&field.ty)).collect()
99+
}
100+
48101
#[derive(Debug)]
49102
pub struct CompileError(pub Vec<Diagnostic>);
50103

@@ -168,7 +221,8 @@ fn compile_test(db: &mut Db, test: FunctionId, optimize: bool) -> CompiledTest {
168221
.to_string()
169222
.replace('"', "\\\"");
170223
let bytecode = compile_to_evm("test", &yul_test, optimize);
171-
CompiledTest::new(test.name(db), bytecode)
224+
let events = db.codegen_abi_module_events(test.module(db));
225+
CompiledTest::new(test.name(db), events, bytecode)
172226
}
173227

174228
#[cfg(feature = "solc-backend")]

crates/fe/src/task/test.rs

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ pub struct TestArgs {
1717
filter: Option<String>,
1818
#[clap(long, takes_value(true))]
1919
optimize: Option<bool>,
20+
#[clap(long)]
21+
logs: bool,
2022
}
2123

2224
pub fn test(args: TestArgs) {
@@ -29,13 +31,36 @@ pub fn test(args: TestArgs) {
2931
};
3032

3133
println!("{test_sink}");
34+
3235
if test_sink.failure_count() != 0 {
3336
std::process::exit(1)
3437
}
3538
}
3639

40+
pub fn execute_tests(module_name: &str, tests: &[CompiledTest], sink: &mut TestSink) {
41+
if tests.len() == 1 {
42+
println!("executing 1 test in {module_name}:");
43+
} else {
44+
println!("executing {} tests in {}:", tests.len(), module_name);
45+
}
46+
47+
for test in tests {
48+
print!(" {} ...", test.name);
49+
let test_passed = test.execute(sink);
50+
51+
if test_passed {
52+
println!(" {}", "passed".green())
53+
} else {
54+
println!(" {}", "failed".red())
55+
}
56+
}
57+
println!();
58+
}
59+
3760
fn test_single_file(args: &TestArgs) -> TestSink {
3861
let input_path = &args.input_path;
62+
let optimize = args.optimize.unwrap_or(true);
63+
let logs = args.logs;
3964

4065
let mut db = fe_driver::Db::default();
4166
let content = match std::fs::read_to_string(input_path) {
@@ -46,11 +71,9 @@ fn test_single_file(args: &TestArgs) -> TestSink {
4671
Ok(content) => content,
4772
};
4873

49-
match fe_driver::compile_single_file_tests(&mut db, input_path, &content, true) {
74+
match fe_driver::compile_single_file_tests(&mut db, input_path, &content, optimize) {
5075
Ok((name, tests)) => {
51-
let tests = filter_tests(&tests, &args.filter);
52-
53-
let mut sink = TestSink::default();
76+
let mut sink = TestSink::new(logs);
5477
execute_tests(&name, &tests, &mut sink);
5578
sink
5679
}
@@ -62,29 +85,10 @@ fn test_single_file(args: &TestArgs) -> TestSink {
6285
}
6386
}
6487

65-
pub fn execute_tests(module_name: &str, tests: &[CompiledTest], sink: &mut TestSink) {
66-
if tests.len() == 1 {
67-
println!("executing 1 test in {module_name}:");
68-
} else {
69-
println!("executing {} tests in {}:", tests.len(), module_name);
70-
}
71-
72-
for test in tests {
73-
print!(" {} ...", test.name);
74-
let test_passed = test.execute(sink);
75-
76-
if test_passed {
77-
println!(" {}", "passed".green())
78-
} else {
79-
println!(" {}", "failed".red())
80-
}
81-
}
82-
println!();
83-
}
84-
8588
fn test_ingot(args: &TestArgs) -> TestSink {
8689
let input_path = &args.input_path;
8790
let optimize = args.optimize.unwrap_or(true);
91+
let logs = args.logs;
8892

8993
if !Path::new(input_path).exists() {
9094
eprintln!("Input directory does not exist: `{input_path}`.");
@@ -103,7 +107,7 @@ fn test_ingot(args: &TestArgs) -> TestSink {
103107

104108
match fe_driver::compile_ingot_tests(&mut db, &build_files, optimize) {
105109
Ok(test_batches) => {
106-
let mut sink = TestSink::default();
110+
let mut sink = TestSink::new(logs);
107111
for (module_name, tests) in test_batches {
108112
let tests = filter_tests(&tests, &args.filter);
109113
execute_tests(&module_name, &tests, &mut sink);

crates/test-runner/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ repository = "https://github.com/ethereum/fe"
1010
hex="0.4"
1111
bytes = "1.3"
1212
colored = "2.0"
13+
ethabi = { default-features = false, features = ["full-serde"], version = "18.0" }
14+
indexmap = "1.6.2"
1315

1416
# used by revm; we need to force the js feature for wasm support
1517
getrandom = { version = "0.2.8", features = ["js"] }

0 commit comments

Comments
 (0)