Source file src/cmp/cmp_test.go

     1  // Copyright 2023 The Go Authors. 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 cmp_test
     6  
     7  import (
     8  	"cmp"
     9  	"fmt"
    10  	"math"
    11  	"slices"
    12  	"sort"
    13  	"testing"
    14  	"unsafe"
    15  )
    16  
    17  var negzero = math.Copysign(0, -1)
    18  var nonnilptr uintptr = uintptr(unsafe.Pointer(&negzero))
    19  var nilptr uintptr = uintptr(unsafe.Pointer(nil))
    20  
    21  var tests = []struct {
    22  	x, y    any
    23  	compare int
    24  }{
    25  	{1, 2, -1},
    26  	{1, 1, 0},
    27  	{2, 1, +1},
    28  	{"a", "aa", -1},
    29  	{"a", "a", 0},
    30  	{"aa", "a", +1},
    31  	{1.0, 1.1, -1},
    32  	{1.1, 1.1, 0},
    33  	{1.1, 1.0, +1},
    34  	{math.Inf(1), math.Inf(1), 0},
    35  	{math.Inf(-1), math.Inf(-1), 0},
    36  	{math.Inf(-1), 1.0, -1},
    37  	{1.0, math.Inf(-1), +1},
    38  	{math.Inf(1), 1.0, +1},
    39  	{1.0, math.Inf(1), -1},
    40  	{math.NaN(), math.NaN(), 0},
    41  	{0.0, math.NaN(), +1},
    42  	{math.NaN(), 0.0, -1},
    43  	{math.NaN(), math.Inf(-1), -1},
    44  	{math.Inf(-1), math.NaN(), +1},
    45  	{0.0, 0.0, 0},
    46  	{negzero, negzero, 0},
    47  	{negzero, 0.0, 0},
    48  	{0.0, negzero, 0},
    49  	{negzero, 1.0, -1},
    50  	{negzero, -1.0, +1},
    51  	{nilptr, nonnilptr, -1},
    52  	{nonnilptr, nilptr, 1},
    53  	{nonnilptr, nonnilptr, 0},
    54  }
    55  
    56  func TestLess(t *testing.T) {
    57  	for _, test := range tests {
    58  		var b bool
    59  		switch test.x.(type) {
    60  		case int:
    61  			b = cmp.Less(test.x.(int), test.y.(int))
    62  		case string:
    63  			b = cmp.Less(test.x.(string), test.y.(string))
    64  		case float64:
    65  			b = cmp.Less(test.x.(float64), test.y.(float64))
    66  		case uintptr:
    67  			b = cmp.Less(test.x.(uintptr), test.y.(uintptr))
    68  		}
    69  		if b != (test.compare < 0) {
    70  			t.Errorf("Less(%v, %v) == %t, want %t", test.x, test.y, b, test.compare < 0)
    71  		}
    72  	}
    73  }
    74  
    75  func TestCompare(t *testing.T) {
    76  	for _, test := range tests {
    77  		var c int
    78  		switch test.x.(type) {
    79  		case int:
    80  			c = cmp.Compare(test.x.(int), test.y.(int))
    81  		case string:
    82  			c = cmp.Compare(test.x.(string), test.y.(string))
    83  		case float64:
    84  			c = cmp.Compare(test.x.(float64), test.y.(float64))
    85  		case uintptr:
    86  			c = cmp.Compare(test.x.(uintptr), test.y.(uintptr))
    87  		}
    88  		if c != test.compare {
    89  			t.Errorf("Compare(%v, %v) == %d, want %d", test.x, test.y, c, test.compare)
    90  		}
    91  	}
    92  }
    93  
    94  func TestSort(t *testing.T) {
    95  	// Test that our comparison function is consistent with
    96  	// sort.Float64s.
    97  	input := []float64{1.0, 0.0, negzero, math.Inf(1), math.Inf(-1), math.NaN()}
    98  	sort.Float64s(input)
    99  	for i := 0; i < len(input)-1; i++ {
   100  		if cmp.Less(input[i+1], input[i]) {
   101  			t.Errorf("Less sort mismatch at %d in %v", i, input)
   102  		}
   103  		if cmp.Compare(input[i], input[i+1]) > 0 {
   104  			t.Errorf("Compare sort mismatch at %d in %v", i, input)
   105  		}
   106  	}
   107  }
   108  
   109  func TestOr(t *testing.T) {
   110  	cases := []struct {
   111  		in   []int
   112  		want int
   113  	}{
   114  		{nil, 0},
   115  		{[]int{0}, 0},
   116  		{[]int{1}, 1},
   117  		{[]int{0, 2}, 2},
   118  		{[]int{3, 0}, 3},
   119  		{[]int{4, 5}, 4},
   120  		{[]int{0, 6, 7}, 6},
   121  	}
   122  	for _, tc := range cases {
   123  		if got := cmp.Or(tc.in...); got != tc.want {
   124  			t.Errorf("cmp.Or(%v) = %v; want %v", tc.in, got, tc.want)
   125  		}
   126  	}
   127  }
   128  
   129  func ExampleOr() {
   130  	// Suppose we have some user input
   131  	// that may or may not be an empty string
   132  	userInput1 := ""
   133  	userInput2 := "some text"
   134  
   135  	fmt.Println(cmp.Or(userInput1, "default"))
   136  	fmt.Println(cmp.Or(userInput2, "default"))
   137  	fmt.Println(cmp.Or(userInput1, userInput2, "default"))
   138  	// Output:
   139  	// default
   140  	// some text
   141  	// some text
   142  }
   143  
   144  func ExampleOr_sort() {
   145  	type Order struct {
   146  		Product  string
   147  		Customer string
   148  		Price    float64
   149  	}
   150  	orders := []Order{
   151  		{"foo", "alice", 1.00},
   152  		{"bar", "bob", 3.00},
   153  		{"baz", "carol", 4.00},
   154  		{"foo", "alice", 2.00},
   155  		{"bar", "carol", 1.00},
   156  		{"foo", "bob", 4.00},
   157  	}
   158  	// Sort by customer first, product second, and last by higher price
   159  	slices.SortFunc(orders, func(a, b Order) int {
   160  		return cmp.Or(
   161  			cmp.Compare(a.Customer, b.Customer),
   162  			cmp.Compare(a.Product, b.Product),
   163  			cmp.Compare(b.Price, a.Price),
   164  		)
   165  	})
   166  	for _, order := range orders {
   167  		fmt.Printf("%s %s %.2f\n", order.Product, order.Customer, order.Price)
   168  	}
   169  
   170  	// Output:
   171  	// foo alice 2.00
   172  	// foo alice 1.00
   173  	// bar bob 3.00
   174  	// foo bob 4.00
   175  	// bar carol 1.00
   176  	// baz carol 4.00
   177  }
   178  

View as plain text