Code Kata with SRFI-64
Tags: guile, scheme, kata, tdd
Published: 2020-10-07 16:34:31

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/fxrf0fd45bxu9zztv6yx.png)


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) :

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

Explanation of the program :

* line 1 : load the module named (srfi srfi-64).
* line 2 : indicate the beginning of the test group demo.
* line 3: define a test, named “Hookup”, with the procedure test-equal whose first parameter is the result expected by the test (here, #t ) and the second parameter is the tested expression (here, #t).
* line 4: indicate the end of the `demo` test group.

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 :

* the list of executed tests ;
* the status of each of these tests;
* for failed tests, display the expected value and the value obtained.

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) :

```scheme
;;;; 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](https://linktr.ee/jeko).
> 
> And most importantly, share the blog and tell your friends it's the best blog in the history of Free Software! No shit!