Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions assert/assert_format.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

347 changes: 176 additions & 171 deletions assert/assert_forward.go

Large diffs are not rendered by default.

220 changes: 110 additions & 110 deletions assert/assert_forward_go127.go

Large diffs are not rendered by default.

15 changes: 15 additions & 0 deletions assert/assert_helpers.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 8 additions & 4 deletions assert/assert_helpers_test.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

142 changes: 142 additions & 0 deletions assert/assert_options_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// SPDX-FileCopyrightText: Copyright 2025 go-swagger maintainers
// SPDX-License-Identifier: Apache-2.0

package assert

import (
"fmt"
"strings"
"testing"
)

// capturingT is a [T] that keeps the last failure message.
type capturingT struct {
message string
failed bool
}

func (capturingT) Helper() {}

func (m *capturingT) Errorf(format string, args ...any) {
m.message = fmt.Sprintf(format, args...)
m.failed = true
}

// TestNewWithHunkSize demonstrates how [WithHunkSize] widens the diff reported by [Assertions.Equal].
//
// The two values differ on their last element only, so the diff holds a single hunk and the
// option decides how many unchanged lines precede the change.
func TestNewWithHunkSize(t *testing.T) {
t.Parallel()

expected := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "j"}
actual := []string{"a", "b", "c", "d", "e", "f", "g", "h", "i", "z"}

for _, toPin := range []struct {
name string
options []Option
wantContext int // unchanged lines of the diff
wantFirst string // first unchanged line of the hunk
}{
{name: "default", options: nil, wantContext: 2, wantFirst: `(string) (len=1) "i",`},
{name: "hunk size 1", options: []Option{WithHunkSize(1)}, wantContext: 2, wantFirst: `(string) (len=1) "i",`},
{name: "hunk size 3", options: []Option{WithHunkSize(3)}, wantContext: 4, wantFirst: `(string) (len=1) "g",`},
{name: "hunk size 5", options: []Option{WithHunkSize(5)}, wantContext: 6, wantFirst: `(string) (len=1) "e",`},
{name: "hunk size 100", options: []Option{WithHunkSize(100)}, wantContext: 11, wantFirst: `([]string) (len=10) {`},
} {
t.Run(toPin.name, func(t *testing.T) {
t.Parallel()

mock := new(capturingT)
a := New(mock, toPin.options...)

if a.Equal(expected, actual) {
t.Fatal("Equal should return false on different values")
}

if !mock.failed {
t.Fatal("Equal should mark the test as failed")
}

if got := countDiffContextLines(mock.message); got != toPin.wantContext {
t.Errorf("expected %d unchanged lines in the diff, got %d in:\n%s",
toPin.wantContext, got, mock.message)
}

if got := firstDiffContextLine(mock.message); got != toPin.wantFirst {
t.Errorf("expected the hunk to start at %q, got %q in:\n%s",
toPin.wantFirst, got, mock.message)
}

if strings.Contains(mock.message, "hunkSize") || strings.Contains(mock.message, "Messages:") {
t.Errorf("expected the option not to leak into the message, got:\n%s", mock.message)
}
})
}

t.Run("the format variant should keep its message", func(t *testing.T) {
t.Parallel()

mock := new(capturingT)
a := New(mock, WithHunkSize(5))

if a.Equalf(expected, actual, "values differ at index %d", 9) {
t.Fatal("Equalf should return false on different values")
}

if !strings.Contains(mock.message, "values differ at index 9") {
t.Errorf("expected the formatted message to be reported, got:\n%s", mock.message)
}

if got := countDiffContextLines(mock.message); got != 6 {
t.Errorf("expected 6 unchanged lines in the diff, got %d in:\n%s", got, mock.message)
}
})
}

// diffLines returns the lines of the "Diff:" section of a failure message, stripped from
// the "\t<padding>\t" indentation that labeledOutput adds to continuation lines.
func diffLines(message string) []string {
_, unified, found := strings.Cut(message, "Diff:\n")
if !found {
return nil
}

var lines []string

for line := range strings.SplitSeq(unified, "\n") {
parts := strings.SplitN(line, "\t", 3)
if len(parts) < 3 {
continue
}

lines = append(lines, parts[2])
}

return lines
}

