about summary refs log tree commit diff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/javascript.scm23
-rw-r--r--tests/propnet.scm41
-rw-r--r--tests/reader.scm324
-rw-r--r--tests/store.scm80
-rw-r--r--tests/work/command-line-tool.scm12
-rw-r--r--tests/workflow.scm31
6 files changed, 336 insertions, 175 deletions
diff --git a/tests/javascript.scm b/tests/javascript.scm
index 75936c0..58d2639 100644
--- a/tests/javascript.scm
+++ b/tests/javascript.scm
@@ -1,5 +1,5 @@
 ;;; ravanan --- High-reproducibility CWL runner powered by Guix
-;;; Copyright © 2024 Arun Isaac <arunisaac@systemreboot.net>
+;;; Copyright © 2024–2025 Arun Isaac <arunisaac@systemreboot.net>
 ;;;
 ;;; This file is part of ravanan.
 ;;;
@@ -119,7 +119,12 @@
    (evaluate-parameter-reference "foo$(inputs.vector)$(inputs.object)")))
 
 (test-equal "evaluate parameter reference with node (without context)"
-  '(evaluate-javascript (*approximate*) "(inputs.n + 1)" "")
+  '(evaluate-javascript (*approximate*)
+                        "(inputs.n + 1)"
+                        (string-append ""
+                                       "inputs = " (scm->json-string inputs) ";"
+                                       "self = " (scm->json-string self) ";"
+                                       "runtime = " (scm->json-string runtime) ";"))
   (gexp->sexp-rec
    (evaluate-parameter-reference "$(inputs.n + 1)")))
 
@@ -129,7 +134,12 @@
            (if (string? token) token (scm->json-string (canonicalize-json token))))
          (list (json-ref runtime "cores")
                "foo"
-               (evaluate-javascript (*approximate*) "(inputs.threads*2)" "")
+               (evaluate-javascript (*approximate*)
+                                    "(inputs.threads*2)"
+                                    (string-append ""
+                                                   "inputs = " (scm->json-string inputs) ";"
+                                                   "self = " (scm->json-string self) ";"
+                                                   "runtime = " (scm->json-string runtime) ";"))
                (json-ref inputs "output_filename")))
     "")
   (gexp->sexp-rec
@@ -142,7 +152,12 @@
          (list "foo"
                (json-ref inputs "vector")
                (json-ref inputs "object")
-               (evaluate-javascript (*approximate*) "(inputs.object.foo*20)" "")))
+               (evaluate-javascript (*approximate*)
+                                    "(inputs.object.foo*20)"
+                                    (string-append ""
+                                                   "inputs = " (scm->json-string inputs) ";"
+                                                   "self = " (scm->json-string self) ";"
+                                                   "runtime = " (scm->json-string runtime) ";"))))
     "")
   (gexp->sexp-rec
    (evaluate-parameter-reference "foo$(inputs.vector)$(inputs.object)$(inputs.object.foo*20)")))
diff --git a/tests/propnet.scm b/tests/propnet.scm
index 182eb30..1f48d61 100644
--- a/tests/propnet.scm
+++ b/tests/propnet.scm
@@ -1,5 +1,5 @@
 ;;; ravanan --- High-reproducibility CWL runner powered by Guix
-;;; Copyright © 2024 Arun Isaac <arunisaac@systemreboot.net>
+;;; Copyright © 2024–2025 Arun Isaac <arunisaac@systemreboot.net>
 ;;;
 ;;; This file is part of ravanan.
 ;;;
