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 builder's path errors, the gpg helpers' own errors) are dropped. gpg's stderr is appended to a gpg failure, and to the error for a signing key gpg did not report, only when gpg wrote some. errHTTPStatus reads "unexpected HTTP status"; both inner-not-set sentinels read "inner message not set". No sentinel, errors.Is result or exit status changes. 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")
|
|
}
|