Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 0 additions & 21 deletions test/integration-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -81,27 +81,6 @@ check "no file returns empty" \

echo ""

# --- idstack-status ---
echo "## idstack-status"

check "no timeline shows empty state message" \
"rm -f .idstack/timeline.jsonl && $IDSTACK_DIR/bin/idstack-status | grep -q 'No course data yet'"

# Rebuild timeline for status tests
$IDSTACK_DIR/bin/idstack-timeline-log '{"skill":"needs-analysis","event":"completed","training_justified":true}'
$IDSTACK_DIR/bin/idstack-timeline-log '{"skill":"course-quality-review","event":"completed","score":65,"dimensions":{"teaching_presence":7,"social_presence":3,"cognitive_presence":5}}'

check "shows skills completed checkboxes" \
"$IDSTACK_DIR/bin/idstack-status | grep -q '\[x\] /needs-analysis'"

check "shows quality trend" \
"$IDSTACK_DIR/bin/idstack-status | grep -q 'Quality trend: 65'"

check "suggests next skill" \
"$IDSTACK_DIR/bin/idstack-status | grep -q 'Suggested next'"

echo ""

# --- idstack-gen-skills ---
echo "## idstack-gen-skills"

Expand Down
5 changes: 5 additions & 0 deletions test/smoke-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ if [ -x "$IDSTACK_DIR/test/test-manifest-merge.sh" ]; then
check "manifest-merge unit tests pass" "'$IDSTACK_DIR/test/test-manifest-merge.sh'"
fi

# idstack-status unit tests
if [ -x "$IDSTACK_DIR/test/test-status.sh" ]; then
check "idstack-status unit tests pass" "'$IDSTACK_DIR/test/test-status.sh'"
fi

# Version classifier (shared by setup + bin/idstack-doctor) must classify
# multi-digit versions correctly. Pinned to catch the pattern-fragility
# regression Gemini flagged twice.
Expand Down
120 changes: 120 additions & 0 deletions test/test-status.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#!/usr/bin/env bash
# Unit tests for bin/idstack-status.
# Run from the repo root (or sourced by smoke-test.sh).

set -e

PASS=0
FAIL=0
TOTAL=0

REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
STATUS="$REPO_ROOT/bin/idstack-status"
Comment on lines +11 to +12

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

If the repository path contains spaces or special characters (e.g., in CI environments or user directories), executing $STATUS directly inside eval will fail due to word splitting.

To prevent this, define a helper function status that safely wraps the executable with proper double-quoting, and use status instead of $STATUS in the assert calls.

Suggested change
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
STATUS="$REPO_ROOT/bin/idstack-status"
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
STATUS="$REPO_ROOT/bin/idstack-status"
status() {
"$STATUS" "$@"
}


assert() {
TOTAL=$((TOTAL + 1))
if eval "$2" >/dev/null 2>&1; then
PASS=$((PASS + 1))
echo " PASS: $1"
else
FAIL=$((FAIL + 1))
echo " FAIL: $1"
fi
}
Comment on lines +14 to +23

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

When an assertion fails, the standard output and error are redirected to /dev/null, making it extremely difficult to debug test failures.

Consider capturing the output of the command to a temporary log file and printing it when the assertion fails to provide helpful diagnostic information.

Suggested change
assert() {
TOTAL=$((TOTAL + 1))
if eval "$2" >/dev/null 2>&1; then
PASS=$((PASS + 1))
echo " PASS: $1"
else
FAIL=$((FAIL + 1))
echo " FAIL: $1"
fi
}
assert() {
TOTAL=$((TOTAL + 1))
local logfile="${WORK:-/tmp}/assert.log"
if eval "$2" >"$logfile" 2>&1; then
PASS=$((PASS + 1))
echo " PASS: $1"
else
FAIL=$((FAIL + 1))
echo " FAIL: $1"
if [ -s "$logfile" ]; then
echo " --- Output ---"
sed 's/^/ /' "$logfile"
echo " --------------"
fi
fi
rm -f "$logfile"
}


