diff --git a/README.md b/README.md index e1619b6..ececfa8 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ if a folder: - [ ] contains a files matching a glob pattern - [ ] is gitignored - [ ] is gitcrypted +- [ ] has specific permissions if a file: - [x] exists @@ -22,9 +23,10 @@ if a file: - [x] content matches value - [x] content matches regex - [ ] content matches template -- [ ] content contains a value +- [x] content contains a value - [ ] is gitignored - [ ] is gitcrypted +- [ ] has specific permissions if a set of files: - [x] exists diff --git a/internal/arch/file/should/contain_value_test.go b/internal/arch/file/should/contain_value_test.go index fab9eaf..ff4d914 100644 --- a/internal/arch/file/should/contain_value_test.go +++ b/internal/arch/file/should/contain_value_test.go @@ -48,6 +48,38 @@ func Test_ContainValue(t *testing.T) { rule.NewViolation("file 'foobar.txt' does not contain the value 'something else'"), }, }, + { + desc: "negated: file 'foobar.txt' contains the value 'bar'", + ruleBuilder: file.One(filepath.Join(basePath, "test/foobar.txt")), + value: "bar", + options: []should.Option{ + should.Negated{}, + }, + want: []rule.Violation{ + rule.NewViolation("file 'foobar.txt' does contain the value 'bar'"), + }, + }, + { + desc: "negated: file 'foobar.txt' contains the value 'bar', ignoring case", + ruleBuilder: file.One(filepath.Join(basePath, "test/foobar.txt")), + value: "BAR", + options: []should.Option{ + should.IgnoreCase{}, + should.Negated{}, + }, + want: []rule.Violation{ + rule.NewViolation("file 'foobar.txt' does contain the value 'BAR'"), + }, + }, + { + desc: "negated: file 'foobar.txt' does not contain the value 'something else'", + ruleBuilder: file.One(filepath.Join(basePath, "test/foobar.txt")), + value: "something else", + options: []should.Option{ + should.Negated{}, + }, + want: nil, + }, } for _, tC := range testCases { diff --git a/internal/arch/file/should/end_with_test.go b/internal/arch/file/should/end_with_test.go index 9cd00d1..1880449 100644 --- a/internal/arch/file/should/end_with_test.go +++ b/internal/arch/file/should/end_with_test.go @@ -15,6 +15,7 @@ func Test_EndWith(t *testing.T) { desc string ruleBuilder *file.RuleBuilder suffix string + options []should.Option want []rule.Violation }{ { @@ -31,36 +32,22 @@ func Test_EndWith(t *testing.T) { rule.NewViolation("file's name 'foobar' does not end with 'baz'"), }, }, - } - for _, tC := range testCases { - t.Run(tC.desc, func(t *testing.T) { - ew := should.EndWith(tC.suffix) - got := ew.Evaluate(tC.ruleBuilder) - - if !cmp.Equal(got, tC.want, cmp.AllowUnexported(rule.Violation{}), cmpopts.EquateEmpty()) { - t.Errorf("want = %+v, got = %+v", tC.want, got) - } - }) - } -} - -func Test_NotEndWith(t *testing.T) { - testCases := []struct { - desc string - ruleBuilder *file.RuleBuilder - suffix string - want []rule.Violation - }{ { - desc: "foobar does not end with baz", + desc: "negated: foobar does not end with baz", ruleBuilder: file.One("foobar"), suffix: "baz", - want: nil, + options: []should.Option{ + should.Negated{}, + }, + want: nil, }, { - desc: "foobar ends with bar", + desc: "negated: foobar ends with bar", ruleBuilder: file.One("foobar"), suffix: "bar", + options: []should.Option{ + should.Negated{}, + }, want: []rule.Violation{ rule.NewViolation("file's name 'foobar' does end with 'bar'"), }, @@ -68,7 +55,7 @@ func Test_NotEndWith(t *testing.T) { } for _, tC := range testCases { t.Run(tC.desc, func(t *testing.T) { - ew := should.Not(should.EndWith(tC.suffix)) + ew := should.EndWith(tC.suffix, tC.options...) got := ew.Evaluate(tC.ruleBuilder) if !cmp.Equal(got, tC.want, cmp.AllowUnexported(rule.Violation{}), cmpopts.EquateEmpty()) { diff --git a/internal/arch/file/should/exist_test.go b/internal/arch/file/should/exist_test.go index 69e9c27..325f38e 100644 --- a/internal/arch/file/should/exist_test.go +++ b/internal/arch/file/should/exist_test.go @@ -14,7 +14,7 @@ func Test_Exist(t *testing.T) { testCases := []struct { desc string ruleBuilder *file.RuleBuilder - suffix string + options []should.Option want []rule.Violation }{ { @@ -29,40 +29,27 @@ func Test_Exist(t *testing.T) { rule.NewViolation("file 'abc.xyz' does not exist"), }, }, - } - for _, tC := range testCases { - t.Run(tC.desc, func(t *testing.T) { - e := should.Exist() - got := e.Evaluate(tC.ruleBuilder) - - if !cmp.Equal(got, tC.want, cmp.AllowUnexported(rule.Violation{}), cmpopts.EquateEmpty()) { - t.Errorf("want = %+v, got = %+v", tC.want, got) - } - }) - } -} - -func Test_NotExist(t *testing.T) { - testCases := []struct { - desc string - ruleBuilder *file.RuleBuilder - want []rule.Violation - }{ { - desc: "exist.go exists", + desc: "negated: exist.go exists", ruleBuilder: file.One("exist.go"), + options: []should.Option{ + should.Negated{}, + }, want: []rule.Violation{ rule.NewViolation("file 'exist.go' does exist"), }, }, { - desc: "abc.xyz does not exist", + desc: "negated: abc.xyz does not exist", ruleBuilder: file.One("abc.xyz"), + options: []should.Option{ + should.Negated{}, + }, }, } for _, tC := range testCases { t.Run(tC.desc, func(t *testing.T) { - e := should.Not(should.Exist()) + e := should.Exist(tC.options...) got := e.Evaluate(tC.ruleBuilder) if !cmp.Equal(got, tC.want, cmp.AllowUnexported(rule.Violation{}), cmpopts.EquateEmpty()) { diff --git a/internal/arch/file/should/have_content_matching_regex_test.go b/internal/arch/file/should/have_content_matching_regex_test.go index 708ae22..9f296f4 100644 --- a/internal/arch/file/should/have_content_matching_regex_test.go +++ b/internal/arch/file/should/have_content_matching_regex_test.go @@ -79,6 +79,15 @@ func Test_HaveContentMatchingRegex(t *testing.T) { rule.NewViolation("file 'baz.txt' does not have all lines matching regex '^bar.+'"), }, }, + { + desc: "negated: content of file 'foobar.txt' does not match regex", + ruleBuilder: file.One(filepath.Join(basePath, "test/foobar.txt")), + regexp: "^something\\ else.+", + options: []should.Option{ + should.Negated{}, + }, + want: nil, + }, } for _, tC := range testCases { diff --git a/internal/arch/file/should/have_content_matching_test.go b/internal/arch/file/should/have_content_matching_test.go index 1ba5cd2..7a33174 100644 --- a/internal/arch/file/should/have_content_matching_test.go +++ b/internal/arch/file/should/have_content_matching_test.go @@ -79,6 +79,15 @@ func Test_HaveContentMatching(t *testing.T) { rule.NewViolation("file 'baz.txt' does not have all lines matching 'something else'"), }, }, + { + desc: "negated: content of file 'foobar.txt' does not match expected content", + ruleBuilder: file.One(filepath.Join(basePath, "test/foobar.txt")), + content: "something else\n", + options: []should.Option{ + should.Negated{}, + }, + want: nil, + }, } for _, tC := range testCases { diff --git a/internal/arch/file/should/match_glob_test.go b/internal/arch/file/should/match_glob_test.go index 7f5c9a7..1b4c961 100644 --- a/internal/arch/file/should/match_glob_test.go +++ b/internal/arch/file/should/match_glob_test.go @@ -31,6 +31,7 @@ func Test_MatchGlob(t *testing.T) { desc string ruleBuilder *file.RuleBuilder glob string + options []should.Option want []rule.Violation }{ { @@ -54,10 +55,40 @@ func Test_MatchGlob(t *testing.T) { rule.NewViolation("file's path 'quux.txt' does not match glob pattern '**/*.doc'"), }, }, + { + desc: "negated: project3 does not match '*.xls'", + ruleBuilder: newRuleBuilder(), + glob: "*/*/*.xls", + options: []should.Option{ + should.Negated{}, + }, + want: nil, + }, + { + desc: "negated: project3 does not match 'test/*/*.xls'", + ruleBuilder: newRuleBuilder(), + glob: "test/*/*.xls", + options: []should.Option{ + should.Negated{}, + }, + want: nil, + }, + { + desc: "negated: project3 does match 'test/*/*.txt'", + ruleBuilder: newRuleBuilder(), + glob: "test/*/*.txt", + options: []should.Option{ + should.Negated{}, + }, + want: []rule.Violation{ + rule.NewViolation("file's path 'baz.txt' does match glob pattern 'test/*/*.txt'"), + rule.NewViolation("file's path 'quux.txt' does match glob pattern 'test/*/*.txt'"), + }, + }, } for _, tC := range testCases { t.Run(tC.desc, func(t *testing.T) { - mg := should.MatchGlob(tC.glob, basePath) + mg := should.MatchGlob(tC.glob, basePath, tC.options...) got := mg.Evaluate(tC.ruleBuilder) if !cmp.Equal(got, tC.want, cmp.AllowUnexported(rule.Violation{}), cmpopts.EquateEmpty()) { diff --git a/internal/arch/file/should/match_regex_test.go b/internal/arch/file/should/match_regex_test.go index aaa0fb5..716c5d2 100644 --- a/internal/arch/file/should/match_regex_test.go +++ b/internal/arch/file/should/match_regex_test.go @@ -15,6 +15,7 @@ func Test_MatchRegex(t *testing.T) { desc string ruleBuilder *file.RuleBuilder regexp string + options []should.Option want []rule.Violation }{ { @@ -37,53 +38,42 @@ func Test_MatchRegex(t *testing.T) { rule.NewViolation("file's name 'foobar' does not match regex '[0-9]+'"), }, }, - } - for _, tC := range testCases { - t.Run(tC.desc, func(t *testing.T) { - ew := should.MatchRegex(tC.regexp) - got := ew.Evaluate(tC.ruleBuilder) - - if !cmp.Equal(got, tC.want, cmp.AllowUnexported(rule.Violation{}), cmpopts.EquateEmpty()) { - t.Errorf("want = %+v, got = %+v", tC.want, got) - } - }) - } -} - -func Test_NotMatchRegex(t *testing.T) { - testCases := []struct { - desc string - ruleBuilder *file.RuleBuilder - regexp string - want []rule.Violation - }{ { - desc: "foobar matches '[a-z]+'", + desc: "negated: foobar matches '[a-z]+'", ruleBuilder: file.One("foobar"), regexp: "[a-z]+", + options: []should.Option{ + should.Negated{}, + }, want: []rule.Violation{ rule.NewViolation("file's name 'foobar' does match regex '[a-z]+'"), }, }, { - desc: "foobar matches 'foobar'", + desc: "negated: foobar matches 'foobar'", ruleBuilder: file.One("foobar"), regexp: "foobar", + options: []should.Option{ + should.Negated{}, + }, want: []rule.Violation{ rule.NewViolation("file's name 'foobar' does match regex 'foobar'"), }, }, { - desc: "foobar does not match '[0-9]+'", + desc: "negated: foobar does not match '[0-9]+'", ruleBuilder: file.One("foobar"), regexp: "[0-9]+", - want: nil, + options: []should.Option{ + should.Negated{}, + }, + want: nil, }, } for _, tC := range testCases { t.Run(tC.desc, func(t *testing.T) { - nmr := should.Not(should.MatchRegex(tC.regexp)) - got := nmr.Evaluate(tC.ruleBuilder) + ew := should.MatchRegex(tC.regexp, tC.options...) + got := ew.Evaluate(tC.ruleBuilder) if !cmp.Equal(got, tC.want, cmp.AllowUnexported(rule.Violation{}), cmpopts.EquateEmpty()) { t.Errorf("want = %+v, got = %+v", tC.want, got) diff --git a/internal/arch/file/should/start_with_test.go b/internal/arch/file/should/start_with_test.go index 5d063d5..2395eb0 100644 --- a/internal/arch/file/should/start_with_test.go +++ b/internal/arch/file/should/start_with_test.go @@ -15,6 +15,7 @@ func Test_StartWith(t *testing.T) { desc string ruleBuilder *file.RuleBuilder prefix string + options []should.Option want []rule.Violation }{ { @@ -31,10 +32,30 @@ func Test_StartWith(t *testing.T) { rule.NewViolation("file's name 'foobar' does not start with 'baz'"), }, }, + { + desc: "negated: foobar does not start with baz", + ruleBuilder: file.One("foobar"), + prefix: "baz", + options: []should.Option{ + should.Negated{}, + }, + want: nil, + }, + { + desc: "negated: foobar starts with foo", + ruleBuilder: file.One("foobar"), + prefix: "foo", + options: []should.Option{ + should.Negated{}, + }, + want: []rule.Violation{ + rule.NewViolation("file's name 'foobar' does start with 'foo'"), + }, + }, } for _, tC := range testCases { t.Run(tC.desc, func(t *testing.T) { - ew := should.StartWith(tC.prefix) + ew := should.StartWith(tC.prefix, tC.options...) got := ew.Evaluate(tC.ruleBuilder) if !cmp.Equal(got, tC.want, cmp.AllowUnexported(rule.Violation{}), cmpopts.EquateEmpty()) {