syntaxai/tdd.md · main · tools / sama-cli / src / b32_utils.test.sh
#!/usr/bin/env bash
# Sibling test for b32_utils.sh. Asserts the pure helpers behave
# as documented: profile parsing populates the PROFILE_* arrays,
# the file classifiers split on .test extension correctly, and
# the line counter matches the TS "split('\n').length" semantics.
#
# A minimal in-file harness (no bats dependency): each test calls
# `assert_eq` which prints PASS/FAIL and increments counters.
# Exit 0 if all assertions pass, 1 otherwise. Run from any cwd.
SAMA_SRC_DIR="$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)"
# shellcheck disable=SC1091
. "$SAMA_SRC_DIR/a31_constants.sh"
# shellcheck disable=SC1091
. "$SAMA_SRC_DIR/b32_utils.sh"
TESTS_RUN=0
TESTS_FAILED=0
assert_eq() {
local expected="$1" actual="$2" label="$3"
TESTS_RUN=$((TESTS_RUN + 1))
if [ "$expected" = "$actual" ]; then
printf " ok %s\n" "$label"
else
TESTS_FAILED=$((TESTS_FAILED + 1))
printf " FAIL %s\n expected: %s\n actual: %s\n" "$label" "$expected" "$actual"
fi
}
assert_contains() {
local haystack="$1" needle="$2" label="$3"
TESTS_RUN=$((TESTS_RUN + 1))
case "$haystack" in
*"$needle"*) printf " ok %s\n" "$label" ;;
*)
TESTS_FAILED=$((TESTS_FAILED + 1))
printf " FAIL %s\n haystack: %s\n needle: %s\n" "$label" "$haystack" "$needle"
;;
esac
}
mkfile() {
local content="$1" path="$2"
printf "%s" "$content" > "$path"
}
# Run tests in a temp dir so we don't touch the real repo profile.
TMP_DIR="$(mktemp -d)"
trap 'rm -rf "$TMP_DIR"' EXIT
# — parse_profile -------------------------------------------------
PROFILE_PATH="$TMP_DIR/test.profile.toml"
cat > "$PROFILE_PATH" <<'EOF'
sama_version = "2.0"
profile = "test-profile"
extension = ".sh"
[layers.0]
prefixes = ["a_"]
[layers.1]
sublayers = [
{ name = "core", prefix = "b_" },
]
[layers.2]
prefixes = ["c_"]
[layers.3]
prefixes = ["d_"]
EOF
parse_profile "$PROFILE_PATH"
assert_eq "test-profile" "$PROFILE_NAME" "parse_profile: PROFILE_NAME"
assert_eq "2.0" "$PROFILE_SAMA_VERSION" "parse_profile: PROFILE_SAMA_VERSION"
assert_eq ".sh" "$PROFILE_EXTENSION" "parse_profile: PROFILE_EXTENSION"
assert_eq "4" "${#PROFILE_PREFIXES[@]}" "parse_profile: 4 prefixes"
assert_eq "a_" "${PROFILE_PREFIXES[0]}" "parse_profile: layer-0 prefix"
assert_eq "b_" "${PROFILE_PREFIXES[1]}" "parse_profile: layer-1 prefix from sublayer"
assert_eq "core" "${PROFILE_SUBLAYER_NAMES[1]}" "parse_profile: layer-1 sublayer name"
# — file classifiers ----------------------------------------------
PROFILE_EXTENSION=".ts"
is_sama_file "src/a31_foo.ts" && r=0 || r=1
assert_eq "0" "$r" "is_sama_file: src/a31_foo.ts"
is_sama_file "src/a31_foo.test.ts" && r=0 || r=1
assert_eq "1" "$r" "is_sama_file rejects .test.ts"
is_test_file "src/a31_foo.test.ts" && r=0 || r=1
assert_eq "0" "$r" "is_test_file: .test.ts"
is_test_file "src/a31_foo.ts" && r=0 || r=1
assert_eq "1" "$r" "is_test_file rejects plain .ts"
# — declared_layer ------------------------------------------------
PROFILE_LAYERS=("0" "1" "1" "2" "3")
PROFILE_PREFIXES=("a31_" "b32_" "b51_" "c14_" "d21_")
PROFILE_SUBLAYER_NAMES=("default" "logic" "render" "io" "handlers")
PROFILE_SUBLAYER_INDEXES=("0" "0" "1" "0" "0")
result="$(declared_layer "src/b51_render_admin.ts")"
assert_eq "1 render 1 b51_" "$result" "declared_layer: b51_ → Layer 1 render"
result="$(declared_layer "src/unprefixed.ts")"
assert_eq "" "$result" "declared_layer: unprefixed returns empty"
# — count_lines ---------------------------------------------------
mkfile "a" "$TMP_DIR/one_no_nl.txt"
assert_eq "1" "$(count_lines "$TMP_DIR/one_no_nl.txt")" "count_lines: 'a' = 1"
mkfile "a\nb\n" "$TMP_DIR/two_with_nl.txt"
# printf %s doesn't interpret \n; use printf for real newlines
printf "a\nb\n" > "$TMP_DIR/two_with_nl.txt"
assert_eq "3" "$(count_lines "$TMP_DIR/two_with_nl.txt")" "count_lines: 'a\\nb\\n' = 3 (matches TS split)"
printf "" > "$TMP_DIR/empty.txt"
assert_eq "1" "$(count_lines "$TMP_DIR/empty.txt")" "count_lines: empty = 1"
# — strip_strings_and_comments -----------------------------------
PROFILE_EXTENSION=".ts"
mkfile "const x = \"hello\"; // a comment" "$TMP_DIR/strip.ts"
stripped="$(strip_strings_and_comments_file "$TMP_DIR/strip.ts")"
assert_contains "$stripped" "const x = " "strip preserves code"
# After stripping, "hello" should be whitespace and // ... should be whitespace.
case "$stripped" in
*"hello"*)
TESTS_FAILED=$((TESTS_FAILED + 1))
printf " FAIL strip removes string content\n leaked: %s\n" "$stripped"
;;
*)
TESTS_RUN=$((TESTS_RUN + 1))
printf " ok strip removes string content\n"
;;
esac
# — Summary -------------------------------------------------------
echo
if [ "$TESTS_FAILED" -eq 0 ]; then
printf "b32_utils.test.sh: %d/%d passed ✓\n" "$TESTS_RUN" "$TESTS_RUN"
exit 0
else
printf "b32_utils.test.sh: %d/%d passed, %d FAILED ✗\n" \
"$((TESTS_RUN - TESTS_FAILED))" "$TESTS_RUN" "$TESTS_FAILED"
exit 1
fi