Skip to content
Merged
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
17 changes: 17 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Tests

on:
pull_request:
push:
branches: [main]

jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
submodules: true

- name: Run tests
run: tests/run.sh
9 changes: 9 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[submodule "tests/bats"]
path = tests/bats
url = https://github.com/bats-core/bats-core.git
[submodule "tests/test_helper/bats-support"]
path = tests/test_helper/bats-support
url = https://github.com/bats-core/bats-support.git
[submodule "tests/test_helper/bats-assert"]
path = tests/test_helper/bats-assert
url = https://github.com/bats-core/bats-assert.git
1 change: 1 addition & 0 deletions skills/dld-audit-auto/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
name: dld-audit-auto
description: Autonomous audit — detects drift, fixes issues, and opens a PR. Designed for scheduled/CI execution without human interaction.
compatibility: Requires bash and git. Scripts use BASH_SOURCE for path resolution.
---

# /dld-audit-auto — Autonomous Audit & Fix
Expand Down
1 change: 1 addition & 0 deletions tests/bats
Submodule bats added at d9faff
13 changes: 13 additions & 0 deletions tests/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env bash
# Run all DLD Kit tests
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BATS="$SCRIPT_DIR/bats/bin/bats"

if [[ ! -x "$BATS" ]]; then
echo "Error: bats not found. Run: git submodule update --init --recursive" >&2
exit 1
fi

"$BATS" "$SCRIPT_DIR"/test_*.bats "$@"
133 changes: 133 additions & 0 deletions tests/test_annotations.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#!/usr/bin/env bats
# Tests for annotation scripts:
# dld-audit/scripts/find-annotations.sh
# dld-implement/scripts/verify-annotations.sh

load 'test_helper/common'

setup() {
setup_flat_project
}

teardown() {
teardown_project
}

# --- find-annotations.sh ---

@test "find-annotations finds annotation in source file" {
mkdir -p src
echo '// @decision(DL-001)' > src/main.ts
git add -A && git commit -m "add" --quiet

run bash "$SKILLS_DIR/dld-audit/scripts/find-annotations.sh"
assert_success
assert_output --partial "src/main.ts"
assert_output --partial "DL-001"
}

@test "find-annotations returns empty with no annotations" {
mkdir -p src
echo 'console.log("hello")' > src/main.ts
git add -A && git commit -m "add" --quiet

run bash "$SKILLS_DIR/dld-audit/scripts/find-annotations.sh"
assert_success
assert_output ""
}

@test "find-annotations finds multiple annotations in one file" {
mkdir -p src
cat > src/main.ts <<'EOF'
// @decision(DL-001)
function foo() {}

// @decision(DL-002)
function bar() {}
EOF
git add -A && git commit -m "add" --quiet

run bash "$SKILLS_DIR/dld-audit/scripts/find-annotations.sh"
assert_success
assert_output --partial "DL-001"
assert_output --partial "DL-002"
}

@test "find-annotations excludes node_modules" {
mkdir -p node_modules/pkg
echo '// @decision(DL-001)' > node_modules/pkg/index.js
git add -A && git commit -m "add" --quiet

run bash "$SKILLS_DIR/dld-audit/scripts/find-annotations.sh"
assert_success
assert_output ""
}

@test "find-annotations excludes decisions directory" {
create_decision "DL-001" "accepted"
git add -A && git commit -m "add" --quiet

run bash "$SKILLS_DIR/dld-audit/scripts/find-annotations.sh"
assert_success
# Decision files contain "id: DL-001" but not the annotation pattern, so this
# should be empty regardless. The exclusion matters when decision docs mention
# the annotation pattern in prose.
assert_output ""
}

@test "find-annotations outputs relative paths" {
mkdir -p src/deep/nested
echo '// @decision(DL-005)' > src/deep/nested/file.py
git add -A && git commit -m "add" --quiet

run bash "$SKILLS_DIR/dld-audit/scripts/find-annotations.sh"
assert_success
assert_output --partial "src/deep/nested/file.py"
# Should NOT contain the absolute path
refute_output --partial "$TEST_PROJECT/src"
}

# --- verify-annotations.sh ---

@test "verify-annotations succeeds when annotation exists" {
mkdir -p src
echo '// @decision(DL-001)' > src/main.ts

run bash "$SKILLS_DIR/dld-implement/scripts/verify-annotations.sh" DL-001
assert_success
assert_output --partial "All decisions have code annotations"
}

@test "verify-annotations fails when annotation missing" {
mkdir -p src
echo 'console.log("hello")' > src/main.ts

run bash "$SKILLS_DIR/dld-implement/scripts/verify-annotations.sh" DL-001
assert_failure
assert_output --partial "MISSING"
assert_output --partial "DL-001"
}

@test "verify-annotations checks multiple IDs" {
mkdir -p src
echo '// @decision(DL-001)' > src/a.ts
echo '// @decision(DL-002)' > src/b.ts

run bash "$SKILLS_DIR/dld-implement/scripts/verify-annotations.sh" DL-001 DL-002
assert_success
}

