aboutsummaryrefslogtreecommitdiff
;;; ravanan --- High-reproducibility CWL runner powered by Guix
;;; Copyright © 2024 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)
             (guix gexp)
             (ice-9 match)
             (ravanan work monads)
             (ravanan javascript))

(define (gexp->sexp-rec exp)
  "Recursively convert G-expression @var{exp} into an approximate S-expression."
  (match exp
    ((? gexp? exp)
     (gexp->sexp-rec (gexp->approximate-sexp exp)))
    ((head tail ...)
     (cons (gexp->sexp-rec head)
           (map gexp->sexp-rec tail)))
    (atom
     atom)))

(test-begin "javascript")

(test-equal "evaluate parameter reference"
  "c"
  (evaluate-parameter-reference "$(inputs.message['bar'][\"foo\"][2])"
                                '(("inputs" ("message" ("bar" ("foo" . #("a" "b" "c" "d"))))))))

(test-equal "evaluate parameter reference to JSON object"
  '(("class" . "File")
    ("path" . "/foo/bar"))
  (evaluate-parameter-reference "$(inputs.fasta)"
                                '(("inputs" ("fasta"
                                             ("class" . "File")
                                             ("path" . "/foo/bar"))))))

(test-equal "evaluate parameter reference with string interpolation"
  "24foo12foobar"
  (evaluate-parameter-reference "$(runtime.cores)foo$(inputs.threads)$(inputs.output_filename)"
                                '(("inputs"
                                   ("threads" . 12)
                                   ("output_filename" . "foobar"))
                                  ("runtime" ("cores" . 24)))))

(test-equal "evaluate parameter reference with string interpolation of JSON trees"
  "foo[0,1,2,3]{\"bar\":2,\"foo\":1}"
  (evaluate-parameter-reference "foo$(inputs.vector)$(inputs.object)"
                                '(("inputs"
                                   ("object"
                                    ("foo" . 1)
                                    ("bar" . 2))
                                   ("vector" . #(0 1 2 3))))))

(test-equal "evaluate parameter reference with node"
  3
  (evaluate-parameter-reference "$(inputs.n + 1)"
                                '(("inputs" ("n" . 2)))))

(test-equal "evaluate parameter reference to JSON object using node"
  '(json-ref inputs "fasta")
  (gexp->sexp-rec
   (evaluate-parameter-reference "$(inputs.fasta)")))

(test-equal "evaluate parameter reference with string interpolation using node"
  "24foo24foobar"
  (evaluate-parameter-reference "$(runtime.cores)foo$(inputs.threads*2)$(inputs.output_filename)"
                                '(("inputs"
                                   ("threads" . 12)
                                   ("output_filename" . "foobar"))
                                  ("runtime" ("cores" . 24)))))

(test-equal "evaluate parameter reference with string interpolation of JSON trees using node"
  "foo[0,1,2,3]{\"bar\":2,\"foo\":1}20"
  (evaluate-parameter-reference "foo$(inputs.vector)$(inputs.object)$(inputs.object.foo*20)"
                                '(("inputs"
                                   ("object"
                                    ("foo" . 1)
                                    ("bar" . 2))
                                   ("vector" . #(0 1 2 3))))))

(test-equal "evaluate parameter reference (without context)"
  '(json-ref inputs "message" "bar" "foo" 2)
  (gexp->sexp-rec
   (evaluate-parameter-reference "$(inputs.message['bar'][\"foo\"][2])")))

(test-equal "evaluate parameter reference with string interpolation (without context)"
  '(string-join
    (map (lambda (token)
           (if (string? token) token (scm->json-string (canonicalize-json token))))
         (list (json-ref runtime "cores")
               "foo"
               (json-ref inputs "threads")
               (json-ref inputs "output_filename")))
    "")
  (gexp->sexp-rec
   (evaluate-parameter-reference "$(runtime.cores)foo$(inputs.threads)$(inputs.output_filename)")))

(test-equal "evaluate parameter reference with string interpolation of JSON trees (without context)"
  '(string-join
    (map (lambda (token)
           (if (string? token) token (scm->json-string (canonicalize-json token))))
         (list "foo" (json-ref inputs "vector") (json-ref inputs "object")))
    "")
  (gexp->sexp-rec
   (evaluate-parameter-reference "foo$(inputs.vector)$(inputs.object)")))

(test-equal "evaluate parameter reference with node (without context)"
  '(evaluate-javascript (*approximate*) "(inputs.n + 1)" "")
  (gexp->sexp-rec
   (evaluate-parameter-reference "$(inputs.n + 1)")))

(test-equal "evaluate parameter reference with string interpolation using node (without context)"
  '(string-join
    (map (lambda (token)
           (if (string? token) token (scm->json-string (canonicalize-json token))))
         (list (json-ref runtime "cores")
               "foo"
               (evaluate-javascript (*approximate*) "(inputs.threads*2)" "")
               (json-ref inputs "output_filename")))
    "")
  (gexp->sexp-rec
   (evaluate-parameter-reference "$(runtime.cores)foo$(inputs.threads*2)$(inputs.output_filename)")))

(test-equal "evaluate parameter reference with string interpolation of JSON trees using node (without context)"
  '(string-join
    (map (lambda (token)
           (if (string? token) token (scm->json-string (canonicalize-json token))))
         (list "foo"
               (json-ref inputs "vector")
               (json-ref inputs "object")
               (evaluate-javascript (*approximate*) "(inputs.object.foo*20)" "")))
    "")
  (gexp->sexp-rec
   (evaluate-parameter-reference "foo$(inputs.vector)$(inputs.object)$(inputs.object.foo*20)")))

(test-end "javascript")