@@ -3,8 +3,9 @@ package overflow_test
33import (
44 "math"
55 "testing"
6+
7+ "github.com/g-utils/overflow"
68)
7- import "github.com/g-utils/overflow"
89
910// sample all possibilities of 8 bit numbers
1011// by checking against 64 bit numbers
@@ -287,3 +288,152 @@ func TestAlgorithmsUintImpl2(t *testing.T) {
287288 }
288289
289290}
291+
292+ func TestConvert (t * testing.T ) {
293+ // int8 | int16 | int32 | int64 | uint8 | uint16 | uint32 | uint64
294+
295+ t .Run ("positive: uint64->unsigned" , func (t * testing.T ) {
296+ t .Parallel ()
297+ for i := uint64 (0 ); i <= math .MaxUint8 ; i ++ {
298+ testConvert4 [uint64 , uint64 , uint32 , uint16 , uint8 ](t , i , true )
299+ }
300+ testConvert3 [uint64 , uint64 , uint32 , uint16 ](t , math .MaxUint16 - 1 , true )
301+ testConvert3 [uint64 , uint64 , uint32 , uint16 ](t , math .MaxUint16 , true )
302+ testConvert2 [uint64 , uint64 , uint32 ](t , math .MaxUint32 - 1 , true )
303+ testConvert2 [uint64 , uint64 , uint32 ](t , math .MaxUint32 , true )
304+ testConvert1 [uint64 , uint64 ](t , math .MaxUint64 - 1 , true )
305+ testConvert1 [uint64 , uint64 ](t , math .MaxUint64 , true )
306+ })
307+
308+ t .Run ("negative: uint64->unsigned" , func (t * testing.T ) {
309+ for i := uint64 (math .MaxUint32 + 1 ); i <= uint64 (math .MaxUint32 + math .MaxUint8 + 1 ); i ++ {
310+ testConvert3 [uint64 , uint32 , uint16 , uint8 ](t , i , false )
311+ }
312+ testConvert2 [uint64 , uint16 , uint8 ](t , math .MaxUint16 + 1 , false )
313+ testConvert1 [uint64 , uint8 ](t , math .MaxUint8 + 1 , false )
314+ })
315+
316+ t .Run ("positive: uint64->signed" , func (t * testing.T ) {
317+ for i := uint64 (0 ); i <= math .MaxInt8 ; i ++ {
318+ testConvert4 [uint64 , int64 , int32 , int16 , int8 ](t , i , true )
319+ }
320+ testConvert3 [uint64 , int64 , int32 , int16 ](t , math .MaxInt16 - 1 , true )
321+ testConvert3 [uint64 , int64 , int32 , int16 ](t , math .MaxInt16 , true )
322+ testConvert2 [uint64 , int64 , int32 ](t , math .MaxInt32 - 1 , true )
323+ testConvert2 [uint64 , int64 , int32 ](t , math .MaxInt32 , true )
324+ testConvert1 [uint64 , int64 ](t , math .MaxInt64 - 1 , true )
325+ testConvert1 [uint64 , int64 ](t , math .MaxInt64 , true )
326+ })
327+
328+ t .Run ("negative: uint64->signed" , func (t * testing.T ) {
329+ for i := uint64 (math .MaxInt64 + 1 ); i <= uint64 (math .MaxInt64 + math .MaxUint8 + 1 ); i ++ {
330+ testConvert4 [uint64 , int64 , int32 , int16 , int8 ](t , i , false )
331+ }
332+ testConvert4 [uint64 , int64 , int32 , int16 , int8 ](t , math .MaxUint64 , false )
333+ testConvert4 [uint64 , int64 , int32 , int16 , int8 ](t , math .MaxUint64 - 1 , false )
334+ testConvert3 [uint64 , int32 , int16 , int8 ](t , math .MaxInt32 + 1 , false )
335+ testConvert2 [uint64 , int16 , int8 ](t , math .MaxInt16 + 1 , false )
336+ testConvert1 [uint64 , int8 ](t , math .MaxInt8 + 1 , false )
337+ })
338+
339+ t .Run ("positive: int64->signed" , func (t * testing.T ) {
340+ for i := int64 (math .MinInt8 ); i <= math .MaxInt8 ; i ++ {
341+ testConvert4 [int64 , int64 , int32 , int16 , int8 ](t , i , true )
342+ }
343+ testConvert3 [int64 , int64 , int32 , int16 ](t , math .MinInt16 , true )
344+ testConvert3 [int64 , int64 , int32 , int16 ](t , math .MinInt16 + 1 , true )
345+ testConvert3 [int64 , int64 , int32 , int16 ](t , math .MaxInt16 - 1 , true )
346+ testConvert3 [int64 , int64 , int32 , int16 ](t , math .MaxInt16 , true )
347+ testConvert2 [int64 , int64 , int32 ](t , math .MinInt32 , true )
348+ testConvert2 [int64 , int64 , int32 ](t , math .MinInt32 + 1 , true )
349+ testConvert2 [int64 , int64 , int32 ](t , math .MaxInt32 - 1 , true )
350+ testConvert2 [int64 , int64 , int32 ](t , math .MaxInt32 , true )
351+ testConvert1 [int64 , int64 ](t , math .MinInt64 , true )
352+ testConvert1 [int64 , int64 ](t , math .MinInt64 + 1 , true )
353+ testConvert1 [int64 , int64 ](t , math .MaxInt64 - 1 , true )
354+ testConvert1 [int64 , int64 ](t , math .MaxInt64 , true )
355+ })
356+
357+ t .Run ("negative: int64->signed" , func (t * testing.T ) {
358+ for i := int64 (math .MaxInt32 + 1 ); i <= int64 (math .MaxInt32 + math .MaxInt8 + 1 ); i ++ {
359+ testConvert3 [int64 , int32 , int16 , int8 ](t , i , false )
360+ }
361+ testConvert2 [int64 , int16 , int8 ](t , math .MaxInt16 + 1 , false )
362+ testConvert1 [int64 , int8 ](t , math .MaxInt8 + 1 , false )
363+ })
364+
365+ t .Run ("positive: int64->unsigned" , func (t * testing.T ) {
366+ for i := int64 (0 ); i <= math .MaxUint8 ; i ++ {
367+ testConvert4 [int64 , uint64 , uint32 , uint16 , uint8 ](t , i , true )
368+ }
369+ testConvert3 [int64 , uint64 , uint32 , uint16 ](t , math .MaxUint16 - 1 , true )
370+ testConvert3 [int64 , uint64 , uint32 , uint16 ](t , math .MaxUint16 , true )
371+ testConvert2 [int64 , uint64 , uint32 ](t , math .MaxUint32 - 1 , true )
372+ testConvert2 [int64 , uint64 , uint32 ](t , math .MaxUint32 , true )
373+ testConvert1 [int64 , uint64 ](t , math .MaxInt64 - 1 , true )
374+ testConvert1 [int64 , uint64 ](t , math .MaxInt64 , true )
375+ })
376+
377+ t .Run ("negative: int64->unsigned" , func (t * testing.T ) {
378+ testConvert4 [int64 , uint64 , uint32 , uint16 , uint8 ](t , math .MinInt64 , false )
379+ testConvert4 [int64 , uint64 , uint32 , uint16 , uint8 ](t , math .MinInt64 + 1 , false )
380+ testConvert4 [int64 , uint64 , uint32 , uint16 , uint8 ](t , - 1 , false )
381+ testConvert3 [int64 , uint32 , uint16 , uint8 ](t , math .MaxUint32 + 1 , false )
382+ testConvert2 [int64 , uint16 , int8 ](t , math .MaxUint16 + 1 , false )
383+ for i := int64 (math .MaxUint8 + 1 ); i <= math .MaxUint8 + math .MaxUint8 + 2 ; i ++ {
384+ testConvert1 [int64 , uint8 ](t , i , false )
385+ }
386+ })
387+
388+ t .Run ("negative: int32|16|8->uint64" , func (t * testing.T ) {
389+ testConvert1 [int32 , uint64 ](t , - 1 , false )
390+ testConvert1 [int32 , uint64 ](t , math .MinInt32 , false )
391+ testConvert1 [int16 , uint64 ](t , - 1 , false )
392+ testConvert1 [int16 , uint64 ](t , math .MinInt16 , false )
393+ testConvert1 [int8 , uint64 ](t , - 1 , false )
394+ testConvert1 [int8 , uint64 ](t , math .MinInt8 , false )
395+ })
396+
397+ // already covered by reverse conversion checks:
398+ // - "positive [u]int32|16|8 -> [u]int64"
399+
400+ // impossible cases:
401+ // "negative uint32|16|8 -> [u]int64"
402+ // "negative [u]int32|16|8 -> int64"
403+ }
404+
405+ func testConvert4 [T overflow.Int , U1 overflow.Int , U2 overflow.Int , U3 overflow.Int , U4 overflow.Int ](t * testing.T , a T , expectOk bool ) {
406+ t .Helper ()
407+ testConvert2 [T , U1 , U2 ](t , a , expectOk )
408+ testConvert2 [T , U3 , U4 ](t , a , expectOk )
409+ }
410+
411+ func testConvert3 [T overflow.Int , U1 overflow.Int , U2 overflow.Int , U3 overflow.Int ](t * testing.T , a T , expectOk bool ) {
412+ t .Helper ()
413+ testConvert1 [T , U1 ](t , a , expectOk )
414+ testConvert1 [T , U2 ](t , a , expectOk )
415+ testConvert1 [T , U3 ](t , a , expectOk )
416+ }
417+
418+ func testConvert2 [T overflow.Int , U1 overflow.Int , U2 overflow.Int ](t * testing.T , a T , expectOk bool ) {
419+ t .Helper ()
420+ testConvert1 [T , U1 ](t , a , expectOk )
421+ testConvert1 [T , U2 ](t , a , expectOk )
422+ }
423+
424+ func testConvert1 [T overflow.Int , U overflow.Int ](t * testing.T , a T , expectOk bool ) {
425+ t .Helper ()
426+ if b , ok := overflow.Convert [T , U ](a ); expectOk && ! ok {
427+ t .Error ("expected ok, got overflow: " , b )
428+ } else if ! expectOk && ok {
429+ t .Error ("expected overflow, got ok: " , b )
430+ } else if a2 , ok2 := overflow.Convert [U , T ](b ); ok && ! ok2 {
431+ t .Error ("expected ok, got ok, but reverse conversion overflowed: " , a2 )
432+ }
433+ }
434+
435+ func BenchmarkConvert (b * testing.B ) {
436+ for i := int64 (- 1_000_000_000 ); i < 1_000_000_000 ; i ++ {
437+ _ , _ = overflow.Convert [int64 , uint64 ](i )
438+ }
439+ }
0 commit comments