github.com/keybase/client/go@v0.0.0-20241007131713-f10651d043c8/libkb/util_test.go (about)

     1  // Copyright 2015 Keybase, Inc. All rights reserved. Use of
     2  // this source code is governed by the included BSD license.
     3  
     4  package libkb
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"os"
    10  	"path/filepath"
    11  	"regexp"
    12  	"strings"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/keybase/clockwork"
    17  
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  type cmpTest struct {
    22  	a, b string
    23  	eq   bool
    24  }
    25  
    26  var nameCmpTest = []cmpTest{
    27  	{a: "UpperCase", b: "uppercase", eq: true},
    28  	{a: " Space prefix", b: "Space prefix", eq: true},
    29  	{a: "Space suffix ", b: "Space suffix", eq: true},
    30  	{a: "Space Inside", b: "SpaceInside", eq: true},
    31  	{a: "work iPad", b: "work ipad", eq: true},
    32  	{a: "my_ipad", b: "MY IPAD", eq: true},
    33  	{a: "device a", b: "device b", eq: false},
    34  	{a: "mike's computer", b: "mikes computer", eq: true},
    35  	{a: "my+-'_device", b: "my device", eq: true},
    36  }
    37  
    38  func TestNameCmp(t *testing.T) {
    39  	for _, test := range nameCmpTest {
    40  		eq := NameCmp(test.a, test.b)
    41  		if eq != test.eq {
    42  			t.Errorf("name compare %q == %q => %v, expected %v", test.a, test.b, eq, test.eq)
    43  		}
    44  	}
    45  }
    46  
    47  func TestCombineErrors(t *testing.T) {
    48  	err := CombineErrors(fmt.Errorf("error1"), nil, fmt.Errorf("error3"))
    49  	expected := "There were multiple errors: error1; error3"
    50  	if err.Error() != expected {
    51  		t.Errorf("Wrong output for combine errors: %#v != %#v", err.Error(), expected)
    52  	}
    53  }
    54  
    55  func TestWhitespaceNormalize(t *testing.T) {
    56  
    57  	data := []struct {
    58  		in, out string
    59  	}{
    60  		{" ab   cd    ef   gh ", "ab cd ef gh"},
    61  		{"a\nb  c\nd", "a b c d"},
    62  		{" a ", "a"},
    63  		{"\na\nb ", "a b"},
    64  		{
    65  			" Verifying myself: I am pomf on Keybase.io. 8a6cewzit2o7zuLKGbDqQADhzfOlGerGuBpq\n/ https://keybase.io/pomf/sigs/8a6cewzit2o7zuLKGbDqQADhzfOlGerGuBpq ",
    66  			"Verifying myself: I am pomf on Keybase.io. 8a6cewzit2o7zuLKGbDqQADhzfOlGerGuBpq / https://keybase.io/pomf/sigs/8a6cewzit2o7zuLKGbDqQADhzfOlGerGuBpq",
    67  		},
    68  	}
    69  
    70  	for i, p := range data {
    71  		out := WhitespaceNormalize(p.in)
    72  		if out != p.out {
    73  			t.Errorf("Failed on test %d: %s != %s", i, out, p.out)
    74  		}
    75  	}
    76  
    77  }
    78  
    79  func TestMakeByte24(t *testing.T) {
    80  	var x1 [24]byte
    81  	var x2 [31]byte
    82  	var x3 [33]byte
    83  
    84  	x1[3] = 5
    85  
    86  	y := MakeByte24(x1[:])
    87  	require.Equal(t, x1, y)
    88  
    89  	require.Panics(t, func() {
    90  		MakeByte24(x2[:])
    91  	})
    92  
    93  	require.Panics(t, func() {
    94  		MakeByte24(x3[:])
    95  	})
    96  }
    97  
    98  func TestMakeByte32(t *testing.T) {
    99  	var x1 [32]byte
   100  	var x2 [31]byte
   101  	var x3 [33]byte
   102  
   103  	x1[3] = 5
   104  
   105  	y := MakeByte32(x1[:])
   106  	require.Equal(t, x1, y)
   107  
   108  	require.Panics(t, func() {
   109  		MakeByte32(x2[:])
   110  	})
   111  
   112  	require.Panics(t, func() {
   113  		MakeByte32(x3[:])
   114  	})
   115  }
   116  
   117  func TestAppDataDir(t *testing.T) {
   118  	dir, err := AppDataDir()
   119  	if err != nil {
   120  		// Non-Windows case.
   121  		require.True(t, strings.HasPrefix(err.Error(), "unsupported"))
   122  		return
   123  	}
   124  
   125  	// Windows case. AppDataDir should exist, at least on our test
   126  	// machines.
   127  	require.NoError(t, err)
   128  	exists, err := FileExists(dir)
   129  	require.NoError(t, err)
   130  	require.True(t, exists)
   131  }
   132  
   133  func TestLocalDataDir(t *testing.T) {
   134  	dir, err := LocalDataDir()
   135  	if err != nil {
   136  		// Non-Windows case.
   137  		require.True(t, strings.HasPrefix(err.Error(), "unsupported"))
   138  		return
   139  	}
   140  
   141  	// Windows case. LocalDataDir should exist, at least on our
   142  	// test machines.
   143  	require.NoError(t, err)
   144  	exists, err := FileExists(dir)
   145  	require.NoError(t, err)
   146  	require.True(t, exists)
   147  }
   148  
   149  func hasMonotonicClock(t time.Time) bool {
   150  	re := regexp.MustCompile(" m=[-+]([.0-9]+)$")
   151  	return re.FindString(t.String()) != ""
   152  }
   153  
   154  func TestForceWallClock(t *testing.T) {
   155  	n := time.Now()
   156  	require.True(t, hasMonotonicClock(n))
   157  	require.False(t, hasMonotonicClock(ForceWallClock(n)))
   158  }
   159  
   160  func TestDecodeHexFixed(t *testing.T) {
   161  	units := []struct {
   162  		src string
   163  		dst []byte
   164  		err string
   165  	}{
   166  		{"", []byte{}, ""},
   167  		{"aa", []byte{170}, ""},
   168  		{"abcd", []byte{171, 205}, ""},
   169  
   170  		{"a", []byte{}, "encoding/hex: odd length hex string"},
   171  		{"aaa", []byte{170}, "encoding/hex: odd length hex string"},
   172  		{"aa", []byte{}, "error decoding fixed-length hex: expected 0 bytes but got 1"},
   173  		{"", []byte{170}, "error decoding fixed-length hex: expected 1 bytes but got 0"},
   174  		{"abcd", []byte{171, 205, 0}, "error decoding fixed-length hex: expected 3 bytes but got 2"},
   175  		{"abcd", []byte{171}, "error decoding fixed-length hex: expected 1 bytes but got 2"},
   176  	}
   177  	for i, unit := range units {
   178  		t.Logf("units[%v]", i)
   179  		buf := make([]byte, len(unit.dst))
   180  		err := DecodeHexFixed(buf, []byte(unit.src))
   181  		if unit.err != "" {
   182  			require.Error(t, err)
   183  			require.Equal(t, unit.err, err.Error())
   184  			empty := make([]byte, len(unit.dst))
   185  			require.True(t, bytes.Equal(empty, buf))
   186  		} else {
   187  			require.NoError(t, err)
   188  			require.Equal(t, unit.dst, buf)
   189  		}
   190  	}
   191  }
   192  
   193  func TestDownloadGetFilenames(t *testing.T) {
   194  	var tests = map[string]string{
   195  		"abc.def":       "abc.def",
   196  		"文件.def":        "文件.def",
   197  		"abc.\u202edef": "abc.%E2%80%AEdef",
   198  		"abc.\u200fdef": "abc.%E2%80%8Fdef",
   199  	}
   200  	for original, expected := range tests {
   201  		safeFilename := GetSafeFilename(original)
   202  		require.Equal(t, expected, safeFilename)
   203  	}
   204  }
   205  
   206  func TestSecureRandomRndRange(t *testing.T) {
   207  	s := SecureRandom{}
   208  
   209  	var tests = []struct {
   210  		lo        int64
   211  		hi        int64
   212  		shouldErr bool
   213  	}{
   214  		{0, 0, false},
   215  		{1, 1, false},
   216  		{-1, -1, false},
   217  		{1, 0, true},
   218  		{-1, -2, true},
   219  		{2, 5, false},
   220  		{-1, 10, false},
   221  		{1, 50, false},
   222  		{-40, -1, false},
   223  	}
   224  
   225  	for _, test := range tests {
   226  		for i := 0; i < 10; i++ {
   227  			r, err := s.RndRange(test.lo, test.hi)
   228  			if test.shouldErr {
   229  				require.Error(t, err)
   230  				continue
   231  			}
   232  			require.True(t, r >= test.lo)
   233  			require.True(t, r <= test.hi)
   234  		}
   235  	}
   236  
   237  	// basic consistency check that sampled random numbers are different (the
   238  	// random function is not a constant). Duplicate outputs should happen very
   239  	// infrequently on a large range. In this case, the test will flake with
   240  	// probability exactly 1/10^12.
   241  	r1, err := s.RndRange(0, 1000000000000)
   242  	require.NoError(t, err)
   243  	r2, err := s.RndRange(0, 1000000000000)
   244  	require.NoError(t, err)
   245  	require.NotEqual(t, r1, r2)
   246  }
   247  
   248  func TestThrottleBatch(t *testing.T) {
   249  	clock := clockwork.NewFakeClock()
   250  	throttleBatchClock = clock
   251  	ch := make(chan int, 100)
   252  	handler := func(arg interface{}) {
   253  		v, ok := arg.(int)
   254  		require.True(t, ok)
   255  		ch <- v
   256  	}
   257  	getVal := func(expected int) {
   258  		select {
   259  		case v := <-ch:
   260  			require.Equal(t, expected, v)
   261  		case <-time.After(2 * time.Second):
   262  			require.Fail(t, "no value received")
   263  		}
   264  	}
   265  	noVal := func() {
   266  		time.Sleep(10 * time.Millisecond)
   267  		select {
   268  		case <-ch:
   269  			require.Fail(t, "no value should have been received")
   270  		default:
   271  		}
   272  	}
   273  	batcher := func(batchedInt interface{}, singleInt interface{}) interface{} {
   274  		batched, ok := batchedInt.(int)
   275  		require.True(t, ok)
   276  		single, ok := singleInt.(int)
   277  		require.True(t, ok)
   278  		return batched + single
   279  	}
   280  	reset := func() interface{} {
   281  		return 0
   282  	}
   283  
   284  	f, cancel := ThrottleBatch(handler, batcher, reset, 200, true)
   285  	f(2)
   286  	getVal(2)
   287  	f(3)
   288  	f(2)
   289  	noVal()
   290  	clock.Advance(300 * time.Millisecond)
   291  	getVal(5)
   292  
   293  	clock.Advance(time.Hour)
   294  	f(2)
   295  	getVal(2)
   296  
   297  	f(2)
   298  	noVal()
   299  	cancel()
   300  	time.Sleep(100 * time.Millisecond)
   301  	clock.Advance(300 * time.Millisecond)
   302  	noVal()
   303  }
   304  
   305  func TestFindFilePathWithNumberSuffix(t *testing.T) {
   306  	parentDir := os.TempDir()
   307  	path, err := FindFilePathWithNumberSuffix(parentDir, "", true)
   308  	require.NoError(t, err)
   309  	require.True(t, strings.HasPrefix(path, parentDir))
   310  
   311  	path, err = FindFilePathWithNumberSuffix(parentDir, "test.txt", true)
   312  	require.NoError(t, err)
   313  	require.True(t, strings.HasPrefix(path, parentDir))
   314  	require.True(t, strings.HasSuffix(path, ".txt"))
   315  
   316  	path, err = FindFilePathWithNumberSuffix(parentDir, "", false)
   317  	require.NoError(t, err)
   318  	require.Equal(t, filepath.Join(parentDir, " (1)"), path)
   319  
   320  	path, err = FindFilePathWithNumberSuffix(parentDir, "test.txt", false)
   321  	require.NoError(t, err)
   322  	require.Equal(t, filepath.Join(parentDir, "test.txt"), path)
   323  
   324  	path, err = FindFilePathWithNumberSuffix(parentDir, ".txt", false)
   325  	require.NoError(t, err)
   326  	require.Equal(t, filepath.Join(parentDir, ".txt"), path)
   327  }