Repository: MarvinJWendt/testza
Pull request #158 (2022-04-10 13:23:35)

Added `AssertUnique` and `AssertNotUnique`


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e096745..5bd5d07 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,9 @@
 ## [Unreleased]
 
 
+<a name="v0.4.0"></a>
+## [v0.4.0] - 2022-04-10
+
 <a name="v0.3.5"></a>
 ## [v0.3.5] - 2022-04-07
 
@@ -304,7 +307,8 @@ Functions have a new structure.
 - **internal:** rewrite `Fail` for a nicer output
 
 
-[Unreleased]: https://github.com/MarvinJWendt/testza/compare/v0.3.5...HEAD
+[Unreleased]: https://github.com/MarvinJWendt/testza/compare/v0.4.0...HEAD
+[v0.4.0]: https://github.com/MarvinJWendt/testza/compare/v0.3.5...v0.4.0
 [v0.3.5]: https://github.com/MarvinJWendt/testza/compare/v0.3.4...v0.3.5
 [v0.3.4]: https://github.com/MarvinJWendt/testza/compare/v0.3.3...v0.3.4
 [v0.3.3]: https://github.com/MarvinJWendt/testza/compare/v0.3.2...v0.3.3
diff --git a/README.md b/README.md
index 3b80893..7eb994c 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@
 </a>
 
 <a href="https://codecov.io/gh/MarvinJWendt/testza">
-<!-- unittestcount:start --><img src="https://img.shields.io/badge/Unit_Tests-2979-magenta?style=flat-square" alt="Unit test count"><!-- unittestcount:end -->
+<!-- unittestcount:start --><img src="https://img.shields.io/badge/Unit_Tests-2995-magenta?style=flat-square" alt="Unit test count"><!-- unittestcount:end -->
 </a>
   
 <a href="https://pkg.go.dev/github.com/MarvinJWendt/testza" target="_blank">
