Files
boshu2__agentops/cli/internal/commands/init/module_test.go
Bo 3a54d5ff53 refactor(cli): unify host-seam contract, shared writeJSON/ExitError, drift guards (age-6j9ee.1)
Collapse the four drifted cmd/ao host-seam shapes into one shared
clicontract.HostOptions consumed by all 17 command modules; delete the
positional-func and bespoke-struct seams and the doctor GlobalOptions bundle.

- clicontract/host.go: single HostOptions union (OutputMode/Verbose/Verbosef/
  DryRun/ProjectRoot/GoalsPath/LedgerPath/Version/Now/EnrichFlagErr), one shared
  WriteJSON (byte-identical to the three deleted copies), one shared ExitError
  (Label field preserves doctor's stderr surfacing; gate stays silent).
- config_module.go + doctor_module.go: package-level module/service singletons
  -> newConfigCommand()/newDoctorCommand() constructors; 7 allowlist rows removed.
- carveout_regression_test.go: three AST drift guards (shared seam type / no
  direct host effects / no module-service singleton vars), each RED-proven.
- docs/architecture/go-cli.md: document the intentional two-tier shape (5 full
  hexagonal, 12 app-seam); drop the stale opportunistic-extraction sentence.

Zero behavior change: ao -o json capabilities byte-identical; full suite +
-shuffle=on -count=2 green; 0 lint issues; gate check --full 67/67.
2026-07-20 10:14:04 -04:00

81 lines
2.1 KiB
Go

package init
import (
"bytes"
"os"
"path/filepath"
"strings"
"testing"
"github.com/boshu2/agentops/cli/internal/clicontract"
)
func newTestModule(dryRun bool) Module {
return NewModule(clicontract.HostOptions{DryRun: func() bool { return dryRun }})
}
func TestModule_Contract(t *testing.T) {
contract := newTestModule(false).Contract()
if contract.ID != "ao.init" {
t.Fatalf("contract ID = %q, want ao.init", contract.ID)
}
if contract.Output != clicontract.OutputText {
t.Fatalf("output = %v, want OutputText", contract.Output)
}
if contract.Effects&clicontract.EffectFilesystem == 0 {
t.Fatalf("effects = %v, want filesystem", contract.Effects)
}
}
func TestModule_CommandAttributes(t *testing.T) {
command := newTestModule(false).Command()
if command.Use != "init" {
t.Fatalf("Use = %q, want init", command.Use)
}
if command.GroupID != "start" {
t.Fatalf("GroupID = %q, want start", command.GroupID)
}
}
func TestInitCreatesEvidenceStorageWithoutGitMutation(t *testing.T) {
dir := t.TempDir()
t.Chdir(dir)
var output bytes.Buffer
command := newTestModule(false).Command()
command.SetOut(&output)
command.SetArgs(nil)
if err := command.Execute(); err != nil {
t.Fatal(err)
}
for _, relative := range []string{
filepath.Join(".agents", "ao", "verdicts", "sha256"),
filepath.Join(".agents", "ao", "provenance"),
filepath.Join(".agents", "handoff"),
} {
if info, err := os.Stat(filepath.Join(dir, relative)); err != nil || !info.IsDir() {
t.Fatalf("missing %s: %v", relative, err)
}
}
if _, err := os.Stat(filepath.Join(dir, ".gitignore")); !os.IsNotExist(err) {
t.Fatal("init must not edit Git ignore state")
}
}
func TestInitDryRunCreatesNothing(t *testing.T) {
dir := t.TempDir()
t.Chdir(dir)
var output bytes.Buffer
command := newTestModule(true).Command()
command.SetOut(&output)
command.SetArgs(nil)
if err := command.Execute(); err != nil {
t.Fatal(err)
}
if !strings.Contains(output.String(), "would create") {
t.Fatalf("dry-run output missing 'would create': %s", output.String())
}
if _, err := os.Stat(filepath.Join(dir, ".agents")); !os.IsNotExist(err) {
t.Fatal("dry-run must not create directories")
}
}