aboutsummaryrefslogtreecommitdiff
path: root/test/sam
diff options
context:
space:
mode:
Diffstat (limited to 'test/sam')
-rw-r--r--test/sam/.gitignore3
-rw-r--r--test/sam/Makefile12
-rw-r--r--test/sam/README.md73
-rw-r--r--test/sam/addresses/columns.cmd4
-rw-r--r--test/sam/addresses/columns.in5
-rw-r--r--test/sam/addresses/first-last.cmd4
-rw-r--r--test/sam/addresses/first-last.in4
-rw-r--r--test/sam/addresses/lines.cmd6
-rw-r--r--test/sam/addresses/lines.in20
-rw-r--r--test/sam/addresses/second.cmd4
-rw-r--r--test/sam/addresses/second.in4
-rw-r--r--test/sam/commands/filter-capitalize.cmd1
-rw-r--r--test/sam/commands/filter-capitalize.in1
-rw-r--r--test/sam/commands/group.cmd5
-rw-r--r--test/sam/commands/group.in1
-rw-r--r--test/sam/commands/long-text.cmd11
-rw-r--r--test/sam/commands/long-text.in0
-rw-r--r--test/sam/commands/loop-empty-match1.cmd4
-rw-r--r--test/sam/commands/loop-empty-match1.in1
-rw-r--r--test/sam/commands/loop-empty-match2.cmd4
-rw-r--r--test/sam/commands/loop-empty-match2.in1
-rw-r--r--test/sam/commands/loop-empty-match3.cmd4
-rw-r--r--test/sam/commands/loop-empty-match3.in1
-rw-r--r--test/sam/commands/loop-empty-match4.cmd4
-rw-r--r--test/sam/commands/loop-empty-match4.in1
-rw-r--r--test/sam/commands/loop-lines.in10
-rw-r--r--test/sam/commands/loop-lines1.cmd1
l---------test/sam/commands/loop-lines1.in1
-rw-r--r--test/sam/commands/loop-lines2.cmd1
l---------test/sam/commands/loop-lines2.in1
-rw-r--r--test/sam/commands/loop-lines3.cmd1
l---------test/sam/commands/loop-lines3.in1
-rw-r--r--test/sam/commands/loop-lines4.cmd1
l---------test/sam/commands/loop-lines4.in1
-rw-r--r--test/sam/commands/loop-lines5.cmd1
l---------test/sam/commands/loop-lines5.in1
-rw-r--r--test/sam/commands/loop-lines6.cmd1
l---------test/sam/commands/loop-lines6.in1
-rw-r--r--test/sam/commands/loop-lines7.cmd1
l---------test/sam/commands/loop-lines7.in1
-rw-r--r--test/sam/commands/loop-lines8.cmd1
l---------test/sam/commands/loop-lines8.in1
-rw-r--r--test/sam/commands/loop-lines9.cmd1
l---------test/sam/commands/loop-lines9.in1
-rw-r--r--test/sam/commands/pipe-in.cmd3
-rw-r--r--test/sam/commands/pipe-in.in10
-rw-r--r--test/sam/commands/pipe-out.cmd5
-rw-r--r--test/sam/commands/pipe-out.in1
-rw-r--r--test/sam/commands/repeated-shell.cmd2
-rw-r--r--test/sam/commands/repeated-shell.in2
-rw-r--r--test/sam/commands/unicode-replace.cmd1
-rw-r--r--test/sam/commands/unicode-replace.in5
-rw-r--r--test/sam/errors/conflict.cmd4
-rw-r--r--test/sam/errors/conflict.in1
-rw-r--r--test/sam/errors/read.cmd1
-rw-r--r--test/sam/errors/read.in1
-rw-r--r--test/sam/errors/unbalanced-group.cmd5
-rw-r--r--test/sam/errors/unbalanced-group.in1
-rw-r--r--test/sam/examples/comment-functions.cmd4
-rw-r--r--test/sam/examples/comment-functions.in15
-rw-r--r--test/sam/examples/delete-empty-lines.cmd1
-rw-r--r--test/sam/examples/delete-empty-lines.in17
-rw-r--r--test/sam/examples/swap-words.cmd4
-rw-r--r--test/sam/examples/swap-words.in1
-rwxr-xr-xtest/sam/test.sh96
-rw-r--r--test/sam/visrc.lua14
66 files changed, 400 insertions, 0 deletions
diff --git a/test/sam/.gitignore b/test/sam/.gitignore
new file mode 100644
index 0000000..589a89a
--- /dev/null
+++ b/test/sam/.gitignore
@@ -0,0 +1,3 @@
+*.out
+*.err
+*.disabled \ No newline at end of file
diff --git a/test/sam/Makefile b/test/sam/Makefile
new file mode 100644
index 0000000..3a91582
--- /dev/null
+++ b/test/sam/Makefile
@@ -0,0 +1,12 @@
+test: ../../vis
+ @./test.sh
+
+../../vis: ../../*.[ch]
+ @echo Compiling vis
+ @$(MAKE) -C ../..
+
+clean:
+ @echo cleaning
+ @find . -name '*.out' -o -name '*.err' | xargs rm -f
+
+.PHONY: clean test
diff --git a/test/sam/README.md b/test/sam/README.md
new file mode 100644
index 0000000..83cf2af
--- /dev/null
+++ b/test/sam/README.md
@@ -0,0 +1,73 @@
+Tests for vis - structural regular expression support
+-----------------------------------------------------
+
+We test the structural regular expression implementation by supplying
+the same command to both vis and [sam](http://sam.cat-v.org/). More
+concretely, we use a `ssam(1)` like script drive the non-graphical
+streaming interface of sam.
+
+These tests are intended to be run on a system with
+[9base](http://tools.suckless.org/9base) or
+[plan9port](https://swtch.com/plan9port/) installed.
+
+However, be aware that there exist some incompatibilities between the
+implementation in sam and vis which need to be taken into account
+when writing tests:
+
+ * _missing commands_: vis does currently deliberately not implement
+ some commands available in sam (e.g. `m`, `t`, `=` `=#`, `k`, `u`).
+ Additionally the commands operating on multiple files are either
+ not implemented or currently not supported by the testing
+ infrastructure.
+
+ * _different semantics_: some language constructs have slightly
+ different semantics. As an example in `sam` searches wrap around
+ while in `vis` they stop at the start/end of the file.
+
+ * _changes need to be in sequence_: sam will reject changes which are not
+ in sequence (i.e. all changes need to be performed in monotonically
+ increasing file position). The following will not work:
+
+ ```
+ ,x/pattern/ {
+ a/</
+ i/>/
+ }
+ ?changes not in sequence
+ ```
+
+ In contrast vis only requires that the changes are non-overlapping.
+ The above works as expected, but the following is rejected:
+
+ ```
+ ,x/pattern/ {
+ c/foo/
+ c/bar/
+ }
+ ?changes not in sequence
+ ```
+
+ * _spurious white spaces_: in sam an empty line/command affects the
+ dot (current range to operate on), namely it is extended to cover
+ the whole line. However in vis we ignore all white space between
+ commands. In order to avoid differing behavior avoid spurious white
+ space between your commands in the test cases.
+
+For now the tests need to take these differences into account, some of the
+vis behavior might be changed in the future.
+
+A test constitutes of 3 files, the first 2 of which are mandatory:
+
+ * `test.in` the file/buffer content with which the editor is started
+ * `test.cmd` a file containing the structural regular expression
+ command as you would type it in vis at the `:`-prompt or pass to
+ `ssam(1)`.
+ * `test.ref` if omitted, the output from sam will be considered as
+ reference.
+
+All commands of a `test.cmd` are executed in an implicit group `.{ ... }`.
+
+The top level shell script `test.sh` looks for these files in sub
+directories, executes both editors and compares the resulting output.
+
+Type `make` to run all tests.
diff --git a/test/sam/addresses/columns.cmd b/test/sam/addresses/columns.cmd
new file mode 100644
index 0000000..b00f736
--- /dev/null
+++ b/test/sam/addresses/columns.cmd
@@ -0,0 +1,4 @@
+,x/def|uvw/ {
+ g/def/ -/^/+#10 i/|/
+ g/uvw/ +/$/-#10 i/|/
+}
diff --git a/test/sam/addresses/columns.in b/test/sam/addresses/columns.in
new file mode 100644
index 0000000..34c740b
--- /dev/null
+++ b/test/sam/addresses/columns.in
@@ -0,0 +1,5 @@
+--
+abcdefghijklmnopqrstuvwxyz
+--
+abcdefghijklmnopqrstuvwxyz
+--
diff --git a/test/sam/addresses/first-last.cmd b/test/sam/addresses/first-last.cmd
new file mode 100644
index 0000000..ff1d6fc
--- /dev/null
+++ b/test/sam/addresses/first-last.cmd
@@ -0,0 +1,4 @@
+0/Emacs/,$-/Emacs/ {
+ i/>>/
+ a/<</
+}
diff --git a/test/sam/addresses/first-last.in b/test/sam/addresses/first-last.in
new file mode 100644
index 0000000..02d5652
--- /dev/null
+++ b/test/sam/addresses/first-last.in
@@ -0,0 +1,4 @@
+This manual is organized in a rather haphazard manner. The first
+several sections were written hastily in an attempt to provide a
+general introduction to the commands in Emacs and to try to show
+the method in the madness that is the Emacs command structure.
diff --git a/test/sam/addresses/lines.cmd b/test/sam/addresses/lines.cmd
new file mode 100644
index 0000000..20a62c6
--- /dev/null
+++ b/test/sam/addresses/lines.cmd
@@ -0,0 +1,6 @@
+10,10 c/--\n/
+16,17 {
+ i/</
+ a/>/
+}
+20d
diff --git a/test/sam/addresses/lines.in b/test/sam/addresses/lines.in
new file mode 100644
index 0000000..0ff3bbb
--- /dev/null
+++ b/test/sam/addresses/lines.in
@@ -0,0 +1,20 @@
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
diff --git a/test/sam/addresses/second.cmd b/test/sam/addresses/second.cmd
new file mode 100644
index 0000000..525bfa1
--- /dev/null
+++ b/test/sam/addresses/second.cmd
@@ -0,0 +1,4 @@
+0/Emacs/+// {
+ i/>>/
+ a/<</
+}
diff --git a/test/sam/addresses/second.in b/test/sam/addresses/second.in
new file mode 100644
index 0000000..02d5652
--- /dev/null
+++ b/test/sam/addresses/second.in
@@ -0,0 +1,4 @@
+This manual is organized in a rather haphazard manner. The first
+several sections were written hastily in an attempt to provide a
+general introduction to the commands in Emacs and to try to show
+the method in the madness that is the Emacs command structure.
diff --git a/test/sam/commands/filter-capitalize.cmd b/test/sam/commands/filter-capitalize.cmd
new file mode 100644
index 0000000..47e2a6f
--- /dev/null
+++ b/test/sam/commands/filter-capitalize.cmd
@@ -0,0 +1 @@
+,y/ / | tr a-z A-Z
diff --git a/test/sam/commands/filter-capitalize.in b/test/sam/commands/filter-capitalize.in
new file mode 100644
index 0000000..980a0d5
--- /dev/null
+++ b/test/sam/commands/filter-capitalize.in
@@ -0,0 +1 @@
+Hello World!
diff --git a/test/sam/commands/group.cmd b/test/sam/commands/group.cmd
new file mode 100644
index 0000000..8d77ed3
--- /dev/null
+++ b/test/sam/commands/group.cmd
@@ -0,0 +1,5 @@
+,x/Emacs/ {
+ i/V/
+ d
+ a/i/
+}
diff --git a/test/sam/commands/group.in b/test/sam/commands/group.in
new file mode 100644
index 0000000..203403a
--- /dev/null
+++ b/test/sam/commands/group.in
@@ -0,0 +1 @@
+Emacs Emacs!
diff --git a/test/sam/commands/long-text.cmd b/test/sam/commands/long-text.cmd
new file mode 100644
index 0000000..420cb30
--- /dev/null
+++ b/test/sam/commands/long-text.cmd
@@ -0,0 +1,11 @@
+i
+The
+quick
+brown
+fox
+jumps
+over
+the
+lazy
+dog
+.
diff --git a/test/sam/commands/long-text.in b/test/sam/commands/long-text.in
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/sam/commands/long-text.in
diff --git a/test/sam/commands/loop-empty-match1.cmd b/test/sam/commands/loop-empty-match1.cmd
new file mode 100644
index 0000000..e4dbf1c
--- /dev/null
+++ b/test/sam/commands/loop-empty-match1.cmd
@@ -0,0 +1,4 @@
+,x/svissvis/ y/s/ {
+ i/[/
+ a/]/
+}
diff --git a/test/sam/commands/loop-empty-match1.in b/test/sam/commands/loop-empty-match1.in
new file mode 100644
index 0000000..3e0c636
--- /dev/null
+++ b/test/sam/commands/loop-empty-match1.in
@@ -0,0 +1 @@
+visvissvisvis
diff --git a/test/sam/commands/loop-empty-match2.cmd b/test/sam/commands/loop-empty-match2.cmd
new file mode 100644
index 0000000..ebc9c9d
--- /dev/null
+++ b/test/sam/commands/loop-empty-match2.cmd
@@ -0,0 +1,4 @@
+,x/svissvis/ x/[^s]*/ {
+ i/[/
+ a/]/
+}
diff --git a/test/sam/commands/loop-empty-match2.in b/test/sam/commands/loop-empty-match2.in
new file mode 100644
index 0000000..3e0c636
--- /dev/null
+++ b/test/sam/commands/loop-empty-match2.in
@@ -0,0 +1 @@
+visvissvisvis
diff --git a/test/sam/commands/loop-empty-match3.cmd b/test/sam/commands/loop-empty-match3.cmd
new file mode 100644
index 0000000..69c1ded
--- /dev/null
+++ b/test/sam/commands/loop-empty-match3.cmd
@@ -0,0 +1,4 @@
+,x/svissvis/ y/[a-z]/ {
+ i/[/
+ a/]/
+}
diff --git a/test/sam/commands/loop-empty-match3.in b/test/sam/commands/loop-empty-match3.in
new file mode 100644
index 0000000..3e0c636
--- /dev/null
+++ b/test/sam/commands/loop-empty-match3.in
@@ -0,0 +1 @@
+visvissvisvis
diff --git a/test/sam/commands/loop-empty-match4.cmd b/test/sam/commands/loop-empty-match4.cmd
new file mode 100644
index 0000000..4d4ffe8
--- /dev/null
+++ b/test/sam/commands/loop-empty-match4.cmd
@@ -0,0 +1,4 @@
+,x/svissvis/ x/[^a-z]/ {
+ i/[/
+ a/]/
+}
diff --git a/test/sam/commands/loop-empty-match4.in b/test/sam/commands/loop-empty-match4.in
new file mode 100644
index 0000000..3e0c636
--- /dev/null
+++ b/test/sam/commands/loop-empty-match4.in
@@ -0,0 +1 @@
+visvissvisvis
diff --git a/test/sam/commands/loop-lines.in b/test/sam/commands/loop-lines.in
new file mode 100644
index 0000000..f00c965
--- /dev/null
+++ b/test/sam/commands/loop-lines.in
@@ -0,0 +1,10 @@
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
diff --git a/test/sam/commands/loop-lines1.cmd b/test/sam/commands/loop-lines1.cmd
new file mode 100644
index 0000000..f947289
--- /dev/null
+++ b/test/sam/commands/loop-lines1.cmd
@@ -0,0 +1 @@
+,x/^.*$/ a,\\,
diff --git a/test/sam/commands/loop-lines1.in b/test/sam/commands/loop-lines1.in
new file mode 120000
index 0000000..0ad8301
--- /dev/null
+++ b/test/sam/commands/loop-lines1.in
@@ -0,0 +1 @@
+loop-lines.in \ No newline at end of file
diff --git a/test/sam/commands/loop-lines2.cmd b/test/sam/commands/loop-lines2.cmd
new file mode 100644
index 0000000..696aab4
--- /dev/null
+++ b/test/sam/commands/loop-lines2.cmd
@@ -0,0 +1 @@
+,x/^.*$/ i,//,
diff --git a/test/sam/commands/loop-lines2.in b/test/sam/commands/loop-lines2.in
new file mode 120000
index 0000000..0ad8301
--- /dev/null
+++ b/test/sam/commands/loop-lines2.in
@@ -0,0 +1 @@
+loop-lines.in \ No newline at end of file
diff --git a/test/sam/commands/loop-lines3.cmd b/test/sam/commands/loop-lines3.cmd
new file mode 100644
index 0000000..9f16753
--- /dev/null
+++ b/test/sam/commands/loop-lines3.cmd
@@ -0,0 +1 @@
+,x/^/ c/#/
diff --git a/test/sam/commands/loop-lines3.in b/test/sam/commands/loop-lines3.in
new file mode 120000
index 0000000..0ad8301
--- /dev/null
+++ b/test/sam/commands/loop-lines3.in
@@ -0,0 +1 @@
+loop-lines.in \ No newline at end of file
diff --git a/test/sam/commands/loop-lines4.cmd b/test/sam/commands/loop-lines4.cmd
new file mode 100644
index 0000000..4ce51bf
--- /dev/null
+++ b/test/sam/commands/loop-lines4.cmd
@@ -0,0 +1 @@
+,x/$/ c/#/
diff --git a/test/sam/commands/loop-lines4.in b/test/sam/commands/loop-lines4.in
new file mode 120000
index 0000000..0ad8301
--- /dev/null
+++ b/test/sam/commands/loop-lines4.in
@@ -0,0 +1 @@
+loop-lines.in \ No newline at end of file
diff --git a/test/sam/commands/loop-lines5.cmd b/test/sam/commands/loop-lines5.cmd
new file mode 100644
index 0000000..45539d5
--- /dev/null
+++ b/test/sam/commands/loop-lines5.cmd
@@ -0,0 +1 @@
+,y/\n/ i/*/
diff --git a/test/sam/commands/loop-lines5.in b/test/sam/commands/loop-lines5.in
new file mode 120000
index 0000000..0ad8301
--- /dev/null
+++ b/test/sam/commands/loop-lines5.in
@@ -0,0 +1 @@
+loop-lines.in \ No newline at end of file
diff --git a/test/sam/commands/loop-lines6.cmd b/test/sam/commands/loop-lines6.cmd
new file mode 100644
index 0000000..8204e7d
--- /dev/null
+++ b/test/sam/commands/loop-lines6.cmd
@@ -0,0 +1 @@
+,y/\n/ a/*/
diff --git a/test/sam/commands/loop-lines6.in b/test/sam/commands/loop-lines6.in
new file mode 120000
index 0000000..0ad8301
--- /dev/null
+++ b/test/sam/commands/loop-lines6.in
@@ -0,0 +1 @@
+loop-lines.in \ No newline at end of file
diff --git a/test/sam/commands/loop-lines7.cmd b/test/sam/commands/loop-lines7.cmd
new file mode 100644
index 0000000..b948c78
--- /dev/null
+++ b/test/sam/commands/loop-lines7.cmd
@@ -0,0 +1 @@
+,x i/--/
diff --git a/test/sam/commands/loop-lines7.in b/test/sam/commands/loop-lines7.in
new file mode 120000
index 0000000..0ad8301
--- /dev/null
+++ b/test/sam/commands/loop-lines7.in
@@ -0,0 +1 @@
+loop-lines.in \ No newline at end of file
diff --git a/test/sam/commands/loop-lines8.cmd b/test/sam/commands/loop-lines8.cmd
new file mode 100644
index 0000000..3cb435a
--- /dev/null
+++ b/test/sam/commands/loop-lines8.cmd
@@ -0,0 +1 @@
+,x a/--/
diff --git a/test/sam/commands/loop-lines8.in b/test/sam/commands/loop-lines8.in
new file mode 120000
index 0000000..0ad8301
--- /dev/null
+++ b/test/sam/commands/loop-lines8.in
@@ -0,0 +1 @@
+loop-lines.in \ No newline at end of file
diff --git a/test/sam/commands/loop-lines9.cmd b/test/sam/commands/loop-lines9.cmd
new file mode 100644
index 0000000..f5e6d4c
--- /dev/null
+++ b/test/sam/commands/loop-lines9.cmd
@@ -0,0 +1 @@
+,x/^.*\n/ i/#/
diff --git a/test/sam/commands/loop-lines9.in b/test/sam/commands/loop-lines9.in
new file mode 120000
index 0000000..0ad8301
--- /dev/null
+++ b/test/sam/commands/loop-lines9.in
@@ -0,0 +1 @@
+loop-lines.in \ No newline at end of file
diff --git a/test/sam/commands/pipe-in.cmd b/test/sam/commands/pipe-in.cmd
new file mode 100644
index 0000000..1a67edb
--- /dev/null
+++ b/test/sam/commands/pipe-in.cmd
@@ -0,0 +1,3 @@
+0 < echo Before first line
+1 < echo Replace first line
+$ < echo New Last line
diff --git a/test/sam/commands/pipe-in.in b/test/sam/commands/pipe-in.in
new file mode 100644
index 0000000..f00c965
--- /dev/null
+++ b/test/sam/commands/pipe-in.in
@@ -0,0 +1,10 @@
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
diff --git a/test/sam/commands/pipe-out.cmd b/test/sam/commands/pipe-out.cmd
new file mode 100644
index 0000000..2a23da1
--- /dev/null
+++ b/test/sam/commands/pipe-out.cmd
@@ -0,0 +1,5 @@
+1 > cat > pipe-out.tmp
+0 < cat pipe-out.tmp
+0 r pipe-out.tmp
+! rm pipe-out.tmp
+0 < cat pipe-out.tmp
diff --git a/test/sam/commands/pipe-out.in b/test/sam/commands/pipe-out.in
new file mode 100644
index 0000000..557db03
--- /dev/null
+++ b/test/sam/commands/pipe-out.in
@@ -0,0 +1 @@
+Hello World
diff --git a/test/sam/commands/repeated-shell.cmd b/test/sam/commands/repeated-shell.cmd
new file mode 100644
index 0000000..643e1d1
--- /dev/null
+++ b/test/sam/commands/repeated-shell.cmd
@@ -0,0 +1,2 @@
+1 | tr a-z A-Z
+2 |
diff --git a/test/sam/commands/repeated-shell.in b/test/sam/commands/repeated-shell.in
new file mode 100644
index 0000000..f9264f7
--- /dev/null
+++ b/test/sam/commands/repeated-shell.in
@@ -0,0 +1,2 @@
+Hello
+World
diff --git a/test/sam/commands/unicode-replace.cmd b/test/sam/commands/unicode-replace.cmd
new file mode 100644
index 0000000..eb6cb82
--- /dev/null
+++ b/test/sam/commands/unicode-replace.cmd
@@ -0,0 +1 @@
+x/♪/ c/♫/
diff --git a/test/sam/commands/unicode-replace.in b/test/sam/commands/unicode-replace.in
new file mode 100644
index 0000000..2e7cca9
--- /dev/null
+++ b/test/sam/commands/unicode-replace.in
@@ -0,0 +1,5 @@
+♪
+♪♪
+♪♪♪
+♪♪
+♪
diff --git a/test/sam/errors/conflict.cmd b/test/sam/errors/conflict.cmd
new file mode 100644
index 0000000..8397024
--- /dev/null
+++ b/test/sam/errors/conflict.cmd
@@ -0,0 +1,4 @@
+,{
+c/text1/
+c/text2/
+}
diff --git a/test/sam/errors/conflict.in b/test/sam/errors/conflict.in
new file mode 100644
index 0000000..980a0d5
--- /dev/null
+++ b/test/sam/errors/conflict.in
@@ -0,0 +1 @@
+Hello World!
diff --git a/test/sam/errors/read.cmd b/test/sam/errors/read.cmd
new file mode 100644
index 0000000..7685f9d
--- /dev/null
+++ b/test/sam/errors/read.cmd
@@ -0,0 +1 @@
+1 r not-found
diff --git a/test/sam/errors/read.in b/test/sam/errors/read.in
new file mode 100644
index 0000000..1b88518
--- /dev/null
+++ b/test/sam/errors/read.in
@@ -0,0 +1 @@
+Read non-existing file
diff --git a/test/sam/errors/unbalanced-group.cmd b/test/sam/errors/unbalanced-group.cmd
new file mode 100644
index 0000000..0a8faf2
--- /dev/null
+++ b/test/sam/errors/unbalanced-group.cmd
@@ -0,0 +1,5 @@
+{
+ i/>/
+ {
+ a/</
+}
diff --git a/test/sam/errors/unbalanced-group.in b/test/sam/errors/unbalanced-group.in
new file mode 100644
index 0000000..8708690
--- /dev/null
+++ b/test/sam/errors/unbalanced-group.in
@@ -0,0 +1 @@
+Unbalanced brace in group
diff --git a/test/sam/examples/comment-functions.cmd b/test/sam/examples/comment-functions.cmd
new file mode 100644
index 0000000..87d04c4
--- /dev/null
+++ b/test/sam/examples/comment-functions.cmd
@@ -0,0 +1,4 @@
+x/^static/+- g/ int / .,+/^\}/ {
+ i,#if 0\n,
+ a,\n#endif\n,
+}
diff --git a/test/sam/examples/comment-functions.in b/test/sam/examples/comment-functions.in
new file mode 100644
index 0000000..49c2452
--- /dev/null
+++ b/test/sam/examples/comment-functions.in
@@ -0,0 +1,15 @@
+static int addi(int a, int b) {
+ return a+b;
+}
+
+static long addl(long a, long b) {
+ return a+b;
+}
+
+static int muli(int a, int b) {
+ return a*b;
+}
+
+static long mull(long a, long b) {
+ return a*b;
+}
diff --git a/test/sam/examples/delete-empty-lines.cmd b/test/sam/examples/delete-empty-lines.cmd
new file mode 100644
index 0000000..04b3459
--- /dev/null
+++ b/test/sam/examples/delete-empty-lines.cmd
@@ -0,0 +1 @@
+x g/^$/ d
diff --git a/test/sam/examples/delete-empty-lines.in b/test/sam/examples/delete-empty-lines.in
new file mode 100644
index 0000000..a82e316
--- /dev/null
+++ b/test/sam/examples/delete-empty-lines.in
@@ -0,0 +1,17 @@
+
+1
+
+2
+
+
+3
+
+
+
+4
+
+
+
+
+5
+
diff --git a/test/sam/examples/swap-words.cmd b/test/sam/examples/swap-words.cmd
new file mode 100644
index 0000000..43bbde6
--- /dev/null
+++ b/test/sam/examples/swap-words.cmd
@@ -0,0 +1,4 @@
+,x/(Emacs|vi)/{
+ g/Emacs/ v/....../ c/vi/
+ g/vi/ v/.../ c/Emacs/
+}
diff --git a/test/sam/examples/swap-words.in b/test/sam/examples/swap-words.in
new file mode 100644
index 0000000..bfdc4fc
--- /dev/null
+++ b/test/sam/examples/swap-words.in
@@ -0,0 +1 @@
+Emacs is better than vi. \ No newline at end of file
diff --git a/test/sam/test.sh b/test/sam/test.sh
new file mode 100755
index 0000000..ec5d003
--- /dev/null
+++ b/test/sam/test.sh
@@ -0,0 +1,96 @@
+#!/bin/sh
+
+NL='
+'
+
+export LANG="en_US.UTF-8"
+
+export VIS_PATH=.
+[ -z "$VIS" ] && VIS="../../vis"
+[ -z "$SAM" ] && SAM="sam"
+[ -z "$PLAN9" ] && PLAN9="/usr/local/plan9/bin"
+
+for SAM in "$SAM" "$PLAN9/sam" /usr/lib/plan9/bin/sam 9; do
+ if type "$SAM" >/dev/null 2>&1; then
+ break
+ fi
+done
+
+type "$SAM" >/dev/null 2>&1 || {
+ echo "sam(1) not found, skipping tests"
+ exit 0
+}
+
+[ "$SAM" = "9" ] && SAM="9 sam"
+
+echo "$SAM"
+$VIS -v
+
+if ! $VIS -v | grep '+lua' >/dev/null 2>&1; then
+ echo "vis compiled without lua support, skipping tests"
+ exit 0
+fi
+
+TESTS=$1
+[ -z "$TESTS" ] && TESTS=$(find . -name '*.cmd' | sed 's/\.cmd$//g')
+
+TESTS_RUN=0
+TESTS_OK=0
+
+for t in $TESTS; do
+ IN="$t.in"
+ SAM_OUT="$t.sam.out"
+ SAM_ERR="$t.sam.err"
+ VIS_OUT="$t.vis.out"
+ VIS_ERR="$t.vis.err"
+ REF="$t.ref"
+ rm -f "$SAM_OUT" "$SAM_ERR" "$VIS_OUT" "$VIS_ERR"
+ printf "Running test %s with sam ... " "$t"
+
+ {
+ echo ',{'
+ cat "$t.cmd"
+ echo '}'
+ echo ,
+ } | $SAM -d "$IN" > "$SAM_OUT" 2>/dev/null
+
+ if [ $? -ne 0 ]; then
+ printf "ERROR\n"
+ elif [ -e "$REF" ]; then
+ if cmp -s "$REF" "$SAM_OUT"; then
+ printf "OK\n"
+ else
+ printf "FAIL\n"
+ diff -u "$REF" "$SAM_OUT" > "$SAM_ERR"
+ fi
+ elif [ -e "$SAM_OUT" ]; then
+ REF="$SAM_OUT"
+ printf "OK\n"
+ fi
+
+ if [ ! -e "$REF" ]; then
+ printf " No reference solution, skipping.\n"
+ continue
+ fi
+
+ TESTS_RUN=$((TESTS_RUN+1))
+
+ $VIS '+qall!' "$IN" </dev/null 2>/dev/null
+ RETURN_CODE=$?
+
+ printf "Running test %s with vis ... " "$t"
+ if [ $RETURN_CODE -ne 0 -o ! -e "$VIS_OUT" ]; then
+ printf "ERROR\n"
+ elif cmp -s "$REF" "$VIS_OUT"; then
+ printf "OK\n"
+ TESTS_OK=$((TESTS_OK+1))
+ else
+ printf "FAIL\n"
+ diff -u "$REF" "$VIS_OUT" > "$VIS_ERR"
+ fi
+done
+
+printf "Tests ok %d/%d\n" $TESTS_OK $TESTS_RUN
+
+# set exit status
+[ $TESTS_OK -eq $TESTS_RUN ]
diff --git a/test/sam/visrc.lua b/test/sam/visrc.lua
new file mode 100644
index 0000000..315526f
--- /dev/null
+++ b/test/sam/visrc.lua
@@ -0,0 +1,14 @@
+vis.events = {}
+vis.events.win_open = function(win)
+ -- test.in file passed to vis
+ local in_file = win.file.name
+ if in_file then
+ -- use the corresponding test.cmd file
+ local cmd_file_name = string.gsub(in_file, '%.in$', '.cmd');
+ local cmd_file = io.open(cmd_file_name)
+ local cmd = cmd_file:read('*all')
+ vis:command(string.format(",{\n %s\n }", cmd))
+ local out_file_name = string.gsub(in_file, '%.in$', '.vis.out')
+ vis:command(string.format("w! %s", out_file_name))
+ end
+end