@@ -23,19 +23,30 @@
 
 (test-equal "Trigger propagator with no inputs"
   '((out . #t))
-  (run-propnet (propnet (list (propagator "const"
-                                          (const '((out . #t)))
-                                          '()
-                                          '()
-                                          '((out . out))))
-                        (@@ (ravanan workflow) value=?)
-                        (@@ (ravanan workflow) merge-values)
-                        (scheduler (lambda (proc _)
-                                     proc)
-                                   (const 'completed)
-                                   0
-                                   (lambda (proc)
-                                     (proc))))
-               '()))
+  (run-with-state
+    (let loop ((mstate (schedule-propnet
+                        (propnet (list (propagator "const"
+                                                   (const '((out . #t)))
+                                                   '()
+                                                   '()
+                                                   '((out . out))))
+                                 (@@ (ravanan workflow) value=?)
+                                 (@@ (ravanan workflow) merge-values)
+                                 (scheduler (lambda (proc inputs scheduler)
+                                              (state-return proc))
+                                            (lambda (state)
+                                              (state-return (state+status state
+                                                                          'completed)))
+                                            (lambda (proc)
+                                              (state-return (proc)))))
+                        '())))
+      ;; Poll.
+      (state-let* ((state mstate)
+                   (state+status (poll-propnet state)))
+        (if (eq? (state+status-status state+status)
+                 'pending)
+            (loop (state-return (state+status-state state+status)))
+            ;; Capture outputs.
+            (capture-propnet-output (state+status-state state+status)))))))
 
 (test-end "propnet")
diff --git a/tests/reader.scm b/tests/reader.scm
index f3bcdd2..d55e396 100644
--- a/tests/reader.scm
+++ b/tests/reader.scm
@@ -16,169 +16,185 @@
 ;;; You should have received a copy of the GNU General Public License
 ;;; along with ravanan.  If not, see <https://www.gnu.org/licenses/>.
 
-(use-modules (srfi srfi-1)
+(use-modules (srfi srfi-26)
              (srfi srfi-64)
              (ice-9 filesystem)
              (ice-9 match)
              (web uri)
              (ravanan reader)
              (ravanan work command-line-tool)
-             (ravanan work utils))
-
-(define normalize-formal-input
-  (@@ (ravanan reader) normalize-formal-input))
-
-(define normalize-formal-output
-  (@@ (ravanan reader) normalize-formal-output))
-
-(define normalize-input
-  (@@ (ravanan reader) normalize-input))
-
-(define (json=? tree1 tree2)
-  (cond
-   ;; Arrays
-   ((vector? tree1)
-    (lset= json=?
-           (vector->list tree1)
-           (vector->list tree2)))
-   ;; Dictionaries
-   ((list? tree1)
-    (lset= (match-lambda*
-             (((key1 . value1) (key2 . value2))
-              (and (string=? key1 key2)
-                   (json=? value1 value2))))
-           tree1
-           tree2))
-   ;; Atoms
-   (else
-    (equal? tree1 tree2))))
+             (ravanan work types)
+             (ravanan work utils)
+             (ravanan work vectors))
 
 (test-begin "reader")
 
-(test-equal "Coerce number to number"
+(test-equal "Coerce to boolean (true)"
+  #t
+  (coerce-type "true" 'boolean))
+
+(test-equal "Coerce to boolean (false)"
+  #f
+  (coerce-type "false" 'boolean))
+
+(test-equal "Coerce to int"
+  37
+  (coerce-type "37" 'int))
+
+(test-equal "Coerce to float"
+  37.1
+  (coerce-type "37.1" 'float))
+
+(test-equal "Coerce to double"
+  37.1
+  (coerce-type "37.1" 'double))
+
+(test-equal "Coerce to string"
+  "37"
+  (coerce-type "37" 'string))
+
+(test-equal "Coerce to File"
+  '(("class" . "File")
+    ("location" . "foo"))
+  (coerce-type '(("class" . "File")
+                 ("location" . "foo"))
+               'File))
+
+(test-equal "Coerce to array"
+  #(1 2 3)
+  (coerce-type #("1" "2" "3")
+               (cwl-array-type 'int)))
+
+(test-equal "Coerce to union type (int first)"
+  37
+  (coerce-type "37"
+               (cwl-union-type 'int 'string)))
+
+(test-equal "Coerce to union type (string first)"
+  "37"
+  (coerce-type "37"
+               (cwl-union-type 'string 'int)))
+
+(test-equal "Coerce int to int"
   37
-  (coerce-type 37 'number))
-
-(test-assert "Normalize File type formal input"
-  (json=? '(("type" . "File")
-            ("id" . "foo")
-            ("secondaryFiles" . #((("pattern" . ".bai")
-                                   ("required" . #t)))))
-          (normalize-formal-input
-           '(("type" . "File")
-             ("id" . "foo")
-             ("secondaryFiles" . #(".bai"))))))
-
-(test-assert "Normalize File array type formal input"
-  (json=? '(("type"
-             ("type" . "array")
-             ("items" . "File"))
-            ("id" . "foo")
-            ("secondaryFiles" . #((("pattern" . ".bai")
-                                   ("required" . #t)))))
-          (normalize-formal-input
-           '(("type"
-              ("type" . "array")
-              ("items" . "File"))
-             ("id" . "foo")
-             ("secondaryFiles" . #(".bai"))))))
-
-(test-assert "Normalize array of File arrays type formal input"
-  (json=? '(("type"
-             ("type" . "array")
-             ("items" . (("type" . "array")
-                         ("items" . "File"))))
-            ("id" . "foo")
-            ("secondaryFiles" . #((("pattern" . ".bai")
-                                   ("required" . #t)))))
-          (normalize-formal-input
-           '(("type"
-              ("type" . "array")
-              ("items" . (("type" . "array")
-                          ("items" . "File"))))
-             ("id" . "foo")
-             ("secondaryFiles" . #(".bai"))))))
-
-(test-assert "Normalize File type formal output"
-  (json=? '(("type" . "File")
-            ("id" . "foo")
-            ("secondaryFiles" . #((("pattern" . ".bai")
-                                   ("required" . #f)))))
-          (normalize-formal-output
-           '(("type" . "File")
-             ("id" . "foo")
-             ("secondaryFiles" . #(".bai"))))))
-
-(test-assert "Normalize File array type formal output"
-  (json=? '(("type"
-             ("type" . "array")
-             ("items" . "File"))
-            ("id" . "foo")
-            ("secondaryFiles" . #((("pattern" . ".bai")
-                                   ("required" . #f)))))
-          (normalize-formal-output
-           '(("type"
-              ("type" . "array")
-              ("items" . "File"))
-             ("id" . "foo")
-             ("secondaryFiles" . #(".bai"))))))
-
-(test-assert "Normalize array of File arrays type formal output"
-  (json=? '(("type"
-             ("type" . "array")
-             ("items" . (("type" . "array")
-                         ("items" . "File"))))
-            ("id" . "foo")
-            ("secondaryFiles" . #((("pattern" . ".bai")
-                                   ("required" . #f)))))
-          (normalize-formal-output
-           '(("type"
-              ("type" . "array")
-              ("items" . (("type" . "array")
-                          ("items" . "File"))))
-             ("id" . "foo")
-             ("secondaryFiles" . #(".bai"))))))
-
-(test-assert "Normalize inputs with only location"
-  (call-with-temporary-directory
-   (lambda (dir)
-     (json=? (let ((path (expand-file-name "foo" dir)))
-               `(("class" . "File")
-                 ("location" . ,(uri->string (build-uri 'file #:path path)))
-                 ("path" . ,path)
-                 ("basename" . "foo")
-                 ("nameroot" . "foo")
-                 ("nameext" . "")
-                 ("size" . 0)
-                 ("checksum" . "sha1$da39a3ee5e6b4b0d3255bfef95601890afd80709")))
-             (call-with-current-directory dir
-               (lambda ()
-                 ;; Create an actual file called "foo" so that canonicalize-path
-                 ;; works.
-                 (call-with-output-file "foo"
-                   (const #t))
-                 (normalize-input '(("class" . "File")
-                                    ("location" . "foo")))))))))
-
-(test-assert "Normalize inputs with only path"
-  (call-with-temporary-directory
-   (lambda (dir)
-     (json=? (let ((path (expand-file-name "foo" dir)))
-               `(("class" . "File")
-                 ("location" . ,(uri->string (build-uri 'file #:path path)))
-                 ("path" . ,path)
-                 ("basename" . "foo")
-                 ("nameroot" . "foo")
-                 ("nameext" . "")
-                 ("size" . 0)
-                 ("checksum" . "sha1$da39a3ee5e6b4b0d3255bfef95601890afd80709")))
-             (call-with-current-directory dir
-               (lambda ()
-                 ;; Create an actual file called "foo" so that canonicalize-path
-                 ;; works.
-                 (call-with-output-file "foo"
-                   (const #t))
-                 (normalize-input '(("class" . "File")
-                                    ("path" . "foo")))))))))
+  (coerce-type 37 'int))
+
+(test-equal "Normalize inputs with only location"
+  (canonicalize-json
+   (let ((path (canonicalize-path "test-data/foo")))
+     `(("class" . "File")
+       ("location" . ,(uri->string (build-uri 'file
+                                              #:host ""
+                                              #:path path
+                                              #:validate? #f)))
+       ("path" . ,path)
+       ("basename" . "foo")
+       ("nameroot" . "foo")
+       ("nameext" . "")
+       ("size" . 0)
+       ("checksum" . "sha1$da39a3ee5e6b4b0d3255bfef95601890afd80709"))))
+  (call-with-values
+      (cut read-workflow+inputs
+           "test-data/workflow-with-a-file-input.cwl"
+           "test-data/input-file-with-location-only.yaml")
+    (lambda (workflow inputs)
+      (canonicalize-json (assoc-ref inputs "foo")))))
+
+(test-equal "Normalize inputs with only path"
+  (canonicalize-json
+   (let ((path (canonicalize-path "test-data/foo")))
+     `(("class" . "File")
+       ("location" . ,(uri->string (build-uri 'file
+                                              #:host ""
+                                              #:path path
+                                              #:validate? #f)))
+       ("path" . ,path)
+       ("basename" . "foo")
+       ("nameroot" . "foo")
+       ("nameext" . "")
+       ("size" . 0)
+       ("checksum" . "sha1$da39a3ee5e6b4b0d3255bfef95601890afd80709"))))
+  (call-with-values
+      (cut read-workflow+inputs
+           "test-data/workflow-with-a-file-input.cwl"
+           "test-data/input-file-with-path-only.yaml")
+    (lambda (workflow inputs)
+      (canonicalize-json (assoc-ref inputs "foo")))))
+
+(test-equal "Read YAML inputs file with type ambiguities"
+  '(("number" . 13)
+    ("flag" . #t)
+    ("reverseflag" . #f)
+    ("foo" . "bar")
+    ("arr" . #(1 2 3)))
+  (call-with-values
+      (cut read-workflow+inputs
+           "test-data/workflow-for-inputs-with-type-ambiguities.cwl"
+           "test-data/inputs-with-type-ambiguities.yaml")
+    (lambda (workflow inputs)
+      inputs)))
+
+(test-equal "Resolve type ambiguities in workflow default inputs"
+  '(("number" . 13)
+    ("flag" . #t)
+    ("reverseflag" . #f)
+    ("foo" . "bar")
+    ("arr" . #(1 2 3)))
+  (call-with-values
+      (cut read-workflow+inputs
+           "test-data/workflow-with-default-inputs.cwl"
+           "test-data/empty.yaml")
+    (lambda (workflow inputs)
+      (vector-map->list (lambda (input)
+                          (cons (assoc-ref input "id")
+                                (assoc-ref input "default")))
+                        (assoc-ref workflow "inputs")))))
+
+(test-equal "Normalize File type formals"
+  (list (vector-map canonicalize-json
+                    #((("id" . "infoo")
+                       ("type" . "File")
+                       ("secondaryFiles" . #((("pattern" . ".bai")
+                                              ("required" . #t)))))
+                      (("id" . "inbar")
+                       ("type"
+                        ("type" . "array")
+                        ("items" . "File"))
+                       ("secondaryFiles" . #((("pattern" . ".bai")
+                                              ("required" . #t)))))
+                      (("id" . "infoobar")
+                       ("type"
+                        ("type" . "array")
+                        ("items" . (("type" . "array")
+                                    ("items" . "File"))))
+                       ("secondaryFiles" . #((("pattern" . ".bai")
+                                              ("required" . #t)))))))
+        (vector-map canonicalize-json
+                    #((("id" . "outfoo")
+                       ("type" . "File")
+                       ("secondaryFiles" . #((("pattern" . ".bai")
+                                              ("required" . #f)))))
+                      (("id" . "outbar")
+                       ("type"
+                        ("type" . "array")
+                        ("items" . "File"))
+                       ("secondaryFiles" . #((("pattern" . ".bai")
+                                              ("required" . #f)))))
+                      (("id" . "outfoobar")
+                       ("type"
+                        ("type" . "array")
+                        ("items" . (("type" . "array")
+                                    ("items" . "File"))))
+                       ("secondaryFiles" . #((("pattern" . ".bai")
+                                              ("required" . #f))))))))
+  (call-with-values
+      (cut read-workflow+inputs
+           "test-data/workflow-with-various-file-type-formals.cwl"
+           "test-data/empty.yaml")
+    (lambda (workflow inputs)
+      (list (vector-map canonicalize-json
+                        (assoc-ref workflow "inputs"))
+            (vector-map canonicalize-json
+                        (assoc-ref workflow "outputs"))))))
 
 (test-end "reader")
diff --git a/tests/store.scm b/tests/store.scm
new file mode 100644
index 0000000..f209583
--- /dev/null
+++ b/tests/store.scm
@@ -0,0 +1,80 @@
+;;; ravanan --- High-reproducibility CWL runner powered by Guix
+;;; Copyright © 2025 Arun Isaac <arunisaac@systemreboot.net>
+;;;
+;;; This file is part of ravanan.
+;;;
+;;; ravanan is free software: you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation, either version 3 of the License, or
+;;; (at your option) any later version.
+;;;
+;;; ravanan is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;; General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with ravanan.  If not, see <https://www.gnu.org/licenses/>.
+
+(use-modules (srfi srfi-64)
+             (ravanan store))
+
+(test-begin "store")
+
+(test-equal "step-store-files-directory must be insensitive to order of inputs"
+  (step-store-files-directory "/gnu/store/hl96c0xd19ngvl8rf4cyw452rpgqsi1b-foo"
+                              '(("foo" . 1)
+                                ("foobar" . 3)
+                                ("bar" . (("aal" . 1)
+                                          ("vel" . 2))))
+                              "store")
+  (step-store-files-directory "/gnu/store/hl96c0xd19ngvl8rf4cyw452rpgqsi1b-foo"
+                              '(("foo" . 1)
+                                ("bar" . (("vel" . 2)
+                                          ("aal" . 1)))
+                                ("foobar" . 3))
+                              "store"))
+
+(test-equal "step-store-data-file must be insensitive to order of inputs"
+  (step-store-data-file "/gnu/store/hl96c0xd19ngvl8rf4cyw452rpgqsi1b-foo"
+                        '(("foo" . 1)
+                          ("foobar" . 3)
+                          ("bar" . (("aal" . 1)
+                                    ("vel" . 2))))
+                        "store")
+  (step-store-data-file "/gnu/store/hl96c0xd19ngvl8rf4cyw452rpgqsi1b-foo"
+                        '(("foo" . 1)
+                          ("bar" . (("vel" . 2)
+                                    ("aal" . 1)))
+                          ("foobar" . 3))
+                        "store"))
+
+(test-equal "step-store-stdout-file must be insensitive to order of inputs"
+  (step-store-stdout-file "/gnu/store/hl96c0xd19ngvl8rf4cyw452rpgqsi1b-foo"
+                          '(("foo" . 1)
+                            ("foobar" . 3)
+                            ("bar" . (("aal" . 1)
+                                      ("vel" . 2))))
+                          "store")
+  (step-store-stdout-file "/gnu/store/hl96c0xd19ngvl8rf4cyw452rpgqsi1b-foo"
+                          '(("foo" . 1)
+                            ("bar" . (("vel" . 2)
+                                      ("aal" . 1)))
+                            ("foobar" . 3))
+                          "store"))
+
+(test-equal "step-store-stderr-file must be insensitive to order of inputs"
+  (step-store-stderr-file "/gnu/store/hl96c0xd19ngvl8rf4cyw452rpgqsi1b-foo"
+                          '(("foo" . 1)
+                            ("foobar" . 3)
+                            ("bar" . (("aal" . 1)
+                                      ("vel" . 2))))
+                          "store")
+  (step-store-stderr-file "/gnu/store/hl96c0xd19ngvl8rf4cyw452rpgqsi1b-foo"
+                          '(("foo" . 1)
+                            ("bar" . (("vel" . 2)
+                                      ("aal" . 1)))
+                            ("foobar" . 3))
+                          "store"))
+
+(test-end "store")
diff --git a/tests/work/command-line-tool.scm b/tests/work/command-line-tool.scm
index 3d11b53..93b97d4 100644
--- a/tests/work/command-line-tool.scm
+++ b/tests/work/command-line-tool.scm
@@ -1,5 +1,5 @@
 ;;; ravanan --- High-reproducibility CWL runner powered by Guix
-;;; Copyright © 2024 Arun Isaac <arunisaac@systemreboot.net>
+;;; Copyright © 2024, 2025 Arun Isaac <arunisaac@systemreboot.net>
 ;;;
 ;;; This file is part of ravanan.
 ;;;
@@ -24,6 +24,14 @@
 
 (test-equal "match null object to array type"
   #f
-  (match-type 'null (array-type 'File)))
+  (match-type 'null (cwl-array-type 'File)))
+
+(test-equal "match int to float"
+  'float
+  (match-type 1 'float))
+
+(test-equal "match float to float"
+  'float
+  (match-type 1.3 'float))
 
 (test-end "work.command-line-tool")
diff --git a/tests/workflow.scm b/tests/workflow.scm
new file mode 100644
index 0000000..06b2609
--- /dev/null
+++ b/tests/workflow.scm
@@ -0,0 +1,31 @@
+;;; ravanan --- High-reproducibility CWL runner powered by Guix
+;;; Copyright © 2025 Arun Isaac <arunisaac@systemreboot.net>
+;;;
+;;; This file is part of ravanan.
+;;;
+;;; ravanan is free software: you can redistribute it and/or modify it
+;;; under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation, either version 3 of the License, or
+;;; (at your option) any later version.
+;;;
+;;; ravanan is distributed in the hope that it will be useful, but
+;;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;; General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with ravanan.  If not, see <https://www.gnu.org/licenses/>.
+
+(use-modules (srfi srfi-64))
+
+(define optional-input?
+  (@@ (ravanan workflow) optional-input?))
+
+(test-begin "workflow")
+
+(test-assert "Inputs that have a boolean #f default are also optional"
+  (optional-input? `(("id" . "foo")
+                     ("type" . "boolean")
+                     ("default" . #f))))
+
+(test-end "workflow")