From 3fa335cc3a9f7beb7c4adbd6d78d98c22679b810 Mon Sep 17 00:00:00 2001 From: "Scott G. Miller" Date: Tue, 21 Jan 2025 14:04:35 -0600 Subject: [PATCH] Improve ParsePaths behavior in errors, and add a usage comment --- options.go | 21 +++++++++++++++++---- options_test.go | 18 +++++++++++++++++- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/options.go b/options.go index f581e2d0..f63199a2 100644 --- a/options.go +++ b/options.go @@ -156,12 +156,25 @@ func WithoutHMAC() Option { } } +// ParsePaths is a helper function to take each string pointer argument and call parseutil.ParsePath, +// replacing the contents of the target string with the result if no error occurs. The function exits +// early if it encounters an error. In that case no passed fields will have been modified. +// +// If any passed pointer is nil it will be ignored. func ParsePaths(fields ...*string) error { + newVals := make([]string, len(fields)) for i := 0; i < len(fields); i++ { - if newVal, err := parseutil.ParsePath(*fields[i], parseutil.WithNoTrimSpaces(true), parseutil.WithErrorOnMissingEnv(true)); err != nil && !errors.Is(err, parseutil.ErrNotAUrl) { - return err - } else { - *fields[i] = newVal + if fields[i] != nil { + if newVal, err := parseutil.ParsePath(*fields[i], parseutil.WithNoTrimSpaces(true), parseutil.WithErrorOnMissingEnv(true)); err != nil && !errors.Is(err, parseutil.ErrNotAUrl) { + return err + } else { + newVals[i] = newVal + } + } + } + for i := 0; i < len(fields); i++ { + if fields[i] != nil { + *fields[i] = newVals[i] } } return nil diff --git a/options_test.go b/options_test.go index aff31e9e..ffb449e3 100644 --- a/options_test.go +++ b/options_test.go @@ -130,10 +130,26 @@ func TestParsePaths(t *testing.T) { t.Fatalf("expected TopSecret, got %s", test.optionB) } + // Test nil handling test = options{ - optionA: "file://test-fixtures/missing.txt", + optionA: "file://test-fixtures/secret.txt", + } + if err := ParsePaths(nil, &test.optionA, nil); err != nil { + t.Fatal(err) + } + if test.optionA != "Top Secret" { + t.Fatalf("expected TopSecret, got %s", test.optionB) + } + + // Test errors and error atomicity + test = options{ + optionA: "file://test-fixtures/secret.txt", + optionB: "file://test-fixtures/missing.txt", } if err := ParsePaths(&test.optionA, &test.optionB); err == nil { t.Fatal("expected error but didn't get one") } + if test.optionA != "file://test-fixtures/secret.txt" { + t.Fatalf("optionA was overwritten despite encountering an error") + } }