diff --git a/Cargo.lock b/Cargo.lock index 7de51f99cb81a019b0c4ae58121a2b2607267a90..e5aa4d63e2b1df09c98f677a0041b057b2c891da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -731,7 +731,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -1128,7 +1128,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -1196,7 +1196,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -1226,7 +1226,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -2065,7 +2065,7 @@ dependencies = [ "regex", "rustc-hash 2.1.1", "shlex", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -2083,7 +2083,7 @@ dependencies = [ "regex", "rustc-hash 2.1.1", "shlex", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -2218,7 +2218,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -2247,7 +2247,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -2397,7 +2397,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -2482,7 +2482,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -2736,7 +2736,7 @@ dependencies = [ "quote", "serde", "serde_json", - "syn 2.0.106", + "syn 2.0.117", "tempfile", "toml 0.8.23", ] @@ -2965,7 +2965,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -3643,6 +3643,15 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "convert_case" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "affbf0190ed2caf063e3def54ff444b449371d55c58e513a95ab98eca50adb49" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "copilot" version = "0.1.0" @@ -4354,7 +4363,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -4431,7 +4440,7 @@ dependencies = [ "proc-macro2", "quote", "scratch", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -4445,7 +4454,7 @@ dependencies = [ "indexmap", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -4463,7 +4472,7 @@ dependencies = [ "indexmap", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -4560,7 +4569,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -4571,7 +4580,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -4803,7 +4812,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -4825,7 +4834,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.106", + "syn 2.0.117", "unicode-xid", ] @@ -4835,7 +4844,7 @@ version = "0.1.0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -4847,7 +4856,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -5038,7 +5047,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -5101,7 +5110,7 @@ dependencies = [ "proc-macro2", "quote", "strum 0.27.2", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -5476,6 +5485,8 @@ dependencies = [ "parking_lot", "pretty_assertions", "project", + "proptest", + "proptest-derive", "rand 0.9.2", "regex", "release_channel", @@ -5652,7 +5663,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -5673,7 +5684,7 @@ checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -5738,7 +5749,7 @@ checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -6213,7 +6224,7 @@ checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -6512,7 +6523,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -6781,7 +6792,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -7192,7 +7203,7 @@ source = "git+https://github.com/zed-industries/gh-workflow?rev=c9eac0ed361583e1 dependencies = [ "heck 0.5.0", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -7441,7 +7452,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -7656,6 +7667,7 @@ dependencies = [ "postage", "pretty_assertions", "profiling", + "proptest", "rand 0.9.2", "raw-window-handle", "refineable", @@ -7783,7 +7795,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -8211,7 +8223,7 @@ dependencies = [ "markup5ever 0.12.1", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -8669,7 +8681,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3" dependencies = [ "byteorder-lite", - "quick-error", + "quick-error 2.0.1", ] [[package]] @@ -8745,7 +8757,7 @@ checksum = "c727f80bfa4a6c6e2508d2f05b6f4bfce242030bd88ed15ae5331c5b5d30fba7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -8840,7 +8852,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -9032,7 +9044,7 @@ checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -10303,7 +10315,7 @@ checksum = "ac84fd3f360fcc43dc5f5d186f02a94192761a080e8bc58621ad4d12296a58cf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -11170,7 +11182,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -11253,7 +11265,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -11646,7 +11658,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -11675,7 +11687,7 @@ checksum = "969ccca8ffc4fb105bd131a228107d5c9dd89d9d627edf3295cbe979156f9712" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -11733,7 +11745,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -11843,7 +11855,7 @@ dependencies = [ "by_address", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -12106,7 +12118,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -12585,7 +12597,7 @@ dependencies = [ "phf_shared 0.11.3", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -12598,7 +12610,7 @@ dependencies = [ "phf_shared 0.12.1", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -12660,7 +12672,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -12984,7 +12996,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -13048,7 +13060,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -13068,7 +13080,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", "version_check", "yansi", ] @@ -13099,7 +13111,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b" dependencies = [ "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -13308,6 +13320,47 @@ dependencies = [ "uuid", ] +[[package]] +name = "proptest" +version = "1.10.0" +source = "git+https://github.com/proptest-rs/proptest?rev=3dca198a8fef1b32e3a66f1e1897c955b4dc5b5b#3dca198a8fef1b32e3a66f1e1897c955b4dc5b5b" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags 2.10.0", + "num-traits", + "proptest-macro", + "rand 0.9.2", + "rand_chacha 0.9.0", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "proptest-derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c57924a81864dddafba92e1bf92f9bf82f97096c44489548a60e888e1547549b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "proptest-macro" +version = "0.5.0" +source = "git+https://github.com/proptest-rs/proptest?rev=3dca198a8fef1b32e3a66f1e1897c955b4dc5b5b#3dca198a8fef1b32e3a66f1e1897c955b4dc5b5b" +dependencies = [ + "convert_case 0.11.0", + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "prost" version = "0.9.0" @@ -13365,7 +13418,7 @@ dependencies = [ "prost 0.12.6", "prost-types 0.12.6", "regex", - "syn 2.0.106", + "syn 2.0.117", "tempfile", ] @@ -13392,7 +13445,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -13560,6 +13613,12 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quick-error" version = "2.0.1" @@ -13785,6 +13844,15 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rand_xorshift" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +dependencies = [ + "rand_core 0.9.3", +] + [[package]] name = "random_choice" version = "0.3.2" @@ -13859,7 +13927,7 @@ dependencies = [ "avif-serialize", "imgref", "loop9", - "quick-error", + "quick-error 2.0.1", "rav1e", "rayon", "rgb", @@ -14059,7 +14127,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -14736,7 +14804,7 @@ dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.106", + "syn 2.0.117", "walkdir", ] @@ -14990,6 +15058,18 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "rusty-fork" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" +dependencies = [ + "fnv", + "quick-error 1.2.3", + "tempfile", + "wait-timeout", +] + [[package]] name = "rustybuzz" version = "0.20.1" @@ -15109,7 +15189,7 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -15170,7 +15250,7 @@ checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -15199,7 +15279,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -15241,7 +15321,7 @@ dependencies = [ "proc-macro2", "quote", "sea-bae", - "syn 2.0.106", + "syn 2.0.117", "unicode-ident", ] @@ -15426,7 +15506,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -15437,7 +15517,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -15495,7 +15575,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -15635,7 +15715,7 @@ version = "0.1.0" dependencies = [ "quote", "settings", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -16009,7 +16089,7 @@ checksum = "0eb01866308440fc64d6c44d9e86c5cc17adfe33c4d6eed55da9145044d0ffc1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -16187,7 +16267,7 @@ version = "0.1.0" dependencies = [ "sqlez", "sqlformat", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -16264,7 +16344,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -16287,7 +16367,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.106", + "syn 2.0.117", "tokio", "url", ] @@ -16446,7 +16526,7 @@ checksum = "172175341049678163e979d9107ca3508046d4d2a7c6682bee46ac541b17db69" dependencies = [ "proc-macro-error2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -16589,7 +16669,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -16605,6 +16685,7 @@ dependencies = [ "arrayvec", "ctor", "log", + "proptest", "rand 0.9.2", "rayon", "tracing", @@ -16890,9 +16971,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.106" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -16931,7 +17012,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -17371,6 +17452,7 @@ dependencies = [ "log", "parking_lot", "postage", + "proptest", "rand 0.9.2", "regex", "rope", @@ -17481,7 +17563,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -17492,7 +17574,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -17513,7 +17595,7 @@ dependencies = [ "fax", "flate2", "half", - "quick-error", + "quick-error 2.0.1", "weezl", "zune-jpeg", ] @@ -17736,7 +17818,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -18074,7 +18156,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -18169,7 +18251,7 @@ checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -18626,7 +18708,7 @@ version = "0.1.0" dependencies = [ "component", "quote", - "syn 2.0.106", + "syn 2.0.117", "ui", ] @@ -18643,6 +18725,12 @@ dependencies = [ "workspace", ] +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + [[package]] name = "unicase" version = "2.8.1" @@ -18881,7 +18969,7 @@ version = "0.1.0" dependencies = [ "perf", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -19099,6 +19187,15 @@ dependencies = [ "serde", ] +[[package]] +name = "wait-timeout" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" +dependencies = [ + "libc", +] + [[package]] name = "waker-fn" version = "1.2.0" @@ -19228,7 +19325,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", "wasm-bindgen-shared", ] @@ -19524,7 +19621,7 @@ dependencies = [ "anyhow", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", "wasmtime-component-util", "wasmtime-wit-bindgen", "wit-parser 0.229.0", @@ -19639,7 +19736,7 @@ checksum = "d0963c1438357a3d8c0efe152b4ef5259846c1cf8b864340270744fe5b3bae5e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -20177,7 +20274,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", "witx", ] @@ -20189,7 +20286,7 @@ checksum = "d873bb5b59ca703b5e41562e96a4796d1af61bf4cf80bf8a7abda755a380ec1c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", "wiggle-generate", ] @@ -20412,7 +20509,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -20423,7 +20520,7 @@ checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -20434,7 +20531,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -20445,7 +20542,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -20456,7 +20553,7 @@ checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -20467,7 +20564,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -21105,7 +21202,7 @@ dependencies = [ "heck 0.5.0", "indexmap", "prettyplease", - "syn 2.0.106", + "syn 2.0.117", "wasm-metadata 0.227.1", "wit-bindgen-core 0.41.0", "wit-component 0.227.1", @@ -21121,7 +21218,7 @@ dependencies = [ "heck 0.5.0", "indexmap", "prettyplease", - "syn 2.0.106", + "syn 2.0.117", "wasm-metadata 0.244.0", "wit-bindgen-core 0.51.0", "wit-component 0.244.0", @@ -21136,7 +21233,7 @@ dependencies = [ "anyhow", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", "wit-bindgen-core 0.22.0", "wit-bindgen-rust 0.22.0", ] @@ -21151,7 +21248,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", "wit-bindgen-core 0.41.0", "wit-bindgen-rust 0.41.0", ] @@ -21166,7 +21263,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", "wit-bindgen-core 0.51.0", "wit-bindgen-rust 0.51.0", ] @@ -21697,7 +21794,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", "synstructure", ] @@ -21709,7 +21806,7 @@ checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", "synstructure", ] @@ -21757,7 +21854,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", "zbus_names", "zvariant", "zvariant_utils", @@ -22155,7 +22252,7 @@ checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -22175,7 +22272,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", "synstructure", ] @@ -22196,7 +22293,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -22253,7 +22350,7 @@ checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", ] [[package]] @@ -22415,7 +22512,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.106", + "syn 2.0.117", "zvariant_utils", ] @@ -22428,6 +22525,6 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.106", + "syn 2.0.117", "winnow", ] diff --git a/Cargo.toml b/Cargo.toml index 597a5f2a207c27154dcf1a55c85d97271604f83f..1d0f29086b45029e4d9dbc3fa9ffd9dbb6135a6e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -650,6 +650,9 @@ postage = { version = "0.5", features = ["futures-traits"] } pretty_assertions = { version = "1.3.0", features = ["unstable"] } proc-macro2 = "1.0.93" profiling = "1" +# replace this with main when #635 is merged +proptest = { git = "https://github.com/proptest-rs/proptest", rev = "3dca198a8fef1b32e3a66f1e1897c955b4dc5b5b", features = ["attr-macro"] } +proptest-derive = "0.8.0" prost = "0.9" prost-build = "0.9" prost-types = "0.9" diff --git a/crates/editor/Cargo.toml b/crates/editor/Cargo.toml index b200d25f6d9ca90e862091b1b999613b0f5e2723..2a8709dea29cf1398a862216e407b973eae41004 100644 --- a/crates/editor/Cargo.toml +++ b/crates/editor/Cargo.toml @@ -26,6 +26,7 @@ test-support = [ "tree-sitter-rust", "tree-sitter-typescript", "tree-sitter-html", + "proptest", "unindent", ] @@ -63,6 +64,8 @@ ordered-float.workspace = true parking_lot.workspace = true pretty_assertions.workspace = true project.workspace = true +proptest = { workspace = true, optional = true } +proptest-derive = { workspace = true, optional = true } rand.workspace = true regex.workspace = true rpc.workspace = true @@ -110,6 +113,8 @@ lsp = { workspace = true, features = ["test-support"] } markdown = { workspace = true, features = ["test-support"] } multi_buffer = { workspace = true, features = ["test-support"] } project = { workspace = true, features = ["test-support"] } +proptest.workspace = true +proptest-derive.workspace = true release_channel.workspace = true rand.workspace = true semver.workspace = true diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index 8b866563636f6fe494bdd8d941458defa786c0da..3cb2ac6ceec6e54b93266e2052403722651f89e3 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -76,6 +76,9 @@ fn display_ranges(editor: &Editor, cx: &mut Context<'_, Editor>) -> Vec, + ) { + match action { + TestAction::Type(text) => self.insert(&text, window, cx), + TestAction::Backspace { count } => { + for _ in 0..*count { + self.delete(&Default::default(), window, cx); + } + } + TestAction::Move { count, direction } => { + for _ in 0..*count { + match direction { + Direction::Up => self.move_up(&Default::default(), window, cx), + Direction::Down => self.move_down(&Default::default(), window, cx), + Direction::Left => self.move_left(&Default::default(), window, cx), + Direction::Right => self.move_right(&Default::default(), window, cx), + } + } + } + } + } +} + +fn test_actions() -> impl Strategy> { + proptest::collection::vec(any::(), 1..10) +} + +#[gpui::property_test(config = ProptestConfig {cases: 100, ..Default::default()})] +fn editor_property_test( + cx: &mut TestAppContext, + #[strategy = test_actions()] actions: Vec, +) { + init_test(cx, |_| {}); + + let group_interval = Duration::from_millis(1); + + let buffer = cx.new(|cx| { + let mut buf = language::Buffer::local("123456", cx); + buf.set_group_interval(group_interval); + buf + }); + + let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx)); + let editor = cx.add_window(|window, cx| build_editor(buffer.clone(), window, cx)); + + editor + .update(cx, |editor, window, cx| { + for action in actions { + editor.apply_test_action(&action, window, cx); + } + }) + .unwrap(); +} diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index c80f97efb6dc8bf1450c08bfe85290096b44815b..a07eb08576c31236df26787c9c9ade4186c466d6 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -24,6 +24,7 @@ test-support = [ "http_client/test-support", "wayland", "x11", + "proptest", ] inspector = ["gpui_macros/inspector"] leak-detection = ["backtrace"] @@ -64,6 +65,7 @@ num_cpus = "1.13" parking = "2.0.0" parking_lot.workspace = true postage.workspace = true +proptest = { workspace = true, optional = true } chrono.workspace = true profiling.workspace = true rand.workspace = true diff --git a/crates/gpui/src/gpui.rs b/crates/gpui/src/gpui.rs index ff36dbce500b8e7472f3d7faa31d9e5cb17e087e..6d7d801cd42c3639d7892295a660319d21b05dfa 100644 --- a/crates/gpui/src/gpui.rs +++ b/crates/gpui/src/gpui.rs @@ -54,6 +54,9 @@ mod util; mod view; mod window; +#[cfg(any(test, feature = "test-support"))] +pub use proptest; + #[cfg(doc)] pub mod _ownership_and_data_flow; @@ -86,7 +89,9 @@ pub use elements::*; pub use executor::*; pub use geometry::*; pub use global::*; -pub use gpui_macros::{AppContext, IntoElement, Render, VisualContext, register_action, test}; +pub use gpui_macros::{ + AppContext, IntoElement, Render, VisualContext, property_test, register_action, test, +}; pub use gpui_util::arc_cow::ArcCow; pub use http_client; pub use input::*; diff --git a/crates/gpui/src/test.rs b/crates/gpui/src/test.rs index 9e76d97e97e941121417d872e8c6f596cf658e20..ddcc3d27bd04d2fd82b3367a2fee6930e86ef356 100644 --- a/crates/gpui/src/test.rs +++ b/crates/gpui/src/test.rs @@ -27,12 +27,43 @@ //! ``` use crate::{Entity, Subscription, TestAppContext, TestDispatcher}; use futures::StreamExt as _; +use proptest::prelude::{Just, Strategy, any}; use std::{ env, - panic::{self, RefUnwindSafe}, + panic::{self, RefUnwindSafe, UnwindSafe}, pin::Pin, }; +/// Strategy injected into `#[gpui::property_test]` tests to control the seed +/// given to the scheduler. Doesn't shrink, since all scheduler seeds are +/// equivalent in complexity. If `$SEED` is set, it always uses that value. +pub fn seed_strategy() -> impl Strategy { + match std::env::var("SEED") { + Ok(val) => Just(val.parse().unwrap()).boxed(), + Err(_) => any::().no_shrink().boxed(), + } +} + +/// Similar to [`run_test`], but only runs the callback once, allowing +/// [`FnOnce`] callbacks. This is intended for use with the +/// `gpui::property_test` macro and generally should not be used directly. +/// +/// Doesn't support many features of [`run_test`], since these are provided by +/// proptest. +pub fn run_test_once(seed: u64, test_fn: Box) { + let result = panic::catch_unwind(|| { + let dispatcher = TestDispatcher::new(seed); + let scheduler = dispatcher.scheduler().clone(); + test_fn(dispatcher); + scheduler.end_test(); + }); + + match result { + Ok(()) => {} + Err(e) => panic::resume_unwind(e), + } +} + /// Run the given test function with the configured parameters. /// This is intended for use with the `gpui::test` macro /// and generally should not be used directly. diff --git a/crates/gpui_macros/Cargo.toml b/crates/gpui_macros/Cargo.toml index 2ee8da52fb7a013cefdd5fe79520a5d18f1e5b3f..513dd61d7b1da83aae2ca4779fb187aece3d7278 100644 --- a/crates/gpui_macros/Cargo.toml +++ b/crates/gpui_macros/Cargo.toml @@ -24,4 +24,4 @@ quote.workspace = true syn.workspace = true [dev-dependencies] -gpui = { workspace = true, features = ["inspector"] } +gpui = { workspace = true, features = ["inspector"] } \ No newline at end of file diff --git a/crates/gpui_macros/src/gpui_macros.rs b/crates/gpui_macros/src/gpui_macros.rs index 0f1365be77ec221d9061f588f84ff6acab3c32ab..e30c85e6edbee8b5307a5139c00a222e9a83bc55 100644 --- a/crates/gpui_macros/src/gpui_macros.rs +++ b/crates/gpui_macros/src/gpui_macros.rs @@ -3,6 +3,7 @@ mod derive_app_context; mod derive_into_element; mod derive_render; mod derive_visual_context; +mod property_test; mod register_action; mod styles; mod test; @@ -188,6 +189,79 @@ pub fn test(args: TokenStream, function: TokenStream) -> TokenStream { test::test(args, function) } +/// A variant of `#[gpui::test]` that supports property-based testing. +/// +/// A property test, much like a standard GPUI randomized test, allows testing +/// claims of the form "for any possible X, Y should hold". For example: +/// ``` +/// #[gpui::property_test] +/// fn test_arithmetic(x: i32, y: i32) { +/// assert!(x == y || x < y || x > y); +/// } +/// ``` +/// Standard GPUI randomized tests provide you with an instance of `StdRng` to +/// generate random data in a controlled manner. Property-based tests have some +/// advantages, however: +/// - Shrinking - the harness also understands a notion of the "complexity" of a +/// particular value. This allows it to find the "simplest possible value that +/// causes the test to fail". +/// - Ergonomics/clarity - the property-testing harness will automatically +/// generate values, removing the need to fill the test body with generation +/// logic. +/// - Failure persistence - if a failing seed is identified, it is stored in a +/// file, which can be checked in, and future runs will check these cases before +/// future cases. +/// +/// Property tests work best when all inputs can be generated up-front and kept +/// in a simple data structure. Sometimes, this isn't possible - for example, if +/// a test needs to make a random decision based on the current state of some +/// structure. In this case, a standard GPUI randomized test may be more +/// suitable. +/// +/// ## Customizing random values +/// +/// This macro is based on the [`#[proptest::property_test]`] macro, but handles +/// some of the same GPUI-specific arguments as `#[gpui::test]`. Specifically, +/// `&{mut,} TestAppContext` and `BackgroundExecutor` work as normal. `StdRng` +/// arguments are **explicitly forbidden**, since they break shrinking, and are +/// a common footgun. +/// +/// All other arguments are forwarded to the underlying proptest macro. +/// +/// Note: much of the following is copied from the proptest docs, specifically the +/// [`#[proptest::property_test]`] macro docs. +/// +/// Random values of type `T` are generated by a `Strategy` object. +/// Some types have a canonical `Strategy` - these types also implement +/// `Arbitrary`. Parameters to a `#[gpui::property_test]`, by default, use a +/// type's `Arbitrary` implementation. If you'd like to provide a custom +/// strategy, you can use `#[strategy = ...]` on the argument: +/// ``` +/// #[gpui::property_test] +/// fn int_test(#[strategy = 1..10] x: i32, #[strategy = "[a-zA-Z0-9]{20}"] s: String) { +/// assert!(s.len() > (x as usize)); +/// } +/// ``` +/// +/// For more information on writing custom `Strategy` and `Arbitrary` +/// implementations, see [the proptest book][book], and the [`Strategy`] trait. +/// +/// ## Scheduler +/// +/// Similar to `#[gpui::test]`, this macro will choose random seeds for the test +/// scheduler. It uses `.no_shrink()` to tell proptest that all seeds are +/// roughly equivalent in terms of "complexity". If `$SEED` is set, it will +/// affect **ONLY** the seed passed to the scheduler. To control other values, +/// use custom `Strategy`s. +/// +/// [`#[proptest::property_test]`]: https://docs.rs/proptest/latest/proptest/attr.property_test.html +/// [book]: https://proptest-rs.github.io/proptest/intro.html +/// [`Strategy`]: https://docs.rs/proptest/latest/proptest/strategy/trait.Strategy.html +#[proc_macro_attribute] +pub fn property_test(args: TokenStream, function: TokenStream) -> TokenStream { + property_test::test(args.into(), function.into()).into() +} + /// When added to a trait, `#[derive_inspector_reflection]` generates a module which provides /// enumeration and lookup by name of all methods that have the shape `fn method(self) -> Self`. /// This is used by the inspector so that it can use the builder methods in `Styled` and diff --git a/crates/gpui_macros/src/property_test.rs b/crates/gpui_macros/src/property_test.rs new file mode 100644 index 0000000000000000000000000000000000000000..6bf60eca1b63a86bce22fbf4ae771230ee34726d --- /dev/null +++ b/crates/gpui_macros/src/property_test.rs @@ -0,0 +1,199 @@ +use proc_macro2::TokenStream; +use quote::{format_ident, quote, quote_spanned}; +use syn::{ + FnArg, Ident, ItemFn, Type, parse2, punctuated::Punctuated, spanned::Spanned, token::Comma, +}; + +pub fn test(args: TokenStream, item: TokenStream) -> TokenStream { + let item_span = item.span(); + let Ok(func) = parse2::(item) else { + return quote_spanned! { item_span => + compile_error!("#[gpui::property_test] must be placed on a function"); + }; + }; + + let test_name = func.sig.ident.clone(); + let inner_fn_name = format_ident!("__{test_name}"); + + let parsed_args = parse_args(func.sig.inputs, &test_name); + + let inner_body = func.block; + let inner_arg_decls = parsed_args.inner_fn_decl_args; + let asyncness = func.sig.asyncness; + + let inner_fn = quote! { + let #inner_fn_name = #asyncness move |#inner_arg_decls| #inner_body; + }; + + let arg_errors = parsed_args.errors; + let proptest_args = parsed_args.proptest_args; + let inner_args = parsed_args.inner_fn_args; + let cx_vars = parsed_args.cx_vars; + let cx_teardowns = parsed_args.cx_teardowns; + + let proptest_args = quote! { + #[strategy = ::gpui::seed_strategy()] __seed: u64, + #proptest_args + }; + + let run_test_body = match &asyncness { + None => quote! { + #cx_vars + #inner_fn_name(#inner_args); + #cx_teardowns + }, + Some(_) => quote! { + let foreground_executor = gpui::ForegroundExecutor::new(std::sync::Arc::new(dispatcher.clone())); + #cx_vars + foreground_executor.block_test(#inner_fn_name(#inner_args)); + #cx_teardowns + }, + }; + + quote! { + #arg_errors + + #[::gpui::proptest::property_test(proptest_path = "::gpui::proptest", #args)] + fn #test_name(#proptest_args) { + #inner_fn + + ::gpui::run_test_once( + __seed, + Box::new(move |dispatcher| { + #run_test_body + }), + ) + } + } +} + +#[derive(Default)] +struct ParsedArgs { + cx_vars: TokenStream, + cx_teardowns: TokenStream, + proptest_args: TokenStream, + errors: TokenStream, + + // exprs passed at the call-site + inner_fn_args: TokenStream, + // args in the declaration + inner_fn_decl_args: TokenStream, +} + +fn parse_args(args: Punctuated, test_name: &Ident) -> ParsedArgs { + let mut parsed = ParsedArgs::default(); + let mut args = args.into_iter().collect(); + + remove_cxs(&mut parsed, &mut args, test_name); + remove_std_rng(&mut parsed, &mut args); + remove_background_executor(&mut parsed, &mut args); + + // all remaining args forwarded to proptest's macro + parsed.proptest_args = quote!( #(#args),* ); + + parsed +} + +fn remove_cxs(parsed: &mut ParsedArgs, args: &mut Vec, test_name: &Ident) { + let mut ix = 0; + args.retain_mut(|arg| { + if !is_test_cx(arg) { + return true; + } + + let cx_varname = format_ident!("cx_{ix}"); + ix += 1; + + parsed.cx_vars.extend(quote!( + let mut #cx_varname = gpui::TestAppContext::build( + dispatcher.clone(), + Some(stringify!(#test_name)), + ); + )); + parsed.cx_teardowns.extend(quote!( + dispatcher.run_until_parked(); + #cx_varname.executor().forbid_parking(); + #cx_varname.quit(); + dispatcher.run_until_parked(); + )); + + parsed.inner_fn_decl_args.extend(quote!(#arg,)); + parsed.inner_fn_args.extend(quote!(&mut #cx_varname,)); + + false + }); +} + +fn remove_std_rng(parsed: &mut ParsedArgs, args: &mut Vec) { + args.retain_mut(|arg| { + if !is_std_rng(arg) { + return true; + } + + parsed.errors.extend(quote_spanned! { arg.span() => + compile_error!("`StdRng` is not allowed in a property test. Consider implementing `Arbitrary`, or implementing a custom `Strategy`. https://altsysrq.github.io/proptest-book/proptest/tutorial/strategy-basics.html"); + }); + + false + }); +} + +fn remove_background_executor(parsed: &mut ParsedArgs, args: &mut Vec) { + args.retain_mut(|arg| { + if !is_background_executor(arg) { + return true; + } + + parsed.inner_fn_decl_args.extend(quote!(#arg,)); + parsed + .inner_fn_args + .extend(quote!(gpui::BackgroundExecutor::new(std::sync::Arc::new( + dispatcher.clone() + )),)); + + false + }); +} + +// Matches `&TestAppContext` or `&foo::bar::baz::TestAppContext` +fn is_test_cx(arg: &FnArg) -> bool { + let FnArg::Typed(arg) = arg else { + return false; + }; + + let Type::Reference(ty) = &*arg.ty else { + return false; + }; + + let Type::Path(ty) = &*ty.elem else { + return false; + }; + + ty.path + .segments + .last() + .is_some_and(|seg| seg.ident == "TestAppContext") +} + +fn is_std_rng(arg: &FnArg) -> bool { + is_path_with_last_segment(arg, "StdRng") +} + +fn is_background_executor(arg: &FnArg) -> bool { + is_path_with_last_segment(arg, "BackgroundExecutor") +} + +fn is_path_with_last_segment(arg: &FnArg, last_segment: &str) -> bool { + let FnArg::Typed(arg) = arg else { + return false; + }; + + let Type::Path(ty) = &*arg.ty else { + return false; + }; + + ty.path + .segments + .last() + .is_some_and(|seg| seg.ident == last_segment) +} diff --git a/crates/sum_tree/Cargo.toml b/crates/sum_tree/Cargo.toml index 3e06ede162dad37f94017207ccbd6ee5c38f26a5..e4cf78181aa43cce4a6692cc3c6c92e03b7bf9ad 100644 --- a/crates/sum_tree/Cargo.toml +++ b/crates/sum_tree/Cargo.toml @@ -19,11 +19,17 @@ rayon.workspace = true log.workspace = true ztracing.workspace = true tracing.workspace = true +proptest = { workspace = true, optional = true } [dev-dependencies] ctor.workspace = true rand.workspace = true +proptest.workspace = true zlog.workspace = true + [package.metadata.cargo-machete] ignored = ["tracing"] + +[features] +test-support = ["proptest"] \ No newline at end of file diff --git a/crates/sum_tree/src/property_test.rs b/crates/sum_tree/src/property_test.rs new file mode 100644 index 0000000000000000000000000000000000000000..d6c6bd76f94704c60dfc6919fa02ba66c19f349d --- /dev/null +++ b/crates/sum_tree/src/property_test.rs @@ -0,0 +1,32 @@ +use core::fmt::Debug; + +use proptest::{prelude::*, sample::SizeRange}; + +use crate::{Item, SumTree, Summary}; + +impl Arbitrary for SumTree +where + T: Debug + Arbitrary + Item + 'static, + T::Summary: Debug + Summary = ()>, +{ + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with((): Self::Parameters) -> Self::Strategy { + any::>() + .prop_map(|vec| SumTree::from_iter(vec, ())) + .boxed() + } +} + +/// A strategy for producing a [`SumTree`] with a given size. +/// +/// Equivalent to [`proptest::collection::vec`]. +pub fn sum_tree(values: S, size: impl Into) -> impl Strategy> +where + T: Debug + Arbitrary + Item + 'static, + T::Summary: Debug + Summary = ()>, + S: Strategy, +{ + proptest::collection::vec(values, size).prop_map(|vec| SumTree::from_iter(vec, ())) +} diff --git a/crates/sum_tree/src/sum_tree.rs b/crates/sum_tree/src/sum_tree.rs index 068bc4bce56816962a3b75d6f6497b033a9209a5..8ab9b5ccb1fdb3b28b3aa0dd93c7a732a21645cb 100644 --- a/crates/sum_tree/src/sum_tree.rs +++ b/crates/sum_tree/src/sum_tree.rs @@ -1,4 +1,6 @@ mod cursor; +#[cfg(any(test, feature = "test-support"))] +pub mod property_test; mod tree_map; use arrayvec::ArrayVec; diff --git a/crates/text/Cargo.toml b/crates/text/Cargo.toml index ed02381eb83db5daececd159171a90072244a340..47c1dd768d19492e43231a3e8cd8270fb648f39c 100644 --- a/crates/text/Cargo.toml +++ b/crates/text/Cargo.toml @@ -37,3 +37,4 @@ rand.workspace = true util = { workspace = true, features = ["test-support"] } http_client = { workspace = true, features = ["test-support"] } zlog.workspace = true +proptest.workspace = true