loki-mode 6.23.0 → 6.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/loki +963 -0
- package/dashboard/__init__.py +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
package/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: loki-mode
|
|
|
3
3
|
description: Multi-agent autonomous startup system. Triggers on "Loki Mode". Takes PRD to deployed product with minimal human intervention. Requires --dangerously-skip-permissions flag.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Loki Mode v6.
|
|
6
|
+
# Loki Mode v6.24.0
|
|
7
7
|
|
|
8
8
|
**You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
|
|
9
9
|
|
|
@@ -267,4 +267,4 @@ The following features are documented in skill modules but not yet fully automat
|
|
|
267
267
|
| Quality gates 3-reviewer system | Implemented (v5.35.0) | 5 specialist reviewers in `skills/quality-gates.md`; execution in run.sh |
|
|
268
268
|
| Benchmarks (HumanEval, SWE-bench) | Infrastructure only | Runner scripts and datasets exist in `benchmarks/`; no published results |
|
|
269
269
|
|
|
270
|
-
**v6.
|
|
270
|
+
**v6.24.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
6.
|
|
1
|
+
6.24.0
|
package/autonomy/loki
CHANGED
|
@@ -439,6 +439,7 @@ show_help() {
|
|
|
439
439
|
echo " onboard [path] Analyze a repo and generate CLAUDE.md (structure, conventions, commands)"
|
|
440
440
|
echo " plan <PRD> Dry-run PRD analysis: complexity, cost, and execution plan"
|
|
441
441
|
echo " ci [opts] CI/CD quality gate integration (--pr, --report, --github-comment)"
|
|
442
|
+
echo " test [opts] AI-powered test generation (--file, --dir, --changed, --dry-run)"
|
|
442
443
|
echo " version Show version"
|
|
443
444
|
echo " help Show this help"
|
|
444
445
|
echo ""
|
|
@@ -9197,6 +9198,9 @@ main() {
|
|
|
9197
9198
|
ci)
|
|
9198
9199
|
cmd_ci "$@"
|
|
9199
9200
|
;;
|
|
9201
|
+
test)
|
|
9202
|
+
cmd_test "$@"
|
|
9203
|
+
;;
|
|
9200
9204
|
version|--version|-v)
|
|
9201
9205
|
cmd_version
|
|
9202
9206
|
;;
|
|
@@ -15326,4 +15330,963 @@ for t in tests:
|
|
|
15326
15330
|
return "$exit_code"
|
|
15327
15331
|
}
|
|
15328
15332
|
|
|
15333
|
+
# AI-powered test generation (v6.24.0)
|
|
15334
|
+
cmd_test() {
|
|
15335
|
+
local test_file=""
|
|
15336
|
+
local test_dir=""
|
|
15337
|
+
local test_changed=false
|
|
15338
|
+
local test_coverage=80
|
|
15339
|
+
local test_format=""
|
|
15340
|
+
local test_output=""
|
|
15341
|
+
local test_dry_run=false
|
|
15342
|
+
local test_json=false
|
|
15343
|
+
local test_verbose=false
|
|
15344
|
+
|
|
15345
|
+
while [[ $# -gt 0 ]]; do
|
|
15346
|
+
case "$1" in
|
|
15347
|
+
--help|-h)
|
|
15348
|
+
echo -e "${BOLD}loki test${NC} - AI-powered test generation"
|
|
15349
|
+
echo ""
|
|
15350
|
+
echo "Usage: loki test [options] [file-or-dir]"
|
|
15351
|
+
echo ""
|
|
15352
|
+
echo "Analyzes source files and generates comprehensive test suites."
|
|
15353
|
+
echo "Detects language and framework automatically. Works without API keys."
|
|
15354
|
+
echo ""
|
|
15355
|
+
echo "Sources (default: git-changed files):"
|
|
15356
|
+
echo " --file <path> Test a specific file"
|
|
15357
|
+
echo " --dir <path> Test all files in a directory"
|
|
15358
|
+
echo " --changed Test only git-changed files (default if no source given)"
|
|
15359
|
+
echo " <file-or-dir> Positional: auto-detect file or directory"
|
|
15360
|
+
echo ""
|
|
15361
|
+
echo "Options:"
|
|
15362
|
+
echo " --coverage <n> Target coverage percentage (default: 80)"
|
|
15363
|
+
echo " --format <fmt> Test framework: auto, jest, pytest, vitest, mocha, go-test"
|
|
15364
|
+
echo " --output <path> Custom output directory for generated tests"
|
|
15365
|
+
echo " --dry-run Preview what tests would be generated without writing"
|
|
15366
|
+
echo " --json JSON output"
|
|
15367
|
+
echo " --verbose Detailed output"
|
|
15368
|
+
echo " --help, -h Show this help"
|
|
15369
|
+
echo ""
|
|
15370
|
+
echo "Supported languages:"
|
|
15371
|
+
echo " JavaScript/TypeScript (.js, .ts, .jsx, .tsx) -> jest, vitest, mocha"
|
|
15372
|
+
echo " Python (.py) -> pytest"
|
|
15373
|
+
echo " Go (.go) -> go-test"
|
|
15374
|
+
echo " Rust (.rs) -> cargo-test"
|
|
15375
|
+
echo " Java (.java) -> junit"
|
|
15376
|
+
echo " Ruby (.rb) -> rspec"
|
|
15377
|
+
echo " Shell/Bash (.sh) -> bats"
|
|
15378
|
+
echo ""
|
|
15379
|
+
echo "Exit codes:"
|
|
15380
|
+
echo " 0 Tests generated successfully"
|
|
15381
|
+
echo " 1 No testable files found"
|
|
15382
|
+
echo " 2 Error (invalid arguments, missing paths)"
|
|
15383
|
+
echo ""
|
|
15384
|
+
echo "Examples:"
|
|
15385
|
+
echo " loki test # Generate tests for git-changed files"
|
|
15386
|
+
echo " loki test --file src/utils.ts # Test a specific file"
|
|
15387
|
+
echo " loki test --dir src/lib/ # Test all files in directory"
|
|
15388
|
+
echo " loki test --changed --format jest # Changed files, force Jest format"
|
|
15389
|
+
echo " loki test --dry-run # Preview without writing"
|
|
15390
|
+
echo " loki test --coverage 90 # Target 90% coverage"
|
|
15391
|
+
echo " loki test --json # Machine-readable output"
|
|
15392
|
+
echo " loki test src/utils.ts # Positional file argument"
|
|
15393
|
+
return 0
|
|
15394
|
+
;;
|
|
15395
|
+
--file)
|
|
15396
|
+
shift
|
|
15397
|
+
test_file="${1:-}"
|
|
15398
|
+
if [ -z "$test_file" ]; then
|
|
15399
|
+
echo -e "${RED}Error: --file requires a path${NC}"
|
|
15400
|
+
return 2
|
|
15401
|
+
fi
|
|
15402
|
+
shift
|
|
15403
|
+
;;
|
|
15404
|
+
--dir)
|
|
15405
|
+
shift
|
|
15406
|
+
test_dir="${1:-}"
|
|
15407
|
+
if [ -z "$test_dir" ]; then
|
|
15408
|
+
echo -e "${RED}Error: --dir requires a path${NC}"
|
|
15409
|
+
return 2
|
|
15410
|
+
fi
|
|
15411
|
+
shift
|
|
15412
|
+
;;
|
|
15413
|
+
--changed) test_changed=true; shift ;;
|
|
15414
|
+
--coverage)
|
|
15415
|
+
shift
|
|
15416
|
+
test_coverage="${1:-80}"
|
|
15417
|
+
if ! [[ "$test_coverage" =~ ^[0-9]+$ ]] || [ "$test_coverage" -lt 1 ] || [ "$test_coverage" -gt 100 ]; then
|
|
15418
|
+
echo -e "${RED}Error: --coverage must be a number between 1 and 100${NC}"
|
|
15419
|
+
return 2
|
|
15420
|
+
fi
|
|
15421
|
+
shift
|
|
15422
|
+
;;
|
|
15423
|
+
--format)
|
|
15424
|
+
shift
|
|
15425
|
+
test_format="${1:-}"
|
|
15426
|
+
if [ -z "$test_format" ]; then
|
|
15427
|
+
echo -e "${RED}Error: --format requires a framework name${NC}"
|
|
15428
|
+
return 2
|
|
15429
|
+
fi
|
|
15430
|
+
test_format="$(echo "$test_format" | tr '[:upper:]' '[:lower:]')"
|
|
15431
|
+
case "$test_format" in
|
|
15432
|
+
auto|jest|pytest|vitest|mocha|go-test|cargo-test|junit|rspec|bats) ;;
|
|
15433
|
+
*) echo -e "${RED}Error: unsupported format '$test_format'. Use: auto, jest, pytest, vitest, mocha, go-test, cargo-test, junit, rspec, bats${NC}"; return 2 ;;
|
|
15434
|
+
esac
|
|
15435
|
+
shift
|
|
15436
|
+
;;
|
|
15437
|
+
--output)
|
|
15438
|
+
shift
|
|
15439
|
+
test_output="${1:-}"
|
|
15440
|
+
if [ -z "$test_output" ]; then
|
|
15441
|
+
echo -e "${RED}Error: --output requires a path${NC}"
|
|
15442
|
+
return 2
|
|
15443
|
+
fi
|
|
15444
|
+
shift
|
|
15445
|
+
;;
|
|
15446
|
+
--dry-run) test_dry_run=true; shift ;;
|
|
15447
|
+
--json) test_json=true; shift ;;
|
|
15448
|
+
--verbose) test_verbose=true; shift ;;
|
|
15449
|
+
-*)
|
|
15450
|
+
echo -e "${RED}Unknown option: $1${NC}"
|
|
15451
|
+
echo "Run 'loki test --help' for usage."
|
|
15452
|
+
return 2
|
|
15453
|
+
;;
|
|
15454
|
+
*)
|
|
15455
|
+
# Positional argument: auto-detect file or directory
|
|
15456
|
+
if [ -f "$1" ]; then
|
|
15457
|
+
test_file="$1"
|
|
15458
|
+
elif [ -d "$1" ]; then
|
|
15459
|
+
test_dir="$1"
|
|
15460
|
+
else
|
|
15461
|
+
echo -e "${RED}Error: '$1' is not a file or directory${NC}"
|
|
15462
|
+
return 2
|
|
15463
|
+
fi
|
|
15464
|
+
shift
|
|
15465
|
+
;;
|
|
15466
|
+
esac
|
|
15467
|
+
done
|
|
15468
|
+
|
|
15469
|
+
# Default to --changed if no source specified
|
|
15470
|
+
if [ -z "$test_file" ] && [ -z "$test_dir" ] && [ "$test_changed" = false ]; then
|
|
15471
|
+
test_changed=true
|
|
15472
|
+
fi
|
|
15473
|
+
|
|
15474
|
+
# --- Collect source files ---
|
|
15475
|
+
local -a source_files=()
|
|
15476
|
+
|
|
15477
|
+
if [ -n "$test_file" ]; then
|
|
15478
|
+
if [ ! -f "$test_file" ]; then
|
|
15479
|
+
echo -e "${RED}Error: file not found: $test_file${NC}"
|
|
15480
|
+
return 2
|
|
15481
|
+
fi
|
|
15482
|
+
source_files+=("$test_file")
|
|
15483
|
+
elif [ -n "$test_dir" ]; then
|
|
15484
|
+
if [ ! -d "$test_dir" ]; then
|
|
15485
|
+
echo -e "${RED}Error: directory not found: $test_dir${NC}"
|
|
15486
|
+
return 2
|
|
15487
|
+
fi
|
|
15488
|
+
while IFS= read -r f; do
|
|
15489
|
+
source_files+=("$f")
|
|
15490
|
+
done < <(_test_find_source_files "$test_dir")
|
|
15491
|
+
elif [ "$test_changed" = true ]; then
|
|
15492
|
+
while IFS= read -r f; do
|
|
15493
|
+
[ -n "$f" ] && [ -f "$f" ] && source_files+=("$f")
|
|
15494
|
+
done < <(git diff --name-only HEAD 2>/dev/null; git diff --name-only --cached 2>/dev/null; git diff --name-only 2>/dev/null)
|
|
15495
|
+
# Deduplicate
|
|
15496
|
+
if [ ${#source_files[@]} -gt 0 ]; then
|
|
15497
|
+
local -a unique_files=()
|
|
15498
|
+
local seen_list=""
|
|
15499
|
+
for f in "${source_files[@]}"; do
|
|
15500
|
+
if [[ "$seen_list" != *"|$f|"* ]]; then
|
|
15501
|
+
seen_list="${seen_list}|$f|"
|
|
15502
|
+
unique_files+=("$f")
|
|
15503
|
+
fi
|
|
15504
|
+
done
|
|
15505
|
+
source_files=("${unique_files[@]}")
|
|
15506
|
+
fi
|
|
15507
|
+
fi
|
|
15508
|
+
|
|
15509
|
+
# Filter to testable source files only (exclude test files, configs, etc.)
|
|
15510
|
+
local -a testable_files=()
|
|
15511
|
+
for f in "${source_files[@]}"; do
|
|
15512
|
+
if _test_is_testable_file "$f"; then
|
|
15513
|
+
testable_files+=("$f")
|
|
15514
|
+
fi
|
|
15515
|
+
done
|
|
15516
|
+
|
|
15517
|
+
if [ ${#testable_files[@]} -eq 0 ]; then
|
|
15518
|
+
if [ "$test_json" = true ]; then
|
|
15519
|
+
echo '{"status":"no_files","message":"No testable source files found","files_scanned":'"${#source_files[@]}"'}'
|
|
15520
|
+
else
|
|
15521
|
+
echo -e "${YELLOW}No testable source files found.${NC}"
|
|
15522
|
+
if [ "$test_changed" = true ]; then
|
|
15523
|
+
echo "Tip: Use --file or --dir to specify source files directly."
|
|
15524
|
+
fi
|
|
15525
|
+
fi
|
|
15526
|
+
return 1
|
|
15527
|
+
fi
|
|
15528
|
+
|
|
15529
|
+
# --- Generate tests ---
|
|
15530
|
+
local total_files=${#testable_files[@]}
|
|
15531
|
+
local generated=0
|
|
15532
|
+
local skipped=0
|
|
15533
|
+
local -a generated_paths=()
|
|
15534
|
+
local json_entries=""
|
|
15535
|
+
|
|
15536
|
+
if [ "$test_json" = false ] && [ "$test_dry_run" = false ]; then
|
|
15537
|
+
echo -e "${BOLD}Loki Test Generator${NC}"
|
|
15538
|
+
echo -e "Target coverage: ${CYAN}${test_coverage}%${NC}"
|
|
15539
|
+
echo -e "Files to process: ${CYAN}${total_files}${NC}"
|
|
15540
|
+
echo ""
|
|
15541
|
+
elif [ "$test_json" = false ] && [ "$test_dry_run" = true ]; then
|
|
15542
|
+
echo -e "${BOLD}Loki Test Generator (dry run)${NC}"
|
|
15543
|
+
echo -e "Files to process: ${CYAN}${total_files}${NC}"
|
|
15544
|
+
echo ""
|
|
15545
|
+
fi
|
|
15546
|
+
|
|
15547
|
+
for src_file in "${testable_files[@]}"; do
|
|
15548
|
+
local lang=""
|
|
15549
|
+
local framework=""
|
|
15550
|
+
local test_path=""
|
|
15551
|
+
|
|
15552
|
+
# Detect language
|
|
15553
|
+
lang=$(_test_detect_language "$src_file")
|
|
15554
|
+
if [ -z "$lang" ]; then
|
|
15555
|
+
((++skipped))
|
|
15556
|
+
[ "$test_verbose" = true ] && echo -e " ${DIM}Skip: $src_file (unsupported language)${NC}"
|
|
15557
|
+
continue
|
|
15558
|
+
fi
|
|
15559
|
+
|
|
15560
|
+
# Detect or use specified framework
|
|
15561
|
+
if [ -n "$test_format" ] && [ "$test_format" != "auto" ]; then
|
|
15562
|
+
framework="$test_format"
|
|
15563
|
+
else
|
|
15564
|
+
framework=$(_test_detect_framework "$lang")
|
|
15565
|
+
fi
|
|
15566
|
+
|
|
15567
|
+
# Determine test output path
|
|
15568
|
+
test_path=$(_test_output_path "$src_file" "$lang" "$framework" "$test_output")
|
|
15569
|
+
|
|
15570
|
+
# Extract testable constructs
|
|
15571
|
+
local constructs=""
|
|
15572
|
+
constructs=$(_test_extract_constructs "$src_file" "$lang")
|
|
15573
|
+
|
|
15574
|
+
if [ -z "$constructs" ]; then
|
|
15575
|
+
((++skipped))
|
|
15576
|
+
[ "$test_verbose" = true ] && echo -e " ${DIM}Skip: $src_file (no testable constructs found)${NC}"
|
|
15577
|
+
continue
|
|
15578
|
+
fi
|
|
15579
|
+
|
|
15580
|
+
local construct_count
|
|
15581
|
+
construct_count=$(echo "$constructs" | wc -l | tr -d ' ')
|
|
15582
|
+
|
|
15583
|
+
if [ "$test_dry_run" = true ]; then
|
|
15584
|
+
if [ "$test_json" = true ]; then
|
|
15585
|
+
local json_entry
|
|
15586
|
+
json_entry=$(printf '{"source":"%s","test_path":"%s","language":"%s","framework":"%s","constructs":%d}' \
|
|
15587
|
+
"$src_file" "$test_path" "$lang" "$framework" "$construct_count")
|
|
15588
|
+
if [ -n "$json_entries" ]; then
|
|
15589
|
+
json_entries="${json_entries},${json_entry}"
|
|
15590
|
+
else
|
|
15591
|
+
json_entries="$json_entry"
|
|
15592
|
+
fi
|
|
15593
|
+
else
|
|
15594
|
+
echo -e " ${CYAN}$src_file${NC}"
|
|
15595
|
+
echo -e " -> ${GREEN}$test_path${NC}"
|
|
15596
|
+
echo -e " Language: $lang | Framework: $framework | Constructs: $construct_count"
|
|
15597
|
+
if [ "$test_verbose" = true ]; then
|
|
15598
|
+
echo "$constructs" | while IFS= read -r c; do
|
|
15599
|
+
echo -e " - $c"
|
|
15600
|
+
done
|
|
15601
|
+
fi
|
|
15602
|
+
fi
|
|
15603
|
+
((++generated))
|
|
15604
|
+
continue
|
|
15605
|
+
fi
|
|
15606
|
+
|
|
15607
|
+
# Generate test content
|
|
15608
|
+
local test_content=""
|
|
15609
|
+
test_content=$(_test_generate_content "$src_file" "$lang" "$framework" "$constructs" "$test_coverage")
|
|
15610
|
+
|
|
15611
|
+
# Write test file
|
|
15612
|
+
local test_dir_path
|
|
15613
|
+
test_dir_path=$(dirname "$test_path")
|
|
15614
|
+
mkdir -p "$test_dir_path"
|
|
15615
|
+
echo "$test_content" > "$test_path"
|
|
15616
|
+
|
|
15617
|
+
generated_paths+=("$test_path")
|
|
15618
|
+
((++generated))
|
|
15619
|
+
|
|
15620
|
+
if [ "$test_json" = false ]; then
|
|
15621
|
+
echo -e " ${GREEN}[generated]${NC} $test_path (${construct_count} constructs, $framework)"
|
|
15622
|
+
else
|
|
15623
|
+
local json_entry
|
|
15624
|
+
json_entry=$(printf '{"source":"%s","test_path":"%s","language":"%s","framework":"%s","constructs":%d,"status":"generated"}' \
|
|
15625
|
+
"$src_file" "$test_path" "$lang" "$framework" "$construct_count")
|
|
15626
|
+
if [ -n "$json_entries" ]; then
|
|
15627
|
+
json_entries="${json_entries},${json_entry}"
|
|
15628
|
+
else
|
|
15629
|
+
json_entries="$json_entry"
|
|
15630
|
+
fi
|
|
15631
|
+
fi
|
|
15632
|
+
done
|
|
15633
|
+
|
|
15634
|
+
# --- Output summary ---
|
|
15635
|
+
if [ "$test_json" = true ]; then
|
|
15636
|
+
local mode="generate"
|
|
15637
|
+
[ "$test_dry_run" = true ] && mode="dry_run"
|
|
15638
|
+
printf '{"status":"success","mode":"%s","files_scanned":%d,"tests_generated":%d,"skipped":%d,"coverage_target":%d,"results":[%s]}\n' \
|
|
15639
|
+
"$mode" "$total_files" "$generated" "$skipped" "$test_coverage" "$json_entries"
|
|
15640
|
+
else
|
|
15641
|
+
echo ""
|
|
15642
|
+
if [ "$test_dry_run" = true ]; then
|
|
15643
|
+
echo -e "${BOLD}Dry run summary:${NC} $generated test files would be generated, $skipped skipped"
|
|
15644
|
+
else
|
|
15645
|
+
echo -e "${BOLD}Summary:${NC} $generated test files generated, $skipped skipped"
|
|
15646
|
+
if [ ${#generated_paths[@]} -gt 0 ] && [ "$test_verbose" = true ]; then
|
|
15647
|
+
echo ""
|
|
15648
|
+
echo "Generated files:"
|
|
15649
|
+
for p in "${generated_paths[@]}"; do
|
|
15650
|
+
echo " $p"
|
|
15651
|
+
done
|
|
15652
|
+
fi
|
|
15653
|
+
fi
|
|
15654
|
+
fi
|
|
15655
|
+
|
|
15656
|
+
if [ "$generated" -eq 0 ]; then
|
|
15657
|
+
return 1
|
|
15658
|
+
fi
|
|
15659
|
+
return 0
|
|
15660
|
+
}
|
|
15661
|
+
|
|
15662
|
+
# --- Test generation helper functions ---
|
|
15663
|
+
|
|
15664
|
+
# Find source files in a directory (non-test, non-config files)
|
|
15665
|
+
_test_find_source_files() {
|
|
15666
|
+
local dir="$1"
|
|
15667
|
+
find "$dir" -type f \( \
|
|
15668
|
+
-name "*.js" -o -name "*.ts" -o -name "*.jsx" -o -name "*.tsx" \
|
|
15669
|
+
-o -name "*.py" -o -name "*.go" -o -name "*.rs" \
|
|
15670
|
+
-o -name "*.java" -o -name "*.rb" -o -name "*.sh" \
|
|
15671
|
+
\) ! -path "*/node_modules/*" ! -path "*/.git/*" ! -path "*/vendor/*" \
|
|
15672
|
+
! -path "*/__pycache__/*" ! -path "*/target/*" ! -path "*/dist/*" \
|
|
15673
|
+
! -path "*/build/*" ! -path "*/.loki/*" \
|
|
15674
|
+
2>/dev/null | sort
|
|
15675
|
+
}
|
|
15676
|
+
|
|
15677
|
+
# Check if a file is a testable source file (not a test, config, or generated file)
|
|
15678
|
+
_test_is_testable_file() {
|
|
15679
|
+
local f="$1"
|
|
15680
|
+
local base
|
|
15681
|
+
base=$(basename "$f")
|
|
15682
|
+
|
|
15683
|
+
# Must be a recognized source file extension
|
|
15684
|
+
case "$f" in
|
|
15685
|
+
*.js|*.ts|*.jsx|*.tsx|*.py|*.go|*.rs|*.java|*.rb|*.sh) ;;
|
|
15686
|
+
*) return 1 ;;
|
|
15687
|
+
esac
|
|
15688
|
+
|
|
15689
|
+
# Skip test files
|
|
15690
|
+
case "$base" in
|
|
15691
|
+
test_*|*_test.*|*.test.*|*.spec.*|*_spec.*|test.*) return 1 ;;
|
|
15692
|
+
esac
|
|
15693
|
+
case "$f" in
|
|
15694
|
+
*/__tests__/*|*/tests/*|*/test/*|*/spec/*|*_test/*) return 1 ;;
|
|
15695
|
+
esac
|
|
15696
|
+
|
|
15697
|
+
# Skip config and generated files
|
|
15698
|
+
case "$base" in
|
|
15699
|
+
setup.*|config.*|*.config.*|*.d.ts|__init__.py|conftest.py) return 1 ;;
|
|
15700
|
+
jest.config.*|vitest.config.*|webpack.config.*|rollup.config.*) return 1 ;;
|
|
15701
|
+
.eslintrc.*|.prettierrc.*|tsconfig.*|package.json) return 1 ;;
|
|
15702
|
+
Makefile|Dockerfile|*.lock|*.min.js|*.min.css) return 1 ;;
|
|
15703
|
+
esac
|
|
15704
|
+
|
|
15705
|
+
return 0
|
|
15706
|
+
}
|
|
15707
|
+
|
|
15708
|
+
# Detect language from file extension
|
|
15709
|
+
_test_detect_language() {
|
|
15710
|
+
local f="$1"
|
|
15711
|
+
case "$f" in
|
|
15712
|
+
*.ts|*.tsx) echo "typescript" ;;
|
|
15713
|
+
*.js|*.jsx) echo "javascript" ;;
|
|
15714
|
+
*.py) echo "python" ;;
|
|
15715
|
+
*.go) echo "go" ;;
|
|
15716
|
+
*.rs) echo "rust" ;;
|
|
15717
|
+
*.java) echo "java" ;;
|
|
15718
|
+
*.rb) echo "ruby" ;;
|
|
15719
|
+
*.sh) echo "bash" ;;
|
|
15720
|
+
*) echo "" ;;
|
|
15721
|
+
esac
|
|
15722
|
+
}
|
|
15723
|
+
|
|
15724
|
+
# Detect test framework based on language and project files
|
|
15725
|
+
_test_detect_framework() {
|
|
15726
|
+
local lang="$1"
|
|
15727
|
+
case "$lang" in
|
|
15728
|
+
typescript|javascript)
|
|
15729
|
+
if [ -f "vitest.config.ts" ] || [ -f "vitest.config.js" ]; then
|
|
15730
|
+
echo "vitest"
|
|
15731
|
+
elif [ -f ".mocharc.yml" ] || [ -f ".mocharc.json" ] || [ -f ".mocharc.js" ]; then
|
|
15732
|
+
echo "mocha"
|
|
15733
|
+
elif [ -f "jest.config.ts" ] || [ -f "jest.config.js" ] || [ -f "jest.config.json" ]; then
|
|
15734
|
+
echo "jest"
|
|
15735
|
+
elif [ -f "package.json" ] && grep -q '"vitest"' package.json 2>/dev/null; then
|
|
15736
|
+
echo "vitest"
|
|
15737
|
+
elif [ -f "package.json" ] && grep -q '"jest"' package.json 2>/dev/null; then
|
|
15738
|
+
echo "jest"
|
|
15739
|
+
else
|
|
15740
|
+
echo "jest"
|
|
15741
|
+
fi
|
|
15742
|
+
;;
|
|
15743
|
+
python) echo "pytest" ;;
|
|
15744
|
+
go) echo "go-test" ;;
|
|
15745
|
+
rust) echo "cargo-test" ;;
|
|
15746
|
+
java) echo "junit" ;;
|
|
15747
|
+
ruby) echo "rspec" ;;
|
|
15748
|
+
bash) echo "bats" ;;
|
|
15749
|
+
*) echo "unknown" ;;
|
|
15750
|
+
esac
|
|
15751
|
+
}
|
|
15752
|
+
|
|
15753
|
+
# Determine output path for generated test file
|
|
15754
|
+
_test_output_path() {
|
|
15755
|
+
local src="$1"
|
|
15756
|
+
local lang="$2"
|
|
15757
|
+
local framework="$3"
|
|
15758
|
+
local custom_output="$4"
|
|
15759
|
+
|
|
15760
|
+
local dir
|
|
15761
|
+
local base
|
|
15762
|
+
local name
|
|
15763
|
+
local ext
|
|
15764
|
+
dir=$(dirname "$src")
|
|
15765
|
+
base=$(basename "$src")
|
|
15766
|
+
name="${base%.*}"
|
|
15767
|
+
ext="${base##*.}"
|
|
15768
|
+
|
|
15769
|
+
# Use custom output dir if specified
|
|
15770
|
+
if [ -n "$custom_output" ]; then
|
|
15771
|
+
dir="$custom_output"
|
|
15772
|
+
fi
|
|
15773
|
+
|
|
15774
|
+
case "$framework" in
|
|
15775
|
+
jest|vitest)
|
|
15776
|
+
# __tests__/ directory convention
|
|
15777
|
+
if [ -n "$custom_output" ]; then
|
|
15778
|
+
echo "${dir}/${name}.test.${ext}"
|
|
15779
|
+
else
|
|
15780
|
+
echo "${dir}/__tests__/${name}.test.${ext}"
|
|
15781
|
+
fi
|
|
15782
|
+
;;
|
|
15783
|
+
mocha)
|
|
15784
|
+
if [ -n "$custom_output" ]; then
|
|
15785
|
+
echo "${dir}/${name}.spec.${ext}"
|
|
15786
|
+
else
|
|
15787
|
+
echo "${dir}/test/${name}.spec.${ext}"
|
|
15788
|
+
fi
|
|
15789
|
+
;;
|
|
15790
|
+
pytest)
|
|
15791
|
+
if [ -n "$custom_output" ]; then
|
|
15792
|
+
echo "${dir}/test_${name}.py"
|
|
15793
|
+
else
|
|
15794
|
+
echo "${dir}/tests/test_${name}.py"
|
|
15795
|
+
fi
|
|
15796
|
+
;;
|
|
15797
|
+
go-test)
|
|
15798
|
+
# Go tests live alongside source
|
|
15799
|
+
echo "${dir}/${name}_test.go"
|
|
15800
|
+
;;
|
|
15801
|
+
cargo-test)
|
|
15802
|
+
# Rust tests in same file or tests/ dir
|
|
15803
|
+
if [ -n "$custom_output" ]; then
|
|
15804
|
+
echo "${dir}/${name}_test.rs"
|
|
15805
|
+
else
|
|
15806
|
+
echo "${dir}/tests/${name}_test.rs"
|
|
15807
|
+
fi
|
|
15808
|
+
;;
|
|
15809
|
+
junit)
|
|
15810
|
+
if [ -n "$custom_output" ]; then
|
|
15811
|
+
echo "${dir}/${name}Test.java"
|
|
15812
|
+
else
|
|
15813
|
+
echo "${dir}/test/${name}Test.java"
|
|
15814
|
+
fi
|
|
15815
|
+
;;
|
|
15816
|
+
rspec)
|
|
15817
|
+
if [ -n "$custom_output" ]; then
|
|
15818
|
+
echo "${dir}/${name}_spec.rb"
|
|
15819
|
+
else
|
|
15820
|
+
echo "${dir}/spec/${name}_spec.rb"
|
|
15821
|
+
fi
|
|
15822
|
+
;;
|
|
15823
|
+
bats)
|
|
15824
|
+
if [ -n "$custom_output" ]; then
|
|
15825
|
+
echo "${dir}/${name}.bats"
|
|
15826
|
+
else
|
|
15827
|
+
echo "${dir}/tests/${name}.bats"
|
|
15828
|
+
fi
|
|
15829
|
+
;;
|
|
15830
|
+
*)
|
|
15831
|
+
echo "${dir}/tests/test_${name}.${ext}"
|
|
15832
|
+
;;
|
|
15833
|
+
esac
|
|
15834
|
+
}
|
|
15835
|
+
|
|
15836
|
+
# Extract testable constructs from a source file (functions, classes, exports)
|
|
15837
|
+
_test_extract_constructs() {
|
|
15838
|
+
local src="$1"
|
|
15839
|
+
local lang="$2"
|
|
15840
|
+
|
|
15841
|
+
case "$lang" in
|
|
15842
|
+
javascript|typescript)
|
|
15843
|
+
# Match exported functions, classes, consts, and standalone functions
|
|
15844
|
+
grep -E '^\s*(export\s+)?(default\s+)?(async\s+)?function\s+\w+|^\s*(export\s+)?(const|let|var)\s+\w+\s*=\s*(async\s+)?\(|^\s*(export\s+)?class\s+\w+|^module\.exports' "$src" 2>/dev/null \
|
|
15845
|
+
| sed 's/^\s*//' | head -50
|
|
15846
|
+
;;
|
|
15847
|
+
python)
|
|
15848
|
+
# Match function definitions, class definitions
|
|
15849
|
+
grep -E '^\s*(async\s+)?def\s+\w+|^\s*class\s+\w+' "$src" 2>/dev/null \
|
|
15850
|
+
| grep -v '^\s*def\s+_' \
|
|
15851
|
+
| sed 's/^\s*//' | head -50
|
|
15852
|
+
;;
|
|
15853
|
+
go)
|
|
15854
|
+
# Match function definitions (exported only - capitalized)
|
|
15855
|
+
grep -E '^func\s+(\([^)]+\)\s+)?[A-Z]\w*\(' "$src" 2>/dev/null \
|
|
15856
|
+
| head -50
|
|
15857
|
+
;;
|
|
15858
|
+
rust)
|
|
15859
|
+
# Match pub functions and impl blocks
|
|
15860
|
+
grep -E '^\s*pub\s+(async\s+)?fn\s+\w+|^\s*impl\s+' "$src" 2>/dev/null \
|
|
15861
|
+
| sed 's/^\s*//' | head -50
|
|
15862
|
+
;;
|
|
15863
|
+
java)
|
|
15864
|
+
# Match public methods and classes
|
|
15865
|
+
grep -E '^\s*public\s+(static\s+)?\w+\s+\w+\s*\(|^\s*public\s+class\s+\w+' "$src" 2>/dev/null \
|
|
15866
|
+
| sed 's/^\s*//' | head -50
|
|
15867
|
+
;;
|
|
15868
|
+
ruby)
|
|
15869
|
+
# Match def and class
|
|
15870
|
+
grep -E '^\s*def\s+\w+|^\s*class\s+\w+' "$src" 2>/dev/null \
|
|
15871
|
+
| sed 's/^\s*//' | head -50
|
|
15872
|
+
;;
|
|
15873
|
+
bash)
|
|
15874
|
+
# Match function definitions
|
|
15875
|
+
grep -E '^\s*\w+\s*\(\)\s*\{|^\s*function\s+\w+' "$src" 2>/dev/null \
|
|
15876
|
+
| sed 's/^\s*//' | head -50
|
|
15877
|
+
;;
|
|
15878
|
+
*) echo "" ;;
|
|
15879
|
+
esac
|
|
15880
|
+
}
|
|
15881
|
+
|
|
15882
|
+
# Generate test file content for a given source file
|
|
15883
|
+
_test_generate_content() {
|
|
15884
|
+
local src="$1"
|
|
15885
|
+
local lang="$2"
|
|
15886
|
+
local framework="$3"
|
|
15887
|
+
local constructs="$4"
|
|
15888
|
+
local coverage="$5"
|
|
15889
|
+
|
|
15890
|
+
local base
|
|
15891
|
+
local name
|
|
15892
|
+
base=$(basename "$src")
|
|
15893
|
+
name="${base%.*}"
|
|
15894
|
+
|
|
15895
|
+
case "$framework" in
|
|
15896
|
+
jest|vitest)
|
|
15897
|
+
_test_gen_jest_vitest "$src" "$name" "$base" "$framework" "$constructs" "$coverage"
|
|
15898
|
+
;;
|
|
15899
|
+
mocha)
|
|
15900
|
+
_test_gen_mocha "$src" "$name" "$base" "$constructs" "$coverage"
|
|
15901
|
+
;;
|
|
15902
|
+
pytest)
|
|
15903
|
+
_test_gen_pytest "$src" "$name" "$base" "$constructs" "$coverage"
|
|
15904
|
+
;;
|
|
15905
|
+
go-test)
|
|
15906
|
+
_test_gen_go "$src" "$name" "$base" "$constructs" "$coverage"
|
|
15907
|
+
;;
|
|
15908
|
+
cargo-test)
|
|
15909
|
+
_test_gen_rust "$src" "$name" "$base" "$constructs" "$coverage"
|
|
15910
|
+
;;
|
|
15911
|
+
junit)
|
|
15912
|
+
_test_gen_junit "$src" "$name" "$base" "$constructs" "$coverage"
|
|
15913
|
+
;;
|
|
15914
|
+
rspec)
|
|
15915
|
+
_test_gen_rspec "$src" "$name" "$base" "$constructs" "$coverage"
|
|
15916
|
+
;;
|
|
15917
|
+
bats)
|
|
15918
|
+
_test_gen_bats "$src" "$name" "$base" "$constructs" "$coverage"
|
|
15919
|
+
;;
|
|
15920
|
+
*)
|
|
15921
|
+
echo "// Unsupported framework: $framework"
|
|
15922
|
+
;;
|
|
15923
|
+
esac
|
|
15924
|
+
}
|
|
15925
|
+
|
|
15926
|
+
# --- Framework-specific generators ---
|
|
15927
|
+
|
|
15928
|
+
_test_gen_jest_vitest() {
|
|
15929
|
+
local src="$1" name="$2" base="$3" framework="$4" constructs="$5" coverage="$6"
|
|
15930
|
+
|
|
15931
|
+
local import_style="require"
|
|
15932
|
+
local ext="${base##*.}"
|
|
15933
|
+
if [[ "$ext" == "ts" || "$ext" == "tsx" ]]; then
|
|
15934
|
+
import_style="import"
|
|
15935
|
+
fi
|
|
15936
|
+
|
|
15937
|
+
# Header
|
|
15938
|
+
if [ "$framework" = "vitest" ]; then
|
|
15939
|
+
echo "import { describe, it, expect, beforeEach, afterEach } from 'vitest';"
|
|
15940
|
+
fi
|
|
15941
|
+
|
|
15942
|
+
# Import statement
|
|
15943
|
+
local rel_path
|
|
15944
|
+
rel_path=$(echo "$src" | sed 's|^\./||')
|
|
15945
|
+
local import_path="../${base%.*}"
|
|
15946
|
+
|
|
15947
|
+
if [ "$import_style" = "import" ]; then
|
|
15948
|
+
echo "import { /* TODO: import constructs */ } from '${import_path}';"
|
|
15949
|
+
else
|
|
15950
|
+
echo "const ${name} = require('${import_path}');"
|
|
15951
|
+
fi
|
|
15952
|
+
echo ""
|
|
15953
|
+
echo "// Generated test suite for ${base}"
|
|
15954
|
+
echo "// Target coverage: ${coverage}%"
|
|
15955
|
+
echo "// Source: ${src}"
|
|
15956
|
+
echo ""
|
|
15957
|
+
echo "describe('${name}', () => {"
|
|
15958
|
+
|
|
15959
|
+
# Generate test cases from constructs
|
|
15960
|
+
echo "$constructs" | while IFS= read -r construct; do
|
|
15961
|
+
[ -z "$construct" ] && continue
|
|
15962
|
+
# Skip module.exports lines
|
|
15963
|
+
echo "$construct" | grep -q '^module\.exports' && continue
|
|
15964
|
+
local func_name=""
|
|
15965
|
+
# Extract function/class name
|
|
15966
|
+
func_name=$(echo "$construct" | grep -oE '(function|const|let|var|class)\s+\w+' | awk '{print $2}')
|
|
15967
|
+
if [ -z "$func_name" ]; then
|
|
15968
|
+
func_name=$(echo "$construct" | grep -oE '\w+\s*=' | sed 's/\s*=$//')
|
|
15969
|
+
fi
|
|
15970
|
+
[ -z "$func_name" ] && continue
|
|
15971
|
+
|
|
15972
|
+
# Check if it's a class
|
|
15973
|
+
if echo "$construct" | grep -q 'class\s'; then
|
|
15974
|
+
echo ""
|
|
15975
|
+
echo " describe('${func_name}', () => {"
|
|
15976
|
+
echo " it('should be instantiable', () => {"
|
|
15977
|
+
echo " // TODO: const instance = new ${func_name}();"
|
|
15978
|
+
echo " // expect(instance).toBeDefined();"
|
|
15979
|
+
echo " });"
|
|
15980
|
+
echo ""
|
|
15981
|
+
echo " it('should have expected properties', () => {"
|
|
15982
|
+
echo " // TODO: verify instance properties"
|
|
15983
|
+
echo " });"
|
|
15984
|
+
echo " });"
|
|
15985
|
+
else
|
|
15986
|
+
echo ""
|
|
15987
|
+
echo " describe('${func_name}', () => {"
|
|
15988
|
+
echo " it('should return expected result for valid input', () => {"
|
|
15989
|
+
echo " // TODO: const result = ${func_name}(/* args */);"
|
|
15990
|
+
echo " // expect(result).toEqual(/* expected */);"
|
|
15991
|
+
echo " });"
|
|
15992
|
+
echo ""
|
|
15993
|
+
echo " it('should handle edge cases', () => {"
|
|
15994
|
+
echo " // TODO: test with null, undefined, empty, boundary values"
|
|
15995
|
+
echo " });"
|
|
15996
|
+
echo ""
|
|
15997
|
+
echo " it('should throw on invalid input', () => {"
|
|
15998
|
+
echo " // TODO: expect(() => ${func_name}(/* invalid */)).toThrow();"
|
|
15999
|
+
echo " });"
|
|
16000
|
+
echo " });"
|
|
16001
|
+
fi
|
|
16002
|
+
done
|
|
16003
|
+
|
|
16004
|
+
echo "});"
|
|
16005
|
+
}
|
|
16006
|
+
|
|
16007
|
+
_test_gen_mocha() {
|
|
16008
|
+
local src="$1" name="$2" base="$3" constructs="$4" coverage="$5"
|
|
16009
|
+
|
|
16010
|
+
echo "const { expect } = require('chai');"
|
|
16011
|
+
echo "const ${name} = require('../${name}');"
|
|
16012
|
+
echo ""
|
|
16013
|
+
echo "// Generated test suite for ${base}"
|
|
16014
|
+
echo "// Target coverage: ${coverage}%"
|
|
16015
|
+
echo ""
|
|
16016
|
+
echo "describe('${name}', function () {"
|
|
16017
|
+
|
|
16018
|
+
echo "$constructs" | while IFS= read -r construct; do
|
|
16019
|
+
[ -z "$construct" ] && continue
|
|
16020
|
+
echo "$construct" | grep -q '^module\.exports' && continue
|
|
16021
|
+
local func_name=""
|
|
16022
|
+
func_name=$(echo "$construct" | grep -oE '(function|const|let|var|class)\s+\w+' | awk '{print $2}')
|
|
16023
|
+
[ -z "$func_name" ] && continue
|
|
16024
|
+
|
|
16025
|
+
echo ""
|
|
16026
|
+
echo " describe('${func_name}', function () {"
|
|
16027
|
+
echo " it('should return expected result', function () {"
|
|
16028
|
+
echo " // TODO: const result = ${name}.${func_name}(/* args */);"
|
|
16029
|
+
echo " // expect(result).to.equal(/* expected */);"
|
|
16030
|
+
echo " });"
|
|
16031
|
+
echo ""
|
|
16032
|
+
echo " it('should handle edge cases', function () {"
|
|
16033
|
+
echo " // TODO: test edge cases"
|
|
16034
|
+
echo " });"
|
|
16035
|
+
echo " });"
|
|
16036
|
+
done
|
|
16037
|
+
|
|
16038
|
+
echo "});"
|
|
16039
|
+
}
|
|
16040
|
+
|
|
16041
|
+
_test_gen_pytest() {
|
|
16042
|
+
local src="$1" name="$2" base="$3" constructs="$4" coverage="$5"
|
|
16043
|
+
|
|
16044
|
+
local module_name
|
|
16045
|
+
module_name=$(echo "$name" | tr '-' '_')
|
|
16046
|
+
|
|
16047
|
+
echo "\"\"\"Tests for ${base}."
|
|
16048
|
+
echo ""
|
|
16049
|
+
echo "Target coverage: ${coverage}%"
|
|
16050
|
+
echo "Source: ${src}"
|
|
16051
|
+
echo "\"\"\""
|
|
16052
|
+
echo "import pytest"
|
|
16053
|
+
echo "# from ${module_name} import # TODO: import from source module"
|
|
16054
|
+
echo ""
|
|
16055
|
+
|
|
16056
|
+
echo "$constructs" | while IFS= read -r construct; do
|
|
16057
|
+
[ -z "$construct" ] && continue
|
|
16058
|
+
local func_name=""
|
|
16059
|
+
|
|
16060
|
+
if echo "$construct" | grep -q '^\s*class\s'; then
|
|
16061
|
+
func_name=$(echo "$construct" | grep -oE 'class\s+\w+' | awk '{print $2}')
|
|
16062
|
+
[ -z "$func_name" ] && continue
|
|
16063
|
+
echo ""
|
|
16064
|
+
echo "class Test${func_name}:"
|
|
16065
|
+
echo " \"\"\"Tests for ${func_name} class.\"\"\""
|
|
16066
|
+
echo ""
|
|
16067
|
+
echo " def test_init(self):"
|
|
16068
|
+
echo " \"\"\"Test ${func_name} instantiation.\"\"\""
|
|
16069
|
+
echo " # TODO: instance = ${func_name}()"
|
|
16070
|
+
echo " # assert instance is not None"
|
|
16071
|
+
echo " pass"
|
|
16072
|
+
echo ""
|
|
16073
|
+
echo " def test_expected_behavior(self):"
|
|
16074
|
+
echo " \"\"\"Test ${func_name} expected behavior.\"\"\""
|
|
16075
|
+
echo " # TODO: implement"
|
|
16076
|
+
echo " pass"
|
|
16077
|
+
else
|
|
16078
|
+
func_name=$(echo "$construct" | grep -oE 'def\s+\w+' | awk '{print $2}')
|
|
16079
|
+
[ -z "$func_name" ] && continue
|
|
16080
|
+
echo ""
|
|
16081
|
+
echo "def test_${func_name}_valid_input():"
|
|
16082
|
+
echo " \"\"\"Test ${func_name} with valid input.\"\"\""
|
|
16083
|
+
echo " # TODO: result = ${func_name}(/* args */)"
|
|
16084
|
+
echo " # assert result == expected"
|
|
16085
|
+
echo " pass"
|
|
16086
|
+
echo ""
|
|
16087
|
+
echo ""
|
|
16088
|
+
echo "def test_${func_name}_edge_cases():"
|
|
16089
|
+
echo " \"\"\"Test ${func_name} edge cases.\"\"\""
|
|
16090
|
+
echo " # TODO: test with None, empty, boundary values"
|
|
16091
|
+
echo " pass"
|
|
16092
|
+
echo ""
|
|
16093
|
+
echo ""
|
|
16094
|
+
echo "def test_${func_name}_invalid_input():"
|
|
16095
|
+
echo " \"\"\"Test ${func_name} with invalid input.\"\"\""
|
|
16096
|
+
echo " # TODO: with pytest.raises(ValueError):"
|
|
16097
|
+
echo " # ${func_name}(/* invalid */)"
|
|
16098
|
+
echo " pass"
|
|
16099
|
+
fi
|
|
16100
|
+
done
|
|
16101
|
+
}
|
|
16102
|
+
|
|
16103
|
+
_test_gen_go() {
|
|
16104
|
+
local src="$1" name="$2" base="$3" constructs="$4" coverage="$5"
|
|
16105
|
+
|
|
16106
|
+
local pkg
|
|
16107
|
+
pkg=$(grep -m1 '^package\s' "$src" 2>/dev/null | awk '{print $2}')
|
|
16108
|
+
[ -z "$pkg" ] && pkg="main"
|
|
16109
|
+
|
|
16110
|
+
echo "package ${pkg}"
|
|
16111
|
+
echo ""
|
|
16112
|
+
echo "import ("
|
|
16113
|
+
echo " \"testing\""
|
|
16114
|
+
echo ")"
|
|
16115
|
+
echo ""
|
|
16116
|
+
echo "// Generated tests for ${base}"
|
|
16117
|
+
echo "// Target coverage: ${coverage}%"
|
|
16118
|
+
|
|
16119
|
+
echo "$constructs" | while IFS= read -r construct; do
|
|
16120
|
+
[ -z "$construct" ] && continue
|
|
16121
|
+
local func_name=""
|
|
16122
|
+
func_name=$(echo "$construct" | grep -oE 'func\s+(\([^)]+\)\s+)?\w+' | grep -oE '\w+$')
|
|
16123
|
+
[ -z "$func_name" ] && continue
|
|
16124
|
+
|
|
16125
|
+
echo ""
|
|
16126
|
+
echo "func Test${func_name}(t *testing.T) {"
|
|
16127
|
+
echo " t.Run(\"valid input\", func(t *testing.T) {"
|
|
16128
|
+
echo " // TODO: result := ${func_name}(/* args */)"
|
|
16129
|
+
echo " // if result != expected {"
|
|
16130
|
+
echo " // t.Errorf(\"${func_name}() = %v, want %v\", result, expected)"
|
|
16131
|
+
echo " // }"
|
|
16132
|
+
echo " })"
|
|
16133
|
+
echo ""
|
|
16134
|
+
echo " t.Run(\"edge cases\", func(t *testing.T) {"
|
|
16135
|
+
echo " // TODO: test boundary values"
|
|
16136
|
+
echo " })"
|
|
16137
|
+
echo "}"
|
|
16138
|
+
done
|
|
16139
|
+
}
|
|
16140
|
+
|
|
16141
|
+
_test_gen_rust() {
|
|
16142
|
+
local src="$1" name="$2" base="$3" constructs="$4" coverage="$5"
|
|
16143
|
+
|
|
16144
|
+
echo "// Generated tests for ${base}"
|
|
16145
|
+
echo "// Target coverage: ${coverage}%"
|
|
16146
|
+
echo ""
|
|
16147
|
+
echo "#[cfg(test)]"
|
|
16148
|
+
echo "mod tests {"
|
|
16149
|
+
echo " use super::*;"
|
|
16150
|
+
echo ""
|
|
16151
|
+
|
|
16152
|
+
echo "$constructs" | while IFS= read -r construct; do
|
|
16153
|
+
[ -z "$construct" ] && continue
|
|
16154
|
+
local func_name=""
|
|
16155
|
+
func_name=$(echo "$construct" | grep -oE 'fn\s+\w+' | awk '{print $2}')
|
|
16156
|
+
[ -z "$func_name" ] && continue
|
|
16157
|
+
|
|
16158
|
+
echo " #[test]"
|
|
16159
|
+
echo " fn test_${func_name}_valid_input() {"
|
|
16160
|
+
echo " // TODO: let result = ${func_name}(/* args */);"
|
|
16161
|
+
echo " // assert_eq!(result, expected);"
|
|
16162
|
+
echo " }"
|
|
16163
|
+
echo ""
|
|
16164
|
+
echo " #[test]"
|
|
16165
|
+
echo " fn test_${func_name}_edge_cases() {"
|
|
16166
|
+
echo " // TODO: test boundary values"
|
|
16167
|
+
echo " }"
|
|
16168
|
+
echo ""
|
|
16169
|
+
done
|
|
16170
|
+
|
|
16171
|
+
echo "}"
|
|
16172
|
+
}
|
|
16173
|
+
|
|
16174
|
+
_test_gen_junit() {
|
|
16175
|
+
local src="$1" name="$2" base="$3" constructs="$4" coverage="$5"
|
|
16176
|
+
|
|
16177
|
+
echo "import org.junit.jupiter.api.Test;"
|
|
16178
|
+
echo "import org.junit.jupiter.api.BeforeEach;"
|
|
16179
|
+
echo "import static org.junit.jupiter.api.Assertions.*;"
|
|
16180
|
+
echo ""
|
|
16181
|
+
echo "/**"
|
|
16182
|
+
echo " * Generated tests for ${base}"
|
|
16183
|
+
echo " * Target coverage: ${coverage}%"
|
|
16184
|
+
echo " */"
|
|
16185
|
+
echo "class ${name}Test {"
|
|
16186
|
+
echo ""
|
|
16187
|
+
|
|
16188
|
+
echo "$constructs" | while IFS= read -r construct; do
|
|
16189
|
+
[ -z "$construct" ] && continue
|
|
16190
|
+
local func_name=""
|
|
16191
|
+
func_name=$(echo "$construct" | grep -oE '(class|void|int|String|boolean|double|float|long)\s+\w+' | awk '{print $NF}')
|
|
16192
|
+
[ -z "$func_name" ] && continue
|
|
16193
|
+
|
|
16194
|
+
# Skip class definitions
|
|
16195
|
+
if echo "$construct" | grep -q 'class\s'; then
|
|
16196
|
+
continue
|
|
16197
|
+
fi
|
|
16198
|
+
|
|
16199
|
+
echo " @Test"
|
|
16200
|
+
echo " void test${func_name^}ValidInput() {"
|
|
16201
|
+
echo " // TODO: var result = instance.${func_name}(/* args */);"
|
|
16202
|
+
echo " // assertEquals(expected, result);"
|
|
16203
|
+
echo " }"
|
|
16204
|
+
echo ""
|
|
16205
|
+
echo " @Test"
|
|
16206
|
+
echo " void test${func_name^}EdgeCases() {"
|
|
16207
|
+
echo " // TODO: test boundary values"
|
|
16208
|
+
echo " }"
|
|
16209
|
+
echo ""
|
|
16210
|
+
done
|
|
16211
|
+
|
|
16212
|
+
echo "}"
|
|
16213
|
+
}
|
|
16214
|
+
|
|
16215
|
+
_test_gen_rspec() {
|
|
16216
|
+
local src="$1" name="$2" base="$3" constructs="$4" coverage="$5"
|
|
16217
|
+
|
|
16218
|
+
echo "# Generated tests for ${base}"
|
|
16219
|
+
echo "# Target coverage: ${coverage}%"
|
|
16220
|
+
echo ""
|
|
16221
|
+
echo "require_relative '../${name}'"
|
|
16222
|
+
echo ""
|
|
16223
|
+
echo "RSpec.describe ${name^} do"
|
|
16224
|
+
|
|
16225
|
+
echo "$constructs" | while IFS= read -r construct; do
|
|
16226
|
+
[ -z "$construct" ] && continue
|
|
16227
|
+
local func_name=""
|
|
16228
|
+
|
|
16229
|
+
if echo "$construct" | grep -q 'class\s'; then
|
|
16230
|
+
func_name=$(echo "$construct" | grep -oE 'class\s+\w+' | awk '{print $2}')
|
|
16231
|
+
[ -z "$func_name" ] && continue
|
|
16232
|
+
echo ""
|
|
16233
|
+
echo " describe ${func_name} do"
|
|
16234
|
+
echo " it 'is instantiable' do"
|
|
16235
|
+
echo " # TODO: instance = ${func_name}.new"
|
|
16236
|
+
echo " # expect(instance).not_to be_nil"
|
|
16237
|
+
echo " end"
|
|
16238
|
+
echo " end"
|
|
16239
|
+
else
|
|
16240
|
+
func_name=$(echo "$construct" | grep -oE 'def\s+\w+' | awk '{print $2}')
|
|
16241
|
+
[ -z "$func_name" ] && continue
|
|
16242
|
+
echo ""
|
|
16243
|
+
echo " describe '#${func_name}' do"
|
|
16244
|
+
echo " it 'returns expected result' do"
|
|
16245
|
+
echo " # TODO: result = subject.${func_name}"
|
|
16246
|
+
echo " # expect(result).to eq(expected)"
|
|
16247
|
+
echo " end"
|
|
16248
|
+
echo ""
|
|
16249
|
+
echo " it 'handles edge cases' do"
|
|
16250
|
+
echo " # TODO: test edge cases"
|
|
16251
|
+
echo " end"
|
|
16252
|
+
echo " end"
|
|
16253
|
+
fi
|
|
16254
|
+
done
|
|
16255
|
+
|
|
16256
|
+
echo "end"
|
|
16257
|
+
}
|
|
16258
|
+
|
|
16259
|
+
_test_gen_bats() {
|
|
16260
|
+
local src="$1" name="$2" base="$3" constructs="$4" coverage="$5"
|
|
16261
|
+
|
|
16262
|
+
echo "#!/usr/bin/env bats"
|
|
16263
|
+
echo "# Generated tests for ${base}"
|
|
16264
|
+
echo "# Target coverage: ${coverage}%"
|
|
16265
|
+
echo ""
|
|
16266
|
+
echo "setup() {"
|
|
16267
|
+
echo " source \"\$(dirname \"\$BATS_TEST_FILENAME\")/../${base}\""
|
|
16268
|
+
echo "}"
|
|
16269
|
+
echo ""
|
|
16270
|
+
|
|
16271
|
+
echo "$constructs" | while IFS= read -r construct; do
|
|
16272
|
+
[ -z "$construct" ] && continue
|
|
16273
|
+
local func_name=""
|
|
16274
|
+
func_name=$(echo "$construct" | grep -oE '\w+' | head -1)
|
|
16275
|
+
[ -z "$func_name" ] && continue
|
|
16276
|
+
|
|
16277
|
+
echo "@test \"${func_name} returns expected result\" {"
|
|
16278
|
+
echo " # TODO: run ${func_name} args"
|
|
16279
|
+
echo " # [ \"\$status\" -eq 0 ]"
|
|
16280
|
+
echo " # [ \"\$output\" = \"expected\" ]"
|
|
16281
|
+
echo " skip \"TODO: implement\""
|
|
16282
|
+
echo "}"
|
|
16283
|
+
echo ""
|
|
16284
|
+
echo "@test \"${func_name} handles edge cases\" {"
|
|
16285
|
+
echo " # TODO: test edge cases"
|
|
16286
|
+
echo " skip \"TODO: implement\""
|
|
16287
|
+
echo "}"
|
|
16288
|
+
echo ""
|
|
16289
|
+
done
|
|
16290
|
+
}
|
|
16291
|
+
|
|
15329
16292
|
main "$@"
|
package/dashboard/__init__.py
CHANGED
package/docs/INSTALLATION.md
CHANGED
package/mcp/__init__.py
CHANGED