diff --git a/Cargo.lock b/Cargo.lock index 26708f8641..335aae4133 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,15 +44,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "ansi_term" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -dependencies = [ - "winapi 0.3.9", -] - [[package]] name = "anyhow" version = "1.0.45" @@ -109,22 +100,11 @@ dependencies = [ "Inflector", "enso-macro-utils", "enso-prelude", - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "syn", ] -[[package]] -name = "ast-new" -version = "0.1.0" -dependencies = [ - "clap", - "itertools 0.10.1", - "proc-macro2 1.0.32", - "syn", - "uuid", -] - [[package]] name = "async-std" version = "1.5.0" @@ -385,12 +365,6 @@ version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd" -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - [[package]] name = "cfg-if" version = "0.1.10" @@ -423,13 +397,9 @@ version = "2.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" dependencies = [ - "ansi_term", - "atty", "bitflags", - "strsim", "textwrap", "unicode-width", - "vec_map", ] [[package]] @@ -459,16 +429,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "combine" -version = "4.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b2f5d0ee456f3928812dfc8c6d9a1d592b98678f6d56db9b0cd2b7bc6c8db5" -dependencies = [ - "bytes 1.1.0", - "memchr", -] - [[package]] name = "config-reader" version = "0.1.0" @@ -488,10 +448,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "controller" -version = "0.1.0" - [[package]] name = "convert_case" version = "0.4.0" @@ -678,7 +634,7 @@ version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" dependencies = [ - "quote 1.0.10", + "quote", "syn", ] @@ -719,8 +675,8 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "syn", ] @@ -731,8 +687,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40eebddd2156ce1bb37b20bbe5151340a31828b1f2d22ba4141f3531710e38df" dependencies = [ "convert_case", - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "rustc_version 0.3.3", "syn", ] @@ -768,7 +724,7 @@ dependencies = [ "regex", "serde", "uuid", - "wasm-bindgen-test 0.3.8", + "wasm-bindgen-test", ] [[package]] @@ -804,10 +760,6 @@ dependencies = [ "cfg-if 1.0.0", ] -[[package]] -name = "engine-model" -version = "0.1.0" - [[package]] name = "engine-protocol" version = "0.1.0" @@ -834,7 +786,7 @@ dependencies = [ "sha3", "tokio", "uuid", - "wasm-bindgen-test 0.3.8", + "wasm-bindgen-test", "zip", "zip-extensions", ] @@ -903,12 +855,12 @@ dependencies = [ "enso-prelude", "itertools 0.8.2", "nonempty", - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "syn", "unicode-segmentation", "wasm-bindgen", - "wasm-bindgen-test 0.2.50", + "wasm-bindgen-test", ] [[package]] @@ -983,11 +935,24 @@ dependencies = [ "span-tree", "uuid", "wasm-bindgen", - "wasm-bindgen-test 0.3.8", + "wasm-bindgen-test", "web-sys", "websocket", ] +[[package]] +name = "enso-integration-test" +version = "0.1.0" +dependencies = [ + "enso-frp", + "enso-gui", + "enso-prelude", + "enso-web", + "ensogl", + "wasm-bindgen", + "wasm-bindgen-test", +] + [[package]] name = "enso-lazy-reader" version = "0.2.0" @@ -1011,10 +976,10 @@ dependencies = [ name = "enso-macro-utils" version = "0.2.0" dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "syn", - "wasm-bindgen-test 0.2.50", + "wasm-bindgen-test", ] [[package]] @@ -1052,7 +1017,7 @@ dependencies = [ "shrinkwraprs 0.3.0", "smallvec 1.7.0", "wasm-bindgen", - "wasm-bindgen-test 0.2.50", + "wasm-bindgen-test", "weak-table", "web-sys", ] @@ -1071,8 +1036,8 @@ name = "enso-profiler-macros" version = "0.1.0" dependencies = [ "Inflector", - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "syn", ] @@ -1086,7 +1051,7 @@ dependencies = [ "paste 0.1.18", "rustversion", "shrinkwraprs 0.3.0", - "wasm-bindgen-test 0.2.50", + "wasm-bindgen-test", ] [[package]] @@ -1097,10 +1062,10 @@ dependencies = [ "boolinator", "enso-macro-utils", "itertools 0.8.2", - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "syn", - "wasm-bindgen-test 0.2.50", + "wasm-bindgen-test", ] [[package]] @@ -1120,39 +1085,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "enso-shortcuts-examples" -version = "0.1.0" -dependencies = [ - "enso-automata", - "enso-frp", - "enso-logger", - "enso-prelude", - "enso-shortcuts", - "enso-web", - "js-sys", - "nalgebra 0.26.2", - "serde", - "serde_json", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "enso-span-tree-example" -version = "0.1.0" -dependencies = [ - "ast", - "enso-logger", - "enso-prelude", - "enso-text", - "enso-web", - "span-tree", - "uuid", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "enso-text" version = "0.1.0" @@ -1186,7 +1118,7 @@ dependencies = [ "js-sys", "nalgebra 0.26.2", "wasm-bindgen", - "wasm-bindgen-test 0.3.8", + "wasm-bindgen-test", "web-sys", ] @@ -1250,7 +1182,7 @@ dependencies = [ "smallvec 1.7.0", "typenum", "wasm-bindgen", - "wasm-bindgen-test 0.3.8", + "wasm-bindgen-test", "web-sys", ] @@ -1275,7 +1207,7 @@ dependencies = [ "enso-web", "js-sys", "wasm-bindgen", - "wasm-bindgen-futures 0.4.8", + "wasm-bindgen-futures", "web-sys", ] @@ -1316,7 +1248,7 @@ dependencies = [ "ensogl-core", "ensogl-drop-manager", "wasm-bindgen", - "wasm-bindgen-futures 0.4.8", + "wasm-bindgen-futures", ] [[package]] @@ -1469,7 +1401,7 @@ dependencies = [ "enso-logger", "ensogl-core", "float_eq", - "wasm-bindgen-test 0.3.8", + "wasm-bindgen-test", ] [[package]] @@ -1555,7 +1487,7 @@ dependencies = [ "ensogl-hardcoded-theme", "ensogl-text-embedded-fonts", "ensogl-text-msdf-sys", - "wasm-bindgen-test 0.3.8", + "wasm-bindgen-test", "xi-rope", ] @@ -1579,7 +1511,7 @@ dependencies = [ "js-sys", "nalgebra 0.26.2", "wasm-bindgen", - "wasm-bindgen-test 0.3.8", + "wasm-bindgen-test", ] [[package]] @@ -1597,18 +1529,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd53b3fde38a39a06b2e66dc282f3e86191e53bd04cc499929c15742beae3df8" dependencies = [ "once_cell", - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "syn", ] -[[package]] -name = "eval-tt" -version = "0.1.0" -dependencies = [ - "paste 1.0.6", -] - [[package]] name = "failure" version = "0.1.8" @@ -1625,8 +1550,8 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "syn", "synstructure", ] @@ -1661,21 +1586,6 @@ dependencies = [ "miniz_oxide", ] -[[package]] -name = "flexer-test-definition" -version = "0.1.0" -dependencies = [ - "enso-flexer", -] - -[[package]] -name = "flexer-test-generation" -version = "0.1.0" -dependencies = [ - "enso-flexer", - "flexer-test-definition", -] - [[package]] name = "flo_stream" version = "0.4.0" @@ -1822,8 +1732,8 @@ checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" dependencies = [ "autocfg 1.0.1", "proc-macro-hack", - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "syn", ] @@ -2195,8 +2105,8 @@ checksum = "e50385662f423431a619ab28ba2beeab3063b581a0d1a943765e23911c502904" dependencies = [ "lazy_static", "proc-macro-hack", - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "regex", "syn", ] @@ -2259,26 +2169,6 @@ version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" -[[package]] -name = "jni" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" -dependencies = [ - "cesu8", - "combine", - "jni-sys", - "log 0.4.14", - "thiserror", - "walkdir", -] - -[[package]] -name = "jni-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" - [[package]] name = "js-sys" version = "0.3.35" @@ -2572,8 +2462,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a673cb441f78cd9af4f5919c28576a3cc325fb6b54e42f7047dacce3c718c17b" dependencies = [ "cfg-if 0.1.10", - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "syn", ] @@ -2817,8 +2707,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "486ea01961c4a818096de679a8b740b26d9033146ac5291b1c98557658f8cdd9" dependencies = [ "proc-macro-crate", - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "syn", ] @@ -2957,18 +2847,10 @@ dependencies = [ "tokio", "uuid", "wasm-bindgen", - "wasm-bindgen-test 0.3.8", + "wasm-bindgen-test", "websocket", ] -[[package]] -name = "parser-jni" -version = "0.1.0" -dependencies = [ - "ast-new", - "jni", -] - [[package]] name = "parser-new" version = "0.1.0" @@ -3048,8 +2930,8 @@ version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389" dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "syn", ] @@ -3146,31 +3028,13 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" -[[package]] -name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -dependencies = [ - "unicode-xid 0.1.0", -] - [[package]] name = "proc-macro2" version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba508cc11742c0dc5c1659771673afbab7a0efab23aa17e854cbab0837ed0b43" dependencies = [ - "unicode-xid 0.2.2", -] - -[[package]] -name = "quote" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" -dependencies = [ - "proc-macro2 0.4.30", + "unicode-xid", ] [[package]] @@ -3179,7 +3043,7 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" dependencies = [ - "proc-macro2 1.0.32", + "proc-macro2", ] [[package]] @@ -3495,7 +3359,7 @@ dependencies = [ "tokio-tls 0.3.1", "url 2.2.2", "wasm-bindgen", - "wasm-bindgen-futures 0.4.8", + "wasm-bindgen-futures", "web-sys", "winreg", ] @@ -3678,8 +3542,8 @@ version = "1.0.130" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "syn", ] @@ -3745,8 +3609,8 @@ checksum = "83695fde96cbe9e08f0e4eb96b1b56fdbd44f2098ee27462dda964c7745fddc7" dependencies = [ "bitflags", "itertools 0.8.2", - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "syn", ] @@ -3758,8 +3622,8 @@ checksum = "e63e6744142336dfb606fe2b068afa2e1cca1ee6a5d8377277a92945d81fa331" dependencies = [ "bitflags", "itertools 0.8.2", - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "syn", ] @@ -3851,24 +3715,18 @@ dependencies = [ "enso-text", "failure", "parser", - "wasm-bindgen-test 0.3.8", + "wasm-bindgen-test", ] -[[package]] -name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - [[package]] name = "syn" version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2afee18b8beb5a596ecb4a2dce128c719b4ba399d34126b9e4396e3f9860966" dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", - "unicode-xid 0.2.2", + "proc-macro2", + "quote", + "unicode-xid", ] [[package]] @@ -3877,10 +3735,10 @@ version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "syn", - "unicode-xid 0.2.2", + "unicode-xid", ] [[package]] @@ -3927,8 +3785,8 @@ version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "syn", ] @@ -4024,8 +3882,8 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e44da00bfc73a25f814cd8d7e57a68a5c31b74b3152a0a1d1f590c97ed06265a" dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "syn", ] @@ -4228,12 +4086,6 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" - [[package]] name = "unicode-xid" version = "0.2.2" @@ -4290,12 +4142,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - [[package]] name = "version_check" version = "0.1.5" @@ -4362,25 +4208,12 @@ dependencies = [ "bumpalo", "lazy_static", "log 0.4.14", - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "syn", "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-futures" -version = "0.3.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83420b37346c311b9ed822af41ec2e82839bfe99867ec6c54e2da43b7538771c" -dependencies = [ - "cfg-if 0.1.10", - "futures 0.1.31", - "js-sys", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wasm-bindgen-futures" version = "0.4.8" @@ -4399,7 +4232,7 @@ version = "0.2.58" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "574094772ce6921576fb6f2e3f7497b8a76273b6db092be18fc48a082de09dc3" dependencies = [ - "quote 1.0.10", + "quote", "wasm-bindgen-macro-support", ] @@ -4409,8 +4242,8 @@ version = "0.2.58" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e85031354f25eaebe78bb7db1c3d86140312a911a106b2e29f9cc440ce3e7668" dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", @@ -4422,21 +4255,6 @@ version = "0.2.58" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f5e7e61fc929f4c0dddb748b102ebf9f632e2b8d739f2016542b4de2965a9601" -[[package]] -name = "wasm-bindgen-test" -version = "0.2.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2d9693b63a742d481c7f80587e057920e568317b2806988c59cd71618bc26c1" -dependencies = [ - "console_error_panic_hook", - "futures 0.1.31", - "js-sys", - "scoped-tls", - "wasm-bindgen", - "wasm-bindgen-futures 0.3.27", - "wasm-bindgen-test-macro 0.2.50", -] - [[package]] name = "wasm-bindgen-test" version = "0.3.8" @@ -4447,18 +4265,8 @@ dependencies = [ "js-sys", "scoped-tls", "wasm-bindgen", - "wasm-bindgen-futures 0.4.8", - "wasm-bindgen-test-macro 0.3.8", -] - -[[package]] -name = "wasm-bindgen-test-macro" -version = "0.2.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0789dac148a8840bbcf9efe13905463b733fa96543bfbf263790535c11af7ba5" -dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", + "wasm-bindgen-futures", + "wasm-bindgen-test-macro", ] [[package]] @@ -4467,8 +4275,8 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97837a6e83ab24a4b3a38d44a257e13335b54f4b4548b2c9d71edd0bf570cb4f" dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", ] [[package]] @@ -4480,8 +4288,8 @@ dependencies = [ "anyhow", "heck", "log 0.4.14", - "proc-macro2 1.0.32", - "quote 1.0.10", + "proc-macro2", + "quote", "syn", "wasm-bindgen-backend", "weedle", @@ -4506,31 +4314,6 @@ dependencies = [ "wasm-bindgen-webidl", ] -[[package]] -name = "web-test" -version = "0.1.0" -dependencies = [ - "enso-prelude", - "enso-web", - "ensogl", - "js-sys", - "shrinkwraprs 0.3.0", - "wasm-bindgen", - "wasm-bindgen-test 0.3.8", - "web-sys", - "web-test-proc-macro", -] - -[[package]] -name = "web-test-proc-macro" -version = "0.1.0" -dependencies = [ - "proc-macro2 1.0.32", - "quote 1.0.10", - "syn", - "wasm-bindgen-test 0.3.8", -] - [[package]] name = "websocket" version = "0.23.0" diff --git a/Cargo.toml b/Cargo.toml index 1e67980ccd..ff3f43c9a4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,97 +1,22 @@ [workspace] +# Listing only the "root" crates of each app/library. All path dependencies are included in the workspace automatically. +# If you want to add sub crate (like `app/gui/config` or `lib/rust/ensogl/example`), just add it as a path dependency +# where plausible. members = [ "app/gui", - "app/gui/controller", - "app/gui/controller/double-representation", - "app/gui/controller/engine-model", - "app/gui/controller/engine-protocol", - "app/gui/analytics", - "app/gui/config", - "app/gui/language/ast/impl", - "app/gui/language/ast/macros", - "app/gui/language/parser", - "app/gui/language/span-tree", - "app/gui/language/span-tree/example", - "app/gui/view", - "app/gui/view/debug_scene", - "app/gui/view/debug_scene/interface", - "app/gui/view/debug_scene/visualization", - "app/gui/view/graph-editor", - "app/gui/view/welcome-screen", "build/rust-scripts", - "lib/rust/automata", - "lib/rust/build-utils", - "lib/rust/callback", - "lib/rust/code-builder", - "lib/rust/config-reader", - "lib/rust/data-structures", - "lib/rust/ensogl", - "lib/rust/ensogl/app/theme/hardcoded", - "lib/rust/ensogl/core", - "lib/rust/ensogl/component", - "lib/rust/ensogl/component/drop-down-menu", - "lib/rust/ensogl/component/drop-manager", - "lib/rust/ensogl/component/file-browser", - "lib/rust/ensogl/component/gui", - "lib/rust/ensogl/component/label", - "lib/rust/ensogl/component/list-view", - "lib/rust/ensogl/component/scroll-area", - "lib/rust/ensogl/component/scrollbar", - "lib/rust/ensogl/component/selector", - "lib/rust/ensogl/component/shadow", - "lib/rust/ensogl/component/text", - "lib/rust/ensogl/component/text/embedded-fonts", - "lib/rust/ensogl/component/text/msdf-sys", - "lib/rust/ensogl/component/toggle-button", - "lib/rust/ensogl/example", - "lib/rust/ensogl/example/animation", - "lib/rust/ensogl/example/complex-shape-system", - "lib/rust/ensogl/example/dom-symbols", - "lib/rust/ensogl/example/drop-manager", - "lib/rust/ensogl/example/easing-animator", - "lib/rust/ensogl/example/glyph-system", - "lib/rust/ensogl/example/list-view", - "lib/rust/ensogl/example/mouse-events", - "lib/rust/ensogl/example/scroll-area", - "lib/rust/ensogl/example/shape-system", - "lib/rust/ensogl/example/slider", - "lib/rust/ensogl/example/sprite-system", - "lib/rust/ensogl/example/sprite-system-benchmark", - "lib/rust/ensogl/example/stats", - "lib/rust/ensogl/example/text-area", - "lib/rust/frp", - "lib/rust/fuzzly", - "lib/rust/generics", - "lib/rust/json-rpc", - "lib/rust/launcher-shims", - "lib/rust/logger", - "lib/rust/macro-utils", - "lib/rust/optics", - "lib/rust/parser", - "lib/rust/parser/ast", - "lib/rust/parser/flexer", - "lib/rust/prelude", - "lib/rust/profiler", - "lib/rust/profiler/macros", - "lib/rust/parser/flexer-testing/definition", - "lib/rust/parser/flexer-testing/generation", - "lib/rust/parser/lexer/definition", - "lib/rust/parser/lexer/generation", - "lib/rust/parser/parser-jni", - "lib/rust/parser/lazy-reader", - "lib/rust/shapely/impl", - "lib/rust/shapely/macros", - "lib/rust/shortcuts", - "lib/rust/shortcuts/example", - "lib/rust/text", - "lib/rust/types", - "lib/rust/web", - "lib/rust/not-used/eval-tt", - "lib/rust/not-used/web-test", - "lib/rust/not-used/web-test-proc-macro", + "lib/rust/*", + "lib/rust/not-used/*", + "integration-test" ] +# This directory is not a crate +exclude = ["lib/rust/not-used"] + +# The default memebers are those we want to check and test by default. +default-members = ["app/gui", "lib/rust/*"] + [profile.dev] opt-level = 0 lto = false @@ -115,3 +40,7 @@ opt-level = 0 lto = false debug = true debug-assertions = true + +[profile.integration-test] +inherits = "test" +opt-level = 2 diff --git a/app/gui/Cargo.toml b/app/gui/Cargo.toml index 097f458bb4..aeae241455 100644 --- a/app/gui/Cargo.toml +++ b/app/gui/Cargo.toml @@ -18,7 +18,7 @@ enso-frp = { path = "../../lib/rust/frp" } enso-logger = { path = "../../lib/rust/logger"} enso-prelude = { path = "../../lib/rust/prelude"} enso-profiler = { path = "../../lib/rust/profiler" } -enso-shapely = { path = "../../lib/rust/shapely/impl"} +enso-shapely = { path = "../../lib/rust/shapely"} enso-text = { path = "../../lib/rust/text" } enso-web = { path = "../../lib/rust/web" } ensogl = { path = "../../lib/rust/ensogl" } diff --git a/app/gui/controller/double-representation/src/alias_analysis.rs b/app/gui/controller/double-representation/src/alias_analysis.rs index e804a9b580..b76ff899b6 100644 --- a/app/gui/controller/double-representation/src/alias_analysis.rs +++ b/app/gui/controller/double-representation/src/alias_analysis.rs @@ -376,7 +376,7 @@ mod tests { name: impl Str, ast: &Ast, expected: Vec>, - actual: &Vec, + actual: &[LocatedName], ) { let mut checker = IdentifierValidator::new(name, ast, expected); checker.validate_identifiers(actual); diff --git a/app/gui/controller/double-representation/src/alias_analysis/test_utils.rs b/app/gui/controller/double-representation/src/alias_analysis/test_utils.rs index e9e118ec17..2b15b25c76 100644 --- a/app/gui/controller/double-representation/src/alias_analysis/test_utils.rs +++ b/app/gui/controller/double-representation/src/alias_analysis/test_utils.rs @@ -149,8 +149,8 @@ impl<'a> IdentifierValidator<'a> { let crumbs = &identifier.crumbs; let ast_result = self.ast.get_traversing(crumbs); let ast = ast_result.expect("failed to retrieve ast from crumb"); - let name_err = || iformat!("Failed to use AST {ast.repr()} as an identifier name"); - let name = NormalizedName::try_from_ast(ast).expect(&name_err()); + let name_err = || ipanic!("Failed to use AST {ast.repr()} as an identifier name"); + let name = NormalizedName::try_from_ast(ast).unwrap_or_else(name_err); assert_eq!(name, identifier.item) } } diff --git a/app/gui/controller/double-representation/src/connection.rs b/app/gui/controller/double-representation/src/connection.rs index 6576f1ae17..32cc1cb312 100644 --- a/app/gui/controller/double-representation/src/connection.rs +++ b/app/gui/controller/double-representation/src/connection.rs @@ -168,7 +168,7 @@ mod tests { impl TestRun { fn from_definition(definition: DefinitionInfo) -> TestRun { - let graph = GraphInfo::from_definition(definition.clone()); + let graph = GraphInfo::from_definition(definition); let repr_of = |connection: &Connection| { let endpoint = &connection.source; let node = graph.find_node(endpoint.node).unwrap(); @@ -177,7 +177,7 @@ mod tests { }; let mut connections = graph.connections(); - connections.sort_by(|lhs, rhs| repr_of(&lhs).cmp(&repr_of(&rhs))); + connections.sort_by_key(|con| repr_of(con)); TestRun { graph, connections } } @@ -273,7 +273,7 @@ f = fun 2"; for node in nodes { let node_repr = node.ast().repr(); let expected = expected_dependent_nodes.get(node_repr.as_str()).unwrap(); - let result = dependent_nodes_in_def(&graph.source.body().item, node.id()); + let result = dependent_nodes_in_def(graph.source.body().item, node.id()); let result_node = result.iter().map(|id| graph.find_node(*id).unwrap()); let mut result_repr = result_node.map(|n| n.ast().repr()).collect_vec(); result_repr.sort(); diff --git a/app/gui/controller/double-representation/src/definition.rs b/app/gui/controller/double-representation/src/definition.rs index 42d32fe016..cf1157bb2e 100644 --- a/app/gui/controller/double-representation/src/definition.rs +++ b/app/gui/controller/double-representation/src/definition.rs @@ -556,7 +556,7 @@ mod tests { assert_eq!(lhs, rhs) } - fn to_names(defs: &Vec) -> Vec { + fn to_names(defs: &[DefinitionInfo]) -> Vec { defs.iter().map(|def| def.name.to_string()).collect() } diff --git a/app/gui/controller/double-representation/src/graph.rs b/app/gui/controller/double-representation/src/graph.rs index 2d40cb26ba..2e4d227247 100644 --- a/app/gui/controller/double-representation/src/graph.rs +++ b/app/gui/controller/double-representation/src/graph.rs @@ -222,7 +222,7 @@ mod tests { fn find_graph(parser: &parser::Parser, program: impl Str, name: impl Str) -> GraphInfo { let module = parser.parse_module(program.into(), default()).unwrap(); - let crumbs = name.into().split(".").map(|name| DefinitionName::new_plain(name)).collect(); + let crumbs = name.into().split('.').map(DefinitionName::new_plain).collect(); let id = Id { crumbs }; let definition = get_definition(&module, &id).unwrap(); GraphInfo::from_definition(definition) @@ -230,7 +230,7 @@ mod tests { #[wasm_bindgen_test] fn detect_a_node() { - let mut parser = parser::Parser::new_or_panic(); + let parser = parser::Parser::new_or_panic(); // Each of these programs should have a `main` definition with a single `2+2` node. let programs = vec![ "main = 2+2", @@ -239,7 +239,7 @@ mod tests { "main = \n foo = 2+2\n bar b = 2+2", // `bar` is a definition, not a node ]; for program in programs { - let graph = main_graph(&mut parser, program); + let graph = main_graph(&parser, program); let nodes = graph.nodes(); assert_eq!(nodes.len(), 1); let node = &nodes[0]; @@ -300,14 +300,14 @@ mod tests { foo = node foo a = not_node print "hello""#; - let mut parser = parser::Parser::new_or_panic(); - let mut graph = main_graph(&mut parser, program); + let parser = parser::Parser::new_or_panic(); + let mut graph = main_graph(&parser, program); - let node_to_add0 = new_expression_node(&mut parser, "4 + 4"); - let node_to_add1 = new_expression_node(&mut parser, "a + b"); - let node_to_add2 = new_expression_node(&mut parser, "x * x"); - let node_to_add3 = new_expression_node(&mut parser, "x / x"); - let node_to_add4 = new_expression_node(&mut parser, "2 - 2"); + let node_to_add0 = new_expression_node(&parser, "4 + 4"); + let node_to_add1 = new_expression_node(&parser, "a + b"); + let node_to_add2 = new_expression_node(&parser, "x * x"); + let node_to_add3 = new_expression_node(&parser, "x / x"); + let node_to_add4 = new_expression_node(&parser, "2 - 2"); graph.add_node(&node_to_add0, LocationHint::Start).unwrap(); graph.add_node(&node_to_add1, LocationHint::Before(graph.nodes()[0].id())).unwrap(); @@ -339,7 +339,7 @@ mod tests { x / x"#; graph.expect_code(expected_code); - let mut graph = find_graph(&mut parser, program, "main.foo"); + let mut graph = find_graph(&parser, program, "main.foo"); assert_eq!(graph.nodes().len(), 1); graph.add_node(&node_to_add4, LocationHint::Start).unwrap(); assert_eq!(graph.nodes().len(), 2); @@ -359,14 +359,14 @@ mod tests { node2 foo = 5"; - let mut parser = parser::Parser::new_or_panic(); - let mut graph = main_graph(&mut parser, program); + let parser = parser::Parser::new_or_panic(); + let mut graph = main_graph(&parser, program); let id2 = graph.nodes()[0].id(); - let node_to_add0 = new_expression_node(&mut parser, "node0"); - let node_to_add1 = new_expression_node(&mut parser, "node1"); - let node_to_add3 = new_expression_node(&mut parser, "node3"); - let node_to_add4 = new_expression_node(&mut parser, "node4"); + let node_to_add0 = new_expression_node(&parser, "node0"); + let node_to_add1 = new_expression_node(&parser, "node1"); + let node_to_add3 = new_expression_node(&parser, "node3"); + let node_to_add4 = new_expression_node(&parser, "node4"); graph.add_node(&node_to_add0, LocationHint::Start).unwrap(); graph.add_node(&node_to_add1, LocationHint::Before(id2)).unwrap(); @@ -387,7 +387,7 @@ foo = 5"; #[wasm_bindgen_test] fn multiple_node_graph() { - let mut parser = parser::Parser::new_or_panic(); + let parser = parser::Parser::new_or_panic(); let program = r" main = ## Faux docstring @@ -403,7 +403,7 @@ main = // TODO [mwu] // Add case like `Int.+ a = not_node` once https://github.com/enso-org/enso/issues/565 is fixed - let graph = main_graph(&mut parser, program); + let graph = main_graph(&parser, program); let nodes = graph.nodes(); assert_eq!(nodes[0].documentation_text(), Some(" Docstring 0".into())); assert_eq!(nodes[0].ast().repr(), "foo = node0"); @@ -418,12 +418,12 @@ main = #[wasm_bindgen_test] fn removing_node_from_graph() { - let mut parser = parser::Parser::new_or_panic(); + let parser = parser::Parser::new_or_panic(); let program = r" main = foo = 2 + 2 bar = 3 + 17"; - let mut graph = main_graph(&mut parser, program); + let mut graph = main_graph(&parser, program); let nodes = graph.nodes(); assert_eq!(nodes.len(), 2); assert_eq!(nodes[0].expression().repr(), "2 + 2"); @@ -444,11 +444,11 @@ main = #[wasm_bindgen_test] fn removing_last_node_from_graph() { - let mut parser = parser::Parser::new_or_panic(); + let parser = parser::Parser::new_or_panic(); let program = r" main = foo = 2 + 2"; - let mut graph = main_graph(&mut parser, program); + let mut graph = main_graph(&parser, program); DEBUG!("aa"); let (node,) = graph.nodes().expect_tuple(); assert_eq!(node.expression().repr(), "2 + 2"); @@ -464,7 +464,7 @@ main = #[wasm_bindgen_test] fn editing_nodes_expression_in_graph() { - let mut parser = parser::Parser::new_or_panic(); + let parser = parser::Parser::new_or_panic(); let program = r" main = foo = 2 + 2 @@ -472,7 +472,7 @@ main = let new_expression = parser.parse("print \"HELLO\"".to_string(), default()).unwrap(); let new_expression = expect_single_line(&new_expression).clone(); - let mut graph = main_graph(&mut parser, program); + let mut graph = main_graph(&parser, program); let nodes = graph.nodes(); assert_eq!(nodes.len(), 2); assert_eq!(nodes[0].expression().repr(), "2 + 2"); diff --git a/app/gui/controller/double-representation/src/lib.rs b/app/gui/controller/double-representation/src/lib.rs index 06c6eff6eb..a2009bc627 100644 --- a/app/gui/controller/double-representation/src/lib.rs +++ b/app/gui/controller/double-representation/src/lib.rs @@ -212,7 +212,7 @@ mod tests { let code = DocumentationCommentInfo::text_to_repr(main.indent(), &text); let ast2 = parser.parse_line(&code).unwrap(); let doc2 = DocumentationCommentInfo::new(&ast2.as_ref(), main.indent()) - .expect(&format!("Failed to parse `{}` as comment", code)); + .unwrap_or_else(|| panic!("Failed to parse `{code}` as comment")); assert_eq!(doc.line().repr(), doc2.line().repr()) } diff --git a/app/gui/controller/double-representation/src/module.rs b/app/gui/controller/double-representation/src/module.rs index 0526fa13a5..561bc65b5b 100644 --- a/app/gui/controller/double-representation/src/module.rs +++ b/app/gui/controller/double-representation/src/module.rs @@ -997,11 +997,11 @@ main = here.method1 10"#; repr_after_insertion(Placement::Begin) ); assert_eq!( - repr_after_insertion(Placement::After(method1_id.clone())), + repr_after_insertion(Placement::After(method1_id)), repr_after_insertion(Placement::Before(main_id.clone())) ); assert_eq!( - repr_after_insertion(Placement::After(main_id.clone())), + repr_after_insertion(Placement::After(main_id)), repr_after_insertion(Placement::End) ); diff --git a/app/gui/controller/double-representation/src/refactorings/collapse.rs b/app/gui/controller/double-representation/src/refactorings/collapse.rs index 6fd8c01c9a..49e1ddc5bd 100644 --- a/app/gui/controller/double-representation/src/refactorings/collapse.rs +++ b/app/gui/controller/double-representation/src/refactorings/collapse.rs @@ -418,7 +418,7 @@ mod tests { let main_crumb = Crumb::from(main.crumb()); module.ast = module.ast.set(&main_crumb, new_main.ast().clone()).unwrap(); module.add_method(collapsed.new_method, placement, parser).unwrap(); - ast::test_utils::assert_unique_ids(&module.ast.as_ref()); + ast::test_utils::assert_unique_ids(module.ast.as_ref()); info!(logger, "Updated method:\n{&module.ast}"); assert_eq!(new_method.repr(), self.expected_generated); assert_eq!(new_main.repr(), self.expected_refactored); diff --git a/app/gui/controller/engine-protocol/Cargo.toml b/app/gui/controller/engine-protocol/Cargo.toml index bee480aa1d..9e7644c1a5 100644 --- a/app/gui/controller/engine-protocol/Cargo.toml +++ b/app/gui/controller/engine-protocol/Cargo.toml @@ -11,7 +11,7 @@ crate-type = ["cdylib", "rlib"] enso-data-structures = { path = "../../../../lib/rust/data-structures" } enso-logger = { path = "../../../../lib/rust/logger"} enso-prelude = { path = "../../../../lib/rust/prelude"} -enso-shapely = { path = "../../../../lib/rust/shapely/impl"} +enso-shapely = { path = "../../../../lib/rust/shapely"} enso-text = { path = "../../../../lib/rust/text"} json-rpc = { path = "../../../../lib/rust/json-rpc" } chrono = { version = "0.4", features = ["serde"] } diff --git a/app/gui/controller/engine-protocol/src/binary/client.rs b/app/gui/controller/engine-protocol/src/binary/client.rs index 4163f11714..508cd54a4f 100644 --- a/app/gui/controller/engine-protocol/src/binary/client.rs +++ b/app/gui/controller/engine-protocol/src/binary/client.rs @@ -317,7 +317,7 @@ mod tests { let mock_error_message = "This is error".to_string(); let mut mock_reply = MessageFromServer::new(FromServerPayloadOwned::Error { code: mock_error_code, - message: mock_error_message.clone(), + message: mock_error_message, data: None, }); mock_reply.correlation_id = Some(generated_message.message_id); @@ -359,7 +359,7 @@ mod tests { |client| client.read_file(&path), data.clone(), ToServerPayloadOwned::ReadFile { path: path.clone() }, - FromServerPayloadOwned::FileContentsReply { contents: data.clone() }, + FromServerPayloadOwned::FileContentsReply { contents: data }, ); } @@ -384,8 +384,8 @@ mod tests { }; let data = Vec::from("Hello".as_bytes()); let message = MessageFromServer::new(FromServerPayloadOwned::VisualizationUpdate { - data: data.clone(), - context: context.clone(), + data: data.clone(), + context, }); diff --git a/app/gui/controller/engine-protocol/src/language_server/tests.rs b/app/gui/controller/engine-protocol/src/language_server/tests.rs index 3720253729..1c4affb42b 100644 --- a/app/gui/controller/engine-protocol/src/language_server/tests.rs +++ b/app/gui/controller/engine-protocol/src/language_server/tests.rs @@ -346,7 +346,7 @@ fn test_computed_value_update() { assert_eq!(expression_updates.context_id, context_id); let update = &expression_updates.updates.first().unwrap(); assert_eq!(update.expression_id, id); - assert_eq!(update.typename.as_ref().map(|ty| ty.as_str()), Some(typename)); + assert_eq!(update.typename.as_deref(), Some(typename)); assert!(update.method_pointer.is_none()); assert!(update.from_cache); assert!(matches!(update.payload, ExpressionUpdatePayload::Value)) diff --git a/app/gui/controller/engine-protocol/src/project_manager.rs b/app/gui/controller/engine-protocol/src/project_manager.rs index 4088415b6c..968212c696 100644 --- a/app/gui/controller/engine-protocol/src/project_manager.rs +++ b/app/gui/controller/engine-protocol/src/project_manager.rs @@ -392,7 +392,7 @@ mod remote_client_tests { let project_id = Uuid::default(); let missing_component_action = MissingComponentAction::Install; let engine_version = "1.0.0".to_owned(); - let engine_version_opt = Some(engine_version.clone()); + let engine_version_opt = Some(engine_version); let create_project_response = response::CreateProject { project_id }; let project_id_json = json!({"projectId":"00000000-0000-0000-0000-000000000000"}); let project_id_and_mca = json!({ diff --git a/app/gui/docs/CONTRIBUTING.md b/app/gui/docs/CONTRIBUTING.md index 05ed2dd52a..f189693f0d 100644 --- a/app/gui/docs/CONTRIBUTING.md +++ b/app/gui/docs/CONTRIBUTING.md @@ -152,6 +152,8 @@ The subdirectories of interests are: paradigm in rust. - `build`: All building scripts and utilities, mostly the logic of the `./run` script. +- `integration-test`: A single crate with all integration tests of our + applications. Other directories are auto-generated `dist` and `target`, or (currently) are the Engine files, which will be moved to `app/engine` soon. @@ -278,6 +280,19 @@ have prepared several scripts which maximally automate the process: [official source](https://chromedriver.chromium.org/downloads) and ensure it is in your `PATH`. +- **Integration Tests** The integration tests are gathered in `integration-test` + crate. One test suite can be run with + `node ./run integration-test -- --test `. This will spawn required + Engine process and then set up a server on localhost:8000 - open the page in + Chrome browser to see the tests running. The `` is a name of the + file in `integration-test/tests` directory without extension, for example + `graph_editor`. + - The integration test can create and leave new Enso projects. **Keep it in + mind when running the script with your own backend (the `--no-backend` + option)**. The Engine spawned by the script will use a dedicated workspace + created in temporary directory, so the user workspace will not be affected. + - Note: in the future there will be possibility to run all tests suite + headlessly. - **Linting** Please be sure to fix all errors reported by `node ./run lint` before creating a pull request to this repository. @@ -285,7 +300,7 @@ have prepared several scripts which maximally automate the process: The following branches are used to develop the product: -- **wip/[initials]/[feature]** +- **wip/[github_user_name]/[feature]** Feature branches. These are temporary branches used by the team to develop a particular feature. - **develop** diff --git a/app/gui/language/ast/impl/Cargo.toml b/app/gui/language/ast/impl/Cargo.toml index 212e0753ad..c1f525a2a8 100644 --- a/app/gui/language/ast/impl/Cargo.toml +++ b/app/gui/language/ast/impl/Cargo.toml @@ -20,4 +20,4 @@ ast-macros = { path = "../macros" } enso-data-structures = { path = "../../../../../lib/rust/data-structures" } enso-text = { path = "../../../../../lib/rust/text" } enso-prelude = { path = "../../../../../lib/rust/prelude" } -enso-shapely = { path = "../../../../../lib/rust/shapely/impl" } +enso-shapely = { path = "../../../../../lib/rust/shapely" } diff --git a/app/gui/language/ast/impl/src/assoc.rs b/app/gui/language/ast/impl/src/assoc.rs index 552ad056a2..73737449e4 100644 --- a/app/gui/language/ast/impl/src/assoc.rs +++ b/app/gui/language/ast/impl/src/assoc.rs @@ -74,11 +74,11 @@ mod tests { #[test] fn test_applicative() { - assert_eq!(is_applicative("<$>"), true); - assert_eq!(is_applicative("<*>"), true); - assert_eq!(is_applicative("<*"), true); - assert_eq!(is_applicative("*>"), true); - assert_eq!(is_applicative("="), false); - assert_eq!(is_applicative("++"), false); + assert!(is_applicative("<$>")); + assert!(is_applicative("<*>")); + assert!(is_applicative("<*")); + assert!(is_applicative("*>")); + assert!(!is_applicative("=")); + assert!(!is_applicative("++")); } } diff --git a/app/gui/language/ast/impl/src/crumbs.rs b/app/gui/language/ast/impl/src/crumbs.rs index a1a869ddcc..2d277d7867 100644 --- a/app/gui/language/ast/impl/src/crumbs.rs +++ b/app/gui/language/ast/impl/src/crumbs.rs @@ -1723,14 +1723,8 @@ mod tests { set(to_crumb_enum, &infix, InfixCrumb::LeftOperand, baz.clone())?.repr(), "baz + bar" ); - assert_eq!( - set(to_crumb_enum, &infix, InfixCrumb::Operator, times.clone())?.repr(), - "foo * bar" - ); - assert_eq!( - set(to_crumb_enum, &infix, InfixCrumb::RightOperand, baz.clone())?.repr(), - "foo + baz" - ); + assert_eq!(set(to_crumb_enum, &infix, InfixCrumb::Operator, times)?.repr(), "foo * bar"); + assert_eq!(set(to_crumb_enum, &infix, InfixCrumb::RightOperand, baz)?.repr(), "foo + baz"); Ok(()) } @@ -1935,8 +1929,8 @@ mod tests { assert_eq!(get(PrefixCrumb::Func)?.repr(), "func"); assert_eq!(get(PrefixCrumb::Arg)?.repr(), "arg"); - assert_eq!(set(PrefixCrumb::Func, foo.clone())?.repr(), "foo arg"); - assert_eq!(set(PrefixCrumb::Arg, x.clone())?.repr(), "func x"); + assert_eq!(set(PrefixCrumb::Func, foo)?.repr(), "foo arg"); + assert_eq!(set(PrefixCrumb::Arg, x)?.repr(), "func x"); Ok(()) } @@ -1975,8 +1969,8 @@ mod tests { assert_eq!(get(SectionLeftCrumb::Arg)?.repr(), "foo"); assert_eq!(get(SectionLeftCrumb::Opr)?.repr(), "bar"); - assert_eq!(set(SectionLeftCrumb::Arg, arg.clone())?.repr(), "arg bar"); - assert_eq!(set(SectionLeftCrumb::Opr, opr.clone())?.repr(), "foo opr"); + assert_eq!(set(SectionLeftCrumb::Arg, arg)?.repr(), "arg bar"); + assert_eq!(set(SectionLeftCrumb::Opr, opr)?.repr(), "foo opr"); Ok(()) } @@ -2014,8 +2008,8 @@ mod tests { assert_eq!(get(SectionRightCrumb::Opr)?.repr(), "foo"); assert_eq!(get(SectionRightCrumb::Arg)?.repr(), "bar"); - assert_eq!(set(SectionRightCrumb::Opr, opr.clone())?.repr(), "opr bar"); - assert_eq!(set(SectionRightCrumb::Arg, arg.clone())?.repr(), "foo arg"); + assert_eq!(set(SectionRightCrumb::Opr, opr)?.repr(), "opr bar"); + assert_eq!(set(SectionRightCrumb::Arg, arg)?.repr(), "foo arg"); Ok(()) } @@ -2050,7 +2044,7 @@ mod tests { assert_eq!(app.repr(), "foo"); assert_eq!(get(SectionSidesCrumb)?.repr(), "foo"); - assert_eq!(set(SectionSidesCrumb, opr.clone())?.repr(), "opr"); + assert_eq!(set(SectionSidesCrumb, opr)?.repr(), "opr"); Ok(()) } @@ -2132,14 +2126,14 @@ mod tests { elem: Shifted { off: 0, wrapped: var.clone() }, })); let body = Rc::new(MacroPatternMatchRaw::Seq(MacroPatternMatchRawSeq { - pat: MacroPatternRawSeq { pat1: pat.clone(), pat2: pat.clone() }, - elem: (tok.clone(), tok.clone()), + pat: MacroPatternRawSeq { pat1: pat.clone(), pat2: pat }, + elem: (tok.clone(), tok), })); let segs = ShiftedVec1 { head: MacroMatchSegment { head: var.clone(), body: body.clone() }, tail: vec![], }; - Match { pfx: Some(body), segs, resolved: Some(var.clone()) } + Match { pfx: Some(body), segs, resolved: Some(var) } } #[test] diff --git a/app/gui/language/ast/impl/src/opr.rs b/app/gui/language/ast/impl/src/opr.rs index 89f21dd199..842e09e5b9 100644 --- a/app/gui/language/ast/impl/src/opr.rs +++ b/app/gui/language/ast/impl/src/opr.rs @@ -545,7 +545,7 @@ mod tests { let b = Ast::var("b"); let c = Ast::var("c"); let a_plus_b = Ast::infix(a.clone(), "+", b.clone()); - let a_plus_b_plus_c = Ast::infix(a_plus_b.clone(), "+", c.clone()); + let a_plus_b_plus_c = Ast::infix(a_plus_b, "+", c.clone()); let chain = Chain::try_new(&a_plus_b_plus_c).unwrap(); expect_at(&chain.target, &a); expect_at(&chain.args[0].operand, &b); @@ -560,7 +560,7 @@ mod tests { let b = Ast::var("b"); let c = Ast::var("c"); let b_comma_c = Ast::infix(b.clone(), ",", c.clone()); - let a_comma_b_comma_c = Ast::infix(a.clone(), ",", b_comma_c.clone()); + let a_comma_b_comma_c = Ast::infix(a.clone(), ",", b_comma_c); let chain = Chain::try_new(&a_comma_b_comma_c).unwrap(); expect_at(&chain.target, &c); expect_at(&chain.args[0].operand, &b); diff --git a/app/gui/language/ast/impl/src/prefix.rs b/app/gui/language/ast/impl/src/prefix.rs index c7e023a324..a585173647 100644 --- a/app/gui/language/ast/impl/src/prefix.rs +++ b/app/gui/language/ast/impl/src/prefix.rs @@ -281,7 +281,7 @@ mod tests { } { - let mut chain = chain.clone(); + let mut chain = chain; chain.insert_arg(4, arg("arg")); assert_eq!(chain.repr(), "a b c _ _ arg"); } diff --git a/app/gui/language/parser/src/api.rs b/app/gui/language/parser/src/api.rs index de8392d9e1..59479eadc1 100644 --- a/app/gui/language/parser/src/api.rs +++ b/app/gui/language/parser/src/api.rs @@ -289,7 +289,7 @@ mod test { {expected_metadata}"# ); - assert_eq!(serialized.content, expected_content.to_string()); + assert_eq!(serialized.content, expected_content); assert_eq!(serialized.code_slice(), "main = 2 + 2"); assert_eq!(serialized.id_map_slice(), expected_id_map.as_str()); assert_eq!(serialized.metadata_slice(), expected_metadata.as_str()); diff --git a/app/gui/language/parser/tests/ast.rs b/app/gui/language/parser/tests/ast.rs index 2908b422b0..46e2bad465 100644 --- a/app/gui/language/parser/tests/ast.rs +++ b/app/gui/language/parser/tests/ast.rs @@ -80,7 +80,7 @@ pub fn flatten_prefix_test() { let case = |code: &str, expected_pieces: Vec<&str>| { let ast = parser.parse(code.into(), default()).unwrap(); let ast = ast::test_utils::expect_single_line(&ast); - let flattened = prefix::Chain::from_ast_non_strict(&ast); + let flattened = prefix::Chain::from_ast_non_strict(ast); expect_pieces(&flattened, expected_pieces); assert_eq!(flattened.repr(), code); }; @@ -107,7 +107,7 @@ pub fn flatten_infix_test() { let case = |code: &str, target: &str, expected_pieces: Vec<&str>| { let ast = parser.parse(code.into(), default()).unwrap(); let ast = ast::test_utils::expect_single_line(&ast); - let flattened = opr::Chain::try_new(&ast).unwrap(); + let flattened = opr::Chain::try_new(ast).unwrap(); expect_pieces(&flattened, target, expected_pieces); }; diff --git a/app/gui/language/parser/tests/parsing.rs b/app/gui/language/parser/tests/parsing.rs index ae17c05920..6ecabcce14 100644 --- a/app/gui/language/parser/tests/parsing.rs +++ b/app/gui/language/parser/tests/parsing.rs @@ -82,7 +82,7 @@ impl Fixture { fn test_shape(&mut self, program: &str, tester: F) where for<'t> &'t Shape: TryInto<&'t T>, - F: FnOnce(&T) -> (), { + F: FnOnce(&T), { let ast = self.parser.parse_line_ast(program).unwrap(); let shape = expect_shape(&ast); tester(shape); @@ -203,7 +203,7 @@ impl Fixture { } fn test_text_fmt_segment(&mut self, program: &str, tester: F) - where F: FnOnce(&SegmentFmt) -> () { + where F: FnOnce(&SegmentFmt) { self.test_shape(program, |shape: &TextLineFmt| { let (segment,) = (&shape.text).expect_tuple(); tester(segment) @@ -357,7 +357,7 @@ impl Fixture { assert_eq!(block.ty, BlockType::Continuous {}); assert_eq!(block.indent, 1); assert_eq!(block.empty_lines.len(), 0); - assert_eq!(block.is_orphan, true); + assert!(block.is_orphan); let first_line = &block.first_line; assert_eq!(first_line.off, 0); @@ -501,7 +501,7 @@ fn nested_macros() { main = operator13 = Json.from_pairs [["a", 42], ["foo", [1,2,3]]] var1 = [operator13, operator13]"#; - roundtrip_program_with(&parser, &program); + roundtrip_program_with(&parser, program); let program = r#"triplets n = 1.up_to n . to_vector . flat_map a-> a+1 . up_to n . to_vector . flat_map b-> @@ -510,7 +510,7 @@ main = n = 10 here.triplets n IO.println(here.triplets n)"#; - roundtrip_program_with(&parser, &program); + roundtrip_program_with(&parser, program); } #[wasm_bindgen_test] diff --git a/app/gui/language/span-tree/src/action.rs b/app/gui/language/span-tree/src/action.rs index 887d9d23fd..d53cdb9be7 100644 --- a/app/gui/language/span-tree/src/action.rs +++ b/app/gui/language/span-tree/src/action.rs @@ -257,9 +257,9 @@ mod test { let ast_id = ast.id; let tree = ast.generate_tree(&context::Empty).unwrap(): SpanTree; let node = tree.root_ref().find_by_span(&self.span.clone().into()); - let node = node.expect( - format!("Invalid case {:?}: no node with span {:?}", self, self.span).as_str(), - ); + let node = node.unwrap_or_else(|| { + panic!("Invalid case {:?}: no node with span {:?}", self, self.span) + }); let arg = Ast::new(ast::Var { name: "foo".to_string() }, None); let result = match &self.action { Set => node.set(&ast, arg), @@ -341,9 +341,9 @@ mod test { let ast = parser.parse_line_ast(self.expr).unwrap(); let tree: SpanTree = ast.generate_tree(&context::Empty).unwrap(); let node = tree.root_ref().find_by_span(&self.span.clone().into()); - let node = node.expect( - format!("Invalid case {:?}: no node with span {:?}", self, self.span).as_str(), - ); + let node = node.unwrap_or_else(|| { + panic!("Invalid case {:?}: no node with span {:?}", self, self.span) + }); let expected: HashSet = self.expected.iter().cloned().collect(); for action in &[Set, Erase] { diff --git a/app/gui/language/span-tree/src/generate.rs b/app/gui/language/span-tree/src/generate.rs index c08d525d98..3f374e5fe4 100644 --- a/app/gui/language/span-tree/src/generate.rs +++ b/app/gui/language/span-tree/src/generate.rs @@ -1023,9 +1023,8 @@ mod test { // === Partial application chain - this argument === let ast = parser.parse_line_ast("here.foo").unwrap(); - let invocation_info = CalledMethodInfo { - parameters: vec![this_param.clone(), param1.clone(), param2.clone()], - }; + let invocation_info = + CalledMethodInfo { parameters: vec![this_param, param1.clone(), param2.clone()] }; let ctx = MockContext::new_single(ast.id.unwrap(), invocation_info); let mut tree = SpanTree::new(&ast, &ctx).unwrap(): SpanTree; match tree.root_ref().leaf_iter().collect_vec().as_slice() { @@ -1056,9 +1055,9 @@ mod test { fn segment_body_crumbs( index: usize, - pattern_crumb: &Vec, + pattern_crumb: &[PatternMatchCrumb], ) -> ast::crumbs::MatchCrumb { - let val = ast::crumbs::SegmentMatchCrumb::Body { val: pattern_crumb.clone() }; + let val = ast::crumbs::SegmentMatchCrumb::Body { val: pattern_crumb.to_vec() }; ast::crumbs::MatchCrumb::Segs { val, index } } diff --git a/app/gui/language/span-tree/src/node.rs b/app/gui/language/span-tree/src/node.rs index 0015d1057e..0ab55dc1b4 100644 --- a/app/gui/language/span-tree/src/node.rs +++ b/app/gui/language/span-tree/src/node.rs @@ -927,7 +927,7 @@ mod test { for case in cases { let (crumbs, expected_crumbs, expected_remaining_ast_crumbs) = case; - let result = root.clone().get_descendant_by_ast_crumbs(&crumbs).unwrap(); + let result = root.clone().get_descendant_by_ast_crumbs(crumbs).unwrap(); assert_eq!(result.node.crumbs.as_slice(), *expected_crumbs); assert_eq!(result.ast_crumbs, expected_remaining_ast_crumbs.as_slice()); } diff --git a/app/gui/src/controller/searcher.rs b/app/gui/src/controller/searcher.rs index a5e5ae5619..d97eb4228f 100644 --- a/app/gui/src/controller/searcher.rs +++ b/app/gui/src/controller/searcher.rs @@ -1304,7 +1304,7 @@ pub mod test { let entry3 = model::suggestion_database::Entry { name: "testMethod1".to_string(), kind: Kind::Method, - self_type: Some(module_name.clone().into()), + self_type: Some(module_name.into()), scope: Scope::Everywhere, arguments: vec![ Argument { @@ -1796,7 +1796,7 @@ pub mod test { .use_suggestion(action::Suggestion::FromDatabase(f.entry1.clone())) .unwrap(); let new_parsed_input = - ParsedInput::new("var.testFunction1", &f.searcher.ide.parser()); + ParsedInput::new("var.testFunction1", f.searcher.ide.parser()); f.searcher.data.borrow_mut().input = new_parsed_input.unwrap(); }), // Variable name already present, need to use it. And not break it. diff --git a/app/gui/src/controller/upload.rs b/app/gui/src/controller/upload.rs index c432e5f0f2..071f9bfccd 100644 --- a/app/gui/src/controller/upload.rs +++ b/app/gui/src/controller/upload.rs @@ -706,8 +706,8 @@ mod test { fn data_dir_attributes() -> FileAttributes { let dummy_time = UTCDateTime::parse_from_rfc3339("1996-12-19T16:39:57-08:00").unwrap(); FileAttributes { - creation_time: dummy_time.clone(), - last_access_time: dummy_time.clone(), + creation_time: dummy_time, + last_access_time: dummy_time, last_modified_time: dummy_time, kind: FileSystemObject::Directory { name: DATA_DIR_NAME.to_owned(), diff --git a/app/gui/src/controller/visualization.rs b/app/gui/src/controller/visualization.rs index 69fb66d9da..667aebb37f 100644 --- a/app/gui/src/controller/visualization.rs +++ b/app/gui/src/controller/visualization.rs @@ -275,7 +275,7 @@ mod tests { vec![embedded_visualization, javascript_vis0, javascript_vis1]; let zipped = visualizations.iter().zip(expected_visualizations.iter()); for (visualization, expected_definition) in zipped { - let loaded_definition = vis_controller.load_visualization(&visualization).await; + let loaded_definition = vis_controller.load_visualization(visualization).await; let loaded_definition = loaded_definition.expect("Couldn't load visualization's content."); let loaded_signature = &loaded_definition.signature; diff --git a/app/gui/src/executor/global.rs b/app/gui/src/executor/global.rs index 333f7cd7ad..87789e940c 100644 --- a/app/gui/src/executor/global.rs +++ b/app/gui/src/executor/global.rs @@ -26,6 +26,41 @@ use crate::prelude::*; use futures::task::LocalSpawn; use futures::task::LocalSpawnExt; +/// Global spawner container. This structure is kept in the global variable `SPAWNER`. See module +/// docs for details. +struct GlobalSpawner { + logger: Logger, + spawner: RefCell>>, +} + +impl Default for GlobalSpawner { + fn default() -> Self { + Self { logger: Logger::new("GlobalSpawner"), spawner: default() } + } +} + +impl GlobalSpawner { + fn set_spawner(&self, spawner_to_set: impl LocalSpawn + 'static) { + info!(self.logger, "Setting new spawner"); + *self.spawner.borrow_mut() = Some(Box::new(spawner_to_set)) + } + + fn spawn(&self, f: impl Future + 'static) { + // Note [Global Executor Safety] + let mut borrowed = self.spawner.borrow_mut(); + if let Some(unwrapped) = borrowed.as_mut() { + if unwrapped.spawn_local(f).is_err() { + error!( + self.logger, + "Failed to spawn the task. Global executor might have been dropped." + ); + } + } else { + error!(self.logger, "Fail to spawn the task. No global executor has been provided.") + } + } +} + thread_local! { /// Global spawner handle. /// @@ -34,7 +69,7 @@ thread_local! { /// /// This is made thread local for tests which may be run in parallel; Each test should set /// executor independently. - static SPAWNER: RefCell>> = default(); + static SPAWNER: GlobalSpawner = default(); } /// Sets the global spawner. It will remain accessible until it is set again to @@ -44,21 +79,14 @@ thread_local! { /// time, so e.g. it must not drop the executor connected with this spawner. pub fn set_spawner(spawner_to_set: impl LocalSpawn + 'static) { // Note [Global Executor Safety] - SPAWNER.with(|s| *s.borrow_mut() = Some(Box::new(spawner_to_set))); + SPAWNER.with(|s| s.set_spawner(spawner_to_set)); } /// Spawns a task using the global spawner. /// Panics, if called when there is no global spawner set or if it fails to /// spawn task (e.g. because the connected executor was prematurely dropped). pub fn spawn(f: impl Future + 'static) { - SPAWNER.with(|spawner| { - let error_msg = "No global executor has been provided."; - // Note [Global Executor Safety] - let mut borrowed = spawner.borrow_mut(); - let unwrapped = borrowed.as_mut().expect(error_msg); - let error_msg = "Failed to spawn the task. Global executor might have been dropped."; - unwrapped.spawn_local(f).expect(error_msg); - }); + SPAWNER.with(|s| s.spawn(f)); } /// Process stream elements while object under `weak` handle exists. /// diff --git a/app/gui/src/ide.rs b/app/gui/src/ide.rs index b24d089839..4e0e913c95 100644 --- a/app/gui/src/ide.rs +++ b/app/gui/src/ide.rs @@ -10,7 +10,6 @@ use crate::presenter::Presenter; use analytics::AnonymousData; use enso_frp as frp; -use ensogl::application::Application; use ensogl::system::web::sleep; use std::time::Duration; @@ -36,26 +35,24 @@ const ALIVE_LOG_INTERVAL_SEC: u64 = 60; /// /// This structure is a root of all objects in our application. It includes both layers: /// Controllers and Views, and an integration between them. +#[allow(missing_docs)] #[derive(Debug)] pub struct Ide { - application: Application, - #[allow(dead_code)] - /// The presenter layer is never directly accessed, but needs to be kept alive to keep - /// performing its function. - presenter: Presenter, - network: frp::Network, + pub ensogl_app: ensogl::application::Application, + pub presenter: Presenter, + network: frp::Network, } impl Ide { /// Constructor. - pub async fn new( - application: Application, + pub fn new( + ensogl_app: ensogl::application::Application, view: ide_view::root::View, controller: controller::Ide, ) -> Self { let presenter = Presenter::new(controller, view); let network = frp::Network::new("Ide"); - Ide { application, presenter, network }.init() + Ide { ensogl_app, presenter, network }.init() } fn init(self) -> Self { @@ -65,7 +62,7 @@ impl Ide { fn alive_log_sending_loop(&self) -> impl Future + 'static { let network = &self.network; - let scene = self.application.display.scene(); + let scene = self.ensogl_app.display.scene(); let mouse = &scene.mouse.frp; let keyboard = &scene.keyboard.frp; @@ -90,6 +87,16 @@ impl Ide { } } +/// A reduced version of [`Ide`] structure, representing an application which failed to initialize. +/// +/// It contains only the view displaying the error. No connection to the backend is maintained. +#[allow(missing_docs)] +#[derive(Debug)] +pub struct FailedIde { + pub view: ide_view::root::View, +} + + /// The Path of the module initially opened after opening project in IDE. pub fn initial_module_path(project: &model::Project) -> FallibleResult { model::module::Path::from_name_segments(project.project_content_root_id(), &[ diff --git a/app/gui/src/ide/initializer.rs b/app/gui/src/ide/initializer.rs index 8af45aeae3..419434d077 100644 --- a/app/gui/src/ide/initializer.rs +++ b/app/gui/src/ide/initializer.rs @@ -5,6 +5,7 @@ use crate::prelude::*; use crate::config; use crate::ide::Ide; use crate::transport::web::WebSocket; +use crate::FailedIde; use engine_protocol::project_manager; use engine_protocol::project_manager::ProjectName; @@ -49,7 +50,6 @@ pub struct Initializer { logger: Logger, } - impl Initializer { /// Create [`Initializer`] with given configuration. pub fn new(config: config::Startup) -> Self { @@ -62,51 +62,52 @@ impl Initializer { pub fn start_and_forget(self) { let executor = setup_global_executor(); executor::global::spawn(async move { - info!(self.logger, "Starting IDE with the following config: {self.config:?}"); - - let application = Application::new(&web::get_html_element_by_id("root").unwrap()); - Initializer::register_views(&application); - let view = application.new_view::(); - - // IDE was opened with `project` argument, we should skip the Welcome Screen. - // We are doing it early, because Controllers initialization - // takes some time and Welcome Screen might be visible for a brief moment while - // controllers are not ready. - if self.config.project_name.is_some() { - view.switch_view_to_project(); - } - - let status_bar = view.status_bar().clone_ref(); - application.display.add_child(&view); - // TODO [mwu] Once IDE gets some well-defined mechanism of reporting - // issues to user, such information should be properly passed - // in case of setup failure. - let result: FallibleResult = (async { - let controller = self.initialize_ide_controller().await?; - Ok(Ide::new(application, view.clone_ref(), controller).await) - }) - .await; - - match result { - Ok(ide) => { - info!(self.logger, "Setup done."); - std::mem::forget(ide); - } - Err(err) => { - let message = iformat!("Failed to initialize application: {err}"); - error!(self.logger, "{message}"); - status_bar.add_event(ide_view::status_bar::event::Label::new(message)); - std::mem::forget(view); - } - } - + let ide = self.start(); web::get_element_by_id("loader") .map(|t| t.parent_node().map(|p| p.remove_child(&t).unwrap())) .ok(); + std::mem::forget(ide); }); std::mem::forget(executor); } + /// Initialize all Ide objects and structures (executor, views, controllers, integration etc.) + pub async fn start(self) -> Result { + info!(self.logger, "Starting IDE with the following config: {self.config:?}"); + + let root_element = web::get_html_element_by_id("root").unwrap(); + let ensogl_app = ensogl::application::Application::new(&root_element); + Initializer::register_views(&ensogl_app); + let view = ensogl_app.new_view::(); + + // IDE was opened with `project` argument, we should skip the Welcome Screen. + // We are doing it early, because Controllers initialization + // takes some time and Welcome Screen might be visible for a brief moment while + // controllers are not ready. + if self.config.project_name.is_some() { + view.switch_view_to_project(); + } + + let status_bar = view.status_bar().clone_ref(); + ensogl_app.display.add_child(&view); + // TODO [mwu] Once IDE gets some well-defined mechanism of reporting + // issues to user, such information should be properly passed + // in case of setup failure. + match self.initialize_ide_controller().await { + Ok(controller) => { + let ide = Ide::new(ensogl_app, view.clone_ref(), controller); + info!(self.logger, "Setup done."); + Ok(ide) + } + Err(error) => { + let message = format!("Failed to initialize application: {error}"); + error!(self.logger, "{message}"); + status_bar.add_event(ide_view::status_bar::event::Label::new(message)); + Err(FailedIde { view }) + } + } + } + fn register_views(app: &Application) { app.views.register::(); app.views.register::(); diff --git a/app/gui/src/model/execution_context/synchronized.rs b/app/gui/src/model/execution_context/synchronized.rs index fbe98d48a4..8c2a59f919 100644 --- a/app/gui/src/model/execution_context/synchronized.rs +++ b/app/gui/src/model/execution_context/synchronized.rs @@ -340,7 +340,7 @@ pub mod test { data: &MockData, ls: &mut language_server::MockClient, ) { - Self::mock_create_destroy_calls(&data, ls); + Self::mock_create_destroy_calls(data, ls); let id = data.context_id; let root_frame = language_server::ExplicitCall { method_pointer: data.main_method_pointer(), diff --git a/app/gui/src/model/module.rs b/app/gui/src/model/module.rs index f939736774..c4cfec3f63 100644 --- a/app/gui/src/model/module.rs +++ b/app/gui/src/model/module.rs @@ -587,6 +587,9 @@ pub trait API: Debug + model::undo_redo::Aware { fn info(&self) -> double_representation::module::Info { double_representation::module::Info::from(self.ast()) } + + /// Returns self as any. Used for casting down the [`Module`] object. + fn as_any(&self) -> &dyn Any; } /// Trait for methods that cannot be defined in `API` because it is a trait object. @@ -620,6 +623,7 @@ pub type Plain = plain::Module; pub type Synchronized = synchronized::Module; + // ============ // === Test === // ============ diff --git a/app/gui/src/model/module/plain.rs b/app/gui/src/model/module/plain.rs index 0b5c5334d8..4fcccd990b 100644 --- a/app/gui/src/model/module/plain.rs +++ b/app/gui/src/model/module/plain.rs @@ -214,6 +214,10 @@ impl model::module::API for Module { content.metadata.ide.project = Some(data); }) } + + fn as_any(&self) -> &dyn Any { + self + } } impl model::undo_redo::Aware for Module { @@ -286,13 +290,13 @@ mod test { // Metadata update let id = Uuid::new_v4(); let node_metadata = NodeMetadata { position: Some(Position::new(1.0, 2.0)), ..default() }; - module.set_node_metadata(id.clone(), node_metadata.clone()).unwrap(); + module.set_node_metadata(id, node_metadata.clone()).unwrap(); expect_notification(NotificationKind::MetadataChanged); - module.remove_node_metadata(id.clone()).unwrap(); + module.remove_node_metadata(id).unwrap(); expect_notification(NotificationKind::MetadataChanged); - module.with_node_metadata(id.clone(), Box::new(|md| *md = node_metadata.clone())).unwrap(); + module.with_node_metadata(id, Box::new(|md| *md = node_metadata.clone())).unwrap(); expect_notification(NotificationKind::MetadataChanged); // Whole update @@ -312,17 +316,17 @@ mod test { let module = model::module::test::plain_from_code(""); let id = Uuid::new_v4(); - let initial_md = module.node_metadata(id.clone()); + let initial_md = module.node_metadata(id); assert!(initial_md.is_err()); let md_to_set = NodeMetadata { position: Some(Position::new(1.0, 2.0)), ..default() }; - module.set_node_metadata(id.clone(), md_to_set.clone()).unwrap(); - assert_eq!(md_to_set.position, module.node_metadata(id.clone()).unwrap().position); + module.set_node_metadata(id, md_to_set.clone()).unwrap(); + assert_eq!(md_to_set.position, module.node_metadata(id).unwrap().position); let new_pos = Position::new(4.0, 5.0); module .with_node_metadata( - id.clone(), + id, Box::new(|md| { assert_eq!(md_to_set.position, md.position); md.position = Some(new_pos); diff --git a/app/gui/src/model/module/synchronized.rs b/app/gui/src/model/module/synchronized.rs index d684faf625..87570c0164 100644 --- a/app/gui/src/model/module/synchronized.rs +++ b/app/gui/src/model/module/synchronized.rs @@ -250,6 +250,10 @@ impl API for Module { ) -> FallibleResult { self.model.boxed_update_project_metadata(fun) } + + fn as_any(&self) -> &dyn Any { + self + } } @@ -538,7 +542,7 @@ pub mod test { client.expect.apply_text_file_edit(move |edits| { let content_so_far = this.current_ls_content.get(); let result = f(edits); - let new_content = apply_edits(content_so_far, &edits); + let new_content = apply_edits(content_so_far, edits); let actual_old = this.current_ls_version.get(); let actual_new = Sha3_224::from_parts(new_content.iter_chunks(..).map(|s| s.as_bytes())); diff --git a/app/gui/src/model/project/synchronized.rs b/app/gui/src/model/project/synchronized.rs index 8ede19e708..a9beb8398f 100644 --- a/app/gui/src/model/project/synchronized.rs +++ b/app/gui/src/model/project/synchronized.rs @@ -752,7 +752,11 @@ mod test { assert_eq!(path, *module.path()); assert_eq!(another_path, *another_module.path()); - assert!(Rc::ptr_eq(&module, &same_module)); + // We have to downcast module, otherwise we would compare vtable pointers. See + // https://rust-lang.github.io/rust-clippy/master/index.html#vtable_address_comparisons + let module = module.as_any().downcast_ref::().unwrap(); + let same_module = same_module.as_any().downcast_ref::().unwrap(); + assert!(std::ptr::eq(module, same_module)); }); } diff --git a/app/gui/src/presenter.rs b/app/gui/src/presenter.rs index af055522cc..c07956002e 100644 --- a/app/gui/src/presenter.rs +++ b/app/gui/src/presenter.rs @@ -43,6 +43,7 @@ impl Model { *self.current_project.borrow_mut() = None; if let Some(project_model) = self.controller.current_project() { + self.view.switch_view_to_project(); // We know the name of new project before it loads. We set it right now to avoid // displaying placeholder on the scene during loading. let project_view = self.view.project(); @@ -228,3 +229,17 @@ impl Presenter { }); } } + + +// === Getters === + +#[allow(missing_docs)] +impl Presenter { + pub fn view(&self) -> &view::root::View { + &self.model.view + } + + pub fn controller(&self) -> &controller::Ide { + &self.model.controller + } +} diff --git a/app/gui/src/presenter/graph/state.rs b/app/gui/src/presenter/graph/state.rs index d027648801..9ab49f9926 100644 --- a/app/gui/src/presenter/graph/state.rs +++ b/app/gui/src/presenter/graph/state.rs @@ -777,33 +777,33 @@ mod tests { let ast_con2 = AstConnection { source: src.clone(), destination: dest2.clone() }; let view_con1 = ensogl::display::object::Id::from(1).into(); let view_con2 = ensogl::display::object::Id::from(2).into(); - let view_src = EdgeEndpoint { node_id: nodes[0].view, port: src.port.clone() }; - let view_tgt1 = EdgeEndpoint { node_id: nodes[1].view, port: dest1.port.clone() }; - let view_tgt2 = EdgeEndpoint { node_id: nodes[1].view, port: dest2.port.clone() }; + let view_src = EdgeEndpoint { node_id: nodes[0].view, port: src.port }; + let view_tgt1 = EdgeEndpoint { node_id: nodes[1].view, port: dest1.port }; + let view_tgt2 = EdgeEndpoint { node_id: nodes[1].view, port: dest2.port }; let view_pair1 = (view_src.clone(), view_tgt1.clone()); let from_controller = state.update_from_controller(); let from_view = state.update_from_view(); - assert_eq!(from_controller.set_connection(ast_con1.clone()), Some(view_pair1.clone())); + assert_eq!(from_controller.set_connection(ast_con1.clone()), Some(view_pair1)); assert_eq!( from_view.create_connection_from_endpoints(view_con1, view_src.clone(), view_tgt1), None ); assert_eq!( - from_view.create_connection_from_endpoints(view_con2, view_src.clone(), view_tgt2), + from_view.create_connection_from_endpoints(view_con2, view_src, view_tgt2), Some(ast_con2.clone()) ); - let all_connections = [ast_con1.clone(), ast_con2.clone()].into_iter().collect(); + let all_connections = [ast_con1, ast_con2.clone()].into_iter().collect(); assert_eq!(from_controller.retain_connections(&all_connections), vec![]); assert_eq!( from_controller.retain_connections(&[ast_con2.clone()].into_iter().collect()), vec![view_con1] ); - assert_eq!(from_view.remove_connection(view_con2), Some(ast_con2.clone())); + assert_eq!(from_view.remove_connection(view_con2), Some(ast_con2)); } #[wasm_bindgen_test] diff --git a/app/gui/src/presenter/graph/visualization/manager.rs b/app/gui/src/presenter/graph/visualization/manager.rs index bc5eea7589..3321f16dc6 100644 --- a/app/gui/src/presenter/graph/visualization/manager.rs +++ b/app/gui/src/presenter/graph/visualization/manager.rs @@ -615,7 +615,7 @@ mod tests { ready(Ok(faux_vis.clone())).boxed_local() }); - let sender = request_sender.clone(); + let sender = request_sender; execution_context.expect_modify_visualization().returning_st( move |id, expression, module| { let request = ExecutionContextRequest::Modify { id, expression, module }; @@ -644,7 +644,7 @@ mod tests { ) -> bool { let PreprocessorConfiguration { module, code } = &metadata.preprocessor; visualization.preprocessor_code == code.to_string() - && visualization.context_module == manager.resolve_context_module(&module).unwrap() + && visualization.context_module == manager.resolve_context_module(module).unwrap() } #[wasm_bindgen_test] @@ -678,7 +678,7 @@ mod tests { // Multiple detach-attach requests are collapsed into a single modify request. requests.expect_pending(); manager.remove_visualization(node_id); - manager.request_visualization(node_id, desired_vis_2.clone()); + manager.request_visualization(node_id, desired_vis_2); manager.remove_visualization(node_id); manager.remove_visualization(node_id); manager.request_visualization(node_id, desired_vis_1.clone()); @@ -701,7 +701,7 @@ mod tests { let desired_vis_3 = Desired { visualization_id: VisualizationId::from_u128(900), expression_id: node_id, - metadata: desired_vis_1.clone(), + metadata: desired_vis_1, }; let visualization_so_far = manager.get_cloned(node_id).unwrap().status.get_cloned(); manager.write_new_desired(node_id, Some(desired_vis_3.clone())); diff --git a/app/gui/src/sync.rs b/app/gui/src/sync.rs index 2b11d6bf94..9ad31d8549 100644 --- a/app/gui/src/sync.rs +++ b/app/gui/src/sync.rs @@ -114,14 +114,14 @@ mod tests { let mut fixture = TestWithLocalPoolExecutor::set_up(); let flag = Synchronized::new(false); - assert_eq!(*flag.borrow(), false); + assert!(!*flag.borrow()); // If condition was already met, be immediately ready. - let mut on_false = flag.when(|f| *f == false).boxed_local(); + let mut on_false = flag.when(|&f| !f).boxed_local(); assert_eq!(on_false.expect_ready(), Some(())); // Otherwise not ready. - let mut on_true = flag.when(|f| *f == true).boxed_local(); + let mut on_true = flag.when(|&f| f).boxed_local(); on_true.expect_pending(); // Faux no-op change. Should not spawn a new task. @@ -135,7 +135,7 @@ mod tests { assert_eq!(on_true.expect_ready(), Some(())); // After dropping the flag, pending future should complete with None. - let mut on_false = flag.when(|f| *f == false).boxed_local(); + let mut on_false = flag.when(|&f| !f).boxed_local(); on_false.expect_pending(); drop(flag); assert_eq!(on_false.expect_ready(), None); diff --git a/app/gui/src/test.rs b/app/gui/src/test.rs index c09eb26c3f..f13d1d60ed 100644 --- a/app/gui/src/test.rs +++ b/app/gui/src/test.rs @@ -388,7 +388,7 @@ pub mod mock { pub fn synchronized_module(&self) -> Rc { let parser = self.data.parser.clone(); let path = self.data.module_path.clone(); - let ls = self.project.json_rpc().clone(); + let ls = self.project.json_rpc(); let repository = self.project.urm().repository.clone_ref(); let module_future = model::module::Synchronized::open(path, ls, parser, repository); // We can `expect_ready`, because in fact this is synchronous in test conditions. diff --git a/app/gui/tests/language_server.rs b/app/gui/tests/language_server.rs index 6cd169c492..d96161c9eb 100644 --- a/app/gui/tests/language_server.rs +++ b/app/gui/tests/language_server.rs @@ -188,7 +188,7 @@ async fn ls_text_protocol_test() { client.delete_file(&move_path).await.expect("Couldn't delete file"); let file = client.file_exists(&move_path).await; let file = file.expect("Couldn't check if file exists."); - assert_eq!(file.exists, false); + assert!(!file.exists); } client.move_file(&new_path, &move_path).await.expect("Couldn't move file"); @@ -248,7 +248,7 @@ async fn file_events() { client.delete_file(&path).await.expect("Couldn't delete file"); let file = client.file_exists(&path).await; let file = file.expect("Couldn't check if file exists."); - assert_eq!(file.exists, false); + assert!(!file.exists); } let path = Path { root_id, segments: vec![] }; diff --git a/app/gui/view/Cargo.toml b/app/gui/view/Cargo.toml index 97bda2a258..8c35532b8c 100644 --- a/app/gui/view/Cargo.toml +++ b/app/gui/view/Cargo.toml @@ -13,7 +13,7 @@ enso-config = { path = "../config" } enso-frp = { path = "../../../lib/rust/frp" } enso-logger = { path = "../../../lib/rust/logger"} enso-prelude = { path = "../../../lib/rust/prelude"} -enso-shapely = { path = "../../../lib/rust/shapely/impl"} +enso-shapely = { path = "../../../lib/rust/shapely"} engine-protocol = { path = "../controller/engine-protocol" } ensogl = { path = "../../../lib/rust/ensogl" } ensogl-component = { path = "../../../lib/rust/ensogl/component" } diff --git a/app/gui/view/graph-editor/Cargo.toml b/app/gui/view/graph-editor/Cargo.toml index d9dbcaa277..8fffacb3cc 100644 --- a/app/gui/view/graph-editor/Cargo.toml +++ b/app/gui/view/graph-editor/Cargo.toml @@ -17,7 +17,7 @@ enso-frp = { version = "0.1.0", path = "../../../../lib/rust/frp" } enso-logger = { path = "../../../../lib/rust/logger"} enso-prelude = { path = "../../../../lib/rust/prelude"} engine-protocol = { version = "0.1.0", path = "../../controller/engine-protocol" } -enso-shapely = { path = "../../../../lib/rust/shapely/impl"} +enso-shapely = { path = "../../../../lib/rust/shapely"} enso-text = { version = "0.1.0", path = "../../../../lib/rust/text" } ensogl = { version = "0.1.0", path = "../../../../lib/rust/ensogl" } ensogl-component = { path = "../../../../lib/rust/ensogl/component" } diff --git a/app/gui/view/graph-editor/src/component/node/input/area.rs b/app/gui/view/graph-editor/src/component/node/input/area.rs index f27828807d..81955a54d5 100644 --- a/app/gui/view/graph-editor/src/component/node/input/area.rs +++ b/app/gui/view/graph-editor/src/component/node/input/area.rs @@ -465,6 +465,10 @@ impl Area { pub fn get_crumbs_by_id(&self, id: ast::Id) -> Option { self.model.id_crumbs_map.borrow().get(&id).cloned() } + + pub fn label(&self) -> &text::Area { + &self.model.label + } } diff --git a/app/gui/view/graph-editor/src/lib.rs b/app/gui/view/graph-editor/src/lib.rs index aaca41b61a..1fa1b6a1cd 100644 --- a/app/gui/view/graph-editor/src/lib.rs +++ b/app/gui/view/graph-editor/src/lib.rs @@ -339,6 +339,14 @@ where } impl SharedHashMap { + pub fn len(&self) -> usize { + self.raw.borrow().len() + } + + pub fn is_empty(&self) -> bool { + self.raw.borrow().is_empty() + } + pub fn clear(&self) { self.raw.borrow_mut().clear() } diff --git a/build/run.js b/build/run.js index 998f8da68c..5cf861acab 100755 --- a/build/run.js +++ b/build/run.js @@ -74,16 +74,16 @@ async function build_project_manager() { } /// Run the local project manager binary. -function run_project_manager() { +function run_project_manager(options = {}) { const bin_path = paths.get_project_manager_path(paths.dist.bin) console.log(`Starting the project manager from "${bin_path}".`) - child_process.execFile(bin_path, [], (error, stdout, stderr) => { + return child_process.execFile(bin_path, [], options, (error, stdout, stderr) => { + console.log(`Project manager finished.`) console.error(stderr) - if (error) { + if (error && !error.killed) { throw error } console.log(stdout) - console.log(`Project manager running.`) }) } @@ -115,7 +115,13 @@ commands.clean.rust = async function () { commands.check = command(`Fast check if project builds (only Rust target)`) commands.check.rust = async function () { - await run_cargo('cargo', ['check']) + await run_cargo('cargo', [ + 'check', + '--workspace', + ' -p', + 'enso-integration-test', + '--all-targets', + ]) } // === Build === @@ -248,11 +254,41 @@ commands.test.rust = async function (argv) { } } +// === Integration Test === + +commands['integration-test'] = command('Run integration test suite') +commands['integration-test'].rust = async function (argv) { + let pm_process = null + if (argv.backend !== 'false') { + let env = { ...process.env, PROJECTS_ROOT: path.resolve(os.tmpdir(), 'enso') } + pm_process = await build_project_manager().then(() => run_project_manager({ env: env })) + } + try { + console.log(`Running Rust WASM test suite.`) + let args = ['test', '--chrome', 'integration-test', '--profile=integration-test'] + await run_cargo('wasm-pack', args) + } finally { + console.log(`Shutting down Project Manager`) + if (pm_process !== null) { + pm_process.kill() + } + } +} + // === Lint === commands.lint = command(`Lint the codebase`) commands.lint.rust = async function () { - await run_cargo('cargo', ['clippy', '--', '-D', 'warnings']) + await run_cargo('cargo', [ + 'clippy', + '--workspace', + '-p', + 'enso-integration-test', + '--all-targets', + '--', + '-D', + 'warnings', + ]) await run_cargo('cargo', ['fmt', '--', '--check']) } diff --git a/build/rust-scripts/src/bin/test_all.rs b/build/rust-scripts/src/bin/test_all.rs index 1782832ad6..87c1278faa 100644 --- a/build/rust-scripts/src/bin/test_all.rs +++ b/build/rust-scripts/src/bin/test_all.rs @@ -3,8 +3,8 @@ use std::path::Path; use std::path::PathBuf; -/// List of workspace members that, despite having should not be tested by wasm-pack test. -const PACKAGE_BLACKLIST: [&str; 0] = []; +/// List of crates that should not be tested by wasm-pack test. +const PACKAGE_BLACKLIST: [&str; 1] = ["integration-test"]; /// Attributes that denote WASM tests. const WASM_TEST_ATTRIBUTES: [&str; 2] = ["#[wasm_bindgen_test]", "#[wasm_bindgen_test(async)]"]; @@ -13,17 +13,44 @@ const WASM_TEST_ATTRIBUTES: [&str; 2] = ["#[wasm_bindgen_test]", "#[wasm_bindgen const SOURCE_SUBDIRECTORIES: [&str; 4] = ["src", "benches", "examples", "tests"]; /// Lists members of given Cargo.toml workspace. -fn get_workspace_members(cargo_toml_root: toml::Value) -> Vec { - let workspace = cargo_toml_root.get("workspace").expect("not a workspace"); - match &workspace["members"] { - toml::Value::Array(list) => list - .iter() - .map(|val| match val { - toml::Value::String(s) => s.clone(), - _ => panic!("Workspace member is not a string"), - }) - .collect(), - _ => panic!("Invalid workspace element"), +fn get_all_crates() -> Vec { + let all_paths = glob::glob("./**/Cargo.toml").expect("Searching for crates failed"); + let valid_paths = all_paths.filter_map(|path| match path { + Ok(path) => Some(path.parent().unwrap().to_owned()), + Err(err) => { + println!("cargo:warning={}", err); + None + } + }); + valid_paths.collect() +} + +/// Check if the given line of source code is an attribute denoting wasm test. +fn is_wasm_test_attribute(line: &str) -> bool { + WASM_TEST_ATTRIBUTES.contains(&line.trim()) +} + +/// Check if the given workspace member contains any wasm tests in the sources. +fn has_wasm_tests(member: &Path) -> bool { + if let Some(member) = member.to_str() { + // We go over selected subdirectories only to avoid entering into sources of other crates + // that are nested within this crate subtree. + for subdir in SOURCE_SUBDIRECTORIES { + let pattern = format!("{}/{}/**/*.rs", member, subdir); + for entry in glob::glob(&pattern).unwrap() { + let contents = std::fs::read_to_string(entry.unwrap()).unwrap(); + if contents.lines().any(is_wasm_test_attribute) { + return true; + } + } + } + false + } else { + println!( + "cargo:warning=Skipping the crate {} containing non-UTF-8 characters in its path. ", + member.to_string_lossy() + ); + false } } @@ -34,35 +61,14 @@ fn parse_toml(path: impl AsRef) -> toml::Value { data.parse().unwrap() } -/// Check if the given line of source code is an attribute denoting wasm test. -fn is_wasm_test_attribute(line: &str) -> bool { - WASM_TEST_ATTRIBUTES.contains(&line.trim()) -} - -/// Check if the given workspace member contains any wasm tests in the sources. -fn has_wasm_tests(member: &str) -> bool { - // We go over selected subdirectories only to avoid entering into sources of other crates that - // are nested within this crate subtree. - for subdir in SOURCE_SUBDIRECTORIES { - let pattern = format!("{}/{}/**/*.rs", member, subdir); - for entry in glob::glob(&pattern).unwrap() { - let contents = std::fs::read_to_string(entry.unwrap()).unwrap(); - if contents.lines().any(is_wasm_test_attribute) { - return true; - } - } - } - false -} - /// Checks if the given member is blacklisted from running the tests. -fn blacklisted(memeber: &str) -> bool { - PACKAGE_BLACKLIST.contains(&memeber) +fn blacklisted(memeber: &Path) -> bool { + PACKAGE_BLACKLIST.contains(&memeber.to_string_lossy().as_ref()) } /// Checks if given workspace member is a proc-macro crate. -fn is_proc_macro_crate(member: &str) -> bool { - let cargo_toml_path = PathBuf::from(member).join("Cargo.toml"); +fn is_proc_macro_crate(member: &Path) -> bool { + let cargo_toml_path = member.join("Cargo.toml"); let cargo_toml_root = parse_toml(cargo_toml_path); get_proc_macro(cargo_toml_root).contains(&true) } @@ -78,28 +84,28 @@ fn get_proc_macro(cargo_toml: toml::Value) -> Option { /// `wasm-pack test` each member. All script arguments are passed to `wasm-pack` process. fn main() { let wasm_pack_args = std::env::args().skip(1).collect::>(); - let cargo_toml_root = parse_toml("Cargo.toml"); - let all_members = get_workspace_members(cargo_toml_root); + let all_members = get_all_crates(); for member in all_members { + let member_str = member.to_string_lossy(); if blacklisted(&member) { - println!("Skipping blacklisted crate {}", member); + println!("Skipping blacklisted crate {}", member_str); } else if is_proc_macro_crate(&member) { - println!("Skipping proc-macro crate {}", member); + println!("Skipping proc-macro crate {}", member_str); } else if has_wasm_tests(&member) { - println!("Running tests for {}", member); + println!("Running tests for {}", member_str); let mut command = std::process::Command::new("wasm-pack"); command.arg("test").args(&wasm_pack_args).arg(&member); println!("{:?}", command); let status = command.status().unwrap(); if !status.success() { - panic!("Process for {} failed!{}", member, match status.code() { + panic!("Process for {} failed!{}", member_str, match status.code() { Some(code) => format!(" Code: {}", code), None => String::new(), }); } } else { - println!("No wasm tests in {}", member); + println!("No wasm tests in {}", member_str); } } } diff --git a/integration-test/Cargo.toml b/integration-test/Cargo.toml new file mode 100644 index 0000000000..a7b101dfc5 --- /dev/null +++ b/integration-test/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "enso-integration-test" +version = "0.1.0" +edition = "2021" + +[dependencies] +ensogl = { path = "../lib/rust/ensogl" } +enso-frp = { path = "../lib/rust/frp" } +enso-prelude = { path = "../lib/rust/prelude" } +enso-gui = { path = "../app/gui" } +enso-web = { path = "../lib/rust/web" } +wasm-bindgen = { version = "=0.2.58" } + +[dev-dependencies] +wasm-bindgen-test = "0.3.8" diff --git a/integration-test/src/lib.rs b/integration-test/src/lib.rs new file mode 100644 index 0000000000..264c26eded --- /dev/null +++ b/integration-test/src/lib.rs @@ -0,0 +1,65 @@ +//! Enso Integration Tests +//! +//! This crate contains all integration tests of Enso applications: the IDE and the backend +//! (engine). All of those are placed in `tests` directory. The sources (`src`) contain only +//! fixtures and helpers. +//! +//! These tests require the Project Manager for working. + +#![warn(missing_docs)] +#![warn(trivial_casts)] +#![warn(trivial_numeric_casts)] +#![warn(unused_import_braces)] +#![warn(unused_qualifications)] +#![warn(unsafe_code)] +#![warn(missing_copy_implementations)] +#![warn(missing_debug_implementations)] + +pub use enso_prelude as prelude; + +use enso_prelude::*; + +use enso_gui::executor::web::EventLoopExecutor; +use enso_gui::initializer::setup_global_executor; +use enso_gui::Ide; +use enso_web::HtmlDivElement; +use enso_web::NodeInserter; +use enso_web::StyleSetter; + + + +// ======================= +// === IntegrationTest === +// ======================= + +/// A fixture for each IDE integration tests. During setup, the executor and [`Ide`] structure are +/// initialized. +#[allow(missing_docs)] +#[derive(Debug)] +pub struct IntegrationTest { + pub executor: EventLoopExecutor, + pub ide: Ide, + pub root_div: HtmlDivElement, +} + +impl IntegrationTest { + /// Initializes the executor and `Ide` structure and returns new Fixture + pub async fn setup() -> Self { + enso_web::forward_panic_hook_to_error(); + let executor = setup_global_executor(); + let root_div = enso_web::create_div(); + root_div.set_id("root"); + root_div.set_style_or_panic("display", "none"); + enso_web::body().append_or_panic(&root_div); + + let initializer = enso_gui::ide::Initializer::new(default()); + let ide = initializer.start().await.expect("Failed to initialize the application."); + Self { executor, ide, root_div } + } +} + +impl Drop for IntegrationTest { + fn drop(&mut self) { + self.root_div.remove(); + } +} diff --git a/integration-test/tests/graph_editor.rs b/integration-test/tests/graph_editor.rs new file mode 100644 index 0000000000..e8a2670365 --- /dev/null +++ b/integration-test/tests/graph_editor.rs @@ -0,0 +1,31 @@ +use enso_frp::future::EventOutputExt; +use enso_integration_test::IntegrationTest; +use wasm_bindgen_test::wasm_bindgen_test; + + +wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser); + +#[wasm_bindgen_test] +async fn create_new_project_and_add_nodes() { + let test = IntegrationTest::setup().await; + let ide = &test.ide; + let project = ide.presenter.view().project(); + let graph_editor = project.graph(); + let controller = ide.presenter.controller(); + let project_management = + controller.manage_projects().expect("Cannot access Managing Project API"); + + let expect_prompt = project.show_prompt.next_event(); + project_management.create_new_project(None).await.expect("Failed to create new project"); + expect_prompt.await; + + assert_eq!(graph_editor.model.nodes.all.len(), 2); + let expect_node_added = graph_editor.node_added.next_event(); + graph_editor.add_node(); + let added_node_id = expect_node_added.expect(); + assert_eq!(graph_editor.model.nodes.all.len(), 3); + + let added_node = + graph_editor.model.nodes.get_cloned_ref(&added_node_id).expect("Added node is not added"); + assert_eq!(added_node.view.expression.value().to_string(), ""); +} diff --git a/integration-test/webdriver.json b/integration-test/webdriver.json new file mode 100644 index 0000000000..99e54b9f45 --- /dev/null +++ b/integration-test/webdriver.json @@ -0,0 +1,5 @@ +{ + "goog:chromeOptions": { + "args": ["--no-proxy-server", "--no-sandbox"] + } +} diff --git a/lib/rust/data-structures/benches/bench_tree_query.rs b/lib/rust/data-structures/benches/bench_tree_query.rs index 6a4e4a5fff..ee1290e997 100644 --- a/lib/rust/data-structures/benches/bench_tree_query.rs +++ b/lib/rust/data-structures/benches/bench_tree_query.rs @@ -88,9 +88,7 @@ fn map_in_place(c: &mut Criterion) { c.bench_function("Map in Place", |b| { b.iter(|| { let mut tree = tree.clone(); - black_box( - tree.iter_mut().for_each(black_box(|(_, v): (Vec<&usize>, &mut usize)| *v *= 2)), - ); + tree.iter_mut().for_each(black_box(|(_, v): (Vec<&usize>, &mut usize)| *v *= 2)); }) }); } diff --git a/lib/rust/data-structures/src/diet.rs b/lib/rust/data-structures/src/diet.rs index e06a5ab174..1e791094a6 100644 --- a/lib/rust/data-structures/src/diet.rs +++ b/lib/rust/data-structures/src/diet.rs @@ -653,7 +653,7 @@ mod tests { } } - + #[allow(clippy::type_complexity)] impl FromSorted<((usize, usize), (usize, usize), (usize, usize), (usize, usize))> for Tree4 { fn from_sorted( t: ((usize, usize), (usize, usize), (usize, usize), (usize, usize)), diff --git a/lib/rust/ensogl/component/selector/src/shape.rs b/lib/rust/ensogl/component/selector/src/shape.rs index db053106dd..bfbefc6266 100644 --- a/lib/rust/ensogl/component/selector/src/shape.rs +++ b/lib/rust/ensogl/component/selector/src/shape.rs @@ -265,20 +265,20 @@ mod tests { // Default is false. - assert_eq!(is_dragged.value(), false); + assert!(!is_dragged.value()); // Mouse down over shape activates dragging. shape.mouse_over.emit(()); mouse.down.emit(Button::from_code(0)); - assert_eq!(is_dragged.value(), true); + assert!(is_dragged.value()); // Release mouse stops dragging. mouse.up.emit(Button::from_code(0)); - assert_eq!(is_dragged.value(), false); + assert!(!is_dragged.value()); // Mouse down while not over shape does not activate dragging. shape.mouse_out.emit(()); mouse.down.emit(Button::from_code(0)); - assert_eq!(is_dragged.value(), false); + assert!(!is_dragged.value()); } } diff --git a/lib/rust/ensogl/component/text/Cargo.toml b/lib/rust/ensogl/component/text/Cargo.toml index 2761f77345..6327a66b91 100644 --- a/lib/rust/ensogl/component/text/Cargo.toml +++ b/lib/rust/ensogl/component/text/Cargo.toml @@ -10,7 +10,7 @@ crate-type = ["rlib", "cdylib"] [dependencies] enso-frp = { path = "../../../frp" } enso-prelude = { path = "../../../prelude"} -enso-shapely = { path = "../../../shapely/impl"} +enso-shapely = { path = "../../../shapely"} enso-text = { path = "../../../text" } enso-types = { path = "../../../types" } ensogl-core = { path = "../../core" } diff --git a/lib/rust/ensogl/component/text/src/typeface/font.rs b/lib/rust/ensogl/component/text/src/typeface/font.rs index 9ebe72d63a..0d0439fa1d 100644 --- a/lib/rust/ensogl/component/text/src/typeface/font.rs +++ b/lib/rust/ensogl/component/text/src/typeface/font.rs @@ -348,8 +348,8 @@ mod tests { const TEST_FONT_NAME: &str = "DejaVuSansMono-Bold"; fn create_test_font() -> Font { - let mut embedded_fonts = EmbeddedFonts::create_and_fill(); - Font::try_from_embedded(&mut embedded_fonts, TEST_FONT_NAME).unwrap() + let embedded_fonts = EmbeddedFonts::create_and_fill(); + Font::try_from_embedded(&embedded_fonts, TEST_FONT_NAME).unwrap() } wasm_bindgen_test_configure!(run_in_browser); diff --git a/lib/rust/ensogl/core/Cargo.toml b/lib/rust/ensogl/core/Cargo.toml index bdf38cde53..496d9cbde8 100644 --- a/lib/rust/ensogl/core/Cargo.toml +++ b/lib/rust/ensogl/core/Cargo.toml @@ -21,7 +21,7 @@ enso-generics = { path = "../../generics"} enso-logger = { path = "../../logger"} enso-optics = { path = "../../optics"} enso-prelude = { path = "../../prelude"} -enso-shapely = { path = "../../shapely/impl"} +enso-shapely = { path = "../../shapely"} enso-shortcuts = { path = "../../shortcuts" } enso-types = { path = "../../types" } enso-web = { path = "../../web" } diff --git a/lib/rust/ensogl/core/src/display/object/class.rs b/lib/rust/ensogl/core/src/display/object/class.rs index 542cd89c5b..7b9871347d 100644 --- a/lib/rust/ensogl/core/src/display/object/class.rs +++ b/lib/rust/ensogl/core/src/display/object/class.rs @@ -1505,20 +1505,20 @@ mod tests { node4.add_child(&node5); node5.add_child(&node6); - assert_eq!(node3.is_visible(), false); - assert_eq!(node4.is_visible(), false); - assert_eq!(node5.is_visible(), false); - assert_eq!(node6.is_visible(), false); + assert!(!node3.is_visible()); + assert!(!node4.is_visible()); + assert!(!node5.is_visible()); + assert!(!node6.is_visible()); // === Init Update === world.update(&()); - assert_eq!(node3.is_visible(), true); - assert_eq!(node4.is_visible(), true); - assert_eq!(node5.is_visible(), true); - assert_eq!(node6.is_visible(), true); + assert!(node3.is_visible()); + assert!(node4.is_visible()); + assert!(node5.is_visible()); + assert!(node6.is_visible()); assert_eq!(node1.global_position(), Vector3::new(0.0, 0.0, 0.0)); assert_eq!(node2.global_position(), Vector3::new(0.0, 0.0, 0.0)); @@ -1551,10 +1551,10 @@ mod tests { node3.unset_parent(); world.update(&()); - assert_eq!(node3.is_visible(), false); - assert_eq!(node4.is_visible(), false); - assert_eq!(node5.is_visible(), false); - assert_eq!(node6.is_visible(), false); + assert!(!node3.is_visible()); + assert!(!node4.is_visible()); + assert!(!node5.is_visible()); + assert!(!node6.is_visible()); } #[test] diff --git a/lib/rust/ensogl/example/Cargo.toml b/lib/rust/ensogl/example/Cargo.toml index 238e6f8b59..feb773cd49 100644 --- a/lib/rust/ensogl/example/Cargo.toml +++ b/lib/rust/ensogl/example/Cargo.toml @@ -26,7 +26,7 @@ ensogl-example-text-area = { path = "text-area" } #enso-frp = { path = "../../frp" } #enso-logger = { path = "../../logger"} #enso-prelude = { path = "../../prelude"} -#enso-shapely = { path = "../../shapely/impl"} +#enso-shapely = { path = "../../shapely"} #enso-text = { path = "../../text" } #ensogl-core = { path = "../core" } #ensogl-gui-component = { path = "../component/gui" } diff --git a/lib/rust/frp/src/data/bitfield.rs b/lib/rust/frp/src/data/bitfield.rs index 5c47392b95..40bb084938 100644 --- a/lib/rust/frp/src/data/bitfield.rs +++ b/lib/rust/frp/src/data/bitfield.rs @@ -161,7 +161,7 @@ mod test { let mut bit_field = BitField32::default(); for bit in tested_bits { - assert_eq!(bit_field.get_bit(*bit), false); + assert!(!bit_field.get_bit(*bit)); } // Set bits one by one @@ -189,7 +189,7 @@ mod test { let mut bit_field = BitField256::default(); for bit in tested_bits { - assert_eq!(bit_field.get_bit(*bit), false); + assert!(!bit_field.get_bit(*bit)); } // Set bits one by one diff --git a/lib/rust/frp/src/future.rs b/lib/rust/frp/src/future.rs new file mode 100644 index 0000000000..08d594df9c --- /dev/null +++ b/lib/rust/frp/src/future.rs @@ -0,0 +1,99 @@ +//! A module containing helpers for FRP networks in asynchronous environments. + +use crate::prelude::*; + +use crate::extend; +use crate::node; +use crate::stream::EventOutput; +use crate::HasLabel; +use crate::Label; +use crate::Network; + +use std::pin::Pin; +use std::task::Context; +use std::task::Poll; + + + +// =================== +// === FutureEvent === +// =================== + +/// A structure returned from [`EventOutputExt::next_event`] method. +/// +/// It's a future which is resolved once the given frp node emits an event. It also allows checking +/// if the value is provided - a useful tool when testing components with FRP API. +#[derive(Debug)] +pub struct FutureEvent { + _network: Network, + label: Label, + value: Rc>>, + wakers: Rc>>, +} + +impl FutureEvent { + fn new(node: &T) -> Self + where + T: EventOutput + HasLabel, + Out: node::Data, { + let label = node.label(); + let network = Network::new(format!("{label}.future_event")); + let value: Rc>> = default(); + let wakers: Rc>> = default(); + extend! { network + let node = node.clone_ref(); + eval node ([value,wakers](event) { + value.set(event.clone()); + for waker in wakers.take() { + waker.wake(); + } + }); + } + + Self { _network: network, label, value, wakers } + } + + /// Returns the received event. + /// + /// # Panics + /// + /// Panics if no event was emitted by the node since this structure creation. + pub fn expect(self) -> Out { + self.value.take().unwrap_or_else(|| ipanic!("Expected {self.label} event")) + } +} + +impl std::future::Future for FutureEvent { + type Output = Out; + + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + let value = self.value.take(); + match value { + Some(val) => Poll::Ready(val), + None => { + self.wakers.borrow_mut().push(cx.waker().clone()); + Poll::Pending + } + } + } +} + + + +// ====================== +// === EventOutputExt === +// ====================== + +/// A trait implemented automatically for every FRP node with helpers related to asynchronous +/// environment. +pub trait EventOutputExt: EventOutput { + /// Returns the future which is resolved once this node emits a next event. The events emitted + /// before calling this method are not considered. + fn next_event(&self) -> FutureEvent; +} + +impl EventOutputExt for T { + fn next_event(&self) -> FutureEvent { + FutureEvent::new(self) + } +} diff --git a/lib/rust/frp/src/lib.rs b/lib/rust/frp/src/lib.rs index 0c36c83874..acc058d369 100644 --- a/lib/rust/frp/src/lib.rs +++ b/lib/rust/frp/src/lib.rs @@ -160,6 +160,7 @@ pub mod data; pub mod debug; +pub mod future; pub mod io; pub mod macros; pub mod network; @@ -181,7 +182,6 @@ pub mod prelude { pub use enso_prelude::*; } - #[cfg(test)] mod network_mode_tests { use crate as frp; @@ -267,7 +267,7 @@ mod dynamic_mode_tests { def toggle_src = source::<()>(); def map_src = source::<()>(); def toggle = toggle_src.toggle_true(); - def _map = map_src.map2(&toggle,|_,value| assert_eq!(*value,true)); + def _map = map_src.map2(&toggle,|_,value| assert!(*value)); } map_src.emit(()); } @@ -278,7 +278,7 @@ mod dynamic_mode_tests { def toggle_src = source::<()>(); def map_src = source::<()>(); def toggle = toggle_src.toggle(); - def _map = map_src.map2(&toggle,|_,value| assert_eq!(*value,true)); + def _map = map_src.map2(&toggle,|_,value| assert!(*value)); } toggle_src.emit(()); map_src.emit(()); @@ -301,7 +301,7 @@ mod dynamic_mode_tests { behavior.emit(val); some_event.emit(()); } - let true_count = input.iter().filter(|&&val| val == true).count(); + let true_count = input.iter().filter(|&&val| val).count(); assert_eq!(passed_events.get(), true_count); } @@ -310,9 +310,9 @@ mod dynamic_mode_tests { let passed_events = Rc::new(Cell::new(0)); frp::new_network! { network source <- source::(); - filtered <- source.filter(|&value| value == true); + filtered <- source.filter(|&value| value); eval filtered ([passed_events](&value) { - assert_eq!(value,true); + assert!(value); passed_events.set(passed_events.get() + 1); }); }; @@ -321,7 +321,7 @@ mod dynamic_mode_tests { for val in input { source.emit(*val); } - let true_count = input.iter().filter(|&&val| val == true).count(); + let true_count = input.iter().filter(|&&val| val).count(); assert_eq!(passed_events.get(), true_count); } @@ -338,7 +338,7 @@ mod dynamic_mode_tests { for val in input { source.emit(*val); } - let true_count = input.iter().filter(|&&val| val == true).count(); + let true_count = input.iter().filter(|&&val| val).count(); assert_eq!(passed_events.get(), true_count); } } diff --git a/lib/rust/frp/src/nodes.rs b/lib/rust/frp/src/nodes.rs index 52b34e7dc2..44706e3b40 100644 --- a/lib/rust/frp/src/nodes.rs +++ b/lib/rust/frp/src/nodes.rs @@ -22,7 +22,6 @@ use enso_generics as generics; use enso_generics::traits::*; - // ======================== // === Network Node API === // ======================== diff --git a/lib/rust/frp/src/stream.rs b/lib/rust/frp/src/stream.rs index e8b9b20aee..6176127bc9 100644 --- a/lib/rust/frp/src/stream.rs +++ b/lib/rust/frp/src/stream.rs @@ -650,6 +650,14 @@ where Def: InputBehaviors } } +impl HasLabel for WeakNode +where Def: InputBehaviors +{ + fn label(&self) -> Label { + self.upgrade().map(|node| node.stream.data.label).unwrap_or("") + } +} + // FIXME code quality below: impl HasOutputTypeLabel for Node where Def: HasOutputStatic + InputBehaviors diff --git a/lib/rust/json-rpc/Cargo.toml b/lib/rust/json-rpc/Cargo.toml index 7e77c69d9b..e28200f62c 100644 --- a/lib/rust/json-rpc/Cargo.toml +++ b/lib/rust/json-rpc/Cargo.toml @@ -9,7 +9,7 @@ crate-type = ["cdylib", "rlib"] [dependencies] enso-prelude = { path = "../prelude", features = ["futures"]} -enso-shapely = { path = "../shapely/impl"} +enso-shapely = { path = "../shapely"} enso-web = { path = "../web" } futures = { version = "0.3.1" } failure = { version = "0.1.6" } diff --git a/lib/rust/json-rpc/src/messages.rs b/lib/rust/json-rpc/src/messages.rs index 662deb4702..6c1da39a93 100644 --- a/lib/rust/json-rpc/src/messages.rs +++ b/lib/rust/json-rpc/src/messages.rs @@ -322,14 +322,14 @@ mod tests { #[test] fn test_response_deserialization() { let response = r#"{"jsonrpc":"2.0","id":0,"result":{"exists":true}}"#; - let msg = serde_json::from_str(&response).unwrap(); + let msg = serde_json::from_str(response).unwrap(); if let IncomingMessage::Response(resp) = msg { assert_eq!(resp.id, Id(0)); if let Result::Success(ret) = resp.result { let obj = ret.result.as_object().expect("expected object ret"); assert_eq!(obj.len(), 1); let exists = obj.get("exists").unwrap().as_bool().unwrap(); - assert_eq!(exists, true) + assert!(exists) } else { panic!("Expected a success result") } diff --git a/lib/rust/logger/Cargo.toml b/lib/rust/logger/Cargo.toml index b1fa594238..b3dee0a6c5 100644 --- a/lib/rust/logger/Cargo.toml +++ b/lib/rust/logger/Cargo.toml @@ -22,7 +22,7 @@ default = [] [dependencies] enso-prelude = { version = "^0.2.1", path = "../prelude" } -enso-shapely = { version = "^0.2.0", path = "../shapely/impl" } +enso-shapely = { version = "^0.2.0", path = "../shapely" } wasm-bindgen = { version = "=0.2.58", features = ["nightly"] } js-sys = { version = "0.3.28" } diff --git a/lib/rust/macro-utils/Cargo.toml b/lib/rust/macro-utils/Cargo.toml index acb17c0786..b5fffe0853 100644 --- a/lib/rust/macro-utils/Cargo.toml +++ b/lib/rust/macro-utils/Cargo.toml @@ -31,4 +31,4 @@ features = [ ] [dev-dependencies] -wasm-bindgen-test = "0.2" +wasm-bindgen-test = "0.3.8" diff --git a/lib/rust/parser/flexer/Cargo.toml b/lib/rust/parser/flexer/Cargo.toml index 8c7989cda3..7d2e379522 100644 --- a/lib/rust/parser/flexer/Cargo.toml +++ b/lib/rust/parser/flexer/Cargo.toml @@ -37,4 +37,4 @@ unicode-segmentation = "1.6.0" wasm-bindgen = "0.2" [dev-dependencies] -wasm-bindgen-test = "0.2" +wasm-bindgen-test = "0.3.8" diff --git a/lib/rust/prelude/Cargo.toml b/lib/rust/prelude/Cargo.toml index 2732d62712..faaf2d190b 100644 --- a/lib/rust/prelude/Cargo.toml +++ b/lib/rust/prelude/Cargo.toml @@ -19,7 +19,7 @@ publish = true crate-type = ["cdylib", "rlib"] [dependencies] -enso-shapely = { version = "^0.2.0", path = "../shapely/impl" } +enso-shapely = { version = "^0.2.0", path = "../shapely" } anyhow = "1.0.37" backtrace = "0.3.53" @@ -89,4 +89,4 @@ features = [ ] [dev-dependencies] -wasm-bindgen-test = "0.2" +wasm-bindgen-test = "0.3.8" diff --git a/lib/rust/shapely/impl/Cargo.toml b/lib/rust/shapely/Cargo.toml similarity index 56% rename from lib/rust/shapely/impl/Cargo.toml rename to lib/rust/shapely/Cargo.toml index 02b1023ec2..12169b24e9 100644 --- a/lib/rust/shapely/impl/Cargo.toml +++ b/lib/rust/shapely/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" description = "Automated typeclass derivation." readme = "README.md" -homepage = "https://github.com/enso-org/rust-lib/src/shapely/impl" +homepage = "https://github.com/enso-org/rust-lib/src/shapely" repository = "https://github.com/enso-org/rust-lib" license-file = "../../../LICENSE" @@ -22,12 +22,12 @@ crate-type = ["cdylib", "rlib"] default = [] [dependencies] -enso-shapely-macros = { version = "^0.2.1", path = "../macros" } -paste = { version = "0.1" } -derivative = { version = "2.2.0" } -shrinkwraprs = { version = "0.3.0" } -rustversion = { version = "1.0" } +enso-shapely-macros = { version = "^0.2.1", path = "macros" } +paste = { version = "0.1" } +derivative = { version = "2.2.0" } +shrinkwraprs = { version = "0.3.0" } +rustversion = { version = "1.0" } [dev-dependencies] -enso-prelude = { path = "../../prelude" } -wasm-bindgen-test = "0.2" +enso-prelude = { path = "../prelude" } +wasm-bindgen-test = "0.3.8" diff --git a/lib/rust/shapely/impl/README.md b/lib/rust/shapely/README.md similarity index 100% rename from lib/rust/shapely/impl/README.md rename to lib/rust/shapely/README.md diff --git a/lib/rust/shapely/macros/Cargo.toml b/lib/rust/shapely/macros/Cargo.toml index 70b2b2ea75..8995d19842 100644 --- a/lib/rust/shapely/macros/Cargo.toml +++ b/lib/rust/shapely/macros/Cargo.toml @@ -36,4 +36,4 @@ features = [ ] [dev-dependencies] -wasm-bindgen-test = "0.2" +wasm-bindgen-test = "0.3.8" diff --git a/lib/rust/shapely/impl/src/cartesian.rs b/lib/rust/shapely/src/cartesian.rs similarity index 100% rename from lib/rust/shapely/impl/src/cartesian.rs rename to lib/rust/shapely/src/cartesian.rs diff --git a/lib/rust/shapely/impl/src/generator.rs b/lib/rust/shapely/src/generator.rs similarity index 100% rename from lib/rust/shapely/impl/src/generator.rs rename to lib/rust/shapely/src/generator.rs diff --git a/lib/rust/shapely/impl/src/lib.rs b/lib/rust/shapely/src/lib.rs similarity index 100% rename from lib/rust/shapely/impl/src/lib.rs rename to lib/rust/shapely/src/lib.rs diff --git a/lib/rust/shapely/impl/src/shared.rs b/lib/rust/shapely/src/shared.rs similarity index 100% rename from lib/rust/shapely/impl/src/shared.rs rename to lib/rust/shapely/src/shared.rs diff --git a/lib/rust/shapely/impl/src/singleton.rs b/lib/rust/shapely/src/singleton.rs similarity index 100% rename from lib/rust/shapely/impl/src/singleton.rs rename to lib/rust/shapely/src/singleton.rs diff --git a/lib/rust/shapely/impl/tests/derivation.rs b/lib/rust/shapely/tests/derivation.rs similarity index 100% rename from lib/rust/shapely/impl/tests/derivation.rs rename to lib/rust/shapely/tests/derivation.rs diff --git a/lib/rust/shapely/impl/tests/derive_clone_ref.rs b/lib/rust/shapely/tests/derive_clone_ref.rs similarity index 100% rename from lib/rust/shapely/impl/tests/derive_clone_ref.rs rename to lib/rust/shapely/tests/derive_clone_ref.rs diff --git a/lib/rust/shortcuts/src/lib.rs b/lib/rust/shortcuts/src/lib.rs index 8d2b25aa09..3006ec82a8 100644 --- a/lib/rust/shortcuts/src/lib.rs +++ b/lib/rust/shortcuts/src/lib.rs @@ -945,8 +945,8 @@ mod benchmarks { use super::*; use test::Bencher; - const CONS_SIMPLE: &'static str = "ctrl"; - const CONS_COMPLEX: &'static str = "ctrl cmd alt shift"; + const CONS_SIMPLE: &str = "ctrl"; + const CONS_COMPLEX: &str = "ctrl cmd alt shift"; // === Construction === diff --git a/lib/rust/types/src/topology.rs b/lib/rust/types/src/topology.rs index e20e97099e..51277d465d 100644 --- a/lib/rust/types/src/topology.rs +++ b/lib/rust/types/src/topology.rs @@ -104,6 +104,9 @@ mod tests { #[test] + // Clippy complains about `-180.0.degrees()`, but the precedence is irrelevant, and code looks + // cleaner without parentheses + #[allow(clippy::precedence)] fn degree_radian_conversions() { fn assert_equivalence(deg: Degrees, rad: Radians) { let deg_from_rad = Degrees::from(rad);