package storage import ( "context" "errors" "testing" ) func TestWalkEmitterHonorsLimit(t *testing.T) { emitter := NewWalkEmitter(context.Background(), "test", WalkOptions{Limit: 2}, func(Entry) error { return nil }) if err := emitter.Emit(Entry{Path: "one"}); err != nil { t.Fatalf("first Emit() error = %v", err) } if err := emitter.Emit(Entry{Path: "two"}); err != nil { t.Fatalf("second Emit() error = %v", err) } if err := emitter.Emit(Entry{Path: "three"}); !errors.Is(err, ErrStopWalk) { t.Fatalf("third Emit() error = %v, want ErrStopWalk", err) } if !emitter.LimitReached() { t.Fatal("LimitReached() = false, want true") } } func TestWalkEmitterStopsWithoutError(t *testing.T) { emitter := NewWalkEmitter(context.Background(), "test", WalkOptions{}, func(Entry) error { return ErrStopWalk }) err := emitter.Emit(Entry{Path: "one"}) if !errors.Is(err, ErrStopWalk) { t.Fatalf("Emit() error = %v, want ErrStopWalk", err) } if err := FinishWalk(err); err != nil { t.Fatalf("FinishWalk() error = %v, want nil", err) } } func TestWalkEmitterWrapsCallbackErrors(t *testing.T) { callbackErr := errors.New("callback failed") emitter := NewWalkEmitter(context.Background(), "test", WalkOptions{}, func(Entry) error { return callbackErr }) err := emitter.Emit(Entry{Path: "one"}) if !errors.Is(err, callbackErr) { t.Fatalf("Emit() error = %v, want callback error", err) } var storageErr *Error if !errors.As(err, &storageErr) { t.Fatalf("Emit() error type = %T, want *Error", err) } if storageErr.Op != OpWalk || storageErr.Backend != "test" || storageErr.Path != "one" || storageErr.Kind != ErrUnknown { t.Fatalf("wrapped error = %#v", storageErr) } } func TestWalkEmitterHonorsContextCancellation(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) cancel() called := false emitter := NewWalkEmitter(ctx, "test", WalkOptions{}, func(Entry) error { called = true return nil }) err := emitter.Emit(Entry{Path: "one"}) if !errors.Is(err, context.Canceled) { t.Fatalf("Emit() error = %v, want context.Canceled", err) } if called { t.Fatal("callback was called after context cancellation") } } func TestHasAnyUsesNonRecursiveLimitOneWalk(t *testing.T) { backend := &recordingBackend{} found, err := HasAny(context.Background(), backend, "bundle") if err != nil { t.Fatalf("HasAny() error = %v", err) } if !found { t.Fatal("HasAny() = false, want true") } if backend.prefix != "bundle" { t.Fatalf("walk prefix = %q, want bundle", backend.prefix) } if backend.opts != (WalkOptions{Recursive: false, Limit: 1}) { t.Fatalf("walk options = %#v, want non-recursive limit one", backend.opts) } } type recordingBackend struct { Backend prefix string opts WalkOptions } func (b *recordingBackend) Walk(_ context.Context, prefix string, opts WalkOptions, fn WalkFunc) error { b.prefix = prefix b.opts = opts return FinishWalk(fn(Entry{Path: "bundle/file.txt", Type: EntryTypeFile})) }