summaryrefslogtreecommitdiff
path: root/corebinutils/ed/tests
diff options
context:
space:
mode:
authorMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-02 18:25:19 +0300
committerMehmet Samet Duman <yongdohyun@projecttick.org>2026-04-02 18:25:19 +0300
commitf0f174696b38adfd6063bb74e5b48d2b864cb650 (patch)
tree445ec6db16bfd8ecd36dfcb8907c852c8c104b10 /corebinutils/ed/tests
parent0e49ba0e7b8b9bc8bdc61f8c80228252392e758e (diff)
parent93528dc40c12704e0f9ca16475e97e68b4317fb9 (diff)
downloadProject-Tick-f0f174696b38adfd6063bb74e5b48d2b864cb650.tar.gz
Project-Tick-f0f174696b38adfd6063bb74e5b48d2b864cb650.zip
Add 'corebinutils/ed/' from commit '93528dc40c12704e0f9ca16475e97e68b4317fb9'
git-subtree-dir: corebinutils/ed git-subtree-mainline: 0e49ba0e7b8b9bc8bdc61f8c80228252392e758e git-subtree-split: 93528dc40c12704e0f9ca16475e97e68b4317fb9
Diffstat (limited to 'corebinutils/ed/tests')
-rw-r--r--corebinutils/ed/tests/test.sh180
-rw-r--r--corebinutils/ed/tests/uu_decode.c132
2 files changed, 312 insertions, 0 deletions
diff --git a/corebinutils/ed/tests/test.sh b/corebinutils/ed/tests/test.sh
new file mode 100644
index 0000000000..a2a8b11550
--- /dev/null
+++ b/corebinutils/ed/tests/test.sh
@@ -0,0 +1,180 @@
+#!/bin/sh
+set -eu
+
+ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
+ED_BIN=${ED_BIN:-"$ROOT/out/ed"}
+CC=${CC:-cc}
+TMPDIR=${TMPDIR:-/tmp}
+WORKDIR=$(mktemp -d "$TMPDIR/ed-test.XXXXXX")
+REGRESS_DIR="$WORKDIR/regress"
+UUDECODE_BIN="$WORKDIR/uu_decode"
+RED_BIN="$WORKDIR/red"
+trap 'rm -rf "$WORKDIR"' EXIT INT TERM
+export LC_ALL=C
+
+fail() {
+ printf '%s\n' "FAIL: $1" >&2
+ exit 1
+}
+
+assert_eq() {
+ name=$1
+ expected=$2
+ actual=$3
+ if [ "$expected" != "$actual" ]; then
+ printf '%s\n' "FAIL: $name" >&2
+ printf '%s\n' "--- expected ---" >&2
+ printf '%s\n' "$expected" >&2
+ printf '%s\n' "--- actual ---" >&2
+ printf '%s\n' "$actual" >&2
+ exit 1
+ fi
+}
+
+assert_contains() {
+ name=$1
+ text=$2
+ pattern=$3
+ case $text in
+ *"$pattern"*) ;;
+ *) fail "$name" ;;
+ esac
+}
+
+run_capture() {
+ output_file=$1
+ status_file=$2
+ shift 2
+
+ set +e
+ "$@" >"$output_file" 2>&1
+ status=$?
+ set -e
+ printf '%s\n' "$status" >"$status_file"
+}
+
+build_uudecode() {
+ "$CC" -O2 -std=c17 -Wall -Wextra -Werror \
+ "$ROOT/tests/uu_decode.c" -o "$UUDECODE_BIN" \
+ || fail "failed to build uu decoder with $CC"
+}
+
+decode_regression_fixtures() {
+ "$UUDECODE_BIN" "$REGRESS_DIR/ascii.d.uu" "$REGRESS_DIR/ascii.d" \
+ || fail "failed to decode ascii.d.uu"
+ "$UUDECODE_BIN" "$REGRESS_DIR/ascii.r.uu" "$REGRESS_DIR/ascii.r" \
+ || fail "failed to decode ascii.r.uu"
+}
+
+run_regression_suite() {
+ known_issue='*** The script nl.red exited abnormally ***'
+
+ cp "$ROOT"/test/* "$REGRESS_DIR"/
+ decode_regression_fixtures
+
+ (
+ cd "$REGRESS_DIR"
+ sh ./mkscripts.sh "$ED_BIN" >/dev/null
+ sh ./ckscripts.sh "$ED_BIN" >/dev/null 2>&1 || true
+ ) || fail "upstream regression harness failed to run"
+
+ issues=$(cd "$REGRESS_DIR" && grep -h '\*\*\*' errs.o scripts.o || true)
+ if [ -n "$issues" ]; then
+ filtered_issues=$(printf '%s\n' "$issues" | grep -Fvx "$known_issue" || true)
+ [ -z "$filtered_issues" ] || fail "upstream regression failures detected:
+$filtered_issues"
+ fi
+}
+
+[ -x "$ED_BIN" ] || fail "missing binary: $ED_BIN"
+mkdir -p "$REGRESS_DIR"
+ln -sf "$ED_BIN" "$RED_BIN"
+build_uudecode
+
+usage_output=$("$ED_BIN" -Z 2>&1 || true)
+assert_contains "invalid option should print usage" "$usage_output" \
+ "usage: ed [-] [-sx] [-p string] [file]"
+
+crypt_option_output=$("$ED_BIN" -x 2>&1 || true)
+assert_contains "unsupported -x option should be explicit" "$crypt_option_output" \
+ "option -x is not supported on Linux"
+
+crypt_command_output=$(printf 'H\nx\nQ\n' | "$ED_BIN" -s 2>&1 || true)
+assert_contains "interactive x command should be explicit" "$crypt_command_output" \
+ "crypt mode is not supported on Linux"
+
+cat >"$WORKDIR/strict-input.txt" <<'EOF'
+line 1
+line 2
+EOF
+
+strict_append_output=$(cat <<EOF | "$ED_BIN" -s 2>&1 || true
+H
+r $WORKDIR/strict-input.txt
+1,\$a
+bad
+.
+Q
+EOF
+)
+assert_contains "append should reject address ranges" "$strict_append_output" \
+ "unexpected address"
+
+strict_read_output=$(cat <<EOF | "$ED_BIN" -s 2>&1 || true
+H
+r $WORKDIR/strict-input.txt
+1,\$r $WORKDIR/strict-input.txt
+Q
+EOF
+)
+assert_contains "read should reject address ranges" "$strict_read_output" \
+ "unexpected address"
+
+no_filename_output=$(printf 'H\nf\nQ\n' | "$ED_BIN" -s 2>&1 || true)
+assert_contains "f without current filename should fail" "$no_filename_output" \
+ "no current filename"
+
+cat <<EOF | "$ED_BIN" -s >/dev/null
+H
+r !printf "shell line\n"
+w $WORKDIR/shell-read.out
+Q
+EOF
+assert_eq "shell read output" "shell line" "$(cat "$WORKDIR/shell-read.out")"
+
+cat >"$WORKDIR/write-input.txt" <<'EOF'
+alpha
+beta
+EOF
+cat <<EOF | "$ED_BIN" -s >/dev/null
+H
+r $WORKDIR/write-input.txt
+w !cat > $WORKDIR/shell-write.out
+Q
+EOF
+assert_eq "shell write output" "$(cat "$WORKDIR/write-input.txt")" \
+ "$(cat "$WORKDIR/shell-write.out")"
+
+mkdir "$WORKDIR/scratch"
+printf 'a\nscratch check\n.\nQ\n' | env TMPDIR="$WORKDIR/scratch" \
+ "$ED_BIN" -s >/dev/null 2>&1
+[ -z "$(find "$WORKDIR/scratch" -mindepth 1 -maxdepth 1 -print)" ] \
+ || fail "scratch files were not cleaned up in TMPDIR"
+
+run_capture "$WORKDIR/red-shell.out" "$WORKDIR/red-shell.status" \
+ sh -c 'printf "H\n!true\nQ\n" | "$1" -s' sh "$RED_BIN"
+assert_eq "red shell restriction exit status" "2" \
+ "$(cat "$WORKDIR/red-shell.status")"
+assert_contains "red shell restriction message" \
+ "$(cat "$WORKDIR/red-shell.out")" "shell access restricted"
+
+run_capture "$WORKDIR/red-path.out" "$WORKDIR/red-path.status" \
+ sh -c 'printf "H\ne /tmp/blocked\nQ\n" | "$1" -s' sh "$RED_BIN"
+assert_eq "red path restriction exit status" "2" \
+ "$(cat "$WORKDIR/red-path.status")"
+assert_contains "red path restriction message" \
+ "$(cat "$WORKDIR/red-path.out")" "shell access restricted"
+
+run_regression_suite
+
+printf '%s\n' "PASS"
diff --git a/corebinutils/ed/tests/uu_decode.c b/corebinutils/ed/tests/uu_decode.c
new file mode 100644
index 0000000000..8f5b8e8a3d
--- /dev/null
+++ b/corebinutils/ed/tests/uu_decode.c
@@ -0,0 +1,132 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int
+decode_char(int c)
+{
+ return (c - 32) & 0x3f;
+}
+
+static int
+decode_line(const char *line, FILE *out)
+{
+ int length;
+ int produced;
+
+ length = decode_char((unsigned char)line[0]);
+ if (length == 0)
+ return 0;
+
+ line++;
+ produced = 0;
+ while (produced < length) {
+ unsigned char a;
+ unsigned char b;
+ unsigned char c;
+ unsigned char d;
+ unsigned char bytes[3];
+ int chunk;
+
+ if (line[0] == '\0' || line[1] == '\0' || line[2] == '\0' ||
+ line[3] == '\0') {
+ fprintf(stderr, "uu_decode: truncated uuencoded line\n");
+ return -1;
+ }
+
+ a = (unsigned char)decode_char((unsigned char)line[0]);
+ b = (unsigned char)decode_char((unsigned char)line[1]);
+ c = (unsigned char)decode_char((unsigned char)line[2]);
+ d = (unsigned char)decode_char((unsigned char)line[3]);
+ line += 4;
+
+ bytes[0] = (unsigned char)((a << 2) | (b >> 4));
+ bytes[1] = (unsigned char)((b << 4) | (c >> 2));
+ bytes[2] = (unsigned char)((c << 6) | d);
+
+ chunk = length - produced;
+ if (chunk > 3)
+ chunk = 3;
+ if (fwrite(bytes, 1, (size_t)chunk, out) != (size_t)chunk) {
+ fprintf(stderr, "uu_decode: write failed: %s\n",
+ strerror(errno));
+ return -1;
+ }
+ produced += chunk;
+ }
+
+ return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ FILE *in;
+ FILE *out;
+ char line[4096];
+ int seen_begin;
+
+ if (argc != 3) {
+ fprintf(stderr, "usage: %s input.uu output\n", argv[0]);
+ return 1;
+ }
+
+ in = fopen(argv[1], "r");
+ if (in == NULL) {
+ fprintf(stderr, "uu_decode: cannot open %s: %s\n", argv[1],
+ strerror(errno));
+ return 1;
+ }
+ out = fopen(argv[2], "wb");
+ if (out == NULL) {
+ fprintf(stderr, "uu_decode: cannot open %s: %s\n", argv[2],
+ strerror(errno));
+ fclose(in);
+ return 1;
+ }
+
+ seen_begin = 0;
+ while (fgets(line, sizeof(line), in) != NULL) {
+ size_t len;
+
+ len = strlen(line);
+ if (len > 0 && line[len - 1] == '\n')
+ line[len - 1] = '\0';
+
+ if (!seen_begin) {
+ if (strncmp(line, "begin ", 6) == 0)
+ seen_begin = 1;
+ continue;
+ }
+ if (strcmp(line, "end") == 0)
+ break;
+ if (decode_line(line, out) != 0) {
+ fclose(out);
+ fclose(in);
+ return 1;
+ }
+ }
+
+ if (fclose(out) != 0) {
+ fprintf(stderr, "uu_decode: cannot close %s: %s\n", argv[2],
+ strerror(errno));
+ fclose(in);
+ return 1;
+ }
+ if (fclose(in) != 0) {
+ fprintf(stderr, "uu_decode: cannot close %s: %s\n", argv[1],
+ strerror(errno));
+ return 1;
+ }
+ if (!seen_begin) {
+ fprintf(stderr, "uu_decode: missing begin line in %s\n", argv[1]);
+ return 1;
+ }
+
+ return 0;
+}