github.com/searKing/golang/go@v1.2.117/exp/math/serial_number_arithmetic_test.go (about)

     1  // Copyright 2023 The searKing Author. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package math_test
     6  
     7  import (
     8  	"fmt"
     9  	"testing"
    10  	"testing/quick"
    11  
    12  	math_ "github.com/searKing/golang/go/exp/math"
    13  	"golang.org/x/exp/constraints"
    14  )
    15  
    16  func TestIsNewer(t *testing.T) {
    17  	tests := []struct {
    18  		x, y uint8
    19  		want bool
    20  	}{
    21  		{0, 0, false},
    22  		{0xFF, 0xFF, false},
    23  		{0, 1, false},
    24  		{0xFE, 0xFF, false},
    25  		{0, 0xFF, true},
    26  		{0xFF, 0, false},
    27  		{0, 0x7F, false},
    28  		{0, 0x7E, false},
    29  		{0, 0x80, false},
    30  		{1, 0, true},
    31  		{44, 0, true},
    32  		{100, 0, true},
    33  		{100, 44, true},
    34  		{200, 100, true},
    35  		{255, 200, true},
    36  		{0, 255, true},
    37  		{100, 255, true},
    38  		{0, 200, true},
    39  		{44, 200, true},
    40  		{126, 255, true},
    41  		{127, 255, false},
    42  		{125, 254, true},
    43  		{126, 254, false},
    44  		{58, 25, true},
    45  	}
    46  	for _, tt := range tests {
    47  		t.Run(fmt.Sprintf("math_.IsNewer(%v, %v)", tt.x, tt.y), func(t *testing.T) {
    48  			{
    49  				got := math_.IsNewer(tt.x, tt.y)
    50  				if got != tt.want {
    51  					t.Errorf("math_.IsNewer(%v, %v) = %v, want %v", tt.x, tt.y, got, tt.want)
    52  				}
    53  			}
    54  		})
    55  	}
    56  
    57  	if err := quick.CheckEqual(math_.IsNewer[uint8], checkIsNewer[uint8], nil); err != nil {
    58  		t.Error(err)
    59  	}
    60  }
    61  
    62  func TestIsNewerUint64(t *testing.T) {
    63  	tests := []struct {
    64  		x, y uint64
    65  		want bool
    66  	}{
    67  		{0, 0, false},
    68  		{0xFFFFFFFF, 0xFFFFFFFF, false},
    69  		{0, 1, false},
    70  		{0xFFFFFFFE, 0xFFFFFFFF, false},
    71  		{0, 0xFFFFFFFFFFFFFFFF, true},
    72  		{0xFFFFFFFFFFFFFFFF, 0, false},
    73  		{0, 0x7FFFFFFFFFFFFFFF, false},
    74  		{0, 0x7FFFFFFFFFFFFFFE, false},
    75  		{0, 0x8000000000000000, false},
    76  		{0x7FFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF, true},
    77  		{0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, false},
    78  		{0x7FFFFFFFFFFFFFFD, 0xFFFFFFFFFFFFFFFE, true},
    79  		{0x7FFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFE, false},
    80  	}
    81  	for _, tt := range tests {
    82  		t.Run(fmt.Sprintf("math_.IsNewer(%v, %v)", tt.x, tt.y), func(t *testing.T) {
    83  			{
    84  				got := math_.IsNewer(tt.x, tt.y)
    85  				if got != tt.want {
    86  					t.Errorf("math_.IsNewer(%v, %v) = %v, want %v", tt.x, tt.y, got, tt.want)
    87  				}
    88  			}
    89  		})
    90  	}
    91  }
    92  
    93  func TestDistance(t *testing.T) {
    94  	tests := []struct {
    95  		x, y uint16
    96  		want int16
    97  	}{
    98  		{0, 0, 0},
    99  		{0x7FFF, 0, 32767},
   100  		{0x0001, 0, 1},
   101  		{0x0000, 0, 0},
   102  		{0xFFFF, 0, -1},
   103  		{0xFFFE, 0, -2},
   104  		{0x8000, 0, -32768},
   105  	}
   106  	for _, tt := range tests {
   107  		t.Run(fmt.Sprintf("math_.distance(%v, %v)", tt.x, tt.y), func(t *testing.T) {
   108  			{
   109  				got := int16(distance(tt.x, tt.y))
   110  				if got != tt.want {
   111  					t.Errorf("math_.distance(%v, %v) = %v, want %v", tt.x, tt.y, got, tt.want)
   112  				}
   113  			}
   114  		})
   115  	}
   116  }
   117  
   118  func TestUnwrap(t *testing.T) {
   119  	tests := []struct {
   120  		last  int64
   121  		value uint8
   122  		want  int64
   123  	}{
   124  		{0, 0, 0},
   125  		{255, 255, 255},
   126  		{255, 0, 256},
   127  		{255, 1, 257},
   128  		{126, 255, 255},
   129  		{127, 255, 255},
   130  		{125, 254, 254},
   131  		{126, 254, 254},
   132  		{125, 0, 0},
   133  		{126, 0, 0},
   134  		{127, 0, 0},
   135  		{128, 0, 0},
   136  		{129, 0, 256},
   137  		{256, 0, 256},
   138  		{257, 0, 256},
   139  		{255, 0, 256},
   140  		{256, 0, 256},
   141  		{256, 1, 257},
   142  		{256, 2, 258},
   143  		{256, 3, 259},
   144  		{512, 0, 512},
   145  		{512, 1, 513},
   146  		{512, 2, 514},
   147  		{512, 3, 515},
   148  	}
   149  	for _, tt := range tests {
   150  		t.Run(fmt.Sprintf("math_.Unwrap(%v, %v)", tt.last, tt.value), func(t *testing.T) {
   151  			{
   152  				got := math_.Unwrap(tt.last, tt.value)
   153  				var u = math_.Unwrapper[uint8]{}
   154  				u.UpdateLast(tt.last)
   155  				got = u.Unwrap(tt.value)
   156  				if got != tt.want {
   157  					t.Errorf("math_.Unwrap(%v, %v) = %v, want %v", tt.last, tt.value, got, tt.want)
   158  				}
   159  			}
   160  		})
   161  	}
   162  	if err := quick.CheckEqual(math_.Unwrap[uint8], func(lastValue int64, value uint8) int64 {
   163  		var u = math_.Unwrapper[uint8]{}
   164  		u.UpdateLast(lastValue)
   165  		return u.Unwrap(value)
   166  	}, nil); err != nil {
   167  		t.Error(err)
   168  	}
   169  }
   170  
   171  // IsNewer implements RFC 1982: Serial Number Arithmetic
   172  // See also: https://datatracker.ietf.org/doc/html/rfc1982#section-2
   173  // s1 < s2 and (s1 + 1) > (s2 + 1)
   174  // See also: https://chromium.googlesource.com/external/webrtc/trunk/webrtc/+/f54860e9ef0b68e182a01edc994626d21961bc4b/modules/include/module_common_types.h
   175  func checkIsNewer[T constraints.Unsigned](value T, preValue T) (newer bool) {
   176  	// kBreakpoint is the half-way mark for the type U. For instance, for a
   177  	// uint16_t it will be 0x8000, and for a uint32_t, it will be 0x8000000.
   178  	kBreakpoint := (math_.MaxInt[T]() >> 1) + 1
   179  	// Distinguish between elements that are exactly kBreakpoint apart.
   180  	// If t1>t2 and |t1-t2| = kBreakpoint: IsNewer(t1,t2)=true,
   181  	// IsNewer(t2,t1)=false
   182  	// rather than having IsNewer(t1,t2) = IsNewer(t2,t1) = false.
   183  	if value-preValue == kBreakpoint {
   184  		return value > preValue
   185  	}
   186  	return (value != preValue) && (T(distance(value, preValue)) < kBreakpoint)
   187  }
   188  
   189  // distance = (signed)(i1 - i2)
   190  // If distance is 0, the numbers are equal.
   191  // If it is < 0, then s1 is "less than" or "before" s2.
   192  // Simple, clean and efficient, and fully defined. However, not without surprises.
   193  func distance[T constraints.Unsigned](s1, s2 T) int64 {
   194  	return int64(s1) - int64(s2)
   195  }