(.require
 [library
  [lux (.except)
   [abstract
    ["[0]" monad (.only do)]]
   [control
    ["[0]" try (.only Try) (.use "[1]#[0]" functor)]
    ["[0]" exception]
    [concurrency
     ["[0]" async (.only Async)]]]
   [data
    ["[0]" binary]
    ["[0]" text (.use "[1]#[0]" equivalence)
     ["%" \\format (.only format)]]
    [collection
     ["[0]" set (.only Set)]]]
   [math
    ["[0]" random]]
   [world
    ["[0]" file]
    ["[0]" environment
     ["program" / (.only Environment)]
     ["[1]" \\parser]]]
   [test
    ["[0]" unit]
    ["_" property (.only Test)]]]]
 [//
  ["$[0]" version]
  [//
   ["$[0]" profile]
   ["$[0]" artifact]]]
 [\\program
  ["[0]" / (.only)
   ["//[1]" ///
    ["[1]" profile]
    ["[1][0]" action (.only Action)]
    ["[1][0]" local]
    ["[1][0]" artifact (.only)
     ["[1]/[0]" extension]]
    ["[1][0]" repository
     ["[1]/[0]" local]]]]])

(def .public (make_sources! fs sources)
  (-> (file.System Async) (Set file.Path) (Action (List Any)))
  (let [/ (at fs separator)
        ! ///action.monad]
    (|> sources
        set.list
        (monad.each ! (function (_ head)
                        (do !
                          [_ (is (Async (Try Any))
                                 (file.make_directories async.monad fs head))]
                          (is (Async (Try Any))
                              (file.make_file async.monad fs (binary.empty 0) (format head / head ".lux")))))))))

(def (execute! program fs sample)
  (-> (Environment Async) (file.System Async) ///.Profile (Async (Try Text)))
  (do ///action.monad
    [.let [console ($version.echo "")]
     _ (..make_sources! fs (the ///.#sources sample))
     _ (/.do! console fs (///repository/local.repository program fs) sample)]
    (at console read_line [])))

(def .public test
  Test
  (<| (_.covering /._)
      (do [! random.monad]
        [identity $artifact.random
         sample (at ! each (has ///.#identity {.#Some identity})
                    $profile.random)
         home (random.alphabetic 5)
         working_directory (random.alphabetic 5)
         .let [/ (at file.default separator)]]
        (all _.and
             (in (do [! async.monad]
                   [.let [fs (file.mock /)
                          program (program.async (program.mock environment.empty home working_directory))

                          artifact_path (///local.uri (the ///artifact.#version identity) identity)
                          library_path (format artifact_path ///artifact/extension.lux_library)
                          pom_path (format artifact_path ///artifact/extension.pom)]
                    verdict (do [! ///action.monad]
                              [succeeded! (at ! each (text#= /.success)
                                              (..execute! program fs sample))
                               library_exists! (|> library_path
                                                   (format home /)
                                                   (at fs file?)
                                                   (at async.monad each (|>> {try.#Success})))
                               pom_exists! (|> pom_path
                                               (format home /)
                                               (at fs file?)
                                               (at async.monad each (|>> {try.#Success})))]
                              (in (and succeeded!
                                       library_exists!
                                       pom_exists!)))]
                   (unit.coverage [/.do! /.success]
                     (try.else false verdict))))
             (in (do [! async.monad]
                   [.let [fs (file.mock /)
                          program (program.async (program.mock environment.empty home working_directory))]
                    logging (..execute! program fs (has ///.#identity {.#None} sample))]
                   (unit.coverage [/.failure]
                     (|> logging
                         (try#each (text#= /.failure))
                         (try.else false)))))
             ))))
