From cae527f1fbfd133e3cac2aa7dd65a9da1dbdbde3 Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Wed, 17 Jun 2026 19:18:53 +0000 Subject: [PATCH 1/4] Inline typed assertion failure checks --- alias_typed_test.go | 28 +++++++ error.go | 86 +++++++++++++++++++++ error_typed_test.go | 128 ++++++++++++++++++++++++++++++++ filesystem.go | 57 ++++++++++++++ filesystem_typed_test.go | 67 +++++++++++++++++ float.go | 37 +++++++++ float_typed_test.go | 36 +++++++++ map.go | 114 ++++++++++++++++++++++++++++ map_typed_test.go | 91 +++++++++++++++++++++++ number.go | 4 + reader.go | 86 +++++++++++++++++++++ reader_typed_test.go | 64 ++++++++++++++++ slice.go | 126 +++++++++++++++++++++++++++++++ slice_typed_test.go | 93 +++++++++++++++++++++++ string.go | 11 +++ typed_assertion_helpers_test.go | 29 ++++++++ url.go | 94 +++++++++++++++++++++++ url_typed_test.go | 74 ++++++++++++++++++ 18 files changed, 1225 insertions(+) create mode 100644 alias_typed_test.go create mode 100644 error.go create mode 100644 error_typed_test.go create mode 100644 filesystem.go create mode 100644 filesystem_typed_test.go create mode 100644 float.go create mode 100644 float_typed_test.go create mode 100644 map_typed_test.go create mode 100644 reader.go create mode 100644 reader_typed_test.go create mode 100644 slice.go create mode 100644 slice_typed_test.go create mode 100644 typed_assertion_helpers_test.go create mode 100644 url.go create mode 100644 url_typed_test.go diff --git a/alias_typed_test.go b/alias_typed_test.go new file mode 100644 index 0000000..cd67373 --- /dev/null +++ b/alias_typed_test.go @@ -0,0 +1,28 @@ +package gunit_test + +import ( + "github.com/gogunit/gunit" + "github.com/gogunit/gunit/eye" + "testing" +) + +func Test_string_NotContains_success(t *testing.T) { gunit.String(t, "Hello").NotContains("bye") } +func Test_string_NotContains_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.String(aSpy, "Hello").NotContains("ell") + aSpy.HadErrorContaining(t, "not to contain") +} + +func Test_string_NotEmpty_success(t *testing.T) { gunit.String(t, "Hello").NotEmpty() } +func Test_string_NotEmpty_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.String(aSpy, "").NotEmpty() + aSpy.HadErrorContaining(t, "was not") +} + +func Test_number_NotEqual_success(t *testing.T) { gunit.Number(t, 1).NotEqual(2) } +func Test_number_NotEqual_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Number(aSpy, 1).NotEqual(1) + aSpy.HadErrorContaining(t, "not equal") +} diff --git a/error.go b/error.go new file mode 100644 index 0000000..06d55dc --- /dev/null +++ b/error.go @@ -0,0 +1,86 @@ +package gunit + +import ( + "errors" + "regexp" + "strings" +) + +func NilError(t T, err error) { + t.Helper() + if err != nil { + t.Errorf("got <%v>, want nil error", err) + } +} +func Error(t T, err error) { + t.Helper() + if err == nil { + t.Errorf("got nil, want error") + } +} +func EqualError(t T, err error, expected string) { + t.Helper() + if err == nil { + t.Errorf("got nil error, want error message <%s>", expected) + return + } + if err.Error() != expected { + t.Errorf("got error message <%s>, want <%s>", err.Error(), expected) + } +} +func ErrorContains(t T, err error, expected string) { + t.Helper() + if err == nil { + t.Errorf("got nil error, want error containing <%s>", expected) + return + } + if !strings.Contains(err.Error(), expected) { + t.Errorf("got error message <%s>, want containing <%s>", err.Error(), expected) + } +} +func ErrorMatchesRegexp(t T, err error, pattern string) { + t.Helper() + if err == nil { + t.Errorf("got nil error, want error matching regexp <%s>", pattern) + return + } + re, compileErr := regexp.Compile(pattern) + if compileErr != nil { + t.Errorf("invalid regexp <%s>: %v", pattern, compileErr) + return + } + if !re.MatchString(err.Error()) { + t.Errorf("got error message <%s>, want regexp <%s>", err.Error(), pattern) + } +} +func ErrorIs(t T, err error, target error) { + t.Helper() + if !errors.Is(err, target) { + t.Errorf("got <%v>, want error matching <%v>", err, target) + } +} +func NotErrorIs(t T, err error, target error) { + t.Helper() + if errors.Is(err, target) { + t.Errorf("got <%v>, want error not matching <%v>", err, target) + } +} +func ErrorAs[E any](t T, err error, target *E) { + t.Helper() + if !errors.As(err, target) { + t.Errorf("got <%v>, want error assignable to <%T>", err, target) + } +} +func NotErrorAs[E any](t T, err error, target *E) { + t.Helper() + if errors.As(err, target) { + t.Errorf("got <%v>, want error not assignable to <%T>", err, target) + } +} +func ErrorType[E error](t T, err error) { + t.Helper() + var target E + if !errors.As(err, &target) { + t.Errorf("got <%v>, want error assignable to <%T>", err, target) + } +} diff --git a/error_typed_test.go b/error_typed_test.go new file mode 100644 index 0000000..8b887cd --- /dev/null +++ b/error_typed_test.go @@ -0,0 +1,128 @@ +package gunit_test + +import ( + "errors" + "github.com/gogunit/gunit" + "github.com/gogunit/gunit/eye" + "testing" +) + +func Test_error_NilError_success(t *testing.T) { gunit.NilError(t, nil) } +func Test_error_NilError_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.NilError(aSpy, errors.New("sentinel")) + aSpy.HadErrorContaining(t, "want nil error") +} + +func Test_error_Error_success(t *testing.T) { gunit.Error(t, errors.New("sentinel")) } +func Test_error_Error_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Error(aSpy, nil) + aSpy.HadErrorContaining(t, "want error") +} + +func Test_error_EqualError_success(t *testing.T) { + gunit.EqualError(t, errors.New("sentinel"), "sentinel") +} +func Test_error_EqualError_failure_for_nil(t *testing.T) { + aSpy := eye.Spy() + gunit.EqualError(aSpy, nil, "sentinel") + aSpy.HadErrorContaining(t, "got nil error") +} +func Test_error_EqualError_failure_for_mismatch(t *testing.T) { + aSpy := eye.Spy() + gunit.EqualError(aSpy, errors.New("wrapped sentinel"), "sentinel") + aSpy.HadErrorContaining(t, "want ") +} + +func Test_error_ErrorContains_success(t *testing.T) { + gunit.ErrorContains(t, errors.New("wrapped sentinel"), "wrapped") +} +func Test_error_ErrorContains_failure_for_nil(t *testing.T) { + aSpy := eye.Spy() + gunit.ErrorContains(aSpy, nil, "wrapped") + aSpy.HadErrorContaining(t, "got nil error") +} +func Test_error_ErrorContains_failure_for_mismatch(t *testing.T) { + aSpy := eye.Spy() + gunit.ErrorContains(aSpy, errors.New("wrapped sentinel"), "missing") + aSpy.HadErrorContaining(t, "want containing") +} + +func Test_error_ErrorMatchesRegexp_success(t *testing.T) { + gunit.ErrorMatchesRegexp(t, errors.New("wrapped sentinel"), "sentinel") +} +func Test_error_ErrorMatchesRegexp_failure_for_nil(t *testing.T) { + aSpy := eye.Spy() + gunit.ErrorMatchesRegexp(aSpy, nil, "wrapped") + aSpy.HadErrorContaining(t, "got nil error") +} +func Test_error_ErrorMatchesRegexp_failure_for_invalid_regexp(t *testing.T) { + aSpy := eye.Spy() + gunit.ErrorMatchesRegexp(aSpy, errors.New("wrapped sentinel"), "[") + aSpy.HadErrorContaining(t, "invalid regexp") +} +func Test_error_ErrorMatchesRegexp_failure_for_mismatch(t *testing.T) { + aSpy := eye.Spy() + gunit.ErrorMatchesRegexp(aSpy, errors.New("wrapped sentinel"), "missing") + aSpy.HadErrorContaining(t, "want regexp") +} + +func Test_error_ErrorIs_success(t *testing.T) { + sentinel := errors.New("sentinel") + gunit.ErrorIs(t, errors.Join(errors.New("wrapped"), sentinel), sentinel) +} +func Test_error_ErrorIs_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.ErrorIs(aSpy, errors.New("wrapped"), errors.New("sentinel")) + aSpy.HadErrorContaining(t, "want error matching") +} + +func Test_error_NotErrorIs_success(t *testing.T) { + gunit.NotErrorIs(t, errors.New("wrapped"), errors.New("sentinel")) +} +func Test_error_NotErrorIs_failure(t *testing.T) { + sentinel := errors.New("sentinel") + aSpy := eye.Spy() + gunit.NotErrorIs(aSpy, sentinel, sentinel) + aSpy.HadErrorContaining(t, "want error not matching") +} + +func Test_error_ErrorAs_success(t *testing.T) { + var target *typedTestError + gunit.ErrorAs(t, &typedTestError{msg: "wrapped sentinel"}, &target) +} +func Test_error_ErrorAs_failure(t *testing.T) { + var target *typedTestError + aSpy := eye.Spy() + gunit.ErrorAs(aSpy, errors.New("sentinel"), &target) + aSpy.HadErrorContaining(t, "want error assignable") +} + +func Test_error_NotErrorAs_success(t *testing.T) { + var target *otherTypedTestError + gunit.NotErrorAs(t, &typedTestError{msg: "wrapped sentinel"}, &target) +} +func Test_error_NotErrorAs_failure(t *testing.T) { + var target *typedTestError + aSpy := eye.Spy() + gunit.NotErrorAs(aSpy, &typedTestError{msg: "wrapped sentinel"}, &target) + aSpy.HadErrorContaining(t, "want error not assignable") +} + +func Test_error_ErrorType_success(t *testing.T) { + gunit.ErrorType[*typedTestError](t, &typedTestError{msg: "wrapped sentinel"}) +} +func Test_error_ErrorType_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.ErrorType[*typedTestError](aSpy, errors.New("sentinel")) + aSpy.HadErrorContaining(t, "want error assignable") +} + +type typedTestError struct{ msg string } + +func (e *typedTestError) Error() string { return e.msg } + +type otherTypedTestError struct{ msg string } + +func (e *otherTypedTestError) Error() string { return e.msg } diff --git a/filesystem.go b/filesystem.go new file mode 100644 index 0000000..57bcfa6 --- /dev/null +++ b/filesystem.go @@ -0,0 +1,57 @@ +package gunit + +import ( + "errors" + "os" +) + +func FileExists(t T, path string) { + t.Helper() + info, err := os.Stat(path) + if err != nil { + t.Errorf("got path <%s> unavailable: %v, wanted existing file", path, err) + return + } + if info.IsDir() { + t.Errorf("got directory <%s>, wanted existing file", path) + } +} +func NoFileExists(t T, path string) { + t.Helper() + info, err := os.Stat(path) + if errors.Is(err, os.ErrNotExist) { + return + } + if err != nil { + t.Errorf("got path <%s> unavailable: %v, wanted no existing file", path, err) + return + } + if !info.IsDir() { + t.Errorf("got existing file <%s>, wanted no file", path) + } +} +func DirExists(t T, path string) { + t.Helper() + info, err := os.Stat(path) + if err != nil { + t.Errorf("got path <%s> unavailable: %v, wanted existing directory", path, err) + return + } + if !info.IsDir() { + t.Errorf("got file <%s>, wanted existing directory", path) + } +} +func NoDirExists(t T, path string) { + t.Helper() + info, err := os.Stat(path) + if errors.Is(err, os.ErrNotExist) { + return + } + if err != nil { + t.Errorf("got path <%s> unavailable: %v, wanted no existing directory", path, err) + return + } + if info.IsDir() { + t.Errorf("got existing directory <%s>, wanted no directory", path) + } +} diff --git a/filesystem_typed_test.go b/filesystem_typed_test.go new file mode 100644 index 0000000..381aca4 --- /dev/null +++ b/filesystem_typed_test.go @@ -0,0 +1,67 @@ +package gunit_test + +import ( + "github.com/gogunit/gunit" + "github.com/gogunit/gunit/eye" + "path/filepath" + "testing" +) + +func Test_filesystem_FileExists_success(t *testing.T) { + _, file := makeTempDirAndFile(t) + gunit.FileExists(t, file) +} +func Test_filesystem_FileExists_failure_for_missing(t *testing.T) { + dir := t.TempDir() + aSpy := eye.Spy() + gunit.FileExists(aSpy, filepath.Join(dir, "missing.txt")) + aSpy.HadErrorContaining(t, "wanted existing file") +} +func Test_filesystem_FileExists_failure_for_directory(t *testing.T) { + dir := t.TempDir() + aSpy := eye.Spy() + gunit.FileExists(aSpy, dir) + aSpy.HadErrorContaining(t, "wanted existing file") +} + +func Test_filesystem_NoFileExists_success_for_missing(t *testing.T) { + dir := t.TempDir() + gunit.NoFileExists(t, filepath.Join(dir, "missing.txt")) +} +func Test_filesystem_NoFileExists_success_for_directory(t *testing.T) { + gunit.NoFileExists(t, t.TempDir()) +} +func Test_filesystem_NoFileExists_failure(t *testing.T) { + _, file := makeTempDirAndFile(t) + aSpy := eye.Spy() + gunit.NoFileExists(aSpy, file) + aSpy.HadErrorContaining(t, "wanted no file") +} + +func Test_filesystem_DirExists_success(t *testing.T) { gunit.DirExists(t, t.TempDir()) } +func Test_filesystem_DirExists_failure_for_missing(t *testing.T) { + dir := t.TempDir() + aSpy := eye.Spy() + gunit.DirExists(aSpy, filepath.Join(dir, "missing")) + aSpy.HadErrorContaining(t, "wanted existing directory") +} +func Test_filesystem_DirExists_failure_for_file(t *testing.T) { + _, file := makeTempDirAndFile(t) + aSpy := eye.Spy() + gunit.DirExists(aSpy, file) + aSpy.HadErrorContaining(t, "wanted existing directory") +} + +func Test_filesystem_NoDirExists_success_for_missing(t *testing.T) { + dir := t.TempDir() + gunit.NoDirExists(t, filepath.Join(dir, "missing")) +} +func Test_filesystem_NoDirExists_success_for_file(t *testing.T) { + _, file := makeTempDirAndFile(t) + gunit.NoDirExists(t, file) +} +func Test_filesystem_NoDirExists_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.NoDirExists(aSpy, t.TempDir()) + aSpy.HadErrorContaining(t, "wanted no directory") +} diff --git a/float.go b/float.go new file mode 100644 index 0000000..541a176 --- /dev/null +++ b/float.go @@ -0,0 +1,37 @@ +package gunit + +import "math" + +type Floaty interface{ ~float32 | ~float64 } + +func Float[F Floaty](t T, actual F) *Flt[F] { return &Flt[F]{T: t, actual: actual} } + +type Flt[F Floaty] struct { + T + actual F +} + +func (f *Flt[F]) CloseTo(expected, delta F) { + f.Helper() + if math.Abs(float64(f.actual-expected)) > float64(delta) { + f.Errorf("got <%v>, wanted within <%v> of <%v>", f.actual, delta, expected) + } +} +func (f *Flt[F]) IsNaN() { + f.Helper() + if !math.IsNaN(float64(f.actual)) { + f.Errorf("got <%v>, wanted NaN", f.actual) + } +} +func (f *Flt[F]) IsInf() { + f.Helper() + if !math.IsInf(float64(f.actual), 0) { + f.Errorf("got <%v>, wanted infinity", f.actual) + } +} +func (f *Flt[F]) IsInfSign(sign int) { + f.Helper() + if !math.IsInf(float64(f.actual), sign) { + f.Errorf("got <%v>, wanted infinity with sign <%d>", f.actual, sign) + } +} diff --git a/float_typed_test.go b/float_typed_test.go new file mode 100644 index 0000000..3ddf15d --- /dev/null +++ b/float_typed_test.go @@ -0,0 +1,36 @@ +package gunit_test + +import ( + "github.com/gogunit/gunit" + "github.com/gogunit/gunit/eye" + "math" + "testing" +) + +func Test_float_CloseTo_success(t *testing.T) { gunit.Float(t, 1.1).CloseTo(1.0, 0.2) } +func Test_float_CloseTo_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Float(aSpy, 1.3).CloseTo(1.0, 0.2) + aSpy.HadErrorContaining(t, "wanted within") +} + +func Test_float_IsNaN_success(t *testing.T) { gunit.Float(t, math.NaN()).IsNaN() } +func Test_float_IsNaN_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Float(aSpy, 1.0).IsNaN() + aSpy.HadErrorContaining(t, "wanted NaN") +} + +func Test_float_IsInf_success(t *testing.T) { gunit.Float(t, math.Inf(1)).IsInf() } +func Test_float_IsInf_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Float(aSpy, 1.0).IsInf() + aSpy.HadErrorContaining(t, "wanted infinity") +} + +func Test_float_IsInfSign_success(t *testing.T) { gunit.Float(t, math.Inf(-1)).IsInfSign(-1) } +func Test_float_IsInfSign_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Float(aSpy, math.Inf(1)).IsInfSign(-1) + aSpy.HadErrorContaining(t, "wanted infinity with sign") +} diff --git a/map.go b/map.go index 39b798a..faa4de3 100644 --- a/map.go +++ b/map.go @@ -90,3 +90,117 @@ func (m *Mappy[K, V]) WithValues(values ...V) { } // TODO: Implement Includes() or Contains() for subset of pairs? + +func (m *Mappy[K, V]) HasKey(key K) { + m.Helper() + if _, ok := m.actual[key]; !ok { + m.Errorf("got key absent <%v>, wanted present in map", key) + } +} + +func (m *Mappy[K, V]) NotHasKey(key K) { + m.Helper() + if _, ok := m.actual[key]; ok { + m.Errorf("got key present <%v>, wanted absent from map", key) + } +} + +func (m *Mappy[K, V]) KeysExactly(expected ...K) { + m.Helper() + actualKeys := make(map[K]bool, len(m.actual)) + for k := range m.actual { + actualKeys[k] = true + } + expectedKeys := make(map[K]bool, len(expected)) + for _, k := range expected { + expectedKeys[k] = true + } + var missing, extra []K + for k := range expectedKeys { + if !actualKeys[k] { + missing = append(missing, k) + } + } + for k := range actualKeys { + if !expectedKeys[k] { + extra = append(extra, k) + } + } + if len(missing) > 0 || len(extra) > 0 { + m.Errorf("got extra keys <%v> and missing keys <%v>, wanted exact key set", extra, missing) + } +} + +func (m *Mappy[K, V]) NotEmpty() { + m.Helper() + if len(m.actual) == 0 { + m.Errorf("got len=<0>, wanted non-empty map") + } +} +func (m *Mappy[K, V]) IsNotEmpty() { m.NotEmpty() } + +func (m *Mappy[K, V]) NotContains(values ...V) { + m.Helper() + var present []V + seen := make(map[int]bool) + for _, actual := range m.actual { + for i, expected := range values { + if cmp.Equal(actual, expected) { + if !seen[i] { + present = append(present, expected) + } + seen[i] = true + } + } + } + if len(present) > 0 { + m.Errorf("got values <%v>, wanted absent from map", present) + } +} + +func (m *Mappy[K, V]) Len(expected int) { + m.Helper() + if len(m.actual) != expected { + m.Errorf("got len=<%v>, wanted <%v>", len(m.actual), expected) + } +} + +func (m *Mappy[K, V]) WithItem(k K, expected V) { + m.Helper() + actual, ok := m.actual[k] + if !ok { + m.Errorf("got key absent, wanted value for key <%v>", k) + return + } + if !cmp.Equal(actual, expected) { + m.Errorf("got value=<%v> for key=<%v>, wanted <%v>", actual, k, expected) + } +} + +func (m *Mappy[K, V]) WithItems(expected map[K]V) { + m.Helper() + var missing, mismatched []K + for key, expectedValue := range expected { + actualValue, ok := m.actual[key] + if !ok { + missing = append(missing, key) + continue + } + if !cmp.Equal(actualValue, expectedValue) { + mismatched = append(mismatched, key) + } + } + if len(missing) > 0 || len(mismatched) > 0 { + m.Errorf("got missing keys <%v> and mismatched keys <%v>, wanted entries <%v>", missing, mismatched, expected) + } +} + +func (m *Mappy[K, V]) WithoutItems(expected map[K]V) { + m.Helper() + for key, expectedValue := range expected { + if actualValue, ok := m.actual[key]; ok && cmp.Equal(actualValue, expectedValue) { + m.Errorf("got all entries <%v>, wanted at least one absent or different", expected) + return + } + } +} diff --git a/map_typed_test.go b/map_typed_test.go new file mode 100644 index 0000000..6423e91 --- /dev/null +++ b/map_typed_test.go @@ -0,0 +1,91 @@ +package gunit_test + +import ( + "github.com/gogunit/gunit" + "github.com/gogunit/gunit/eye" + "testing" +) + +func Test_map_HasKey_success(t *testing.T) { gunit.Map(t, testMap()).HasKey("a") } +func Test_map_HasKey_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Map(aSpy, testMap()).HasKey("c") + aSpy.HadErrorContaining(t, "wanted present in map") +} + +func Test_map_NotHasKey_success(t *testing.T) { gunit.Map(t, testMap()).NotHasKey("c") } +func Test_map_NotHasKey_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Map(aSpy, testMap()).NotHasKey("a") + aSpy.HadErrorContaining(t, "wanted absent from map") +} + +func Test_map_KeysExactly_success(t *testing.T) { gunit.Map(t, testMap()).KeysExactly("a", "b") } +func Test_map_KeysExactly_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Map(aSpy, testMap()).KeysExactly("a", "c") + aSpy.HadErrorContaining(t, "wanted exact key set") +} + +func Test_map_NotEmpty_success(t *testing.T) { gunit.Map(t, testMap()).NotEmpty() } +func Test_map_NotEmpty_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Map(aSpy, map[string]int{}).NotEmpty() + aSpy.HadErrorContaining(t, "wanted non-empty map") +} + +func Test_map_IsNotEmpty_success(t *testing.T) { gunit.Map(t, testMap()).IsNotEmpty() } +func Test_map_IsNotEmpty_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Map(aSpy, map[string]int{}).IsNotEmpty() + aSpy.HadErrorContaining(t, "wanted non-empty map") +} + +func Test_map_NotContains_success(t *testing.T) { gunit.Map(t, testMap()).NotContains(3) } +func Test_map_NotContains_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Map(aSpy, testMap()).NotContains(1) + aSpy.HadErrorContaining(t, "wanted absent from map") +} + +func Test_map_Len_success(t *testing.T) { gunit.Map(t, testMap()).Len(2) } +func Test_map_Len_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Map(aSpy, testMap()).Len(3) + aSpy.HadErrorContaining(t, "wanted <3>") +} + +func Test_map_WithItem_success(t *testing.T) { gunit.Map(t, testMap()).WithItem("a", 1) } +func Test_map_WithItem_failure_for_missing_key(t *testing.T) { + aSpy := eye.Spy() + gunit.Map(aSpy, testMap()).WithItem("c", 3) + aSpy.HadErrorContaining(t, "got key absent") +} +func Test_map_WithItem_failure_for_mismatched_value(t *testing.T) { + aSpy := eye.Spy() + gunit.Map(aSpy, testMap()).WithItem("a", 3) + aSpy.HadErrorContaining(t, "wanted <3>") +} + +func Test_map_WithItems_success(t *testing.T) { + gunit.Map(t, testMap()).WithItems(map[string]int{"a": 1}) +} +func Test_map_WithItems_failure_for_missing_key(t *testing.T) { + aSpy := eye.Spy() + gunit.Map(aSpy, testMap()).WithItems(map[string]int{"c": 3}) + aSpy.HadErrorContaining(t, "missing keys") +} +func Test_map_WithItems_failure_for_mismatched_value(t *testing.T) { + aSpy := eye.Spy() + gunit.Map(aSpy, testMap()).WithItems(map[string]int{"a": 3}) + aSpy.HadErrorContaining(t, "mismatched keys") +} + +func Test_map_WithoutItems_success(t *testing.T) { + gunit.Map(t, testMap()).WithoutItems(map[string]int{"a": 2}) +} +func Test_map_WithoutItems_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Map(aSpy, testMap()).WithoutItems(map[string]int{"a": 1}) + aSpy.HadErrorContaining(t, "wanted at least one absent") +} diff --git a/number.go b/number.go index 064f652..e0f72bb 100644 --- a/number.go +++ b/number.go @@ -31,6 +31,10 @@ func (n *Num[N]) NotEqualTo(expected N) { } } +func (n *Num[N]) NotEqual(expected N) { + n.NotEqualTo(expected) +} + func (n *Num[N]) LessThan(expected N) { n.Helper() if n.actual >= expected { diff --git a/reader.go b/reader.go new file mode 100644 index 0000000..deb45a3 --- /dev/null +++ b/reader.go @@ -0,0 +1,86 @@ +package gunit + +import ( + "bytes" + "io" + "strings" +) + +func Reader(t T, actual io.Reader) *ReaderAssert { return &ReaderAssert{T: t, actual: actual} } + +type ReaderAssert struct { + T + actual io.Reader + body []byte + read bool +} + +func (r *ReaderAssert) EqualToString(expected string) { + r.Helper() + actual, ok := r.readAll() + if !ok { + return + } + if string(actual) != expected { + r.Errorf("got reader string <%s>, wanted <%s>", string(actual), expected) + } +} +func (r *ReaderAssert) ContainsString(expected string) { + r.Helper() + actual, ok := r.readAll() + if !ok { + return + } + if !strings.Contains(string(actual), expected) { + r.Errorf("got reader string <%s>, wanted substring <%s>", string(actual), expected) + } +} +func (r *ReaderAssert) EqualToBytes(expected []byte) { + r.Helper() + actual, ok := r.readAll() + if !ok { + return + } + if !bytes.Equal(actual, expected) { + r.Errorf("got reader bytes <%v>, wanted <%v>", actual, expected) + } +} +func (r *ReaderAssert) IsEmpty() { + r.Helper() + actual, ok := r.readAll() + if !ok { + return + } + if len(actual) != 0 { + r.Errorf("got reader len()=%d, wanted empty reader", len(actual)) + } +} +func (r *ReaderAssert) IsNotEmpty() { + r.Helper() + actual, ok := r.readAll() + if !ok { + return + } + if len(actual) == 0 { + r.Errorf("got empty reader, wanted non-empty reader") + } +} +func (r *ReaderAssert) NotEmpty() { r.IsNotEmpty() } + +func (r *ReaderAssert) readAll() ([]byte, bool) { + if r.actual == nil { + r.Errorf("got nil reader, wanted reader body") + return nil, false + } + if r.read { + return r.body, true + } + body, err := io.ReadAll(r.actual) + if err != nil { + r.Errorf("got reader read error: %v", err) + return nil, false + } + r.body = body + r.read = true + return body, true +} diff --git a/reader_typed_test.go b/reader_typed_test.go new file mode 100644 index 0000000..3608a61 --- /dev/null +++ b/reader_typed_test.go @@ -0,0 +1,64 @@ +package gunit_test + +import ( + "bytes" + "github.com/gogunit/gunit" + "github.com/gogunit/gunit/eye" + "strings" + "testing" +) + +func Test_reader_ContainsString_success(t *testing.T) { + gunit.Reader(t, strings.NewReader("hello world")).ContainsString("world") +} +func Test_reader_ContainsString_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Reader(aSpy, strings.NewReader("hello")).ContainsString("bye") + aSpy.HadErrorContaining(t, "wanted substring") +} + +func Test_reader_EqualToString_success(t *testing.T) { + gunit.Reader(t, strings.NewReader("hello")).EqualToString("hello") +} +func Test_reader_EqualToString_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Reader(aSpy, strings.NewReader("hello")).EqualToString("bye") + aSpy.HadErrorContaining(t, "wanted ") +} +func Test_reader_EqualToString_failure_for_nil(t *testing.T) { + aSpy := eye.Spy() + gunit.Reader(aSpy, nil).EqualToString("hello") + aSpy.HadErrorContaining(t, "got nil reader") +} + +func Test_reader_EqualToBytes_success(t *testing.T) { + gunit.Reader(t, bytes.NewBufferString("bytes")).EqualToBytes([]byte("bytes")) +} +func Test_reader_EqualToBytes_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Reader(aSpy, bytes.NewBufferString("bytes")).EqualToBytes([]byte("other")) + aSpy.HadErrorContaining(t, "wanted") +} + +func Test_reader_IsEmpty_success(t *testing.T) { gunit.Reader(t, strings.NewReader("")).IsEmpty() } +func Test_reader_IsEmpty_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Reader(aSpy, strings.NewReader("x")).IsEmpty() + aSpy.HadErrorContaining(t, "wanted empty reader") +} + +func Test_reader_IsNotEmpty_success(t *testing.T) { + gunit.Reader(t, strings.NewReader("x")).IsNotEmpty() +} +func Test_reader_IsNotEmpty_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Reader(aSpy, strings.NewReader("")).IsNotEmpty() + aSpy.HadErrorContaining(t, "wanted non-empty reader") +} + +func Test_reader_NotEmpty_success(t *testing.T) { gunit.Reader(t, strings.NewReader("x")).NotEmpty() } +func Test_reader_NotEmpty_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Reader(aSpy, strings.NewReader("")).NotEmpty() + aSpy.HadErrorContaining(t, "wanted non-empty reader") +} diff --git a/slice.go b/slice.go new file mode 100644 index 0000000..c800c73 --- /dev/null +++ b/slice.go @@ -0,0 +1,126 @@ +package gunit + +import "github.com/google/go-cmp/cmp" + +func Slice[I any](t T, actual []I) *Slc[I] { + return &Slc[I]{T: t, actual: actual} +} + +type Slc[I any] struct { + T + actual []I +} + +func (s *Slc[I]) Contains(expected ...I) { + s.Helper() + missing := missingItems(s.actual, expected) + if len(missing) > 0 { + s.Errorf("got missing items <%v>, wanted slice containing <%v>", missing, expected) + } +} + +func (s *Slc[I]) ContainsAny(expected ...I) { + s.Helper() + for _, actual := range s.actual { + for _, want := range expected { + if cmp.Equal(actual, want) { + return + } + } + } + s.Errorf("got no matching item, wanted any of <%v>", expected) +} + +func (s *Slc[I]) NotContains(expected ...I) { + s.Helper() + var present []I + for _, want := range expected { + for _, actual := range s.actual { + if cmp.Equal(actual, want) { + present = append(present, want) + break + } + } + } + if len(present) > 0 { + s.Errorf("got items <%v> present in slice, wanted absent", present) + } +} + +func (s *Slc[I]) EqualTo(expected ...I) { + s.Helper() + if diff := cmp.Diff(expected, s.actual); diff != "" { + s.Errorf("slice mismatch (-want +got):\n%s", diff) + } +} + +func (s *Slc[I]) Len(expected int) { + s.Helper() + if len(s.actual) != expected { + s.Errorf("got len()=%d, wanted %d", len(s.actual), expected) + } +} +func (s *Slc[I]) Cap(expected int) { + s.Helper() + if cap(s.actual) != expected { + s.Errorf("got cap()=%d, wanted %d", cap(s.actual), expected) + } +} +func (s *Slc[I]) IsEmpty() { + s.Helper() + if len(s.actual) != 0 { + s.Errorf("got len()=%d, wanted 0", len(s.actual)) + } +} +func (s *Slc[I]) IsNotEmpty() { + s.Helper() + if len(s.actual) == 0 { + s.Errorf("got len()=0, wanted > 0") + } +} +func (s *Slc[I]) NotEmpty() { s.IsNotEmpty() } + +func (s *Slc[I]) ContainsExactly(expected ...I) { + s.Helper() + if len(s.actual) != len(expected) { + s.Errorf("length mismatch got %d, want %d", len(s.actual), len(expected)) + return + } + s.Contains(expected...) +} +func (s *Slc[I]) SubsetOf(expected ...I) { + s.Helper() + for _, actual := range s.actual { + if !containsEqual(expected, actual) { + s.Errorf("got item <%v> outside expected set <%v>", actual, expected) + return + } + } +} +func (s *Slc[I]) NotSubsetOf(expected ...I) { + s.Helper() + for _, actual := range s.actual { + if !containsEqual(expected, actual) { + return + } + } + s.Errorf("got subset <%v>, wanted at least one item outside <%v>", s.actual, expected) +} + +func missingItems[I any](actual, expected []I) []I { + var missing []I + for _, want := range expected { + if !containsEqual(actual, want) { + missing = append(missing, want) + } + } + return missing +} +func containsEqual[I any](items []I, target I) bool { + for _, item := range items { + if cmp.Equal(item, target) { + return true + } + } + return false +} diff --git a/slice_typed_test.go b/slice_typed_test.go new file mode 100644 index 0000000..d8f7fa4 --- /dev/null +++ b/slice_typed_test.go @@ -0,0 +1,93 @@ +package gunit_test + +import ( + "github.com/gogunit/gunit" + "github.com/gogunit/gunit/eye" + "testing" +) + +func Test_slice_Contains_success(t *testing.T) { gunit.Slice(t, []int{1, 2, 3}).Contains(2, 3) } +func Test_slice_Contains_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Slice(aSpy, []int{1}).Contains(2) + aSpy.HadErrorContaining(t, "missing items") +} + +func Test_slice_ContainsAny_success(t *testing.T) { gunit.Slice(t, []int{1, 2, 3}).ContainsAny(4, 3) } +func Test_slice_ContainsAny_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Slice(aSpy, []int{1}).ContainsAny(2) + aSpy.HadErrorContaining(t, "no matching item") +} + +func Test_slice_NotContains_success(t *testing.T) { gunit.Slice(t, []int{1, 2, 3}).NotContains(4) } +func Test_slice_NotContains_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Slice(aSpy, []int{1}).NotContains(1) + aSpy.HadErrorContaining(t, "present in slice") +} + +func Test_slice_EqualTo_success(t *testing.T) { gunit.Slice(t, []int{1, 2, 3}).EqualTo(1, 2, 3) } +func Test_slice_EqualTo_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Slice(aSpy, []int{1}).EqualTo(2) + aSpy.HadErrorContaining(t, "slice mismatch") +} + +func Test_slice_Len_success(t *testing.T) { gunit.Slice(t, make([]int, 2, 4)).Len(2) } +func Test_slice_Len_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Slice(aSpy, []int{1}).Len(2) + aSpy.HadErrorContaining(t, "got len()=1") +} + +func Test_slice_Cap_success(t *testing.T) { gunit.Slice(t, make([]int, 2, 4)).Cap(4) } +func Test_slice_Cap_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Slice(aSpy, make([]int, 1, 2)).Cap(1) + aSpy.HadErrorContaining(t, "got cap()=2") +} + +func Test_slice_IsEmpty_success(t *testing.T) { gunit.Slice(t, []int{}).IsEmpty() } +func Test_slice_IsEmpty_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Slice(aSpy, []int{1}).IsEmpty() + aSpy.HadErrorContaining(t, "wanted 0") +} + +func Test_slice_IsNotEmpty_success(t *testing.T) { gunit.Slice(t, []int{1}).IsNotEmpty() } +func Test_slice_IsNotEmpty_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Slice(aSpy, []int{}).IsNotEmpty() + aSpy.HadErrorContaining(t, "wanted > 0") +} + +func Test_slice_NotEmpty_success(t *testing.T) { gunit.Slice(t, []int{1}).NotEmpty() } +func Test_slice_NotEmpty_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Slice(aSpy, []int{}).NotEmpty() + aSpy.HadErrorContaining(t, "wanted > 0") +} + +func Test_slice_ContainsExactly_success(t *testing.T) { + gunit.Slice(t, []int{1, 2}).ContainsExactly(2, 1) +} +func Test_slice_ContainsExactly_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Slice(aSpy, []int{1}).ContainsExactly(1, 2) + aSpy.HadErrorContaining(t, "length mismatch") +} + +func Test_slice_SubsetOf_success(t *testing.T) { gunit.Slice(t, []int{1, 2}).SubsetOf(1, 2, 3) } +func Test_slice_SubsetOf_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Slice(aSpy, []int{1, 4}).SubsetOf(1, 2, 3) + aSpy.HadErrorContaining(t, "outside expected set") +} + +func Test_slice_NotSubsetOf_success(t *testing.T) { gunit.Slice(t, []int{1, 4}).NotSubsetOf(1, 2, 3) } +func Test_slice_NotSubsetOf_failure(t *testing.T) { + aSpy := eye.Spy() + gunit.Slice(aSpy, []int{1, 2}).NotSubsetOf(1, 2, 3) + aSpy.HadErrorContaining(t, "got subset") +} diff --git a/string.go b/string.go index 1ec1a04..6c1b0c3 100644 --- a/string.go +++ b/string.go @@ -29,6 +29,13 @@ func (s *Str[S]) Contains(needle S) { } } +func (s *Str[S]) NotContains(needle S) { + s.Helper() + if strings.Contains(string(s.actual), string(needle)) { + s.Errorf("want <%v> not to contain <%v>", s.actual, needle) + } +} + func (s *Str[S]) HasPrefix(prefix S) { s.Helper() if !strings.HasPrefix(string(s.actual), string(prefix)) { @@ -43,6 +50,10 @@ func (s *Str[S]) HasSuffix(suffix S) { } } +func (s *Str[S]) NotEmpty() { + s.IsNotEmpty() +} + func (s *Str[S]) IsEmpty() { s.Helper() if s.actual != "" { diff --git a/typed_assertion_helpers_test.go b/typed_assertion_helpers_test.go new file mode 100644 index 0000000..b4c3258 --- /dev/null +++ b/typed_assertion_helpers_test.go @@ -0,0 +1,29 @@ +package gunit_test + +import ( + "github.com/gogunit/gunit" + "net/url" + "os" + "path/filepath" + "testing" +) + +func makeTempDirAndFile(t *testing.T) (string, string) { + t.Helper() + dir := t.TempDir() + file := filepath.Join(dir, "file.txt") + if err := os.WriteFile(file, []byte("hello"), 0o600); err != nil { + t.Fatal(err) + } + return dir, file +} + +func testURL(t gunit.T) *gunit.URLAssert { + parsed, err := url.Parse("https://example.com/path?q=go") + if err != nil { + t.Fatalf("failed to parse test URL: %v", err) + } + return gunit.URL(t, parsed) +} + +func testMap() map[string]int { return map[string]int{"a": 1, "b": 2} } diff --git a/url.go b/url.go new file mode 100644 index 0000000..b1242ea --- /dev/null +++ b/url.go @@ -0,0 +1,94 @@ +package gunit + +import "net/url" + +func URL(t T, actual *url.URL) *URLAssert { return &URLAssert{T: t, actual: actual} } +func ParseURL(t T, actual string) *URLAssert { + parsed, err := url.Parse(actual) + if err != nil { + return &URLAssert{T: t, validation: err, raw: actual} + } + return URL(t, parsed) +} + +type URLAssert struct { + T + actual *url.URL + validation error + raw string +} + +func (u *URLAssert) Scheme(expected string) { + if !u.ready() { + return + } + if u.actual.Scheme != expected { + u.Errorf("got URL scheme <%s>, wanted <%s>", u.actual.Scheme, expected) + } +} +func (u *URLAssert) Host(expected string) { + if !u.ready() { + return + } + if u.actual.Host != expected { + u.Errorf("got URL host <%s>, wanted <%s>", u.actual.Host, expected) + } +} +func (u *URLAssert) Path(expected string) { + if !u.ready() { + return + } + if u.actual.Path != expected { + u.Errorf("got URL path <%s>, wanted <%s>", u.actual.Path, expected) + } +} +func (u *URLAssert) RawQuery(expected string) { + if !u.ready() { + return + } + if u.actual.RawQuery != expected { + u.Errorf("got URL raw query <%s>, wanted <%s>", u.actual.RawQuery, expected) + } +} +func (u *URLAssert) QueryParam(key, expected string) { + if !u.ready() { + return + } + values, ok := u.actual.Query()[key] + if !ok { + u.Errorf("missing URL query parameter <%s>, wanted <%s>", key, expected) + return + } + if values[0] != expected { + u.Errorf("got URL query parameter <%s> value <%s>, wanted <%s>", key, values[0], expected) + } +} +func (u *URLAssert) NoQueryParam(key string) { + if !u.ready() { + return + } + if _, ok := u.actual.Query()[key]; ok { + u.Errorf("got URL query parameter <%s>, wanted it absent", key) + } +} +func (u *URLAssert) String(expected string) { + if !u.ready() { + return + } + if u.actual.String() != expected { + u.Errorf("got URL string <%s>, wanted <%s>", u.actual.String(), expected) + } +} + +func (u *URLAssert) ready() bool { + u.Helper() + if u.validation != nil { + u.Errorf("invalid URL <%s>: %v", u.raw, u.validation) + return false + } + if u.actual == nil { + u.Errorf("got nil URL") + return false + } + return true +} diff --git a/url_typed_test.go b/url_typed_test.go new file mode 100644 index 0000000..e003b71 --- /dev/null +++ b/url_typed_test.go @@ -0,0 +1,74 @@ +package gunit_test + +import ( + "github.com/gogunit/gunit" + "github.com/gogunit/gunit/eye" + "testing" +) + +func Test_url_Scheme_success(t *testing.T) { testURL(t).Scheme("https") } +func Test_url_Scheme_failure(t *testing.T) { + aSpy := eye.Spy() + testURL(aSpy).Scheme("http") + aSpy.HadErrorContaining(t, "wanted ") +} +func Test_url_Scheme_failure_for_nil(t *testing.T) { + aSpy := eye.Spy() + gunit.URL(aSpy, nil).Scheme("https") + aSpy.HadErrorContaining(t, "got nil URL") +} + +func Test_url_Host_success(t *testing.T) { testURL(t).Host("example.com") } +func Test_url_Host_failure(t *testing.T) { + aSpy := eye.Spy() + testURL(aSpy).Host("other.example") + aSpy.HadErrorContaining(t, "wanted ") +} + +func Test_url_Path_success(t *testing.T) { testURL(t).Path("/path") } +func Test_url_Path_failure(t *testing.T) { + aSpy := eye.Spy() + testURL(aSpy).Path("/other") + aSpy.HadErrorContaining(t, "wanted ") +} + +func Test_url_RawQuery_success(t *testing.T) { testURL(t).RawQuery("q=go") } +func Test_url_RawQuery_failure(t *testing.T) { + aSpy := eye.Spy() + testURL(aSpy).RawQuery("q=rust") + aSpy.HadErrorContaining(t, "wanted ") +} + +func Test_url_QueryParam_success(t *testing.T) { testURL(t).QueryParam("q", "go") } +func Test_url_QueryParam_failure_for_missing(t *testing.T) { + aSpy := eye.Spy() + testURL(aSpy).QueryParam("missing", "go") + aSpy.HadErrorContaining(t, "missing URL query parameter") +} +func Test_url_QueryParam_failure_for_mismatch(t *testing.T) { + aSpy := eye.Spy() + testURL(aSpy).QueryParam("q", "rust") + aSpy.HadErrorContaining(t, "wanted ") +} + +func Test_url_NoQueryParam_success(t *testing.T) { testURL(t).NoQueryParam("missing") } +func Test_url_NoQueryParam_failure(t *testing.T) { + aSpy := eye.Spy() + testURL(aSpy).NoQueryParam("q") + aSpy.HadErrorContaining(t, "wanted it absent") +} + +func Test_url_String_success(t *testing.T) { testURL(t).String("https://example.com/path?q=go") } +func Test_url_String_failure(t *testing.T) { + aSpy := eye.Spy() + testURL(aSpy).String("https://example.com/other") + aSpy.HadErrorContaining(t, "wanted ") +} +func Test_url_ParseURL_String_success(t *testing.T) { + gunit.ParseURL(t, "https://example.com/path?q=go").String("https://example.com/path?q=go") +} +func Test_url_ParseURL_String_failure_for_invalid_url(t *testing.T) { + aSpy := eye.Spy() + gunit.ParseURL(aSpy, "%zz").String("x") + aSpy.HadErrorContaining(t, "invalid URL") +} From 86c428a0eb3505de7fd3bf13d8bc370d656f9d80 Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Wed, 17 Jun 2026 19:33:40 +0000 Subject: [PATCH 2/4] Avoid errors.Join in typed error test --- error_typed_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/error_typed_test.go b/error_typed_test.go index 8b887cd..b537e7e 100644 --- a/error_typed_test.go +++ b/error_typed_test.go @@ -2,6 +2,7 @@ package gunit_test import ( "errors" + "fmt" "github.com/gogunit/gunit" "github.com/gogunit/gunit/eye" "testing" @@ -70,7 +71,7 @@ func Test_error_ErrorMatchesRegexp_failure_for_mismatch(t *testing.T) { func Test_error_ErrorIs_success(t *testing.T) { sentinel := errors.New("sentinel") - gunit.ErrorIs(t, errors.Join(errors.New("wrapped"), sentinel), sentinel) + gunit.ErrorIs(t, fmt.Errorf("wrapped: %w", sentinel), sentinel) } func Test_error_ErrorIs_failure(t *testing.T) { aSpy := eye.Spy() From 21439724bd23ae14933f47589bda52aa0bcaac96 Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Wed, 17 Jun 2026 20:09:16 +0000 Subject: [PATCH 3/4] Expand typed assertion success tests --- alias_typed_test.go | 12 ++++++++--- error_typed_test.go | 8 ++++++-- filesystem_typed_test.go | 4 +++- float_typed_test.go | 16 +++++++++++---- map_typed_test.go | 32 +++++++++++++++++++++-------- reader_typed_test.go | 8 ++++++-- slice_typed_test.go | 44 ++++++++++++++++++++++++++++++---------- url_typed_test.go | 28 ++++++++++++++++++------- 8 files changed, 114 insertions(+), 38 deletions(-) diff --git a/alias_typed_test.go b/alias_typed_test.go index cd67373..f3f50d9 100644 --- a/alias_typed_test.go +++ b/alias_typed_test.go @@ -6,21 +6,27 @@ import ( "testing" ) -func Test_string_NotContains_success(t *testing.T) { gunit.String(t, "Hello").NotContains("bye") } +func Test_string_NotContains_success(t *testing.T) { + gunit.String(t, "Hello").NotContains("bye") +} func Test_string_NotContains_failure(t *testing.T) { aSpy := eye.Spy() gunit.String(aSpy, "Hello").NotContains("ell") aSpy.HadErrorContaining(t, "not to contain") } -func Test_string_NotEmpty_success(t *testing.T) { gunit.String(t, "Hello").NotEmpty() } +func Test_string_NotEmpty_success(t *testing.T) { + gunit.String(t, "Hello").NotEmpty() +} func Test_string_NotEmpty_failure(t *testing.T) { aSpy := eye.Spy() gunit.String(aSpy, "").NotEmpty() aSpy.HadErrorContaining(t, "was not") } -func Test_number_NotEqual_success(t *testing.T) { gunit.Number(t, 1).NotEqual(2) } +func Test_number_NotEqual_success(t *testing.T) { + gunit.Number(t, 1).NotEqual(2) +} func Test_number_NotEqual_failure(t *testing.T) { aSpy := eye.Spy() gunit.Number(aSpy, 1).NotEqual(1) diff --git a/error_typed_test.go b/error_typed_test.go index b537e7e..5ae0553 100644 --- a/error_typed_test.go +++ b/error_typed_test.go @@ -8,14 +8,18 @@ import ( "testing" ) -func Test_error_NilError_success(t *testing.T) { gunit.NilError(t, nil) } +func Test_error_NilError_success(t *testing.T) { + gunit.NilError(t, nil) +} func Test_error_NilError_failure(t *testing.T) { aSpy := eye.Spy() gunit.NilError(aSpy, errors.New("sentinel")) aSpy.HadErrorContaining(t, "want nil error") } -func Test_error_Error_success(t *testing.T) { gunit.Error(t, errors.New("sentinel")) } +func Test_error_Error_success(t *testing.T) { + gunit.Error(t, errors.New("sentinel")) +} func Test_error_Error_failure(t *testing.T) { aSpy := eye.Spy() gunit.Error(aSpy, nil) diff --git a/filesystem_typed_test.go b/filesystem_typed_test.go index 381aca4..7f6c66c 100644 --- a/filesystem_typed_test.go +++ b/filesystem_typed_test.go @@ -38,7 +38,9 @@ func Test_filesystem_NoFileExists_failure(t *testing.T) { aSpy.HadErrorContaining(t, "wanted no file") } -func Test_filesystem_DirExists_success(t *testing.T) { gunit.DirExists(t, t.TempDir()) } +func Test_filesystem_DirExists_success(t *testing.T) { + gunit.DirExists(t, t.TempDir()) +} func Test_filesystem_DirExists_failure_for_missing(t *testing.T) { dir := t.TempDir() aSpy := eye.Spy() diff --git a/float_typed_test.go b/float_typed_test.go index 3ddf15d..af1debe 100644 --- a/float_typed_test.go +++ b/float_typed_test.go @@ -7,28 +7,36 @@ import ( "testing" ) -func Test_float_CloseTo_success(t *testing.T) { gunit.Float(t, 1.1).CloseTo(1.0, 0.2) } +func Test_float_CloseTo_success(t *testing.T) { + gunit.Float(t, 1.1).CloseTo(1.0, 0.2) +} func Test_float_CloseTo_failure(t *testing.T) { aSpy := eye.Spy() gunit.Float(aSpy, 1.3).CloseTo(1.0, 0.2) aSpy.HadErrorContaining(t, "wanted within") } -func Test_float_IsNaN_success(t *testing.T) { gunit.Float(t, math.NaN()).IsNaN() } +func Test_float_IsNaN_success(t *testing.T) { + gunit.Float(t, math.NaN()).IsNaN() +} func Test_float_IsNaN_failure(t *testing.T) { aSpy := eye.Spy() gunit.Float(aSpy, 1.0).IsNaN() aSpy.HadErrorContaining(t, "wanted NaN") } -func Test_float_IsInf_success(t *testing.T) { gunit.Float(t, math.Inf(1)).IsInf() } +func Test_float_IsInf_success(t *testing.T) { + gunit.Float(t, math.Inf(1)).IsInf() +} func Test_float_IsInf_failure(t *testing.T) { aSpy := eye.Spy() gunit.Float(aSpy, 1.0).IsInf() aSpy.HadErrorContaining(t, "wanted infinity") } -func Test_float_IsInfSign_success(t *testing.T) { gunit.Float(t, math.Inf(-1)).IsInfSign(-1) } +func Test_float_IsInfSign_success(t *testing.T) { + gunit.Float(t, math.Inf(-1)).IsInfSign(-1) +} func Test_float_IsInfSign_failure(t *testing.T) { aSpy := eye.Spy() gunit.Float(aSpy, math.Inf(1)).IsInfSign(-1) diff --git a/map_typed_test.go b/map_typed_test.go index 6423e91..fa933d3 100644 --- a/map_typed_test.go +++ b/map_typed_test.go @@ -6,56 +6,72 @@ import ( "testing" ) -func Test_map_HasKey_success(t *testing.T) { gunit.Map(t, testMap()).HasKey("a") } +func Test_map_HasKey_success(t *testing.T) { + gunit.Map(t, testMap()).HasKey("a") +} func Test_map_HasKey_failure(t *testing.T) { aSpy := eye.Spy() gunit.Map(aSpy, testMap()).HasKey("c") aSpy.HadErrorContaining(t, "wanted present in map") } -func Test_map_NotHasKey_success(t *testing.T) { gunit.Map(t, testMap()).NotHasKey("c") } +func Test_map_NotHasKey_success(t *testing.T) { + gunit.Map(t, testMap()).NotHasKey("c") +} func Test_map_NotHasKey_failure(t *testing.T) { aSpy := eye.Spy() gunit.Map(aSpy, testMap()).NotHasKey("a") aSpy.HadErrorContaining(t, "wanted absent from map") } -func Test_map_KeysExactly_success(t *testing.T) { gunit.Map(t, testMap()).KeysExactly("a", "b") } +func Test_map_KeysExactly_success(t *testing.T) { + gunit.Map(t, testMap()).KeysExactly("a", "b") +} func Test_map_KeysExactly_failure(t *testing.T) { aSpy := eye.Spy() gunit.Map(aSpy, testMap()).KeysExactly("a", "c") aSpy.HadErrorContaining(t, "wanted exact key set") } -func Test_map_NotEmpty_success(t *testing.T) { gunit.Map(t, testMap()).NotEmpty() } +func Test_map_NotEmpty_success(t *testing.T) { + gunit.Map(t, testMap()).NotEmpty() +} func Test_map_NotEmpty_failure(t *testing.T) { aSpy := eye.Spy() gunit.Map(aSpy, map[string]int{}).NotEmpty() aSpy.HadErrorContaining(t, "wanted non-empty map") } -func Test_map_IsNotEmpty_success(t *testing.T) { gunit.Map(t, testMap()).IsNotEmpty() } +func Test_map_IsNotEmpty_success(t *testing.T) { + gunit.Map(t, testMap()).IsNotEmpty() +} func Test_map_IsNotEmpty_failure(t *testing.T) { aSpy := eye.Spy() gunit.Map(aSpy, map[string]int{}).IsNotEmpty() aSpy.HadErrorContaining(t, "wanted non-empty map") } -func Test_map_NotContains_success(t *testing.T) { gunit.Map(t, testMap()).NotContains(3) } +func Test_map_NotContains_success(t *testing.T) { + gunit.Map(t, testMap()).NotContains(3) +} func Test_map_NotContains_failure(t *testing.T) { aSpy := eye.Spy() gunit.Map(aSpy, testMap()).NotContains(1) aSpy.HadErrorContaining(t, "wanted absent from map") } -func Test_map_Len_success(t *testing.T) { gunit.Map(t, testMap()).Len(2) } +func Test_map_Len_success(t *testing.T) { + gunit.Map(t, testMap()).Len(2) +} func Test_map_Len_failure(t *testing.T) { aSpy := eye.Spy() gunit.Map(aSpy, testMap()).Len(3) aSpy.HadErrorContaining(t, "wanted <3>") } -func Test_map_WithItem_success(t *testing.T) { gunit.Map(t, testMap()).WithItem("a", 1) } +func Test_map_WithItem_success(t *testing.T) { + gunit.Map(t, testMap()).WithItem("a", 1) +} func Test_map_WithItem_failure_for_missing_key(t *testing.T) { aSpy := eye.Spy() gunit.Map(aSpy, testMap()).WithItem("c", 3) diff --git a/reader_typed_test.go b/reader_typed_test.go index 3608a61..85fe4b0 100644 --- a/reader_typed_test.go +++ b/reader_typed_test.go @@ -40,7 +40,9 @@ func Test_reader_EqualToBytes_failure(t *testing.T) { aSpy.HadErrorContaining(t, "wanted") } -func Test_reader_IsEmpty_success(t *testing.T) { gunit.Reader(t, strings.NewReader("")).IsEmpty() } +func Test_reader_IsEmpty_success(t *testing.T) { + gunit.Reader(t, strings.NewReader("")).IsEmpty() +} func Test_reader_IsEmpty_failure(t *testing.T) { aSpy := eye.Spy() gunit.Reader(aSpy, strings.NewReader("x")).IsEmpty() @@ -56,7 +58,9 @@ func Test_reader_IsNotEmpty_failure(t *testing.T) { aSpy.HadErrorContaining(t, "wanted non-empty reader") } -func Test_reader_NotEmpty_success(t *testing.T) { gunit.Reader(t, strings.NewReader("x")).NotEmpty() } +func Test_reader_NotEmpty_success(t *testing.T) { + gunit.Reader(t, strings.NewReader("x")).NotEmpty() +} func Test_reader_NotEmpty_failure(t *testing.T) { aSpy := eye.Spy() gunit.Reader(aSpy, strings.NewReader("")).NotEmpty() diff --git a/slice_typed_test.go b/slice_typed_test.go index d8f7fa4..d6597fd 100644 --- a/slice_typed_test.go +++ b/slice_typed_test.go @@ -6,63 +6,81 @@ import ( "testing" ) -func Test_slice_Contains_success(t *testing.T) { gunit.Slice(t, []int{1, 2, 3}).Contains(2, 3) } +func Test_slice_Contains_success(t *testing.T) { + gunit.Slice(t, []int{1, 2, 3}).Contains(2, 3) +} func Test_slice_Contains_failure(t *testing.T) { aSpy := eye.Spy() gunit.Slice(aSpy, []int{1}).Contains(2) aSpy.HadErrorContaining(t, "missing items") } -func Test_slice_ContainsAny_success(t *testing.T) { gunit.Slice(t, []int{1, 2, 3}).ContainsAny(4, 3) } +func Test_slice_ContainsAny_success(t *testing.T) { + gunit.Slice(t, []int{1, 2, 3}).ContainsAny(4, 3) +} func Test_slice_ContainsAny_failure(t *testing.T) { aSpy := eye.Spy() gunit.Slice(aSpy, []int{1}).ContainsAny(2) aSpy.HadErrorContaining(t, "no matching item") } -func Test_slice_NotContains_success(t *testing.T) { gunit.Slice(t, []int{1, 2, 3}).NotContains(4) } +func Test_slice_NotContains_success(t *testing.T) { + gunit.Slice(t, []int{1, 2, 3}).NotContains(4) +} func Test_slice_NotContains_failure(t *testing.T) { aSpy := eye.Spy() gunit.Slice(aSpy, []int{1}).NotContains(1) aSpy.HadErrorContaining(t, "present in slice") } -func Test_slice_EqualTo_success(t *testing.T) { gunit.Slice(t, []int{1, 2, 3}).EqualTo(1, 2, 3) } +func Test_slice_EqualTo_success(t *testing.T) { + gunit.Slice(t, []int{1, 2, 3}).EqualTo(1, 2, 3) +} func Test_slice_EqualTo_failure(t *testing.T) { aSpy := eye.Spy() gunit.Slice(aSpy, []int{1}).EqualTo(2) aSpy.HadErrorContaining(t, "slice mismatch") } -func Test_slice_Len_success(t *testing.T) { gunit.Slice(t, make([]int, 2, 4)).Len(2) } +func Test_slice_Len_success(t *testing.T) { + gunit.Slice(t, make([]int, 2, 4)).Len(2) +} func Test_slice_Len_failure(t *testing.T) { aSpy := eye.Spy() gunit.Slice(aSpy, []int{1}).Len(2) aSpy.HadErrorContaining(t, "got len()=1") } -func Test_slice_Cap_success(t *testing.T) { gunit.Slice(t, make([]int, 2, 4)).Cap(4) } +func Test_slice_Cap_success(t *testing.T) { + gunit.Slice(t, make([]int, 2, 4)).Cap(4) +} func Test_slice_Cap_failure(t *testing.T) { aSpy := eye.Spy() gunit.Slice(aSpy, make([]int, 1, 2)).Cap(1) aSpy.HadErrorContaining(t, "got cap()=2") } -func Test_slice_IsEmpty_success(t *testing.T) { gunit.Slice(t, []int{}).IsEmpty() } +func Test_slice_IsEmpty_success(t *testing.T) { + gunit.Slice(t, []int{}).IsEmpty() +} func Test_slice_IsEmpty_failure(t *testing.T) { aSpy := eye.Spy() gunit.Slice(aSpy, []int{1}).IsEmpty() aSpy.HadErrorContaining(t, "wanted 0") } -func Test_slice_IsNotEmpty_success(t *testing.T) { gunit.Slice(t, []int{1}).IsNotEmpty() } +func Test_slice_IsNotEmpty_success(t *testing.T) { + gunit.Slice(t, []int{1}).IsNotEmpty() +} func Test_slice_IsNotEmpty_failure(t *testing.T) { aSpy := eye.Spy() gunit.Slice(aSpy, []int{}).IsNotEmpty() aSpy.HadErrorContaining(t, "wanted > 0") } -func Test_slice_NotEmpty_success(t *testing.T) { gunit.Slice(t, []int{1}).NotEmpty() } +func Test_slice_NotEmpty_success(t *testing.T) { + gunit.Slice(t, []int{1}).NotEmpty() +} func Test_slice_NotEmpty_failure(t *testing.T) { aSpy := eye.Spy() gunit.Slice(aSpy, []int{}).NotEmpty() @@ -78,14 +96,18 @@ func Test_slice_ContainsExactly_failure(t *testing.T) { aSpy.HadErrorContaining(t, "length mismatch") } -func Test_slice_SubsetOf_success(t *testing.T) { gunit.Slice(t, []int{1, 2}).SubsetOf(1, 2, 3) } +func Test_slice_SubsetOf_success(t *testing.T) { + gunit.Slice(t, []int{1, 2}).SubsetOf(1, 2, 3) +} func Test_slice_SubsetOf_failure(t *testing.T) { aSpy := eye.Spy() gunit.Slice(aSpy, []int{1, 4}).SubsetOf(1, 2, 3) aSpy.HadErrorContaining(t, "outside expected set") } -func Test_slice_NotSubsetOf_success(t *testing.T) { gunit.Slice(t, []int{1, 4}).NotSubsetOf(1, 2, 3) } +func Test_slice_NotSubsetOf_success(t *testing.T) { + gunit.Slice(t, []int{1, 4}).NotSubsetOf(1, 2, 3) +} func Test_slice_NotSubsetOf_failure(t *testing.T) { aSpy := eye.Spy() gunit.Slice(aSpy, []int{1, 2}).NotSubsetOf(1, 2, 3) diff --git a/url_typed_test.go b/url_typed_test.go index e003b71..441e49b 100644 --- a/url_typed_test.go +++ b/url_typed_test.go @@ -6,7 +6,9 @@ import ( "testing" ) -func Test_url_Scheme_success(t *testing.T) { testURL(t).Scheme("https") } +func Test_url_Scheme_success(t *testing.T) { + testURL(t).Scheme("https") +} func Test_url_Scheme_failure(t *testing.T) { aSpy := eye.Spy() testURL(aSpy).Scheme("http") @@ -18,28 +20,36 @@ func Test_url_Scheme_failure_for_nil(t *testing.T) { aSpy.HadErrorContaining(t, "got nil URL") } -func Test_url_Host_success(t *testing.T) { testURL(t).Host("example.com") } +func Test_url_Host_success(t *testing.T) { + testURL(t).Host("example.com") +} func Test_url_Host_failure(t *testing.T) { aSpy := eye.Spy() testURL(aSpy).Host("other.example") aSpy.HadErrorContaining(t, "wanted ") } -func Test_url_Path_success(t *testing.T) { testURL(t).Path("/path") } +func Test_url_Path_success(t *testing.T) { + testURL(t).Path("/path") +} func Test_url_Path_failure(t *testing.T) { aSpy := eye.Spy() testURL(aSpy).Path("/other") aSpy.HadErrorContaining(t, "wanted ") } -func Test_url_RawQuery_success(t *testing.T) { testURL(t).RawQuery("q=go") } +func Test_url_RawQuery_success(t *testing.T) { + testURL(t).RawQuery("q=go") +} func Test_url_RawQuery_failure(t *testing.T) { aSpy := eye.Spy() testURL(aSpy).RawQuery("q=rust") aSpy.HadErrorContaining(t, "wanted ") } -func Test_url_QueryParam_success(t *testing.T) { testURL(t).QueryParam("q", "go") } +func Test_url_QueryParam_success(t *testing.T) { + testURL(t).QueryParam("q", "go") +} func Test_url_QueryParam_failure_for_missing(t *testing.T) { aSpy := eye.Spy() testURL(aSpy).QueryParam("missing", "go") @@ -51,14 +61,18 @@ func Test_url_QueryParam_failure_for_mismatch(t *testing.T) { aSpy.HadErrorContaining(t, "wanted ") } -func Test_url_NoQueryParam_success(t *testing.T) { testURL(t).NoQueryParam("missing") } +func Test_url_NoQueryParam_success(t *testing.T) { + testURL(t).NoQueryParam("missing") +} func Test_url_NoQueryParam_failure(t *testing.T) { aSpy := eye.Spy() testURL(aSpy).NoQueryParam("q") aSpy.HadErrorContaining(t, "wanted it absent") } -func Test_url_String_success(t *testing.T) { testURL(t).String("https://example.com/path?q=go") } +func Test_url_String_success(t *testing.T) { + testURL(t).String("https://example.com/path?q=go") +} func Test_url_String_failure(t *testing.T) { aSpy := eye.Spy() testURL(aSpy).String("https://example.com/other") From 38cdb358abc3f53f981abd187d6a3d0bc9a2c997 Mon Sep 17 00:00:00 2001 From: Nathan Fisher Date: Wed, 17 Jun 2026 20:09:55 +0000 Subject: [PATCH 4/4] Add spacing between typed assertion functions --- alias_typed_test.go | 3 +++ error.go | 9 +++++++++ error_typed_test.go | 14 ++++++++++++++ filesystem.go | 3 +++ filesystem_typed_test.go | 8 ++++++++ float.go | 3 +++ float_typed_test.go | 4 ++++ map.go | 1 + map_typed_test.go | 12 ++++++++++++ reader.go | 5 +++++ reader_typed_test.go | 7 +++++++ slice.go | 7 +++++++ slice_typed_test.go | 12 ++++++++++++ url.go | 6 ++++++ url_typed_test.go | 11 +++++++++++ 15 files changed, 105 insertions(+) diff --git a/alias_typed_test.go b/alias_typed_test.go index f3f50d9..c7663a5 100644 --- a/alias_typed_test.go +++ b/alias_typed_test.go @@ -9,6 +9,7 @@ import ( func Test_string_NotContains_success(t *testing.T) { gunit.String(t, "Hello").NotContains("bye") } + func Test_string_NotContains_failure(t *testing.T) { aSpy := eye.Spy() gunit.String(aSpy, "Hello").NotContains("ell") @@ -18,6 +19,7 @@ func Test_string_NotContains_failure(t *testing.T) { func Test_string_NotEmpty_success(t *testing.T) { gunit.String(t, "Hello").NotEmpty() } + func Test_string_NotEmpty_failure(t *testing.T) { aSpy := eye.Spy() gunit.String(aSpy, "").NotEmpty() @@ -27,6 +29,7 @@ func Test_string_NotEmpty_failure(t *testing.T) { func Test_number_NotEqual_success(t *testing.T) { gunit.Number(t, 1).NotEqual(2) } + func Test_number_NotEqual_failure(t *testing.T) { aSpy := eye.Spy() gunit.Number(aSpy, 1).NotEqual(1) diff --git a/error.go b/error.go index 06d55dc..93ed3ad 100644 --- a/error.go +++ b/error.go @@ -12,12 +12,14 @@ func NilError(t T, err error) { t.Errorf("got <%v>, want nil error", err) } } + func Error(t T, err error) { t.Helper() if err == nil { t.Errorf("got nil, want error") } } + func EqualError(t T, err error, expected string) { t.Helper() if err == nil { @@ -28,6 +30,7 @@ func EqualError(t T, err error, expected string) { t.Errorf("got error message <%s>, want <%s>", err.Error(), expected) } } + func ErrorContains(t T, err error, expected string) { t.Helper() if err == nil { @@ -38,6 +41,7 @@ func ErrorContains(t T, err error, expected string) { t.Errorf("got error message <%s>, want containing <%s>", err.Error(), expected) } } + func ErrorMatchesRegexp(t T, err error, pattern string) { t.Helper() if err == nil { @@ -53,30 +57,35 @@ func ErrorMatchesRegexp(t T, err error, pattern string) { t.Errorf("got error message <%s>, want regexp <%s>", err.Error(), pattern) } } + func ErrorIs(t T, err error, target error) { t.Helper() if !errors.Is(err, target) { t.Errorf("got <%v>, want error matching <%v>", err, target) } } + func NotErrorIs(t T, err error, target error) { t.Helper() if errors.Is(err, target) { t.Errorf("got <%v>, want error not matching <%v>", err, target) } } + func ErrorAs[E any](t T, err error, target *E) { t.Helper() if !errors.As(err, target) { t.Errorf("got <%v>, want error assignable to <%T>", err, target) } } + func NotErrorAs[E any](t T, err error, target *E) { t.Helper() if errors.As(err, target) { t.Errorf("got <%v>, want error not assignable to <%T>", err, target) } } + func ErrorType[E error](t T, err error) { t.Helper() var target E diff --git a/error_typed_test.go b/error_typed_test.go index 5ae0553..cbd75f9 100644 --- a/error_typed_test.go +++ b/error_typed_test.go @@ -11,6 +11,7 @@ import ( func Test_error_NilError_success(t *testing.T) { gunit.NilError(t, nil) } + func Test_error_NilError_failure(t *testing.T) { aSpy := eye.Spy() gunit.NilError(aSpy, errors.New("sentinel")) @@ -20,6 +21,7 @@ func Test_error_NilError_failure(t *testing.T) { func Test_error_Error_success(t *testing.T) { gunit.Error(t, errors.New("sentinel")) } + func Test_error_Error_failure(t *testing.T) { aSpy := eye.Spy() gunit.Error(aSpy, nil) @@ -29,11 +31,13 @@ func Test_error_Error_failure(t *testing.T) { func Test_error_EqualError_success(t *testing.T) { gunit.EqualError(t, errors.New("sentinel"), "sentinel") } + func Test_error_EqualError_failure_for_nil(t *testing.T) { aSpy := eye.Spy() gunit.EqualError(aSpy, nil, "sentinel") aSpy.HadErrorContaining(t, "got nil error") } + func Test_error_EqualError_failure_for_mismatch(t *testing.T) { aSpy := eye.Spy() gunit.EqualError(aSpy, errors.New("wrapped sentinel"), "sentinel") @@ -43,11 +47,13 @@ func Test_error_EqualError_failure_for_mismatch(t *testing.T) { func Test_error_ErrorContains_success(t *testing.T) { gunit.ErrorContains(t, errors.New("wrapped sentinel"), "wrapped") } + func Test_error_ErrorContains_failure_for_nil(t *testing.T) { aSpy := eye.Spy() gunit.ErrorContains(aSpy, nil, "wrapped") aSpy.HadErrorContaining(t, "got nil error") } + func Test_error_ErrorContains_failure_for_mismatch(t *testing.T) { aSpy := eye.Spy() gunit.ErrorContains(aSpy, errors.New("wrapped sentinel"), "missing") @@ -57,16 +63,19 @@ func Test_error_ErrorContains_failure_for_mismatch(t *testing.T) { func Test_error_ErrorMatchesRegexp_success(t *testing.T) { gunit.ErrorMatchesRegexp(t, errors.New("wrapped sentinel"), "sentinel") } + func Test_error_ErrorMatchesRegexp_failure_for_nil(t *testing.T) { aSpy := eye.Spy() gunit.ErrorMatchesRegexp(aSpy, nil, "wrapped") aSpy.HadErrorContaining(t, "got nil error") } + func Test_error_ErrorMatchesRegexp_failure_for_invalid_regexp(t *testing.T) { aSpy := eye.Spy() gunit.ErrorMatchesRegexp(aSpy, errors.New("wrapped sentinel"), "[") aSpy.HadErrorContaining(t, "invalid regexp") } + func Test_error_ErrorMatchesRegexp_failure_for_mismatch(t *testing.T) { aSpy := eye.Spy() gunit.ErrorMatchesRegexp(aSpy, errors.New("wrapped sentinel"), "missing") @@ -77,6 +86,7 @@ func Test_error_ErrorIs_success(t *testing.T) { sentinel := errors.New("sentinel") gunit.ErrorIs(t, fmt.Errorf("wrapped: %w", sentinel), sentinel) } + func Test_error_ErrorIs_failure(t *testing.T) { aSpy := eye.Spy() gunit.ErrorIs(aSpy, errors.New("wrapped"), errors.New("sentinel")) @@ -86,6 +96,7 @@ func Test_error_ErrorIs_failure(t *testing.T) { func Test_error_NotErrorIs_success(t *testing.T) { gunit.NotErrorIs(t, errors.New("wrapped"), errors.New("sentinel")) } + func Test_error_NotErrorIs_failure(t *testing.T) { sentinel := errors.New("sentinel") aSpy := eye.Spy() @@ -97,6 +108,7 @@ func Test_error_ErrorAs_success(t *testing.T) { var target *typedTestError gunit.ErrorAs(t, &typedTestError{msg: "wrapped sentinel"}, &target) } + func Test_error_ErrorAs_failure(t *testing.T) { var target *typedTestError aSpy := eye.Spy() @@ -108,6 +120,7 @@ func Test_error_NotErrorAs_success(t *testing.T) { var target *otherTypedTestError gunit.NotErrorAs(t, &typedTestError{msg: "wrapped sentinel"}, &target) } + func Test_error_NotErrorAs_failure(t *testing.T) { var target *typedTestError aSpy := eye.Spy() @@ -118,6 +131,7 @@ func Test_error_NotErrorAs_failure(t *testing.T) { func Test_error_ErrorType_success(t *testing.T) { gunit.ErrorType[*typedTestError](t, &typedTestError{msg: "wrapped sentinel"}) } + func Test_error_ErrorType_failure(t *testing.T) { aSpy := eye.Spy() gunit.ErrorType[*typedTestError](aSpy, errors.New("sentinel")) diff --git a/filesystem.go b/filesystem.go index 57bcfa6..45802f9 100644 --- a/filesystem.go +++ b/filesystem.go @@ -16,6 +16,7 @@ func FileExists(t T, path string) { t.Errorf("got directory <%s>, wanted existing file", path) } } + func NoFileExists(t T, path string) { t.Helper() info, err := os.Stat(path) @@ -30,6 +31,7 @@ func NoFileExists(t T, path string) { t.Errorf("got existing file <%s>, wanted no file", path) } } + func DirExists(t T, path string) { t.Helper() info, err := os.Stat(path) @@ -41,6 +43,7 @@ func DirExists(t T, path string) { t.Errorf("got file <%s>, wanted existing directory", path) } } + func NoDirExists(t T, path string) { t.Helper() info, err := os.Stat(path) diff --git a/filesystem_typed_test.go b/filesystem_typed_test.go index 7f6c66c..9a7d2c7 100644 --- a/filesystem_typed_test.go +++ b/filesystem_typed_test.go @@ -11,12 +11,14 @@ func Test_filesystem_FileExists_success(t *testing.T) { _, file := makeTempDirAndFile(t) gunit.FileExists(t, file) } + func Test_filesystem_FileExists_failure_for_missing(t *testing.T) { dir := t.TempDir() aSpy := eye.Spy() gunit.FileExists(aSpy, filepath.Join(dir, "missing.txt")) aSpy.HadErrorContaining(t, "wanted existing file") } + func Test_filesystem_FileExists_failure_for_directory(t *testing.T) { dir := t.TempDir() aSpy := eye.Spy() @@ -28,9 +30,11 @@ func Test_filesystem_NoFileExists_success_for_missing(t *testing.T) { dir := t.TempDir() gunit.NoFileExists(t, filepath.Join(dir, "missing.txt")) } + func Test_filesystem_NoFileExists_success_for_directory(t *testing.T) { gunit.NoFileExists(t, t.TempDir()) } + func Test_filesystem_NoFileExists_failure(t *testing.T) { _, file := makeTempDirAndFile(t) aSpy := eye.Spy() @@ -41,12 +45,14 @@ func Test_filesystem_NoFileExists_failure(t *testing.T) { func Test_filesystem_DirExists_success(t *testing.T) { gunit.DirExists(t, t.TempDir()) } + func Test_filesystem_DirExists_failure_for_missing(t *testing.T) { dir := t.TempDir() aSpy := eye.Spy() gunit.DirExists(aSpy, filepath.Join(dir, "missing")) aSpy.HadErrorContaining(t, "wanted existing directory") } + func Test_filesystem_DirExists_failure_for_file(t *testing.T) { _, file := makeTempDirAndFile(t) aSpy := eye.Spy() @@ -58,10 +64,12 @@ func Test_filesystem_NoDirExists_success_for_missing(t *testing.T) { dir := t.TempDir() gunit.NoDirExists(t, filepath.Join(dir, "missing")) } + func Test_filesystem_NoDirExists_success_for_file(t *testing.T) { _, file := makeTempDirAndFile(t) gunit.NoDirExists(t, file) } + func Test_filesystem_NoDirExists_failure(t *testing.T) { aSpy := eye.Spy() gunit.NoDirExists(aSpy, t.TempDir()) diff --git a/float.go b/float.go index 541a176..f2b3b6d 100644 --- a/float.go +++ b/float.go @@ -17,18 +17,21 @@ func (f *Flt[F]) CloseTo(expected, delta F) { f.Errorf("got <%v>, wanted within <%v> of <%v>", f.actual, delta, expected) } } + func (f *Flt[F]) IsNaN() { f.Helper() if !math.IsNaN(float64(f.actual)) { f.Errorf("got <%v>, wanted NaN", f.actual) } } + func (f *Flt[F]) IsInf() { f.Helper() if !math.IsInf(float64(f.actual), 0) { f.Errorf("got <%v>, wanted infinity", f.actual) } } + func (f *Flt[F]) IsInfSign(sign int) { f.Helper() if !math.IsInf(float64(f.actual), sign) { diff --git a/float_typed_test.go b/float_typed_test.go index af1debe..164f93a 100644 --- a/float_typed_test.go +++ b/float_typed_test.go @@ -10,6 +10,7 @@ import ( func Test_float_CloseTo_success(t *testing.T) { gunit.Float(t, 1.1).CloseTo(1.0, 0.2) } + func Test_float_CloseTo_failure(t *testing.T) { aSpy := eye.Spy() gunit.Float(aSpy, 1.3).CloseTo(1.0, 0.2) @@ -19,6 +20,7 @@ func Test_float_CloseTo_failure(t *testing.T) { func Test_float_IsNaN_success(t *testing.T) { gunit.Float(t, math.NaN()).IsNaN() } + func Test_float_IsNaN_failure(t *testing.T) { aSpy := eye.Spy() gunit.Float(aSpy, 1.0).IsNaN() @@ -28,6 +30,7 @@ func Test_float_IsNaN_failure(t *testing.T) { func Test_float_IsInf_success(t *testing.T) { gunit.Float(t, math.Inf(1)).IsInf() } + func Test_float_IsInf_failure(t *testing.T) { aSpy := eye.Spy() gunit.Float(aSpy, 1.0).IsInf() @@ -37,6 +40,7 @@ func Test_float_IsInf_failure(t *testing.T) { func Test_float_IsInfSign_success(t *testing.T) { gunit.Float(t, math.Inf(-1)).IsInfSign(-1) } + func Test_float_IsInfSign_failure(t *testing.T) { aSpy := eye.Spy() gunit.Float(aSpy, math.Inf(1)).IsInfSign(-1) diff --git a/map.go b/map.go index faa4de3..017c935 100644 --- a/map.go +++ b/map.go @@ -137,6 +137,7 @@ func (m *Mappy[K, V]) NotEmpty() { m.Errorf("got len=<0>, wanted non-empty map") } } + func (m *Mappy[K, V]) IsNotEmpty() { m.NotEmpty() } func (m *Mappy[K, V]) NotContains(values ...V) { diff --git a/map_typed_test.go b/map_typed_test.go index fa933d3..3d3128d 100644 --- a/map_typed_test.go +++ b/map_typed_test.go @@ -9,6 +9,7 @@ import ( func Test_map_HasKey_success(t *testing.T) { gunit.Map(t, testMap()).HasKey("a") } + func Test_map_HasKey_failure(t *testing.T) { aSpy := eye.Spy() gunit.Map(aSpy, testMap()).HasKey("c") @@ -18,6 +19,7 @@ func Test_map_HasKey_failure(t *testing.T) { func Test_map_NotHasKey_success(t *testing.T) { gunit.Map(t, testMap()).NotHasKey("c") } + func Test_map_NotHasKey_failure(t *testing.T) { aSpy := eye.Spy() gunit.Map(aSpy, testMap()).NotHasKey("a") @@ -27,6 +29,7 @@ func Test_map_NotHasKey_failure(t *testing.T) { func Test_map_KeysExactly_success(t *testing.T) { gunit.Map(t, testMap()).KeysExactly("a", "b") } + func Test_map_KeysExactly_failure(t *testing.T) { aSpy := eye.Spy() gunit.Map(aSpy, testMap()).KeysExactly("a", "c") @@ -36,6 +39,7 @@ func Test_map_KeysExactly_failure(t *testing.T) { func Test_map_NotEmpty_success(t *testing.T) { gunit.Map(t, testMap()).NotEmpty() } + func Test_map_NotEmpty_failure(t *testing.T) { aSpy := eye.Spy() gunit.Map(aSpy, map[string]int{}).NotEmpty() @@ -45,6 +49,7 @@ func Test_map_NotEmpty_failure(t *testing.T) { func Test_map_IsNotEmpty_success(t *testing.T) { gunit.Map(t, testMap()).IsNotEmpty() } + func Test_map_IsNotEmpty_failure(t *testing.T) { aSpy := eye.Spy() gunit.Map(aSpy, map[string]int{}).IsNotEmpty() @@ -54,6 +59,7 @@ func Test_map_IsNotEmpty_failure(t *testing.T) { func Test_map_NotContains_success(t *testing.T) { gunit.Map(t, testMap()).NotContains(3) } + func Test_map_NotContains_failure(t *testing.T) { aSpy := eye.Spy() gunit.Map(aSpy, testMap()).NotContains(1) @@ -63,6 +69,7 @@ func Test_map_NotContains_failure(t *testing.T) { func Test_map_Len_success(t *testing.T) { gunit.Map(t, testMap()).Len(2) } + func Test_map_Len_failure(t *testing.T) { aSpy := eye.Spy() gunit.Map(aSpy, testMap()).Len(3) @@ -72,11 +79,13 @@ func Test_map_Len_failure(t *testing.T) { func Test_map_WithItem_success(t *testing.T) { gunit.Map(t, testMap()).WithItem("a", 1) } + func Test_map_WithItem_failure_for_missing_key(t *testing.T) { aSpy := eye.Spy() gunit.Map(aSpy, testMap()).WithItem("c", 3) aSpy.HadErrorContaining(t, "got key absent") } + func Test_map_WithItem_failure_for_mismatched_value(t *testing.T) { aSpy := eye.Spy() gunit.Map(aSpy, testMap()).WithItem("a", 3) @@ -86,11 +95,13 @@ func Test_map_WithItem_failure_for_mismatched_value(t *testing.T) { func Test_map_WithItems_success(t *testing.T) { gunit.Map(t, testMap()).WithItems(map[string]int{"a": 1}) } + func Test_map_WithItems_failure_for_missing_key(t *testing.T) { aSpy := eye.Spy() gunit.Map(aSpy, testMap()).WithItems(map[string]int{"c": 3}) aSpy.HadErrorContaining(t, "missing keys") } + func Test_map_WithItems_failure_for_mismatched_value(t *testing.T) { aSpy := eye.Spy() gunit.Map(aSpy, testMap()).WithItems(map[string]int{"a": 3}) @@ -100,6 +111,7 @@ func Test_map_WithItems_failure_for_mismatched_value(t *testing.T) { func Test_map_WithoutItems_success(t *testing.T) { gunit.Map(t, testMap()).WithoutItems(map[string]int{"a": 2}) } + func Test_map_WithoutItems_failure(t *testing.T) { aSpy := eye.Spy() gunit.Map(aSpy, testMap()).WithoutItems(map[string]int{"a": 1}) diff --git a/reader.go b/reader.go index deb45a3..7eafb17 100644 --- a/reader.go +++ b/reader.go @@ -25,6 +25,7 @@ func (r *ReaderAssert) EqualToString(expected string) { r.Errorf("got reader string <%s>, wanted <%s>", string(actual), expected) } } + func (r *ReaderAssert) ContainsString(expected string) { r.Helper() actual, ok := r.readAll() @@ -35,6 +36,7 @@ func (r *ReaderAssert) ContainsString(expected string) { r.Errorf("got reader string <%s>, wanted substring <%s>", string(actual), expected) } } + func (r *ReaderAssert) EqualToBytes(expected []byte) { r.Helper() actual, ok := r.readAll() @@ -45,6 +47,7 @@ func (r *ReaderAssert) EqualToBytes(expected []byte) { r.Errorf("got reader bytes <%v>, wanted <%v>", actual, expected) } } + func (r *ReaderAssert) IsEmpty() { r.Helper() actual, ok := r.readAll() @@ -55,6 +58,7 @@ func (r *ReaderAssert) IsEmpty() { r.Errorf("got reader len()=%d, wanted empty reader", len(actual)) } } + func (r *ReaderAssert) IsNotEmpty() { r.Helper() actual, ok := r.readAll() @@ -65,6 +69,7 @@ func (r *ReaderAssert) IsNotEmpty() { r.Errorf("got empty reader, wanted non-empty reader") } } + func (r *ReaderAssert) NotEmpty() { r.IsNotEmpty() } func (r *ReaderAssert) readAll() ([]byte, bool) { diff --git a/reader_typed_test.go b/reader_typed_test.go index 85fe4b0..18383cf 100644 --- a/reader_typed_test.go +++ b/reader_typed_test.go @@ -11,6 +11,7 @@ import ( func Test_reader_ContainsString_success(t *testing.T) { gunit.Reader(t, strings.NewReader("hello world")).ContainsString("world") } + func Test_reader_ContainsString_failure(t *testing.T) { aSpy := eye.Spy() gunit.Reader(aSpy, strings.NewReader("hello")).ContainsString("bye") @@ -20,11 +21,13 @@ func Test_reader_ContainsString_failure(t *testing.T) { func Test_reader_EqualToString_success(t *testing.T) { gunit.Reader(t, strings.NewReader("hello")).EqualToString("hello") } + func Test_reader_EqualToString_failure(t *testing.T) { aSpy := eye.Spy() gunit.Reader(aSpy, strings.NewReader("hello")).EqualToString("bye") aSpy.HadErrorContaining(t, "wanted ") } + func Test_reader_EqualToString_failure_for_nil(t *testing.T) { aSpy := eye.Spy() gunit.Reader(aSpy, nil).EqualToString("hello") @@ -34,6 +37,7 @@ func Test_reader_EqualToString_failure_for_nil(t *testing.T) { func Test_reader_EqualToBytes_success(t *testing.T) { gunit.Reader(t, bytes.NewBufferString("bytes")).EqualToBytes([]byte("bytes")) } + func Test_reader_EqualToBytes_failure(t *testing.T) { aSpy := eye.Spy() gunit.Reader(aSpy, bytes.NewBufferString("bytes")).EqualToBytes([]byte("other")) @@ -43,6 +47,7 @@ func Test_reader_EqualToBytes_failure(t *testing.T) { func Test_reader_IsEmpty_success(t *testing.T) { gunit.Reader(t, strings.NewReader("")).IsEmpty() } + func Test_reader_IsEmpty_failure(t *testing.T) { aSpy := eye.Spy() gunit.Reader(aSpy, strings.NewReader("x")).IsEmpty() @@ -52,6 +57,7 @@ func Test_reader_IsEmpty_failure(t *testing.T) { func Test_reader_IsNotEmpty_success(t *testing.T) { gunit.Reader(t, strings.NewReader("x")).IsNotEmpty() } + func Test_reader_IsNotEmpty_failure(t *testing.T) { aSpy := eye.Spy() gunit.Reader(aSpy, strings.NewReader("")).IsNotEmpty() @@ -61,6 +67,7 @@ func Test_reader_IsNotEmpty_failure(t *testing.T) { func Test_reader_NotEmpty_success(t *testing.T) { gunit.Reader(t, strings.NewReader("x")).NotEmpty() } + func Test_reader_NotEmpty_failure(t *testing.T) { aSpy := eye.Spy() gunit.Reader(aSpy, strings.NewReader("")).NotEmpty() diff --git a/slice.go b/slice.go index c800c73..4e98b5f 100644 --- a/slice.go +++ b/slice.go @@ -60,24 +60,28 @@ func (s *Slc[I]) Len(expected int) { s.Errorf("got len()=%d, wanted %d", len(s.actual), expected) } } + func (s *Slc[I]) Cap(expected int) { s.Helper() if cap(s.actual) != expected { s.Errorf("got cap()=%d, wanted %d", cap(s.actual), expected) } } + func (s *Slc[I]) IsEmpty() { s.Helper() if len(s.actual) != 0 { s.Errorf("got len()=%d, wanted 0", len(s.actual)) } } + func (s *Slc[I]) IsNotEmpty() { s.Helper() if len(s.actual) == 0 { s.Errorf("got len()=0, wanted > 0") } } + func (s *Slc[I]) NotEmpty() { s.IsNotEmpty() } func (s *Slc[I]) ContainsExactly(expected ...I) { @@ -88,6 +92,7 @@ func (s *Slc[I]) ContainsExactly(expected ...I) { } s.Contains(expected...) } + func (s *Slc[I]) SubsetOf(expected ...I) { s.Helper() for _, actual := range s.actual { @@ -97,6 +102,7 @@ func (s *Slc[I]) SubsetOf(expected ...I) { } } } + func (s *Slc[I]) NotSubsetOf(expected ...I) { s.Helper() for _, actual := range s.actual { @@ -116,6 +122,7 @@ func missingItems[I any](actual, expected []I) []I { } return missing } + func containsEqual[I any](items []I, target I) bool { for _, item := range items { if cmp.Equal(item, target) { diff --git a/slice_typed_test.go b/slice_typed_test.go index d6597fd..35376a3 100644 --- a/slice_typed_test.go +++ b/slice_typed_test.go @@ -9,6 +9,7 @@ import ( func Test_slice_Contains_success(t *testing.T) { gunit.Slice(t, []int{1, 2, 3}).Contains(2, 3) } + func Test_slice_Contains_failure(t *testing.T) { aSpy := eye.Spy() gunit.Slice(aSpy, []int{1}).Contains(2) @@ -18,6 +19,7 @@ func Test_slice_Contains_failure(t *testing.T) { func Test_slice_ContainsAny_success(t *testing.T) { gunit.Slice(t, []int{1, 2, 3}).ContainsAny(4, 3) } + func Test_slice_ContainsAny_failure(t *testing.T) { aSpy := eye.Spy() gunit.Slice(aSpy, []int{1}).ContainsAny(2) @@ -27,6 +29,7 @@ func Test_slice_ContainsAny_failure(t *testing.T) { func Test_slice_NotContains_success(t *testing.T) { gunit.Slice(t, []int{1, 2, 3}).NotContains(4) } + func Test_slice_NotContains_failure(t *testing.T) { aSpy := eye.Spy() gunit.Slice(aSpy, []int{1}).NotContains(1) @@ -36,6 +39,7 @@ func Test_slice_NotContains_failure(t *testing.T) { func Test_slice_EqualTo_success(t *testing.T) { gunit.Slice(t, []int{1, 2, 3}).EqualTo(1, 2, 3) } + func Test_slice_EqualTo_failure(t *testing.T) { aSpy := eye.Spy() gunit.Slice(aSpy, []int{1}).EqualTo(2) @@ -45,6 +49,7 @@ func Test_slice_EqualTo_failure(t *testing.T) { func Test_slice_Len_success(t *testing.T) { gunit.Slice(t, make([]int, 2, 4)).Len(2) } + func Test_slice_Len_failure(t *testing.T) { aSpy := eye.Spy() gunit.Slice(aSpy, []int{1}).Len(2) @@ -54,6 +59,7 @@ func Test_slice_Len_failure(t *testing.T) { func Test_slice_Cap_success(t *testing.T) { gunit.Slice(t, make([]int, 2, 4)).Cap(4) } + func Test_slice_Cap_failure(t *testing.T) { aSpy := eye.Spy() gunit.Slice(aSpy, make([]int, 1, 2)).Cap(1) @@ -63,6 +69,7 @@ func Test_slice_Cap_failure(t *testing.T) { func Test_slice_IsEmpty_success(t *testing.T) { gunit.Slice(t, []int{}).IsEmpty() } + func Test_slice_IsEmpty_failure(t *testing.T) { aSpy := eye.Spy() gunit.Slice(aSpy, []int{1}).IsEmpty() @@ -72,6 +79,7 @@ func Test_slice_IsEmpty_failure(t *testing.T) { func Test_slice_IsNotEmpty_success(t *testing.T) { gunit.Slice(t, []int{1}).IsNotEmpty() } + func Test_slice_IsNotEmpty_failure(t *testing.T) { aSpy := eye.Spy() gunit.Slice(aSpy, []int{}).IsNotEmpty() @@ -81,6 +89,7 @@ func Test_slice_IsNotEmpty_failure(t *testing.T) { func Test_slice_NotEmpty_success(t *testing.T) { gunit.Slice(t, []int{1}).NotEmpty() } + func Test_slice_NotEmpty_failure(t *testing.T) { aSpy := eye.Spy() gunit.Slice(aSpy, []int{}).NotEmpty() @@ -90,6 +99,7 @@ func Test_slice_NotEmpty_failure(t *testing.T) { func Test_slice_ContainsExactly_success(t *testing.T) { gunit.Slice(t, []int{1, 2}).ContainsExactly(2, 1) } + func Test_slice_ContainsExactly_failure(t *testing.T) { aSpy := eye.Spy() gunit.Slice(aSpy, []int{1}).ContainsExactly(1, 2) @@ -99,6 +109,7 @@ func Test_slice_ContainsExactly_failure(t *testing.T) { func Test_slice_SubsetOf_success(t *testing.T) { gunit.Slice(t, []int{1, 2}).SubsetOf(1, 2, 3) } + func Test_slice_SubsetOf_failure(t *testing.T) { aSpy := eye.Spy() gunit.Slice(aSpy, []int{1, 4}).SubsetOf(1, 2, 3) @@ -108,6 +119,7 @@ func Test_slice_SubsetOf_failure(t *testing.T) { func Test_slice_NotSubsetOf_success(t *testing.T) { gunit.Slice(t, []int{1, 4}).NotSubsetOf(1, 2, 3) } + func Test_slice_NotSubsetOf_failure(t *testing.T) { aSpy := eye.Spy() gunit.Slice(aSpy, []int{1, 2}).NotSubsetOf(1, 2, 3) diff --git a/url.go b/url.go index b1242ea..040dc22 100644 --- a/url.go +++ b/url.go @@ -26,6 +26,7 @@ func (u *URLAssert) Scheme(expected string) { u.Errorf("got URL scheme <%s>, wanted <%s>", u.actual.Scheme, expected) } } + func (u *URLAssert) Host(expected string) { if !u.ready() { return @@ -34,6 +35,7 @@ func (u *URLAssert) Host(expected string) { u.Errorf("got URL host <%s>, wanted <%s>", u.actual.Host, expected) } } + func (u *URLAssert) Path(expected string) { if !u.ready() { return @@ -42,6 +44,7 @@ func (u *URLAssert) Path(expected string) { u.Errorf("got URL path <%s>, wanted <%s>", u.actual.Path, expected) } } + func (u *URLAssert) RawQuery(expected string) { if !u.ready() { return @@ -50,6 +53,7 @@ func (u *URLAssert) RawQuery(expected string) { u.Errorf("got URL raw query <%s>, wanted <%s>", u.actual.RawQuery, expected) } } + func (u *URLAssert) QueryParam(key, expected string) { if !u.ready() { return @@ -63,6 +67,7 @@ func (u *URLAssert) QueryParam(key, expected string) { u.Errorf("got URL query parameter <%s> value <%s>, wanted <%s>", key, values[0], expected) } } + func (u *URLAssert) NoQueryParam(key string) { if !u.ready() { return @@ -71,6 +76,7 @@ func (u *URLAssert) NoQueryParam(key string) { u.Errorf("got URL query parameter <%s>, wanted it absent", key) } } + func (u *URLAssert) String(expected string) { if !u.ready() { return diff --git a/url_typed_test.go b/url_typed_test.go index 441e49b..c509504 100644 --- a/url_typed_test.go +++ b/url_typed_test.go @@ -9,11 +9,13 @@ import ( func Test_url_Scheme_success(t *testing.T) { testURL(t).Scheme("https") } + func Test_url_Scheme_failure(t *testing.T) { aSpy := eye.Spy() testURL(aSpy).Scheme("http") aSpy.HadErrorContaining(t, "wanted ") } + func Test_url_Scheme_failure_for_nil(t *testing.T) { aSpy := eye.Spy() gunit.URL(aSpy, nil).Scheme("https") @@ -23,6 +25,7 @@ func Test_url_Scheme_failure_for_nil(t *testing.T) { func Test_url_Host_success(t *testing.T) { testURL(t).Host("example.com") } + func Test_url_Host_failure(t *testing.T) { aSpy := eye.Spy() testURL(aSpy).Host("other.example") @@ -32,6 +35,7 @@ func Test_url_Host_failure(t *testing.T) { func Test_url_Path_success(t *testing.T) { testURL(t).Path("/path") } + func Test_url_Path_failure(t *testing.T) { aSpy := eye.Spy() testURL(aSpy).Path("/other") @@ -41,6 +45,7 @@ func Test_url_Path_failure(t *testing.T) { func Test_url_RawQuery_success(t *testing.T) { testURL(t).RawQuery("q=go") } + func Test_url_RawQuery_failure(t *testing.T) { aSpy := eye.Spy() testURL(aSpy).RawQuery("q=rust") @@ -50,11 +55,13 @@ func Test_url_RawQuery_failure(t *testing.T) { func Test_url_QueryParam_success(t *testing.T) { testURL(t).QueryParam("q", "go") } + func Test_url_QueryParam_failure_for_missing(t *testing.T) { aSpy := eye.Spy() testURL(aSpy).QueryParam("missing", "go") aSpy.HadErrorContaining(t, "missing URL query parameter") } + func Test_url_QueryParam_failure_for_mismatch(t *testing.T) { aSpy := eye.Spy() testURL(aSpy).QueryParam("q", "rust") @@ -64,6 +71,7 @@ func Test_url_QueryParam_failure_for_mismatch(t *testing.T) { func Test_url_NoQueryParam_success(t *testing.T) { testURL(t).NoQueryParam("missing") } + func Test_url_NoQueryParam_failure(t *testing.T) { aSpy := eye.Spy() testURL(aSpy).NoQueryParam("q") @@ -73,14 +81,17 @@ func Test_url_NoQueryParam_failure(t *testing.T) { func Test_url_String_success(t *testing.T) { testURL(t).String("https://example.com/path?q=go") } + func Test_url_String_failure(t *testing.T) { aSpy := eye.Spy() testURL(aSpy).String("https://example.com/other") aSpy.HadErrorContaining(t, "wanted ") } + func Test_url_ParseURL_String_success(t *testing.T) { gunit.ParseURL(t, "https://example.com/path?q=go").String("https://example.com/path?q=go") } + func Test_url_ParseURL_String_failure_for_invalid_url(t *testing.T) { aSpy := eye.Spy() gunit.ParseURL(aSpy, "%zz").String("x")