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  }