Skip to content

Commit

Permalink
[snforge-test-collector] Add TestDetails to TestCaseRaw (#1121)
Browse files Browse the repository at this point in the history
  • Loading branch information
drknzz authored and maciektr committed Feb 14, 2024
1 parent 2c15014 commit 863bad6
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 66 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ cairo-lang-semantic = "2.6.0-rc.0"
cairo-lang-sierra = "2.6.0-rc.0"
cairo-lang-sierra-generator = "2.6.0-rc.0"
cairo-lang-sierra-to-casm = "2.6.0-rc.0"
cairo-lang-sierra-type-size = "2.6.0-rc.0"
cairo-lang-starknet = "2.6.0-rc.0"
cairo-lang-starknet-classes = "2.6.0-rc.0"
cairo-lang-syntax = "2.6.0-rc.0"
Expand Down
1 change: 1 addition & 0 deletions extensions/scarb-snforge-test-collector/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ cairo-lang-project.workspace = true
cairo-lang-semantic.workspace = true
cairo-lang-sierra.workspace = true
cairo-lang-sierra-generator.workspace = true
cairo-lang-sierra-type-size.workspace = true
cairo-lang-starknet.workspace = true
cairo-lang-syntax.workspace = true
cairo-lang-test-plugin.workspace = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use cairo_lang_semantic::items::functions::GenericFunctionId;
use cairo_lang_semantic::{ConcreteFunction, FunctionLongId};
use cairo_lang_sierra::extensions::enm::EnumType;
use cairo_lang_sierra::extensions::NamedType;
use cairo_lang_sierra::ids::GenericTypeId;
use cairo_lang_sierra::program::{GenericArg, Program};
use cairo_lang_sierra_generator::db::SierraGenGroup;
use cairo_lang_sierra_generator::replace_ids::replace_sierra_ids_in_program;
Expand Down Expand Up @@ -74,6 +75,14 @@ pub struct TestCaseRaw {
pub expected_result: ExpectedTestResult,
pub fork_config: Option<RawForkConfig>,
pub fuzzer_config: Option<FuzzerConfig>,
pub test_details: TestDetails,
}

#[derive(Debug, PartialEq, Clone, Serialize)]
pub struct TestDetails {
pub entry_point_offset: usize,
pub parameter_types: Vec<(GenericTypeId, i16)>,
pub return_types: Vec<(GenericTypeId, i16)>,
}

pub fn collect_tests(
Expand Down Expand Up @@ -138,6 +147,9 @@ pub fn collect_tests(
.context("Compilation failed without any diagnostics")
.context("Failed to get sierra program")?;

let sierra_program = replace_sierra_ids_in_program(db, &sierra_program.program);
let function_finder = FunctionFinder::new(sierra_program.clone())?;

let collected_tests = all_tests
.into_iter()
.map(|(func_id, test)| {
Expand All @@ -157,23 +169,39 @@ pub fn collect_tests(
})
.collect_vec()
.into_iter()
.map(|(test_name, config)| TestCaseRaw {
name: test_name,
available_gas: config.available_gas,
ignored: config.ignored,
expected_result: config.expected_result,
fork_config: config.fork_config,
fuzzer_config: config.fuzzer_config,
.map(|(test_name, config)| {
let test_details = build_test_details(&function_finder, &test_name).unwrap();
TestCaseRaw {
name: test_name,
available_gas: config.available_gas,
ignored: config.ignored,
expected_result: config.expected_result,
fork_config: config.fork_config,
fuzzer_config: config.fuzzer_config,
test_details,
}
})
.collect();

let sierra_program = replace_sierra_ids_in_program(db, &sierra_program.program);

validate_tests(sierra_program.clone(), &collected_tests)?;
validate_tests(&function_finder, &collected_tests)?;

Ok((sierra_program, collected_tests))
}

fn build_test_details(function_finder: &FunctionFinder, test_name: &str) -> Result<TestDetails> {
let func = function_finder.find_function(test_name)?;

let parameter_types =
function_finder.generic_id_and_size_from_concrete(&func.signature.param_types);
let return_types = function_finder.generic_id_and_size_from_concrete(&func.signature.ret_types);

Ok(TestDetails {
entry_point_offset: func.entry_point.0,
parameter_types,
return_types,
})
}

fn build_diagnostics_reporter(compilation_unit: &CompilationUnit) -> DiagnosticsReporter<'static> {
if compilation_unit.allow_warnings() {
DiagnosticsReporter::stderr().allow_warnings()
Expand Down Expand Up @@ -208,13 +236,9 @@ fn insert_lib_entrypoint_content_into_db(
}

fn validate_tests(
sierra_program: Program,
function_finder: &FunctionFinder,
collected_tests: &Vec<TestCaseRaw>,
) -> Result<(), anyhow::Error> {
let function_finder = match FunctionFinder::new(sierra_program) {
Ok(casm_generator) => casm_generator,
Err(e) => panic!("{}", e),
};
for test in collected_tests {
let func = function_finder.find_function(&test.name)?;
let signature = &func.signature;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

use cairo_lang_sierra::extensions::core::{CoreLibfunc, CoreType};
use cairo_lang_sierra::extensions::ConcreteType;
use cairo_lang_sierra::ids::{ConcreteTypeId, GenericTypeId};
use cairo_lang_sierra::program::Function;
use cairo_lang_sierra::program_registry::{ProgramRegistry, ProgramRegistryError};
use cairo_lang_sierra_type_size::{get_type_size_map, TypeSizeMap};
use thiserror::Error;

#[derive(Debug, Error)]
Expand All @@ -12,23 +14,31 @@ pub enum FinderError {
MissingFunction { suffix: String },
#[error(transparent)]
ProgramRegistryError(#[from] Box<ProgramRegistryError>),
#[error("Unable to create TypeSizeMap.")]
TypeSizeMapError,
}

pub struct FunctionFinder {
/// The sierra program.
sierra_program: cairo_lang_sierra::program::Program,
/// Program registry for the Sierra program.
sierra_program_registry: ProgramRegistry<CoreType, CoreLibfunc>,
// Mapping for the sizes of all types for sierra_program
type_size_map: TypeSizeMap,
}

#[allow(clippy::result_large_err)]
impl FunctionFinder {
pub fn new(sierra_program: cairo_lang_sierra::program::Program) -> Result<Self, FinderError> {
let sierra_program_registry =
ProgramRegistry::<CoreType, CoreLibfunc>::new(&sierra_program)?;
let type_size_map = get_type_size_map(&sierra_program, &sierra_program_registry)
.ok_or(FinderError::TypeSizeMapError)?;

Ok(Self {
sierra_program,
sierra_program_registry,
type_size_map,
})
}

Expand Down Expand Up @@ -57,4 +67,20 @@ impl FunctionFinder {
) -> &cairo_lang_sierra::extensions::types::TypeInfo {
self.sierra_program_registry.get_type(ty).unwrap().info()
}

/// Converts array of `ConcreteTypeId`s into corresponding `GenericTypeId`s and their sizes
pub fn generic_id_and_size_from_concrete(
&self,
types: &[ConcreteTypeId],
) -> Vec<(GenericTypeId, i16)> {
types
.iter()
.map(|pt| {
let info = self.get_info(pt);
let generic_id = &info.long_id.generic_id;
let size = self.type_size_map[pt];
(generic_id.clone(), size)
})
.collect()
}
}
98 changes: 47 additions & 51 deletions extensions/scarb-snforge-test-collector/tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,20 @@ fn forge_test_locations() {
assert_eq!(&json[1]["test_cases"][0]["name"], "tests::tests::test");
assert_eq!(&json[1]["tests_location"], "Tests");

assert_eq!(&json[0]["test_cases"][0]["available_gas"], &Value::Null);
assert_eq!(&json[0]["test_cases"][0]["expected_result"], "Success");
assert_eq!(&json[0]["test_cases"][0]["fork_config"], &Value::Null);
assert_eq!(&json[0]["test_cases"][0]["fuzzer_config"], &Value::Null);
assert_eq!(&json[0]["test_cases"][0]["ignored"], false);
let case_0 = &json[0]["test_cases"][0];

assert_eq!(&case_0["available_gas"], &Value::Null);
assert_eq!(&case_0["expected_result"], "Success");
assert_eq!(&case_0["fork_config"], &Value::Null);
assert_eq!(&case_0["fuzzer_config"], &Value::Null);
assert_eq!(&case_0["ignored"], false);
assert_eq!(&case_0["test_details"]["entry_point_offset"], 0);
assert_eq!(
&case_0["test_details"]["parameter_types"],
&Value::Array(vec![])
);
assert_eq!(&case_0["test_details"]["return_types"][0][0], "Enum");
assert_eq!(&case_0["test_details"]["return_types"][0][1], 3);
}

#[test]
Expand Down Expand Up @@ -88,7 +97,9 @@ const WITH_MANY_ATTRIBUTES_TEST: &str = indoc! {r#"
#[available_gas(100)]
#[test]
fn test(a: felt252) {
assert(true == true, 'it works!')
let (x, y) = (1_u8, 2_u8);
let z = x + y;
assert(x < z, 'it works!')
}
}
"#
Expand All @@ -114,37 +125,32 @@ fn forge_test_with_attributes() {
.read_to_string();

let json: Value = serde_json::from_str(&snforge_sierra).unwrap();
let case_0 = &json[0]["test_cases"][0];

assert_eq!(&case_0["available_gas"], &Value::Number(Number::from(100)));
assert_eq!(&case_0["expected_result"]["Panics"], "Any");
assert_eq!(&case_0["fork_config"]["Params"]["block_id_type"], "Number");
assert_eq!(&case_0["fork_config"]["Params"]["block_id_value"], "123");
assert_eq!(
&json[0]["test_cases"][0]["available_gas"],
&Value::Number(Number::from(100))
);
assert_eq!(
&json[0]["test_cases"][0]["expected_result"]["Panics"],
"Any"
);
assert_eq!(
&json[0]["test_cases"][0]["fork_config"]["Params"]["block_id_type"],
"Number"
);
assert_eq!(
&json[0]["test_cases"][0]["fork_config"]["Params"]["block_id_value"],
"123"
);
assert_eq!(
&json[0]["test_cases"][0]["fork_config"]["Params"]["url"],
case_0["fork_config"]["Params"]["url"],
"http://your.rpc.url"
);
assert_eq!(&case_0["fuzzer_config"]["fuzzer_runs"], 22);
assert_eq!(&case_0["fuzzer_config"]["fuzzer_seed"], 38);
assert_eq!(&case_0["ignored"], true);
assert_eq!(&case_0["name"], "forge_test::tests::test");
assert_eq!(&case_0["test_details"]["entry_point_offset"], 0);
assert_eq!(
&json[0]["test_cases"][0]["fuzzer_config"]["fuzzer_runs"],
22
);
assert_eq!(
&json[0]["test_cases"][0]["fuzzer_config"]["fuzzer_seed"],
38
&case_0["test_details"]["parameter_types"][0][0],
"RangeCheck"
);
assert_eq!(&json[0]["test_cases"][0]["ignored"], true);
assert_eq!(&json[0]["test_cases"][0]["name"], "forge_test::tests::test");
assert_eq!(&case_0["test_details"]["parameter_types"][0][1], 1);
assert_eq!(&case_0["test_details"]["parameter_types"][1][0], "felt252");
assert_eq!(&case_0["test_details"]["parameter_types"][1][1], 1);
assert_eq!(&case_0["test_details"]["return_types"][0][0], "RangeCheck");
assert_eq!(&case_0["test_details"]["return_types"][0][1], 1);
assert_eq!(&case_0["test_details"]["return_types"][1][0], "Enum");
assert_eq!(&case_0["test_details"]["return_types"][1][1], 3);
}

const FORK_TAG_TEST: &str = indoc! {r#"
Expand Down Expand Up @@ -179,21 +185,16 @@ fn forge_test_with_fork_tag_attribute() {
.read_to_string();

let json: Value = serde_json::from_str(&snforge_sierra).unwrap();
let case_0 = &json[0]["test_cases"][0];

assert_eq!(&case_0["fork_config"]["Params"]["block_id_type"], "Tag");
assert_eq!(&case_0["fork_config"]["Params"]["block_id_value"], "Latest");
assert_eq!(
&json[0]["test_cases"][0]["fork_config"]["Params"]["block_id_type"],
"Tag"
);
assert_eq!(
&json[0]["test_cases"][0]["fork_config"]["Params"]["block_id_value"],
"Latest"
);
assert_eq!(
&json[0]["test_cases"][0]["fork_config"]["Params"]["url"],
case_0["fork_config"]["Params"]["url"],
"http://your.rpc.url"
);

assert_eq!(&json[0]["test_cases"][0]["name"], "forge_test::tests::test");
assert_eq!(&case_0["name"], "forge_test::tests::test");
}

const FORK_HASH_TEST: &str = indoc! {r#"
Expand Down Expand Up @@ -228,21 +229,16 @@ fn forge_test_with_fork_hash_attribute() {
.read_to_string();

let json: Value = serde_json::from_str(&snforge_sierra).unwrap();
let case_0 = &json[0]["test_cases"][0];

assert_eq!(&case_0["fork_config"]["Params"]["block_id_type"], "Hash");
assert_eq!(&case_0["fork_config"]["Params"]["block_id_value"], "123");
assert_eq!(
&json[0]["test_cases"][0]["fork_config"]["Params"]["block_id_type"],
"Hash"
);
assert_eq!(
&json[0]["test_cases"][0]["fork_config"]["Params"]["block_id_value"],
"123"
);
assert_eq!(
&json[0]["test_cases"][0]["fork_config"]["Params"]["url"],
case_0["fork_config"]["Params"]["url"],
"http://your.rpc.url"
);

assert_eq!(&json[0]["test_cases"][0]["name"], "forge_test::tests::test");
assert_eq!(&case_0["name"], "forge_test::tests::test");
}

const SHOULD_PANIC_TEST: &str = indoc! {r#"
Expand Down

0 comments on commit 863bad6

Please sign in to comment.