@@ -192,6 +192,7 @@ testza.FuzzStringRunTests(t, emailAddresses, func(t *testing.T, index int, str s
   - [AssertNotPanics](https://github.com/MarvinJWendt/testza#AssertNotPanics)
   - [AssertNotRegexp](https://github.com/MarvinJWendt/testza#AssertNotRegexp)
   - [AssertNotSameElements](https://github.com/MarvinJWendt/testza#AssertNotSameElements)
+  - [AssertNotUnique](https://github.com/MarvinJWendt/testza#AssertNotUnique)
   - [AssertNotZero](https://github.com/MarvinJWendt/testza#AssertNotZero)
   - [AssertNumeric](https://github.com/MarvinJWendt/testza#AssertNumeric)
   - [AssertPanics](https://github.com/MarvinJWendt/testza#AssertPanics)
@@ -200,6 +201,7 @@ testza.FuzzStringRunTests(t, emailAddresses, func(t *testing.T, index int, str s
   - [AssertSubset](https://github.com/MarvinJWendt/testza#AssertSubset)
   - [AssertTestFails](https://github.com/MarvinJWendt/testza#AssertTestFails)
   - [AssertTrue](https://github.com/MarvinJWendt/testza#AssertTrue)
+  - [AssertUnique](https://github.com/MarvinJWendt/testza#AssertUnique)
   - [AssertZero](https://github.com/MarvinJWendt/testza#AssertZero)
 </td>
 
@@ -228,6 +230,7 @@ testza.FuzzStringRunTests(t, emailAddresses, func(t *testing.T, index int, str s
 <details>
 <summary>Click to expand</summary>
 
+  - [FuzzUtilDistinctSet](https://github.com/MarvinJWendt/testza#FuzzUtilDistinctSet)
   - [FuzzUtilLimitSet](https://github.com/MarvinJWendt/testza#FuzzUtilLimitSet)
   - [FuzzUtilModifySet](https://github.com/MarvinJWendt/testza#FuzzUtilModifySet)
   - [FuzzUtilRunTests](https://github.com/MarvinJWendt/testza#FuzzUtilRunTests)
@@ -975,6 +978,21 @@ Example:
      }
      testza.AssertNotSameElements(t, []*A{{a: "A"}, {a: "B"}, {a: "C"}}, []*A{{a: "A"}, {a: "B"}, {a: "C"}, {a: "D"}})
 
+#### AssertNotUnique
+
+```go
+func AssertNotUnique[elementType comparable](t testRunner, list []elementType, msg ...any)
+```
+
+AssertNotUnique asserts that the elements in a list are not unique.
+
+When using a custom message, the same formatting as with fmt.Sprintf() is
+used.
+
+Example:
+
+    testza.AssertNotUnique(t, []int{1, 2, 3, 3})
+
 #### AssertNotZero
 
 ```go
@@ -1126,6 +1144,23 @@ Example:
     testza.AssertTrue(t, 2 != 3)
     testza.AssertTrue(t, 1 > 0 && 4 < 5)
 
+#### AssertUnique
+
+```go
+func AssertUnique[elementType comparable](t testRunner, list []elementType, msg ...any)
+```
+
+AssertUnique asserts that the list contains only unique elements. The order
+is irrelevant.
+
+When using a custom message, the same formatting as with fmt.Sprintf() is
+used.
+
+Example:
+
+    testza.AssertUnique(t, []int{1, 2, 3})
+    testza.AssertUnique(t, []string{"Hello", "World", "!"})
+
 #### AssertZero
 
 ```go
@@ -1383,6 +1418,19 @@ FuzzStringUsernames returns a test set with usernames.
 
 ### Fuzz Utils
 
+#### FuzzUtilDistinctSet
+
+```go
+func FuzzUtilDistinctSet[setType comparable](testSet []setType) []setType
+```
+
+FuzzUtilDistinctSet returns a set with removed duplicates.
+
+Example:
+
+    uniqueSet := testza.FuzzUtilDistinctSet([]string{"A", "C", "A", "B", "A", "B", "C"})
+    // uniqueSet => []string{"A", "C", "B"}
+
 #### FuzzUtilLimitSet
 
 ```go
diff --git a/assert.go b/assert.go
index ef231a3..dbcb0d4 100644
--- a/assert.go
+++ b/assert.go
@@ -1005,3 +1005,37 @@ func AssertNoSubset(t testRunner, list any, subset any, msg ...any) {
 		internal.Fail(t, "The second parameter !!is a subset of the list!!, but should not be.", internal.Objects{internal.NewObjectsSingleNamed("List", list)[0], internal.NewObjectsSingleNamed("Subset", subset)[0]}, msg...)
 	}
 }
+
+// AssertUnique asserts that the list contains only unique elements.
+// The order is irrelevant.
+//
+// When using a custom message, the same formatting as with fmt.Sprintf() is used.
+//
+// Example:
+//  testza.AssertUnique(t, []int{1, 2, 3})
+//  testza.AssertUnique(t, []string{"Hello", "World", "!"})
+func AssertUnique[elementType comparable](t testRunner, list []elementType, msg ...any) {
+	if test, ok := t.(helper); ok {
+		test.Helper()
+	}
+
+	if len(FuzzUtilDistinctSet(list)) != len(list) {
+		internal.Fail(t, "The list is !!not unique!!.", internal.NewObjectsSingleNamed("List", list), msg...)
+	}
+}
+
+// AssertNotUnique asserts that the elements in a list are not unique.
+//
+// When using a custom message, the same formatting as with fmt.Sprintf() is used.
+//
+// Example:
+//  testza.AssertNotUnique(t, []int{1, 2, 3, 3})
+func AssertNotUnique[elementType comparable](t testRunner, list []elementType, msg ...any) {
+	if test, ok := t.(helper); ok {
+		test.Helper()
+	}
+
+	if len(FuzzUtilDistinctSet(list)) == len(list) {
+		internal.Fail(t, "The list !!is unique!!, but should not.", internal.NewObjectsSingleNamed("List", list), msg...)
+	}
+}
diff --git a/fuzz-utils.go b/fuzz-utils.go
index 48dd40f..43bd79f 100644
--- a/fuzz-utils.go
+++ b/fuzz-utils.go
@@ -67,3 +67,22 @@ func FuzzUtilLimitSet[setType any](testSet []setType, max int) []setType {
 
 	return testSet[:max]
 }
+
+// FuzzUtilDistinctSet returns a set with removed duplicates.
+//
+// Example:
+//  uniqueSet := testza.FuzzUtilDistinctSet([]string{"A", "C", "A", "B", "A", "B", "C"})
+//  // uniqueSet => []string{"A", "C", "B"}
+func FuzzUtilDistinctSet[setType comparable](testSet []setType) []setType {
+	seen := map[setType]bool{}
+	var result []setType
+
+	for _, v := range testSet {
+		if !seen[v] {
+			seen[v] = true
+			result = append(result, v)
+		}
+	}
+
+	return result
+}


Test patch:
diff --git a/assert_test.go b/assert_test.go
index a187ff5..c19786a 100644
--- a/assert_test.go
+++ b/assert_test.go
@@ -1520,3 +1520,53 @@ Proin puvinar feliss consectetur codiementum tincidunt.`
 		AssertNoError(t, err)
 	})
 }
+
+func TestAssertUnique(t *testing.T) {
+	AssertUnique(t, []int{1, 2, 3, 4, 5})
+	AssertUnique(t, []string{"foo", "bar", "baz"})
+	AssertUnique(t, []bool{true, false})
+	AssertUnique(t, []float64{1.1, 1.2, 1.3, 1.4, 1.5})
+}
+
+func TestAssertUnique_fails(t *testing.T) {
+	AssertTestFails(t, func(t TestingPackageWithFailFunctions) {
+		AssertUnique(t, []int{1, 2, 3, 4, 5, 1})
+	})
+
+	AssertTestFails(t, func(t TestingPackageWithFailFunctions) {
+		AssertUnique(t, []string{"foo", "bar", "baz", "foo"})
+	})
+
+	AssertTestFails(t, func(t TestingPackageWithFailFunctions) {
+		AssertUnique(t, []bool{true, false, true})
+	})
+
+	AssertTestFails(t, func(t TestingPackageWithFailFunctions) {
+		AssertUnique(t, []float64{1.1, 1.2, 1.3, 1.4, 1.5, 1.1})
+	})
+}
+
+func TestAssertNotUnique(t *testing.T) {
+	AssertNotUnique(t, []int{1, 2, 3, 4, 5, 1})
+	AssertNotUnique(t, []string{"foo", "bar", "baz", "foo"})
+	AssertNotUnique(t, []bool{true, false, true})
+	AssertNotUnique(t, []float64{1.1, 1.2, 1.3, 1.4, 1.5, 1.1})
+}
+
+func TestAssertNotUnique_fails(t *testing.T) {
+	AssertTestFails(t, func(t TestingPackageWithFailFunctions) {
+		AssertNotUnique(t, []int{1, 2, 3, 4, 5})
+	})
+
+	AssertTestFails(t, func(t TestingPackageWithFailFunctions) {
+		AssertNotUnique(t, []string{"foo", "bar", "baz"})
+	})
+
+	AssertTestFails(t, func(t TestingPackageWithFailFunctions) {
+		AssertNotUnique(t, []bool{true, false})
+	})
+
+	AssertTestFails(t, func(t TestingPackageWithFailFunctions) {
+		AssertNotUnique(t, []float64{1.1, 1.2, 1.3, 1.4, 1.5})
+	})
+}
diff --git a/fuzz_test.go b/fuzz_test.go
index 6a05cb0..0fabe55 100644
--- a/fuzz_test.go
+++ b/fuzz_test.go
@@ -10,7 +10,7 @@ import (
 )
 
 //region FuzzUtil
-func TestFuzzUtilModify(t *testing.T) {
+func TestFuzzUtilModifySet(t *testing.T) {
 	t.Run("String Slice", func(t *testing.T) {
 		slice := []string{"Hello", "World", "TeSt"}
 		expected := []string{"hello", "world", "test"}
@@ -39,7 +39,7 @@ func TestFuzzUtilModify(t *testing.T) {
 	})
 }
 
-func TestFuzzUtilLimit(t *testing.T) {
+func TestFuzzUtilLimitSet(t *testing.T) {
 	for i := 0; i < 10; i++ {
 		t.Run(fmt.Sprintf("String (Limit=%d)", i), func(t *testing.T) {
 			AssertLen(t, FuzzUtilLimitSet(FuzzStringFull(), i), i)