git: f015e48a4a04 - main - ed: convert test suite to ATF/kyua
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 19 Feb 2026 09:47:19 UTC
The branch main has been updated by bapt:
URL: https://cgit.FreeBSD.org/src/commit/?id=f015e48a4a0482787b46e972754619a75475439c
commit f015e48a4a0482787b46e972754619a75475439c
Author: Baptiste Daroussin <bapt@FreeBSD.org>
AuthorDate: 2026-02-17 16:14:09 +0000
Commit: Baptiste Daroussin <bapt@FreeBSD.org>
CommitDate: 2026-02-19 09:46:42 +0000
ed: convert test suite to ATF/kyua
MFC After: 1 week
---
bin/ed/Makefile | 3 +
bin/ed/tests/Makefile | 3 +
bin/ed/tests/ed_test.sh | 1782 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 1788 insertions(+)
diff --git a/bin/ed/Makefile b/bin/ed/Makefile
index cad48082f186..07fee7478261 100644
--- a/bin/ed/Makefile
+++ b/bin/ed/Makefile
@@ -6,4 +6,7 @@ SRCS= buf.c glbl.c io.c main.c re.c sub.c undo.c
LINKS= ${BINDIR}/ed ${BINDIR}/red
MLINKS= ed.1 red.1
+HAS_TESTS=
+SUBDIR.${MK_TESTS}+= tests
+
.include <bsd.prog.mk>
diff --git a/bin/ed/tests/Makefile b/bin/ed/tests/Makefile
new file mode 100644
index 000000000000..b75f97bf4d63
--- /dev/null
+++ b/bin/ed/tests/Makefile
@@ -0,0 +1,3 @@
+ATF_TESTS_SH= ed_test
+
+.include <bsd.test.mk>
diff --git a/bin/ed/tests/ed_test.sh b/bin/ed/tests/ed_test.sh
new file mode 100755
index 000000000000..c67df8ae9f65
--- /dev/null
+++ b/bin/ed/tests/ed_test.sh
@@ -0,0 +1,1782 @@
+# SPDX-License-Identifier: BSD-2-Clause
+# Copyright (c) 2025 Baptiste Daroussin <bapt@FreeBSD.org>
+
+# Helper: create standard 5-line data file
+create_std_data()
+{
+ cat > "$1" <<'EOF'
+line 1
+line 2
+line 3
+line 4
+line5
+EOF
+}
+
+# ---------------------------------------------------------------------------
+# Append (a)
+# ---------------------------------------------------------------------------
+atf_test_case append
+append_head()
+{
+ atf_set "descr" "Test append command (a)"
+}
+
+append_body()
+{
+ create_std_data input.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+0a
+hello world
+.
+2a
+hello world!
+.
+$a
+hello world!!
+.
+w output.txt
+CMDS
+ cat > expected.txt <<'EOF'
+hello world
+line 1
+hello world!
+line 2
+line 3
+line 4
+line5
+hello world!!
+EOF
+ atf_check cmp output.txt expected.txt
+}
+
+# ---------------------------------------------------------------------------
+# Address parsing (addr)
+# ---------------------------------------------------------------------------
+atf_test_case address
+address_head()
+{
+ atf_set "descr" "Test complex address parsing"
+}
+address_body()
+{
+ cat > input.txt <<'EOF'
+line 1
+line 2
+line 3
+line 4
+line5
+1ine6
+line7
+line8
+line9
+EOF
+ ed -s - <<'CMDS'
+H
+r input.txt
+1 d
+1 1 d
+1,2,d
+1;+ + ,d
+1,2;., + 2d
+w output.txt
+CMDS
+ cat > expected.txt <<'EOF'
+line 2
+line9
+EOF
+ atf_check cmp output.txt expected.txt
+}
+
+# ---------------------------------------------------------------------------
+# Change (c)
+# ---------------------------------------------------------------------------
+atf_test_case change
+change_head()
+{
+ atf_set "descr" "Test change command (c)"
+}
+change_body()
+{
+ create_std_data input.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+1c
+at the top
+.
+4c
+in the middle
+.
+$c
+at the bottom
+.
+2,3c
+between top/middle
+.
+w output.txt
+CMDS
+ cat > expected.txt <<'EOF'
+at the top
+between top/middle
+in the middle
+at the bottom
+EOF
+ atf_check cmp output.txt expected.txt
+}
+
+# ---------------------------------------------------------------------------
+# Delete (d)
+# ---------------------------------------------------------------------------
+atf_test_case delete
+delete_head()
+{
+ atf_set "descr" "Test delete command (d)"
+}
+delete_body()
+{
+ create_std_data input.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+1d
+2;+1d
+$d
+w output.txt
+CMDS
+ printf 'line 2\n' > expected.txt
+ atf_check cmp output.txt expected.txt
+}
+
+# ---------------------------------------------------------------------------
+# Insert (i)
+# ---------------------------------------------------------------------------
+atf_test_case insert
+insert_head()
+{
+ atf_set "descr" "Test insert command (i)"
+}
+insert_body()
+{
+ create_std_data input.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+1i
+hello world
+.
+2i
+hello world!
+.
+$i
+hello world!!
+.
+w output.txt
+CMDS
+ cat > expected.txt <<'EOF'
+hello world
+hello world!
+line 1
+line 2
+line 3
+line 4
+hello world!!
+line5
+EOF
+ atf_check cmp output.txt expected.txt
+}
+
+# ---------------------------------------------------------------------------
+# Join (j)
+# ---------------------------------------------------------------------------
+atf_test_case join
+join_head()
+{
+ atf_set "descr" "Test join command (j)"
+}
+join_body()
+{
+ create_std_data input.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+1,1j
+2,3j
+w output.txt
+CMDS
+ cat > expected.txt <<'EOF'
+line 1
+line 2line 3
+line 4
+line5
+EOF
+ atf_check cmp output.txt expected.txt
+}
+
+# ---------------------------------------------------------------------------
+# Mark (k)
+# ---------------------------------------------------------------------------
+atf_test_case mark
+mark_head()
+{
+ atf_set "descr" "Test mark and reference commands (k, ')"
+}
+mark_body()
+{
+ create_std_data input.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+2ka
+1d
+'am$
+1ka
+0a
+hello world
+.
+'ad
+u
+'am0
+w output.txt
+CMDS
+ cat > expected.txt <<'EOF'
+line 3
+hello world
+line 4
+line5
+line 2
+EOF
+ atf_check cmp output.txt expected.txt
+}
+
+# ---------------------------------------------------------------------------
+# Move (m)
+# ---------------------------------------------------------------------------
+atf_test_case move
+move_head()
+{
+ atf_set "descr" "Test move command (m)";
+}
+move_body()
+{
+
+ create_std_data input.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+1,2m$
+1,2m$
+1,2m$
+$m0
+$m0
+2,3m1
+2,3m3
+w output.txt
+CMDS
+ cat > expected.txt <<'EOF'
+line5
+line 1
+line 2
+line 3
+line 4
+EOF
+ atf_check cmp output.txt expected.txt
+}
+
+# ---------------------------------------------------------------------------
+# Transfer / Copy (t)
+# ---------------------------------------------------------------------------
+atf_test_case transfer
+transfer_head()
+{
+ atf_set "descr" "Test transfer/copy command (t)";
+}
+transfer_body()
+{
+
+ create_std_data input.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+1t0
+2,3t2
+,t$
+w output.txt
+CMDS
+ cat > expected.txt <<'EOF'
+line 1
+line 1
+line 1
+line 2
+line 2
+line 3
+line 4
+line5
+line 1
+line 1
+line 1
+line 2
+line 2
+line 3
+line 4
+line5
+EOF
+ atf_check cmp output.txt expected.txt
+}
+
+atf_test_case transfer_search
+transfer_search_head()
+{
+ atf_set "descr" "Test transfer with address search (t)";
+}
+transfer_search_body()
+{
+
+ create_std_data input.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+t0;/./
+w output.txt
+CMDS
+ cat > expected.txt <<'EOF'
+line 1
+line5
+line 2
+line 3
+line 4
+line5
+EOF
+ atf_check cmp output.txt expected.txt
+}
+
+# ---------------------------------------------------------------------------
+# Undo (u)
+# ---------------------------------------------------------------------------
+atf_test_case undo
+undo_head()
+{
+ atf_set "descr" "Test undo command (u)";
+}
+undo_body()
+{
+
+ create_std_data input.txt
+ printf 'dummy\n' > readfile.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+1;r readfile.txt
+u
+a
+hello
+world
+.
+g/./s//x/\
+a\
+hello\
+world
+u
+u
+u
+a
+hello world!
+.
+u
+1,$d
+u
+2,3d
+u
+c
+hello world!!
+.
+u
+u
+-1;.,+1j
+u
+u
+u
+.,+1t$
+w output.txt
+CMDS
+ cat > expected.txt <<'EOF'
+line 1
+hello
+hello world!!
+line 2
+line 3
+line 4
+line5
+hello
+hello world!!
+EOF
+ atf_check cmp output.txt expected.txt
+}
+
+# ---------------------------------------------------------------------------
+# Global (g)
+# ---------------------------------------------------------------------------
+atf_test_case global_move
+global_move_head()
+{
+ atf_set "descr" "Test global command with move (g)";
+}
+global_move_body()
+{
+
+ create_std_data input.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+g/./m0
+g/./s/$/\
+hello world
+g/hello /s/lo/p!/\
+a\
+order
+w output.txt
+CMDS
+ cat > expected.txt <<'EOF'
+line5
+help! world
+order
+line 4
+help! world
+order
+line 3
+help! world
+order
+line 2
+help! world
+order
+line 1
+help! world
+order
+EOF
+ atf_check cmp output.txt expected.txt
+}
+
+atf_test_case global_change
+global_change_head()
+{
+ atf_set "descr" "Test global command with change (g)";
+}
+global_change_body()
+{
+
+ create_std_data input.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+g/[2-4]/-1,+1c\
+hello world
+w output.txt
+CMDS
+ printf 'hello world\n' > expected.txt
+ atf_check cmp output.txt expected.txt
+}
+
+atf_test_case global_substitute
+global_substitute_head()
+{
+ atf_set "descr" "Test global with substitute and move (g)";
+}
+global_substitute_body()
+{
+
+ create_std_data input.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+g/./s//x/\
+3m0
+g/./s/e/c/\
+2,3m1
+w output.txt
+CMDS
+ cat > expected.txt <<'EOF'
+linc 3
+xine 1
+xine 2
+xinc 4
+xinc5
+EOF
+ atf_check cmp output.txt expected.txt
+}
+
+atf_test_case global_undo
+global_undo_head()
+{
+ atf_set "descr" "Test global with undo (g)";
+}
+global_undo_body()
+{
+
+ create_std_data input.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+g/./s/./x/\
+u\
+s/./y/\
+u\
+s/./z/\
+u
+u
+0a
+hello
+.
+$a
+world
+.
+w output.txt
+CMDS
+ cat > expected.txt <<'EOF'
+hello
+zine 1
+line 2
+line 3
+line 4
+line5
+world
+EOF
+ atf_check cmp output.txt expected.txt
+}
+
+atf_test_case global_copy
+global_copy_head()
+{
+ atf_set "descr" "Test global with copy (g)";
+}
+global_copy_body()
+{
+
+ cat > input.txt <<'EOF'
+line 1
+line 2
+line 3
+EOF
+ ed -s - <<'CMDS'
+H
+r input.txt
+g/./1,3t$\
+1d
+w output.txt
+CMDS
+ cat > expected.txt <<'EOF'
+line 1
+line 2
+line 3
+line 2
+line 3
+line 1
+line 3
+line 1
+line 2
+EOF
+ atf_check cmp output.txt expected.txt
+}
+
+# ---------------------------------------------------------------------------
+# Inverse global (v)
+# ---------------------------------------------------------------------------
+atf_test_case inverse_global
+inverse_global_head()
+{
+ atf_set "descr" "Test inverse global command (v)";
+}
+inverse_global_body()
+{
+
+ create_std_data input.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+v/[ ]/m0
+v/[ ]/s/$/\
+hello world
+v/hello /s/lo/p!/\
+a\
+order
+w output.txt
+CMDS
+ cat > expected.txt <<'EOF'
+line5
+order
+hello world
+line 1
+order
+line 2
+order
+line 3
+order
+line 4
+order
+EOF
+ atf_check cmp output.txt expected.txt
+}
+
+# ---------------------------------------------------------------------------
+# Substitution (s)
+# ---------------------------------------------------------------------------
+atf_test_case subst_backreference
+subst_backreference_head()
+{
+ atf_set "descr" "Test substitute with backreferences (s)";
+}
+subst_backreference_body()
+{
+
+ create_std_data input.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+s/\([^ ][^ ]*\)/(\1)/g
+2s
+/3/s
+/\(4\)/sr
+/\(.\)/srg
+%s/i/&e/
+w output.txt
+CMDS
+ cat > expected.txt <<'EOF'
+liene 1
+(liene) (2)
+(liene) (3)
+liene (4)
+(()liene5)
+EOF
+ atf_check cmp output.txt expected.txt
+}
+
+atf_test_case subst_range
+subst_range_head()
+{
+ atf_set "descr" "Test substitute on range with count and repeat (s)";
+}
+subst_range_body()
+{
+
+ create_std_data input.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+,s/./(&)/3
+s/$/00
+2s//%/g
+s/^l
+w output.txt
+CMDS
+ cat > expected.txt <<'EOF'
+li(n)e 1
+i(n)e 200
+li(n)e 3
+li(n)e 4
+li(n)e500
+EOF
+ atf_check cmp output.txt expected.txt
+}
+
+atf_test_case subst_charclass
+subst_charclass_head()
+{
+ atf_set "descr" "Test substitute with character classes (s)";
+}
+subst_charclass_body()
+{
+
+ ed -s - <<'CMDS'
+H
+a
+hello/[]world
+.
+s/[/]/ /
+s/[[:digit:][]/ /
+s/[]]/ /
+w output.txt
+CMDS
+ printf 'hello world\n' > expected.txt
+ atf_check cmp output.txt expected.txt
+}
+
+# ---------------------------------------------------------------------------
+# Edit (e/E)
+# ---------------------------------------------------------------------------
+atf_test_case edit_file
+edit_file_head()
+{
+ atf_set "descr" "Test edit file command (E)";
+}
+edit_file_body()
+{
+
+ printf 'hello world\n' > input.txt
+ printf 'E e1_data.txt\n' > e1_data.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+E e1_data.txt
+w output.txt
+CMDS
+ printf 'E e1_data.txt\n' > expected.txt
+ atf_check cmp output.txt expected.txt
+}
+
+atf_test_case edit_command
+edit_command_head()
+{
+ atf_set "descr" "Test edit with shell command (E !)";
+}
+edit_command_body()
+{
+
+ printf 'E !echo hello world-\n' > input.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+E !echo hello world-
+w output.txt
+CMDS
+ printf 'hello world-\n' > expected.txt
+ atf_check cmp output.txt expected.txt
+}
+
+atf_test_case edit_reread
+edit_reread_head()
+{
+ atf_set "descr" "Test edit re-read default file (E)";
+}
+edit_reread_body()
+{
+
+ printf 'E !echo hello world-\n' > input.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+E
+w output.txt
+CMDS
+ printf 'E !echo hello world-\n' > expected.txt
+ atf_check cmp output.txt expected.txt
+}
+
+atf_test_case edit_lowercase
+edit_lowercase_head()
+{
+ atf_set "descr" "Test lowercase edit re-read (e)";
+}
+edit_lowercase_body()
+{
+
+ printf 'E !echo hello world-\n' > input.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+e
+w output.txt
+CMDS
+ printf 'E !echo hello world-\n' > expected.txt
+ atf_check cmp output.txt expected.txt
+}
+
+# ---------------------------------------------------------------------------
+# Read (r)
+# ---------------------------------------------------------------------------
+atf_test_case read_command
+read_command_head()
+{
+ atf_set "descr" "Test read with shell command (r !)";
+}
+read_command_body()
+{
+
+ create_std_data input.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+1;r !echo hello world
+1
+r !echo hello world
+w output.txt
+CMDS
+ cat > expected.txt <<'EOF'
+line 1
+hello world
+line 2
+line 3
+line 4
+line5
+hello world
+EOF
+ atf_check cmp output.txt expected.txt
+}
+
+atf_test_case read_default
+read_default_head()
+{
+ atf_set "descr" "Test read with default filename (r)";
+}
+read_default_body()
+{
+
+ create_std_data input.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+r
+w output.txt
+CMDS
+ cat > expected.txt <<'EOF'
+line 1
+line 2
+line 3
+line 4
+line5
+line 1
+line 2
+line 3
+line 4
+line5
+EOF
+ atf_check cmp output.txt expected.txt
+}
+
+atf_test_case read_file
+read_file_head()
+{
+ atf_set "descr" "Test read from file (r)";
+}
+read_file_body()
+{
+
+ printf 'r r3_data.txt\n' > r3_data.txt
+ ed -s - <<'CMDS'
+H
+r r3_data.txt
+r r3_data.txt
+w output.txt
+CMDS
+ cat > expected.txt <<'EOF'
+r r3_data.txt
+r r3_data.txt
+EOF
+ atf_check cmp output.txt expected.txt
+}
+
+# ---------------------------------------------------------------------------
+# Write (w)
+# ---------------------------------------------------------------------------
+atf_test_case write_pipe
+write_pipe_head()
+{
+ atf_set "descr" "Test write to shell command (w !)";
+}
+write_pipe_body()
+{
+
+ create_std_data input.txt
+ ed -s - <<'CMDS'
+H
+r input.txt
+w !cat >\!.z
+r \!.z
+w output.txt
+CMDS
+ cat > expected.txt <<'EOF'
+line 1
+line 2
+line 3
+line 4
+line5
+line 1
+line 2
+line 3
+line 4
+line5
+EOF
+ atf_check cmp output.txt expected.txt
+}
+
+# ---------------------------------------------------------------------------
+# Quit (q)
+# ---------------------------------------------------------------------------
+atf_test_case quit
+quit_head()
+{
+ atf_set "descr" "Test quit command (q)";
+}
+quit_body()
+{
+
+ ed -s - <<'CMDS'
+H
+w output.txt
+a
+hello
+.
+q
+CMDS
+ atf_check -s exit:0 test ! -s output.txt
+}
+
+# ---------------------------------------------------------------------------
+# Shell command (!)
+# ---------------------------------------------------------------------------
+atf_test_case shell_command
+shell_command_head()
+{
+ atf_set "descr" "Test shell command execution (!)";
+}
+shell_command_body()
+{
+
+ ed -s - <<'CMDS'
+H
+!read one
+hello, world
+a
+okay
+.
*** 841 LINES SKIPPED ***