Skip to content

Commit

Permalink
feat: add glob matching for files
Browse files Browse the repository at this point in the history
  • Loading branch information
omissis committed Aug 10, 2022
1 parent 46dc0bb commit 24e4062
Show file tree
Hide file tree
Showing 7 changed files with 286 additions and 14 deletions.
13 changes: 6 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ if a set of files:
- [x] does not exist
- [x] names match a regex
- [x] names do not match a regex
- [ ] paths matching a glob pattern exist
- [ ] paths matching a glob pattern do not exist
- [x] paths matching a glob pattern exist
- [x] paths matching a glob pattern do not exist
- [ ] is gitignored
- [ ] is gitcrypted

Expand All @@ -42,11 +42,10 @@ if all files that respect some conditions:
- [x] do not end with a given suffix
- [x] names match a regex
- [x] names do not match a regex
- [ ] paths matching a glob pattern exist
- [ ] paths matching a glob pattern do not exist
- [ ] is gitignored
- [ ] is gitcrypted

- [x] paths matching a glob pattern exist
- [x] paths matching a glob pattern do not exist
- [ ] are gitignored
- [ ] are gitcrypted

if a package:
- [ ] depends on another package
Expand Down
108 changes: 101 additions & 7 deletions internal/arch/file/rule_all_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,49 @@ import (
"github.com/google/go-cmp/cmp/cmpopts"
)

func Test_It_Checks_All_Files_In_A_Folder_Start_With(t *testing.T) {
basePath, err := os.Getwd()
if err != nil {
t.Fatal(err)
}

testCases := []struct {
desc string
folder string
wantViolations []rule.Violation
}{
{
desc: "check that all files in a folder start with the given prefix when they do",
folder: filepath.Join(basePath, "test/project2"),
wantViolations: nil,
},
{
desc: "check that all files in a folder start with the given prefix when they don't",
folder: filepath.Join(basePath, "test/project"),
wantViolations: []rule.Violation{
rule.NewViolation("file's name 'Makefile' does not start with 'Docker'"),
},
},
}

for _, tC := range testCases {
t.Run(tC.desc, func(t *testing.T) {
vs, errs := file.All().
That(ft.AreInFolder(tC.folder, false)).
Should(fs.StartWith("Docker")).
Because("testing reasons")

if !cmp.Equal(vs, tC.wantViolations, cmp.AllowUnexported(rule.Violation{}), cmpopts.EquateEmpty()) {
t.Errorf("Expected %v, got %v", tC.wantViolations, vs)
}

if errs != nil {
t.Errorf("Expected errs to be nil, got: %+v", errs)
}
})
}
}

