Test driving the development of a testing framework using itself in Guile

Guile Logo

Previously :

My last post was full of errors ! I guess I got lost in the REPL state and faced ghosts, like variables and procedures no more defined… In this post, I give you a new version of the code without errors. You also get a bonus feature : the failing tests are named in the summary. Enjoy !

The steps followed are almost the same as the one in the previous article of this serie. The difference lies in the way I encapsulate everything inside functions : * gunit-test is the function responsible for running the tests. * runner and summary are the functions under test. * gunit-project is the function that ensure my REPL is not relying on the state of old evaluations.

(use-modules ((debugging assert) #:select (assert))
             (ice-9 exceptions))

(define (gunit-project)

  (define* (runner #:key (setup (const #f)) (teardown (const #f)))
    (let ([count (vector 0 0)]
          [failures '()])
      (lambda* (#:rest procs)
         (lambda (proc)
           (vector-set! count 0 (1+ (vector-ref count 0)))
           (guard (e
                   ((exception? e)
                    (vector-set! count 1 (1+ (vector-ref count 1)))
                    (set! failures (cons (symbol->string (procedure-name proc)) failures))))
             (dynamic-wind setup proc teardown)))
        (values count failures))))

  (define (summary count failures)
    (format #f "~A run, ~A failed~A"
            (vector-ref count 0)
            (vector-ref count 1)
            (string-concatenate (map
                                 (lambda (failure)
                                   (format #f "\n- ~A" failure))

  (define (gunit-test)

    (define log "")
    (define (test-proc) (set! log (string-append log "proc ")))
    (define (test-proc-broken) (raise-exception (make-exception)))
    (define (setup-proc) (set! log (string-append log "setup ")))
    (define (teardown-proc) (set! log (string-append log "teardown ")))
    (define (test-template)
      ((runner #:setup setup-proc #:teardown teardown-proc) test-proc)
      (assert (string=? log "setup proc teardown ")))

    (define (test-result)
      (call-with-values (lambda () ((runner) test-proc))
        (lambda (count failures)
          (assert (string=? "1 run, 0 failed" (summary count failures))))))

    (define (test-failed-result)
      (call-with-values (lambda () ((runner) test-proc-broken))
        (lambda (count failures)
          (assert (string=? "1 run, 1 failed\n- test-proc-broken" (summary count failures))))))

    (define (test-suite)
      (call-with-values (lambda () ((runner) test-proc test-proc-broken))
        (lambda (count failures)
          (assert (string=? "2 run, 1 failed\n- test-proc-broken" (summary count failures))))))
    (let* ([setup (lambda () (set! log ""))]
           [run (runner #:setup setup)])
      (call-with-values (lambda ()
                          (run test-template
        (lambda (count failures)
          (summary count failures)))))



Thank you very much for reading this article!

Don't hesitate to give me your opinion, suggest an idea for improvement, report an error, or ask a question ! I would be so glad to discuss about the topic covered here with you ! You can reach me here.

Don't miss out on the next ones ! Either via RSS or via e-mail !

And more importantly, share this blog and tell your friends why they should read this post!

#gnu #guile #tdd #book #english

GPG: 036B 4D54 B7B4 D6C8 DA62 2746 700F 5E0C CBB2 E2D1