check / check (push) Waiting to run
Error messages in mfer/ and internal/cli/ are lowercase except names and acronyms, carry no "failed to" or command-name prefix, and each wrap names only the operation and thing the wrapped error does not already name, so a stacked message names what failed once. Wraps around errors that already name their operation and path (os and afero path errors, url.Error, the gpg helpers' own errors) are dropped. runGPG appends gpg's stderr only when gpg wrote some, so no message ends in a colon. errHTTPStatus reads "unexpected HTTP status"; both inner-not-set sentinels read "inner message not set". No sentinel, errors.Is result or exit status changes. Message tests pin the new text through the real call sites. Model: opus-5-5
92 lines
2.1 KiB
Go
92 lines
2.1 KiB
Go
//nolint:testpackage // white-box tests exercise unexported internals
|
|
package mfer
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// TestValidatePathMessagesVerbatim pins the exact rendered text of every
|
|
// ValidatePath rejection.
|
|
//
|
|
// These strings are user-visible and are assembled by wrapping static
|
|
// sentinels mid-sentence, which makes them easy to reword by accident
|
|
// while refactoring for errors.Is matchability. Changing one is a
|
|
// deliberate change, not a refactoring side effect.
|
|
func TestValidatePathMessagesVerbatim(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
for _, tc := range []struct {
|
|
name string
|
|
path string
|
|
want string
|
|
is error
|
|
}{
|
|
{
|
|
name: "empty",
|
|
path: "",
|
|
want: "path cannot be empty",
|
|
is: errPathEmpty,
|
|
},
|
|
{
|
|
name: "not utf8",
|
|
path: "a\xffb",
|
|
want: `path "a\xffb" is not valid UTF-8`,
|
|
is: errPathNotUTF8,
|
|
},
|
|
{
|
|
name: "backslash",
|
|
path: `a\b`,
|
|
want: `path "a\\b" contains backslash; ` +
|
|
"use forward slashes only",
|
|
is: errPathBackslash,
|
|
},
|
|
{
|
|
name: "absolute",
|
|
path: "/a/b",
|
|
want: `path "/a/b" is absolute; must be relative`,
|
|
is: errPathAbsolute,
|
|
},
|
|
{
|
|
name: "empty segment",
|
|
path: "a//b",
|
|
want: `path "a//b" contains empty segment`,
|
|
is: errPathEmptySegment,
|
|
},
|
|
{
|
|
name: "dotdot segment",
|
|
path: "a/../b",
|
|
want: `path "a/../b" contains '..' segment`,
|
|
is: errPathDotDot,
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
err := ValidatePath(tc.path)
|
|
require.Error(t, err)
|
|
assert.Equal(t, tc.want, err.Error())
|
|
require.ErrorIs(t, err, tc.is)
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestSerializeInnerNotSetMessagesVerbatim pins the messages generate and
|
|
// generateOuter return when the inner message is missing.
|
|
func TestSerializeInnerNotSetMessagesVerbatim(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
m := &manifest{}
|
|
|
|
err := m.generate(context.Background())
|
|
require.ErrorIs(t, err, errInnerNotSet)
|
|
require.EqualError(t, err, "inner message not set")
|
|
|
|
err = m.generateOuter(context.Background())
|
|
require.ErrorIs(t, err, errInternal)
|
|
require.EqualError(t, err, "inner message not set")
|
|
}
|