diff options
| author | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:25:19 +0300 |
|---|---|---|
| committer | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:25:19 +0300 |
| commit | f0f174696b38adfd6063bb74e5b48d2b864cb650 (patch) | |
| tree | 445ec6db16bfd8ecd36dfcb8907c852c8c104b10 /corebinutils/ed/tests | |
| parent | 0e49ba0e7b8b9bc8bdc61f8c80228252392e758e (diff) | |
| parent | 93528dc40c12704e0f9ca16475e97e68b4317fb9 (diff) | |
| download | Project-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.sh | 180 | ||||
| -rw-r--r-- | corebinutils/ed/tests/uu_decode.c | 132 |
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; +} |
