From 3915cf2dda0e591acf84d2ef7419476ceea72b05 Mon Sep 17 00:00:00 2001 From: djmil Date: Thu, 11 Jun 2026 19:10:08 +0000 Subject: [PATCH] pkg/check: NotEqual, DeepEqual, ElementsMatch --- pkg/check/check.go | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/pkg/check/check.go b/pkg/check/check.go index 0f4bdbb..6f6e798 100644 --- a/pkg/check/check.go +++ b/pkg/check/check.go @@ -9,6 +9,7 @@ package check import ( + "reflect" "strings" "testing" @@ -71,6 +72,44 @@ func Equal[T comparable](t *testing.T, got, want T) { } } +// NotEqual fails the test if got == want. +func NotEqual[T comparable](t *testing.T, got, want T) { + t.Helper() + if got == want { + t.Errorf("expected values to differ, got %v", got) + } +} + +// DeepEqual fails the test if got and want are not deeply equal. +// Use instead of Equal for maps, slices, and structs with slice fields. +func DeepEqual(t *testing.T, got, want any) { + t.Helper() + if !reflect.DeepEqual(got, want) { + t.Errorf("got %v, want %v", got, want) + } +} + +// ElementsMatch fails the test if got and want do not contain the same +// elements regardless of order, including duplicates. T must be comparable — +// for slices or maps as elements, use DeepEqual after sorting manually. +func ElementsMatch[T comparable](t *testing.T, got, want []T) { + t.Helper() + if len(got) != len(want) { + t.Errorf("length mismatch: got %d elements, want %d", len(got), len(want)) + return + } + freq := make(map[T]int, len(want)) + for _, v := range want { + freq[v]++ + } + for _, v := range got { + if freq[v]--; freq[v] < 0 { + t.Errorf("unexpected element: %v", v) + return + } + } +} + // Ok fails the test if r holds an error, then returns the value. func Ok[T any](t *testing.T, r result.Expect[T]) T { t.Helper()