;; lib/flow/tests/basic.sx — Phase 1: declarative DAG + sequential execution. (define flow-basic-pass 0) (define flow-basic-fail 0) (define flow-basic-fails (list)) (define flow-basic-test (fn (name actual expected) (if (= actual expected) (set! flow-basic-pass (+ flow-basic-pass 1)) (begin (set! flow-basic-fail (+ flow-basic-fail 1)) (append! flow-basic-fails {:name name :expected expected :actual actual}))))) ;; Run a Scheme flow-program string and return its final value. (define flow-b (fn (src) (flow-run src))) ;; Scheme strings are boxed as {:scm-string "..."}; unwrap to a host string. (define flow-bs (fn (src) (get (flow-run src) :scm-string))) ;; ── single node ───────────────────────────────────────────────── (flow-basic-test "node: identity passes input through" (flow-b "(flow/start flow-id 7)") 7) (flow-basic-test "node: const ignores input" (flow-b "(flow/start (flow-const 99) 1)") 99) (flow-basic-test "node: bare lambda is a node" (flow-b "(flow/start (lambda (x) (* x x)) 6)") 36) ;; ── linear sequence ───────────────────────────────────────────── (flow-basic-test "sequence: empty is identity" (flow-b "(flow/start (sequence) 42)") 42) (flow-basic-test "sequence: single child" (flow-b "(flow/start (sequence (lambda (x) (+ x 1))) 41)") 42) (flow-basic-test "sequence: two children thread" (flow-b "(flow/start (sequence (lambda (x) (+ x 1)) (lambda (x) (* x 10))) 4)") 50) (flow-basic-test "sequence: three children thread" (flow-b "(flow/start (sequence (lambda (x) (+ x 1)) (lambda (x) (* x 2)) (lambda (x) (- x 3))) 5)") 9) ;; ── data flow between nodes ───────────────────────────────────── (flow-basic-test "data flow: string accumulation" (flow-bs "(flow/start (sequence (lambda (s) (string-append s \"-a\")) (lambda (s) (string-append s \"-b\"))) \"x\")") "x-a-b") (flow-basic-test "data flow: list build" (flow-b "(flow/start (sequence (lambda (x) (cons x (list))) (lambda (xs) (cons 0 xs))) 7)") (list 0 7)) ;; ── defflow ───────────────────────────────────────────────────── (flow-basic-test "defflow: names a flow" (flow-b "(defflow inc2 (sequence (lambda (x) (+ x 1)) (lambda (x) (+ x 1)))) (flow/start inc2 40)") 42) (flow-basic-test "defflow: reusable" (flow-b "(defflow dbl (lambda (x) (* x 2))) (+ (flow/start dbl 3) (flow/start dbl 10))") 26) ;; ── parallel (sequential semantics, join into list) ───────────── (flow-basic-test "parallel: fans input to all branches" (flow-b "(flow/start (parallel (lambda (x) (+ x 1)) (lambda (x) (* x 2)) (lambda (x) (- x 3))) 10)") (list 11 20 7)) (flow-basic-test "parallel: empty joins to empty list" (flow-b "(flow/start (parallel) 5)") (list)) (flow-basic-test "parallel: single branch" (flow-b "(flow/start (parallel (lambda (x) (* x x))) 9)") (list 81)) ;; ── nested composition ────────────────────────────────────────── (flow-basic-test "nested: sequence of sequences" (flow-b "(flow/start (sequence (sequence (lambda (x) (+ x 1)) (lambda (x) (+ x 1))) (sequence (lambda (x) (* x 3)))) 0)") 6) (flow-basic-test "nested: parallel inside sequence, join then reduce" (flow-b "(flow/start (sequence (parallel (lambda (x) (+ x 1)) (lambda (x) (* x 2))) (lambda (xs) (apply + xs))) 10)") 31) (flow-basic-test "nested: sequence inside parallel branch" (flow-b "(flow/start (parallel (sequence (lambda (x) (+ x 1)) (lambda (x) (* x 2))) (lambda (x) x)) 5)") (list 12 5)) ;; ── publish-shaped flow (the architecture sketch) ─────────────── (flow-basic-test "publish: write -> (review | spell) -> join lengths" (flow-b "(defflow publish (sequence (lambda (draft) (string-append draft \"!\")) (parallel (lambda (c) (string-length c)) (lambda (c) (string-length (string-append c \"?\")))))) (flow/start publish \"hi\")") (list 3 4)) (define flow-basic-tests-run! (fn () {:total (+ flow-basic-pass flow-basic-fail) :passed flow-basic-pass :failed flow-basic-fail :fails flow-basic-fails}))