Chapa 1)


Test blocks: eev @ EmacsConf 2021

My talk at the EmacsConf2021 was about test blocks.
Here are its slides, its video, and its subtitles.
If you are new to eev then start by eepitch and its "Try it!".
See my old page on test blocks, and my talks at the EmacsConf2020 and EmacsConf2019.

Title: Test blocks
Intended duration: 5 minutes

In this presentation I will show an idea that feels completely obvious once we see it, but that only occured to me after after using Emacs and eev as my main interface to the computer for more than 20 years. Take any interpreted language that supports multi-line comments, and whose interpreter can be run in an Emacs buffer - for example Lua, Haskell, Python, or Julia; let's say just "Lua" from here on for simplicity. So: suppose that we have a Lua script that we wrote, that is called "foo.lua" and that defines lots of functions and defines the classes Bar and Bletch. We can put after the definition of the class Bar a multi-line comment that contains an eepitch block that when executed starts a Lua interpreter, loads the script foo.lua (by running 'dofile "foo.lua"'), and then has several tests for that class and its methods; and we can put another block with tests like that after the class Bletch, and other blocks after some functions. Eepitch allows sending these tests line by line to the Lua interpreter by typing <f8> on each line that we want to send, and this lets us create tests that are very easy to understand even without writing comments; this gives us a very quick way to document code by executable tests, that is super-great for experimental code that is still going to change a lot before running the risk of being read by other people.

These multi-line comments with eepitch blocks that run an interpreter and make it load the current file are called "test blocks". The command `M-x eeit' inserts a test block at point, using the major mode to decide the right syntax to use for the multi-line comments and for the "dofile". We can configure the syntax of the test blocks for the current major mode by running `M-x find-eeit-links'; this can also be used to add support for test blocks to more languages (or, more precisely: to more major modes).


Here is a hack to use test blocks in languages without multi-line comments.
You can watch the video of my presentation with subtitles here.
You can download a local copy of it with (find-1stclassvideo-links "eev2021") or with:

# See:  http://anggtwu.net/eev-videos.html
#       http://anggtwu.net/eev-videos.html#mpv-keys
# Play: (find-eev2021video "0:00")
# Info: (find-1stclassvideo-links "eev2021")
# Subs: (find-1stclassvideolsubs  "eev2021")

wget -nc http://anggtwu.net/eev-videos/emacsconf2021.mp4
wget -N  http://anggtwu.net/eev-videos/emacsconf2021.vtt
mpv --fs --osd-level=2 emacsconf2021.mp4

A real-world example (2021nov28)

Test blocks became one of my favorite ways to document my code. I'm using them a lot in Dednat6; this video shows how, and it also shows how you can run those test blocks yourself. Note that most video introductions on eev, like this one, stress that the three basic keys of eev are M-e, M-j, and M-k, but for running test blocks you only need to use <f8>, that is the fourth of the three basic keys.

In the beginning I thought that using test blocks as documentation could scare some people, but then 1) I reminded myself that very few people use dednat6, and that now that things like Quiver are available even fewer people are going to be interested in trying a text-based tool like dednat6, 2) my friends who tried the test blocks grokked them in seconds.

sudo apt-get install lua5.1

rm -Rfv /tmp/dednat6/
mkdir   /tmp/dednat6/
cd      /tmp/dednat6/
git clone https://github.com/edrx/dednat6 .

# (find-fline "/tmp/dednat6/")
# (find-fline "/tmp/dednat6/dednat6/")
# (find-fline "/tmp/dednat6/dednat6/edrxlib.lua")
# (find-anchor "/tmp/dednat6/dednat6/zhas.lua" "MixedPicture-arch-tests")

 (code-c-d "dn6"     "/tmp/dednat6/dednat6/" :anchor)
 (setenv "LUA_INIT" "@/tmp/dednat6/dednat6/edrxlib.lua")
 (find-dn6 "zhas.lua" "MixedPicture-arch-tests")
 (find-dn6 "zhas.lua" "shortoperators-tests")

Here's a quick index to the video that shows how I use test blocks in Dednat6:

0:33  What I am going to show
0:47  Dednat6 is an extensible (semi-)preprocessor
0:58  sometimes we want to draw diagrams like this
1:12  that would understand some ... in comments
1:38  and it also supports diagrams for Category Theory
1:57  LaTeX interprets these things as comments but
2:13  Dednat6 is very extensible
2:28  very boring to draw by hand
2:43  In the beginning I thought that using test blocks...
3:06  now that we have things like Quiver
3:36  and this gave me much more freedom
3:50  I showed to some friends
4:06  Let me show how these test blocks work
4:25  Note that these things are not red stars
4:32  this sexp will make them behave as red stars
4:41  f8 four times
5:15  these two lines ... I don't want to explain
5:29  this one is easy ... is just a hyperlink
5:37  this anchor in is the middle of a very big test block
5:42  if we execute it with f8
6:07  so let me execute these tests
6:23  these lines create a certain object and display it
6:36  I can also change these tests
7:03  run some undos here
7:07  these objects correspond to these diagrams
7:24  I am also going to show another test block
7:28  this one here
7:43  they correspond to these diagrams here
7:54  this demo here can be executed by just typing
7:57  f8 in the right places

You can download the video about the "real-world example" and its subtitles using the two "wget"s below:

# See:  http://anggtwu.net/eev-videos.html
#       http://anggtwu.net/eev-videos.html#mpv-keys
# Play: (find-eev2021bvideo "0:00")
# Info: (find-1stclassvideo-links "eev2021b")
# Subs: (find-1stclassvideolsubs  "eev2021b")

