Files
ctool/cmd/ctool/cmd_fetch_test.go
Pim van Pelt e18a89dcf0 Add Debian packaging, Makefile, manpages, tests, and design doc
Introduces a static-binary build and Debian package (amd64/arm64) with
version/commit/date stamped via -ldflags. Ships section-1 manpages for
ctool, ctfetch, and ctail. Adds a `version` subcommand reachable as
`ctool version`, `ctool -version`, `ctool --version`, `ctool fetch
version`, `ctool tail version`, and via the ctfetch/ctail symlinks. Adds
tests covering the dispatcher, fetch/tail argument parsing, and the
formatter/helper functions. Adds a retrofit design document modelled on
the vpp-maglev one, with FRs and NFRs for each tool and the dispatcher.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 22:21:32 +02:00

74 lines
2.4 KiB
Go

package main
import (
"strings"
"testing"
)
func TestFetchNoArgsShowsUsage(t *testing.T) {
_, stderr, exit := runCLI(t, "ctool", "fetch")
if exit == 0 {
t.Errorf("expected non-zero exit, got 0 (stderr=%q)", stderr)
}
if !strings.Contains(stderr, "Usage:") {
t.Errorf("stderr missing usage header: %q", stderr)
}
if !strings.Contains(stderr, "ctool fetch") {
t.Errorf("stderr missing qualified command name: %q", stderr)
}
}
// When invoked via the ctfetch symlink, the usage banner must use the
// symlink name ("ctfetch"), not "ctool fetch". This exercises cmdName's
// symlink branch through the real CLI.
func TestFetchUsageUsesSymlinkName(t *testing.T) {
_, stderr, exit := runCLI(t, "ctfetch")
if exit == 0 {
t.Errorf("expected non-zero exit, got 0")
}
if !strings.Contains(stderr, "ctfetch") {
t.Errorf("stderr should mention ctfetch: %q", stderr)
}
if strings.Contains(stderr, "ctool fetch") {
t.Errorf("stderr should NOT say 'ctool fetch' when invoked via symlink: %q", stderr)
}
}
func TestFetchHelpExitsZero(t *testing.T) {
_, _, exit := runCLI(t, "ctool", "fetch", "-h")
if exit != 0 {
t.Errorf("expected exit 0 for -h, got %d", exit)
}
}
// An unknown +modifier must be rejected before any network request is made.
// The fetch dispatcher validates the modifier enum (sct/issuer/ctlog/all)
// up-front; we pass a junk URL to prove the error happens during parse,
// not during HTTP.
func TestFetchRejectsUnknownModifier(t *testing.T) {
_, stderr, exit := runCLI(t, "ctool", "fetch", "http://invalid.invalid", "1", "+bogus")
if exit == 0 {
t.Errorf("expected non-zero exit")
}
if !strings.Contains(stderr, "unknown argument") {
t.Errorf("stderr should mention 'unknown argument', got %q", stderr)
}
if !strings.Contains(stderr, "+bogus") {
t.Errorf("stderr should echo the bad modifier: %q", stderr)
}
}
// Leaf-index mode is distinguished from tile-dump mode by whether the
// second positional parses as an integer. The +modifier-rejection path
// runs through different code for each mode; verify both reach the
// same validation.
func TestFetchRejectsUnknownModifierTileMode(t *testing.T) {
_, stderr, exit := runCLI(t, "ctool", "fetch", "http://invalid.invalid/tile/data/x000/000", "+bogus")
if exit == 0 {
t.Errorf("expected non-zero exit")
}
if !strings.Contains(stderr, "unknown argument") {
t.Errorf("stderr should mention 'unknown argument', got %q", stderr)
}
}