github.com/keybase/client/go@v0.0.0-20240309051027-028f7c731f8b/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 }