// Copyright (c) 2026 Storm Dragon // SPDX-License-Identifier: GPL-3.0-or-later package audio import ( "context" "errors" "io" "net" "os/exec" "syscall" "testing" "time" ) func TestRetryRecoversAndPreservesPermanentErrors(t *testing.T) { attempts := 0 err := Retry(context.Background(), func(context.Context) error { attempts++ if attempts < 2 { return &net.OpError{Op: "dial", Net: "unix", Err: syscall.ENOENT} } return nil }, Temporary) if err != nil || attempts != 2 { t.Fatal(err, attempts) } for _, problem := range []error{syscall.EACCES, errors.New("invalid configuration"), &exec.Error{Name: "missing-speech-daemon", Err: exec.ErrNotFound}} { attempts = 0 err := Retry(context.Background(), func(context.Context) error { attempts++; return problem }, Temporary) if !errors.Is(err, problem) || attempts != 1 { t.Fatal(err, attempts) } } } func TestRetryCancellationStopsBackoffAndDeadlinePreservesCause(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) attempts := 0 err := Retry(ctx, func(context.Context) error { attempts++; cancel(); return io.EOF }, Temporary) if !errors.Is(err, context.Canceled) || attempts != 1 { t.Fatal(err, attempts) } ctx, cancel = context.WithTimeout(context.Background(), 20*time.Millisecond) defer cancel() err = Retry(ctx, func(context.Context) error { return io.EOF }, Temporary) if !errors.Is(err, context.DeadlineExceeded) || !errors.Is(err, io.EOF) { t.Fatal(err) } }