aboutsummaryrefslogtreecommitdiff
path: root/internal/cli/dryrun_test.go
diff options
context:
space:
mode:
authortsne <tsne.dev@outlook.com>2026-07-06 16:52:20 +0200
committertsne <tsne.dev@outlook.com>2026-07-06 19:21:15 +0200
commit2c41acab4c97f584e8e199b31dc456194b8d7e6c (patch)
tree42381deb6c4f6da0f32945432207a31b4d86664e /internal/cli/dryrun_test.go
downloadhopper-2c41acab4c97f584e8e199b31dc456194b8d7e6c.tar.gz
initial
Diffstat (limited to 'internal/cli/dryrun_test.go')
-rw-r--r--internal/cli/dryrun_test.go78
1 files changed, 78 insertions, 0 deletions
diff --git a/internal/cli/dryrun_test.go b/internal/cli/dryrun_test.go
new file mode 100644
index 0000000..c2538d6
--- /dev/null
+++ b/internal/cli/dryrun_test.go
@@ -0,0 +1,78 @@
+package cli
+
+import (
+ "context"
+ "strings"
+ "testing"
+
+ "tsne.dev/hopper/internal/bunny"
+)
+
+// TestDryRunPushStubsUploads asserts that under dry-run the push flow performs
+// NO uploads against the wrapped API, yet prints the normal per-file action
+// line and summary (logging is owned by the command, not the decorator). The
+// recording fake is the wrapped (real-stand-in) API, so a zero put-count
+// provably shows the write side was never invoked.
+func TestDryRunPushStubsUploads(t *testing.T) {
+ arc := makeArchive(t, []tarEntry{
+ {name: "index.html", body: "<html>"},
+ {name: "assets/app.abc.js", body: "console.log(1)"},
+ })
+
+ spy := newFakeAPI()
+ out, _ := captureLogs(t)
+ dryRun = true
+
+ if err := runPush(arc, dryRunStorageAPI{spy}); err != nil {
+ t.Fatalf("push: %v", err)
+ }
+
+ if got := spy.paths(); len(got) != 0 {
+ t.Fatalf("expected no real uploads, got %v", got)
+ }
+
+ s := out.String()
+ for _, want := range []string{
+ "[dryrun] uploading index.html",
+ "[dryrun] uploading assets/app.abc.js",
+ "uploaded: 2",
+ } {
+ if !strings.Contains(s, want) {
+ t.Fatalf("output missing %q; got:\n%s", want, s)
+ }
+ }
+}
+
+// TestDryRunDeleteStubbed asserts Delete never reaches the wrapped API
+// (reused by prune in issue 008, which will own the delete log line).
+func TestDryRunDeleteStubbed(t *testing.T) {
+ spy := newFakeAPI()
+ api := dryRunStorageAPI{spy}
+
+ if err := api.Delete(context.Background(), "old/file.js"); err != nil {
+ t.Fatalf("Delete: %v", err)
+ }
+ if len(spy.deletes) != 0 {
+ t.Fatalf("expected no real deletes, got %v", spy.deletes)
+ }
+}
+
+// TestDryRunListDelegates asserts the read side still reaches the wrapped API
+// (real Bunny in production), unaffected by the write stubbing.
+func TestDryRunListDelegates(t *testing.T) {
+ spy := newFakeAPI()
+ spy.lists[""] = []bunny.Object{{Path: "a.js", Size: 3}}
+ api := dryRunStorageAPI{spy}
+
+ it := api.List(context.Background(), "")
+ var got []bunny.Object
+ for it.Next() {
+ got = append(got, it.Object())
+ }
+ if err := it.Err(); err != nil {
+ t.Fatalf("List: %v", err)
+ }
+ if len(got) != 1 || got[0].Path != "a.js" {
+ t.Fatalf("List delegate = %v", got)
+ }
+}