(.module: [lux #* ["_" test (#+ Test)] [abstract [monad (#+ do)]] [control ["." try] [parser ["." environment (#+ Environment)]] [concurrency ["." atom (#+ Atom)] ["." promise (#+ Promise)]] [security ["!" capability]]] [data ["." text ["%" format (#+ format)]] [number ["n" nat]] [collection ["." dictionary] ["." set] ["." list ("#\." functor)]]] [math ["." random]] [world [console (#+ Console)] ["." shell (#+ Shell)] ["." program (#+ Program)] ["." file (#+ Path) ["." watch]]]] ["." // #_ ["@." version] ["@." build] ["$/#" // #_ ["#." package]]] {#program ["." / ["/#" // #_ ["#." build] ["/#" // #_ [command (#+ Command)] ["#" profile (#+ Profile)] ["#." action] ["#." artifact ["#/." type]] ["#." dependency ["#/." resolution (#+ Resolution)]]]]]}) (def: (command end_signal dummy_files) (-> Text (List Path) [(Atom [Nat (List Path)]) (-> (Console Promise) (Program Promise) (file.System Promise) (Shell Promise) Resolution (Command Any))]) (let [@runs (: (Atom [Nat (List Path)]) (atom.atom [0 dummy_files]))] [@runs (function (_ console program fs shell resolution profile) (do {! promise.monad} [[runs remaining_files] (promise.future (atom.update (function (_ [runs remaining_files]) [(inc runs) remaining_files]) @runs))] (case remaining_files #.Nil (wrap (#try.Failure end_signal)) (#.Cons head tail) (do (try.with !) [_ (!.use (\ fs create_file) [head])] (do ! [_ (promise.future (atom.write [runs tail] @runs))] (wrap (#try.Success [])))))))])) (def: #export test Test (<| (_.covering /._) (do {! random.monad} [#let [/ (\ file.default separator) [fs watcher] (watch.mock /)] end_signal (random.ascii/alpha 5) program (random.ascii/alpha 5) target (random.ascii/alpha 5) home (random.ascii/alpha 5) working_directory (random.ascii/alpha 5) expected_runs (\ ! map (|>> (n.% 10) (n.max 2)) random.nat) source (random.ascii/alpha 5) dummy_files (|> (random.ascii/alpha 5) (random.set text.hash (dec expected_runs)) (\ ! map (|>> set.to_list (list\map (|>> (format source /)))))) #let [empty_profile (: Profile (\ ///.monoid identity)) with_target (: (-> Profile Profile) (set@ #///.target (#.Some target))) with_program (: (-> Profile Profile) (set@ #///.program (#.Some program))) profile (|> empty_profile with_program with_target (set@ #///.sources (set.from_list text.hash (list source))))] resolution @build.resolution] ($_ _.and (wrap (do promise.monad [verdict (do ///action.monad [#let [[@runs command] (..command end_signal dummy_files)] _ (!.use (\ fs create_directory) [source]) _ (\ watcher poll [])] (do promise.monad [outcome ((/.do! watcher command) (@version.echo "") (program.async (program.mock environment.empty home working_directory)) fs (@build.good_shell []) resolution profile) [actual_runs _] (promise.future (atom.read @runs))] (wrap (#try.Success (and (n.= expected_runs actual_runs) (case outcome (#try.Failure error) (is? end_signal error) (#try.Success _) false))))))] (_.cover' [/.do!] (try.default false verdict)))) ))))