github.com/juju/charm/v11@v11.2.0/jujuignore_test.go (about)

     1  // Copyright 2019 Canonical Ltd.
     2  // Licensed under the LGPLv3, see LICENCE file for details.
     3  
     4  package charm
     5  
     6  import (
     7  	"strings"
     8  
     9  	gc "gopkg.in/check.v1"
    10  )
    11  
    12  type JujuIgnoreSuite struct{}
    13  
    14  var _ = gc.Suite(&JujuIgnoreSuite{})
    15  
    16  func (s *JujuIgnoreSuite) TestBuildRules(c *gc.C) {
    17  	type test struct {
    18  		path     string
    19  		isDir    bool
    20  		expMatch bool
    21  	}
    22  
    23  	specs := []struct {
    24  		descr string
    25  		rules string
    26  		tests []test
    27  	}{
    28  		{
    29  			descr: `Match a directory named "target" at any depth`,
    30  			rules: `target/`,
    31  			tests: []test{
    32  				{path: "target", isDir: true, expMatch: true},
    33  				{path: "foo/target", isDir: true, expMatch: true},
    34  				{path: "foo/1target", isDir: true, expMatch: false},
    35  				{path: "foo/target", isDir: false, expMatch: false},
    36  			},
    37  		},
    38  		{
    39  			descr: `Match a directory OR a file named "target" at any depth`,
    40  			rules: `target`,
    41  			tests: []test{
    42  				{path: "/target", isDir: true, expMatch: true},
    43  				{path: "/foo/target", isDir: true, expMatch: true},
    44  				{path: "/foo/1target", isDir: true, expMatch: false},
    45  				{path: "/foo/target", isDir: false, expMatch: true},
    46  			},
    47  		},
    48  		{
    49  			descr: `Match a directory at the root only`,
    50  			rules: `/target/`,
    51  			tests: []test{
    52  				{path: "/target", isDir: true, expMatch: true},
    53  				{path: "/foo/target", isDir: true, expMatch: false},
    54  				{path: "/target", isDir: false, expMatch: false},
    55  			},
    56  		},
    57  		{
    58  			descr: `Match a directory OR file at the root only`,
    59  			rules: `/target`,
    60  			tests: []test{
    61  				{path: "/target", isDir: true, expMatch: true},
    62  				{path: "/foo/target", isDir: true, expMatch: false},
    63  				{path: "/target", isDir: false, expMatch: true},
    64  			},
    65  		},
    66  		{
    67  			descr: `Every file or dir ending with .go recursively`,
    68  			rules: `*.go`,
    69  			tests: []test{
    70  				{path: "/target.go", isDir: true, expMatch: true},
    71  				{path: "/target.go", isDir: false, expMatch: true},
    72  				{path: "/foo/target.go", isDir: true, expMatch: true},
    73  				{path: "/foo/target.go", isDir: false, expMatch: true},
    74  				{path: "/target.goT", isDir: true, expMatch: false},
    75  				{path: "/target.goT", isDir: false, expMatch: false},
    76  			},
    77  		},
    78  		{
    79  			descr: `every file or dir named "#comment"`,
    80  			rules: `
    81  # NOTE: leading hash must be escaped so as not to treat line as a comment
    82  \#comment
    83  `,
    84  			tests: []test{
    85  				{path: "/#comment", isDir: true, expMatch: true},
    86  				{path: "/#comment", isDir: false, expMatch: true},
    87  			},
    88  		},
    89  		{
    90  			descr: `Every dir called "logs" under "apps"`,
    91  			rules: `apps/logs/`,
    92  			tests: []test{
    93  				{path: "/apps/logs", isDir: true, expMatch: true},
    94  				{path: "/apps/foo/logs", isDir: true, expMatch: false},
    95  			},
    96  		},
    97  		{
    98  			descr: `Every dir called "logs" two levels under "apps"`,
    99  			rules: `apps/*/logs/`,
   100  			tests: []test{
   101  				{path: "/apps/foo/logs", isDir: true, expMatch: true},
   102  				{path: "/apps/foo/bar/logs", isDir: true, expMatch: false},
   103  				{path: "/apps/logs", isDir: true, expMatch: false},
   104  			},
   105  		},
   106  		{
   107  			descr: `Every dir called "logs" any number of levels under "apps"`,
   108  			rules: `apps/**/logs/`,
   109  			tests: []test{
   110  				{path: "/apps/foo/logs", isDir: true, expMatch: true},
   111  				{path: "/apps/foo/bar/logs", isDir: true, expMatch: true},
   112  				{path: "/apps/logs", isDir: true, expMatch: true},
   113  			},
   114  		},
   115  		{
   116  			descr: `Ignore all under "foo" but not "foo" itself`,
   117  			rules: `foo/**`,
   118  			tests: []test{
   119  				{path: "/foo", isDir: true, expMatch: false},
   120  				{path: "/foo/something", isDir: true, expMatch: true},
   121  				{path: "/foo/something.txt", isDir: false, expMatch: true},
   122  			},
   123  		},
   124  		{
   125  			descr: `Ignore all under "foo" except README.md`,
   126  			rules: `
   127  foo/**
   128  !foo/README.md
   129  `,
   130  			tests: []test{
   131  				{path: "/foo", isDir: true, expMatch: false},
   132  				{path: "/foo/something", isDir: true, expMatch: true},
   133  				{path: "/foo/something.txt", isDir: false, expMatch: true},
   134  				{path: "/foo/README.md", isDir: false, expMatch: false},
   135  			},
   136  		},
   137  		{
   138  			descr: `Multiple double-star separators`,
   139  			rules: `foo/**/bar/**/baz`,
   140  			tests: []test{
   141  				{path: "/foo/1/2/bar/baz", isDir: true, expMatch: true},
   142  				{path: "/foo/1/2/bar/1/2/baz", isDir: true, expMatch: true},
   143  				{path: "/foo/bar/1/baz", isDir: true, expMatch: true},
   144  				{path: "/foo/1/bar/baz", isDir: true, expMatch: true},
   145  				{path: "/foo/bar/baz", isDir: true, expMatch: true},
   146  			},
   147  		},
   148  	}
   149  
   150  	for specIndex, spec := range specs {
   151  		c.Logf("[spec %d] %s", specIndex, spec.descr)
   152  
   153  		rs, err := newIgnoreRuleset(strings.NewReader(spec.rules))
   154  		if err != nil {
   155  			c.Assert(err, gc.IsNil)
   156  			continue
   157  		}
   158  
   159  		for testIndex, test := range spec.tests {
   160  			c.Logf("  [test %d] match against path %q", testIndex, test.path)
   161  			c.Assert(rs.Match(test.path, test.isDir), gc.DeepEquals, test.expMatch)
   162  		}
   163  	}
   164  }
   165  
   166  func (s *JujuIgnoreSuite) TestGenIgnorePatternPermutations(c *gc.C) {
   167  	specs := []struct {
   168  		in  string
   169  		exp []string
   170  	}{
   171  		{
   172  			in:  "foo/bar",
   173  			exp: []string{"foo/bar"},
   174  		},
   175  		{
   176  			in: "foo/**/bar",
   177  			exp: []string{
   178  				"foo/**/bar",
   179  				"foo/bar",
   180  			},
   181  		},
   182  		{
   183  			in: "foo/**/bar/**/baz",
   184  			exp: []string{
   185  				"foo/**/bar/**/baz",
   186  				"foo/bar/**/baz",
   187  				"foo/**/bar/baz",
   188  				"foo/bar/baz",
   189  			},
   190  		},
   191  	}
   192  
   193  	for specIndex, spec := range specs {
   194  		c.Logf("  [spec %d] gen permutations for %q", specIndex, spec.in)
   195  		got := genIgnorePatternPermutations(spec.in)
   196  		c.Assert(got, gc.DeepEquals, spec.exp)
   197  	}
   198  }
   199  
   200  func (s *JujuIgnoreSuite) TestUnescapeIgnorePattern(c *gc.C) {
   201  	specs := []struct {
   202  		desc string
   203  		in   string
   204  		exp  string
   205  	}{
   206  		{
   207  			desc: "trailing unescaped spaces should be trimmed",
   208  			in:   `lore\ m\   `,
   209  			exp:  `lore m `,
   210  		},
   211  		{
   212  			desc: "escaped hashes should be unescaped",
   213  			in:   `\#this-is-not-a-comment`,
   214  			exp:  `#this-is-not-a-comment`,
   215  		},
   216  		{
   217  			desc: "escaped bangs should be unescaped",
   218  			in:   `\!important`,
   219  			exp:  `!important`,
   220  		},
   221  	}
   222  
   223  	for specIndex, spec := range specs {
   224  		c.Logf("[spec %d] %s", specIndex, spec.desc)
   225  		c.Assert(unescapeIgnorePattern(spec.in), gc.Equals, spec.exp)
   226  	}
   227  }