// countDiffContextLines counts the unchanged lines of the diff, i.e. those prefixed with a space.
func countDiffContextLines(message string) int {
var count int

for _, line := range diffLines(message) {
if strings.HasPrefix(line, " ") && strings.TrimSpace(line) != "" {
count++
}
}

return count
}

// firstDiffContextLine returns the first unchanged line of the diff, which tells how far
// back the hunk reaches.
func firstDiffContextLine(message string) string {
for _, line := range diffLines(message) {
if strings.HasPrefix(line, " ") && strings.TrimSpace(line) != "" {
return strings.TrimSpace(line)
}
}

return ""
}
8 changes: 8 additions & 0 deletions assert/assert_types.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions codegen/internal/generator/doc_generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,9 @@ func (d *DocGenerator) buildMetrics(docsByDomain iter.Seq2[string, model.Documen
var domainMetrics model.DomainMetrics
domainMetrics.Name = doc.Title
for _, fn := range doc.Package.Functions {
if fn.IsExcluded {
continue
}
metrics.Functions++

if fn.IsHelper {
Expand Down
4 changes: 4 additions & 0 deletions codegen/internal/generator/domains/domains.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@ func findDescribedDomains(data *model.AssertionPackage, describedDomains map[str

func discoverDomainsInFunctions(pkg string, data *model.AssertionPackage, discoveredDomains map[string]Entry) {
for _, fn := range data.Functions {
if fn.IsExcluded {
continue
}

domain := fn.Domain
if domain == "" {
entry := discoveredDomains[nodomain]
Expand Down
4 changes: 2 additions & 2 deletions codegen/internal/generator/forward_generics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func TestForwardGenericsAssert(t *testing.T) {
for _, want := range []string{
"//go:build go1.27",
"func (a *Assertions) EqualT[V comparable](expected V, actual V, msgAndArgs ...any) bool {",
"return assertions.EqualT[V](a.T, expected, actual, msgAndArgs...)",
"return assertions.EqualT[V](a.T, expected, actual, append(msgAndArgs, a.o)...)",
"func (a *Assertions) EqualTf[V comparable](expected V, actual V, msg string, args ...any) bool {",
} {
if !strings.Contains(guarded, want) {
Expand Down Expand Up @@ -133,7 +133,7 @@ func TestForwardGenericsRequire(t *testing.T) {
for _, want := range []string{
"//go:build go1.27",
"func (a *Assertions) EqualT[V comparable](expected V, actual V, msgAndArgs ...any) {",
"if assertions.EqualT[V](a.T, expected, actual, msgAndArgs...) {",
"if assertions.EqualT[V](a.T, expected, actual, append(msgAndArgs, a.o)...) {",
"a.T.FailNow()",
} {
if !strings.Contains(guarded, want) {
Expand Down
7 changes: 5 additions & 2 deletions codegen/internal/generator/templates/assertion_format.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,13 @@ func {{ .GenericName "f" }}(t T, {{ params .Params }}, msg string, args ...any)
{{- end }}
{{- if not .BuildConstraint }}{{/* package-level boilerplate belongs only to the default (unguarded) file */}}

func forwardArgs(msg string, args []any) []any {
result := make([]any, len(args)+1)
func forwardArgs(msg string, args []any, extras ...any) []any {
result := make([]any, len(args)+len(extras)+1)
result[0]=msg
copy(result[1:], args)
for i, extra := range extras {
result[len(args)+i+1] = extra
}

return result
}
Expand Down
11 changes: 8 additions & 3 deletions codegen/internal/generator/templates/assertion_forward.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,17 @@ import (
{{ docStringPackage .Package }}
type {{ .Receiver }} struct {
T

o any
}

// New makes a new [{{ .Receiver }}] object for the specified [T] (e.g. [testing.T]).
func New(t T) *{{ .Receiver }} {
//
// It may be tuned using [Option].
func New(t T, opts ...Option) *{{ .Receiver }} {
return &{{ .Receiver }}{
T: t,
o: assertions.BuildOptions(opts),
}
}
{{- end }}
Expand All @@ -35,7 +40,7 @@ func New(t T) *{{ .Receiver }} {
{{ docStringPackage $.Package }}
func (a *{{ $.Receiver }}) {{ .GenericName }}({{ params .Params }}, msgAndArgs ...any) {{ returns .Returns }} {
if h, ok := a.T.(H); ok { h.Helper() }
return {{ .TargetPackage }}.{{ .GenericCallName }}(a.T, {{ forward .Params }}, msgAndArgs...)
return {{ .TargetPackage }}.{{ .GenericCallName }}(a.T, {{ forward .Params }}, append(msgAndArgs, a.o)...)
}
{{- if $.EnableFormat }}

Expand All @@ -44,7 +49,7 @@ func (a *{{ $.Receiver }}) {{ .GenericName }}({{ params .Params }}, msgAndArgs .
{{ docStringPackage $.Package }}
func (a *{{ $.Receiver }}) {{ .GenericName "f" }}({{ params .Params }}, msg string, args ...any) {{ returns .Returns }} {
if h, ok := a.T.(H); ok { h.Helper() }
return {{ .TargetPackage }}.{{ .GenericCallName }}(a.T, {{ forward .Params }}, forwardArgs(msg, args)...)
return {{ .TargetPackage }}.{{ .GenericCallName }}(a.T, {{ forward .Params }}, forwardArgs(msg, args, a.o)...)
}
{{- end }}
{{- end }}
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,13 @@ import (
)
{{- end }}

{{- range .Functions }}
{{- if .IsHelper }}
{{- range .Functions.Scope "only-helpers" . }}

func Test{{ .Name }}f(t *testing.T) {
func Test{{ .Name }}(t *testing.T) {
{{- if (not .HasTest) }}
t.Skip() // this function doesn't have tests yet
{{- else }}
// TODO
{{- end }}
}
{{- end }}
{{- end }}
11 changes: 6 additions & 5 deletions codegen/internal/generator/templates/doc_metrics.md.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ on methods; on go1.26 those two variants per generic assertion are excluded by t

| Kind | Count | Note |
| ------------------------- | ----------------- | ---- |
| All core functions | {{ .Functions }} | Maintained core |
| All core assertions | {{ .Assertions }} | Usage with `*testing.T` |
| Generic assertions | {{ .Generics }} | Type-safe assertions ("T" suffix) |
| Helpers (not assertions) | {{ .Helpers }} | General-purpose utilities, not assertions |
| All core functions | {{ .Functions }} | Maintained core (internal) |
| All core assertions | {{ .Assertions }} | Usage with `*testing.T` (per package) |
| Generic assertions | {{ .Generics }} | Type-safe assertions ("T" suffix) (per package) |
| Helpers (not assertions) | {{ .Helpers }} | General-purpose utilities, not assertions (per package) |
| Others | {{ .Others }} | |
| assert/require variants | {{ .PackageVariants }} | Generated variants |
| Total assertions variants | {{ .TotalVariants }} | Available assertions API |
| Total API surface | {{ .TotalFunctions }} | |
| Constructors | 2 | Builders of Assertion values |
| Total API surface | {{ .TotalFunctions }} | All variants, constructors and helpers over all packages |

{{- end }}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,13 @@ func {{ .GenericName "f" }}(t T, {{ params .Params }}, msg string, args ...any)
{{- end }}
{{- if not .BuildConstraint }}{{/* package-level boilerplate belongs only to the default (unguarded) file */}}

func forwardArgs(msg string, args []any) []any {
result := make([]any, len(args)+1)
func forwardArgs(msg string, args []any, extras ...any) []any {
result := make([]any, len(args)+len(extras)+1)
result[0]=msg
copy(result[1:], args)
for i, extra := range extras {
result[len(args)+i+1] = extra
}

return result
}
Expand Down
Loading
Loading