github.com/richardwilkes/toolbox@v1.121.0/check/check.go (about)

     1  // Copyright (c) 2016-2024 by Richard A. Wilkes. All rights reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the Mozilla Public
     4  // License, version 2.0. If a copy of the MPL was not distributed with
     5  // this file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6  //
     7  // This Source Code Form is "Incompatible With Secondary Licenses", as
     8  // defined by the Mozilla Public License, version 2.0.
     9  
    10  package check
    11  
    12  import (
    13  	"bytes"
    14  	"fmt"
    15  	"reflect"
    16  	"strings"
    17  	"testing"
    18  
    19  	"github.com/richardwilkes/toolbox"
    20  	"github.com/richardwilkes/toolbox/errs"
    21  )
    22  
    23  // Equal compares two values for equality.
    24  func Equal(t *testing.T, expected, actual any, msgAndArgs ...any) {
    25  	t.Helper()
    26  	if !equal(expected, actual) {
    27  		errMsg(t, fmt.Sprintf("Expected %v, got %v", expected, actual), msgAndArgs...)
    28  	}
    29  }
    30  
    31  // NotEqual compares two values for inequality.
    32  func NotEqual(t *testing.T, expected, actual any, msgAndArgs ...any) {
    33  	t.Helper()
    34  	if equal(expected, actual) {
    35  		errMsg(t, fmt.Sprintf("Expected %v to not be %v", expected, actual), msgAndArgs...)
    36  	}
    37  }
    38  
    39  func equal(expected, actual any) bool {
    40  	if expected == nil || actual == nil {
    41  		return expected == actual
    42  	}
    43  	exp, ok := expected.([]byte)
    44  	if !ok {
    45  		return reflect.DeepEqual(expected, actual)
    46  	}
    47  	act, ok2 := actual.([]byte)
    48  	if !ok2 {
    49  		return false
    50  	}
    51  	if exp == nil || act == nil {
    52  		return exp == nil && act == nil
    53  	}
    54  	return bytes.Equal(exp, act)
    55  }
    56  
    57  // Nil expects value to be nil.
    58  func Nil(t *testing.T, value any, msgAndArgs ...any) {
    59  	t.Helper()
    60  	if !toolbox.IsNil(value) {
    61  		errMsg(t, fmt.Sprintf("Expected nil, instead got %v", value), msgAndArgs...)
    62  	}
    63  }
    64  
    65  // NotNil expects value to not be nil.
    66  func NotNil(t *testing.T, value any, msgAndArgs ...any) {
    67  	t.Helper()
    68  	if toolbox.IsNil(value) {
    69  		errMsg(t, "Expected a non-nil value", msgAndArgs...)
    70  	}
    71  }
    72  
    73  // True expects value to be true.
    74  func True(t *testing.T, value bool, msgAndArgs ...any) {
    75  	t.Helper()
    76  	if !value {
    77  		errMsg(t, "Expected true", msgAndArgs...)
    78  	}
    79  }
    80  
    81  // False expects value to be false.
    82  func False(t *testing.T, value bool, msgAndArgs ...any) {
    83  	t.Helper()
    84  	if value {
    85  		errMsg(t, "Expected false", msgAndArgs...)
    86  	}
    87  }
    88  
    89  // Contains expects s to contain substr.
    90  func Contains(t *testing.T, s, substr string, msgAndArgs ...any) {
    91  	t.Helper()
    92  	if !strings.Contains(s, substr) {
    93  		errMsg(t, fmt.Sprintf("Expected string %q to contain %q", s, substr), msgAndArgs...)
    94  	}
    95  }
    96  
    97  // NotContains expects s not to contain substr.
    98  func NotContains(t *testing.T, s, substr string, msgAndArgs ...any) {
    99  	t.Helper()
   100  	if strings.Contains(s, substr) {
   101  		errMsg(t, fmt.Sprintf("Expected string %q not to contain %q", s, substr), msgAndArgs...)
   102  	}
   103  }
   104  
   105  // NoError expects err to be nil.
   106  func NoError(t *testing.T, err error, msgAndArgs ...any) {
   107  	t.Helper()
   108  	if err != nil {
   109  		errMsg(t, fmt.Sprintf("Expected no error, got %v", err), msgAndArgs...)
   110  	}
   111  }
   112  
   113  // Error expects err to not be nil.
   114  func Error(t *testing.T, err error, msgAndArgs ...any) {
   115  	t.Helper()
   116  	if err == nil {
   117  		errMsg(t, "Expected an error", msgAndArgs...)
   118  	}
   119  }
   120  
   121  // Panics expects f to panic when called.
   122  func Panics(t *testing.T, f func(), msgAndArgs ...any) {
   123  	t.Helper()
   124  	if err := doesPanic(f); err == nil {
   125  		errMsg(t, "Expected panic, but got none", msgAndArgs...)
   126  	}
   127  }
   128  
   129  // NotPanics expects no panic when f is called.
   130  func NotPanics(t *testing.T, f func(), msgAndArgs ...any) {
   131  	t.Helper()
   132  	if err := doesPanic(f); err != nil {
   133  		errMsg(t, fmt.Sprintf("Expected no panic, but does: %v", err), msgAndArgs...)
   134  	}
   135  }
   136  
   137  func doesPanic(f func()) (panicErr error) {
   138  	defer errs.Recovery(func(err error) { panicErr = err })
   139  	f()
   140  	return
   141  }
   142  
   143  func errMsg(t *testing.T, prefix string, msgAndArgs ...any) {
   144  	t.Helper()
   145  	var buffer strings.Builder
   146  	buffer.WriteString(prefix)
   147  	switch len(msgAndArgs) {
   148  	case 0:
   149  	case 1:
   150  		_, _ = fmt.Fprintf(&buffer, "; %v", msgAndArgs[0])
   151  	default:
   152  		if s, ok := msgAndArgs[0].(string); ok {
   153  			_, _ = fmt.Fprintf(&buffer, "; "+s, msgAndArgs[1:]...)
   154  		} else {
   155  			buffer.WriteByte(';')
   156  			for _, one := range msgAndArgs {
   157  				_, _ = fmt.Fprintf(&buffer, " %v", one)
   158  			}
   159  		}
   160  	}
   161  	t.Error(buffer.String())
   162  }