# Skip the suite if python3 is missing (the tool requires python3).
if ! command -v python3 >/dev/null 2>&1; then
echo "test-status: python3 not available, skipping"
exit 0
fi

if [ ! -x "$STATUS" ]; then
echo "test-status: $STATUS missing or not executable"
exit 1
fi

WORK=$(mktemp -d)
trap 'rm -rf "$WORK"' EXIT

# idstack-status looks for files relative to current working directory
cd "$WORK"

echo "test-status"
echo ""

# --- Test 1: No state ---
assert "no timeline shows empty state message" "$STATUS | grep -q 'No course data yet'"

# --- Test 2: Project name from manifest ---
mkdir -p .idstack
cat > .idstack/project.json <<'JSON'
{
"project_name": "Test Course 123"
}
JSON
cat > .idstack/timeline.jsonl <<'JSON'
{"skill":"needs-analysis","event":"completed","training_justified":true}
JSON
assert "project name from manifest" "$STATUS | grep -q 'Project: Test Course 123'"

# --- Test 3: Timeline parsing ---
cat > .idstack/timeline.jsonl <<'JSON'
{"skill":"needs-analysis","event":"completed","training_justified":true}
{"skill":"course-quality-review","event":"completed","score":65,"dimensions":{"teaching_presence":7,"social_presence":3,"cognitive_presence":5}}
{"skill":"course-quality-review","event":"completed","score":85,"dimensions":{"teaching_presence":8,"social_presence":7,"cognitive_presence":8}}
JSON
assert "shows skills completed checkboxes" "$STATUS | grep -q '\[x\] /needs-analysis'"
assert "shows quality trend" "$STATUS | grep -q 'Quality trend: 65 -> 85'"
assert "suggests next skill" "$STATUS | grep -q 'Suggested next: /learning-objectives'"

# --- Test 4: Learnings log ---
cat > .idstack/learnings.jsonl <<'JSON'
{"skill":"needs-analysis","type":"operational","insight":"Learned X"}
{"skill":"needs-analysis","type":"pattern","insight":"Learned Y"}
JSON
assert "shows learnings count" "$STATUS | grep -q 'Learnings: 2 discoveries stored'"

# --- Test 5: Exports directory ---
mkdir -p .idstack/exports/test-course-123
touch .idstack/exports/test-course-123/index.html
touch .idstack/exports/test-course-123/other-report.html
assert "reports section present" "$STATUS | grep -q 'Reports (open in a browser for the human view)'"
assert "index.html listed" "$STATUS | grep -q 'test-course-123/index.html'"
assert "other report listed" "$STATUS | grep -q 'test-course-123/other-report.html'"

# --- Test 6: Readiness flag - INCOMPLETE ---
# Using readiness should show incomplete when missing skills
assert "readiness incomplete due to missing reviews" "$STATUS --readiness | grep -q 'INCOMPLETE'"

# --- Test 7: Readiness flag - NOT-READY ---
# Complete the timeline for readiness
cat >> .idstack/timeline.jsonl <<'JSON'
{"skill":"red-team","event":"completed"}
{"skill":"accessibility-review","event":"completed"}
JSON

# Default manifest with poor scores
cat > .idstack/project.json <<'JSON'
{
"project_name": "Test Course 123",
"quality_review": {"overall_score": 60},
"red_team_audit": {"findings_summary": {"critical": 2}},
"accessibility_review": {"score": {"overall": 70}}
}
JSON
assert "readiness not-ready due to low scores" "$STATUS --readiness | grep -q 'NOT-READY'"

# --- Test 8: Readiness flag - READY TO EXPORT ---
cat > .idstack/project.json <<'JSON'
{
"project_name": "Test Course 123",
"quality_review": {"overall_score": 80},
"red_team_audit": {"findings_summary": {"critical": 0}},
"accessibility_review": {"score": {"overall": 90}}
}
JSON
assert "readiness ready to export" "$STATUS --readiness | grep -q 'READY TO EXPORT'"

echo ""
echo "test-status: $PASS/$TOTAL passed, $FAIL failed"
[ "$FAIL" -eq 0 ] && exit 0 || exit 1