func Test_It_Checks_All_Files_In_A_Folder_End_With(t *testing.T) {
basePath, err := os.Getwd()
if err != nil {
Expand Down Expand Up @@ -56,7 +99,7 @@ func Test_It_Checks_All_Files_In_A_Folder_End_With(t *testing.T) {
}
}

func Test_It_Checks_All_Files_In_A_Folder_Start_With(t *testing.T) {
func Test_It_Checks_All_Files_Names_In_A_Folder_Match_A_Regexp(t *testing.T) {
basePath, err := os.Getwd()
if err != nil {
t.Fatal(err)
Expand All @@ -65,18 +108,22 @@ func Test_It_Checks_All_Files_In_A_Folder_Start_With(t *testing.T) {
testCases := []struct {
desc string
folder string
regexp string
wantViolations []rule.Violation
}{
{
desc: "check that all files in a folder start with the given prefix when they do",
folder: filepath.Join(basePath, "test/project2"),
desc: "check that all files' names in a folder match a regex",
folder: filepath.Join(basePath, "test/project"),
regexp: "[a-zA-Z0-9]+",
wantViolations: nil,
},
{
desc: "check that all files in a folder start with the given prefix when they don't",
desc: "check that all files' names in a folder do not match a regex",
folder: filepath.Join(basePath, "test/project"),
regexp: "[0-9]+",
wantViolations: []rule.Violation{
rule.NewViolation("file's name 'Makefile' does not start with 'Docker'"),
rule.NewViolation("file's name 'Dockerfile' does not match regex '[0-9]+'"),
rule.NewViolation("file's name 'Makefile' does not match regex '[0-9]+'"),
},
},
}
Expand All @@ -85,11 +132,58 @@ func Test_It_Checks_All_Files_In_A_Folder_Start_With(t *testing.T) {
t.Run(tC.desc, func(t *testing.T) {
vs, errs := file.All().
That(ft.AreInFolder(tC.folder, false)).
Should(fs.StartWith("Docker")).
Should(fs.MatchRegex(tC.regexp)).
Because("testing reasons")

if !cmp.Equal(vs, tC.wantViolations, cmp.AllowUnexported(rule.Violation{}), cmpopts.EquateEmpty()) {
t.Errorf("Expected %v, got %v", tC.wantViolations, vs)
t.Errorf("Expected violations %v, got %v", tC.wantViolations, vs)
}

if errs != nil {
t.Errorf("Expected errs to be nil, got: %+v", errs)
}
})
}
}

func Test_It_Checks_All_Files_Paths_In_A_Folder_Match_A_Glob_Pattern(t *testing.T) {
basePath, err := os.Getwd()
if err != nil {
t.Fatal(err)
}

testCases := []struct {
desc string
folder string
glob string
wantViolations []rule.Violation
}{
{
desc: "check that all files' names in a folder match a glob pattern",
folder: filepath.Join(basePath, "test/project3"),
glob: "*/*/*.go",
wantViolations: nil,
},
{
desc: "check that all files' names in a folder do not match a glob pattern",
folder: filepath.Join(basePath, "test/project3"),
glob: "*/*/*.ts",
wantViolations: []rule.Violation{
rule.NewViolation("file's path 'baz.go' does not match glob pattern '*/*/*.ts'"),
rule.NewViolation("file's path 'quux.go' does not match glob pattern '*/*/*.ts'"),
},
},
}

for _, tC := range testCases {
t.Run(tC.desc, func(t *testing.T) {
vs, errs := file.All().
That(ft.AreInFolder(tC.folder, false)).
Should(fs.MatchGlob(tC.glob, basePath)).
Because("testing reasons")

if !cmp.Equal(vs, tC.wantViolations, cmp.AllowUnexported(rule.Violation{}), cmpopts.EquateEmpty()) {
t.Errorf("Expected violations %v, got %v", tC.wantViolations, vs)
}

if errs != nil {
Expand Down
73 changes: 73 additions & 0 deletions internal/arch/file/rule_set_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,76 @@ func Test_It_Checks_A_Set_Of_Files_Names_Matches_A_Regexp(t *testing.T) {
})
}
}

func Test_It_Checks_A_Set_Of_Files_Names_Matches_A_Glob_Pattern(t *testing.T) {
basePath, err := os.Getwd()
if err != nil {
t.Fatal(err)
}

testCases := []struct {
desc string
filenames []string
glob string
wantViolations []rule.Violation
}{
{
desc: "check that a set of files' names match a glob pattern when it's actually there",
filenames: []string{
filepath.Join(basePath, "test/project3/baz.go"),
filepath.Join(basePath, "test/project3/quux.go"),
},
glob: "*/*/*.go",
wantViolations: nil,
},
{
desc: "check that a set of files' names match a glob pattern when it's not actually there",
filenames: []string{
filepath.Join(basePath, "test/project3/baz.ts"),
filepath.Join(basePath, "test/project3/quux.ts"),
},
glob: "*/*/*.ts",
wantViolations: nil,
},
{
desc: "check that a set of files' names do not match a glob pattern when it's actually there",
filenames: []string{
filepath.Join(basePath, "test/project3/baz.go"),
filepath.Join(basePath, "test/project3/quux.go"),
},
glob: "*/*/*.ts",
wantViolations: []rule.Violation{
rule.NewViolation("file's path 'baz.go' does not match glob pattern '*/*/*.ts'"),
rule.NewViolation("file's path 'quux.go' does not match glob pattern '*/*/*.ts'"),
},
},
{
desc: "check that a set of files' names do not match a glob pattern when it's not actually there",
filenames: []string{
filepath.Join(basePath, "test/project3/baz.ts"),
filepath.Join(basePath, "test/project3/quux.ts"),
},
glob: "*/*/*.go",
wantViolations: []rule.Violation{
rule.NewViolation("file's path 'baz.ts' does not match glob pattern '*/*/*.go'"),
rule.NewViolation("file's path 'quux.ts' does not match glob pattern '*/*/*.go'"),
},
},
}

for _, tC := range testCases {
t.Run(tC.desc, func(t *testing.T) {
vs, errs := file.Set(tC.filenames...).
Should(fs.MatchGlob(tC.glob, basePath)).
Because("testing reasons")

if !cmp.Equal(vs, tC.wantViolations, cmp.AllowUnexported(rule.Violation{}), cmpopts.EquateEmpty()) {
t.Errorf("Expected violations %v, got %v", tC.wantViolations, vs)
}

if errs != nil {
t.Errorf("Expected errs to be nil, got: %+v", errs)
}
})
}
}
29 changes: 29 additions & 0 deletions internal/arch/file/should/match_glob.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package should

import (
"fmt"
"goarkitect/internal/arch/rule"
"path/filepath"
)

func MatchGlob(glob string, basePath string) *Expression {
return &Expression{
evaluate: func(rb rule.Builder, filePath string) bool {
match, err := filepath.Match(filepath.Join(basePath, glob), filePath)
if err != nil {
rb.AddError(err)
}

return !match
},
getViolation: func(filePath string) rule.Violation {
return rule.NewViolation(
fmt.Sprintf(
"file's path '%s' does not match glob pattern '%s'",
filepath.Base(filePath),
glob,
),
)
},
}
}
67 changes: 67 additions & 0 deletions internal/arch/file/should/match_glob_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package should_test

import (
"goarkitect/internal/arch/file"
"goarkitect/internal/arch/file/should"
"goarkitect/internal/arch/rule"
"os"
"path/filepath"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
)

func Test_MatchGlob(t *testing.T) {
basePath, err := os.Getwd()
if err != nil {
t.Fatal(err)
}

newRuleBuilder := func() *file.RuleBuilder {
rb := file.All()
rb.SetFiles([]string{
filepath.Join(basePath, "test/project3/baz.go"),
filepath.Join(basePath, "test/project3/quux.go"),
})
return rb
}

testCases := []struct {
desc string
ruleBuilder *file.RuleBuilder
glob string
want []rule.Violation
}{
{
desc: "project3 matches '*.go'",
ruleBuilder: newRuleBuilder(),
glob: "*/*/*.go",
want: nil,
},
{
desc: "project3 matches 'foo/*/*.go'",
ruleBuilder: newRuleBuilder(),
glob: "test/*/*.go",
want: nil,
},
{
desc: "project3 does not match '**/*.ts'",
ruleBuilder: newRuleBuilder(),
glob: "**/*.ts",
want: []rule.Violation{
rule.NewViolation("file's path 'baz.go' does not match glob pattern '**/*.ts'"),
rule.NewViolation("file's path 'quux.go' does not match glob pattern '**/*.ts'"),
},
},
}
for _, tC := range testCases {
t.Run(tC.desc, func(t *testing.T) {
mg := should.MatchGlob(tC.glob, basePath)
got := mg.Evaluate(tC.ruleBuilder)
if !cmp.Equal(got, tC.want, cmp.AllowUnexported(rule.Violation{}), cmpopts.EquateEmpty()) {
t.Errorf("want = %+v, got = %+v", tC.want, got)
}
})
}
}
5 changes: 5 additions & 0 deletions internal/arch/file/test/project3/baz.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package bar

func baz() string {
return "baz"
}
5 changes: 5 additions & 0 deletions internal/arch/file/test/project3/quux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package bar

func quux() string {
return "quux"
}

0 comments on commit 24e4062

Please sign in to comment.