Code Kata with SRFI-64

Guile Logo

I got into the habit of doing about 30 minutes of Code Kata every morning. I practice these Kata following the test-driven development (TDD) approach.

Guile distribution includes the SRFI-64 module: a unit testing framework. In this article, I explain how to use it and how to configure it in order to practice code kata.

Basic usage

The SRFI-64 module has a default configuration. Let me show you what it looks like here.

Below is a Guile program that creates a test suite with only one test (doomed to fail) :

(use-modules (srfi srfi-64))
(test-begin "demo")
(test "Hookup" #f #t)
(test-end "demo")

Explanation of the program :

It is relatively simple, there are few frills.

This is the result of the execution of this suite if you save it in a /tmp/tests.scm file and execute the :

$ guile --no-auto-compile test.scm 
%%%% Starting test demo (Writing full log to "demo.log")
/tmp/test.scm:3: FAIL Hookup
# of unexpected failures 1

The console displays only a summary of the result: line 3 shows an unexpected failure from the “Hookup” test. It's very brief but it gives a quick idea of the state of the program.

The complete detail is in the /tmp/demo.log file:

cat demo.log
%%%% Starting test demo
Group begin: demo
Test begin:
  test-name: "Hookup"
  source-file: "/tmp/test.scm".
  source-line: 3
  source-form: (test-equal "Hookup" #f #t)
Test end:
  result-kind: fail
  actual-value: #t
  expected-value: #f
Group end: demo
# of unexpected failures 1

This report gives me two pieces of information that I use a lot : actual-value and expected-value.

This default configuration, although ready to use, has the disadvantage of providing informations in two places : in the console (list of tests and their states) and in a file (test results). Not very practical...

Fortunately, the test framework is easily configurable. In the following article, I present you my configuration dedicated to code kata.

Configuration for Code Kata

The idea here is to configure the SRFI-64 module to display all the information I need directly in the console (and I don't need to report in a file). I want to see at a glance :

According to the SRFI-64 reference, the objects that maintain the statistics on the test suite (total number of tests, number of successful, failed, passed, ...) are the test-runners.

Thanks to the section Writing a new test-runner and some examples gleaned from the web, you should be able to create the test-runner that suits you!

Here is the one I made for myself (based on the work of Mathieu Lirzin and Alex Sassmannshausen) :

;;;; kata-driver.scm - Guile test driver for code kata practice

(define script-version "2020-10-04") ;UTC

;;; Copyright © 2015, 2016 Mathieu Lirzin <mthl@gnu.org>
;;; Copyright © 2019 Alex Sassmannshausen <alex@pompo.co>
;;; Copyright © 2019 Jérémy Korwin-Zmijowski <jeremy@korwin-zmijowski.fr>
;;;
;;; This program 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.
;;;
;;; This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.

;;;; Commentary:
;;;
;;; This script provides a Guile test driver using the SRFI-64 Scheme API for
;;; test suites.  SRFI-64 is distributed with Guile since version 2.0.9.
;;;
;;; This script is a very cleaned up version of the Alex Sassmannshausen 's 
;;; version. The changes make it suitable for use in a code kata practice.
;;;
;;;; Code:

(define-module (runner-kata)
  #:export (test-runner-kata))

(use-modules (srfi srfi-64)
             (ice-9 pretty-print)
             (srfi srfi-26))

(define* (test-display field value  #:optional (port (current-output-port))
                       #:key pretty?)
  "Display 'FIELD: VALUE\n' on PORT."
  (if pretty?
      (begin
        (format port "~A:~%" field)
        (pretty-print value port #:per-line-prefix "+ "))
      (format port "~A: ~S~%" field value)))

(define* (result->string symbol)
  "Return SYMBOL as an upper case string.  Use colors when COLORIZE is #t."
  (let ((result (string-upcase (symbol->string symbol))))
    (string-append (case symbol
                     ((pass)       "")  ;green
                     ((xfail)      "")  ;light green
                     ((skip)       "")  ;blue
                     ((fail xpass) "")  ;red
                     ((error)      "")) ;magenta
                   result
                   "")))

(define* (test-runner-kata)

  (define (test-on-test-end-kata runner)
    (let* ((results (test-result-alist runner))
           (result? (cut assq <> results))
           (result  (cut assq-ref results <>)))
      (if (equal? 'fail (result 'result-kind))
	  (begin
	    (newline)
	    (format #t "~a ~A~%"
		    (result->string (result 'result-kind))
		    (result 'test-name))
	    (when (result? 'expected-value)
              (test-display "expected-value" (result 'expected-value)))
	    (when (result? 'expected-error)
              (test-display "expected-error" (result 'expected-error) #:pretty? #t))
	    (when (result? 'actual-value)
              (test-display "actual-value" (result 'actual-value)))
	    (newline))
	  (begin
	    (format #t "~a ~A~%"
		    (result->string (result 'result-kind))
		    (result 'test-name))))))

  (let ((runner (test-runner-null)))
    (test-runner-on-test-end! runner test-on-test-end-kata)
    runner))

I created a git repository which contains a project template for a code kata. Just follow the README instructions and code !

Here is an example of feedback from your terminal while the watch.sh script is running :

FAIL Hookup
expected-value: #f
actual-value: #t

No more need to look at the content of the report (which is no longer generated) to find out what the problem is. So I can execute this script in a dedicated emacs buffer, every time I save, and act according to the test results.

Now it's up to you!

Choose a code kata exercise, work on it for about 30 minutes, share the link to your code and your tests in comments below!

Then, I give you my 2 cents for your next session!

Thank you so much for reading this article!

Don't hesitate to give me your opinion or ask a question ! To do so, please leave a comment below or contact me.

Also, please subscribe so you don't miss the next ones :blog via Mastodon @jeko@write.as et RSSscreencast via Peertube @jeko@video.tedomum.net et RSS

And most importantly, share the blog and tell your friends it's the best blog in the history of Free Software! No shit!

#english #guile #tool #tdd #kata #gnu