diff --git a/crates/forge-runner/src/lib.rs b/crates/forge-runner/src/lib.rs index 57a0ef6e84..616f94c207 100644 --- a/crates/forge-runner/src/lib.rs +++ b/crates/forge-runner/src/lib.rs @@ -12,7 +12,6 @@ use foundry_ui::UI; use foundry_ui::components::warning::WarningMessage; use futures::StreamExt; use futures::stream::FuturesUnordered; -use package_tests::with_config_resolved::TestCaseWithResolvedConfig; use profiler_api::run_profiler; use rand::SeedableRng; use rand::prelude::StdRng; @@ -58,9 +57,9 @@ const BUILTINS: [&str; 11] = [ ]; pub trait TestCaseFilter { - fn should_be_run(&self, test_case: &TestCase) -> bool - where - T: TestCaseIsIgnored; + fn should_be_run(&self, test_case: &TestCase) -> bool; + + fn should_run_test(&self, test_case_config: bool) -> bool; } pub trait TestCaseIsIgnored { @@ -113,7 +112,7 @@ pub fn maybe_generate_coverage( #[must_use] #[tracing::instrument(skip_all, level = "debug")] pub fn run_for_test_case( - case: Arc, + case: Arc, casm_program: Arc, forge_config: Arc, versioned_program_path: Arc, @@ -148,7 +147,7 @@ pub fn run_for_test_case( #[tracing::instrument(skip_all, level = "debug")] fn run_with_fuzzing( - case: Arc, + case: Arc, casm_program: Arc, forge_config: Arc, versioned_program_path: Arc, diff --git a/crates/forge-runner/src/package_tests.rs b/crates/forge-runner/src/package_tests.rs index 42fea5110d..991417390a 100644 --- a/crates/forge-runner/src/package_tests.rs +++ b/crates/forge-runner/src/package_tests.rs @@ -1,20 +1,27 @@ +use crate::package_tests::raw::TestTargetRaw; +use crate::package_tests::with_config_resolved::TestCaseResolvedConfig; use crate::running::hints_to_params; -use anyhow::Result; +use anyhow::{Result, anyhow}; use cairo_lang_sierra::extensions::NamedType; use cairo_lang_sierra::extensions::bitwise::BitwiseType; use cairo_lang_sierra::extensions::circuit::{AddModType, MulModType}; +use cairo_lang_sierra::extensions::core::{CoreLibfunc, CoreType}; use cairo_lang_sierra::extensions::ec::EcOpType; use cairo_lang_sierra::extensions::pedersen::PedersenType; use cairo_lang_sierra::extensions::poseidon::PoseidonType; use cairo_lang_sierra::extensions::range_check::{RangeCheck96Type, RangeCheckType}; use cairo_lang_sierra::extensions::segment_arena::SegmentArenaType; -use cairo_lang_sierra::ids::GenericTypeId; -use cairo_lang_sierra::program::ProgramArtifact; +use cairo_lang_sierra::ids::{ConcreteTypeId, GenericTypeId}; +use cairo_lang_sierra::program::{GenFunction, ProgramArtifact, StatementIdx, TypeDeclaration}; +use cairo_lang_sierra::program_registry::ProgramRegistry; +use cairo_lang_sierra_type_size::get_type_size_map; +use cairo_lang_utils::unordered_hash_map::UnorderedHashMap; use cairo_vm::serde::deserialize_program::ReferenceManager; use cairo_vm::types::builtin_name::BuiltinName; use cairo_vm::types::program::Program; use cairo_vm::types::relocatable::MaybeRelocatable; use camino::Utf8PathBuf; +use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use serde::Serialize; use starknet_types_core::felt::Felt; use std::collections::HashMap; @@ -66,6 +73,30 @@ impl TestDetails { builtins } + #[tracing::instrument(skip_all, level = "debug")] + fn build( + func: &GenFunction, + type_declarations: &HashMap, + type_size_map: &UnorderedHashMap, + ) -> Self { + let map_types = |concrete_types: &[ConcreteTypeId]| { + concrete_types + .iter() + .map(|ty| { + let ty = type_declarations[&ty.id]; + + (ty.long_id.generic_id.clone(), type_size_map[&ty.id]) + }) + .collect() + }; + + Self { + sierra_entry_point_statement_idx: func.entry_point.0, + parameter_types: map_types(&func.signature.param_types), + return_types: map_types(&func.signature.ret_types), + } + } + pub fn try_into_program(&self, casm_program: &RawCasmProgram) -> Result { let builtins = self.builtins(); @@ -95,17 +126,87 @@ impl TestDetails { } #[derive(Debug, Clone)] -pub struct TestTarget { +pub struct TestTarget { + pub tests_location: TestTargetLocation, + pub sierra_program: ProgramArtifact, + pub sierra_program_path: Arc, + pub test_cases: Vec, +} + +impl TestTarget { + #[tracing::instrument(skip_all, level = "debug")] + pub fn from_raw(test_target_raw: TestTargetRaw) -> Result { + macro_rules! by_id { + ($field:ident) => {{ + let temp: HashMap<_, _> = test_target_raw + .sierra_program + .program + .$field + .iter() + .map(|f| (f.id.id, f)) + .collect(); + + temp + }}; + } + let funcs = by_id!(funcs); + let type_declarations = by_id!(type_declarations); + + let sierra_program_registry = + ProgramRegistry::::new(&test_target_raw.sierra_program.program)?; + let type_size_map = get_type_size_map( + &test_target_raw.sierra_program.program, + &sierra_program_registry, + ) + .ok_or_else(|| anyhow!("can not get type size map"))?; + + let default_executables = vec![]; + let debug_info = test_target_raw.sierra_program.debug_info.clone(); + let executables = debug_info + .as_ref() + .and_then(|info| info.executables.get("snforge_internal_test_executable")) + .unwrap_or(&default_executables); + + let test_cases = executables + .par_iter() + .map(|case| -> Result { + let func = funcs[&case.id]; + let test_details = TestDetails::build(func, &type_declarations, &type_size_map); + + Ok(TestCandidate { + name: case.debug_name.clone().unwrap().into(), + test_details, + }) + }) + .collect::>()?; + + Ok(TestTarget { + tests_location: test_target_raw.tests_location, + test_cases, + sierra_program: test_target_raw.sierra_program, + sierra_program_path: test_target_raw.sierra_program_path.into(), + }) + } +} + +#[derive(Debug, Clone)] +pub struct TestTargetResolved { pub tests_location: TestTargetLocation, pub sierra_program: ProgramArtifact, pub sierra_program_path: Arc, pub casm_program: Arc, - pub test_cases: Vec>, + pub test_cases: Vec, } #[derive(Debug, Clone, PartialEq)] -pub struct TestCase { +pub struct TestCandidate { + pub name: String, pub test_details: TestDetails, +} + +#[derive(Debug, Clone, PartialEq)] +pub struct TestCase { pub name: String, - pub config: C, + pub test_details: TestDetails, + pub config: TestCaseResolvedConfig, } diff --git a/crates/forge-runner/src/package_tests/with_config.rs b/crates/forge-runner/src/package_tests/with_config.rs index 73481e43ea..50d0af3962 100644 --- a/crates/forge-runner/src/package_tests/with_config.rs +++ b/crates/forge-runner/src/package_tests/with_config.rs @@ -1,18 +1,13 @@ -use super::{TestCase, TestTarget}; use crate::{ TestCaseIsIgnored, expected_result::{ExpectedPanicValue, ExpectedTestResult}, }; use cheatnet::runtime_extensions::forge_config_extension::config::{ - Expected, RawAvailableResourceBoundsConfig, RawForgeConfig, RawForkConfig, RawFuzzerConfig, + Expected, RawAvailableResourceBoundsConfig, RawForkConfig, RawFuzzerConfig, RawShouldPanicConfig, }; use conversions::serde::serialize::SerializeToFeltVec; -pub type TestTargetWithConfig = TestTarget; - -pub type TestCaseWithConfig = TestCase; - /// Test case with config that has not yet been resolved /// see [`super::with_config_resolved::TestCaseResolvedConfig`] for more info #[derive(Debug, Clone)] @@ -31,21 +26,6 @@ impl TestCaseIsIgnored for TestCaseConfig { } } -impl From for TestCaseConfig { - fn from(value: RawForgeConfig) -> Self { - Self { - available_gas: value.available_gas, - ignored: value.ignore.is_some_and(|v| v.is_ignored), - expected_result: value.should_panic.into(), - fork_config: value.fork, - fuzzer_config: value.fuzzer, - disable_predeployed_contracts: value - .disable_predeployed_contracts - .is_some_and(|v| v.is_disabled), - } - } -} - impl From> for ExpectedTestResult { fn from(value: Option) -> Self { match value { diff --git a/crates/forge-runner/src/package_tests/with_config_resolved.rs b/crates/forge-runner/src/package_tests/with_config_resolved.rs index 0423a75559..159f48a2c5 100644 --- a/crates/forge-runner/src/package_tests/with_config_resolved.rs +++ b/crates/forge-runner/src/package_tests/with_config_resolved.rs @@ -1,4 +1,4 @@ -use super::{TestCase, TestTarget}; +use super::TestCase; use crate::{TestCaseIsIgnored, expected_result::ExpectedTestResult, package_tests::TestDetails}; use anyhow::Result; use cairo_vm::types::program::Program; @@ -9,17 +9,13 @@ use starknet_api::block::BlockNumber; use universal_sierra_compiler_api::representation::RawCasmProgram; use url::Url; -pub type TestTargetWithResolvedConfig = TestTarget; - -pub type TestCaseWithResolvedConfig = TestCase; - fn sanitize_test_case_name(name: &str) -> String { // Test names generated by `#[test]` and `#[fuzzer]` macros contain internal suffixes name.replace("__snforge_internal_test_generated", "") .replace("__snforge_internal_fuzzer_generated", "") } -impl TestCaseWithResolvedConfig { +impl TestCase { #[must_use] pub fn new(name: &str, test_details: TestDetails, config: TestCaseResolvedConfig) -> Self { Self { diff --git a/crates/forge-runner/src/running.rs b/crates/forge-runner/src/running.rs index a099753cb8..d6ae72099c 100644 --- a/crates/forge-runner/src/running.rs +++ b/crates/forge-runner/src/running.rs @@ -1,7 +1,8 @@ use crate::backtrace::add_backtrace_footer; use crate::forge_config::{ForgeConfig, RuntimeConfig}; use crate::gas::calculate_used_gas; -use crate::package_tests::with_config_resolved::{ResolvedForkConfig, TestCaseWithResolvedConfig}; +use crate::package_tests::TestCase; +use crate::package_tests::with_config_resolved::ResolvedForkConfig; use crate::test_case_summary::{Single, TestCaseSummary}; use anyhow::{Result, bail}; use blockifier::execution::call_info::CallInfo; @@ -62,7 +63,7 @@ pub use syscall_handler::syscall_handler_offset; #[must_use] #[tracing::instrument(skip_all, level = "debug")] pub fn run_test( - case: Arc, + case: Arc, casm_program: Arc, forge_config: Arc, versioned_program_path: Arc, @@ -98,7 +99,7 @@ pub fn run_test( #[tracing::instrument(skip_all, level = "debug")] #[allow(clippy::too_many_arguments)] pub(crate) fn run_fuzz_test( - case: Arc, + case: Arc, program: Program, casm_program: Arc, forge_config: Arc, @@ -165,7 +166,7 @@ pub enum RunResult { #[expect(clippy::too_many_lines)] #[tracing::instrument(skip_all, level = "debug")] pub fn run_test_case( - case: &TestCaseWithResolvedConfig, + case: &TestCase, program: &Program, casm_program: &RawCasmProgram, runtime_config: &RuntimeConfig, @@ -395,7 +396,7 @@ pub fn run_test_case( fn extract_test_case_summary( run_result: Result, - case: &TestCaseWithResolvedConfig, + case: &TestCase, forge_config: &ForgeConfig, versioned_program_path: &Utf8Path, ) -> TestCaseSummary { diff --git a/crates/forge-runner/src/running/with_config.rs b/crates/forge-runner/src/running/with_config.rs index 68ac1111b9..8b13789179 100644 --- a/crates/forge-runner/src/running/with_config.rs +++ b/crates/forge-runner/src/running/with_config.rs @@ -1,112 +1 @@ -use crate::{ - forge_config::ForgeTrackedResource, - package_tests::{ - TestDetails, - raw::TestTargetRaw, - with_config::{TestCaseWithConfig, TestTargetWithConfig}, - }, - running::config_run::run_config_pass, -}; -use anyhow::{Result, anyhow}; -use cairo_lang_sierra::{ - extensions::core::{CoreLibfunc, CoreType}, - ids::ConcreteTypeId, - program::{GenFunction, StatementIdx, TypeDeclaration}, - program_registry::ProgramRegistry, -}; -use cairo_lang_sierra_type_size::get_type_size_map; -use cairo_lang_utils::unordered_hash_map::UnorderedHashMap; -use rayon::iter::IntoParallelRefIterator; -use rayon::iter::ParallelIterator; -use std::{collections::HashMap, sync::Arc}; -use universal_sierra_compiler_api::compile_raw_sierra_at_path; -#[tracing::instrument(skip_all, level = "debug")] -pub fn test_target_with_config( - test_target_raw: TestTargetRaw, - tracked_resource: &ForgeTrackedResource, -) -> Result { - macro_rules! by_id { - ($field:ident) => {{ - let temp: HashMap<_, _> = test_target_raw - .sierra_program - .program - .$field - .iter() - .map(|f| (f.id.id, f)) - .collect(); - - temp - }}; - } - let funcs = by_id!(funcs); - let type_declarations = by_id!(type_declarations); - - let casm_program = Arc::new(compile_raw_sierra_at_path( - test_target_raw.sierra_program_path.as_std_path(), - )?); - - let sierra_program_registry = - ProgramRegistry::::new(&test_target_raw.sierra_program.program)?; - let type_size_map = get_type_size_map( - &test_target_raw.sierra_program.program, - &sierra_program_registry, - ) - .ok_or_else(|| anyhow!("can not get type size map"))?; - - let default_executables = vec![]; - let debug_info = test_target_raw.sierra_program.debug_info.clone(); - let executables = debug_info - .as_ref() - .and_then(|info| info.executables.get("snforge_internal_test_executable")) - .unwrap_or(&default_executables); - - let test_cases = executables - .par_iter() - .map(|case| -> Result { - let func = funcs[&case.id]; - - let test_details = build_test_details(func, &type_declarations, &type_size_map); - - let raw_config = run_config_pass(&test_details, &casm_program, tracked_resource)?; - - Ok(TestCaseWithConfig { - config: raw_config.into(), - name: case.debug_name.clone().unwrap().into(), - test_details, - }) - }) - .collect::>()?; - - Ok(TestTargetWithConfig { - tests_location: test_target_raw.tests_location, - test_cases, - sierra_program: test_target_raw.sierra_program, - sierra_program_path: test_target_raw.sierra_program_path.into(), - casm_program, - }) -} - -#[tracing::instrument(skip_all, level = "debug")] -fn build_test_details( - func: &GenFunction, - type_declarations: &HashMap, - type_size_map: &UnorderedHashMap, -) -> TestDetails { - let map_types = |concrete_types: &[ConcreteTypeId]| { - concrete_types - .iter() - .map(|ty| { - let ty = type_declarations[&ty.id]; - - (ty.long_id.generic_id.clone(), type_size_map[&ty.id]) - }) - .collect() - }; - - TestDetails { - sierra_entry_point_statement_idx: func.entry_point.0, - parameter_types: map_types(&func.signature.param_types), - return_types: map_types(&func.signature.ret_types), - } -} diff --git a/crates/forge-runner/src/test_case_summary.rs b/crates/forge-runner/src/test_case_summary.rs index 980b884982..ee421aa29d 100644 --- a/crates/forge-runner/src/test_case_summary.rs +++ b/crates/forge-runner/src/test_case_summary.rs @@ -4,7 +4,7 @@ use crate::debugging::{TraceArgs, build_debugging_trace}; use crate::expected_result::{ExpectedPanicValue, ExpectedTestResult}; use crate::gas::check_available_gas; use crate::gas::stats::GasStats; -use crate::package_tests::with_config_resolved::TestCaseWithResolvedConfig; +use crate::package_tests::TestCase; use crate::running::{RunCompleted, RunStatus}; use cairo_annotations::trace_data::VersionedCallTrace as VersionedProfilerCallTrace; use camino::Utf8Path; @@ -284,7 +284,7 @@ impl TestCaseSummary { fuzzer_args, fork_data, }: RunCompleted, - test_case: &TestCaseWithResolvedConfig, + test_case: &TestCase, contracts_data: &ContractsData, versioned_program_path: &Utf8Path, trace_args: &TraceArgs, @@ -320,7 +320,7 @@ impl TestCaseSummary { } ExpectedTestResult::Panics(expected_panic_value) => TestCaseSummary::Failed { name, - msg: Some(build_expected_panic_message(expected_panic_value)), + msg: Some(build_expected_panic_message(&expected_panic_value)), fuzzer_args, test_statistics: (), debugging_trace, @@ -337,7 +337,7 @@ impl TestCaseSummary { }, ExpectedTestResult::Panics(expected_panic_value) => { let (matching, msg) = - check_if_matching_and_get_message(&value, expected_panic_value); + check_if_matching_and_get_message(&value, &expected_panic_value); if matching { TestCaseSummary::Passed { name, diff --git a/crates/forge/src/run_tests/package.rs b/crates/forge/src/run_tests/package.rs index 3304c49f9e..2e60f02412 100644 --- a/crates/forge/src/run_tests/package.rs +++ b/crates/forge/src/run_tests/package.rs @@ -1,40 +1,24 @@ -use super::{ - resolve_config::resolve_config, - test_target::{TestTargetRunResult, run_for_test_target}, -}; -use crate::scarb::load_package_config; +use super::test_target::{TestTargetRunResult, run_for_test_target}; +use crate::run_tests::resolve_config::resolve_config; use crate::{ - TestArgs, block_number_map::BlockNumberMap, - combine_configs::combine_configs, - run_tests::{ - messages::{ - collected_tests_count::CollectedTestsCountMessage, tests_run::TestsRunMessage, - tests_summary::TestsSummaryMessage, - }, - workspace::WorkspaceDirs, - }, - scarb::{ - config::{ForgeConfigFromScarb, ForkTarget}, - load_test_artifacts, + run_tests::messages::{ + collected_tests_count::CollectedTestsCountMessage, tests_summary::TestsSummaryMessage, }, - shared_cache::FailedTestsCache, + scarb::config::ForkTarget, test_filter::{NameFilter, TestsFilter}, warn::warn_if_incompatible_rpc_version, }; use anyhow::Result; -use cheatnet::runtime_extensions::forge_runtime_extension::contracts_data::ContractsData; use console::Style; +use forge_runner::package_tests::TestTargetResolved; use forge_runner::{ - forge_config::ForgeConfig, - package_tests::{raw::TestTargetRaw, with_config_resolved::TestTargetWithResolvedConfig}, - running::with_config::test_target_with_config, + forge_config::{ForgeConfig, ForgeTrackedResource}, + package_tests::TestTarget, test_case_summary::AnyTestCaseSummary, test_target_summary::TestTargetSummary, }; use foundry_ui::{UI, components::labeled::LabeledMessage}; -use scarb_api::{CompilationOpts, get_contracts_artifacts_and_source_sierra_paths}; -use scarb_metadata::{Metadata, PackageMetadata}; use std::sync::Arc; pub struct PackageTestResult { @@ -62,95 +46,25 @@ impl PackageTestResult { } } -pub struct RunForPackageArgs { - pub test_targets: Vec, - pub tests_filter: TestsFilter, - pub forge_config: Arc, - pub fork_targets: Vec, - pub package_name: String, -} - -impl RunForPackageArgs { - #[tracing::instrument(skip_all, level = "debug")] - pub fn build( - package: PackageMetadata, - scarb_metadata: &Metadata, - args: &TestArgs, - workspace_dirs: &WorkspaceDirs, - ui: &UI, - ) -> Result { - let raw_test_targets = load_test_artifacts(&workspace_dirs.artifacts_dir, &package)?; - - let contracts = get_contracts_artifacts_and_source_sierra_paths( - &workspace_dirs.artifacts_dir, - &package, - ui, - CompilationOpts { - use_test_target_contracts: !args.no_optimization, - #[cfg(feature = "cairo-native")] - run_native: args.run_native, - }, - )?; - let contracts_data = ContractsData::try_from(contracts)?; - - let forge_config_from_scarb = - load_package_config::(scarb_metadata, &package.id)?; - let forge_config = Arc::new(combine_configs( - args.exit_first, - args.fuzzer_runs, - args.fuzzer_seed, - args.detailed_resources, - args.save_trace_data, - args.build_profile, - args.coverage, - args.max_n_steps, - args.tracked_resource, - contracts_data, - workspace_dirs.cache_dir.clone(), - &forge_config_from_scarb, - &args.additional_args, - args.trace_args.clone(), - args.experimental_oracles, - )); - - let test_filter = TestsFilter::from_flags( - args.test_filter.clone(), - args.exact, - args.skip.clone(), - args.only_ignored, - args.include_ignored, - args.rerun_failed, - FailedTestsCache::new(&workspace_dirs.cache_dir), - ); - - Ok(RunForPackageArgs { - test_targets: raw_test_targets, - forge_config, - tests_filter: test_filter, - fork_targets: forge_config_from_scarb.fork, - package_name: package.name, - }) - } -} - #[tracing::instrument(skip_all, level = "debug")] -async fn test_package_with_config_resolved( - test_targets: Vec, +pub async fn test_package_with_config_resolved( + test_targets: Vec, fork_targets: &[ForkTarget], block_number_map: &mut BlockNumberMap, - forge_config: &ForgeConfig, tests_filter: &TestsFilter, -) -> Result> { + tracked_resource: &ForgeTrackedResource, +) -> Result> { let mut test_targets_with_resolved_config = Vec::with_capacity(test_targets.len()); for test_target in test_targets { - let test_target = test_target_with_config( + let test_target = resolve_config( test_target, - &forge_config.test_runner_config.tracked_resource, - )?; - - let test_target = - resolve_config(test_target, fork_targets, block_number_map, tests_filter).await?; + fork_targets, + block_number_map, + tests_filter, + tracked_resource, + ) + .await?; test_targets_with_resolved_config.push(test_target); } @@ -158,30 +72,18 @@ async fn test_package_with_config_resolved( Ok(test_targets_with_resolved_config) } -fn sum_test_cases(test_targets: &[TestTargetWithResolvedConfig]) -> usize { +fn sum_test_cases(test_targets: &[TestTargetResolved]) -> usize { test_targets.iter().map(|tc| tc.test_cases.len()).sum() } #[tracing::instrument(skip_all, level = "debug")] pub async fn run_for_package( - RunForPackageArgs { - test_targets, - forge_config, - tests_filter, - fork_targets, - package_name, - }: RunForPackageArgs, - block_number_map: &mut BlockNumberMap, + package_name: String, + forge_config: Arc, + mut test_targets: Vec, + tests_filter: &TestsFilter, ui: Arc, ) -> Result { - let mut test_targets = test_package_with_config_resolved( - test_targets, - &fork_targets, - block_number_map, - &forge_config, - &tests_filter, - ) - .await?; let all_tests = sum_test_cases(&test_targets); for test_target in &mut test_targets { @@ -200,11 +102,6 @@ pub async fn run_for_package( for test_target in test_targets { let ui = ui.clone(); - ui.println(&TestsRunMessage::new( - test_target.tests_location, - test_target.test_cases.len(), - )); - let summary = run_for_test_target(test_target, forge_config.clone(), &tests_filter, ui).await?; diff --git a/crates/forge/src/run_tests/resolve_config.rs b/crates/forge/src/run_tests/resolve_config.rs index f011413419..aa6cc33220 100644 --- a/crates/forge/src/run_tests/resolve_config.rs +++ b/crates/forge/src/run_tests/resolve_config.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use super::maat::env_ignore_fork_tests; use crate::{ block_number_map::BlockNumberMap, scarb::config::ForkTarget, test_filter::TestsFilter, @@ -9,52 +11,60 @@ use cheatnet::runtime_extensions::forge_config_extension::config::{ use conversions::byte_array::ByteArray; use forge_runner::{ TestCaseFilter, + forge_config::ForgeTrackedResource, package_tests::{ - with_config::TestTargetWithConfig, - with_config_resolved::{ - ResolvedForkConfig, TestCaseResolvedConfig, TestCaseWithResolvedConfig, - TestTargetWithResolvedConfig, - }, + TestCase, TestTarget, TestTargetResolved, + with_config_resolved::{ResolvedForkConfig, TestCaseResolvedConfig}, }, + running::config_run::run_config_pass, }; use starknet_api::block::BlockNumber; +use universal_sierra_compiler_api::compile_raw_sierra_at_path; #[tracing::instrument(skip_all, level = "debug")] pub async fn resolve_config( - test_target: TestTargetWithConfig, + test_target: TestTarget, fork_targets: &[ForkTarget], block_number_map: &mut BlockNumberMap, tests_filter: &TestsFilter, -) -> Result { + tracked_resource: &ForgeTrackedResource, +) -> Result { let mut test_cases = Vec::with_capacity(test_target.test_cases.len()); let env_ignore_fork_tests = env_ignore_fork_tests(); + let casm_program = Arc::new(compile_raw_sierra_at_path( + test_target.sierra_program_path.as_std_path(), + )?); + for case in test_target.test_cases { - test_cases.push(TestCaseWithResolvedConfig::new( + let raw_config = run_config_pass(&case.test_details, &casm_program, tracked_resource)?; + let ignored = raw_config.ignore.is_some_and(|v| v.is_ignored); + + test_cases.push(TestCase::new( &case.name, case.test_details.clone(), TestCaseResolvedConfig { - available_gas: case.config.available_gas, - ignored: case.config.ignored - || (env_ignore_fork_tests && case.config.fork_config.is_some()), - fork_config: if tests_filter.should_be_run(&case) { - resolve_fork_config(case.config.fork_config, block_number_map, fork_targets) - .await? + available_gas: raw_config.available_gas, + ignored: ignored || (env_ignore_fork_tests && raw_config.fork.is_some()), + fork_config: if tests_filter.should_run_test(ignored) { + resolve_fork_config(raw_config.fork, block_number_map, fork_targets).await? } else { None }, - expected_result: case.config.expected_result, - fuzzer_config: case.config.fuzzer_config, - disable_predeployed_contracts: case.config.disable_predeployed_contracts, + expected_result: raw_config.should_panic.into(), + fuzzer_config: raw_config.fuzzer, + disable_predeployed_contracts: raw_config + .disable_predeployed_contracts + .is_some_and(|v| v.is_disabled), }, )); } - Ok(TestTargetWithResolvedConfig { + Ok(TestTargetResolved { tests_location: test_target.tests_location, sierra_program: test_target.sierra_program, sierra_program_path: test_target.sierra_program_path, - casm_program: test_target.casm_program, + casm_program: casm_program, test_cases, }) } @@ -136,11 +146,8 @@ mod tests { use crate::shared_cache::FailedTestsCache; use cairo_lang_sierra::program::ProgramArtifact; use cairo_lang_sierra::{ids::GenericTypeId, program::Program}; - use forge_runner::package_tests::TestTargetLocation; - use forge_runner::package_tests::with_config::{TestCaseConfig, TestCaseWithConfig}; - use forge_runner::{expected_result::ExpectedTestResult, package_tests::TestDetails}; + use forge_runner::package_tests::{TestCandidate, TestDetails, TestTargetLocation}; use std::sync::Arc; - use universal_sierra_compiler_api::compile_raw_sierra; use url::Url; fn program_for_testing() -> ProgramArtifact { @@ -157,19 +164,11 @@ mod tests { fn create_test_case_with_config( name: &str, - ignored: bool, - fork_config: Option, - ) -> TestCaseWithConfig { - TestCaseWithConfig { + _ignored: bool, + _fork_config: Option, + ) -> TestCandidate { + TestCandidate { name: name.to_string(), - config: TestCaseConfig { - available_gas: None, - ignored, - expected_result: ExpectedTestResult::Success, - fork_config, - fuzzer_config: None, - disable_predeployed_contracts: false, - }, test_details: TestDetails { sierra_entry_point_statement_idx: 100, parameter_types: vec![ @@ -182,17 +181,27 @@ mod tests { (GenericTypeId("Enum".into()), 3), ], }, + // TODO: Change + // config: TestCaseResolvedConfig { + // available_gas: None, + // ignored: _ignored, + // expected_result: forge_runner::expected_result::ExpectedTestResult::Panics( + // "some panic".into(), + // ), + // fork_config: _fork_config.map(|_| ResolvedForkConfig { + // url: Url::parse("https://example.com").unwrap(), + // block_number: BlockNumber(42), + // }), + // fuzzer_config: None, + // disable_predeployed_contracts: false, + // }, } } - fn create_test_target_with_cases(test_cases: Vec) -> TestTargetWithConfig { - TestTargetWithConfig { + fn create_test_target_with_cases(test_cases: Vec) -> TestTarget { + TestTarget { sierra_program: program_for_testing(), sierra_program_path: Arc::default(), - casm_program: Arc::new( - compile_raw_sierra(&serde_json::to_value(&program_for_testing().program).unwrap()) - .unwrap(), - ), test_cases, tests_location: TestTargetLocation::Lib, } @@ -234,6 +243,7 @@ mod tests { )], &mut BlockNumberMap::default(), &tests_filter, + &ForgeTrackedResource::default(), ) .await .is_err() @@ -266,6 +276,7 @@ mod tests { &[], &mut BlockNumberMap::default(), &tests_filter, + &ForgeTrackedResource::default(), ) .await .unwrap(); @@ -306,6 +317,7 @@ mod tests { &fork_targets, &mut BlockNumberMap::default(), &tests_filter, + &ForgeTrackedResource::default(), ) .await .unwrap(); @@ -350,6 +362,7 @@ mod tests { &fork_targets, &mut BlockNumberMap::default(), &tests_filter, + &ForgeTrackedResource::default(), ) .await .unwrap(); @@ -406,6 +419,7 @@ mod tests { &fork_targets, &mut BlockNumberMap::default(), &tests_filter, + &ForgeTrackedResource::default(), ) .await .unwrap(); @@ -474,6 +488,7 @@ mod tests { &fork_targets, &mut BlockNumberMap::default(), &tests_filter, + &ForgeTrackedResource::default(), ) .await .unwrap(); @@ -531,6 +546,7 @@ mod tests { &fork_targets, &mut BlockNumberMap::default(), &tests_filter, + &ForgeTrackedResource::default(), ) .await .unwrap(); @@ -580,6 +596,7 @@ mod tests { &[], &mut BlockNumberMap::default(), &tests_filter, + &ForgeTrackedResource::default(), ) .await .unwrap(); @@ -628,6 +645,7 @@ mod tests { &fork_targets, &mut BlockNumberMap::default(), &tests_filter, + &ForgeTrackedResource::default(), ) .await .unwrap(); @@ -672,6 +690,7 @@ mod tests { &fork_targets, &mut BlockNumberMap::default(), &tests_filter, + &ForgeTrackedResource::default(), ) .await .unwrap(); diff --git a/crates/forge/src/run_tests/test_target.rs b/crates/forge/src/run_tests/test_target.rs index e03e6d874e..40d37a1449 100644 --- a/crates/forge/src/run_tests/test_target.rs +++ b/crates/forge/src/run_tests/test_target.rs @@ -1,11 +1,10 @@ use anyhow::Result; use forge_runner::messages::TestResultMessage; +use forge_runner::package_tests::TestTargetResolved; use forge_runner::{ TestCaseFilter, forge_config::ForgeConfig, - maybe_generate_coverage, maybe_save_trace_and_profile, - package_tests::with_config_resolved::TestTargetWithResolvedConfig, - run_for_test_case, + maybe_generate_coverage, maybe_save_trace_and_profile, run_for_test_case, test_case_summary::{AnyTestCaseSummary, TestCaseSummary}, test_target_summary::TestTargetSummary, }; @@ -14,6 +13,9 @@ use futures::{StreamExt, stream::FuturesUnordered}; use std::sync::Arc; use tokio::sync::mpsc::channel; +use crate::run_tests::messages::tests_run::TestsRunMessage; +use crate::test_filter::TestsFilter; + #[non_exhaustive] pub enum TestTargetRunResult { Ok(TestTargetSummary), @@ -22,11 +24,16 @@ pub enum TestTargetRunResult { #[tracing::instrument(skip_all, level = "debug")] pub async fn run_for_test_target( - tests: TestTargetWithResolvedConfig, + tests: TestTargetResolved, forge_config: Arc, - tests_filter: &impl TestCaseFilter, + tests_filter: &TestsFilter, ui: Arc, ) -> Result { + ui.println(&TestsRunMessage::new( + tests.tests_location, + tests.test_cases.len(), + )); + let casm_program = tests.casm_program.clone(); let mut tasks = FuturesUnordered::new(); @@ -40,7 +47,7 @@ pub async fn run_for_test_target( for case in tests.test_cases { let case_name = case.name.clone(); - if !tests_filter.should_be_run(&case) { + if !tests_filter.should_run_test(case.config.ignored) { tasks.push(tokio::task::spawn(async { // TODO TestCaseType should also be encoded in the test case definition Ok(AnyTestCaseSummary::Single(TestCaseSummary::Ignored { diff --git a/crates/forge/src/run_tests/workspace.rs b/crates/forge/src/run_tests/workspace.rs index f45e4b1250..8a6d612dba 100644 --- a/crates/forge/src/run_tests/workspace.rs +++ b/crates/forge/src/run_tests/workspace.rs @@ -1,22 +1,34 @@ -use super::package::RunForPackageArgs; +use crate::combine_configs::combine_configs; use crate::run_tests::messages::latest_blocks_numbers::LatestBlocksNumbersMessage; use crate::run_tests::messages::tests_failure_summary::TestsFailureSummaryMessage; use crate::run_tests::messages::workspace_summary::WorkspaceSummaryMessage; +use crate::run_tests::package::{run_for_package, test_package_with_config_resolved}; +use crate::scarb::load_package_config; +use crate::scarb::{config::ForgeConfigFromScarb, load_test_artifacts}; +use crate::test_filter::TestsFilter; +use crate::warn::warn_if_incompatible_rpc_version; use crate::{ - ExitStatus, TestArgs, block_number_map::BlockNumberMap, run_tests::package::run_for_package, - scarb::build_artifacts_with_scarb, shared_cache::FailedTestsCache, + ExitStatus, TestArgs, block_number_map::BlockNumberMap, scarb::build_artifacts_with_scarb, + shared_cache::FailedTestsCache, }; use anyhow::{Context, Result}; use camino::Utf8PathBuf; +use cheatnet::runtime_extensions::forge_runtime_extension::contracts_data::ContractsData; +use forge_runner::forge_config::ForgeConfig; +use forge_runner::package_tests::TestTarget; use forge_runner::test_case_summary::AnyTestCaseSummary; use forge_runner::{CACHE_DIR, test_target_summary::TestTargetSummary}; use foundry_ui::UI; +use scarb_api::CompilationOpts; +use scarb_api::get_contracts_artifacts_and_source_sierra_paths; use scarb_api::{ metadata::{Metadata, PackageMetadata}, target_dir_for_workspace, }; +use scarb_metadata::PackageId; use scarb_ui::args::PackagesFilter; use shared::consts::SNFORGE_TEST_FILTER; +use std::collections::HashMap; use std::env; use std::sync::Arc; @@ -30,6 +42,7 @@ impl WorkspaceDirs { pub fn new(scarb_metadata: &Metadata) -> Self { let artifacts_dir = target_dir_for_workspace(&scarb_metadata).join(&scarb_metadata.current_profile); + let workspace_root = &scarb_metadata.workspace.root; let cache_dir = workspace_root.join(CACHE_DIR); @@ -77,14 +90,59 @@ pub async fn run_for_workspace( let mut all_tests = vec![]; let mut total_filtered_count = Some(0); + let tests_filter = TestsFilter::from_flags( + args.test_filter.clone(), + args.exact, + args.skip.clone(), + args.only_ignored, + args.include_ignored, + args.rerun_failed, + FailedTestsCache::new(&workspace_dirs.cache_dir), + ); + let packages_len = packages.len(); - for package in packages { + let workspace = Workspace::build(&workspace_dirs, &packages)?; + + for (package_id, test_targets) in workspace.0 { + let package = packages + .iter() + .find(|pkg| pkg.id == package_id) + .expect("Package metadata not found for package id from workspace"); + env::set_current_dir(&package.root)?; - let args = RunForPackageArgs::build(package, scarb_metadata, &args, &workspace_dirs, &ui)?; + let forge_config_from_scarb = + load_package_config::(scarb_metadata, &package.id)?; + + let fork_targets = &forge_config_from_scarb.fork; - let result = run_for_package(args, &mut block_number_map, ui.clone()).await?; + let forge_config = build_forge_config( + &args, + &package, + &forge_config_from_scarb, + &workspace_dirs, + &ui, + )?; + let test_targets = test_package_with_config_resolved( + test_targets, + &fork_targets, + &mut block_number_map, + &tests_filter, + &args.tracked_resource, + ) + .await?; + + warn_if_incompatible_rpc_version(&test_targets, ui.clone()).await?; + + let result = run_for_package( + package.name.clone(), + Arc::new(forge_config), + test_targets, + &tests_filter, + ui.clone(), + ) + .await?; let filtered = result.filtered(); all_tests.extend(result.summaries()); @@ -96,7 +154,7 @@ pub async fn run_for_workspace( .map(|(total, filtered)| total + filtered); } - let workspace_summary = WorkspaceSummaryMessage::new(&all_tests, total_filtered_count); + let overall_summary = WorkspaceSummaryMessage::new(&all_tests, total_filtered_count); let all_failed_tests: Vec = extract_failed_tests(all_tests).collect(); FailedTestsCache::new(&workspace_dirs.cache_dir).save_failed_tests(&all_failed_tests)?; @@ -113,7 +171,7 @@ pub async fn run_for_workspace( if packages_len > 1 { // Add newline to separate summary from previous output ui.print_blank_line(); - ui.println(&workspace_summary); + ui.println(&overall_summary); } if args.exact { @@ -150,3 +208,65 @@ fn unset_forge_test_filter() { env::remove_var(SNFORGE_TEST_FILTER); }; } + +pub struct Workspace(pub HashMap>); + +impl Workspace { + pub fn build(workspace_dirs: &WorkspaceDirs, packages: &[PackageMetadata]) -> Result { + let mut result = Workspace(HashMap::new()); + + for package in packages { + let raw_test_targets = load_test_artifacts(&workspace_dirs.artifacts_dir, &package)?; + + let test_targets_with_config = raw_test_targets + .into_iter() + .map(TestTarget::from_raw) + .collect::>>()?; + + result + .0 + .insert(package.id.clone(), test_targets_with_config); + } + + Ok(result) + } +} + +fn build_forge_config( + args: &TestArgs, + package: &PackageMetadata, + forge_config_from_scarb: &ForgeConfigFromScarb, + workspace_dirs: &WorkspaceDirs, + ui: &UI, +) -> Result { + let contracts = get_contracts_artifacts_and_source_sierra_paths( + &workspace_dirs.artifacts_dir, + &package, + ui, + CompilationOpts { + use_test_target_contracts: !args.no_optimization, + #[cfg(feature = "cairo-native")] + run_native: args.run_native, + }, + )?; + let contracts_data = ContractsData::try_from(contracts)?; + let forge_config = combine_configs( + args.exit_first, + args.fuzzer_runs, + args.fuzzer_seed, + args.detailed_resources, + args.save_trace_data, + args.build_profile, + args.coverage, + args.max_n_steps, + args.tracked_resource, + contracts_data, + workspace_dirs.cache_dir.clone(), + &forge_config_from_scarb, + &args.additional_args, + args.trace_args.clone(), + args.experimental_oracles, + ); + + Ok(forge_config) +} diff --git a/crates/forge/src/test_filter.rs b/crates/forge/src/test_filter.rs index f9ba77285d..efba4fb060 100644 --- a/crates/forge/src/test_filter.rs +++ b/crates/forge/src/test_filter.rs @@ -1,7 +1,6 @@ use crate::shared_cache::FailedTestsCache; use anyhow::Result; use forge_runner::package_tests::TestCase; -use forge_runner::package_tests::with_config_resolved::TestCaseWithResolvedConfig; use forge_runner::{TestCaseFilter, TestCaseIsIgnored}; #[derive(Debug, PartialEq)] @@ -78,10 +77,7 @@ impl TestsFilter { } } - pub(crate) fn filter_tests( - &self, - test_cases: &mut Vec, - ) -> Result<()> { + pub(crate) fn filter_tests(&self, test_cases: &mut Vec) -> Result<()> { match &self.name_filter { NameFilter::All => {} NameFilter::Match(filter) => { @@ -119,10 +115,7 @@ impl TestsFilter { } impl TestCaseFilter for TestsFilter { - fn should_be_run(&self, test_case: &TestCase) -> bool - where - T: TestCaseIsIgnored, - { + fn should_be_run(&self, test_case: &TestCase) -> bool { let ignored = test_case.config.is_ignored(); match self.ignored_filter { @@ -131,6 +124,14 @@ impl TestCaseFilter for TestsFilter { IgnoredFilter::NotIgnored => !ignored, } } + + fn should_run_test(&self, test_config_ignored: bool) -> bool { + match self.ignored_filter { + IgnoredFilter::All => true, + IgnoredFilter::Ignored => test_config_ignored, + IgnoredFilter::NotIgnored => !test_config_ignored, + } + } } #[cfg(test)] @@ -140,9 +141,9 @@ mod tests { use cairo_lang_sierra::program::Program; use cairo_lang_sierra::program::ProgramArtifact; use forge_runner::expected_result::ExpectedTestResult; - use forge_runner::package_tests::with_config_resolved::{ - TestCaseResolvedConfig, TestCaseWithResolvedConfig, TestTargetWithResolvedConfig, - }; + use forge_runner::package_tests::TestCase; + use forge_runner::package_tests::TestTargetResolved; + use forge_runner::package_tests::with_config_resolved::TestCaseResolvedConfig; use forge_runner::package_tests::{TestDetails, TestTargetLocation}; use std::sync::Arc; use universal_sierra_compiler_api::compile_raw_sierra; @@ -190,7 +191,7 @@ mod tests { #[test] #[expect(clippy::too_many_lines)] fn filtering_tests() { - let mocked_tests = TestTargetWithResolvedConfig { + let mocked_tests = TestTargetResolved { sierra_program: program_for_testing(), sierra_program_path: Arc::default(), casm_program: Arc::new( @@ -198,7 +199,7 @@ mod tests { .unwrap(), ), test_cases: vec![ - TestCaseWithResolvedConfig { + TestCase { name: "crate1::do_thing".to_string(), test_details: TestDetails::default(), @@ -211,7 +212,7 @@ mod tests { disable_predeployed_contracts: false, }, }, - TestCaseWithResolvedConfig { + TestCase { name: "crate2::run_other_thing".to_string(), test_details: TestDetails::default(), @@ -224,7 +225,7 @@ mod tests { disable_predeployed_contracts: false, }, }, - TestCaseWithResolvedConfig { + TestCase { name: "outer::crate2::execute_next_thing".to_string(), test_details: TestDetails::default(), @@ -237,7 +238,7 @@ mod tests { disable_predeployed_contracts: false, }, }, - TestCaseWithResolvedConfig { + TestCase { name: "thing".to_string(), test_details: TestDetails::default(), @@ -270,7 +271,7 @@ mod tests { assert_eq!( filtered.test_cases, - vec![TestCaseWithResolvedConfig { + vec![TestCase { name: "crate1::do_thing".to_string(), test_details: TestDetails::default(), @@ -300,7 +301,7 @@ mod tests { assert_eq!( filtered.test_cases, - vec![TestCaseWithResolvedConfig { + vec![TestCase { name: "crate2::run_other_thing".to_string(), test_details: TestDetails::default(), @@ -331,7 +332,7 @@ mod tests { assert_eq!( filtered.test_cases, vec![ - TestCaseWithResolvedConfig { + TestCase { name: "crate1::do_thing".to_string(), test_details: TestDetails::default(), @@ -344,7 +345,7 @@ mod tests { disable_predeployed_contracts: false, }, }, - TestCaseWithResolvedConfig { + TestCase { name: "crate2::run_other_thing".to_string(), test_details: TestDetails::default(), @@ -357,7 +358,7 @@ mod tests { disable_predeployed_contracts: false, }, }, - TestCaseWithResolvedConfig { + TestCase { name: "outer::crate2::execute_next_thing".to_string(), test_details: TestDetails::default(), @@ -370,7 +371,7 @@ mod tests { disable_predeployed_contracts: false, }, }, - TestCaseWithResolvedConfig { + TestCase { name: "thing".to_string(), test_details: TestDetails::default(), @@ -417,7 +418,7 @@ mod tests { assert_eq!( filtered.test_cases, vec![ - TestCaseWithResolvedConfig { + TestCase { name: "crate1::do_thing".to_string(), test_details: TestDetails::default(), @@ -430,7 +431,7 @@ mod tests { disable_predeployed_contracts: false, }, }, - TestCaseWithResolvedConfig { + TestCase { name: "crate2::run_other_thing".to_string(), test_details: TestDetails::default(), @@ -443,7 +444,7 @@ mod tests { disable_predeployed_contracts: false, }, }, - TestCaseWithResolvedConfig { + TestCase { name: "outer::crate2::execute_next_thing".to_string(), test_details: TestDetails::default(), @@ -456,7 +457,7 @@ mod tests { disable_predeployed_contracts: false, }, }, - TestCaseWithResolvedConfig { + TestCase { name: "thing".to_string(), test_details: TestDetails::default(), @@ -475,7 +476,7 @@ mod tests { #[test] fn filtering_with_no_tests() { - let mocked_tests = TestTargetWithResolvedConfig { + let mocked_tests = TestTargetResolved { sierra_program: program_for_testing(), sierra_program_path: Arc::default(), casm_program: Arc::new( @@ -520,7 +521,7 @@ mod tests { #[test] #[expect(clippy::too_many_lines)] fn filtering_with_exact_match() { - let mocked_tests = TestTargetWithResolvedConfig { + let mocked_tests = TestTargetResolved { sierra_program: program_for_testing(), sierra_program_path: Arc::default(), casm_program: Arc::new( @@ -528,7 +529,7 @@ mod tests { .unwrap(), ), test_cases: vec![ - TestCaseWithResolvedConfig { + TestCase { name: "crate1::do_thing".to_string(), test_details: TestDetails::default(), @@ -541,7 +542,7 @@ mod tests { disable_predeployed_contracts: false, }, }, - TestCaseWithResolvedConfig { + TestCase { name: "crate2::run_other_thing".to_string(), test_details: TestDetails::default(), @@ -554,7 +555,7 @@ mod tests { disable_predeployed_contracts: false, }, }, - TestCaseWithResolvedConfig { + TestCase { name: "outer::crate3::run_other_thing".to_string(), test_details: TestDetails::default(), @@ -567,7 +568,7 @@ mod tests { disable_predeployed_contracts: false, }, }, - TestCaseWithResolvedConfig { + TestCase { name: "do_thing".to_string(), test_details: TestDetails::default(), @@ -629,7 +630,7 @@ mod tests { assert_eq!( filtered.test_cases, - vec![TestCaseWithResolvedConfig { + vec![TestCase { name: "do_thing".to_string(), test_details: TestDetails::default(), @@ -659,7 +660,7 @@ mod tests { assert_eq!( filtered.test_cases, - vec![TestCaseWithResolvedConfig { + vec![TestCase { name: "crate1::do_thing".to_string(), test_details: TestDetails::default(), @@ -704,7 +705,7 @@ mod tests { assert_eq!( filtered.test_cases, - vec![TestCaseWithResolvedConfig { + vec![TestCase { name: "outer::crate3::run_other_thing".to_string(), test_details: TestDetails::default(), @@ -722,7 +723,7 @@ mod tests { #[test] fn filtering_with_only_ignored() { - let mocked_tests = TestTargetWithResolvedConfig { + let mocked_tests = TestTargetResolved { sierra_program: program_for_testing(), sierra_program_path: Arc::default(), casm_program: Arc::new( @@ -730,7 +731,7 @@ mod tests { .unwrap(), ), test_cases: vec![ - TestCaseWithResolvedConfig { + TestCase { name: "crate1::do_thing".to_string(), test_details: TestDetails::default(), @@ -743,7 +744,7 @@ mod tests { disable_predeployed_contracts: false, }, }, - TestCaseWithResolvedConfig { + TestCase { name: "crate2::run_other_thing".to_string(), test_details: TestDetails::default(), @@ -756,7 +757,7 @@ mod tests { disable_predeployed_contracts: false, }, }, - TestCaseWithResolvedConfig { + TestCase { name: "outer::crate3::run_other_thing".to_string(), test_details: TestDetails::default(), @@ -769,7 +770,7 @@ mod tests { disable_predeployed_contracts: false, }, }, - TestCaseWithResolvedConfig { + TestCase { name: "do_thing".to_string(), test_details: TestDetails::default(), @@ -801,7 +802,7 @@ mod tests { assert_eq!( filtered.test_cases, vec![ - TestCaseWithResolvedConfig { + TestCase { name: "crate2::run_other_thing".to_string(), test_details: TestDetails::default(), @@ -814,7 +815,7 @@ mod tests { disable_predeployed_contracts: false, }, }, - TestCaseWithResolvedConfig { + TestCase { name: "outer::crate3::run_other_thing".to_string(), test_details: TestDetails::default(), @@ -834,7 +835,7 @@ mod tests { #[test] #[expect(clippy::too_many_lines)] fn filtering_with_include_ignored() { - let mocked_tests = TestTargetWithResolvedConfig { + let mocked_tests = TestTargetResolved { sierra_program: program_for_testing(), sierra_program_path: Arc::default(), casm_program: Arc::new( @@ -842,7 +843,7 @@ mod tests { .unwrap(), ), test_cases: vec![ - TestCaseWithResolvedConfig { + TestCase { name: "crate1::do_thing".to_string(), test_details: TestDetails::default(), @@ -855,7 +856,7 @@ mod tests { disable_predeployed_contracts: false, }, }, - TestCaseWithResolvedConfig { + TestCase { name: "crate2::run_other_thing".to_string(), test_details: TestDetails::default(), @@ -868,7 +869,7 @@ mod tests { disable_predeployed_contracts: false, }, }, - TestCaseWithResolvedConfig { + TestCase { name: "outer::crate3::run_other_thing".to_string(), test_details: TestDetails::default(), @@ -881,7 +882,7 @@ mod tests { disable_predeployed_contracts: false, }, }, - TestCaseWithResolvedConfig { + TestCase { name: "do_thing".to_string(), test_details: TestDetails::default(), @@ -913,7 +914,7 @@ mod tests { assert_eq!( filtered.test_cases, vec![ - TestCaseWithResolvedConfig { + TestCase { name: "crate1::do_thing".to_string(), test_details: TestDetails::default(), @@ -926,7 +927,7 @@ mod tests { disable_predeployed_contracts: false, }, }, - TestCaseWithResolvedConfig { + TestCase { name: "crate2::run_other_thing".to_string(), test_details: TestDetails::default(), @@ -939,7 +940,7 @@ mod tests { disable_predeployed_contracts: false, }, }, - TestCaseWithResolvedConfig { + TestCase { name: "outer::crate3::run_other_thing".to_string(), test_details: TestDetails::default(), @@ -952,7 +953,7 @@ mod tests { disable_predeployed_contracts: false, }, }, - TestCaseWithResolvedConfig { + TestCase { name: "do_thing".to_string(), test_details: TestDetails::default(), diff --git a/crates/forge/src/warn.rs b/crates/forge/src/warn.rs index 3c06464121..6ece83a401 100644 --- a/crates/forge/src/warn.rs +++ b/crates/forge/src/warn.rs @@ -1,7 +1,7 @@ use crate::{MINIMAL_SNFORGE_STD_DEPRECATED_VERSION, MINIMAL_SNFORGE_STD_VERSION}; use anyhow::{Result, anyhow}; use forge_runner::backtrace::is_backtrace_enabled; -use forge_runner::package_tests::with_config_resolved::TestTargetWithResolvedConfig; +use forge_runner::package_tests::TestTargetResolved; use foundry_ui::UI; use foundry_ui::components::warning::WarningMessage; use indoc::formatdoc; @@ -16,7 +16,7 @@ use std::sync::Arc; use url::Url; pub(crate) async fn warn_if_incompatible_rpc_version( - test_targets: &[TestTargetWithResolvedConfig], + test_targets: &[TestTargetResolved], ui: Arc, ) -> Result<()> { let mut urls = HashSet::::new(); diff --git a/crates/forge/tests/integration/setup_fork.rs b/crates/forge/tests/integration/setup_fork.rs index 2723cfd258..ee879275c0 100644 --- a/crates/forge/tests/integration/setup_fork.rs +++ b/crates/forge/tests/integration/setup_fork.rs @@ -1,4 +1,6 @@ use cheatnet::runtime_extensions::forge_config_extension::config::BlockId; +use forge::run_tests::resolve_config::resolve_config; +use forge_runner::package_tests::TestTarget; use foundry_ui::UI; use indoc::{formatdoc, indoc}; use std::num::NonZeroU32; @@ -17,7 +19,6 @@ use crate::utils::runner::{Contract, assert_case_output_contains, assert_failed, use crate::utils::running_tests::run_test_case; use crate::utils::test_case; use cheatnet::runtime_extensions::forge_runtime_extension::contracts_data::ContractsData; -use forge::run_tests::package::RunForPackageArgs; use forge::scarb::load_test_artifacts; use forge::shared_cache::FailedTestsCache; use forge_runner::CACHE_DIR; @@ -72,8 +73,8 @@ fn fork_simple_decorator() { assert_passed(&result); } -#[test] -fn fork_aliased_decorator() { +#[tokio::test] +async fn fork_aliased_decorator() { let test = test_case!(indoc!( r#" use result::ResultTrait; @@ -128,50 +129,65 @@ fn fork_aliased_decorator() { let raw_test_targets = load_test_artifacts(&test.path().unwrap().join("target/dev"), package).unwrap(); + let fork_targets = vec![ForkTarget { + name: "FORK_NAME_FROM_SCARB_TOML".to_string(), + url: node_rpc_url().as_str().parse().unwrap(), + block_id: BlockId::BlockTag, + }]; + let mut block_number_map = BlockNumberMap::default(); + let tests_filter = TestsFilter::from_flags( + None, + false, + Vec::new(), + false, + false, + false, + FailedTestsCache::default(), + ); + let tracked_resource = ForgeTrackedResource::default(); + + let mut test_targets_resolved = Vec::new(); + for raw in raw_test_targets.into_iter() { + let tt = TestTarget::from_raw(raw).expect("failed to prepare test target"); + let tt_resolved = resolve_config( + tt, + &fork_targets, + &mut block_number_map, + &tests_filter, + &tracked_resource, + ) + .await; + test_targets_resolved.push(tt_resolved.unwrap()); + } + let ui = Arc::new(UI::default()); + let result = rt .block_on(run_for_package( - RunForPackageArgs { - test_targets: raw_test_targets, - package_name: "test_package".to_string(), - tests_filter: TestsFilter::from_flags( - None, - false, - Vec::new(), - false, - false, - false, - FailedTestsCache::default(), - ), - forge_config: Arc::new(ForgeConfig { - test_runner_config: Arc::new(TestRunnerConfig { - exit_first: false, - fuzzer_runs: NonZeroU32::new(256).unwrap(), - fuzzer_seed: 12345, - max_n_steps: None, - is_vm_trace_needed: false, - cache_dir: Utf8PathBuf::from_path_buf(tempdir().unwrap().keep()) - .unwrap() - .join(CACHE_DIR), - contracts_data: ContractsData::try_from(test.contracts(&ui).unwrap()) - .unwrap(), - tracked_resource: ForgeTrackedResource::CairoSteps, - environment_variables: test.env().clone(), - experimental_oracles: false, - }), - output_config: Arc::new(OutputConfig { - detailed_resources: false, - execution_data_to_save: ExecutionDataToSave::default(), - trace_args: TraceArgs::default(), - }), + "test_package".to_string(), + Arc::new(ForgeConfig { + test_runner_config: Arc::new(TestRunnerConfig { + exit_first: false, + fuzzer_runs: NonZeroU32::new(256).unwrap(), + fuzzer_seed: 12345, + max_n_steps: None, + is_vm_trace_needed: false, + cache_dir: Utf8PathBuf::from_path_buf(tempdir().unwrap().keep()) + .unwrap() + .join(CACHE_DIR), + contracts_data: ContractsData::try_from(test.contracts(&ui).unwrap()).unwrap(), + tracked_resource: ForgeTrackedResource::CairoSteps, + environment_variables: test.env().clone(), + experimental_oracles: false, + }), + output_config: Arc::new(OutputConfig { + detailed_resources: false, + execution_data_to_save: ExecutionDataToSave::default(), + trace_args: TraceArgs::default(), }), - fork_targets: vec![ForkTarget { - name: "FORK_NAME_FROM_SCARB_TOML".to_string(), - url: node_rpc_url().as_str().parse().unwrap(), - block_id: BlockId::BlockTag, - }], - }, - &mut BlockNumberMap::default(), + }), + test_targets_resolved, + &tests_filter, ui, )) .expect("Runner fail") @@ -180,8 +196,8 @@ fn fork_aliased_decorator() { assert_passed(&result); } -#[test] -fn fork_aliased_decorator_overrding() { +#[tokio::test] +async fn fork_aliased_decorator_overrding() { let test = test_case!(indoc!( r#" use starknet::syscalls::get_execution_info_syscall; @@ -218,50 +234,67 @@ fn fork_aliased_decorator_overrding() { let raw_test_targets = load_test_artifacts(&test.path().unwrap().join("target/dev"), package).unwrap(); + let fork_targets = vec![ForkTarget { + name: "FORK_NAME_FROM_SCARB_TOML".to_string(), + url: node_rpc_url().as_str().parse().unwrap(), + block_id: BlockId::BlockNumber(12_341_234), + }]; + let mut block_number_map = BlockNumberMap::default(); + let tests_filter = TestsFilter::from_flags( + None, + false, + Vec::new(), + false, + false, + false, + FailedTestsCache::default(), + ); + let tracked_resource = ForgeTrackedResource::default(); + + let mut test_targets_resolved = Vec::new(); + for raw in raw_test_targets.into_iter() { + let tt = TestTarget::from_raw(raw).expect("failed to prepare test target"); + let tt_resolved = resolve_config( + tt, + &fork_targets, + &mut block_number_map, + &tests_filter, + &tracked_resource, + ) + .await; + test_targets_resolved.push(tt_resolved.unwrap()); + } + let ui = Arc::new(UI::default()); + + let forge_config = Arc::new(ForgeConfig { + test_runner_config: Arc::new(TestRunnerConfig { + exit_first: false, + fuzzer_runs: NonZeroU32::new(256).unwrap(), + fuzzer_seed: 12345, + max_n_steps: None, + is_vm_trace_needed: false, + cache_dir: Utf8PathBuf::from_path_buf(tempdir().unwrap().keep()) + .unwrap() + .join(CACHE_DIR), + contracts_data: ContractsData::try_from(test.contracts(&ui).unwrap()).unwrap(), + tracked_resource: ForgeTrackedResource::CairoSteps, + environment_variables: test.env().clone(), + experimental_oracles: false, + }), + output_config: Arc::new(OutputConfig { + detailed_resources: false, + execution_data_to_save: ExecutionDataToSave::default(), + trace_args: TraceArgs::default(), + }), + }); + let result = rt .block_on(run_for_package( - RunForPackageArgs { - test_targets: raw_test_targets, - package_name: "test_package".to_string(), - tests_filter: TestsFilter::from_flags( - None, - false, - Vec::new(), - false, - false, - false, - FailedTestsCache::default(), - ), - forge_config: Arc::new(ForgeConfig { - test_runner_config: Arc::new(TestRunnerConfig { - exit_first: false, - fuzzer_runs: NonZeroU32::new(256).unwrap(), - fuzzer_seed: 12345, - max_n_steps: None, - is_vm_trace_needed: false, - cache_dir: Utf8PathBuf::from_path_buf(tempdir().unwrap().keep()) - .unwrap() - .join(CACHE_DIR), - contracts_data: ContractsData::try_from(test.contracts(&ui).unwrap()) - .unwrap(), - tracked_resource: ForgeTrackedResource::CairoSteps, - environment_variables: test.env().clone(), - experimental_oracles: false, - }), - output_config: Arc::new(OutputConfig { - detailed_resources: false, - execution_data_to_save: ExecutionDataToSave::default(), - trace_args: TraceArgs::default(), - }), - }), - fork_targets: vec![ForkTarget { - name: "FORK_NAME_FROM_SCARB_TOML".to_string(), - url: node_rpc_url().as_str().parse().unwrap(), - block_id: BlockId::BlockNumber(12_341_234), - }], - }, - &mut BlockNumberMap::default(), + "test_package".to_string(), + forge_config, + test_targets_resolved, + &tests_filter, ui, )) .expect("Runner fail") diff --git a/crates/forge/tests/utils/running_tests.rs b/crates/forge/tests/utils/running_tests.rs index 878e101330..076e8560da 100644 --- a/crates/forge/tests/utils/running_tests.rs +++ b/crates/forge/tests/utils/running_tests.rs @@ -1,18 +1,18 @@ use crate::utils::runner::TestCase; use camino::Utf8PathBuf; use cheatnet::runtime_extensions::forge_runtime_extension::contracts_data::ContractsData; +use forge::run_tests::package::run_for_package; +use forge::run_tests::resolve_config::resolve_config; use forge::shared_cache::FailedTestsCache; use forge::{ - block_number_map::BlockNumberMap, - run_tests::package::{RunForPackageArgs, run_for_package}, - scarb::load_test_artifacts, - test_filter::TestsFilter, + block_number_map::BlockNumberMap, scarb::load_test_artifacts, test_filter::TestsFilter, }; use forge_runner::CACHE_DIR; use forge_runner::debugging::TraceArgs; use forge_runner::forge_config::{ ExecutionDataToSave, ForgeConfig, ForgeTrackedResource, OutputConfig, TestRunnerConfig, }; +use forge_runner::package_tests::TestTarget; use forge_runner::test_target_summary::TestTargetSummary; use foundry_ui::UI; use scarb_api::ScarbCommand; @@ -46,44 +46,61 @@ pub fn run_test_case( let raw_test_targets = load_test_artifacts(&test.path().unwrap().join("target/dev"), package).unwrap(); + let fork_targets = vec![]; + let mut block_number_map = BlockNumberMap::default(); + let tests_filter = TestsFilter::from_flags( + None, + false, + Vec::new(), + false, + false, + false, + FailedTestsCache::default(), + ); + + let mut test_targets_resolved = Vec::new(); + + for raw in raw_test_targets.into_iter() { + let tt = TestTarget::from_raw(raw).expect("failed to prepare test target"); + + let tt_resolved = tokio::runtime::Runtime::new() + .unwrap() + .block_on(resolve_config( + tt, + &fork_targets, + &mut block_number_map, + &tests_filter, + &tracked_resource, + )); + test_targets_resolved.push(tt_resolved.unwrap()); + } + let ui = Arc::new(UI::default()); rt.block_on(run_for_package( - RunForPackageArgs { - test_targets: raw_test_targets, - package_name: "test_package".to_string(), - tests_filter: TestsFilter::from_flags( - None, - false, - Vec::new(), - false, - false, - false, - FailedTestsCache::default(), - ), - forge_config: Arc::new(ForgeConfig { - test_runner_config: Arc::new(TestRunnerConfig { - exit_first: false, - fuzzer_runs: NonZeroU32::new(256).unwrap(), - fuzzer_seed: 12345, - max_n_steps: None, - is_vm_trace_needed: false, - cache_dir: Utf8PathBuf::from_path_buf(tempdir().unwrap().keep()) - .unwrap() - .join(CACHE_DIR), - contracts_data: ContractsData::try_from(test.contracts(&ui).unwrap()).unwrap(), - tracked_resource, - environment_variables: test.env().clone(), - experimental_oracles: false, - }), - output_config: Arc::new(OutputConfig { - detailed_resources: false, - execution_data_to_save: ExecutionDataToSave::default(), - trace_args: TraceArgs::default(), - }), + "test_package".to_string(), + Arc::new(ForgeConfig { + test_runner_config: Arc::new(TestRunnerConfig { + exit_first: false, + fuzzer_runs: NonZeroU32::new(256).unwrap(), + fuzzer_seed: 12345, + max_n_steps: None, + is_vm_trace_needed: false, + cache_dir: Utf8PathBuf::from_path_buf(tempdir().unwrap().keep()) + .unwrap() + .join(CACHE_DIR), + contracts_data: ContractsData::try_from(test.contracts(&ui).unwrap()).unwrap(), + tracked_resource: ForgeTrackedResource::CairoSteps, + environment_variables: test.env().clone(), + experimental_oracles: false, + }), + output_config: Arc::new(OutputConfig { + detailed_resources: false, + execution_data_to_save: ExecutionDataToSave::default(), + trace_args: TraceArgs::default(), }), - fork_targets: vec![], - }, - &mut BlockNumberMap::default(), + }), + test_targets_resolved, + &tests_filter, ui, )) .expect("Runner fail")