diff --git a/Cargo.lock b/Cargo.lock index 6f0da27c9..44d699510 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,6 +52,12 @@ version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + [[package]] name = "assert_cmd" version = "2.0.8" @@ -156,6 +162,15 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitmaps" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" +dependencies = [ + "typenum", +] + [[package]] name = "block-buffer" version = "0.9.0" @@ -238,6 +253,107 @@ dependencies = [ "syn", ] +[[package]] +name = "bytesize" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c58ec36aac5066d5ca17df51b3e70279f5670a72102f5752cb7e7c856adfc70" + +[[package]] +name = "cargo" +version = "0.68.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df5e8070173cd407a849cb3d231542f6781fe09cf52ae1c58fbb4d3ae01cf24d" +dependencies = [ + "anyhow", + "base64 0.13.1", + "bytesize", + "cargo-platform", + "cargo-util", + "clap 4.1.6", + "crates-io", + "curl", + "curl-sys", + "env_logger", + "filetime", + "flate2", + "fwdansi", + "git2", + "git2-curl", + "glob", + "hex 0.4.3", + "hmac 0.12.1", + "home", + "http-auth", + "humantime", + "ignore", + "im-rc", + "indexmap", + "is-terminal", + "itertools", + "jobserver", + "lazy_static", + "lazycell", + "libc", + "libgit2-sys", + "log", + "memchr", + "opener", + "os_info", + "pathdiff", + "percent-encoding", + "rustc-workspace-hack", + "rustfix", + "semver", + "serde", + "serde-value", + "serde_ignored", + "serde_json", + "sha1", + "shell-escape", + "strip-ansi-escapes", + "tar", + "tempfile", + "termcolor", + "toml_edit", + "unicode-width", + "unicode-xid", + "url", + "walkdir", + "winapi", +] + +[[package]] +name = "cargo-platform" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-util" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e0cd00582e110eb8d99de768521d36fce9e24a286babf3cea68824ae09948f" +dependencies = [ + "anyhow", + "core-foundation", + "crypto-hash", + "filetime", + "hex 0.4.3", + "jobserver", + "libc", + "log", + "miow", + "same-file", + "shell-escape", + "tempfile", + "walkdir", + "winapi", +] + [[package]] name = "cc" version = "1.0.78" @@ -278,7 +394,7 @@ dependencies = [ "atty", "bitflags", "clap_derive", - "clap_lex", + "clap_lex 0.2.4", "indexmap", "once_cell", "strsim", @@ -286,13 +402,26 @@ dependencies = [ "textwrap", ] +[[package]] +name = "clap" +version = "4.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0b0588d44d4d63a87dbd75c136c166bbfd9a86a31cb89e09906521c7d3f5e3" +dependencies = [ + "bitflags", + "clap_lex 0.3.1", + "is-terminal", + "strsim", + "termcolor", +] + [[package]] name = "clap_complete" version = "3.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f7a2e0a962c45ce25afce14220bc24f9dade0a1787f185cecf96bfba7847cd8" dependencies = [ - "clap", + "clap 3.2.23", ] [[package]] @@ -317,6 +446,15 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "clap_lex" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "codespan-reporting" version = "0.11.1" @@ -327,6 +465,34 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "combine" +version = "4.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "commoncrypto" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007" +dependencies = [ + "commoncrypto-sys", +] + +[[package]] +name = "commoncrypto-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2" +dependencies = [ + "libc", +] + [[package]] name = "config" version = "0.13.2" @@ -382,6 +548,29 @@ dependencies = [ "serde_json", ] +[[package]] +name = "crates-io" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "848493b0d668efbe713dcddcde49f1e5d4b6d542337262660c198336db47977e" +dependencies = [ + "anyhow", + "curl", + "percent-encoding", + "serde", + "serde_json", + "url", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -392,6 +581,18 @@ dependencies = [ "typenum", ] +[[package]] +name = "crypto-hash" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a77162240fd97248d19a564a565eb563a3f592b386e4136fb300909e67dddca" +dependencies = [ + "commoncrypto", + "hex 0.3.2", + "openssl", + "winapi", +] + [[package]] name = "crypto-mac" version = "0.9.1" @@ -424,6 +625,37 @@ dependencies = [ "memchr", ] +[[package]] +name = "curl" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22" +dependencies = [ + "curl-sys", + "libc", + "openssl-probe", + "openssl-sys", + "schannel", + "socket2", + "winapi", +] + +[[package]] +name = "curl-sys" +version = "0.4.59+curl-7.86.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cfce34829f448b08f55b7db6d0009e23e2e86a34e8c2b366269bf5799b4a407" +dependencies = [ + "cc", + "libc", + "libnghttp2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", + "winapi", +] + [[package]] name = "curve25519-dalek" version = "3.2.0" @@ -615,6 +847,40 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "errno" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1" +dependencies = [ + "errno-dragonfly", + "libc", + "winapi", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "fastrand" version = "1.8.0" @@ -624,6 +890,29 @@ dependencies = [ "instant", ] +[[package]] +name = "filetime" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "windows-sys 0.45.0", +] + +[[package]] +name = "flate2" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +dependencies = [ + "crc32fast", + "libz-sys", + "miniz_oxide", +] + [[package]] name = "float-cmp" version = "0.9.0" @@ -639,6 +928,21 @@ 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.1.0" @@ -648,6 +952,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "futures-channel" version = "0.3.25" @@ -690,6 +1000,16 @@ dependencies = [ "slab", ] +[[package]] +name = "fwdansi" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c1f5787fe85505d1f7777268db5103d80a7a374d2316a7ce262e57baf8f208" +dependencies = [ + "memchr", + "termcolor", +] + [[package]] name = "generic-array" version = "0.14.6" @@ -728,6 +1048,39 @@ version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dec7af912d60cdbd3677c1af9352ebae6fb8394d165568a2234df0fa00f87793" +[[package]] +name = "git2" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf7f68c2995f392c49fffb4f95ae2c873297830eb25c6bc4c114ce8f4562acc" +dependencies = [ + "bitflags", + "libc", + "libgit2-sys", + "log", + "openssl-probe", + "openssl-sys", + "url", +] + +[[package]] +name = "git2-curl" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7577f4e6341ba7c90d883511130a45b956c274ba5f4d205d9f9da990f654cd33" +dependencies = [ + "curl", + "git2", + "log", + "url", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + [[package]] name = "globset" version = "0.4.10" @@ -829,6 +1182,18 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "hex" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" + [[package]] name = "hex" version = "0.4.3" @@ -857,6 +1222,15 @@ dependencies = [ "digest 0.10.6", ] +[[package]] +name = "home" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "747309b4b440c06d57b0b25f2aee03ee9b5e5397d288c60e21fc709bb98a7408" +dependencies = [ + "winapi", +] + [[package]] name = "http" version = "0.2.8" @@ -868,6 +1242,15 @@ dependencies = [ "itoa 1.0.5", ] +[[package]] +name = "http-auth" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5430cacd7a1f9a02fbeb350dfc81a0e5ed42d81f3398cb0ba184017f85bdcfbc" +dependencies = [ + "memchr", +] + [[package]] name = "http-body" version = "0.4.5" @@ -891,6 +1274,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + [[package]] name = "hyper" version = "0.14.23" @@ -988,6 +1377,20 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "im-rc" +version = "15.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1955a75fa080c677d3972822ec4bad316169ab1cfc6c257a942c2265dbe5fe" +dependencies = [ + "bitmaps", + "rand_core 0.6.4", + "rand_xoshiro", + "sized-chunks", + "typenum", + "version_check", +] + [[package]] name = "indexmap" version = "1.9.2" @@ -1014,6 +1417,28 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "io-lifetimes" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1abeb7a0dd0f8181267ff8adc397075586500b81b28a73e8a0208b00fc170fb3" +dependencies = [ + "libc", + "windows-sys 0.45.0", +] + +[[package]] +name = "is-terminal" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0a45d56fe973d6db23972bf5bc46f988a4a2385deac9cc29572f09daef" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys 0.45.0", +] + [[package]] name = "itertools" version = "0.10.5" @@ -1117,24 +1542,89 @@ dependencies = [ "tracing", ] +[[package]] +name = "kstring" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3066350882a1cd6d950d055997f379ac37fd39f81cd4d8ed186032eb3c5747" +dependencies = [ + "static_assertions", +] + [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + [[package]] name = "libc" version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +[[package]] +name = "libgit2-sys" +version = "0.14.2+1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f3d95f6b51075fe9810a7ae22c7095f12b98005ab364d8544797a825ce946a4" +dependencies = [ + "cc", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", +] + [[package]] name = "libm" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" +[[package]] +name = "libnghttp2-sys" +version = "0.1.7+1.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ed28aba195b38d5ff02b9170cbff627e336a20925e43b4945390401c5dc93f" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "libssh2-sys" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b094a36eb4b8b8c8a7b4b8ae43b2944502be3e59cd87687595cf6b0a71b3f4ca" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libz-sys" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "link-cplusplus" version = "1.0.8" @@ -1150,6 +1640,12 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + [[package]] name = "lock_api" version = "0.4.9" @@ -1221,7 +1717,16 @@ dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.42.0", +] + +[[package]] +name = "miow" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ffbca2f655e33c08be35d87278e5b18b89550a37dbd598c20db92f6a471123" +dependencies = [ + "windows-sys 0.42.0", ] [[package]] @@ -1342,12 +1847,70 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "opener" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "293c15678e37254c15bd2f092314abb4e51d7fdde05c2021279c12631b54f005" +dependencies = [ + "bstr 1.1.0", + "winapi", +] + +[[package]] +name = "openssl" +version = "0.10.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[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.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "ordered-float" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" +dependencies = [ + "num-traits", +] + [[package]] name = "ordered-multimap" version = "0.4.3" @@ -1358,6 +1921,17 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "os_info" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c424bc68d15e0778838ac013b5b3449544d8133633d8016319e7e05a820b8c0" +dependencies = [ + "log", + "serde", + "winapi", +] + [[package]] name = "os_str_bytes" version = "6.4.1" @@ -1384,7 +1958,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -1484,6 +2058,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1658,6 +2238,15 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rand_xoshiro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core 0.6.4", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -1779,6 +2368,38 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-workspace-hack" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" + +[[package]] +name = "rustfix" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd2853d9e26988467753bd9912c3a126f642d05d229a4b53f5752ee36c56481" +dependencies = [ + "anyhow", + "log", + "serde", + "serde_json", +] + +[[package]] +name = "rustix" +version = "0.36.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.45.0", +] + [[package]] name = "rustls" version = "0.20.8" @@ -1854,7 +2475,7 @@ version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" dependencies = [ - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -1908,6 +2529,15 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" +dependencies = [ + "serde", +] + [[package]] name = "sep5" version = "0.0.2" @@ -1940,6 +2570,16 @@ dependencies = [ "serde_json", ] +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + [[package]] name = "serde_derive" version = "1.0.152" @@ -1951,6 +2591,15 @@ dependencies = [ "syn", ] +[[package]] +name = "serde_ignored" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94eb4a4087ba8bdf14a9208ac44fddbf55c01a6195f7edfc511ddaff6cae45a6" +dependencies = [ + "serde", +] + [[package]] name = "serde_json" version = "1.0.91" @@ -1982,7 +2631,7 @@ checksum = "30d904179146de381af4c93d3af6ca4984b3152db687dacb9c3c35e86f39809c" dependencies = [ "base64 0.13.1", "chrono", - "hex", + "hex 0.4.3", "indexmap", "serde", "serde_json", @@ -2048,6 +2697,12 @@ dependencies = [ "digest 0.10.6", ] +[[package]] +name = "shell-escape" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" + [[package]] name = "signal-hook-registry" version = "1.4.0" @@ -2063,6 +2718,16 @@ version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +[[package]] +name = "sized-chunks" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +dependencies = [ + "bitmaps", + "typenum", +] + [[package]] name = "slab" version = "0.4.7" @@ -2107,14 +2772,14 @@ dependencies = [ "assert_fs", "base64 0.13.1", "chrono", - "clap", + "clap 3.2.23", "clap_complete", "config", "crate-git-revision", "csv", "dirs", "ed25519-dalek", - "hex", + "hex 0.4.3", "itertools", "jsonrpsee-core", "jsonrpsee-http-client", @@ -2133,6 +2798,7 @@ dependencies = [ "soroban-ledger-snapshot", "soroban-sdk", "soroban-spec", + "soroban-test", "soroban-token-spec", "stellar-strkey", "termcolor", @@ -2179,7 +2845,7 @@ dependencies = [ "curve25519-dalek", "dyn-fmt", "ed25519-dalek", - "hex", + "hex 0.4.3", "log", "num-derive", "num-integer", @@ -2287,6 +2953,26 @@ dependencies = [ "wasmparser 0.88.0", ] +[[package]] +name = "soroban-test" +version = "0.6.0" +dependencies = [ + "assert_cmd", + "assert_fs", + "cargo", + "fs_extra", + "predicates", + "sep5", + "sha2 0.10.6", + "soroban-env-host", + "soroban-ledger-snapshot", + "soroban-sdk", + "soroban-spec", + "soroban-token-spec", + "stellar-strkey", + "thiserror", +] + [[package]] name = "soroban-token-spec" version = "0.6.0" @@ -2356,11 +3042,20 @@ checksum = "940dc58ca70e647b0b2517461beb3476fbffa5dc78d10f5c53645da8503c765c" dependencies = [ "base64 0.13.1", "crate-git-revision", - "hex", + "hex 0.4.3", "serde", "serde_with", ] +[[package]] +name = "strip-ansi-escapes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "011cbb39cf7c1f62871aea3cc46e5817b0937b49e9447370c93cacbe93a766d8" +dependencies = [ + "vte", +] + [[package]] name = "strsim" version = "0.10.0" @@ -2415,6 +3110,16 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "tar" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" +dependencies = [ + "filetime", + "libc", +] + [[package]] name = "tempfile" version = "3.3.0" @@ -2598,7 +3303,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.42.0", ] [[package]] @@ -2669,6 +3374,29 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1541ba70885967e662f69d31ab3aeca7b1aaecfcd58679590b893e9239c3646" +dependencies = [ + "combine", + "indexmap", + "itertools", + "kstring", + "serde", + "toml_datetime", +] + [[package]] name = "tower-service" version = "0.3.2" @@ -2829,12 +3557,45 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf8parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" + +[[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 = "vte" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983" +dependencies = [ + "arrayvec", + "utf8parse", + "vte_generate_state_changes", +] + +[[package]] +name = "vte_generate_state_changes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "wait-timeout" version = "0.2.0" @@ -3111,6 +3872,30 @@ dependencies = [ "windows_x86_64_msvc", ] +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.42.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.42.1" diff --git a/Cargo.toml b/Cargo.toml index 7e7fb21e7..56486485c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ resolver = "2" members = [ "cmd/soroban-cli", + "cmd/crates/*", "cmd/soroban-cli/tests/fixtures/test-wasms/*", "cmd/soroban-rpc/lib/preflight", ] diff --git a/cmd/crates/soroban-test/Cargo.toml b/cmd/crates/soroban-test/Cargo.toml new file mode 100644 index 000000000..551aa6c9e --- /dev/null +++ b/cmd/crates/soroban-test/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "soroban-test" +description = "Soroban Test Framework" +homepage = "https://github.com/stellar/soroban-test" +repository = "https://github.com/stellar/soroban-test" +authors = ["Stellar Development Foundation "] +license = "Apache-2.0" +readme = "README.md" +version = "0.6.0" +edition = "2021" +rust-version = "1.67" +autobins = false + + +[lib] +crate-type = ["rlib", "cdylib"] + + +[dependencies] +soroban-env-host = { workspace = true, features = ["vm", "serde", "hostfn_log_fmt_values"] } +soroban-spec = { workspace = true } +soroban-token-spec = { workspace = true } +soroban-ledger-snapshot = { workspace = true } +stellar-strkey = { workspace = true } +soroban-sdk = { workspace = true } +thiserror = "1.0.31" +sep5 = { workspace = true} +sha2 = "0.10.6" +cargo = "0.68.0" +assert_cmd = "2.0.4" +assert_fs = "1.0.7" +predicates = "2.1.5" +fs_extra = "1.3.0" \ No newline at end of file diff --git a/cmd/crates/soroban-test/src/lib.rs b/cmd/crates/soroban-test/src/lib.rs new file mode 100644 index 000000000..4dbc435f5 --- /dev/null +++ b/cmd/crates/soroban-test/src/lib.rs @@ -0,0 +1,222 @@ +use std::{ffi::OsString, fmt::Display, path::Path}; + +use assert_cmd::{assert::Assert, Command}; +use assert_fs::{fixture::FixtureError, prelude::PathChild, TempDir}; +use fs_extra::dir::CopyOptions; +pub use wasm::Wasm; + +mod wasm; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("Failed to create temporary directory")] + TempDir(FixtureError), + + #[error(transparent)] + FsError(#[from] fs_extra::error::Error), +} + +/// The primary interface to your tests. Creates an isolated process with its own temporary directory, storing all config and output there. +/// +/// # Example: +/// +/// use soroban_test::{TestEnv, Wasm}; +/// const WASM: &Wasm = &Wasm::Release("my_contract"); +/// +/// #[test] +/// fn invoke_and_read() { +/// TestEnv::with_default(|e| { +/// e.new_cmd("contract") +/// .arg("invoke") +/// .arg("--wasm") +/// .arg(&WASM.path()) +/// .args(["--fn", "some_fn"]) +/// .assert() +/// .stderr(""); +/// }); +/// } +pub struct TestEnv { + pub temp_dir: TempDir, +} + +impl Default for TestEnv { + fn default() -> Self { + Self::new().unwrap() + } +} + +impl TestEnv { + /// Initialize a TestEnv with default settings. Takes a closure to execute within this TestEnv. + /// + /// For now, this is the primary interface to create and use a TestEnv. In the future, TestEnv may provide an alternate, more customizable method of initialization. + /// + /// # Example + /// + /// In a test function: + /// + /// TestEnv::with_default(|e| { + /// println!("{:#?}", e.new_cmd("version").ok()); + /// }); + pub fn with_default(f: F) { + let test_env = TestEnv::default(); + f(&test_env) + } + + /// Initialize a TestEnv with default settings and return a Result with this TestEnv or an error. You probably want `with_default` instead, which makes use of `new` internally. + pub fn new() -> Result { + TempDir::new() + .map_err(Error::TempDir) + .map(|temp_dir| TestEnv { temp_dir }) + } + + /// Start building a new `soroban` command, skipping the repetitive `soroban` starting word and setting the current directory to the one for this TestEnv. + /// + /// # Example + /// + /// TestEnv::with_default(|e| { + /// println!("{:#?}", e.new_cmd("version").ok()); + /// }); + /// + /// Note that you don't need `e.new_cmd("soroban").arg("version")`. + pub fn new_cmd(&self, name: &str) -> Command { + let mut this = Command::cargo_bin("soroban").unwrap_or_else(|_| Command::new("soroban")); + this.arg(name); + this.current_dir(&self.temp_dir); + this + } + + /// Get the location of the temporary directory created by this TestEnv. + pub fn dir(&self) -> &TempDir { + &self.temp_dir + } + + /// Generate new identity for testing. Names the identity `test`. Uses a hard-coded all-zero seed. + pub fn gen_test_identity(&self) { + self.new_cmd("config") + .arg("identity") + .arg("generate") + .arg("--seed") + .arg("0000000000000000") + .arg("test") + .assert() + .success(); + } + + /// Return a public key of the identity named `test`, which needs to first be created with `gen_test_identity`. The `test` identity is stored as a seed, which can be used to generate multiple public keys. The specific key generated depends on the `hd_path` supplied. Specifying the same `hd_path` will always generate the same key. + /// + /// The phrase "HD path" comes from the larger world of crypto wallets: https://www.ledger.com/academy/crypto/what-are-hierarchical-deterministic-hd-wallets + pub fn test_address(&self, hd_path: usize) -> String { + self.new_cmd("config") + .args("identity address test --hd-path".split(' ')) + .arg(format!("{hd_path}")) + .assert() + .stdout_as_str() + } + + /// Fork TestEnv, return a Result with the new TestEnv or an error. Might be useful to create multiple tests that use the same setup. + pub fn fork(&self) -> Result { + let this = TestEnv::new()?; + self.save(&this.temp_dir)?; + Ok(this) + } + + /// Save the current state of the TestEnv to the given directory. + pub fn save(&self, dst: &Path) -> Result<(), Error> { + fs_extra::dir::copy(&self.temp_dir, dst, &CopyOptions::new())?; + Ok(()) + } +} + +pub fn temp_ledger_file() -> OsString { + TempDir::new() + .unwrap() + .child("ledger.json") + .as_os_str() + .into() +} + +/// Import this trait into your file to extend `assert_cmd` with extra utility functions. +/// +/// `assert_cmd` is the CLI command builder powering soroban_test. +/// +/// You don't need to do anything else with `AssertExt` other than import it; it magically extends the command builder with `stdout_as_str` and other helpers. +/// +/// # Example: +/// +/// use soroban_test::{AssertExt, TestEnv, Wasm}; +/// +/// const WASM: &Wasm = &Wasm::Release("my_contract"); +/// +/// #[test] +/// fn invoke() { +/// TestEnv::with_default(|e| { +/// let stdout = e +/// .new_cmd("contract") +/// .arg("install") +/// .arg("--wasm") +/// .arg(&WASM.path()) +/// .assert() +/// .stdout_as_str(); +/// println!("{stdout}"); +/// } +/// } +/// +/// Note that you need the `.assert()`, which is where `assert_cmd` executes the command and returns a struct to make assertions on. +pub trait AssertExt { + /// If the command emits to STDOUT, this will return its output as a `&str`, with leading and trailing whitespace trimmed. + fn stdout_as_str(&self) -> String; + + /// If the command emits to STDERR, this will return its output as a `&str`, with leading and trailing whitespace trimmed. + fn stderr_as_str(&self) -> String; +} + +impl AssertExt for Assert { + fn stdout_as_str(&self) -> String { + String::from_utf8(self.get_output().stdout.clone()) + .expect("failed to make str") + .trim() + .to_owned() + } + fn stderr_as_str(&self) -> String { + String::from_utf8(self.get_output().stderr.clone()) + .expect("failed to make str") + .trim() + .to_owned() + } +} + +/// Import this trait into your file to extend `assert_cmd` with extra utility functions. +/// +/// `assert_cmd` is the CLI command builder powering soroban_test. +/// +/// You don't need to do anything else with `CommandExt` other than import it; it magically extends the command builder with `json_arg` and other helpers. +/// +/// # Example: +/// +/// use serde_json::json; +/// use soroban_test::{AssertExt, TestEnv}; +/// +/// #[test] +/// fn invoke() { +/// TestEnv::with_default(|e| { +/// e.new_cmd("contract") +/// .arg("invoke") +/// .args(["--id", "0"]) +/// .json_arg(json!({"ease": true, "pain": false})); +/// } +/// } +pub trait CommandExt { + /// Pass json (constructed with the serde_json::json macro or similar) as a segment to your command. + fn json_arg(&mut self, j: A) -> &mut Self + where + A: Display; +} + +impl CommandExt for Command { + fn json_arg(&mut self, j: A) -> &mut Self + where + A: Display, + { + self.arg(OsString::from(j.to_string())) + } +} diff --git a/cmd/crates/soroban-test/src/wasm.rs b/cmd/crates/soroban-test/src/wasm.rs new file mode 100644 index 000000000..db7024c70 --- /dev/null +++ b/cmd/crates/soroban-test/src/wasm.rs @@ -0,0 +1,80 @@ +use std::{fs, path::PathBuf}; + +use sha2::{Digest, Sha256}; +use soroban_env_host::xdr::{self, InstallContractCodeArgs, WriteXdr}; + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error(transparent)] + Xdr(#[from] xdr::Error), +} + +/// Easily include a built Wasm artifact from your project's `target` folder +/// +/// # Example +/// +/// If your workspace includes a member with name "my-contract" (that is, with `name = "my-contract"` in its Cargo.toml), or if this is the name of your root project, then in your test you can use: +/// +/// use soroban_test::{TestEnv, Wasm}; +/// const WASM: &Wasm = &Wasm::Release("my_contract"); +/// +/// #[test] +/// fn invoke_and_read() { +/// TestEnv::with_default(|e| { +/// let output = e.new_cmd("contract") +/// .arg("invoke") +/// .arg("--wasm") +/// .arg(&WASM.path()) +/// .ok(); +/// }) +/// } +pub enum Wasm<'a> { + /// Takes a filename. Look inside `target/wasm32-unknown-unknown/release` for a Wasm file with the given name. + Release(&'a str), + + /// Takes a `profile` and a filename. Look inside `target/wasm32-unknown-unknown/{profile}` for a given Wasm file with the given name. + /// + /// # Example + /// + /// const WASM: &Wasm = &Wasm::Custom("debug", "my_contract"); + Custom(&'a str, &'a str), +} + +fn find_target_dir() -> Option { + let path = std::env::current_dir().unwrap(); + for parent in path.ancestors().skip(1) { + let path = parent.join("target"); + if path.is_dir() { + return Some(path); + } + } + None +} + +impl Wasm<'_> { + /// The file path to the specified Wasm file + pub fn path(&self) -> PathBuf { + let path = find_target_dir().unwrap().join("wasm32-unknown-unknown"); + let mut path = match self { + Wasm::Release(name) => path.join("release").join(name), + Wasm::Custom(profile, name) => path.join(profile).join(name), + }; + path.set_extension("wasm"); + assert!(path.is_file(), "File not found: {}. run 'make build-test-wasms' to generate .wasm files before running this test", path.display()); + std::env::current_dir().unwrap().join(path) + } + + /// The bytes of the specified Wasm file + pub fn bytes(&self) -> Vec { + fs::read(self.path()).unwrap() + } + + /// The derived hash of the specified Wasm file which will be used to refer to a contract "installed" in the Soroban blockchain (that is, to contract bytes that have been uploaded, and which zero or more contract instances may refer to for their behavior). + pub fn hash(&self) -> Result { + let args_xdr = InstallContractCodeArgs { + code: self.bytes().try_into()?, + } + .to_xdr()?; + Ok(xdr::Hash(Sha256::digest(args_xdr).into())) + } +} diff --git a/cmd/soroban-cli/Cargo.toml b/cmd/soroban-cli/Cargo.toml index 9449cb58a..b76dbe0ae 100644 --- a/cmd/soroban-cli/Cargo.toml +++ b/cmd/soroban-cli/Cargo.toml @@ -61,3 +61,4 @@ crate-git-revision = "0.0.4" assert_cmd = "2.0.4" assert_fs = "1.0.7" predicates = "2.1.5" +soroban-test = { path = "../crates/soroban-test"} diff --git a/cmd/soroban-cli/tests/it/config.rs b/cmd/soroban-cli/tests/it/config.rs index 5429ef0ca..a42deba5a 100644 --- a/cmd/soroban-cli/tests/it/config.rs +++ b/cmd/soroban-cli/tests/it/config.rs @@ -1,14 +1,14 @@ use assert_cmd::Command; -use crate::util::{ - add_identity, add_test_id, temp_dir, temp_ledger_file, Sandbox, SecretKind, - DEFAULT_SEED_PHRASE, HELLO_WORLD, -}; +use assert_fs::TempDir; +use soroban_test::{temp_ledger_file, TestEnv}; use std::{fs, path::Path}; +use crate::util::{add_identity, add_test_id, SecretKind, DEFAULT_SEED_PHRASE, HELLO_WORLD}; + #[test] fn set_and_remove_network() { - let sandbox = Sandbox::new(); + let sandbox = TestEnv::default(); sandbox .new_cmd("config") .arg("network") @@ -50,7 +50,7 @@ fn set_and_remove_network() { .stdout("\n"); } -fn add_network(sandbox: &Sandbox, name: &str) -> Command { +fn add_network(sandbox: &TestEnv, name: &str) -> Command { let mut cmd = sandbox.new_cmd("config"); cmd.arg("network") .arg("add") @@ -62,7 +62,7 @@ fn add_network(sandbox: &Sandbox, name: &str) -> Command { cmd } -fn add_network_global(sandbox: &Sandbox, dir: &Path, name: &str) { +fn add_network_global(sandbox: &TestEnv, dir: &Path, name: &str) { sandbox .new_cmd("config") .env("XDG_CONFIG_HOME", dir.to_str().unwrap()) @@ -80,8 +80,8 @@ fn add_network_global(sandbox: &Sandbox, dir: &Path, name: &str) { #[test] fn set_and_remove_global_network() { - let sandbox = Sandbox::new(); - let dir = temp_dir(); + let sandbox = TestEnv::default(); + let dir = TempDir::new().unwrap(); add_network_global(&sandbox, &dir, "global"); @@ -115,7 +115,7 @@ fn set_and_remove_global_network() { #[test] fn mulitple_networks() { - let sandbox = Sandbox::new(); + let sandbox = TestEnv::default(); add_network(&sandbox, "local").assert().success(); add_network(&sandbox, "local2").assert().success(); @@ -157,7 +157,7 @@ fn mulitple_networks() { #[test] fn read_identity() { - let sandbox = Sandbox::new(); + let sandbox = TestEnv::default(); add_test_id(&sandbox.temp_dir); sandbox .new_cmd("config") @@ -169,7 +169,7 @@ fn read_identity() { #[test] fn generate_identity() { - let sandbox = Sandbox::new(); + let sandbox = TestEnv::default(); sandbox.gen_test_identity(); sandbox @@ -188,7 +188,7 @@ fn generate_identity() { #[test] fn seed_phrase() { - let sandbox = Sandbox::new(); + let sandbox = TestEnv::default(); let dir = sandbox.dir(); add_identity( dir, @@ -208,7 +208,7 @@ fn seed_phrase() { #[test] fn use_different_ledger_file() { - let sandbox = Sandbox::new(); + let sandbox = TestEnv::default(); sandbox .new_cmd("contract") .arg("invoke") @@ -228,14 +228,14 @@ fn use_different_ledger_file() { #[test] fn read_address() { - let sandbox = Sandbox::new(); + let sandbox = TestEnv::default(); sandbox.gen_test_identity(); for hd_path in 0..2 { test_hd_path(&sandbox, hd_path); } } -fn test_hd_path(sandbox: &Sandbox, hd_path: usize) { +fn test_hd_path(sandbox: &TestEnv, hd_path: usize) { let seed_phrase = sep5::SeedPhrase::from_seed_phrase(DEFAULT_SEED_PHRASE).unwrap(); let key_pair = seed_phrase.from_path_index(hd_path, None).unwrap(); let pub_key = key_pair.public().to_string(); diff --git a/cmd/soroban-cli/tests/it/custom_types.rs b/cmd/soroban-cli/tests/it/custom_types.rs index 838ca3815..20c0cfd4c 100644 --- a/cmd/soroban-cli/tests/it/custom_types.rs +++ b/cmd/soroban-cli/tests/it/custom_types.rs @@ -1,10 +1,12 @@ use serde_json::json; -use crate::util::{invoke, invoke_with_roundtrip, Sandbox}; +use soroban_test::TestEnv; + +use crate::util::{invoke, invoke_with_roundtrip}; #[test] fn symbol() { - invoke(&Sandbox::new(), "hello") + invoke(&TestEnv::default(), "hello") .arg("--hello") .arg("world") .assert() @@ -22,7 +24,7 @@ fn symbol_with_quotes() { #[test] fn generate_help() { - invoke(&Sandbox::new(), "test") + invoke(&TestEnv::default(), "test") .arg("--help") .assert() .success(); @@ -30,7 +32,7 @@ fn generate_help() { #[test] fn multi_arg() { - invoke(&Sandbox::new(), "multi_args") + invoke(&TestEnv::default(), "multi_args") .arg("--b") .assert() .success() @@ -39,7 +41,7 @@ fn multi_arg() { #[test] fn multi_arg_success() { - invoke(&Sandbox::new(), "multi_args") + invoke(&TestEnv::default(), "multi_args") .arg("--a") .arg("42") .arg("--b") @@ -55,7 +57,7 @@ fn map() { #[test] fn map_help() { - invoke(&Sandbox::new(), "map") + invoke(&TestEnv::default(), "map") .arg("--help") .assert() .success() @@ -64,13 +66,12 @@ fn map_help() { #[test] fn set() { - // invoke(&Sandbox::new(), "set").assert().stdout("[42]\n"); invoke_with_roundtrip("set", json!([0, 1])); } #[test] fn set_help() { - invoke(&Sandbox::new(), "set") + invoke(&TestEnv::default(), "set") .arg("--help") .assert() .success() @@ -84,7 +85,7 @@ fn vec_() { #[test] fn vec_help() { - invoke(&Sandbox::new(), "vec") + invoke(&TestEnv::default(), "vec") .arg("--help") .assert() .success() @@ -98,7 +99,7 @@ fn tuple() { #[test] fn tuple_help() { - invoke(&Sandbox::new(), "tuple") + invoke(&TestEnv::default(), "tuple") .arg("--help") .assert() .success() @@ -148,7 +149,7 @@ fn i32() { #[test] fn handle_arg_larger_than_i32() { - invoke(&Sandbox::new(), "i32_") + invoke(&TestEnv::default(), "i32_") .arg("--i32_") .arg(u32::MAX.to_string()) .assert() @@ -158,7 +159,7 @@ fn handle_arg_larger_than_i32() { #[test] fn handle_arg_larger_than_i64() { - invoke(&Sandbox::new(), "i64_") + invoke(&TestEnv::default(), "i64_") .arg("--i64_") .arg(u64::MAX.to_string()) .assert() @@ -210,7 +211,7 @@ fn const_enum() { #[test] fn parse_u128() { let num = "340000000000000000000000000000000000000"; - invoke(&Sandbox::new(), "u128") + invoke(&TestEnv::default(), "u128") .arg("--u128") .arg(num) .assert() @@ -224,7 +225,7 @@ fn parse_u128() { #[test] fn parse_i128() { let num = "170000000000000000000000000000000000000"; - invoke(&Sandbox::new(), "i128") + invoke(&TestEnv::default(), "i128") .arg("--i128") .arg(num) .assert() @@ -238,7 +239,7 @@ fn parse_i128() { #[test] fn parse_negative_i128() { let num = "-170000000000000000000000000000000000000"; - invoke(&Sandbox::new(), "i128") + invoke(&TestEnv::default(), "i128") .arg("--i128") .arg(num) .assert() @@ -251,7 +252,7 @@ fn parse_negative_i128() { #[test] fn boolean() { - invoke(&Sandbox::new(), "boolean") + invoke(&TestEnv::default(), "boolean") .arg("--boolean") .assert() .success() @@ -262,7 +263,7 @@ fn boolean() { } #[test] fn boolean_no_flag() { - invoke(&Sandbox::new(), "boolean") + invoke(&TestEnv::default(), "boolean") .assert() .success() .stdout( @@ -273,7 +274,7 @@ fn boolean_no_flag() { #[test] fn boolean_not() { - invoke(&Sandbox::new(), "not") + invoke(&TestEnv::default(), "not") .arg("--boolean") .assert() .success() @@ -285,8 +286,11 @@ fn boolean_not() { #[test] fn boolean_not_no_flag() { - invoke(&Sandbox::new(), "not").assert().success().stdout( - r#"true + invoke(&TestEnv::default(), "not") + .assert() + .success() + .stdout( + r#"true "#, - ); + ); } diff --git a/cmd/soroban-cli/tests/it/invoke_sandbox.rs b/cmd/soroban-cli/tests/it/invoke_sandbox.rs index 2924816db..39bef1f1d 100644 --- a/cmd/soroban-cli/tests/it/invoke_sandbox.rs +++ b/cmd/soroban-cli/tests/it/invoke_sandbox.rs @@ -1,9 +1,11 @@ -use crate::util::{add_test_seed, Sandbox, HELLO_WORLD}; +use soroban_test::TestEnv; + +use crate::util::{add_test_seed, HELLO_WORLD}; #[test] fn install_wasm_then_deploy_contract() { - let hash = HELLO_WORLD.hash(); - let sandbox = Sandbox::new(); + let hash = HELLO_WORLD.hash().unwrap(); + let sandbox = TestEnv::default(); sandbox .new_cmd("contract") .arg("install") @@ -26,7 +28,7 @@ fn install_wasm_then_deploy_contract() { #[test] fn deploy_contract_with_wasm_file() { - Sandbox::new() + TestEnv::default() .new_cmd("contract") .arg("deploy") .arg("--wasm") @@ -39,7 +41,7 @@ fn deploy_contract_with_wasm_file() { #[test] fn invoke_hello_world_with_deploy_first() { - let sandbox = Sandbox::new(); + let sandbox = TestEnv::default(); let res = sandbox .new_cmd("contract") .arg("deploy") @@ -67,7 +69,7 @@ fn invoke_hello_world_with_deploy_first() { #[test] fn invoke_hello_world() { - let sandbox = Sandbox::new(); + let sandbox = TestEnv::default(); sandbox .new_cmd("contract") .arg("invoke") @@ -84,7 +86,7 @@ fn invoke_hello_world() { #[test] fn invoke_respects_conflicting_args() { - let sandbox = Sandbox::new(); + let sandbox = TestEnv::default(); sandbox .new_cmd("contract") .arg("invoke") @@ -126,27 +128,28 @@ fn invoke_respects_conflicting_args() { #[test] fn invoke_auth() { - let sandbox = Sandbox::new(); - sandbox - .new_cmd("contract") - .arg("invoke") - .arg("--account") - .arg("GD5KD2KEZJIGTC63IGW6UMUSMVUVG5IHG64HUTFWCHVZH2N2IBOQN7PS") - .arg("--id=1") - .arg("--wasm") - .arg(HELLO_WORLD.path()) - .arg("--fn=auth") - .arg("--") - .arg("--addr=GD5KD2KEZJIGTC63IGW6UMUSMVUVG5IHG64HUTFWCHVZH2N2IBOQN7PS") - .arg("--world=world") - .assert() - .stdout("[\"Hello\",\"world\"]\n") - .success(); + TestEnv::with_default(|sandbox| { + sandbox + .new_cmd("contract") + .arg("invoke") + .arg("--account") + .arg("GD5KD2KEZJIGTC63IGW6UMUSMVUVG5IHG64HUTFWCHVZH2N2IBOQN7PS") + .arg("--id=1") + .arg("--wasm") + .arg(HELLO_WORLD.path()) + .arg("--fn=auth") + .arg("--") + .arg("--addr=GD5KD2KEZJIGTC63IGW6UMUSMVUVG5IHG64HUTFWCHVZH2N2IBOQN7PS") + .arg("--world=world") + .assert() + .stdout("[\"Hello\",\"world\"]\n") + .success(); + }); } #[test] fn invoke_hello_world_with_seed() { - let sandbox = Sandbox::new(); + let sandbox = TestEnv::default(); let identity = add_test_seed(sandbox.dir()); sandbox .new_cmd("contract") diff --git a/cmd/soroban-cli/tests/it/util.rs b/cmd/soroban-cli/tests/it/util.rs index 6b3218da4..f772c3570 100644 --- a/cmd/soroban-cli/tests/it/util.rs +++ b/cmd/soroban-cli/tests/it/util.rs @@ -1,127 +1,11 @@ -use std::{ffi::OsString, fmt::Display, fs, path::PathBuf}; +use std::{fmt::Display, fs}; -use assert_cmd::{assert::Assert, Command}; -use assert_fs::{prelude::PathChild, TempDir}; -use sha2::{Digest, Sha256}; -use soroban_env_host::xdr::{Error as XdrError, Hash, InstallContractCodeArgs, WriteXdr}; +use assert_cmd::Command; +use assert_fs::TempDir; +use soroban_test::{CommandExt, TestEnv, Wasm}; -pub struct Wasm<'a>(pub &'a str); - -impl Wasm<'_> { - pub fn path(&self) -> PathBuf { - let mut path = PathBuf::from( - std::env::var("CARGO_MANIFEST_DIR") - .map_or_else(|_| "", |_| "../..") - .to_string(), - ) - .join("target/wasm32-unknown-unknown/test-wasms") - .join(self.0); - path.set_extension("wasm"); - assert!(path.is_file(), "File not found: {}. run 'make build-test-wasms' to generate .wasm files before running this test", path.display()); - std::env::current_dir().unwrap().join(path) - } - - pub fn bytes(&self) -> Vec { - fs::read(self.path()).unwrap() - } - - pub fn hash(&self) -> Hash { - contract_hash(&self.bytes()).unwrap() - } -} - -/// Default -pub struct Sandbox { - pub temp_dir: TempDir, -} - -impl Sandbox { - pub fn new() -> Sandbox { - Self { - temp_dir: TempDir::new().expect("failed to create temp dir"), - } - } - pub fn new_cmd(&self, name: &str) -> Command { - let mut this = Command::cargo_bin("soroban").expect("failed to find local soroban binary"); - this.arg(name); - this.current_dir(&self.temp_dir); - this - } - - pub fn dir(&self) -> &TempDir { - &self.temp_dir - } - - pub fn gen_test_identity(&self) { - self.new_cmd("config") - .arg("identity") - .arg("generate") - .arg("--default-seed") - .arg("test") - .assert() - .success(); - } - - pub fn test_address(&self, hd_path: usize) -> String { - self.new_cmd("config") - .args("identity address test --hd-path".split(' ')) - .arg(format!("{hd_path}")) - .assert() - .stdout_as_str() - } -} - -pub fn temp_ledger_file() -> OsString { - TempDir::new() - .unwrap() - .child("ledger.json") - .as_os_str() - .into() -} - -pub trait AssertExt { - fn stdout_as_str(&self) -> String; -} - -impl AssertExt for Assert { - fn stdout_as_str(&self) -> String { - String::from_utf8(self.get_output().stdout.clone()) - .expect("failed to make str") - .trim() - .to_owned() - } -} -pub trait CommandExt { - fn json_arg(&mut self, j: A) -> &mut Self - where - A: Display; -} - -impl CommandExt for Command { - fn json_arg(&mut self, j: A) -> &mut Self - where - A: Display, - { - self.arg(OsString::from(j.to_string())) - } -} - -// TODO add a `lib.rs` so that this can be imported -pub fn contract_hash(contract: &[u8]) -> Result { - let args_xdr = InstallContractCodeArgs { - code: contract.try_into()?, - } - .to_xdr()?; - Ok(Hash(Sha256::digest(args_xdr).into())) -} - -pub const HELLO_WORLD: &Wasm = &Wasm("test_hello_world"); -pub const CUSTOM_TYPES: &Wasm = &Wasm("test_custom_types"); - -#[allow(unused)] -pub fn temp_dir() -> TempDir { - TempDir::new().unwrap() -} +pub const HELLO_WORLD: &Wasm = &Wasm::Custom("test-wasms", "test_hello_world"); +pub const CUSTOM_TYPES: &Wasm = &Wasm::Custom("test-wasms", "test_custom_types"); #[derive(Clone)] pub enum SecretKind { @@ -166,7 +50,7 @@ pub fn add_test_seed(dir: &TempDir) -> String { name.to_owned() } -pub fn invoke(sandbox: &Sandbox, func: &str) -> Command { +pub fn invoke(sandbox: &TestEnv, func: &str) -> Command { let mut s = sandbox.new_cmd("contract"); s.arg("invoke") .arg("--id=1") @@ -182,7 +66,7 @@ pub fn invoke_with_roundtrip(func: &str, data: D) where D: Display, { - invoke(&Sandbox::new(), func) + invoke(&TestEnv::default(), func) .arg(&format!("--{func}")) .json_arg(&data) .assert()