Skip to content

Commit b93e9cc

Browse files
Refactor function names generated by plugin (#3671)
<!-- Reference any GitHub issues resolved by this PR --> Towards #1431 **Stack**: - #3697 - #3669 - #3671 ⬅ - #3670 ## Introduced changes This change makes the name of the test function remain the same. Previously, we modified its name by adding `_return_wrapper` and `_actual_body` suffixes. However, while implementing `#[test_case]`, it turned out its tricky to determine the name of the function to be called. ## Checklist <!-- Make sure all of these are complete --> - [ ] Linked relevant issue - [ ] Updated relevant documentation - [ ] Added relevant tests - [x] Performed self-review of the code - [ ] Added changes to `CHANGELOG.md`
1 parent 4dff7b1 commit b93e9cc

File tree

8 files changed

+219
-106
lines changed

8 files changed

+219
-106
lines changed

crates/forge-runner/src/package_tests/with_config_resolved.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::{TestCase, TestTarget};
2-
use crate::expected_result::ExpectedTestResult;
2+
use crate::{expected_result::ExpectedTestResult, package_tests::TestDetails};
33
use anyhow::Result;
44
use cairo_vm::types::program::Program;
55
use cheatnet::runtime_extensions::forge_config_extension::config::{
@@ -13,7 +13,22 @@ pub type TestTargetWithResolvedConfig = TestTarget<TestCaseResolvedConfig>;
1313

1414
pub type TestCaseWithResolvedConfig = TestCase<TestCaseResolvedConfig>;
1515

16+
fn sanitize_test_case_name(name: &str) -> String {
17+
// Test names generated by `#[test]` and `#[fuzzer]` macros contain internal suffixes
18+
name.replace("__snforge_internal_test_generated", "")
19+
.replace("__snforge_internal_fuzzer_generated", "")
20+
}
21+
1622
impl TestCaseWithResolvedConfig {
23+
#[must_use]
24+
pub fn new(name: &str, test_details: TestDetails, config: TestCaseResolvedConfig) -> Self {
25+
Self {
26+
name: sanitize_test_case_name(name),
27+
test_details,
28+
config,
29+
}
30+
}
31+
1732
pub fn try_into_program(
1833
&self,
1934
casm_program: &AssembledProgramWithDebugInfo,

crates/forge/src/run_tests/resolve_config.rs

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,24 +24,25 @@ pub async fn resolve_config(
2424
let env_ignore_fork_tests = env_ignore_fork_tests();
2525

2626
for case in test_target.test_cases {
27-
test_cases.push(TestCaseWithResolvedConfig {
28-
name: case.name,
29-
test_details: case.test_details,
30-
config: TestCaseResolvedConfig {
31-
available_gas: case.config.available_gas,
32-
ignored: case.config.ignored
33-
|| (env_ignore_fork_tests && case.config.fork_config.is_some()),
34-
expected_result: case.config.expected_result,
35-
fork_config: resolve_fork_config(
36-
case.config.fork_config,
37-
block_number_map,
38-
fork_targets,
39-
)
40-
.await?,
41-
fuzzer_config: case.config.fuzzer_config,
42-
disable_predeployed_contracts: case.config.disable_predeployed_contracts,
43-
},
44-
});
27+
let config = TestCaseResolvedConfig {
28+
available_gas: case.config.available_gas,
29+
ignored: case.config.ignored
30+
|| (env_ignore_fork_tests && case.config.fork_config.is_some()),
31+
expected_result: case.config.expected_result,
32+
fork_config: resolve_fork_config(
33+
case.config.fork_config,
34+
block_number_map,
35+
fork_targets,
36+
)
37+
.await?,
38+
fuzzer_config: case.config.fuzzer_config,
39+
disable_predeployed_contracts: case.config.disable_predeployed_contracts,
40+
};
41+
test_cases.push(TestCaseWithResolvedConfig::new(
42+
&case.name,
43+
case.test_details,
44+
config,
45+
));
4546
}
4647

4748
Ok(TestTargetWithResolvedConfig {

crates/snforge-scarb-plugin/src/attributes/fuzzer/wrapper.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,10 @@ fn fuzzer_wrapper_internal(
6767
let vis = func.visibility(db).as_syntax_node();
6868
let vis = SyntaxNodeWithDb::new(&vis, db);
6969

70-
let name = func.declaration(db).name(db).as_syntax_node();
71-
let name = SyntaxNodeWithDb::new(&name, db);
70+
let name = format_ident!(
71+
"{}__snforge_internal_fuzzer_generated",
72+
func.declaration(db).name(db).text(db)
73+
);
7274

7375
let signature = func.declaration(db).signature(db).as_syntax_node();
7476
let signature = SyntaxNodeWithDb::new(&signature, db);
@@ -104,8 +106,8 @@ fn fuzzer_wrapper_internal(
104106
}
105107
});
106108

107-
let actual_body_fn_name =
108-
format_ident!("{}_actual_body", func.declaration(db).name(db).text(db));
109+
let func_name = func.declaration(db).name(db).as_syntax_node();
110+
let func_name = SyntaxNodeWithDb::new(&func_name, db);
109111

110112
let (statements, if_content) = get_statements(db, func);
111113

@@ -117,17 +119,17 @@ fn fuzzer_wrapper_internal(
117119
if snforge_std::_internals::is_config_run() {
118120
#if_content
119121

120-
#actual_body_fn_name(#blank_values_for_config_run);
122+
#func_name(#blank_values_for_config_run);
121123

122124
return;
123125
}
124126
#fuzzer_assignments
125-
#actual_body_fn_name(#arguments_list);
127+
#func_name(#arguments_list);
126128
}
127129

128130
#actual_body_fn_attrs
129131
#[#internal_config_attr]
130-
fn #actual_body_fn_name #signature {
132+
fn #func_name #signature {
131133
#statements
132134
}
133135
))

crates/snforge-scarb-plugin/src/attributes/test.rs

Lines changed: 16 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use super::{AttributeInfo, ErrorExt, internal_config_statement::InternalConfigStatementCollector};
22
use crate::asserts::assert_is_used_once;
3-
use crate::attributes::fuzzer::wrapper::FuzzerWrapperCollector;
4-
use crate::attributes::fuzzer::{FuzzerCollector, FuzzerConfigCollector};
3+
use crate::common::has_fuzzer_attribute;
54
use crate::external_inputs::ExternalInput;
65
use crate::utils::create_single_token;
76
use crate::{
@@ -13,7 +12,6 @@ use cairo_lang_macro::{Diagnostic, Diagnostics, ProcMacroResult, TokenStream, qu
1312
use cairo_lang_parser::utils::SimpleParserDatabase;
1413
use cairo_lang_syntax::node::with_db::SyntaxNodeWithDb;
1514
use cairo_lang_syntax::node::{Terminal, TypedSyntaxNode, ast::FunctionWithBody};
16-
use std::ops::Not;
1715

1816
pub struct TestCollector;
1917

@@ -55,8 +53,15 @@ fn test_internal(
5553
None => true,
5654
};
5755

58-
let name = func.declaration(db).name(db).as_syntax_node();
59-
let name = SyntaxNodeWithDb::new(&name, db);
56+
let has_fuzzer = has_fuzzer_attribute(db, func);
57+
58+
// If there is `#[fuzzer]` attribute, called function is suffixed with `__snforge_internal_fuzzer_generated`
59+
// `#[__fuzzer_wrapper]` is responsible for adding this suffix.
60+
let called_func_ident = if has_fuzzer {
61+
format_ident!("{name}__snforge_internal_fuzzer_generated")
62+
} else {
63+
format_ident!("{}", name)
64+
};
6065

6166
let signature = func.declaration(db).signature(db).as_syntax_node();
6267
let signature = SyntaxNodeWithDb::new(&signature, db);
@@ -68,35 +73,32 @@ fn test_internal(
6873
let attributes = func.attributes(db).as_syntax_node();
6974
let attributes = SyntaxNodeWithDb::new(&attributes, db);
7075

71-
let name_return_wrapper =
72-
format_ident!("{}_return_wrapper", func.declaration(db).name(db).text(db));
73-
74-
let mut return_wrapper = TokenStream::new(vec![name_return_wrapper.clone()]);
75-
return_wrapper.extend(signature);
76+
let test_func_ident = format_ident!("{}__snforge_internal_test_generated", name);
77+
let func_ident = format_ident!("{}", name);
7678

7779
let out_of_gas = create_single_token("'Out of gas'");
7880

7981
if should_run_test {
8082
Ok(quote!(
8183
#[implicit_precedence(core::pedersen::Pedersen, core::RangeCheck, core::integer::Bitwise, core::ec::EcOp, core::poseidon::Poseidon, core::SegmentArena, core::circuit::RangeCheck96, core::circuit::AddMod, core::circuit::MulMod, core::gas::GasBuiltin, System)]
8284
#[snforge_internal_test_executable]
83-
fn #name(mut _data: Span<felt252>) -> Span::<felt252> {
85+
fn #test_func_ident(mut _data: Span<felt252>) -> Span::<felt252> {
8486
core::internal::require_implicit::<System>();
8587
core::internal::revoke_ap_tracking();
8688
core::option::OptionTraitImpl::expect(core::gas::withdraw_gas(), #out_of_gas);
8789

8890
core::option::OptionTraitImpl::expect(
8991
core::gas::withdraw_gas_all(core::gas::get_builtin_costs()), #out_of_gas
9092
);
91-
#name_return_wrapper();
93+
#called_func_ident();
9294

9395
let mut arr = ArrayTrait::new();
9496
core::array::ArrayTrait::span(@arr)
9597
}
9698

9799
#attributes
98100
#[#internal_config]
99-
fn #return_wrapper
101+
fn #func_ident #signature
100102
#body
101103
))
102104
} else {
@@ -111,7 +113,7 @@ fn ensure_parameters_only_with_fuzzer_attribute(
111113
db: &SimpleParserDatabase,
112114
func: &FunctionWithBody,
113115
) -> Result<(), Diagnostic> {
114-
if has_parameters(db, func) && no_fuzzer_attribute(db, func) {
116+
if has_parameters(db, func) && !has_fuzzer_attribute(db, func) {
115117
Err(TestCollector::error(
116118
"function with parameters must have #[fuzzer] attribute",
117119
))?;
@@ -128,24 +130,3 @@ fn has_parameters(db: &SimpleParserDatabase, func: &FunctionWithBody) -> bool {
128130
.len()
129131
!= 0
130132
}
131-
132-
fn no_fuzzer_attribute(db: &SimpleParserDatabase, func: &FunctionWithBody) -> bool {
133-
const FUZZER_ATTRIBUTES: [&str; 3] = [
134-
FuzzerCollector::ATTR_NAME,
135-
FuzzerWrapperCollector::ATTR_NAME,
136-
FuzzerConfigCollector::ATTR_NAME,
137-
];
138-
139-
func.attributes(db)
140-
.elements(db)
141-
.any(|attr| {
142-
FUZZER_ATTRIBUTES.contains(
143-
&attr
144-
.attr(db)
145-
.as_syntax_node()
146-
.get_text_without_trivia(db)
147-
.as_str(),
148-
)
149-
})
150-
.not()
151-
}

crates/snforge-scarb-plugin/src/common.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
use crate::{
22
args::Arguments,
3-
attributes::AttributeInfo,
3+
attributes::{
4+
AttributeInfo,
5+
fuzzer::{FuzzerCollector, FuzzerConfigCollector, wrapper::FuzzerWrapperCollector},
6+
},
47
parse::{parse, parse_args},
58
};
69
use cairo_lang_macro::{Diagnostic, Diagnostics, ProcMacroResult, TokenStream};
710
use cairo_lang_parser::utils::SimpleParserDatabase;
8-
use cairo_lang_syntax::node::ast::FunctionWithBody;
11+
use cairo_lang_syntax::node::{TypedSyntaxNode, ast::FunctionWithBody};
912
use cairo_lang_utils::Upcast;
1013

1114
#[expect(clippy::needless_pass_by_value)]
@@ -58,3 +61,28 @@ where
5861

5962
handler(db, &func, args_db, args, warns)
6063
}
64+
65+
fn has_any_attribute(
66+
db: &SimpleParserDatabase,
67+
func: &FunctionWithBody,
68+
attr_names: &[&str],
69+
) -> bool {
70+
func.attributes(db).elements(db).any(|attr| {
71+
attr_names.contains(
72+
&attr
73+
.attr(db)
74+
.as_syntax_node()
75+
.get_text_without_trivia(db)
76+
.as_str(),
77+
)
78+
})
79+
}
80+
81+
pub fn has_fuzzer_attribute(db: &SimpleParserDatabase, func: &FunctionWithBody) -> bool {
82+
const FUZZER_ATTRIBUTES: [&str; 3] = [
83+
FuzzerCollector::ATTR_NAME,
84+
FuzzerWrapperCollector::ATTR_NAME,
85+
FuzzerConfigCollector::ATTR_NAME,
86+
];
87+
has_any_attribute(db, func, &FUZZER_ATTRIBUTES)
88+
}

0 commit comments

Comments
 (0)