gitlab.com/SkynetLabs/skyd@v1.6.9/skymodules/siapath_test.go (about) 1 package skymodules 2 3 import ( 4 "runtime" 5 "testing" 6 7 "gitlab.com/NebulousLabs/errors" 8 ) 9 10 var ( 11 // TestGlobalSiaPathVar tests that the NewGlobalSiaPath initialization 12 // works. 13 TestGlobalSiaPathVar SiaPath = NewGlobalSiaPath("/testdir") 14 ) 15 16 // TestGlobalSiaPath checks that initializing a new global siapath does not 17 // cause any issues. 18 func TestGlobalSiaPath(t *testing.T) { 19 sp, err := TestGlobalSiaPathVar.Join("testfile") 20 if err != nil { 21 t.Fatal(err) 22 } 23 mirror, err := NewSiaPath("/testdir") 24 if err != nil { 25 t.Fatal(err) 26 } 27 expected, err := mirror.Join("testfile") 28 if err != nil { 29 t.Fatal(err) 30 } 31 if !sp.Equals(expected) { 32 t.Error("the separately spawned siapath should equal the global siapath") 33 } 34 } 35 36 // TestRandomSiaPath tests that RandomSiaPath always returns a valid SiaPath 37 func TestRandomSiaPath(t *testing.T) { 38 for i := 0; i < 1000; i++ { 39 err := RandomSiaPath().Validate(false) 40 if err != nil { 41 t.Fatal(err) 42 } 43 err = RandomSkynetFilePath().Validate(false) 44 if err != nil { 45 t.Fatal(err) 46 } 47 } 48 } 49 50 // TestSiapathValidate verifies that the validate function correctly validates 51 // SiaPaths. 52 func TestSiapathValidate(t *testing.T) { 53 var pathtests = []struct { 54 in string 55 valid bool 56 }{ 57 {"valid/siapath", true}, 58 {"../../../directory/traversal", false}, 59 {"testpath", true}, 60 {"valid/siapath/../with/directory/traversal", false}, 61 {"validpath/test", true}, 62 {"..validpath/..test", true}, 63 {"./invalid/path", false}, 64 {".../path", true}, 65 {"valid./path", true}, 66 {"valid../path", true}, 67 {"valid/path./test", true}, 68 {"valid/path../test", true}, 69 {"test/path", true}, 70 {"/leading/slash", false}, 71 {"foo/./bar", false}, 72 {"", false}, 73 {"blank/end/", false}, 74 {"double//dash", false}, 75 {"../", false}, 76 {"./", false}, 77 {".", false}, 78 } 79 for _, pathtest := range pathtests { 80 err := ValidatePathString(pathtest.in, false) 81 if err != nil && pathtest.valid { 82 t.Fatal("validateSiapath failed on valid path: ", pathtest.in) 83 } 84 if err == nil && !pathtest.valid { 85 t.Fatal("validateSiapath succeeded on invalid path: ", pathtest.in) 86 } 87 } 88 } 89 90 // TestSiapath tests that the NewSiaPath, LoadString, and Join methods function correctly 91 func TestSiapath(t *testing.T) { 92 var pathtests = []struct { 93 in string 94 valid bool 95 out string 96 }{ 97 {`\\some\\windows\\path`, true, `\\some\\windows\\path`}, // if the os is not windows this will not update the separators 98 {"valid/siapath", true, "valid/siapath"}, 99 {`\some\back\slashes\path`, true, `\some\back\slashes\path`}, 100 {"../../../directory/traversal", false, ""}, 101 {"testpath", true, "testpath"}, 102 {"valid/siapath/../with/directory/traversal", false, ""}, 103 {"validpath/test", true, "validpath/test"}, 104 {"..validpath/..test", true, "..validpath/..test"}, 105 {"./invalid/path", false, ""}, 106 {".../path", true, ".../path"}, 107 {"valid./path", true, "valid./path"}, 108 {"valid../path", true, "valid../path"}, 109 {"valid/path./test", true, "valid/path./test"}, 110 {"valid/path../test", true, "valid/path../test"}, 111 {"test/path", true, "test/path"}, 112 {"/leading/slash", true, "leading/slash"}, // clean will trim leading slashes so this is a valid input 113 {"foo/./bar", false, ""}, 114 {"", false, ""}, 115 {`\`, true, `\`}, 116 {`\\`, true, `\\`}, 117 {`\\\`, true, `\\\`}, 118 {`\\\\`, true, `\\\\`}, 119 {`\\\\\`, true, `\\\\\`}, 120 {"/", false, ""}, 121 {"//", false, ""}, 122 {"///", false, ""}, 123 {"////", false, ""}, 124 {"/////", false, ""}, 125 {"blank/end/", true, "blank/end"}, // clean will trim trailing slashes so this is a valid input 126 {"double//dash", false, ""}, 127 {"../", false, ""}, 128 {"./", false, ""}, 129 {".", false, ""}, 130 {"dollar$sign", true, "dollar$sign"}, 131 {"and&sign", true, "and&sign"}, 132 {"single`quote", true, "single`quote"}, 133 {"full:colon", true, "full:colon"}, 134 {"semi;colon", true, "semi;colon"}, 135 {"hash#tag", true, "hash#tag"}, 136 {"percent%sign", true, "percent%sign"}, 137 {"at@sign", true, "at@sign"}, 138 {"less<than", true, "less<than"}, 139 {"greater>than", true, "greater>than"}, 140 {"equal=to", true, "equal=to"}, 141 {"question?mark", true, "question?mark"}, 142 {"open[bracket", true, "open[bracket"}, 143 {"close]bracket", true, "close]bracket"}, 144 {"open{bracket", true, "open{bracket"}, 145 {"close}bracket", true, "close}bracket"}, 146 {"carrot^top", true, "carrot^top"}, 147 {"pipe|pipe", true, "pipe|pipe"}, 148 {"tilda~tilda", true, "tilda~tilda"}, 149 {"plus+sign", true, "plus+sign"}, 150 {"minus-sign", true, "minus-sign"}, 151 {"under_score", true, "under_score"}, 152 {"comma,comma", true, "comma,comma"}, 153 {"apostrophy's", true, "apostrophy's"}, 154 {`quotation"marks`, true, `quotation"marks`}, 155 } 156 // If the OS is windows then the windows path is valid and will be updated 157 if runtime.GOOS == "windows" { 158 pathtests[0].valid = true 159 pathtests[0].out = `some/windows/path` 160 } 161 162 // Test NewSiaPath 163 for _, pathtest := range pathtests { 164 sp, err := NewSiaPath(pathtest.in) 165 // Verify expected Error 166 if err != nil && pathtest.valid { 167 t.Fatal("validateSiapath failed on valid path: ", pathtest.in) 168 } 169 if err == nil && !pathtest.valid { 170 t.Fatal("validateSiapath succeeded on invalid path: ", pathtest.in) 171 } 172 // Verify expected path 173 if err == nil && pathtest.valid && sp.String() != pathtest.out { 174 t.Fatalf("Unexpected SiaPath From New; got %v, expected %v, for test %v", sp.String(), pathtest.out, pathtest.in) 175 } 176 177 // Only test Suffix for valid SiaPaths 178 if !pathtest.valid { 179 continue 180 } 181 182 // Test Add Suffix 183 extendedSiaPath, err := sp.AddSuffixStr(ExtendedSuffix) 184 // Verify expected Error 185 if err != nil && pathtest.valid { 186 t.Fatal("AddSuffixStr failed on valid path: ", pathtest.in) 187 } 188 if err == nil && !pathtest.valid { 189 t.Fatal("AddSuffixStr succeeded on invalid path: ", pathtest.in) 190 } 191 // Verify expected path 192 if err == nil && pathtest.valid && extendedSiaPath.String() != pathtest.out+ExtendedSuffix { 193 t.Fatalf("Unexpected SiaPath From AddSuffixStr; got %v, expected %v, for test %v", sp.String(), pathtest.out+ExtendedSuffix, pathtest.in) 194 } 195 } 196 197 // Test LoadString 198 var sp SiaPath 199 for _, pathtest := range pathtests { 200 err := sp.LoadString(pathtest.in) 201 // Verify expected Error 202 if err != nil && pathtest.valid { 203 t.Fatal("validateSiapath failed on valid path: ", pathtest.in) 204 } 205 if err == nil && !pathtest.valid { 206 t.Fatal("validateSiapath succeeded on invalid path: ", pathtest.in) 207 } 208 // Verify expected path 209 if err == nil && pathtest.valid && sp.String() != pathtest.out { 210 t.Fatalf("Unexpected SiaPath from LoadString; got %v, expected %v, for test %v", sp.String(), pathtest.out, pathtest.in) 211 } 212 } 213 214 // Test Join 215 sp, err := NewSiaPath("test") 216 if err != nil { 217 t.Fatal(err) 218 } 219 for _, pathtest := range pathtests { 220 newSiaPath, err := sp.Join(pathtest.in) 221 // Verify expected Error 222 if err != nil && pathtest.valid { 223 t.Fatal("validateSiapath failed on valid path: ", pathtest.in) 224 } 225 if err == nil && !pathtest.valid { 226 t.Fatal("validateSiapath succeeded on invalid path: ", pathtest.in) 227 } 228 // Verify expected path 229 if err == nil && pathtest.valid && newSiaPath.String() != "test/"+pathtest.out { 230 t.Fatalf("Unexpected SiaPath from Join; got %v, expected %v, for test %v", newSiaPath.String(), "test/"+pathtest.out, pathtest.in) 231 } 232 } 233 } 234 235 // TestSiapathRebase tests the SiaPath.Rebase method. 236 func TestSiapathRebase(t *testing.T) { 237 var rebasetests = []struct { 238 oldBase string 239 newBase string 240 siaPath string 241 result string 242 }{ 243 {"a/b", "a", "a/b/myfile", "a/myfile"}, // basic rebase 244 {"a/b", "", "a/b/myfile", "myfile"}, // newBase is root 245 {"", "b", "myfile", "b/myfile"}, // oldBase is root 246 {"a/a", "a/b", "a/a", "a/b"}, // folder == oldBase 247 } 248 249 for _, test := range rebasetests { 250 var oldBase, newBase SiaPath 251 var err1, err2 error 252 if test.oldBase == "" { 253 oldBase = RootSiaPath() 254 } else { 255 oldBase, err1 = newSiaPath(test.oldBase) 256 } 257 if test.newBase == "" { 258 newBase = RootSiaPath() 259 } else { 260 newBase, err2 = newSiaPath(test.newBase) 261 } 262 file, err3 := newSiaPath(test.siaPath) 263 expectedPath, err4 := newSiaPath(test.result) 264 if err := errors.Compose(err1, err2, err3, err4); err != nil { 265 t.Fatal(err) 266 } 267 // Rebase the path 268 res, err := file.Rebase(oldBase, newBase) 269 if err != nil { 270 t.Fatal(err) 271 } 272 // Check result. 273 if !res.Equals(expectedPath) { 274 t.Fatalf("'%v' doesn't match '%v'", res.String(), expectedPath.String()) 275 } 276 } 277 } 278 279 // TestSiapathDir probes the Dir function for SiaPaths. 280 func TestSiapathDir(t *testing.T) { 281 var pathtests = []struct { 282 path string 283 dir string 284 }{ 285 {"one/dir", "one"}, 286 {"many/more/dirs", "many/more"}, 287 {"nodir", ""}, 288 {"/leadingslash", ""}, 289 {"./leadingdotslash", ""}, 290 {"", ""}, 291 {".", ""}, 292 } 293 for _, pathtest := range pathtests { 294 siaPath := SiaPath{ 295 Path: pathtest.path, 296 } 297 dir, err := siaPath.Dir() 298 if err != nil { 299 t.Errorf("Dir should not return an error %v, path %v", err, pathtest.path) 300 continue 301 } 302 if dir.Path != pathtest.dir { 303 t.Errorf("Dir %v not the same as expected dir %v ", dir.Path, pathtest.dir) 304 continue 305 } 306 } 307 } 308 309 // TestSiapathName probes the Name function for SiaPaths. 310 func TestSiapathName(t *testing.T) { 311 var pathtests = []struct { 312 path string 313 name string 314 }{ 315 {"one/dir", "dir"}, 316 {"many/more/dirs", "dirs"}, 317 {"nodir", "nodir"}, 318 {"/leadingslash", "leadingslash"}, 319 {"./leadingdotslash", "leadingdotslash"}, 320 {"", ""}, 321 {".", ""}, 322 } 323 for _, pathtest := range pathtests { 324 siaPath := SiaPath{ 325 Path: pathtest.path, 326 } 327 name := siaPath.Name() 328 if name != pathtest.name { 329 t.Errorf("name %v not the same as expected name %v ", name, pathtest.name) 330 } 331 } 332 } 333 334 // TestSiaPathDepth checks that the Depth() call returns the right value for a 335 // siapath. 336 func TestSiaPathDepth(t *testing.T) { 337 var sp SiaPath 338 if sp.Depth() != 0 { 339 t.Error("bad") 340 } 341 342 // This is the old way we could calculate it, and it worked well in 343 // production, so it's what we verify against. 344 oldLevels := func(sp SiaPath) int { 345 levels := 0 346 next := sp 347 for !next.IsRoot() { 348 parent, err := next.Dir() 349 if err != nil { 350 t.Fatal(err) 351 } 352 next = parent 353 levels++ 354 } 355 return levels 356 } 357 root := RootSiaPath() 358 if root.Depth() != 0 { 359 t.Error("bad", root.Depth(), root.String()) 360 } 361 if oldLevels(root) != root.Depth() { 362 t.Error("bad") 363 } 364 one, err := NewSiaPath("one") 365 if err != nil { 366 t.Fatal(err) 367 } 368 if one.Depth() != 1 { 369 t.Error("bad", one.Depth(), one.String()) 370 } 371 if oldLevels(one) != one.Depth() { 372 t.Error("bad") 373 } 374 two, err := NewSiaPath("two/two") 375 if err != nil { 376 t.Fatal(err) 377 } 378 if two.Depth() != 2 { 379 t.Error("bad", two.Depth(), two.String()) 380 } 381 if oldLevels(two) != two.Depth() { 382 t.Error("bad") 383 } 384 three, err := NewSiaPath("three/three/three") 385 if err != nil { 386 t.Fatal(err) 387 } 388 if three.Depth() != 3 { 389 t.Error("bad", three.Depth(), three.String()) 390 } 391 if oldLevels(three) != three.Depth() { 392 t.Error("bad") 393 } 394 }