diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..a52bd184c2 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.* text eol=lf \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9d10c834bc..c9c25b4463 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,5 +1,8 @@ name: CI +env: + DEVNET_TAG: "v0.2.2" + on: pull_request: merge_group: @@ -11,7 +14,10 @@ on: jobs: test-forge-unit-and-integration: name: Test Forge / Unit and Integration Tests - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ ubuntu-latest, windows-latest ] steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable @@ -23,7 +29,11 @@ jobs: - run: cargo test --release integration -p forge build-test-forge-e2e-nextest-archive: - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ ubuntu-latest, windows-latest ] steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable @@ -31,50 +41,50 @@ jobs: - name: Install nextest uses: taiki-e/install-action@nextest - name: Build and archive tests - run: cargo nextest archive --release -p forge --archive-file nextest-archive.tar.zst + run: cargo nextest archive --release -p forge --archive-file 'nextest-archive-${{ matrix.os }}.tar.zst' - name: Upload archive to workflow uses: actions/upload-artifact@v4 with: - name: nextest-archive - path: nextest-archive.tar.zst + name: nextest-archive-${{ matrix.os }} + path: nextest-archive-${{ matrix.os }}.tar.zst test-forge-e2e: name: Test Forge / E2E Tests - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} needs: build-test-forge-e2e-nextest-archive strategy: + fail-fast: false matrix: partition: [ 1, 2, 3, 4, 5, 6, 7, 8 ] + os: [ ubuntu-latest, windows-latest ] steps: - name: Extract branch name if: github.event_name != 'pull_request' run: echo "BRANCH_NAME=$(echo ${GITHUB_REF#refs/heads/})" >> $GITHUB_ENV + shell: bash - name: Extract branch name on pull request if: github.event_name == 'pull_request' run: echo "BRANCH_NAME=$(echo $GITHUB_HEAD_REF)" >> $GITHUB_ENV + shell: bash - name: Extract repo name and owner if: github.event_name != 'pull_request' run: echo "REPO_NAME=$(echo ${{ github.repository }}.git)" >> $GITHUB_ENV + shell: bash - name: Extract repo name and owner on pull request if: github.event_name == 'pull_request' run: echo "REPO_NAME=$(echo ${{ github.event.pull_request.head.repo.full_name }}.git)" >> $GITHUB_ENV + shell: bash - name: Print repo name run: echo 'The repo name is' $REPO_NAME + shell: bash - name: Get branch name run: echo 'The branch name is' $BRANCH_NAME - - - name: Install cairo-profiler - run: | - curl -L https://raw.githubusercontent.com/software-mansion/cairo-profiler/main/scripts/install.sh | sh - - - name: Install cairo-coverage - run: | - curl -L https://raw.githubusercontent.com/software-mansion/cairo-coverage/main/scripts/install.sh | sh + shell: bash - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable @@ -84,9 +94,9 @@ jobs: - uses: taiki-e/install-action@nextest - uses: actions/download-artifact@v4 with: - name: nextest-archive + name: nextest-archive-${{ matrix.os }} - name: nextest partition ${{ matrix.partition }}/8 - run: cargo nextest run --partition 'count:${{ matrix.partition }}/8' --archive-file 'nextest-archive.tar.zst' e2e + run: cargo nextest run --no-fail-fast --partition 'count:${{ matrix.partition }}/8' --archive-file 'nextest-archive-${{ matrix.os }}.tar.zst' e2e test-scarb-2-8-3: name: Test scarb 2.8.3 @@ -104,8 +114,13 @@ jobs: run: | curl -L https://raw.githubusercontent.com/software-mansion/cairo-coverage/main/scripts/install.sh | sh + - name: Install cairo-profiler + run: | + curl -L https://raw.githubusercontent.com/software-mansion/cairo-profiler/main/scripts/install.sh | sh + - run: cargo test --package forge --features scarb_2_8_3 --test main e2e::coverage - run: cargo test --package forge --features scarb_2_8_3 --test main e2e::backtrace + - run: cargo test --package forge --features scarb_2_8_3 --test main e2e::build_profile test-coverage-error: name: Test coverage error @@ -188,15 +203,32 @@ jobs: test-cast: name: Test Cast - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ ubuntu-latest, windows-latest ] steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@7b1c307e0dcbda6122208f10795a713336a9b35a with: toolchain: stable - uses: Swatinem/rust-cache@82a92a6e8fbeee089604da2575dc567ae9ddeaab - - name: Install starknet-devnet-rs - run: ./scripts/install_devnet.sh + - name: Install starknet-devnet-rs on Linux/Macos + if: runner.os != 'Windows' + run: | + ./scripts/install_devnet.sh + - name: Cache devnet build + if: runner.os == 'Windows' + id: windows-devnet-cache + uses: actions/cache@v4 + with: + path: ${{ github.workspace }}\crates\sncast\tests\utils\devnet + key: ${{ runner.os }}-devnet-${{ env.DEVNET_TAG }} + - name: Install devnet + if: runner.os == 'Windows' && steps.windows-devnet-cache.outputs.cache-hit != 'true' + run: | + $DEVNET_INSTALL_DIR = "${{ github.workspace }}\crates\sncast\tests\utils\devnet" + cargo install --git https://github.com/0xSpaceShard/starknet-devnet-rs.git --locked --tag ${{ env.DEVNET_TAG }} --root $DEVNET_INSTALL_DIR - uses: software-mansion/setup-scarb@v1 with: scarb-version: "2.7.0" @@ -229,7 +261,10 @@ jobs: test-scarb-api: name: Test Scarb Api - runs-on: ubuntu-latest + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ ubuntu-latest, windows-latest ] steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable diff --git a/Cargo.lock b/Cargo.lock index b9fa0b1262..ba56ed56c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "addr2line" @@ -2247,6 +2247,7 @@ dependencies = [ "rand", "rayon", "runtime", + "sanitize-filename", "scarb-api", "semver", "serde", @@ -4449,6 +4450,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "sanitize-filename" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc984f4f9ceb736a7bb755c3e3bd17dc56370af2600c9780dcc48c66453da34d" +dependencies = [ + "regex", +] + [[package]] name = "scarb-api" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index d17dd84fb9..45c56cd522 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -124,3 +124,4 @@ serde_path_to_error = "0.1.16" wiremock = "0.6.0" const-hex = "1.14.0" indicatif = "0.17.9" +sanitize-filename = "0.6.0" diff --git a/crates/forge-runner/Cargo.toml b/crates/forge-runner/Cargo.toml index a9e35b7012..9aca86e5be 100644 --- a/crates/forge-runner/Cargo.toml +++ b/crates/forge-runner/Cargo.toml @@ -55,3 +55,4 @@ shared = { path = "../shared" } universal-sierra-compiler-api = { path = "../universal-sierra-compiler-api" } fs4.workspace = true which.workspace = true +sanitize-filename.workspace = true diff --git a/crates/forge-runner/src/build_trace_data.rs b/crates/forge-runner/src/build_trace_data.rs index 845775c234..4c8382ebdf 100644 --- a/crates/forge-runner/src/build_trace_data.rs +++ b/crates/forge-runner/src/build_trace_data.rs @@ -307,7 +307,7 @@ fn build_profiler_trace_entry(value: &RelocatedTraceEntry) -> ProfilerTraceEntry } pub fn save_trace_data( - test_name: &String, + test_name: &str, trace_data: &VersionedProfilerCallTrace, ) -> Result { let serialized_trace = diff --git a/crates/forge-runner/src/lib.rs b/crates/forge-runner/src/lib.rs index 8608f685e6..d3aebf4887 100644 --- a/crates/forge-runner/src/lib.rs +++ b/crates/forge-runner/src/lib.rs @@ -68,9 +68,10 @@ pub fn maybe_save_trace_and_profile( }) = result { if execution_data_to_save.is_vm_trace_needed() { - let trace_path = save_trace_data(name, trace_data)?; + let name = sanitize_filename::sanitize(name.replace("::", "_")); + let trace_path = save_trace_data(&name, trace_data)?; if execution_data_to_save.profile { - run_profiler(name, &trace_path, &execution_data_to_save.additional_args)?; + run_profiler(&name, &trace_path, &execution_data_to_save.additional_args)?; } return Ok(Some(trace_path)); } diff --git a/crates/forge/tests/data/exit_first/tests/ext_function_test.cairo b/crates/forge/tests/data/exit_first/tests/ext_function_test.cairo index 09d8dc6c93..e74e9adb88 100644 --- a/crates/forge/tests/data/exit_first/tests/ext_function_test.cairo +++ b/crates/forge/tests/data/exit_first/tests/ext_function_test.cairo @@ -2,7 +2,7 @@ use exit_first::fib; #[test] fn hard_test() { - fib(0, 1, 30344); + fib(0, 1, 99999999999999999999999); assert(2 == 2, 'simple check'); } diff --git a/crates/forge/tests/e2e/build_profile.rs b/crates/forge/tests/e2e/build_profile.rs index 975c8e452e..f668baf319 100644 --- a/crates/forge/tests/e2e/build_profile.rs +++ b/crates/forge/tests/e2e/build_profile.rs @@ -2,6 +2,7 @@ use super::common::runner::{setup_package, test_runner}; use forge_runner::profiler_api::PROFILE_DIR; #[test] +#[cfg_attr(not(feature = "scarb_2_8_3"), ignore)] fn simple_package_build_profile() { let temp = setup_package("simple_package"); @@ -9,19 +10,19 @@ fn simple_package_build_profile() { assert!(temp .join(PROFILE_DIR) - .join("simple_package::tests::test_fib.pb.gz") + .join("simple_package_tests_test_fib.pb.gz") .is_file()); assert!(!temp .join(PROFILE_DIR) - .join("simple_package_integrationtest::test_simple::test_failing.pb.gz") + .join("simple_package_integrationtest_test_simple_test_failing.pb.gz") .is_file()); assert!(!temp .join(PROFILE_DIR) - .join("simple_package::tests::ignored_test.pb.gz") + .join("simple_package_tests_ignored_test.pb.gz") .is_file()); assert!(temp .join(PROFILE_DIR) - .join("simple_package_integrationtest::ext_function_test::test_simple.pb.gz") + .join("simple_package_integrationtest_ext_function_test_test_simple.pb.gz") .is_file()); // Check if it doesn't crash in case some data already exists @@ -29,6 +30,7 @@ fn simple_package_build_profile() { } #[test] +#[cfg_attr(not(feature = "scarb_2_8_3"), ignore)] fn simple_package_build_profile_and_pass_args() { let temp = setup_package("simple_package"); diff --git a/crates/forge/tests/e2e/build_trace_data.rs b/crates/forge/tests/e2e/build_trace_data.rs index 2f9f6502f6..438adc0f89 100644 --- a/crates/forge/tests/e2e/build_trace_data.rs +++ b/crates/forge/tests/e2e/build_trace_data.rs @@ -16,24 +16,24 @@ fn simple_package_save_trace() { assert!(temp .join(TRACE_DIR) - .join("simple_package::tests::test_fib.json") + .join("simple_package_tests_test_fib.json") .exists()); assert!(!temp .join(TRACE_DIR) - .join("simple_package_integrationtest::test_simple::test_failing.json") + .join("simple_package_integrationtest_test_simple_test_failing.json") .exists()); assert!(!temp .join(TRACE_DIR) - .join("simple_package::tests::ignored_test.json") + .join("simple_package_tests_ignored_test.json") .exists()); assert!(temp .join(TRACE_DIR) - .join("simple_package_integrationtest::ext_function_test::test_simple.json") + .join("simple_package_integrationtest_ext_function_test_test_simple.json") .exists()); let trace_data = fs::read_to_string( temp.join(TRACE_DIR) - .join("simple_package_integrationtest::ext_function_test::test_simple.json"), + .join("simple_package_integrationtest_ext_function_test_test_simple.json"), ) .unwrap(); @@ -56,7 +56,7 @@ fn trace_has_contract_and_function_names() { let trace_data = fs::read_to_string( temp.join(TRACE_DIR) - .join("trace_info_integrationtest::test_trace::test_trace.json"), + .join("trace_info_integrationtest_test_trace_test_trace.json"), ) .unwrap(); @@ -103,7 +103,7 @@ fn trace_has_cairo_execution_info() { let trace_data = fs::read_to_string( temp.join(TRACE_DIR) - .join("trace_info_integrationtest::test_trace::test_trace.json"), + .join("trace_info_integrationtest_test_trace_test_trace.json"), ) .unwrap(); @@ -145,7 +145,7 @@ fn trace_has_deploy_with_no_constructor_phantom_nodes() { let trace_data = fs::read_to_string( temp.join(TRACE_DIR) - .join("trace_info_integrationtest::test_trace::test_trace.json"), + .join("trace_info_integrationtest_test_trace_test_trace.json"), ) .unwrap(); diff --git a/crates/forge/tests/e2e/io_operations.rs b/crates/forge/tests/e2e/io_operations.rs index af7394c16e..340d24d449 100644 --- a/crates/forge/tests/e2e/io_operations.rs +++ b/crates/forge/tests/e2e/io_operations.rs @@ -21,7 +21,7 @@ fn file_reading() { [FAIL] file_reading_integrationtest::test::json_non_existent Failure data: - "No such file or directory [..]" + [..] [FAIL] file_reading_integrationtest::test::invalid_json @@ -31,7 +31,7 @@ fn file_reading() { [FAIL] file_reading_integrationtest::test::non_existent Failure data: - "No such file or directory [..]" + "[..] file [..]" [FAIL] file_reading_integrationtest::test::non_ascii diff --git a/crates/forge/tests/e2e/mod.rs b/crates/forge/tests/e2e/mod.rs index 9fbf0d711c..c57881e399 100644 --- a/crates/forge/tests/e2e/mod.rs +++ b/crates/forge/tests/e2e/mod.rs @@ -11,7 +11,9 @@ mod coverage; mod docs_snippets_validation; mod env; mod features; +#[cfg(not(target_os = "windows"))] mod fork_warning; +#[cfg(not(target_os = "windows"))] mod forking; mod fuzzing; mod io_operations; diff --git a/crates/forge/tests/e2e/running.rs b/crates/forge/tests/e2e/running.rs index fd85ca524e..4424000e18 100644 --- a/crates/forge/tests/e2e/running.rs +++ b/crates/forge/tests/e2e/running.rs @@ -1045,7 +1045,7 @@ fn catch_runtime_errors() { use snforge_std::fs::{FileTrait, read_txt}; #[test] - #[should_panic(expected: "No such file or directory (os error 2)")] + #[should_panic(expected: "file")] fn catch_no_such_file() { let file = FileTrait::new("no_way_this_file_exists"); let content = read_txt(@file); diff --git a/crates/forge/tests/e2e/trace_resources.rs b/crates/forge/tests/e2e/trace_resources.rs index 7ceb37373f..8d2b69651a 100644 --- a/crates/forge/tests/e2e/trace_resources.rs +++ b/crates/forge/tests/e2e/trace_resources.rs @@ -65,7 +65,7 @@ fn assert_resources_for_test( fn deserialize_call_trace(test_name: &str, temp_dir: &TempDir) -> VersionedProfilerCallTrace { let trace_data = fs::read_to_string(temp_dir.join(TRACE_DIR).join(format!( - "trace_resources_tests::{test_name}::{test_name}.json" + "trace_resources_tests_{test_name}_{test_name}.json" ))) .unwrap(); serde_json::from_str(&trace_data).expect("Failed to parse call trace") diff --git a/crates/forge/tests/integration/cheat_fork.rs b/crates/forge/tests/integration/cheat_fork.rs index a1ba19c3de..f3fd428433 100644 --- a/crates/forge/tests/integration/cheat_fork.rs +++ b/crates/forge/tests/integration/cheat_fork.rs @@ -4,6 +4,7 @@ use test_utils::runner::assert_passed; use test_utils::running_tests::run_test_case; use test_utils::test_case; +#[cfg(not(target_os = "windows"))] #[test] fn cheat_caller_address_cairo0_contract() { let test = test_case!(formatdoc!( @@ -52,6 +53,7 @@ fn cheat_caller_address_cairo0_contract() { assert_passed(&result); } +#[cfg(not(target_os = "windows"))] #[test] fn cheat_block_number_cairo0_contract() { let test = test_case!(formatdoc!( @@ -100,6 +102,7 @@ fn cheat_block_number_cairo0_contract() { assert_passed(&result); } +#[cfg(not(target_os = "windows"))] #[test] fn cheat_block_timestamp_cairo0_contract() { let test = test_case!(formatdoc!( @@ -150,12 +153,13 @@ fn cheat_block_timestamp_cairo0_contract() { assert_passed(&result); } +#[cfg(not(target_os = "windows"))] #[test] -fn mock_call_cairo0_contract() { +fn store_load_cairo0_contract() { let test = test_case!(formatdoc!( r#" use starknet::{{contract_address_const}}; - use snforge_std::{{start_mock_call, stop_mock_call}}; + use snforge_std::{{store, load}}; #[starknet::interface] trait IERC20 {{ @@ -173,13 +177,17 @@ fn mock_call_cairo0_contract() { assert(eth_dispatcher.name() == 'Ether', 'invalid name'); - start_mock_call(eth_dispatcher.contract_address, selector!("name"), 'NotEther'); + let name = load(eth_dispatcher.contract_address, selector!("ERC20_name"), 1); - assert(eth_dispatcher.name() == 'NotEther', 'invalid mocked name'); + assert(name == array!['Ether'], 'invalid load value'); - stop_mock_call(eth_dispatcher.contract_address, selector!("name")); + store(eth_dispatcher.contract_address, selector!("ERC20_name"), array!['NotEther'].span()); - assert(eth_dispatcher.name() == 'Ether', 'invalid name after mock'); + assert(eth_dispatcher.name() == 'NotEther', 'invalid store name'); + + let name = load(eth_dispatcher.contract_address, selector!("ERC20_name"), 1); + + assert(name == array!['NotEther'], 'invalid load2 name'); }} "#, node_rpc_url(), @@ -191,12 +199,13 @@ fn mock_call_cairo0_contract() { assert_passed(&result); } +#[cfg(not(target_os = "windows"))] #[test] -fn store_load_cairo0_contract() { +fn mock_call_cairo0_contract() { let test = test_case!(formatdoc!( r#" use starknet::{{contract_address_const}}; - use snforge_std::{{store, load}}; + use snforge_std::{{start_mock_call, stop_mock_call}}; #[starknet::interface] trait IERC20 {{ @@ -214,17 +223,13 @@ fn store_load_cairo0_contract() { assert(eth_dispatcher.name() == 'Ether', 'invalid name'); - let name = load(eth_dispatcher.contract_address, selector!("ERC20_name"), 1); + start_mock_call(eth_dispatcher.contract_address, selector!("name"), 'NotEther'); - assert(name == array!['Ether'], 'invalid load value'); + assert(eth_dispatcher.name() == 'NotEther', 'invalid mocked name'); - store(eth_dispatcher.contract_address, selector!("ERC20_name"), array!['NotEther'].span()); + stop_mock_call(eth_dispatcher.contract_address, selector!("name")); - assert(eth_dispatcher.name() == 'NotEther', 'invalid store name'); - - let name = load(eth_dispatcher.contract_address, selector!("ERC20_name"), 1); - - assert(name == array!['NotEther'], 'invalid load2 name'); + assert(eth_dispatcher.name() == 'Ether', 'invalid name after mock'); }} "#, node_rpc_url(), diff --git a/crates/forge/tests/integration/setup_fork.rs b/crates/forge/tests/integration/setup_fork.rs index cad6272be1..730fbc594a 100644 --- a/crates/forge/tests/integration/setup_fork.rs +++ b/crates/forge/tests/integration/setup_fork.rs @@ -27,6 +27,7 @@ use test_utils::runner::{assert_case_output_contains, assert_failed, assert_pass use test_utils::running_tests::run_test_case; use test_utils::test_case; +#[cfg(not(target_os = "windows"))] #[test] fn fork_simple_decorator() { let test = test_case!(formatdoc!( @@ -70,6 +71,7 @@ fn fork_simple_decorator() { assert_passed(&result); } +#[cfg(not(target_os = "windows"))] #[test] fn fork_aliased_decorator() { let test = test_case!(indoc!( @@ -178,6 +180,7 @@ fn fork_aliased_decorator() { assert_passed(&result); } +#[cfg(not(target_os = "windows"))] #[test] fn fork_aliased_decorator_overrding() { let test = test_case!(indoc!( @@ -268,6 +271,7 @@ fn fork_aliased_decorator_overrding() { assert_passed(&result); } +#[cfg(not(target_os = "windows"))] #[test] fn fork_cairo0_contract() { let test = test_case!(formatdoc!( @@ -298,6 +302,7 @@ fn fork_cairo0_contract() { assert_passed(&result); } +#[cfg(not(target_os = "windows"))] #[test] fn get_block_info_in_forked_block() { let test = test_case!(formatdoc!( @@ -398,6 +403,7 @@ fn get_block_info_in_forked_block() { assert_passed(&result); } +#[cfg(not(target_os = "windows"))] #[test] fn fork_get_block_info_fails() { let test = test_case!(formatdoc!( @@ -422,6 +428,7 @@ fn fork_get_block_info_fails() { ); } +#[cfg(not(target_os = "windows"))] #[test] // found in: https://github.com/foundry-rs/starknet-foundry/issues/1175 fn incompatible_abi() { diff --git a/crates/forge/tests/integration/spy_events.rs b/crates/forge/tests/integration/spy_events.rs index 7cc3469d85..bfff44ec45 100644 --- a/crates/forge/tests/integration/spy_events.rs +++ b/crates/forge/tests/integration/spy_events.rs @@ -632,6 +632,7 @@ fn assert_not_emitted_fails() { assert_case_output_contains(&result, "assert_not_emitted_fails", "keys was emitted"); } +#[cfg(not(target_os = "windows"))] #[test] fn capture_cairo0_event() { let test = test_case!( diff --git a/crates/forge/tests/integration/store_load.rs b/crates/forge/tests/integration/store_load.rs index 3c3d289257..6af0be20ee 100644 --- a/crates/forge/tests/integration/store_load.rs +++ b/crates/forge/tests/integration/store_load.rs @@ -556,6 +556,7 @@ fn store_load_felt_to_felt() { assert_passed(&result); } +#[cfg(not(target_os = "windows"))] #[test] fn fork_store_load() { let test = test_utils::test_case!(formatdoc!( diff --git a/crates/sncast/src/state/state_file.rs b/crates/sncast/src/state/state_file.rs index 920ea6f93c..70b51a6dec 100644 --- a/crates/sncast/src/state/state_file.rs +++ b/crates/sncast/src/state/state_file.rs @@ -396,7 +396,8 @@ mod tests { } #[test] - #[should_panic(expected = "No such file or directory (os error 2)")] + #[should_panic(expected = "Failed to load state file")] + // TODO handle system specific panics fn test_load_state_file_invalid_path() { let state_file = Utf8PathBuf::from("bla/bla/crypto.json"); load_state_file(&state_file).unwrap(); diff --git a/crates/sncast/tests/e2e/account/import.rs b/crates/sncast/tests/e2e/account/import.rs index cfbe7daa2c..4e0f7e6d50 100644 --- a/crates/sncast/tests/e2e/account/import.rs +++ b/crates/sncast/tests/e2e/account/import.rs @@ -455,7 +455,7 @@ pub async fn test_invalid_private_key_file_path() { output, indoc! {r" command: account import - error: Failed to obtain private key from the file my_private_key: No such file or directory (os error 2) + error: Failed to obtain private key from the file my_private_key: [..] "}, ); } diff --git a/crates/sncast/tests/e2e/call.rs b/crates/sncast/tests/e2e/call.rs index 157102e856..6dd3e846ec 100644 --- a/crates/sncast/tests/e2e/call.rs +++ b/crates/sncast/tests/e2e/call.rs @@ -231,10 +231,23 @@ fn test_wrong_block_id() { #[test] fn test_happy_case_shell() { - let test_path = PathBuf::from("tests/shell/call.sh").canonicalize().unwrap(); + let script_extension = if cfg!(windows) { ".ps1" } else { ".sh" }; + let test_path = PathBuf::from(format!("tests/shell/call{script_extension}")) + .canonicalize() + .unwrap(); let binary_path = cargo_bin!("sncast"); - let snapbox = Command::new(test_path) + let command = if cfg!(windows) { + Command::new("powershell") + .arg("-ExecutionPolicy") + .arg("Bypass") + .arg("-File") + .arg(test_path) + } else { + Command::new(test_path) + }; + + let snapbox = command .arg(binary_path) .arg(URL) .arg(DATA_TRANSFORMER_CONTRACT_ADDRESS_SEPOLIA); diff --git a/crates/sncast/tests/e2e/deploy.rs b/crates/sncast/tests/e2e/deploy.rs index feb57b8f0a..3de61512d4 100644 --- a/crates/sncast/tests/e2e/deploy.rs +++ b/crates/sncast/tests/e2e/deploy.rs @@ -440,12 +440,23 @@ fn test_too_low_max_fee() { async fn test_happy_case_shell() { let tempdir = create_and_deploy_oz_account().await; - let test_path = PathBuf::from("tests/shell/deploy.sh") + let script_extension = if cfg!(windows) { ".ps1" } else { ".sh" }; + let test_path = PathBuf::from(format!("tests/shell/deploy{script_extension}")) .canonicalize() .unwrap(); let binary_path = cargo_bin!("sncast"); - let snapbox = Command::new(test_path) + let command = if cfg!(windows) { + Command::new("powershell") + .arg("-ExecutionPolicy") + .arg("Bypass") + .arg("-File") + .arg(test_path) + } else { + Command::new(test_path) + }; + + let snapbox = command .current_dir(tempdir.path()) .arg(binary_path) .arg(URL) diff --git a/crates/sncast/tests/e2e/invoke.rs b/crates/sncast/tests/e2e/invoke.rs index 4d7fa721f2..63c85afba3 100644 --- a/crates/sncast/tests/e2e/invoke.rs +++ b/crates/sncast/tests/e2e/invoke.rs @@ -429,12 +429,23 @@ async fn test_happy_case_cairo_expression_calldata() { async fn test_happy_case_shell() { let tempdir = create_and_deploy_oz_account().await; - let test_path = PathBuf::from("tests/shell/invoke.sh") + let script_extension = if cfg!(windows) { ".ps1" } else { ".sh" }; + let test_path = PathBuf::from(format!("tests/shell/invoke{script_extension}")) .canonicalize() .unwrap(); let binary_path = cargo_bin!("sncast"); - let snapbox = Command::new(test_path) + let command = if cfg!(windows) { + Command::new("powershell") + .arg("-ExecutionPolicy") + .arg("Bypass") + .arg("-File") + .arg(test_path) + } else { + Command::new(test_path) + }; + + let snapbox = command .current_dir(tempdir.path()) .arg(binary_path) .arg(URL) diff --git a/crates/sncast/tests/e2e/multicall/new.rs b/crates/sncast/tests/e2e/multicall/new.rs index 79a8703ebc..97361052f7 100644 --- a/crates/sncast/tests/e2e/multicall/new.rs +++ b/crates/sncast/tests/e2e/multicall/new.rs @@ -47,7 +47,7 @@ async fn test_no_output_path_specified() { error: the following required arguments were not provided: - Usage: sncast multicall new + Usage: sncast[..] multicall new For more information, try '--help'. "}; @@ -77,7 +77,7 @@ async fn test_directory_non_existent() { output, indoc! {r" command: multicall new - error: No such file or directory[..] + error: [..] "}, ); } diff --git a/crates/sncast/tests/e2e/multicall/run.rs b/crates/sncast/tests/e2e/multicall/run.rs index 9a378486f7..79e15f78ce 100644 --- a/crates/sncast/tests/e2e/multicall/run.rs +++ b/crates/sncast/tests/e2e/multicall/run.rs @@ -122,7 +122,7 @@ async fn test_invalid_path() { output, indoc! {r" command: multicall run - error: No such file or directory [..] + error: [..] "}, ); } diff --git a/crates/sncast/tests/e2e/script/init.rs b/crates/sncast/tests/e2e/script/init.rs index 704f11d9b5..9e09090049 100644 --- a/crates/sncast/tests/e2e/script/init.rs +++ b/crates/sncast/tests/e2e/script/init.rs @@ -133,7 +133,7 @@ fn test_initialized_script_compiles() { formatdoc! {r" [WARNING] The newly created script isn't auto-added to the workspace. [..] command: script init - message: Successfully initialized `{script_name}` at [..]/scripts/{script_name} + message: Successfully initialized `{script_name}` at [..]{script_name} "}, ); diff --git a/crates/sncast/tests/helpers/devnet.rs b/crates/sncast/tests/helpers/devnet.rs index 491f0634fb..63ebc92281 100644 --- a/crates/sncast/tests/helpers/devnet.rs +++ b/crates/sncast/tests/helpers/devnet.rs @@ -34,7 +34,13 @@ fn start_devnet() { } } - Command::new("tests/utils/devnet/starknet-devnet") + let devnet_path = if cfg!(target_os = "windows") { + "tests/utils/devnet/bin/starknet-devnet.exe" + } else { + "tests/utils/devnet/starknet-devnet" + }; + + Command::new(devnet_path) .args([ "--port", &port, @@ -81,11 +87,17 @@ fn start_devnet() { #[dtor] fn stop_devnet() { let port = Url::parse(URL).unwrap().port().unwrap_or(80).to_string(); - Command::new("pkill") - .args([ - "-f", - &format!("starknet-devnet.*{}.*{}", &port, &SEED.to_string())[..], - ]) - .spawn() - .expect("Failed to kill devnet processes"); + let pattern = format!("starknet-devnet.*{port}.*{SEED}"); + + if cfg!(target_os = "windows") { + Command::new("taskkill") + .args(["/IM", &pattern, "/F"]) + .output() + .expect("Failed to kill devnet processes"); + } else { + Command::new("pkill") + .args(["-f", &pattern]) + .output() + .expect("Failed to kill devnet processes"); + } } diff --git a/crates/sncast/tests/shell/call.ps1 b/crates/sncast/tests/shell/call.ps1 new file mode 100644 index 0000000000..12bcf8fbc3 --- /dev/null +++ b/crates/sncast/tests/shell/call.ps1 @@ -0,0 +1,19 @@ +$CAST_BINARY = $args[0] +$URL = $args[1] +$DATA_TRANSFORMER_CONTRACT_ADDRESS_SEPOLIA = $args[2] +& $CAST_BINARY ` + --int-format ` + --json ` + call ` + --url $URL ` + --contract-address $DATA_TRANSFORMER_CONTRACT_ADDRESS_SEPOLIA ` + --function complex_fn ` + --arguments @' +array![array![1, 2], array![3, 4, 5], array![6]], +12, +-128_i8, +\"Some string (a ByteArray)\", +('a shortstring', 32_u32), +true, +0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +'@ diff --git a/crates/sncast/tests/shell/deploy.ps1 b/crates/sncast/tests/shell/deploy.ps1 new file mode 100644 index 0000000000..40f369bad8 --- /dev/null +++ b/crates/sncast/tests/shell/deploy.ps1 @@ -0,0 +1,14 @@ +$CAST_BINARY = $args[0] +$URL = $args[1] +$CONSTRUCTOR_WITH_PARAMS_CONTRACT_CLASS_HASH_SEPOLIA = $args[2] +& $CAST_BINARY ` + --accounts-file accounts.json ` + --account my_account ` + --int-format ` + --json ` + deploy ` + --url $URL ` + --class-hash $CONSTRUCTOR_WITH_PARAMS_CONTRACT_CLASS_HASH_SEPOLIA ` + --arguments '0x420, 0x2137_u256' ` + --max-fee 99999999999999999 ` + --fee-token eth diff --git a/crates/sncast/tests/shell/invoke.ps1 b/crates/sncast/tests/shell/invoke.ps1 new file mode 100644 index 0000000000..e9eeb02f07 --- /dev/null +++ b/crates/sncast/tests/shell/invoke.ps1 @@ -0,0 +1,23 @@ +$CAST_BINARY = $args[0] +$URL = $args[1] +$DATA_TRANSFORMER_CONTRACT_ADDRESS_SEPOLIA = $args[2] +& $CAST_BINARY ` + --accounts-file accounts.json ` + --account my_account ` + --int-format ` + --json ` + invoke ` + --url $URL ` + --contract-address $DATA_TRANSFORMER_CONTRACT_ADDRESS_SEPOLIA ` + --function complex_fn ` + --arguments @' +array![array![1, 2], array![3, 4, 5], array![6]], +12, +-128_i8, +\"Some string (a ByteArray)\", +('a shortstring', 32_u32), +true, +0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +'@ ` + --max-fee 99999999999999999 ` + --fee-token eth diff --git a/scripts/install_devnet.ps1 b/scripts/install_devnet.ps1 new file mode 100644 index 0000000000..260c8406f8 --- /dev/null +++ b/scripts/install_devnet.ps1 @@ -0,0 +1,21 @@ +# Set strict mode +Set-StrictMode -Version Latest + +# Stop the script on error +$ErrorActionPreference = "Stop" + +# Get the path of the top-level Git directory +$DEVNET_INSTALL_DIR = Join-Path (git rev-parse --show-toplevel) "crates\sncast\tests\utils\devnet" + +# Set the DEVNET repository and revision +$DEVNET_REPO = "https://github.com/0xSpaceShard/starknet-devnet-rs.git" +$DEVNET_TAG = "v0.2.2" + +# Perform cargo install +cargo install --locked --git $DEVNET_REPO --tag $DEVNET_TAG --root $DEVNET_INSTALL_DIR --force + +# Output completion message +Write-Host "All done!" + +# Exit with success +exit 0 \ No newline at end of file