@test "verify-annotations reports all missing IDs" {
mkdir -p src
echo '// @decision(DL-001)' > src/a.ts

run bash "$SKILLS_DIR/dld-implement/scripts/verify-annotations.sh" DL-001 DL-002 DL-003
assert_failure
assert_output --partial "DL-002"
assert_output --partial "DL-003"
}

@test "verify-annotations fails with no arguments" {
run bash "$SKILLS_DIR/dld-implement/scripts/verify-annotations.sh"
assert_failure
}
64 changes: 64 additions & 0 deletions tests/test_audit_state.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#!/usr/bin/env bats
# Tests for dld-audit/scripts/update-audit-state.sh

load 'test_helper/common'

SCRIPT=""

setup() {
setup_flat_project
SCRIPT="$SKILLS_DIR/dld-audit/scripts/update-audit-state.sh"
}

teardown() {
teardown_project
}

@test "update-audit-state creates state file" {
run bash "$SCRIPT"
assert_success

[[ -f decisions/.dld-state.yaml ]]
run cat decisions/.dld-state.yaml
assert_output --partial "audit:"
assert_output --partial "last_run:"
assert_output --partial "commit_hash:"
}

@test "update-audit-state records git commit hash" {
bash "$SCRIPT"
hash="$(git rev-parse --short HEAD)"

run cat decisions/.dld-state.yaml
assert_output --partial "commit_hash: $hash"
}

@test "update-audit-state preserves snapshot section" {
cat > decisions/.dld-state.yaml <<'YAML'
snapshot:
last_run: 2026-01-10T08:00:00Z
decisions_included: 5
artifacts:
SNAPSHOT.md: 2026-01-10T08:00:00Z
OVERVIEW.md: 2026-01-10T08:00:00Z
YAML

bash "$SCRIPT"
run cat decisions/.dld-state.yaml
assert_output --partial "snapshot:"
assert_output --partial "decisions_included: 5"
assert_output --partial "audit:"
}

@test "update-audit-state replaces existing audit section" {
cat > decisions/.dld-state.yaml <<'YAML'
audit:
last_run: 2026-01-01T00:00:00Z
commit_hash: old1234
YAML

bash "$SCRIPT"
run cat decisions/.dld-state.yaml
refute_output --partial "old1234"
assert_output --partial "audit:"
}
95 changes: 95 additions & 0 deletions tests/test_collect_decisions.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
#!/usr/bin/env bats
# Tests for dld-snapshot/scripts/collect-active-decisions.sh

load 'test_helper/common'

SCRIPT=""

setup() {
setup_flat_project
SCRIPT="$SKILLS_DIR/dld-snapshot/scripts/collect-active-decisions.sh"
}

teardown() {
teardown_project
}

@test "collect-active-decisions outputs nothing with no decisions" {
run bash "$SCRIPT"
assert_success
assert_output ""
}

@test "collect-active-decisions returns only accepted decisions" {
create_decision "DL-001" "accepted"
create_decision "DL-002" "proposed"
create_decision "DL-003" "superseded"
create_decision "DL-004" "accepted"

run bash "$SCRIPT"
assert_success
assert_output --partial "DL-001"
assert_output --partial "DL-004"
refute_output --partial "id: DL-002"
refute_output --partial "id: DL-003"
}

@test "collect-active-decisions separates with boundary markers" {
create_decision "DL-001" "accepted"
create_decision "DL-002" "accepted"

run bash "$SCRIPT"
assert_success
assert_output --partial "===DLD_DECISION_BOUNDARY==="
}

@test "collect-active-decisions has no boundary before first decision" {
create_decision "DL-001" "accepted"
create_decision "DL-002" "accepted"

output="$(bash "$SCRIPT")"
# First line should be the frontmatter start, not a boundary
first_line="$(echo "$output" | head -1)"
assert_equal "$first_line" "---"
}

@test "collect-active-decisions outputs in ascending ID order" {
create_decision "DL-003" "accepted"
create_decision "DL-001" "accepted"

output="$(bash "$SCRIPT")"
# DL-001 content should appear before DL-003
pos_001="$(echo "$output" | grep -n "id: DL-001" | head -1 | cut -d: -f1)"
pos_003="$(echo "$output" | grep -n "id: DL-003" | head -1 | cut -d: -f1)"
[[ "$pos_001" -lt "$pos_003" ]]
}

@test "collect-active-decisions fails when records dir missing" {
rmdir decisions/records
run bash "$SCRIPT"
assert_failure
assert_output --partial "records directory not found"
}

@test "collect-active-decisions works with namespaced decisions" {
setup_namespaced_project
create_decision "DL-001" "accepted" "billing"
create_decision "DL-002" "proposed" "auth"
create_decision "DL-003" "accepted" "auth"

run bash "$SCRIPT"
assert_success
assert_output --partial "id: DL-001"
assert_output --partial "id: DL-003"
refute_output --partial "id: DL-002"
}

@test "collect-active-decisions includes full file content" {
create_decision "DL-001" "accepted"

run bash "$SCRIPT"
assert_success
assert_output --partial "## Context"
assert_output --partial "## Decision"
assert_output --partial "Test decision content for DL-001"
}
Loading
Loading