wget -nc http://anggtwu.net/eev-videos/emacsconf2021-dednat6.mp4
wget -N  http://anggtwu.net/eev-videos/emacsconf2021-dednat6.vtt
mpv --fs --osd-level=2 emacsconf2021-dednat6.mp4


00:00 Hi! My name is Eduardo Ochs. I'm the author of
00:02 an Emacs package called eev, and this talk is
00:05 about a new feature of eev called "test
00:07 blocks".

00:08 Let's start by a demo.
00:10 This is a file in Lua that defines these
00:12 two functions here,
00:14 and if we type f8 several times
00:16 here
00:18 the f8s create a Lua REPL - here - and
00:20 then they send these lines to the REPL,
00:24 where this line here loads this file
00:27 into the REPL, and these other lines - here -
00:29 are tests for these lines.
00:33 There's a lot of information here, so let
00:35 me organize them in a more visual way.

00:40 This is our file in Lua.
00:42 Lua sees this thing as a multi-line
00:45 comment, but we are going to see it as a
00:47 test block. And eev mode is active - so
00:51 f8 does the right thing.
00:54 These three lines here set up the
00:57 target buffer running a Lua REPL - you
01:00 can see the the prompt of the REPL here -
01:03 and these lines here are sent to the
01:05 REPL.
01:07 When we type f8 on a line that
01:09 starts
01:10 with a red star, like these lines here,
01:13 what f8 does is that it sends the
01:15 rest of the line - sorry, it
01:18 executes the rest of the line as Lisp.
01:21 So the three f8s here
01:23 executes these lines as Lisp, and they
01:26 set up the target buffer - here -
01:29 and when we type f8 on a line that
01:31 does not start with a red star
01:34 the f8 sends the line to the target
01:36 buffer and moves down.
01:38 This line loads this file in the
01:41 REPL, and these lines are tests.

01:45 So we just saw how to use an existing
01:47 test block; let's now see how to create a
01:50 new test block. We just have to run this:
01:52 M-x ee-insert-test-block -
01:55 or M-x eeit.
01:58 The result depends on the major mode.
02:01 Let's understand that
02:03 by looking at the source code.
02:06 `eeit' is an alias to this function here,
02:08 and this function is just five lines of
02:10 code plus a docstring...
02:12 and the docstring explains that if the
02:14 major mode is foo-mode then this
02:16 function tries to call
02:18 a function called `ee-insert-test-foo-mode'
02:21 if that function exists,
02:24 and that if that function does not exist
02:27 then it yields an error.
02:29 And here's an example of one such
02:32 function - that's a function that
02:34 inserts a test block in haskell-mode -
02:37 and here we can see two functions like
02:40 this: one for haskell-mode and one for
02:42 js-mode.
02:46 These functions look quite similar
02:48 but their effects look quite different.
02:52 To make this comparison here i started
02:55 by writing -
02:57 by creating seven files, each one in a
02:59 different language,
03:01 and initially each one of these files
03:03 only had a comment with the name of the
03:04 language... so: C, Haskell, Javascript,
03:08 Org Mode, etc -
03:10 and in each one of these files I typed
03:13 M-x eeit to insert a test block.
03:16 So here we can see that these test
03:18 blocks are different -
03:20 for example, the syntax for multi-line
03:22 comments is different depending on the
03:24 language -
03:25 this block here that selects which
03:27 REPL to run is also different, and
03:30 this line here that
03:33 tells the REPL to
03:34 load the current file is also different
03:37 depending on the language.
03:39 In some cases I had to improvise a bit -
03:41 for example,
03:43 to implement test blocks in shell mode
03:46 I had to use this -
03:48 this weird syntax using a here-document -
03:52 in Tcl I also had to improvise a bit, and
03:55 in some cases I had to improvise a lot.
03:57 For example in Org Mode there isn't an
04:01 obvious REPL to run, and there isn't an
04:03 obvious way to load the
04:05 the current Org file into the REPL, so
04:08 the default action of M-x eeit
04:11 in Org Mode is just to insert this thing
04:14 here, that we can use to run a
04:17 shell in a REPL.

04:22 So these functions are quite similar, and in
04:25 the beginning I was writing all of them
04:27 by hand... but then I got bored and I wrote
04:29 a function to help me write functions
04:32 like that.
04:33 This function is called
04:35 `find-eeit-links' and it creates a
04:38 temporary buffer...
04:39 and the contents of this temporary
04:41 buffer depends on the major mode - for
04:43 example if the current mode is python-mode
04:45 then running this function here
04:48 creates a temporary buffer that lets me
04:51 write the support for
04:53 test blocks in python-mode, or rewrite
04:56 the function that supports test blocks
04:59 in python-mode.
05:00 So if I'm in python-mode and I run this
05:03 I get a temporary buffer like this...
05:06 in which this thing is my template for
05:08 the function - usually this string is
05:11 totally wrong, I have to rewrite this
05:13 but the rest is right - you can see python-mode
05:16 here in the name of the function. So
05:18 we have to edit this and save that to
05:21 our ~/.emacs - and by the way these things
05:25 here are hyperlinks to many different
05:28 things... this elisp hyperlink here
05:31 points to the source code - to the section
05:34 in which these functions are defined -
05:38 so you can see this here the function
05:40 that supports C,
05:41 the function for Haskell, the function
05:43 for Javascript, etc...
05:46 and that's it! This is a five-minute talk
05:49 so I can't say much...

05:50 If you want more information, or if you
05:52 want to see real-world examples, how I
05:55 use test blocks, etc, etc, see this page
05:58 here... and I do not have time to explain
06:00 this "By the way" here.
06:02 So that's it! Thanks! =)