test-with-0.12.2/.cargo_vcs_info.json0000644000000001360000000000100130460ustar { "git": { "sha1": "b0449df6cb8f778a4b03e4f36c15a6e0d1ef8d46" }, "path_in_vcs": "" }test-with-0.12.2/.envrc000064400000000000000000000000121046102023000127450ustar 00000000000000use flake test-with-0.12.2/.github/workflows/dep_check.yml000064400000000000000000000016471046102023000176730ustar 00000000000000name: Dependency Check concurrency: group: rust-dependency-check-${{ github.head_ref }} cancel-in-progress: true on: schedule: - cron: '0 0 * * *' jobs: update_dependency: name: Check dependency runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 with: submodules: recursive - uses: cachix/install-nix-action@v15 with: nix_path: nixpkgs=channel:nixos-unstable - name: Update dependency id: update-dependency run: nix develop -c 'update-dependency' - name: Create Pull Request if: failure() && steps.update-dependency.outcome != 'success' uses: peter-evans/create-pull-request@v4 with: add-paths: Cargo.toml reviewers: yanganto base: main branch: dependency-update title: "Dependency Update" commit-message: "automated dependency update" test-with-0.12.2/.github/workflows/lint.yml000064400000000000000000000011431046102023000167230ustar 00000000000000name: Lint concurrency: group: lint-${{ github.head_ref }} cancel-in-progress: true on: pull_request: jobs: lint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Check spelling of file.txt uses: crate-ci/typos@master - name: Super-Linter uses: github/super-linter@v4 env: VALIDATE_ALL_CODEBASE: false DEFAULT_BRANCH: main VALIDATE_RUST_2021: true # Clippy is not updated for Rust 1.58, temp disable # VALIDATE_RUST_CLIPPY: true GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} test-with-0.12.2/.github/workflows/release.yml000064400000000000000000000010601046102023000173730ustar 00000000000000name: Rust Crate Release concurrency: group: rust-crate-release-${{ github.head_ref }} cancel-in-progress: true on: push: tags: - "v[0-9]+.[0-9]+.[0-9]+*" jobs: crate_release: name: Create Release runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 with: submodules: recursive - uses: cachix/install-nix-action@v15 with: nix_path: nixpkgs=channel:nixos-unstable - name: Publish Crate run: nix develop -c 'crate-publish' ${{ secrets.CARGO_REGISTRY_TOKEN }} test-with-0.12.2/.github/workflows/test.yml000064400000000000000000000006041046102023000167350ustar 00000000000000name: Test concurrency: group: test-${{ github.head_ref }} cancel-in-progress: true on: pull_request: jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: cachix/install-nix-action@v15 with: nix_path: nixpkgs=channel:nixos-unstable - name: Example test in features run: nix develop -c feature-test test-with-0.12.2/.gitignore000064400000000000000000000002731046102023000136300ustar 00000000000000/target/ **/*.rs.bk .envrc .direnv/ # The library shouldn't decide about the exact versions of # its dependencies, but let the downstream crate decide. Cargo.lock examples/runner/target test-with-0.12.2/Cargo.lock0000644000001352270000000000100110330ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "addr2line" version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" dependencies = [ "gimli", ] [[package]] name = "adler" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "ahash" version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" dependencies = [ "getrandom", "once_cell", "version_check", ] [[package]] name = "aho-corasick" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] [[package]] name = "arrayvec" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "backtrace" version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" dependencies = [ "addr2line", "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", ] [[package]] name = "base64" version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "bitvec" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ "funty", "radium", "tap", "wyz", ] [[package]] name = "borsh" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d4d6dafc1a3bb54687538972158f07b2c948bc57d5890df22c0739098b3028" dependencies = [ "borsh-derive", "cfg_aliases", ] [[package]] name = "borsh-derive" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf4918709cc4dd777ad2b6303ed03cb37f3ca0ccede8c1b0d28ac6db8f4710e0" dependencies = [ "once_cell", "proc-macro-crate", "proc-macro2", "quote", "syn 2.0.42", "syn_derive", ] [[package]] name = "bumpalo" version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" [[package]] name = "byte-unit" version = "5.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d405b41420a161b4e1dd5a52e3349f41b4dae9a39be02aff1d67fe53256430ac" dependencies = [ "rust_decimal", "serde", "utf8-width", ] [[package]] name = "bytecheck" version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6372023ac861f6e6dc89c8344a8f398fb42aaba2b5dbc649ca0c0e9dbcb627" dependencies = [ "bytecheck_derive", "ptr_meta", "simdutf8", ] [[package]] name = "bytecheck_derive" version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7ec4c6f261935ad534c0c22dbef2201b45918860eb1c574b972bd213a76af61" dependencies = [ "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "bytes" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "cc" version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ "libc", ] [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "core-foundation" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", ] [[package]] name = "core-foundation-sys" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "crossbeam-deque" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fca89a0e215bab21874660c67903c5f143333cab1da83d041c7ded6053774751" dependencies = [ "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" version = "0.9.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d2fe95351b870527a5d09bf563ed3c97c0cffb87cf1c78a591bf48bb218d9aa" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", "memoffset", ] [[package]] name = "crossbeam-utils" version = "0.8.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d96137f14f244c37f989d9fff8f95e6c18b918e71f36638f8c49112e4c78f" dependencies = [ "cfg-if", ] [[package]] name = "dashmap" version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", "hashbrown 0.14.3", "lock_api", "once_cell", "parking_lot_core", ] [[package]] name = "either" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" [[package]] name = "encoding_rs" version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" dependencies = [ "cfg-if", ] [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] name = "fastrand" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foreign-types" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ "foreign-types-shared", ] [[package]] name = "foreign-types-shared" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "funty" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" dependencies = [ "futures-channel", "futures-core", "futures-executor", "futures-io", "futures-sink", "futures-task", "futures-util", ] [[package]] name = "futures-channel" version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", "futures-sink", ] [[package]] name = "futures-core" version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-executor" version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" dependencies = [ "futures-core", "futures-task", "futures-util", ] [[package]] name = "futures-io" version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-sink" version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-util" version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-channel", "futures-core", "futures-io", "futures-sink", "futures-task", "memchr", "pin-project-lite", "pin-utils", "slab", ] [[package]] name = "getrandom" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "gimli" version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" [[package]] name = "h2" version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d6250322ef6e60f93f9a2162799302cd6f68f79f6e5d85c8c16f14d1d958178" dependencies = [ "bytes", "fnv", "futures-core", "futures-sink", "futures-util", "http", "indexmap", "slab", "tokio", "tokio-util", "tracing", ] [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ "ahash", ] [[package]] name = "hashbrown" version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" [[package]] name = "hermit-abi" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" [[package]] name = "home" version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "http" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" dependencies = [ "bytes", "fnv", "itoa", ] [[package]] name = "http-body" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", "pin-project-lite", ] [[package]] name = "httparse" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" version = "0.14.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" dependencies = [ "bytes", "futures-channel", "futures-core", "futures-util", "h2", "http", "http-body", "httparse", "httpdate", "itoa", "pin-project-lite", "socket2 0.5.5", "tokio", "tower-service", "tracing", "want", ] [[package]] name = "hyper-tls" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", "hyper", "native-tls", "tokio", "tokio-native-tls", ] [[package]] name = "idna" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", ] [[package]] name = "indexmap" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" dependencies = [ "equivalent", "hashbrown 0.14.3", ] [[package]] name = "ipnet" version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "itoa" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "js-sys" version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cee9c64da59eae3b50095c18d3e74f8b73c0b86d2792824ff01bbce68ba229ca" dependencies = [ "wasm-bindgen", ] [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" [[package]] name = "linux-raw-sys" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "lock_api" version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" dependencies = [ "autocfg", "scopeguard", ] [[package]] name = "log" version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" [[package]] name = "memchr" version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" [[package]] name = "memoffset" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" dependencies = [ "autocfg", ] [[package]] name = "mime" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "miniz_oxide" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ "adler", ] [[package]] name = "mio" version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" dependencies = [ "libc", "wasi", "windows-sys 0.48.0", ] [[package]] name = "native-tls" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" dependencies = [ "lazy_static", "libc", "log", "openssl", "openssl-probe", "openssl-sys", "schannel", "security-framework", "security-framework-sys", "tempfile", ] [[package]] name = "ntapi" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" dependencies = [ "winapi", ] [[package]] name = "num-traits" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] [[package]] name = "num_cpus" version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ "hermit-abi", "libc", ] [[package]] name = "object" version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ "memchr", ] [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "openssl" version = "0.10.61" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b8419dc8cc6d866deb801274bba2e6f8f6108c1bb7fcc10ee5ab864931dbb45" dependencies = [ "bitflags 2.4.1", "cfg-if", "foreign-types", "libc", "once_cell", "openssl-macros", "openssl-sys", ] [[package]] name = "openssl-macros" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", "syn 2.0.42", ] [[package]] name = "openssl-probe" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" version = "0.9.97" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3eaad34cdd97d81de97964fc7f29e2d104f483840d906ef56daa1912338460b" dependencies = [ "cc", "libc", "pkg-config", "vcpkg", ] [[package]] name = "parking_lot" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", "windows-targets 0.48.5", ] [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pin-project-lite" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" [[package]] name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "ping" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "500fabcec9333c21e32bbc3c98dc0eb54fa59eadfc34d1d2e2d7db71547be4b4" dependencies = [ "rand", "socket2 0.4.10", "thiserror", ] [[package]] name = "pkg-config" version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69d3587f8a9e599cc7ec2c00e331f71c4e69a5f9a4b8a6efd5b07466b9736f9a" [[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro-crate" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97dc5fea232fc28d2f597b37c4876b348a40e33f3b02cc975c8d006d78d94b1a" dependencies = [ "toml_datetime", "toml_edit", ] [[package]] name = "proc-macro-error" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", "syn 1.0.109", "version_check", ] [[package]] name = "proc-macro-error-attr" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ "proc-macro2", "quote", "version_check", ] [[package]] name = "proc-macro2" version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8" dependencies = [ "unicode-ident", ] [[package]] name = "ptr_meta" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" dependencies = [ "ptr_meta_derive", ] [[package]] name = "ptr_meta_derive" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" dependencies = [ "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "quote" version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ "proc-macro2", ] [[package]] name = "radium" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] [[package]] name = "rayon" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" dependencies = [ "either", "rayon-core", ] [[package]] name = "rayon-core" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" dependencies = [ "crossbeam-deque", "crossbeam-utils", ] [[package]] name = "redox_syscall" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "regex" version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rend" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2571463863a6bd50c32f94402933f03457a3fbaf697a707c5be741e459f08fd" dependencies = [ "bytecheck", ] [[package]] name = "reqwest" version = "0.11.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" dependencies = [ "base64", "bytes", "encoding_rs", "futures-core", "futures-util", "h2", "http", "http-body", "hyper", "hyper-tls", "ipnet", "js-sys", "log", "mime", "native-tls", "once_cell", "percent-encoding", "pin-project-lite", "serde", "serde_json", "serde_urlencoded", "system-configuration", "tokio", "tokio-native-tls", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", "winreg", ] [[package]] name = "rkyv" version = "0.7.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "527a97cdfef66f65998b5f3b637c26f5a5ec09cc52a3f9932313ac645f4190f5" dependencies = [ "bitvec", "bytecheck", "bytes", "hashbrown 0.12.3", "ptr_meta", "rend", "rkyv_derive", "seahash", "tinyvec", "uuid", ] [[package]] name = "rkyv_derive" version = "0.7.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5c462a1328c8e67e4d6dbad1eb0355dd43e8ab432c6e227a43657f16ade5033" dependencies = [ "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "rust_decimal" version = "1.33.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06676aec5ccb8fc1da723cc8c0f9a46549f21ebb8753d3915c6c41db1e7f1dc4" dependencies = [ "arrayvec", "borsh", "bytes", "num-traits", "rand", "rkyv", "serde", "serde_json", ] [[package]] name = "rustc-demangle" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustix" version = "0.38.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" dependencies = [ "bitflags 2.4.1", "errno", "libc", "linux-raw-sys", "windows-sys 0.52.0", ] [[package]] name = "ryu" version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "schannel" version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88" dependencies = [ "windows-sys 0.48.0", ] [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "seahash" version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "security-framework" version = "2.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" dependencies = [ "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", "security-framework-sys", ] [[package]] name = "security-framework-sys" version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" dependencies = [ "core-foundation-sys", "libc", ] [[package]] name = "serde" version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", "syn 2.0.42", ] [[package]] name = "serde_json" version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ "itoa", "ryu", "serde", ] [[package]] name = "serde_urlencoded" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", "itoa", "ryu", "serde", ] [[package]] name = "serial_test" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e56dd856803e253c8f298af3f4d7eb0ae5e23a737252cd90bb4f3b435033b2d" dependencies = [ "dashmap", "futures", "lazy_static", "log", "parking_lot", "serial_test_derive", ] [[package]] name = "serial_test_derive" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", "syn 2.0.42", ] [[package]] name = "simdutf8" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" [[package]] name = "slab" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "smallvec" version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "socket2" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" dependencies = [ "libc", "winapi", ] [[package]] name = "socket2" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" dependencies = [ "libc", "windows-sys 0.48.0", ] [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "syn" version = "2.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b7d0a2c048d661a1a59fcd7355baa232f7ed34e0ee4df2eef3c1c1c0d3852d8" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "syn_derive" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" dependencies = [ "proc-macro-error", "proc-macro2", "quote", "syn 2.0.42", ] [[package]] name = "sysinfo" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c68492e7268037de59ae153d7efb79546cf94a18a9548235420d3d8d2436b4b1" dependencies = [ "cfg-if", "core-foundation-sys", "libc", "ntapi", "once_cell", "rayon", "windows", ] [[package]] name = "system-configuration" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", "core-foundation", "system-configuration-sys", ] [[package]] name = "system-configuration-sys" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" dependencies = [ "core-foundation-sys", "libc", ] [[package]] name = "tap" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" dependencies = [ "cfg-if", "fastrand", "redox_syscall", "rustix", "windows-sys 0.48.0", ] [[package]] name = "test-with" version = "0.12.2" dependencies = [ "byte-unit", "num_cpus", "ping", "proc-macro-error", "proc-macro2", "quote", "regex", "reqwest", "serial_test", "syn 2.0.42", "sysinfo", "tokio", "users", "which", ] [[package]] name = "thiserror" version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f11c217e1416d6f036b870f14e0413d480dbf28edbee1f877abaf0206af43bb7" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01742297787513b79cf8e29d1056ede1313e2420b7b3b15d0a768b4921f549df" dependencies = [ "proc-macro2", "quote", "syn 2.0.42", ] [[package]] name = "tinyvec" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] [[package]] name = "tinyvec_macros" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" version = "1.35.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" dependencies = [ "backtrace", "bytes", "libc", "mio", "num_cpus", "pin-project-lite", "socket2 0.5.5", "tokio-macros", "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", "syn 2.0.42", ] [[package]] name = "tokio-native-tls" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" dependencies = [ "native-tls", "tokio", ] [[package]] name = "tokio-util" version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" dependencies = [ "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", "tracing", ] [[package]] name = "toml_datetime" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" [[package]] name = "toml_edit" version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" dependencies = [ "indexmap", "toml_datetime", "winnow", ] [[package]] name = "tower-service" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "pin-project-lite", "tracing-core", ] [[package]] name = "tracing-core" version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] [[package]] name = "try-lock" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "unicode-bidi" version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f2528f27a9eb2b21e69c95319b30bd0efd85d09c379741b0f78ea1d86be2416" [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ "tinyvec", ] [[package]] name = "url" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", "percent-encoding", ] [[package]] name = "users" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24cc0f6d6f267b73e5a2cadf007ba8f9bc39c6a6f9666f8cf25ea809a153b032" dependencies = [ "libc", "log", ] [[package]] name = "utf8-width" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" [[package]] name = "uuid" version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e395fcf16a7a3d8127ec99782007af141946b4795001f876d54fb0d55978560" [[package]] name = "vcpkg" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "want" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ "try-lock", ] [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ed0d4f68a3015cc185aff4db9506a015f4b96f95303897bfa23f846db54064e" dependencies = [ "cfg-if", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b56f625e64f3a1084ded111c4d5f477df9f8c92df113852fa5a374dbda78826" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", "syn 2.0.42", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac36a15a220124ac510204aec1c3e5db8a22ab06fd6706d881dc6149f8ed9a12" dependencies = [ "cfg-if", "js-sys", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0162dbf37223cd2afce98f3d0785506dcb8d266223983e4b5b525859e6e182b2" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", "syn 2.0.42", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.89" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ab9b36309365056cd639da3134bf87fa8f3d86008abf99e612384a6eecd459f" [[package]] name = "web-sys" version = "0.3.66" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50c24a44ec86bb68fbecd1b3efed7e85ea5621b39b35ef2766b66cd984f8010f" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "which" version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bf3ea8596f3a0dd5980b46430f2058dfe2c36a27ccfbb1845d6fbfcd9ba6e14" dependencies = [ "either", "home", "once_cell", "rustix", "windows-sys 0.48.0", ] [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" dependencies = [ "windows-core", "windows-targets 0.48.5", ] [[package]] name = "windows-core" version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" dependencies = [ "windows-targets 0.48.5", ] [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets 0.48.5", ] [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets 0.52.0", ] [[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm 0.48.5", "windows_aarch64_msvc 0.48.5", "windows_i686_gnu 0.48.5", "windows_i686_msvc 0.48.5", "windows_x86_64_gnu 0.48.5", "windows_x86_64_gnullvm 0.48.5", "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" dependencies = [ "windows_aarch64_gnullvm 0.52.0", "windows_aarch64_msvc 0.52.0", "windows_i686_gnu 0.52.0", "windows_i686_msvc 0.52.0", "windows_x86_64_gnu 0.52.0", "windows_x86_64_gnullvm 0.52.0", "windows_x86_64_msvc 0.52.0", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" version = "0.5.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b5c3db89721d50d0e2a673f5043fc4722f76dcc352d7b1ab8b8288bed4ed2c5" dependencies = [ "memchr", ] [[package]] name = "winreg" version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ "cfg-if", "windows-sys 0.48.0", ] [[package]] name = "wyz" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" dependencies = [ "tap", ] test-with-0.12.2/Cargo.toml0000644000000037160000000000100110530ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" name = "test-with" version = "0.12.2" authors = ["Antonio Yang "] description = "A lib help you run test with condition" readme = "README.md" keywords = [ "testing", "condition", "toggle", "integration", "ignore", ] categories = [ "development-tools", "testing", ] license = "MIT" repository = "https://github.com/yanganto/test-with" [lib] proc-macro = true [dependencies.byte-unit] version = "5.0" optional = true [dependencies.num_cpus] version = "1.13" optional = true [dependencies.ping] version = "0.5" optional = true [dependencies.proc-macro-error] version = "1.0" [dependencies.proc-macro2] version = "1.0" [dependencies.quote] version = "1.0" [dependencies.regex] version = "1" [dependencies.reqwest] version = "0.11" features = ["blocking"] optional = true [dependencies.syn] version = "2.0" features = ["full"] [dependencies.sysinfo] version = "0.30" optional = true [dependencies.which] version = "5.0" optional = true [dev-dependencies.serial_test] version = "2.0.0" [dev-dependencies.tokio] version = "1.15.0" features = [ "rt", "macros", ] [features] default = [ "net", "resource", "user", "executable", ] executable = ["which"] http = ["reqwest"] icmp = ["ping"] ign-msg = [] net = [ "http", "icmp", ] resource = [ "sysinfo", "byte-unit", "num_cpus", ] runtime = [] user = ["users"] [target."cfg(not(target_os = \"windows\"))".dependencies.users] version = "0.11" optional = true test-with-0.12.2/Cargo.toml.orig000064400000000000000000000024051046102023000145260ustar 00000000000000[package] name = "test-with" version = "0.12.2" authors = ["Antonio Yang "] edition = "2021" license = "MIT" description = "A lib help you run test with condition" repository = "https://github.com/yanganto/test-with" keywords = [ "testing", "condition", "toggle", "integration", "ignore" ] categories = [ "development-tools", "testing" ] [lib] proc-macro = true [dependencies] proc-macro-error = "1.0" proc-macro2 = "1.0" quote = "1.0" syn = { version = "2.0", features = [ "full" ] } regex = { version = "1" } reqwest = { version = "0.11", features = ["blocking"], optional = true } ping = { version = "0.5", optional = true } sysinfo = { version = "0.30", optional = true } byte-unit = { version = "5.0", optional = true } num_cpus = { version = "1.13", optional = true } which = { version = "5.0", optional = true } [target.'cfg(not(target_os = "windows"))'.dependencies] users = { version = "0.11", optional = true } [features] default = ["net", "resource", "user", "executable"] ign-msg = [] runtime = [] net = ["http", "icmp"] http = ["reqwest"] icmp = ["ping"] resource = ["sysinfo", "byte-unit", "num_cpus"] user = ["users"] executable = ["which"] [dev-dependencies] tokio = { version = "1.15.0", features = ["rt", "macros"] } serial_test = "2.0.0" test-with-0.12.2/LICENSE000064400000000000000000000020551046102023000126450ustar 00000000000000MIT License Copyright (c) 2021 Antonio Yang Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. test-with-0.12.2/README.md000064400000000000000000000237021046102023000131210ustar 00000000000000# test-with [![Crates.io][crates-badge]][crate-url] [![MIT licensed][mit-badge]][mit-url] [![Docs][doc-badge]][doc-url] A lib help you run test with conditions, else the test will be ignored with clear message. Also, you can easiler run test with customed test environment or mock service. ## Introduction It is good to use this crate in dev dependency as following ```toml [dev-dependencies] test-with = "*" ``` If you want the dependency smaller with a shorter compiling time, you can disable default features and use specific one. For example, if you only checking a remote web server, you can use the `net` or `http` feature as the following. ```toml [dev-dependencies] test-with = { version = "*", default-features = false, features = ["http"] } ``` The features you can use are `net`(`http`, `icmp`), `resource`, `user`, `executable`. Currently, the condition is checked on build-time not runtime and not perfect and good for most develop scenario, because of this [issue][original-issue] of rust-lang. Here are [slides@COSCUP][coscup-slides] and [slides@COSCON][coscon-slides] to help you know more about it. If you really want to check the condition in runtime, please check [runtime section](https://github.com/yanganto/test-with#runtime). The `runtime` feature and runtime macros (`test_with::runner!`, `#[test_with::module]`, `#[test_with::runtime_env()]`) can help you run the test and check the conditions in runtime. Also, the customed test environment or mock service can set with the modules with `runtime` feature. If you forget to add `#[test]` flag on the test case, `#[test_with]` macro will add it for you. Rust version `1.61` of stable channel or `2022-03-30` of nightly channel will show the ignore message. If the ignore message does not show in the previous Rust version you used, the feature `ign-msg` can be used to work around. and the name of ignored test case will be rewritten, such that you can easier to know why the test is ignored. The order of test macros(`#[test]`, `#[tokio::test]`, `#[serial_test::serial]`, ...) is important, please check out examples. ## Environment Variable Run test case when the environment variable is set. ```rust // PWD environment variable exists #[test_with::env(PWD)] #[test] fn test_works() { assert!(true); } // NOTHING environment variable does not exist #[test_with::env(NOTHING)] #[test] fn test_ignored() { panic!("should be ignored") } ``` Result of `cargo test` ```text running 2 tests test tests::test_ignored ... ignored, because following variable not found: NOTHING test tests::test_works ... ok test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s ``` Or run all test cases for test module when the environment variable is set. ```rust #[test_with::env(PWD)] #[cfg(test)] mod tests { #[test] fn test_works() { assert!(true); } } ``` If the test depends on more than one environment variables, you can write it with multiple variables, `#[test_with::env(VAR1, VAR2)]`. Also, the test case can be ignored with the specific environment variable. ```rust // The test will be ignored in Github actions. #[test_with::no_env(GITHUB_ACTIONS)] #[test] fn test_ignore_in_github_action() { println!("Should be ignored in GITHUB_ACTION"); } ``` ## File/Folder Run test case when the file or folder exist. This is good for testing with database config. If you want to check the folder exist or not, please use `path`. ```rust // hostname exists #[test_with::file(/etc/hostname)] #[test] fn test_works() { assert!(true); } // nothing file does not exist #[test_with::file(/etc/nothing)] #[test] fn test_ignored() { panic!("should be ignored") } // etc exists #[test_with::path(/etc)] #[test] fn test_works_for_path() { assert!(true); } ``` If the test depends on more than one file or path, you can write it with multiple file/path, `#[test_with::file(/file1, /file2)]` or `#[test_with::path(/folder, /file)]`. ## Http/Https Service Run test case when the http/https service available. This is good for integration testing. Require `http` feature, if default features are disabled. ```rust // https service exists #[test_with::https(www.rust-lang.org)] #[test] fn test_works() { assert!(true); } // There is no not.exist.com #[test_with::https(not.exist.com)] #[test] fn test_ignored() { panic!("should be ignored") } ``` If the test depends on more than one service, you can write it with multiple service, `#[test_with::http(service1, service2)]` or `#[test_with::http2(service1, service2)]`. ## TCP socket Run integration test case when the remote tcp socket is listening. ```rust #[test_with::tcp(8.8.8.8:53)] #[test] fn test_works() { assert!(true); } #[test_with::tcp(193.194.195.196)] #[test] fn test_ignored() { panic!("should be ignored") } ``` ## Remote Server Online Status Run integration test case when the remote server online. **Please note the user running test case should have capability to open socket**. Require `icmp` feature, if default features are disabled. ```rust // localhost is online #[test_with::icmp(127.0.0.1)] #[test] fn test_works() { assert!(true); } // 193.194.195.196 is offline #[test_with::icmp(193.194.195.196)] #[test] fn test_ignored() { panic!("should be ignored") } ``` ## User/Group condition Run integration test case when the user is specific user or in specific group Require `user` feature, if default features are disabled. ```rust #[test_with::root()] #[test] fn test_ignored() { panic!("should be ignored") } #[test_with::group(avengers)] #[test] fn test_ignored2() { panic!("should be ignored") } #[test_with::user(spider)] #[test] fn test_ignored3() { panic!("should be ignored") } ``` ## CPU/Memory/Swap condition Run integration test case when the memory/swap is enough Require `resource` feature, if default features are disabled. ```rust #[test_with::cpu_core(32)] #[test] fn test_ignored_by_cpu_core() { panic!("should be ignored") } #[test_with::phy_core(32)] #[test] fn test_ignored_by_physical_cpu_core() { panic!("should be ignored") } #[test_with::mem(999GB)] #[test] fn test_ignored_by_mem() { panic!("should be ignored") } #[test_with::swap(999GB)] #[test] fn test_ignored_by_swap() { panic!("should be ignored") } ``` ## Executable condition Run integration test case when the executables can be accessed Require `executable` feature, if default features are disabled. ```rust // `pwd` executable command exists #[test_with::executable(pwd)] #[test] fn test_executable() { assert!(true); } // `/bin/sh` executable exists #[test_with::executable(/bin/sh)] #[test] fn test_executable_with_path() { assert!(true); } // `non` does not exist #[test_with::executable(non)] #[test] fn test_non_existing_executable() { panic!("should be ignored") } // `pwd` and `ls` exist #[test_with::executable(pwd, ls)] #[test] fn test_executables_too() { assert!(true); } ``` ## Runtime We can let an example to do thing that cargo test runner do, `cargo run --example=`, and ignore testcase in runtime. The testcase of in the example will not in `#[cfg(test)]` or `#[test]` anymore, and use `#[test_with::runtime_*]`, the test runner will treat it as the test in Rust and also provide the same summary as `cargo test`. The `runtime` feature should be enabled and include as normal dependency, and also include the `libtest-with` with corresponding features in `Cargo.toml`. ```toml test-with = { version = "0.10", features = ["runtime"] } libtest-with = { version = "0.6.1-6", features = ["net", "resource", "user", "executable"] } ``` Create an example with the following runtime macros (`test_with::runner!`, `#[test_with::module]`, `#[test_with::runtime_env()]`). ```rust test_with::runner!(module_name); #[test_with::module] mod module_name { #[test_with::runtime_env(PWD)] fn test_works() { } } ``` or you can customized your condition function with `runtime_ignore_if` ```rust test_with::runner!(custom_mod); fn something_happened() -> Option { Some("because something happened".to_string()) } #[test_with::module] mod custom_mod { #[test_with::runtime_ignore_if(something_happened)] fn test_ignored() { assert!(false); } } ``` There are two ways to setup mock service in the test runner, one is by `struct` and the other is by `type`. ```rust test_with::runner!(test_with_mock); #[test_with::module] mod test_with_mock { pub struct TestEnv {} impl Default for TestEnv { fn default() -> TestEnv { // Set up mock here TestEnv {} } } impl Drop for TestEnv { fn drop(&mut self) { // Tear down mock here } } } ``` or ```rust test_with::runner!(test_with_mock); pub struct Moc {} impl Default for Moc { fn default() -> Moc { // Set up mock here Moc {} } } impl Drop for Moc { fn drop(&mut self) { // Tear down mock here } } #[test_with::module] mod test_with_mock { pub type TestEnv = super::Moc; } ``` Please check out examples uder the [example/runner](https://github.com/yanganto/test-with/tree/main/examples/runner) project. ## Relating issues * [Solve this in runtime][original-issue] [crates-badge]: https://img.shields.io/crates/v/test-with.svg [crate-url]: https://crates.io/crates/test-with [mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg [mit-url]: https://github.com/yanganto/test-with/blob/readme/LICENSE [doc-badge]: https://img.shields.io/badge/docs-rs-orange.svg [doc-url]: https://docs.rs/test-with/latest/test_with/ [original-issue]: https://github.com/rust-lang/rust/issues/68007 [rust-pre-rfc]: https://internals.rust-lang.org/t/pre-rfc-provide-ignore-message-when-the-test-ignored/15904 [known-issue]: https://github.com/yanganto/test-with/issues/18 [coscup-slides]: http://slides.com/yanganto/rust-ignore [coscon-slides]: https://docs.google.com/presentation/d/1SjKdwWk0_YyhrRxV0bcay8PTO5htDRjBu99-tPRkMto/edit?usp=sharing test-with-0.12.2/examples/env.rs000064400000000000000000000024121046102023000146110ustar 00000000000000fn main() {} #[cfg(test)] mod tests { #[test_with::env(PWD)] fn test_works() { assert!(true); } #[test_with::env(NOTHING)] #[test] fn test_ignored() { panic!("should be ignored") } #[test_with::env(PWD, SAYING)] #[test] fn test_works_too() { assert!(true); } #[test_with::env(PWD, NOT_SAYING)] #[test] fn test_ignored_too() { panic!("should be ignored") } #[test_with::no_env(GITHUB_ACTIONS)] #[test] fn test_ignore_in_github_action() { println!("should be ignored in GITHUB_ACTION"); } } #[test_with::env(PWD)] pub mod workable_mod { #[test] fn test_works() { assert!(true); } } #[test_with::env(NOTHING)] pub mod ignore_pub_mod { #[test] fn test_ignored() { panic!("should be ignored") } } #[test_with::env(NOTHING)] mod ignore_private_mod { #[test] fn test_ignored() { panic!("should be ignored") } } #[test_with::env(NOTHING)] #[cfg(test)] pub mod ignore_pub_test_mod { #[test] fn test_ignored() { panic!("should be ignored") } } #[test_with::env(NOTHING)] #[cfg(test)] mod ignore_private_test_mod { #[test] fn test_ignored() { panic!("should be ignored") } } test-with-0.12.2/examples/executable.rs000064400000000000000000000011671046102023000161500ustar 00000000000000fn main() {} #[cfg(test)] mod tests { // `pwd` executable command exists #[test_with::executable(pwd)] #[test] fn test_executable() { assert!(true); } // `/bin/sh` executable exists #[test_with::executable(/bin/sh)] #[test] fn test_executable_with_path() { assert!(true); } // `non` does not exist #[test_with::executable(non)] #[test] fn test_non_existing_executable() { panic!("should be ignored") } // `pwd` and `ls` exist #[test_with::executable(pwd, ls)] #[test] fn test_executables_too() { assert!(true); } } test-with-0.12.2/examples/file.rs000064400000000000000000000042221046102023000147410ustar 00000000000000fn main() {} #[cfg(test)] mod tests { // hostname exists #[test_with::file(/etc/hostname)] fn test_works() { assert!(true); } // nothing file does not exist #[test_with::file(/etc/nothing)] #[test] fn test_ignored() { panic!("should be ignored") } // hostname and hosts exist #[test_with::file(/etc/hostname, /etc/hosts)] #[test] fn test_works_too() { assert!(true); } // nothing file does not exist #[test_with::file(/etc/hostname, /etc/nothing)] #[test] fn test_ignored_too() { panic!("should be ignored") } // etc exists, but not file #[test_with::file(/etc)] #[test] fn test_ignored_for_file() { panic!("should be ignored") } // hostname exists #[test_with::path(/etc/hostname)] #[test] fn test_works_for_file() { assert!(true); } // etc exists #[test_with::path(/etc)] #[test] fn test_works_for_path() { assert!(true); } // nothing does not exist #[test_with::path(/nothing)] #[test] fn test_ignored_for_path() { panic!("should be ignored") } // etc and tmp exist #[test_with::path(/etc, /tmp)] #[test] fn test_works_for_paths_too() { assert!(true); } // nothing does not exist #[test_with::file(/etc, /nothing)] #[test] fn test_ignored_for_paths_too() { panic!("should be ignored") } } #[test_with::file(/etc/hostname)] pub mod workable_mod { #[test] fn test_works() { assert!(true); } } #[test_with::file(/etc/nothing)] pub mod ignore_pub_mod { #[test] fn test_ignored() { panic!("should be ignored") } } #[test_with::file(/etc/nothing)] mod ignore_private_mod { #[test] fn test_ignored() { panic!("should be ignored") } } #[test_with::file(/etc/nothing)] #[cfg(test)] pub mod ignore_pub_test_mod { #[test] fn test_ignored() { panic!("should be ignored") } } #[test_with::file(/etc/nothing)] #[cfg(test)] mod ignore_private_test_mod { #[test] fn test_ignored() { panic!("should be ignored") } } test-with-0.12.2/examples/http.rs000064400000000000000000000037611046102023000150100ustar 00000000000000fn main() {} // HTTP #[cfg(test)] mod http_tests { #[test_with::http(httpbin.org)] #[test] fn test_works() { assert!(true); } #[test_with::http(not.exist.com)] #[test] fn test_ignored() { panic!("should be ignored") } } #[test_with::http(httpbin.org)] pub mod workable_http_mod { #[test] fn test_works() { assert!(true); } } #[test_with::http(not.exist.com)] pub mod ignore_pub_http_mod { #[test] fn test_ignored() { panic!("should be ignored") } } #[test_with::http(not.exist.com)] mod ignore_private_http_mod { #[test] fn test_ignored() { panic!("should be ignored") } } #[test_with::http(not.exist.com)] #[cfg(test)] pub mod ignore_pub_test_http_mod { #[test] fn test_ignored() { panic!("should be ignored") } } #[test_with::http(not.exist.com)] #[cfg(test)] mod ignore_private_test_http_mod { #[test] fn test_ignored() { panic!("should be ignored") } } // HTTPS #[cfg(test)] mod https_tests { #[test_with::https(www.rust-lang.org)] #[test] fn test_works() { assert!(true); } #[test_with::https(not.exist.com)] #[test] fn test_ignored() { panic!("should be ignored") } } #[test_with::https(httpbin.org)] pub mod workable_https_mod { #[test] fn test_works() { assert!(true); } } #[test_with::https(not.exist.com)] pub mod ignore_pub_https_mod { #[test] fn test_ignored() { panic!("should be ignored") } } #[test_with::https(not.exist.com)] mod ignore_private_https_mod { #[test] fn test_ignored() { panic!("should be ignored") } } #[test_with::https(not.exist.com)] #[cfg(test)] pub mod ignore_pub_test_https_mod { #[test] fn test_ignored() { panic!("should be ignored") } } #[test_with::https(not.exist.com)] #[cfg(test)] mod ignore_private_test_https_mod { #[test] fn test_ignored() { panic!("should be ignored") } } test-with-0.12.2/examples/icmp.rs000064400000000000000000000021231046102023000147500ustar 00000000000000fn main() {} #[cfg(test)] mod icmp_tests { #[test_with::icmp(127.0.0.1)] #[test] fn test_works() { assert!(true); } #[test_with::icmp(::1)] #[test] fn test_ipv6_works() { assert!(true); } #[test_with::icmp(193.194.195.196)] #[test] fn test_ignored() { panic!("should be ignored") } } #[test_with::icmp(127.0.0.1)] pub mod workable_icmp_mod { #[test] fn test_works() { assert!(true); } } #[test_with::icmp(193.194.195.196)] pub mod ignore_pub_icmp_mod { #[test] fn test_ignored() { panic!("should be ignored") } } #[test_with::icmp(193.194.195.196)] mod ignore_private_icmp_mod { #[test] fn test_ignored() { panic!("should be ignored") } } #[test_with::icmp(193.194.195.196)] #[cfg(test)] pub mod ignore_pub_test_icmp_mod { #[test] fn test_ignored() { panic!("should be ignored") } } #[test_with::icmp(193.194.195.196)] #[cfg(test)] mod ignore_private_test_icmp_mod { #[test] fn test_ignored() { panic!("should be ignored") } } test-with-0.12.2/examples/resource.rs000064400000000000000000000010011046102023000156410ustar 00000000000000fn main() {} #[cfg(test)] mod tests { #[test_with::mem(999GB)] #[test] fn mem_test_ignored() { panic!("should be ignored") } #[test_with::swap(999GB)] #[test] fn swap_test_ignored() { panic!("should be ignored") } #[test_with::cpu_core(32)] #[test] fn cpu_core_test_ignored() { panic!("should be ignored") } #[test_with::phy_core(32)] #[test] fn physical_cpu_core_test_ignored() { panic!("should be ignored") } } test-with-0.12.2/examples/serial.rs000064400000000000000000000004001046102023000152730ustar 00000000000000use serial_test::serial; #[tokio::main] async fn main() {} #[serial] #[test_with::env(NOTHING)] #[tokio::test] async fn my_test_1() { assert!(false); } #[serial] #[test_with::env(NOTHING)] #[tokio::test] async fn my_test_2() { assert!(false); } test-with-0.12.2/examples/tcp.rs000064400000000000000000000015041046102023000146100ustar 00000000000000fn main() {} #[cfg(test)] mod tcp_tests { #[test_with::tcp(8.8.8.8:53)] #[test] fn test_works() { assert!(true); } #[test_with::tcp(193.194.195.196)] #[test] fn test_ignored() { panic!("should be ignored") } } #[test_with::tcp(8.8.8.8:53)] pub mod workable_tcp_mod { #[test] fn test_works() { assert!(true); } } #[test_with::tcp(193.194.195.196)] pub mod ignore_pub_tcp_mod { #[test] fn test_ignored() { panic!("should be ignored") } } #[test_with::tcp(193.194.195.196)] mod ignore_private_tcp_mod { #[test] fn test_ignored() { panic!("should be ignored") } } #[test_with::tcp(193.194.195.196)] #[cfg(test)] pub mod ignore_pub_test_tcp_mod { #[test] fn test_ignored() { panic!("should be ignored") } } test-with-0.12.2/examples/tokio.rs000064400000000000000000000002711046102023000151470ustar 00000000000000use tokio; #[tokio::main] async fn main() {} #[cfg(test)] mod tokio_tests { #[test_with::env(NOTHING)] #[tokio::test] async fn my_test() { assert!(false); } } test-with-0.12.2/examples/user.rs000064400000000000000000000006241046102023000150020ustar 00000000000000fn main() {} #[cfg(test)] #[cfg(not(target_os = "windows"))] mod tests { #[test_with::root()] #[test] fn test_ignored() { panic!("should be ignored") } #[test_with::group(avengers)] #[test] fn test_ignored2() { panic!("should be ignored") } #[test_with::user(spider)] #[test] fn test_ignored3() { panic!("should be ignored") } } test-with-0.12.2/flake.lock000064400000000000000000000142071046102023000135760ustar 00000000000000{ "nodes": { "dependency-refresh": { "inputs": { "flake-utils": "flake-utils", "nixpkgs": "nixpkgs", "rust-overlay": "rust-overlay" }, "locked": { "lastModified": 1655108838, "narHash": "sha256-+4+mdQ+gGc21k82kkpp6ypIcm6HmqzZ6SGhHnUNoLSs=", "owner": "yanganto", "repo": "dependency-refresh", "rev": "31c08f60c09c2828e12740455785d2bba425ae77", "type": "github" }, "original": { "owner": "yanganto", "repo": "dependency-refresh", "type": "github" } }, "flake-utils": { "locked": { "lastModified": 1653893745, "narHash": "sha256-0jntwV3Z8//YwuOjzhV2sgJJPt+HY6KhU7VZUL0fKZQ=", "owner": "numtide", "repo": "flake-utils", "rev": "1ed9fb1935d260de5fe1c2f7ee0ebaae17ed2fa1", "type": "github" }, "original": { "owner": "numtide", "repo": "flake-utils", "type": "github" } }, "flake-utils_2": { "locked": { "lastModified": 1637014545, "narHash": "sha256-26IZAc5yzlD9FlDT54io1oqG/bBoyka+FJk5guaX4x4=", "owner": "numtide", "repo": "flake-utils", "rev": "bba5dcc8e0b20ab664967ad83d24d64cb64ec4f4", "type": "github" }, "original": { "owner": "numtide", "repo": "flake-utils", "type": "github" } }, "flake-utils_3": { "inputs": { "systems": "systems" }, "locked": { "lastModified": 1689068808, "narHash": "sha256-6ixXo3wt24N/melDWjq70UuHQLxGV8jZvooRanIHXw0=", "owner": "numtide", "repo": "flake-utils", "rev": "919d646de7be200f3bf08cb76ae1f09402b6f9b4", "type": "github" }, "original": { "owner": "numtide", "repo": "flake-utils", "type": "github" } }, "flake-utils_4": { "inputs": { "systems": "systems_2" }, "locked": { "lastModified": 1681202837, "narHash": "sha256-H+Rh19JDwRtpVPAWp64F+rlEtxUWBAQW28eAi3SRSzg=", "owner": "numtide", "repo": "flake-utils", "rev": "cfacdce06f30d2b68473a46042957675eebb3401", "type": "github" }, "original": { "owner": "numtide", "repo": "flake-utils", "type": "github" } }, "nixpkgs": { "locked": { "lastModified": 1654953433, "narHash": "sha256-TwEeh4r50NdWHFAHQSyjCk2cZxgwUfcCCAJOhPdXB28=", "owner": "nixos", "repo": "nixpkgs", "rev": "90cd5459a1fd707819b9a3fb9c852beaaac3b79a", "type": "github" }, "original": { "owner": "nixos", "ref": "nixos-unstable", "repo": "nixpkgs", "type": "github" } }, "nixpkgs_2": { "locked": { "lastModified": 1637453606, "narHash": "sha256-Gy6cwUswft9xqsjWxFYEnx/63/qzaFUwatcbV5GF/GQ=", "owner": "NixOS", "repo": "nixpkgs", "rev": "8afc4e543663ca0a6a4f496262cd05233737e732", "type": "github" }, "original": { "owner": "NixOS", "ref": "nixpkgs-unstable", "repo": "nixpkgs", "type": "github" } }, "nixpkgs_3": { "locked": { "lastModified": 1691006197, "narHash": "sha256-DbtxVWPt+ZP5W0Usg7jAyTomIM//c3Jtfa59Ht7AV8s=", "owner": "nixos", "repo": "nixpkgs", "rev": "66aedfd010204949cb225cf749be08cb13ce1813", "type": "github" }, "original": { "owner": "nixos", "ref": "nixos-unstable", "repo": "nixpkgs", "type": "github" } }, "nixpkgs_4": { "locked": { "lastModified": 1681358109, "narHash": "sha256-eKyxW4OohHQx9Urxi7TQlFBTDWII+F+x2hklDOQPB50=", "owner": "NixOS", "repo": "nixpkgs", "rev": "96ba1c52e54e74c3197f4d43026b3f3d92e83ff9", "type": "github" }, "original": { "owner": "NixOS", "ref": "nixpkgs-unstable", "repo": "nixpkgs", "type": "github" } }, "root": { "inputs": { "dependency-refresh": "dependency-refresh", "flake-utils": "flake-utils_3", "nixpkgs": "nixpkgs_3", "rust-overlay": "rust-overlay_2" } }, "rust-overlay": { "inputs": { "flake-utils": "flake-utils_2", "nixpkgs": "nixpkgs_2" }, "locked": { "lastModified": 1655088497, "narHash": "sha256-t8YdiQqG43uQKIB9BfjrmJauewFfpfZiT+Ts434CiCQ=", "owner": "oxalica", "repo": "rust-overlay", "rev": "cab0cb7f4dbbfa10cb3332da47726ed75861bfeb", "type": "github" }, "original": { "owner": "oxalica", "repo": "rust-overlay", "type": "github" } }, "rust-overlay_2": { "inputs": { "flake-utils": "flake-utils_4", "nixpkgs": "nixpkgs_4" }, "locked": { "lastModified": 1691115502, "narHash": "sha256-M4QWfCRrwBZ6HvYpJxB2bZCIs7ZCBEsF4a7mabRy3Zs=", "owner": "oxalica", "repo": "rust-overlay", "rev": "c6f763fe0ecbbcdbec404ff62f546485a03946e7", "type": "github" }, "original": { "owner": "oxalica", "repo": "rust-overlay", "type": "github" } }, "systems": { "locked": { "lastModified": 1681028828, "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", "owner": "nix-systems", "repo": "default", "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", "type": "github" }, "original": { "owner": "nix-systems", "repo": "default", "type": "github" } }, "systems_2": { "locked": { "lastModified": 1681028828, "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", "owner": "nix-systems", "repo": "default", "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", "type": "github" }, "original": { "owner": "nix-systems", "repo": "default", "type": "github" } } }, "root": "root", "version": 7 } test-with-0.12.2/flake.nix000064400000000000000000000045051046102023000134440ustar 00000000000000{ inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; rust-overlay.url = "github:oxalica/rust-overlay"; flake-utils.url = "github:numtide/flake-utils"; dependency-refresh.url = "github:yanganto/dependency-refresh"; }; outputs = { self, rust-overlay, nixpkgs, flake-utils, dependency-refresh }: flake-utils.lib.eachDefaultSystem (system: let overlays = [ (import rust-overlay) ]; pkgs = import nixpkgs { inherit system overlays; }; rust = pkgs.rust-bin.stable."1.71.1".default; dr = dependency-refresh.defaultPackage.${system}; publishScript = pkgs.writeShellScriptBin "crate-publish" '' cargo login $1 cargo publish ''; updateDependencyScript = pkgs.writeShellScriptBin "update-dependency" '' dr ./Cargo.toml if [ -f "Cargo.toml.old" ]; then rm Cargo.toml.old exit 1 fi ''; featureTestScript = pkgs.writeShellScriptBin "feature-test" '' set -e cargo run --no-default-features --features=http --example=http cargo run --no-default-features --features=icmp --example=icmp cargo run --no-default-features --example=tcp cargo run --no-default-features --features=net --example=http cargo run --no-default-features --features=net --example=icmp cargo run --no-default-features --features=user --example=user cargo run --no-default-features --features=resource --example=resource cargo run --no-default-features --features=executable --example=executable cargo install cargo-hack cargo hack test --examples # runtime ignore example cd examples/runner cargo run --example test cargo run --example mock cargo run --example mock2 cargo run --example mix ''; in with pkgs; { devShell = mkShell { buildInputs = [ rust openssl pkg-config dr publishScript featureTestScript updateDependencyScript ]; SAYING = '' The value of a man resides in what he gives and not in what he is capable of receiving.''; }; } ); } test-with-0.12.2/src/lib.rs000064400000000000000000002254631046102023000135550ustar 00000000000000//! `test_with` provides [macro@env], [macro@file], [macro@path], [macro@http], [macro@https], //! [macro@icmp], [macro@tcp], [macro@root], [macro@group], [macro@user], [macro@mem], [macro@swap], //! [macro@cpu_core], [macro@phy_core], [macro@executable] macros to help you run test case only //! with the condition is fulfilled. If the `#[test]` is absent for the test case, `#[test_with]` //! will add it to the test case automatically. //! //! This crate help you easier make integrating test case and has a good cargo summary on CI server, //! and will not affect on your binary output when you dependent it as dev-dependency as following. //! ```toml //! [dev-dependencies] //! test-with = "*" //! ``` //! All features will be opt-in default feature, so this crate will be easier to use, if you using //! a CI server with really limitation resource and want this crate as slim as possible, you can //! select the feature you want as following. //! ```toml //! [dev-dependencies] //! test-with = { version = "*", default-features = false, features = ["net"] } //! ``` //! //! The solution to have a real runtime condition check, we need to put the test as normal function //! as an example, then use `cargo run --example` //! The `test-with` need be included as normal dependency with `runtime` feature. //! And also include the `libtest-with` with corresponding features in `Cargo.toml` //! [macro@runner] and [macro@module] are for the basic skeleton of the test runner. //! [macro@runtime_env], [macro@runtime_no_env], [macro@runtime_file], [macro@runtime_path], //! [macro@runtime_http], [macro@runtime_https], [macro@runtime_icmp], [macro@runtime_tcp], //! [macro@runtime_root], [macro@runtime_group], [macro@runtime_user], [macro@runtime_mem], //! [macro@runtime_free_mem], [macro@runtime_available_mem], [macro@runtime_swap], //! [macro@runtime_free_swap], [macro@runtime_available_swap], [macro@runtime_cpu_core], //! [macro@runtime_phy_core], [macro@runtime_executable] and [macro@runtime_ignore_if] are //! used to transform a normal function to a //! testcase. //! //! ```toml //! [dependencies] //! test-with = { version = "*", default-features = false, features = ["runtime"] } //! libtest-with = { version = "0.6.1-6", features = ["net", "resource", "user", "executable"] } //! ``` //! //! ```rust //! // write as example in exmaples/*rs //! test_with::runner!(env); //! #[test_with::module] //! mod env { //! #[test_with::runtime_env(PWD)] //! fn test_works() { //! assert!(true); //! } //! } //! ``` use std::{fs::metadata, path::Path}; #[cfg(feature = "icmp")] use std::net::IpAddr; use std::net::TcpStream; use proc_macro::TokenStream; #[cfg(any(feature = "resource", feature = "icmp"))] use proc_macro_error::abort_call_site; use proc_macro_error::proc_macro_error; use syn::{parse_macro_input, ItemFn, ItemMod}; #[cfg(feature = "runtime")] use syn::{Item, ItemStruct, ItemType}; #[cfg(feature = "executable")] use which::which; use crate::utils::{fn_macro, is_module, mod_macro}; mod utils; /// Run test case when the environment variable is set. /// ``` /// #[cfg(test)] /// mod tests { /// /// // PWD environment variable exists /// #[test_with::env(PWD)] /// #[test] /// fn test_works() { /// assert!(true); /// } /// /// // NOTHING environment variable does not exist /// #[test_with::env(NOTHING)] /// #[test] /// fn test_ignored() { /// panic!("should be ignored") /// } /// /// // NOT_SAYING environment variable does not exist /// #[test_with::env(PWD, NOT_SAYING)] /// #[test] /// fn test_ignored_too() { /// panic!("should be ignored") /// } /// } /// ``` /// or run all test cases for test module when the environment variable is set. /// ``` /// #[test_with::env(PWD)] /// #[cfg(test)] /// mod tests { /// /// #[test] /// fn test_works() { /// assert!(true); /// } /// } /// ``` #[proc_macro_attribute] #[proc_macro_error] pub fn env(attr: TokenStream, stream: TokenStream) -> TokenStream { if is_module(&stream) { mod_macro( attr, parse_macro_input!(stream as ItemMod), check_env_condition, ) } else { fn_macro( attr, parse_macro_input!(stream as ItemFn), check_env_condition, ) } } fn check_env_condition(attr_str: String) -> (bool, String) { let var_names: Vec<&str> = attr_str.split(',').collect(); let mut missing_vars = vec![]; for var in var_names.iter() { if std::env::var(var).is_err() { missing_vars.push(var.to_string()); } } let ignore_msg = if missing_vars.len() == 1 { format!("because variable {} not found", missing_vars[0]) } else { format!( "because following variables not found:\n{}\n", missing_vars.join(", ") ) }; (missing_vars.is_empty(), ignore_msg) } /// Run test case when the example running and the environment variable is set. ///```rust /// // write as example in exmaples/*rs /// test_with::runner!(env); /// #[test_with::module] /// mod env { /// #[test_with::runtime_env(PWD)] /// fn test_works() { /// assert!(true); /// } /// } ///``` #[cfg(not(feature = "runtime"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_env(_attr: TokenStream, _stream: TokenStream) -> TokenStream { panic!("should be used with runtime feature") } #[cfg(feature = "runtime")] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_env(attr: TokenStream, stream: TokenStream) -> TokenStream { let attr_str = attr.to_string().replace(' ', ""); let var_names: Vec<&str> = attr_str.split(',').collect(); let ItemFn { attrs, vis, sig, block, } = parse_macro_input!(stream as ItemFn); let syn::Signature { ident, .. } = sig.clone(); let check_ident = syn::Ident::new( &format!("_check_{}", ident.to_string()), proc_macro2::Span::call_site(), ); quote::quote! { fn #check_ident() -> Result<(), libtest_with::Failed> { let mut missing_vars = vec![]; #( if std::env::var(#var_names).is_err() { missing_vars.push(#var_names); } )* match missing_vars.len() { 0 => { #ident(); Ok(()) }, 1 => Err( format!("{}because variable {} not found", libtest_with::RUNTIME_IGNORE_PREFIX, missing_vars[0] ).into()), _ => Err( format!("{}because following variables not found:\n{}\n", libtest_with::RUNTIME_IGNORE_PREFIX, missing_vars.join(", ") ).into()), } } #(#attrs)* #vis #sig #block } .into() } /// Ignore test case when the environment variable is set. /// ``` /// #[cfg(test)] /// mod tests { /// /// // The test will be ignored in GITHUB_ACTION /// #[test_with::no_env(GITHUB_ACTIONS)] /// #[test] /// fn test_ignore_in_github_action() { /// assert!(false); /// } /// } #[proc_macro_attribute] #[proc_macro_error] pub fn no_env(attr: TokenStream, stream: TokenStream) -> TokenStream { if is_module(&stream) { mod_macro( attr, parse_macro_input!(stream as ItemMod), check_no_env_condition, ) } else { fn_macro( attr, parse_macro_input!(stream as ItemFn), check_no_env_condition, ) } } fn check_no_env_condition(attr_str: String) -> (bool, String) { let var_names: Vec<&str> = attr_str.split(',').collect(); for var in var_names.iter() { if std::env::var(var).is_ok() { return ( false, format!("because the environment with variable {var:} will ignore"), ); } } (true, String::new()) } /// Ignore test case when the example running and the environment variable is set. ///```rust /// // write as example in exmaples/*rs /// test_with::runner!(env); /// #[test_with::module] /// mod env { /// #[test_with::runtime_no_env(NOT_EXIST)] /// fn test_works() { /// assert!(true); /// } /// } ///``` #[cfg(not(feature = "runtime"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_no_env(_attr: TokenStream, _stream: TokenStream) -> TokenStream { panic!("should be used with runtime feature") } #[cfg(feature = "runtime")] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_no_env(attr: TokenStream, stream: TokenStream) -> TokenStream { let attr_str = attr.to_string().replace(' ', ""); let var_names: Vec<&str> = attr_str.split(',').collect(); let ItemFn { attrs, vis, sig, block, } = parse_macro_input!(stream as ItemFn); let syn::Signature { ident, .. } = sig.clone(); let check_ident = syn::Ident::new( &format!("_check_{}", ident.to_string()), proc_macro2::Span::call_site(), ); quote::quote! { fn #check_ident() -> Result<(), libtest_with::Failed> { let mut should_no_exist_vars = vec![]; #( if std::env::var(#var_names).is_ok() { should_no_exist_vars.push(#var_names); } )* match should_no_exist_vars.len() { 0 => { #ident(); Ok(()) }, 1 => Err( format!("{}because variable {} found", libtest_with::RUNTIME_IGNORE_PREFIX, should_no_exist_vars[0] ).into()), _ => Err( format!("{}because following variables found:\n{}\n", libtest_with::RUNTIME_IGNORE_PREFIX, should_no_exist_vars.join(", ") ).into()), } } #(#attrs)* #vis #sig #block } .into() } /// Run test case when the file exist. /// ``` /// #[cfg(test)] /// mod tests { /// /// // hostname exists /// #[test_with::file(/etc/hostname)] /// #[test] /// fn test_works() { /// assert!(true); /// } /// /// // nothing file does not exist /// #[test_with::file(/etc/nothing)] /// #[test] /// fn test_ignored() { /// panic!("should be ignored") /// } /// /// // hostname and hosts exist /// #[test_with::file(/etc/hostname, /etc/hosts)] /// #[test] /// fn test_works_too() { /// assert!(true); /// } /// } /// ``` #[proc_macro_attribute] #[proc_macro_error] pub fn file(attr: TokenStream, stream: TokenStream) -> TokenStream { if is_module(&stream) { mod_macro( attr, parse_macro_input!(stream as ItemMod), check_file_condition, ) } else { fn_macro( attr, parse_macro_input!(stream as ItemFn), check_file_condition, ) } } fn check_file_condition(attr_str: String) -> (bool, String) { let files: Vec<&str> = attr_str.split(',').collect(); let mut missing_files = vec![]; for file in files.iter() { if !Path::new(file.trim_matches('"')).is_file() { missing_files.push(file.to_string()); } } let ignore_msg = if missing_files.len() == 1 { format!("because file not found: {}", missing_files[0]) } else { format!( "because following files not found: \n{}\n", missing_files.join("\n") ) }; (missing_files.is_empty(), ignore_msg) } /// Run test case when the example running and the file exist. ///```rust /// // write as example in exmaples/*rs /// test_with::runner!(file); /// #[test_with::module] /// mod file { /// #[test_with::runtime_file(/etc/hostname)] /// fn test_works() { /// assert!(true); /// } /// } ///``` #[cfg(not(feature = "runtime"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_file(_attr: TokenStream, _stream: TokenStream) -> TokenStream { panic!("should be used with runtime feature") } #[cfg(feature = "runtime")] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_file(attr: TokenStream, stream: TokenStream) -> TokenStream { let attr_str = attr.to_string().replace(' ', ""); let files: Vec<&str> = attr_str.split(',').collect(); let ItemFn { attrs, vis, sig, block, } = parse_macro_input!(stream as ItemFn); let syn::Signature { ident, .. } = sig.clone(); let check_ident = syn::Ident::new( &format!("_check_{}", ident.to_string()), proc_macro2::Span::call_site(), ); quote::quote! { fn #check_ident() -> Result<(), libtest_with::Failed> { let mut missing_files = vec![]; #( if !std::path::Path::new(#files.trim_matches('"')).is_file() { missing_files.push(#files); } )* match missing_files.len() { 0 => { #ident(); Ok(()) }, 1 => Err( format!("{}because file not found: {}", libtest_with::RUNTIME_IGNORE_PREFIX, missing_files[0] ).into()), _ => Err( format!("{}because following files not found: \n{}\n", libtest_with::RUNTIME_IGNORE_PREFIX, missing_files.join(", ") ).into()), } } #(#attrs)* #vis #sig #block } .into() } /// Run test case when the path(file or folder) exist. /// ``` /// #[cfg(test)] /// mod tests { /// /// // etc exists /// #[test_with::path(/etc)] /// #[test] /// fn test_works() { /// assert!(true); /// } /// /// // nothing does not exist /// #[test_with::path(/nothing)] /// #[test] /// fn test_ignored() { /// panic!("should be ignored") /// } /// /// // etc and tmp exist /// #[test_with::path(/etc, /tmp)] /// #[test] /// fn test_works_too() { /// assert!(true); /// } /// } /// ``` #[proc_macro_attribute] #[proc_macro_error] pub fn path(attr: TokenStream, stream: TokenStream) -> TokenStream { if is_module(&stream) { mod_macro( attr, parse_macro_input!(stream as ItemMod), check_path_condition, ) } else { fn_macro( attr, parse_macro_input!(stream as ItemFn), check_path_condition, ) } } fn check_path_condition(attr_str: String) -> (bool, String) { let paths: Vec<&str> = attr_str.split(',').collect(); let mut missing_paths = vec![]; for path in paths.iter() { if metadata(path.trim_matches('"')).is_err() { missing_paths.push(path.to_string()); } } let ignore_msg = if missing_paths.len() == 1 { format!("because path not found: {}", missing_paths[0]) } else { format!( "because following paths not found: \n{}\n", missing_paths.join("\n") ) }; (missing_paths.is_empty(), ignore_msg) } /// Run test case when the example running and the path(file or folder) exist. ///```rust /// // write as example in exmaples/*rs /// test_with::runner!(path); /// #[test_with::module] /// mod path { /// #[test_with::runtime_path(/etc)] /// fn test_works() { /// assert!(true); /// } /// } ///``` #[cfg(not(feature = "runtime"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_path(_attr: TokenStream, _stream: TokenStream) -> TokenStream { panic!("should be used with runtime feature") } #[cfg(feature = "runtime")] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_path(attr: TokenStream, stream: TokenStream) -> TokenStream { let attr_str = attr.to_string().replace(' ', ""); let paths: Vec<&str> = attr_str.split(',').collect(); let ItemFn { attrs, vis, sig, block, } = parse_macro_input!(stream as ItemFn); let syn::Signature { ident, .. } = sig.clone(); let check_ident = syn::Ident::new( &format!("_check_{}", ident.to_string()), proc_macro2::Span::call_site(), ); quote::quote! { fn #check_ident() -> Result<(), libtest_with::Failed> { let mut missing_paths = vec![]; #( if std::fs::metadata(#paths.trim_matches('"')).is_err() { missing_paths.push(#paths.to_string()); } )* match missing_paths.len() { 0 => { #ident(); Ok(()) }, 1 => Err( format!("{}because path not found: {}", libtest_with::RUNTIME_IGNORE_PREFIX, missing_paths[0] ).into()), _ => Err( format!("{}because following paths not found: \n{}\n", libtest_with::RUNTIME_IGNORE_PREFIX, missing_paths.join(", ") ).into()), } } #(#attrs)* #vis #sig #block } .into() } /// Run test case when the http service exist. /// ``` /// #[cfg(test)] /// mod tests { /// /// // http service exists /// #[test_with::http(httpbin.org)] /// #[test] /// fn test_works() { /// assert!(true); /// } /// /// // There is no not.exist.com /// #[test_with::http(not.exist.com)] /// #[test] /// fn test_ignored() { /// panic!("should be ignored") /// } /// } /// ``` #[proc_macro_attribute] #[proc_macro_error] #[cfg(feature = "http")] pub fn http(attr: TokenStream, stream: TokenStream) -> TokenStream { if is_module(&stream) { mod_macro( attr, parse_macro_input!(stream as ItemMod), check_http_condition, ) } else { fn_macro( attr, parse_macro_input!(stream as ItemFn), check_http_condition, ) } } #[cfg(feature = "http")] fn check_http_condition(attr_str: String) -> (bool, String) { let links: Vec<&str> = attr_str.split(',').collect(); let mut missing_links = vec![]; let client = reqwest::blocking::Client::new(); for link in links.iter() { if client.head(&format!("http://{}", link)).send().is_err() { missing_links.push(format!("http://{link:}")); } } let ignore_msg = if missing_links.len() == 1 { format!("because {} not response", missing_links[0]) } else { format!( "because following links not response: \n{}\n", missing_links.join("\n") ) }; (missing_links.is_empty(), ignore_msg) } /// Run test case when the example running and the http service exist. ///```rust /// // write as example in exmaples/*rs /// test_with::runner!(http); /// #[test_with::module] /// mod http { /// #[test_with::runtime_http(httpbin.org)] /// fn test_works() { /// assert!(true); /// } /// } #[cfg(not(feature = "runtime"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_http(_attr: TokenStream, _stream: TokenStream) -> TokenStream { panic!("should be used with runtime feature") } #[cfg(all(feature = "runtime", feature = "http"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_http(attr: TokenStream, stream: TokenStream) -> TokenStream { let attr_str = attr.to_string().replace(' ', ""); let links: Vec<&str> = attr_str.split(',').collect(); let ItemFn { attrs, vis, sig, block, } = parse_macro_input!(stream as ItemFn); let syn::Signature { ident, .. } = sig.clone(); let check_ident = syn::Ident::new( &format!("_check_{}", ident.to_string()), proc_macro2::Span::call_site(), ); quote::quote! { fn #check_ident() -> Result<(), libtest_with::Failed> { let mut missing_links = vec![]; let client = libtest_with::reqwest::blocking::Client::new(); #( if client.head(&format!("http://{}", #links)).send().is_err() { missing_links.push(format!("http://{}", #links)); } )* match missing_links.len() { 0 => { #ident(); Ok(()) }, 1 => Err( format!("{}because {} not response", libtest_with::RUNTIME_IGNORE_PREFIX, missing_links[0] ).into()), _ => Err( format!("{}because following links not response: \n{}\n", libtest_with::RUNTIME_IGNORE_PREFIX, missing_links.join(", ") ).into()), } } #(#attrs)* #vis #sig #block } .into() } /// Run test case when the https service exist. /// ``` /// #[cfg(test)] /// mod tests { /// /// // https server exists /// #[test_with::https(www.rust-lang.org)] /// #[test] /// fn test_works() { /// assert!(true); /// } /// /// // There is no not.exist.com /// #[test_with::https(not.exist.com)] /// #[test] /// fn test_ignored() { /// panic!("should be ignored") /// } /// } /// ``` #[proc_macro_attribute] #[proc_macro_error] #[cfg(feature = "http")] pub fn https(attr: TokenStream, stream: TokenStream) -> TokenStream { if is_module(&stream) { mod_macro( attr, parse_macro_input!(stream as ItemMod), check_https_condition, ) } else { fn_macro( attr, parse_macro_input!(stream as ItemFn), check_https_condition, ) } } #[cfg(feature = "http")] fn check_https_condition(attr_str: String) -> (bool, String) { let links: Vec<&str> = attr_str.split(',').collect(); let mut missing_links = vec![]; let client = reqwest::blocking::Client::new(); for link in links.iter() { if client.head(&format!("https://{}", link)).send().is_err() { missing_links.push(format!("https://{link:}")); } } let ignore_msg = if missing_links.len() == 1 { format!("because {} not response", missing_links[0]) } else { format!( "because following links not response: \n{}\n", missing_links.join("\n") ) }; (missing_links.is_empty(), ignore_msg) } /// Run test case when the example running and the http service exist. ///```rust /// // write as example in exmaples/*rs /// test_with::runner!(http); /// #[test_with::module] /// mod http { /// #[test_with::runtime_https(httpbin.org)] /// fn test_works() { /// assert!(true); /// } /// } #[cfg(not(feature = "runtime"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_https(_attr: TokenStream, _stream: TokenStream) -> TokenStream { panic!("should be used with runtime feature") } #[cfg(all(feature = "runtime", feature = "http"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_https(attr: TokenStream, stream: TokenStream) -> TokenStream { let attr_str = attr.to_string().replace(' ', ""); let links: Vec<&str> = attr_str.split(',').collect(); let ItemFn { attrs, vis, sig, block, } = parse_macro_input!(stream as ItemFn); let syn::Signature { ident, .. } = sig.clone(); let check_ident = syn::Ident::new( &format!("_check_{}", ident.to_string()), proc_macro2::Span::call_site(), ); quote::quote! { fn #check_ident() -> Result<(), libtest_with::Failed> { let mut missing_links = vec![]; let client = libtest_with::reqwest::blocking::Client::new(); #( if client.head(&format!("https://{}", #links)).send().is_err() { missing_links.push(format!("https://{}", #links)); } )* match missing_links.len() { 0 => { #ident(); Ok(()) }, 1 => Err( format!("{}because {} not response", libtest_with::RUNTIME_IGNORE_PREFIX, missing_links[0] ).into()), _ => Err( format!("{}because following links not response: \n{}\n", libtest_with::RUNTIME_IGNORE_PREFIX, missing_links.join(", ") ).into()), } } #(#attrs)* #vis #sig #block } .into() } /// Run test case when the server online. /// Please make sure the role of test case runner have capability to open socket /// /// ``` /// #[cfg(test)] /// mod tests { /// /// // localhost is online /// #[test_with::icmp(127.0.0.1)] /// #[test] /// fn test_works() { /// assert!(true); /// } /// /// // 193.194.195.196 is offline /// #[test_with::icmp(193.194.195.196)] /// #[test] /// fn test_ignored() { /// panic!("should be ignored") /// } /// } /// ``` #[proc_macro_attribute] #[proc_macro_error] #[cfg(feature = "icmp")] pub fn icmp(attr: TokenStream, stream: TokenStream) -> TokenStream { if is_module(&stream) { mod_macro( attr, parse_macro_input!(stream as ItemMod), check_icmp_condition, ) } else { fn_macro( attr, parse_macro_input!(stream as ItemFn), check_icmp_condition, ) } } #[cfg(feature = "icmp")] fn check_icmp_condition(attr_str: String) -> (bool, String) { let ips: Vec<&str> = attr_str.split(',').collect(); let mut missing_ips = vec![]; for ip in ips.iter() { if let Ok(addr) = ip.parse::() { if ping::ping(addr, None, None, None, None, None).is_err() { missing_ips.push(ip.to_string()); } } else { abort_call_site!("ip address malformat") } } let ignore_msg = if missing_ips.len() == 1 { format!("because ip {} not response", missing_ips[0]) } else { format!( "because following ip not response: \n{}\n", missing_ips.join(", ") ) }; (missing_ips.is_empty(), ignore_msg) } /// Run test case when the example running and the server online. /// Please make sure the role of test case runner have capability to open socket ///```rust /// // write as example in exmaples/*rs /// test_with::runner!(icmp); /// #[test_with::module] /// mod icmp { /// // 193.194.195.196 is offline /// #[test_with::runtime_icmp(193.194.195.196)] /// fn test_ignored_with_non_existing_host() { /// panic!("should be ignored with non existing host") /// } /// } #[cfg(not(feature = "runtime"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_icmp(_attr: TokenStream, _stream: TokenStream) -> TokenStream { panic!("should be used with runtime feature") } #[cfg(all(feature = "runtime", feature = "icmp"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_icmp(attr: TokenStream, stream: TokenStream) -> TokenStream { let attr_str = attr.to_string().replace(' ', ""); let ips: Vec<&str> = attr_str.split(',').collect(); let ItemFn { attrs, vis, sig, block, } = parse_macro_input!(stream as ItemFn); let syn::Signature { ident, .. } = sig.clone(); let check_ident = syn::Ident::new( &format!("_check_{}", ident.to_string()), proc_macro2::Span::call_site(), ); quote::quote! { fn #check_ident() -> Result<(), libtest_with::Failed> { let mut missing_ips = vec![]; #( if libtest_with::ping::ping(#ips.parse().expect("ip address is invalid"), None, None, None, None, None).is_err() { missing_ips.push(#ips); } )* match missing_ips.len() { 0 => { #ident(); Ok(()) } , 1 => Err( format!("{}because {} not response", libtest_with::RUNTIME_IGNORE_PREFIX, missing_ips[0] ).into()), _ => Err( format!("{}because following ips not response: \n{}\n", libtest_with::RUNTIME_IGNORE_PREFIX, missing_ips.join(", ") ).into()), } } #(#attrs)* #vis #sig #block } .into() } /// Run test case when socket connected /// /// ``` /// #[cfg(test)] /// mod tests { /// /// // Google DNS is online /// #[test_with::tcp(8.8.8.8:53)] /// #[test] /// fn test_works() { /// assert!(true); /// } /// /// // 193.194.195.196 is offline /// #[test_with::tcp(193.194.195.196)] /// #[test] /// fn test_ignored() { /// panic!("should be ignored") /// } /// } /// ``` #[proc_macro_attribute] #[proc_macro_error] pub fn tcp(attr: TokenStream, stream: TokenStream) -> TokenStream { if is_module(&stream) { mod_macro( attr, parse_macro_input!(stream as ItemMod), check_tcp_condition, ) } else { fn_macro( attr, parse_macro_input!(stream as ItemFn), check_tcp_condition, ) } } fn check_tcp_condition(attr_str: String) -> (bool, String) { let sockets: Vec<&str> = attr_str.split(',').collect(); let mut missing_sockets = vec![]; for socket in sockets.iter() { if TcpStream::connect(socket).is_err() { missing_sockets.push(socket.to_string()); } } let ignore_msg = if missing_sockets.len() == 1 { format!("because fail to connect socket {}", missing_sockets[0]) } else { format!( "because follow sockets can not connect\n{}\n", missing_sockets.join(", ") ) }; (missing_sockets.is_empty(), ignore_msg) } /// Run test case when the example running and socket connected ///```rust /// // write as example in exmaples/*rs /// test_with::runner!(tcp); /// #[test_with::module] /// mod tcp { /// // Google DNS is online /// #[test_with::runtime_tcp(8.8.8.8:53)] /// fn test_works_with_DNS_server() { /// assert!(true); /// } /// } #[cfg(not(feature = "runtime"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_tcp(_attr: TokenStream, _stream: TokenStream) -> TokenStream { panic!("should be used with runtime feature") } #[cfg(all(feature = "runtime"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_tcp(attr: TokenStream, stream: TokenStream) -> TokenStream { let attr_str = attr.to_string().replace(' ', ""); let sockets: Vec<&str> = attr_str.split(',').collect(); let ItemFn { attrs, vis, sig, block, } = parse_macro_input!(stream as ItemFn); let syn::Signature { ident, .. } = sig.clone(); let check_ident = syn::Ident::new( &format!("_check_{}", ident.to_string()), proc_macro2::Span::call_site(), ); quote::quote! { fn #check_ident() -> Result<(), libtest_with::Failed> { let mut missing_sockets = vec![]; #( if std::net::TcpStream::connect(#sockets).is_err() { missing_sockets.push(#sockets); } )* match missing_sockets.len() { 0 => { #ident(); Ok(()) }, 1 => Err( format!("{}because {} not response", libtest_with::RUNTIME_IGNORE_PREFIX, missing_sockets[0] ).into()), _ => Err( format!("{}because following sockets not response: \n{}\n", libtest_with::RUNTIME_IGNORE_PREFIX, missing_sockets.join(", ") ).into()), } } #(#attrs)* #vis #sig #block } .into() } /// Run test case when runner is root /// /// ``` /// #[cfg(test)] /// mod tests { /// /// // Only works with root account /// #[test_with::root()] /// #[test] /// fn test_ignored() { /// panic!("should be ignored") /// } /// } /// ``` #[proc_macro_attribute] #[proc_macro_error] #[cfg(all(feature = "user", not(target_os = "windows")))] pub fn root(attr: TokenStream, stream: TokenStream) -> TokenStream { if is_module(&stream) { mod_macro( attr, parse_macro_input!(stream as ItemMod), check_root_condition, ) } else { fn_macro( attr, parse_macro_input!(stream as ItemFn), check_root_condition, ) } } #[cfg(all(feature = "user", not(target_os = "windows")))] fn check_root_condition(_attr_str: String) -> (bool, String) { let current_user_id = users::get_current_uid(); ( current_user_id == 0, "because this case should run with root".into(), ) } /// Run test case when runner is root ///```rust /// // write as example in exmaples/*rs /// test_with::runner!(user); /// #[test_with::module] /// mod user { /// // Google DNS is online /// #[test_with::runtime_root()] /// fn test_ignored() { /// panic!("should be ignored") /// } /// } #[cfg(not(feature = "runtime"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_root(_attr: TokenStream, _stream: TokenStream) -> TokenStream { panic!("should be used with runtime feature") } #[cfg(all(feature = "runtime", feature = "user", not(target_os = "windows")))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_root(_attr: TokenStream, stream: TokenStream) -> TokenStream { let ItemFn { attrs, vis, sig, block, } = parse_macro_input!(stream as ItemFn); let syn::Signature { ident, .. } = sig.clone(); let check_ident = syn::Ident::new( &format!("_check_{}", ident.to_string()), proc_macro2::Span::call_site(), ); quote::quote! { fn #check_ident() -> Result<(), libtest_with::Failed> { if 0 == libtest_with::users::get_current_uid() { #ident(); Ok(()) } else { Err(format!("{}because this case should run with root", libtest_with::RUNTIME_IGNORE_PREFIX).into()) } } #(#attrs)* #vis #sig #block } .into() } /// Run test case when runner in group /// /// ``` /// #[cfg(test)] /// mod tests { /// /// // Only works with group avengers /// #[test_with::group(avengers)] /// #[test] /// fn test_ignored() { /// panic!("should be ignored") /// } /// } /// ``` #[proc_macro_attribute] #[proc_macro_error] #[cfg(all(feature = "user", not(target_os = "windows")))] pub fn group(attr: TokenStream, stream: TokenStream) -> TokenStream { if is_module(&stream) { mod_macro( attr, parse_macro_input!(stream as ItemMod), check_group_condition, ) } else { fn_macro( attr, parse_macro_input!(stream as ItemFn), check_group_condition, ) } } #[cfg(feature = "user")] #[cfg(all(feature = "user", not(target_os = "windows")))] fn check_group_condition(group_name: String) -> (bool, String) { let current_user_id = users::get_current_uid(); let in_group = match users::get_user_by_uid(current_user_id) { Some(user) => { let mut in_group = false; for group in user.groups().expect("user not found") { if in_group { break; } in_group |= group.name().to_string_lossy() == group_name; } in_group } None => false, }; ( in_group, format!("because this case should run user in group {}", group_name), ) } /// Run test case when runner in group ///```rust /// // write as example in exmaples/*rs /// test_with::runner!(user); /// #[test_with::module] /// mod user { /// // Only works with group avengers /// #[test_with::runtime_group(avengers)] /// fn test_ignored() { /// panic!("should be ignored") /// } /// } #[cfg(not(feature = "runtime"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_group(_attr: TokenStream, _stream: TokenStream) -> TokenStream { panic!("should be used with runtime feature") } #[cfg(all(feature = "runtime", feature = "user", not(target_os = "windows")))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_group(attr: TokenStream, stream: TokenStream) -> TokenStream { let group_name = attr.to_string().replace(' ', ""); let ItemFn { attrs, vis, sig, block, } = parse_macro_input!(stream as ItemFn); let syn::Signature { ident, .. } = sig.clone(); let check_ident = syn::Ident::new( &format!("_check_{}", ident.to_string()), proc_macro2::Span::call_site(), ); quote::quote! { fn #check_ident() -> Result<(), libtest_with::Failed> { let current_user_id = libtest_with::users::get_current_uid(); let in_group = match libtest_with::users::get_user_by_uid(current_user_id) { Some(user) => { let mut in_group = false; for group in user.groups().expect("user not found") { if in_group { break; } in_group |= group.name().to_string_lossy() == #group_name; } in_group } None => false, }; if in_group { #ident(); Ok(()) } else { Err(format!("{}because this case should run user in group {}", libtest_with::RUNTIME_IGNORE_PREFIX, #group_name).into()) } } #(#attrs)* #vis #sig #block } .into() } /// Run test case when runner is specific user /// /// ``` /// #[cfg(test)] /// mod tests { /// /// // Only works with user /// #[test_with::user(spider)] /// #[test] /// fn test_ignored() { /// panic!("should be ignored") /// } /// } /// ``` #[proc_macro_attribute] #[proc_macro_error] #[cfg(all(feature = "user", not(target_os = "windows")))] pub fn user(attr: TokenStream, stream: TokenStream) -> TokenStream { if is_module(&stream) { mod_macro( attr, parse_macro_input!(stream as ItemMod), check_user_condition, ) } else { fn_macro( attr, parse_macro_input!(stream as ItemFn), check_user_condition, ) } } #[cfg(feature = "user")] #[cfg(all(feature = "user", not(target_os = "windows")))] fn check_user_condition(user_name: String) -> (bool, String) { let is_user = match users::get_current_username() { Some(uname) => uname.to_string_lossy() == user_name, None => false, }; ( is_user, format!("because this case should run with user {}", user_name), ) } /// Run test case when runner is specific user ///```rust /// // write as example in exmaples/*rs /// test_with::runner!(user); /// #[test_with::module] /// mod user { /// // Only works with user /// #[test_with::runtime_user(spider)] /// fn test_ignored() { /// panic!("should be ignored") /// } /// } #[cfg(not(feature = "runtime"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_user(_attr: TokenStream, _stream: TokenStream) -> TokenStream { panic!("should be used with runtime feature") } #[cfg(all(feature = "runtime", feature = "user", not(target_os = "windows")))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_user(attr: TokenStream, stream: TokenStream) -> TokenStream { let user_name = attr.to_string().replace(' ', ""); let ItemFn { attrs, vis, sig, block, } = parse_macro_input!(stream as ItemFn); let syn::Signature { ident, .. } = sig.clone(); let check_ident = syn::Ident::new( &format!("_check_{}", ident.to_string()), proc_macro2::Span::call_site(), ); quote::quote! { fn #check_ident() -> Result<(), libtest_with::Failed> { let is_user = match libtest_with::users::get_current_username() { Some(uname) => uname.to_string_lossy() == #user_name, None => false, }; if is_user { #ident(); Ok(()) } else { Err(format!("{}because this case should run with user {}", libtest_with::RUNTIME_IGNORE_PREFIX, #user_name).into()) } } #(#attrs)* #vis #sig #block } .into() } /// Run test case when memory size enough /// /// ``` /// #[cfg(test)] /// mod tests { /// /// // Only works with enough memory size /// #[test_with::mem(100GB)] /// #[test] /// fn test_ignored() { /// panic!("should be ignored") /// } /// } /// ``` #[proc_macro_attribute] #[proc_macro_error] #[cfg(feature = "resource")] pub fn mem(attr: TokenStream, stream: TokenStream) -> TokenStream { if is_module(&stream) { mod_macro( attr, parse_macro_input!(stream as ItemMod), check_mem_condition, ) } else { fn_macro( attr, parse_macro_input!(stream as ItemFn), check_mem_condition, ) } } #[cfg(feature = "resource")] fn check_mem_condition(mem_size_str: String) -> (bool, String) { let sys = sysinfo::System::new_with_specifics( sysinfo::RefreshKind::new().with_memory(sysinfo::MemoryRefreshKind::new().with_swap()), ); let mem_size = match byte_unit::Byte::parse_str(format!("{} B", sys.total_memory()), false) { Ok(b) => b, Err(_) => abort_call_site!("memory size description is not correct"), }; let mem_size_limitation = match byte_unit::Byte::parse_str(&mem_size_str, true) { Ok(b) => b, Err(_) => abort_call_site!("system memory size can not get"), }; ( mem_size >= mem_size_limitation, format!("because the memory less than {}", mem_size_str), ) } /// Run test case when the example running and memory size enough ///```rust /// // write as example in exmaples/*rs /// test_with::runner!(resource); /// #[test_with::module] /// mod resource { /// // Only works with enough memory size /// #[test_with::runtime_mem(100GB)] /// fn test_ignored_mem_not_enough() { /// panic!("should be ignored") /// } /// } #[cfg(not(feature = "runtime"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_mem(_attr: TokenStream, _stream: TokenStream) -> TokenStream { panic!("should be used with runtime feature") } #[cfg(all(feature = "runtime", feature = "resource"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_mem(attr: TokenStream, stream: TokenStream) -> TokenStream { let mem_limitation_str = attr.to_string().replace(' ', ""); if byte_unit::Byte::parse_str(&mem_limitation_str, true).is_err() { abort_call_site!("memory size description is not correct") } let ItemFn { attrs, vis, sig, block, } = parse_macro_input!(stream as ItemFn); let syn::Signature { ident, .. } = sig.clone(); let check_ident = syn::Ident::new( &format!("_check_{}", ident.to_string()), proc_macro2::Span::call_site(), ); quote::quote! { fn #check_ident() -> Result<(), libtest_with::Failed> { let sys = libtest_with::sysinfo::System::new_with_specifics( libtest_with::sysinfo::RefreshKind::new().with_memory(libtest_with::sysinfo::MemoryRefreshKind::new().with_ram()), ); let mem_size = match libtest_with::byte_unit::Byte::parse_str(format!("{} B", sys.total_memory()), false) { Ok(b) => b, Err(_) => panic!("system memory size can not get"), }; let mem_size_limitation = libtest_with::byte_unit::Byte::parse_str(#mem_limitation_str, true).expect("mem limitation should correct"); if mem_size >= mem_size_limitation { #ident(); Ok(()) } else { Err(format!("{}because the memory less than {}", libtest_with::RUNTIME_IGNORE_PREFIX, #mem_limitation_str).into()) } } #(#attrs)* #vis #sig #block } .into() } /// Run test case when the example running and free memory size enough ///```rust /// // write as example in exmaples/*rs /// test_with::runner!(resource); /// #[test_with::module] /// mod resource { /// // Only works with enough free memory size /// #[test_with::runtime_free_mem(100GB)] /// fn test_ignored_free_mem_not_enough() { /// panic!("should be ignored") /// } /// } #[cfg(not(feature = "runtime"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_free_mem(_attr: TokenStream, _stream: TokenStream) -> TokenStream { panic!("should be used with runtime feature") } #[cfg(all(feature = "runtime", feature = "resource"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_free_mem(attr: TokenStream, stream: TokenStream) -> TokenStream { let mem_limitation_str = attr.to_string().replace(' ', ""); if byte_unit::Byte::parse_str(&mem_limitation_str, true).is_err() { abort_call_site!("memory size description is not correct") } let ItemFn { attrs, vis, sig, block, } = parse_macro_input!(stream as ItemFn); let syn::Signature { ident, .. } = sig.clone(); let check_ident = syn::Ident::new( &format!("_check_{}", ident.to_string()), proc_macro2::Span::call_site(), ); quote::quote! { fn #check_ident() -> Result<(), libtest_with::Failed> { let sys = libtest_with::sysinfo::System::new_with_specifics( libtest_with::sysinfo::RefreshKind::new().with_memory(libtest_with::sysinfo::MemoryRefreshKind::new().with_ram()), ); let mem_size = match libtest_with::byte_unit::Byte::parse_str(format!("{} B", sys.free_memory()), false) { Ok(b) => b, Err(_) => panic!("system memory size can not get"), }; let mem_size_limitation = libtest_with::byte_unit::Byte::parse_str(#mem_limitation_str, true).expect("mem limitation should correct"); if mem_size >= mem_size_limitation { #ident(); Ok(()) } else { Err(format!("{}because the memory less than {}", libtest_with::RUNTIME_IGNORE_PREFIX, #mem_limitation_str).into()) } } #(#attrs)* #vis #sig #block } .into() } /// Run test case when the example running and available memory size enough ///```rust /// // write as example in exmaples/*rs /// test_with::runner!(resource); /// #[test_with::module] /// mod resource { /// // Only works with enough available memory size /// #[test_with::runtime_available_mem(100GB)] /// fn test_ignored_available_mem_not_enough() { /// panic!("should be ignored") /// } /// } #[cfg(not(feature = "runtime"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_available_mem(_attr: TokenStream, _stream: TokenStream) -> TokenStream { panic!("should be used with runtime feature") } #[cfg(all(feature = "runtime", feature = "resource"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_available_mem(attr: TokenStream, stream: TokenStream) -> TokenStream { let mem_limitation_str = attr.to_string().replace(' ', ""); if byte_unit::Byte::parse_str(&mem_limitation_str, true).is_err() { abort_call_site!("memory size description is not correct") } let ItemFn { attrs, vis, sig, block, } = parse_macro_input!(stream as ItemFn); let syn::Signature { ident, .. } = sig.clone(); let check_ident = syn::Ident::new( &format!("_check_{}", ident.to_string()), proc_macro2::Span::call_site(), ); quote::quote! { fn #check_ident() -> Result<(), libtest_with::Failed> { let sys = libtest_with::sysinfo::System::new_with_specifics( libtest_with::sysinfo::RefreshKind::new().with_memory(libtest_with::sysinfo::MemoryRefreshKind::new().with_ram()), ); let mem_size = match libtest_with::byte_unit::Byte::parse_str(format!("{} B", sys.available_memory()), false) { Ok(b) => b, Err(_) => panic!("system memory size can not get"), }; let mem_size_limitation = libtest_with::byte_unit::Byte::parse_str(#mem_limitation_str, true).expect("mem limitation should correct"); if mem_size >= mem_size_limitation { #ident(); Ok(()) } else { Err(format!("{}because the memory less than {}", libtest_with::RUNTIME_IGNORE_PREFIX, #mem_limitation_str).into()) } } #(#attrs)* #vis #sig #block } .into() } /// Run test case when swap size enough /// /// ``` /// #[cfg(test)] /// mod tests { /// /// // Only works with enough swap size /// #[test_with::swap(100GB)] /// #[test] /// fn test_ignored() { /// panic!("should be ignored") /// } /// } /// ``` #[proc_macro_attribute] #[proc_macro_error] #[cfg(feature = "resource")] pub fn swap(attr: TokenStream, stream: TokenStream) -> TokenStream { if is_module(&stream) { mod_macro( attr, parse_macro_input!(stream as ItemMod), check_swap_condition, ) } else { fn_macro( attr, parse_macro_input!(stream as ItemFn), check_swap_condition, ) } } #[cfg(feature = "resource")] fn check_swap_condition(swap_size_str: String) -> (bool, String) { let sys = sysinfo::System::new_with_specifics( sysinfo::RefreshKind::new().with_memory(sysinfo::MemoryRefreshKind::new().with_swap()), ); let swap_size = match byte_unit::Byte::parse_str(format!("{} B", sys.total_swap()), false) { Ok(b) => b, Err(_) => abort_call_site!("Swap size description is not correct"), }; let swap_size_limitation = match byte_unit::Byte::parse_str(&swap_size_str, true) { Ok(b) => b, Err(_) => abort_call_site!("Can not get system swap size"), }; ( swap_size >= swap_size_limitation, format!("because the swap less than {}", swap_size_str), ) } /// Run test case when the example running and swap enough ///```rust /// // write as example in exmaples/*rs /// test_with::runner!(resource); /// #[test_with::module] /// mod resource { /// // Only works with enough swap size /// #[test_with::runtime_swap(100GB)] /// fn test_ignored_swap_not_enough() { /// panic!("should be ignored") /// } /// } #[cfg(not(feature = "runtime"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_swap(_attr: TokenStream, _stream: TokenStream) -> TokenStream { panic!("should be used with runtime feature") } #[cfg(all(feature = "runtime", feature = "resource"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_swap(attr: TokenStream, stream: TokenStream) -> TokenStream { let swap_limitation_str = attr.to_string().replace(' ', ""); if byte_unit::Byte::parse_str(&swap_limitation_str, true).is_err() { abort_call_site!("swap size description is not correct") } let ItemFn { attrs, vis, sig, block, } = parse_macro_input!(stream as ItemFn); let syn::Signature { ident, .. } = sig.clone(); let check_ident = syn::Ident::new( &format!("_check_{}", ident.to_string()), proc_macro2::Span::call_site(), ); quote::quote! { fn #check_ident() -> Result<(), libtest_with::Failed> { let sys = libtest_with::sysinfo::System::new_with_specifics( libtest_with::sysinfo::RefreshKind::new().with_memory(libtest_with::sysinfo::MemoryRefreshKind::new().with_swap()), ); let swap_size = match libtest_with::byte_unit::Byte::parse_str(format!("{} B", sys.total_swap()), false) { Ok(b) => b, Err(_) => panic!("system swap size can not get"), }; let swap_size_limitation = libtest_with::byte_unit::Byte::parse_str(#swap_limitation_str, true).expect("swap limitation should correct"); if swap_size >= swap_size_limitation { #ident(); Ok(()) } else { Err(format!("{}because the swap less than {}", libtest_with::RUNTIME_IGNORE_PREFIX, #swap_limitation_str).into()) } } #(#attrs)* #vis #sig #block } .into() } /// Run test case when the example running and free swap enough ///```rust /// // write as example in exmaples/*rs /// test_with::runner!(resource); /// #[test_with::module] /// mod resource { /// // Only works with enough free swap size /// #[test_with::runtime_free_swap(100GB)] /// fn test_ignored_free_swap_not_enough() { /// panic!("should be ignored") /// } /// } #[cfg(not(feature = "runtime"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_free_swap(_attr: TokenStream, _stream: TokenStream) -> TokenStream { panic!("should be used with runtime feature") } #[cfg(all(feature = "runtime", feature = "resource"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_free_swap(attr: TokenStream, stream: TokenStream) -> TokenStream { let swap_limitation_str = attr.to_string().replace(' ', ""); if byte_unit::Byte::parse_str(&swap_limitation_str, true).is_err() { abort_call_site!("swap size description is not correct") } let ItemFn { attrs, vis, sig, block, } = parse_macro_input!(stream as ItemFn); let syn::Signature { ident, .. } = sig.clone(); let check_ident = syn::Ident::new( &format!("_check_{}", ident.to_string()), proc_macro2::Span::call_site(), ); quote::quote! { fn #check_ident() -> Result<(), libtest_with::Failed> { let sys = libtest_with::sysinfo::System::new_with_specifics( libtest_with::sysinfo::RefreshKind::new().with_memory(libtest_with::sysinfo::MemoryRefreshKind::new().with_swap()), ); let swap_size = match libtest_with::byte_unit::Byte::parse_str(format!("{} B", sys.free_swap()), false) { Ok(b) => b, Err(_) => panic!("system swap size can not get"), }; let swap_size_limitation = libtest_with::byte_unit::Byte::parse_str(#swap_limitation_str, true).expect("swap limitation should correct"); if swap_size >= swap_size_limitation { #ident(); Ok(()) } else { Err(format!("{}because the swap less than {}", libtest_with::RUNTIME_IGNORE_PREFIX, #swap_limitation_str).into()) } } #(#attrs)* #vis #sig #block } .into() } /// Run test case when cpu core enough /// /// ``` /// #[cfg(test)] /// mod tests { /// /// // Only works with enough cpu core /// #[test_with::cpu_core(32)] /// #[test] /// fn test_ignored() { /// panic!("should be ignored") /// } /// } /// ``` #[proc_macro_attribute] #[proc_macro_error] #[cfg(feature = "resource")] pub fn cpu_core(attr: TokenStream, stream: TokenStream) -> TokenStream { if is_module(&stream) { mod_macro( attr, parse_macro_input!(stream as ItemMod), check_cpu_core_condition, ) } else { fn_macro( attr, parse_macro_input!(stream as ItemFn), check_cpu_core_condition, ) } } #[cfg(feature = "resource")] fn check_cpu_core_condition(core_limitation_str: String) -> (bool, String) { ( match core_limitation_str.parse::() { Ok(c) => num_cpus::get() >= c, Err(_) => abort_call_site!("core limitation is incorrect"), }, format!("because the cpu core less than {}", core_limitation_str), ) } /// Run test case when cpu core enough ///```rust /// // write as example in exmaples/*rs /// test_with::runner!(resource); /// #[test_with::module] /// mod resource { /// // Only works with enough cpu core /// #[test_with::runtime_cpu_core(32)] /// fn test_ignored_core_not_enough() { /// panic!("should be ignored") /// } /// } #[cfg(not(feature = "runtime"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_cpu_core(_attr: TokenStream, _stream: TokenStream) -> TokenStream { panic!("should be used with runtime feature") } #[cfg(all(feature = "runtime", feature = "resource"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_cpu_core(attr: TokenStream, stream: TokenStream) -> TokenStream { let attr_str = attr.to_string().replace(' ', ""); let core_limitation = match attr_str.parse::() { Ok(c) => c, Err(_) => abort_call_site!("core limitation is incorrect"), }; let ItemFn { attrs, vis, sig, block, } = parse_macro_input!(stream as ItemFn); let syn::Signature { ident, .. } = sig.clone(); let check_ident = syn::Ident::new( &format!("_check_{}", ident.to_string()), proc_macro2::Span::call_site(), ); quote::quote! { fn #check_ident() -> Result<(), libtest_with::Failed> { if libtest_with::num_cpus::get() >= #core_limitation { #ident(); Ok(()) } else { Err(format!("{}because the cpu core less than {}", libtest_with::RUNTIME_IGNORE_PREFIX, #core_limitation).into()) } } #(#attrs)* #vis #sig #block } .into() } /// Run test case when physical cpu core enough /// /// ``` /// #[cfg(test)] /// mod tests { /// /// // Only works with enough cpu core /// #[test_with::phy_core(32)] /// #[test] /// fn test_ignored() { /// panic!("should be ignored") /// } /// } /// ``` #[proc_macro_attribute] #[proc_macro_error] #[cfg(feature = "resource")] pub fn phy_core(attr: TokenStream, stream: TokenStream) -> TokenStream { if is_module(&stream) { mod_macro( attr, parse_macro_input!(stream as ItemMod), check_cpu_core_condition, ) } else { fn_macro( attr, parse_macro_input!(stream as ItemFn), check_phy_core_condition, ) } } #[cfg(feature = "resource")] fn check_phy_core_condition(core_limitation_str: String) -> (bool, String) { ( match core_limitation_str.parse::() { Ok(c) => num_cpus::get_physical() >= c, Err(_) => abort_call_site!("physical core limitation is incorrect"), }, format!( "because the physical cpu core less than {}", core_limitation_str ), ) } /// Run test case when physical core enough ///```rust /// // write as example in exmaples/*rs /// test_with::runner!(resource); /// #[test_with::module] /// mod resource { /// // Only works with enough physical cpu core /// #[test_with::runtime_phy_cpu_core(32)] /// fn test_ignored_phy_core_not_enough() { /// panic!("should be ignored") /// } /// } #[cfg(not(feature = "runtime"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_phy_cpu_core(_attr: TokenStream, _stream: TokenStream) -> TokenStream { panic!("should be used with runtime feature") } #[cfg(all(feature = "runtime", feature = "resource"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_phy_cpu_core(attr: TokenStream, stream: TokenStream) -> TokenStream { let attr_str = attr.to_string().replace(' ', ""); let core_limitation = match attr_str.parse::() { Ok(c) => c, Err(_) => abort_call_site!("physical core limitation is incorrect"), }; let ItemFn { attrs, vis, sig, block, } = parse_macro_input!(stream as ItemFn); let syn::Signature { ident, .. } = sig.clone(); let check_ident = syn::Ident::new( &format!("_check_{}", ident.to_string()), proc_macro2::Span::call_site(), ); quote::quote! { fn #check_ident() -> Result<(), libtest_with::Failed> { if libtest_with::num_cpus::get_physical() >= #core_limitation { #ident(); Ok(()) } else { Err(format!("{}because the physical cpu core less than {}", libtest_with::RUNTIME_IGNORE_PREFIX, #core_limitation).into()) } } #(#attrs)* #vis #sig #block } .into() } /// Run test case when the executables exist. /// ``` /// #[cfg(test)] /// mod tests { /// // `pwd` executable command exists /// #[test_with::executable(pwd)] /// #[test] /// fn test_executable() { /// assert!(true); /// } /// /// // `/bin/sh` executable exists /// #[test_with::executable(/bin/sh)] /// #[test] /// fn test_executable_with_path() { /// assert!(true); /// } /// /// // `non` does not exist /// #[test_with::executable(non)] /// #[test] /// fn test_non_existing_executable() { /// panic!("should be ignored") /// } /// /// // `pwd` and `ls` exist /// #[test_with::executable(pwd, ls)] /// #[test] /// fn test_executables_too() { /// assert!(true); /// } /// } /// ``` #[proc_macro_attribute] #[proc_macro_error] #[cfg(feature = "executable")] pub fn executable(attr: TokenStream, stream: TokenStream) -> TokenStream { if is_module(&stream) { mod_macro( attr, parse_macro_input!(stream as ItemMod), check_executable_condition, ) } else { fn_macro( attr, parse_macro_input!(stream as ItemFn), check_executable_condition, ) } } #[cfg(feature = "executable")] fn check_executable_condition(attr_str: String) -> (bool, String) { let executables: Vec<&str> = attr_str.split(',').collect(); let mut missing_executables = vec![]; for exe in executables.iter() { if which(exe.trim_matches('"')).is_err() { missing_executables.push(exe.to_string()); } } let ignore_msg = if missing_executables.len() == 1 { format!("because executable not found: {}", missing_executables[0]) } else { format!( "because following executables not found: \n{}\n", missing_executables.join("\n") ) }; (missing_executables.is_empty(), ignore_msg) } /// Run test case when the executable existing ///```rust /// // write as example in exmaples/*rs /// test_with::runner!(exe); /// #[test_with::module] /// mod exe { /// // `/bin/sh` executable exists /// #[test_with::runtime_executable(/bin/sh)] /// fn test_executable_with_path() { /// assert!(true); /// } /// } #[cfg(not(feature = "runtime"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_executable(_attr: TokenStream, _stream: TokenStream) -> TokenStream { panic!("should be used with runtime feature") } #[cfg(all(feature = "runtime", feature = "executable"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_executable(attr: TokenStream, stream: TokenStream) -> TokenStream { let attr_str = attr.to_string().replace(' ', ""); let executables: Vec<&str> = attr_str.split(',').collect(); let ItemFn { attrs, vis, sig, block, } = parse_macro_input!(stream as ItemFn); let syn::Signature { ident, .. } = sig.clone(); let check_ident = syn::Ident::new( &format!("_check_{}", ident.to_string()), proc_macro2::Span::call_site(), ); quote::quote! { fn #check_ident() -> Result<(), libtest_with::Failed> { let mut missing_executables = vec![]; #( if libtest_with::which::which(#executables).is_err() { missing_executables.push(#executables); } )* match missing_executables.len() { 0 => { #ident(); Ok(()) }, 1 => Err( format!("{}because executable {} not found", libtest_with::RUNTIME_IGNORE_PREFIX, missing_executables[0] ).into()), _ => Err( format!("{}because following executables not found:\n{}\n", libtest_with::RUNTIME_IGNORE_PREFIX, missing_executables.join(", ") ).into()), } } #(#attrs)* #vis #sig #block } .into() } /// Provide a test runner and test on each module ///```rust /// // example/run-test.rs /// /// test_with::runner!(module1, module2); /// #[test_with::module] /// mod module1 { /// #[test_with::runtime_env(PWD)] /// fn test_works() { /// assert!(true); /// } /// } /// /// #[test_with::module] /// mod module2 { /// #[test_with::runtime_env(PWD)] /// fn test_works() { /// assert!(true); /// } /// } ///``` #[cfg(not(feature = "runtime"))] #[proc_macro] pub fn runner(_input: TokenStream) -> TokenStream { panic!("should be used with runtime feature") } #[cfg(feature = "runtime")] #[proc_macro] pub fn runner(input: TokenStream) -> TokenStream { let input_str = input.to_string(); let mod_names: Vec = input_str .split(",") .map(|s| syn::Ident::new(s.trim(), proc_macro2::Span::call_site())) .collect(); quote::quote! { fn main() { let args = libtest_with::Arguments::from_args(); let mut no_env_tests = Vec::new(); #( match #mod_names::_runtime_tests() { (Some(env), tests) => { libtest_with::run(&args, tests).exit_if_failed(); drop(env); }, (None, mut tests) => no_env_tests.append(&mut tests), } )* libtest_with::run(&args, no_env_tests).exit(); } } .into() } /// Help each function with `#[test_with::runtime_*]` in the module can register to run /// Also you can set up a mock instance for all of the test in the module /// /// ```rust /// // example/run-test.rs /// /// test_with::runner!(module1, module2); /// #[test_with::module] /// mod module1 { /// #[test_with::runtime_env(PWD)] /// fn test_works() { /// assert!(true); /// } /// } /// /// #[test_with::module] /// mod module2 { /// #[test_with::runtime_env(PWD)] /// fn test_works() { /// assert!(true); /// } /// } /// ``` /// You can set up mock with a public struct named `TestEnv` inside the module, or a public type /// named `TestEnv` inside the module. And the type or struct should have a Default trait for /// initialize the mock instance. /// ```rust /// use std::ops::Drop; /// use std::process::{Child, Command}; /// /// test_with::runner!(net); /// /// #[test_with::module] /// mod net { /// pub struct TestEnv { /// p: Child, /// } /// /// impl Default for TestEnv { /// fn default() -> TestEnv { /// let p = Command::new("python") /// .args(["-m", "http.server"]) /// .spawn() /// .expect("failed to execute child"); /// let mut count = 0; /// while count < 3 { /// if libtest_with::reqwest::blocking::get("http://127.0.0.1:8000").is_ok() { /// break; /// } /// std::thread::sleep(std::time::Duration::from_secs(1)); /// count += 1; /// } /// TestEnv { p } /// } /// } /// /// impl Drop for TestEnv { /// fn drop(&mut self) { /// self.p.kill().expect("fail to kill python http.server"); /// } /// } /// /// #[test_with::runtime_http(127.0.0.1:8000)] /// fn test_with_environment() { /// assert!(true); /// } /// } /// /// ``` /// or you can write mock struct in other place and just pass by type. /// ```rust /// use std::ops::Drop; /// use std::process::{Child, Command}; /// /// test_with::runner!(net); /// /// pub struct Moc { /// p: Child, /// } /// /// impl Default for Moc { /// fn default() -> Moc { /// let p = Command::new("python") /// .args(["-m", "http.server"]) /// .spawn() /// .expect("failed to execute child"); /// let mut count = 0; /// while count < 3 { /// if libtest_with::reqwest::blocking::get("http://127.0.0.1:8000").is_ok() { /// break; /// } /// std::thread::sleep(std::time::Duration::from_secs(1)); /// count += 1; /// } /// Moc { p } /// } /// } /// /// impl Drop for Moc { /// fn drop(&mut self) { /// self.p.kill().expect("fail to kill python http.server"); /// } /// } /// /// #[test_with::module] /// mod net { /// pub type TestEnv = super::Moc; /// /// #[test_with::runtime_http(127.0.0.1:8000)] /// fn test_with_environment() { /// assert!(true); /// } /// } /// ``` #[cfg(not(feature = "runtime"))] #[proc_macro_attribute] #[proc_macro_error] pub fn module(_attr: TokenStream, _stream: TokenStream) -> TokenStream { panic!("should be used with runtime feature") } #[cfg(feature = "runtime")] #[proc_macro_attribute] #[proc_macro_error] pub fn module(_attr: TokenStream, stream: TokenStream) -> TokenStream { let ItemMod { attrs, vis, mod_token, ident, content, .. } = parse_macro_input!(stream as ItemMod); if let Some(content) = content { let content = content.1; if crate::utils::has_test_cfg(&attrs) { abort_call_site!("should not use `#[cfg(test)]` on the mod with `#[test_with::module]`") } else { let mut test_env_type = None; let test_names: Vec = content .iter() .filter_map(|c| match c { Item::Fn(ItemFn { sig: syn::Signature { ident, .. }, attrs, .. }) => match crate::utils::test_with_attrs(&attrs) { (true, true, _) => abort_call_site!( "should not use #[test] for method in `#[test_with::module]`" ), (_, true, false) => abort_call_site!( "use `#[test_with::runtime_*]` for method in `#[test_with::module]`" ), (false, true, true) => Some(ident.to_string()), _ => None, }, Item::Struct(ItemStruct { ident, vis, .. }) | Item::Type(ItemType { ident, vis, .. }) => { if ident.to_string() == "TestEnv" { match vis { syn::Visibility::Public(_) => test_env_type = Some(ident), _ => abort_call_site!("TestEnv should be pub for testing"), } } None } _ => None, }) .collect(); let check_names: Vec = test_names .iter() .map(|c| { syn::Ident::new( &format!("_check_{}", c.to_string()), proc_macro2::Span::call_site(), ) }) .collect(); if let Some(test_env_type) = test_env_type { quote::quote! { #(#attrs)* #vis #mod_token #ident { use super::*; pub fn _runtime_tests() -> (Option<#test_env_type>, Vec) { use libtest_with::Trial; ( Some(#test_env_type::default()), vec![ #(Trial::test(#test_names, #check_names),)* ] ) } #(#content)* } } .into() } else { quote::quote! { #(#attrs)* #vis #mod_token #ident { use super::*; pub fn _runtime_tests() -> (Option<()>, Vec) { use libtest_with::Trial; ( None, vec![ #(Trial::test(#test_names, #check_names),)* ] ) } #(#content)* } } .into() } } } else { abort_call_site!("should use on mod with context") } } /// Ignore test case when function return some reason /// The function should be `fn() -> Option` /// ``` /// test_with::runner!(custom_mod); /// /// fn something_happened() -> Option { /// Some("because something happened".to_string()) /// } /// /// #[test_with::module] /// mod custom_mod { /// #[test_with::runtime_ignore_if(something_happened)] /// fn test_ignored() { /// assert!(false); /// } /// } /// ``` #[cfg(not(feature = "runtime"))] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_ignore_if(_attr: TokenStream, _stream: TokenStream) -> TokenStream { panic!("should be used with runtime feature") } #[cfg(feature = "runtime")] #[proc_macro_attribute] #[proc_macro_error] pub fn runtime_ignore_if(attr: TokenStream, stream: TokenStream) -> TokenStream { let ignore_function = syn::Ident::new( &attr.to_string().replace(' ', ""), proc_macro2::Span::call_site(), ); let ItemFn { attrs, vis, sig, block, } = parse_macro_input!(stream as ItemFn); let syn::Signature { ident, .. } = sig.clone(); let check_ident = syn::Ident::new( &format!("_check_{}", ident.to_string()), proc_macro2::Span::call_site(), ); quote::quote! { fn #check_ident() -> Result<(), libtest_with::Failed> { if let Some(msg) = #ignore_function() { Err(format!("{}{msg}", libtest_with::RUNTIME_IGNORE_PREFIX).into()) } else { #ident(); Ok(()) } } #(#attrs)* #vis #sig #block } .into() } test-with-0.12.2/src/utils.rs000064400000000000000000000165431046102023000141440ustar 00000000000000use regex::Regex; use proc_macro::TokenStream; #[cfg(feature = "ign-msg")] use proc_macro2::Span; use proc_macro2::TokenTree; use proc_macro_error::abort_call_site; use quote::quote; #[cfg(feature = "ign-msg")] use syn::Signature; use syn::{Attribute, Meta}; use syn::{Ident, Item, ItemFn, ItemMod}; // check for `#[test]`, `#[tokio::test]`, `#[async_std::test]` pub(crate) fn has_test_attr(attrs: &[Attribute]) -> bool { for attr in attrs.iter() { if let Some(seg) = attr.path().segments.last() { if seg.ident == "test" { return true; } } } false } // check // first for `#[test]`, `#[tokio::test]`, `#[async_std::test]` // second for `#[test_with::*]` // third for runtime mod `#[test_with::runtime_*]` #[cfg(feature = "runtime")] pub(crate) fn test_with_attrs(attrs: &[Attribute]) -> (bool, bool, bool) { let mut has_test = false; let mut has_test_with = false; let mut has_rt_test_with = false; for attr in attrs.iter() { if let Some(seg) = attr.path().segments.last() { if seg.ident == "test" { has_test = true; } } if let (Some(first_seg), Some(last_seg)) = (attr.path().segments.first(), attr.path().segments.last()) { if first_seg.ident == "test_with" { has_test_with = true; } if last_seg.ident.to_string().starts_with("runtime_") { has_rt_test_with = true; } } } (has_test, has_test_with, has_rt_test_with) } // check the attribute order for `#[serial]` pub(crate) fn check_before_attrs(attrs: &[Attribute]) { for attr in attrs.iter() { if let Some(seg) = attr.path().segments.last() { if seg.ident == "serial" { abort_call_site!("`#[test_with::*]` should place after `#[serial]`"); } } } } // check for `#[cfg(test)]` pub(crate) fn has_test_cfg(attrs: &[Attribute]) -> bool { for attr in attrs.iter() { if let Meta::List(metalist) = &attr.meta { for token in metalist.tokens.clone().into_iter() { if let TokenTree::Group(group) = token { for tt in group.stream().into_iter() { if "test" == tt.to_string() { return true; } } } } } } false } #[cfg(feature = "ign-msg")] pub(crate) fn rewrite_fn_sig_with_msg(sig: &mut Signature, msg: &String) { let re = unsafe { Regex::new(r"[^\w]").unwrap_unchecked() }; let new_fn_name = Ident::new( &format!("{}__{}", sig.ident, re.replace_all(msg, "_")), Span::call_site(), ); sig.ident = new_fn_name; } #[cfg(feature = "ign-msg")] pub(crate) fn rewrite_fn_ident_with_msg(ident: Ident, msg: &String) -> Ident { let re = unsafe { Regex::new(r"[^\w]").unwrap_unchecked() }; Ident::new( &format!("{}__{}", ident.to_string(), re.replace_all(msg, "_")), Span::call_site(), ) } pub(crate) fn is_module(context: &TokenStream) -> bool { let re = unsafe { Regex::new("(?:pub mod |mod )").unwrap_unchecked() }; re.is_match(&context.to_string()) } pub(crate) fn fn_macro( attr: TokenStream, input: ItemFn, check_condition: fn(String) -> (bool, String), ) -> TokenStream { #[cfg(feature = "ign-msg")] let ItemFn { attrs, vis, mut sig, block, } = input; #[cfg(not(feature = "ign-msg"))] let ItemFn { attrs, vis, sig, block, } = input; let attr_str = attr.to_string().replace(' ', ""); let (all_var_exist, ignore_msg) = check_condition(attr_str); check_before_attrs(&attrs); let has_test = has_test_attr(&attrs); if all_var_exist && has_test { quote! { #(#attrs)* #vis #sig #block } .into() } else if all_var_exist { quote! { #(#attrs)* #[test] #vis #sig #block } .into() } else if has_test { #[cfg(feature = "ign-msg")] rewrite_fn_sig_with_msg(&mut sig, &ignore_msg); quote! { #(#attrs)* #[ignore = #ignore_msg ] #vis #sig #block } .into() } else { #[cfg(feature = "ign-msg")] rewrite_fn_sig_with_msg(&mut sig, &ignore_msg); quote! { #(#attrs)* #[test] #[ignore = #ignore_msg ] #vis #sig #block } .into() } } pub(crate) fn mod_macro( attr: TokenStream, input: ItemMod, check_condition: fn(String) -> (bool, String), ) -> TokenStream { let ItemMod { attrs, vis, mod_token, ident, content, .. } = input; if let Some(content) = content { let content = content.1; let attr_str = attr.to_string().replace(' ', ""); let (all_var_exist, ignore_msg) = check_condition(attr_str); let has_test = has_test_cfg(&attrs); if all_var_exist && has_test { quote! { #(#attrs)* #[cfg(test)] #vis #mod_token #ident { #(#content)* } } .into() } else if all_var_exist { quote! { #(#attrs)* #[cfg(test)] #vis #mod_token #ident { #(#content)* } } .into() } else if has_test { let fn_names: Vec = content .into_iter() .filter_map(|i| match i { Item::Fn(ItemFn { sig, .. }) => { #[cfg(not(feature = "ign-msg"))] let ident = sig.ident; #[cfg(feature = "ign-msg")] let ident = rewrite_fn_ident_with_msg(sig.ident, &ignore_msg); Some(ident) } _ => None, }) .collect(); quote! { #(#attrs)* #vis #mod_token #ident { #( #[test] #[ignore = #ignore_msg ] fn #fn_names () {} )* } } .into() } else { let fn_names: Vec = content .into_iter() .filter_map(|i| match i { Item::Fn(ItemFn { sig, .. }) => { #[cfg(not(feature = "ign-msg"))] let ident = sig.ident; #[cfg(feature = "ign-msg")] let ident = rewrite_fn_ident_with_msg(sig.ident, &ignore_msg); Some(ident) } _ => None, }) .collect(); quote! { #(#attrs)* #[cfg(test)] #vis #mod_token #ident { #( #[test] #[ignore = #ignore_msg ] fn #fn_names () {} )* } } .into() } } else { abort_call_site!("should use on mod with context") } }