@@ -3,6 +3,7 @@ package tests
33import (
44 "cmp"
55 "fmt"
6+ "math"
67 "math/bits"
78 "math/rand"
89 "runtime"
@@ -203,43 +204,111 @@ func Test_32BitEnvironment(t *testing.T) {
203204 }
204205}
205206
206- // checkMinMax is a helper for Test_MinMax that checks the builtin min and max methods.
207- // The x value must be less than y.
208- func checkMinMax [T cmp.Ordered ](t * testing.T , x , y T ) {
207+ // checkMinMax2 is a helper for Test_MinMax that checks the builtin min
208+ // and max methods. The x value must be less than y.
209+ func checkMinMax2 [T cmp.Ordered ](t * testing.T , x , y T ) {
209210 t .Helper ()
210- if got , want := min (x , y ), x ; got != want {
211- t .Errorf ("min[%T](x, y): got: %v, want: %v" , x , got , want )
211+ check := func (a , b T ) {
212+ if got , want := min (a , b ), x ; got != want {
213+ t .Errorf ("min[%T](%v, %v): got: %v, want: %v" , want , a , b , got , want )
214+ }
215+ if got , want := max (a , b ), y ; got != want {
216+ t .Errorf ("max[%T](%v, %v): got: %v, want: %v" , want , a , b , got , want )
217+ }
212218 }
213- if got , want := min (y , x ), x ; got != want {
214- t .Errorf ("min[%T](y, x): got: %v, want: %v" , x , got , want )
219+ check (x , y )
220+ check (y , x )
221+ }
222+
223+ // checkMinMax4 is a helper for Test_MinMax that checks the builtin min
224+ // and max methods. The builtin min and max are not actually veriadic,
225+ // so cannot be tested via `min(first, rest...)`, but they do allow 1 or more
226+ // arguments, so this one checks 4 arguments. v1 must be the actual min,
227+ // and v4 must be the actual max.
228+ func checkMinMax4 [T cmp.Ordered ](t * testing.T , v1 , v2 , v3 , v4 T ) {
229+ t .Helper ()
230+ check := func (a , b , c , d T ) {
231+ if got , want := min (a , b , c , d ), v1 ; got != want {
232+ t .Errorf ("min[%T](%v, %v, %v, %v): got: %v, want: %v" , want , a , b , c , d , got , want )
233+ }
234+ if got , want := max (a , b , c , d ), v4 ; got != want {
235+ t .Errorf ("max[%T](%v, %v, %v, %v): got: %v, want: %v" , want , a , b , c , d , got , want )
236+ }
215237 }
216- if got , want := max (x , y ), y ; got != want {
217- t .Errorf ("max[%T](x, y): got: %v, want: %v" , x , got , want )
238+ check (v1 , v2 , v3 , v4 )
239+ check (v1 , v2 , v4 , v3 )
240+ check (v1 , v4 , v2 , v3 )
241+ check (v1 , v4 , v3 , v2 )
242+ check (v2 , v1 , v3 , v4 )
243+ check (v2 , v1 , v4 , v3 )
244+ check (v2 , v4 , v1 , v3 )
245+ check (v2 , v4 , v3 , v1 )
246+ check (v3 , v1 , v2 , v4 )
247+ check (v3 , v1 , v4 , v2 )
248+ check (v3 , v4 , v1 , v2 )
249+ check (v3 , v4 , v2 , v1 )
250+ check (v4 , v1 , v2 , v3 )
251+ check (v4 , v1 , v3 , v2 )
252+ check (v4 , v3 , v1 , v2 )
253+ check (v4 , v3 , v2 , v1 )
254+ }
255+
256+ // checkMinMax1 is a helper for Test_MinMax that checks the builtin min
257+ // and max methods. This checks the edge case with 1 argument.
258+ func checkMinMax1 [T cmp.Ordered ](t * testing.T , x T ) {
259+ t .Helper ()
260+ if got := min (x ); got != x {
261+ t .Errorf ("min[%T](%v): got: %v, want: %v" , x , x , got , x )
218262 }
219- if got , want := max (y , x ), y ; got != want {
220- t .Errorf ("max[%T](y, x ): got: %v, want: %v" , x , got , want )
263+ if got := max (x ) ; got != x {
264+ t .Errorf ("max[%T](%v ): got: %v, want: %v" , x , x , got , x )
221265 }
222266}
223267
224268func Test_MinMax (t * testing.T ) {
225- checkMinMax (t , 0 , 1 ) // int
226- checkMinMax (t , - 1 , 0 ) // int
227- checkMinMax (t , 12 , 42 ) // int
228- checkMinMax (t , - 42 , - 12 ) // int
229- checkMinMax [int8 ](t , - 9 , 13 )
230- checkMinMax [int16 ](t , 0 , 23 )
231- checkMinMax [int32 ](t , - 87 , 1234 )
232- checkMinMax [int64 ](t , - 0xDEAD_BEEF , 0x7FFF_FFFF_FFFF_FFFF )
233- checkMinMax [uint8 ](t , 9 , 13 )
234- checkMinMax [uint16 ](t , 0 , 23 )
235- checkMinMax [uint32 ](t , 87 , 1234 )
236- checkMinMax [uint64 ](t , 0xDEAD_BEEF , 0x7FFF_FFFF_FFFF_FFFF )
237- checkMinMax [uintptr ](t , 12345 , 54321 )
238- checkMinMax [float32 ](t , 1.41421356237 , 3.14159265359 )
239- checkMinMax (t , - 3.14159265359 , 1.41421356237 ) // float64
240- checkMinMax (t , `` , `a` ) // string
241- checkMinMax (t , `a` , `z` ) // string
242- checkMinMax (t , `a` , `aa` ) // string
243- checkMinMax (t , `banana` , `cat` ) // string
244- checkMinMax (t , `Dog` , `dog` ) // string
269+ checkMinMax2 (t , 0 , 1 ) // int
270+ checkMinMax2 (t , - 1 , 0 ) // int
271+ checkMinMax2 (t , 12 , 42 ) // int
272+ checkMinMax2 (t , - 42 , - 12 ) // int
273+ checkMinMax2 [int8 ](t , - 9 , 13 )
274+ checkMinMax2 [int16 ](t , 0 , 23 )
275+ checkMinMax2 [int32 ](t , - 87 , 1234 )
276+ checkMinMax2 [int64 ](t , - 0xDEAD_BEEF , 0x7FFF_FFFF_FFFF_FFFF )
277+ checkMinMax2 [uint8 ](t , 9 , 13 )
278+ checkMinMax2 [uint16 ](t , 0 , 23 )
279+ checkMinMax2 [uint32 ](t , 87 , 1234 )
280+ checkMinMax2 [uint64 ](t , 0xDEAD_BEEF , 0x7FFF_FFFF_FFFF_FFFF )
281+ checkMinMax2 [uintptr ](t , 12345 , 54321 )
282+ checkMinMax2 [float32 ](t , 1.41421356237 , 3.14159265359 )
283+ checkMinMax2 (t , - 3.14159265359 , 1.41421356237 ) // float64
284+ checkMinMax2 (t , `` , `a` ) // string
285+ checkMinMax2 (t , `a` , `z` ) // string
286+ checkMinMax2 (t , `a` , `aa` ) // string
287+ checkMinMax2 (t , `banana` , `cat` ) // string
288+ checkMinMax2 (t , `Dog` , `dog` ) // string
289+
290+ checkMinMax4 (t , - 4 , - 3 , - 2 , - 1 ) // int
291+ checkMinMax4 (t , 1 , 2 , 3 , 4 ) // int
292+ checkMinMax4 [int64 ](t , - 4 , - 3 , - 2 , - 1 )
293+ checkMinMax4 [int64 ](t , 1 , 2 , 3 , 4 )
294+ checkMinMax4 [uint64 ](t , 1 , 2 , 3 , 4 )
295+ checkMinMax4 (t , `apple` , `banana` , `carrot` , `durian` ) // string
296+
297+ checkMinMax1 (t , 1 ) // int
298+ checkMinMax1 [int64 ](t , - 19 )
299+ checkMinMax1 [uint64 ](t , 244 )
300+ checkMinMax1 (t , 2.3 ) // float64
301+ checkMinMax1 (t , `Ludo` ) // string
302+
303+ // Note that math.Min and math.Max act differently for NaN than max and min,
304+ // see [https://github.com/golang/go/issues/60616]
305+ // Fortunelty the builtin max and min act like JS's Math.max and Math.min,
306+ // see [https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/min]
307+ // If any argument is NaN, then NaN will be returned.
308+ if got := min (42 , math .NaN (), - 81 ); ! math .IsNaN (got ) {
309+ t .Errorf ("min(..NaN..): got: %v, want: %v" , got , math .NaN ())
310+ }
311+ if got := max (42 , math .NaN (), - 81 ); ! math .IsNaN (got ) {
312+ t .Errorf ("max(..NaN..): got: %v, want: %v" , got , math .NaN ())
313+ }
245314}
0 commit comments