Skip to content

Commit

Permalink
feat: implement basic file builder functionalities
Browse files Browse the repository at this point in the history
  • Loading branch information
omissis committed Aug 8, 2022
1 parent 9532210 commit c0bb128
Show file tree
Hide file tree
Showing 38 changed files with 928 additions and 291 deletions.
4 changes: 3 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
module goarkitect

go 1.17
go 1.18

require github.com/google/go-cmp v0.5.8
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
23 changes: 0 additions & 23 deletions internal/arch/expression.go

This file was deleted.

26 changes: 26 additions & 0 deletions internal/arch/file/except/except.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package except

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

type Expression struct {
value string
}

func (e Expression) Evaluate(rb rule.Builder) {
frb := rb.(*file.RuleBuilder)

nf := make([]string, 0)
for _, f := range frb.GetFiles() {
if filepath.Base(f) != e.value {
nf = append(nf, f)
}
}

frb.SetFiles(nf)

return
}
7 changes: 7 additions & 0 deletions internal/arch/file/except/this.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package except

func This(value string) *Expression {
return &Expression{
value: value,
}
}
3 changes: 3 additions & 0 deletions internal/arch/file/except/this_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package except_test

// TODO: implement this
96 changes: 96 additions & 0 deletions internal/arch/file/rule.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package file

import (
"goarkitect/internal/arch/rule"
)

func All() *RuleBuilder {
return NewRuleBuilder().AllFiles()
}

func One(filename string) *RuleBuilder {
return NewRuleBuilder().File(filename)
}

func NewRuleBuilder() *RuleBuilder {
return &RuleBuilder{}
}

type RuleBuilder struct {
thats []rule.That
excepts []rule.Except
shoulds []rule.Should
because rule.Because
Violations []rule.Violation

files []string
}

func (rb *RuleBuilder) That(t rule.That) rule.Builder {
rb.thats = []rule.That{t}

return rb
}

func (rb *RuleBuilder) AndThat(t rule.That) rule.Builder {
rb.thats = append(rb.thats, t)

return rb
}

func (rb *RuleBuilder) Except(s ...rule.Except) rule.Builder {
rb.excepts = s

return rb
}

func (rb *RuleBuilder) Should(e rule.Should) rule.Builder {
rb.shoulds = []rule.Should{e}

return rb
}

func (rb *RuleBuilder) AndShould(e rule.Should) rule.Builder {
rb.shoulds = append(rb.shoulds, e)

return rb
}

func (rb *RuleBuilder) Because(b rule.Because) []rule.Violation {
rb.because = b

for _, that := range rb.thats {
that.Evaluate(rb)
}

for _, except := range rb.excepts {
except.Evaluate(rb)
}

for _, should := range rb.shoulds {
rb.Violations = should.Evaluate(rb)
if len(rb.Violations) > 0 {
return rb.Violations
}
}

return nil
}

func (rb *RuleBuilder) GetFiles() []string {
return rb.files
}

func (rb *RuleBuilder) SetFiles(files []string) {
rb.files = files
}

func (rb *RuleBuilder) AllFiles() *RuleBuilder {
return rb
}

func (rb *RuleBuilder) File(filename string) *RuleBuilder {
rb.files = []string{filename}

return rb
}
93 changes: 93 additions & 0 deletions internal/arch/file/rule_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package file_test

import (
"goarkitect/internal/arch/file"
fe "goarkitect/internal/arch/file/except"
fs "goarkitect/internal/arch/file/should"
ft "goarkitect/internal/arch/file/that"
"os"
"path/filepath"
"testing"
)

func Test_It_Checks_A_File_Exists(t *testing.T) {
filename := "./test/project/Makefile"

vs := file.One(filename).
Should(fs.Exist()).
Because("it is needed to encapsulate common project operations")

if vs != nil {
for _, v := range vs {
t.Errorf("%v", v)
}
}
}

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

vs := file.All().
That(ft.AreInFolder(filepath.Join(basePath, "test/project"), false)).
Should(fs.Exist()).
AndShould(fs.EndWith("file")).
Because("they are needed for developing and deploying the project")

if vs != nil {
for _, v := range vs {
t.Errorf("%v", v)
}
}
}

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

vs := file.All().
That(ft.AreInFolder(filepath.Join(basePath, "test/project"), false)).
Should(fs.Exist()).
AndShould(fs.EndWith(".yaml")).
Because("they are needed for developing and deploying the project")

if vs == nil {
t.Errorf("Expected violations, got nil")
}

if len(vs) != 2 {
t.Errorf("Expected 2 violations, got %d", len(vs))
}

if vs[0].String() != "file's name 'Dockerfile' does not end with '.yaml'" {
t.Errorf("Expected violation for Dockerfile, got: '%s'", vs[0].String())
}

if vs[1].String() != "file's name 'Makefile' does not end with '.yaml'" {
t.Errorf("Expected violation for Makefile, got: '%s'", vs[1].String())
}
}

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

vs := file.All().
That(ft.AreInFolder(filepath.Join(basePath, "test/project"), false)).
Should(fs.Exist()).
AndShould(fs.StartWith("Docker")).
Except(fe.This("Makefile"), fe.This("Something")).
Because("they are needed for developing and deploying the project")

if vs != nil {
for _, v := range vs {
t.Errorf("%v", v)
}
}
}
30 changes: 30 additions & 0 deletions internal/arch/file/should/end_with.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package should

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

func EndWith(suffix string) *Expression {
ls := len(suffix)

return &Expression{
checkViolation: func(filePath string) bool {
fileName := filepath.Base(filePath)

lf := len(fileName)

return ls <= lf && fileName[lf-ls:] != suffix
},
getViolation: func(filePath string) rule.Violation {
return rule.NewViolation(
fmt.Sprintf(
"file's name '%s' does not end with '%s'",
filepath.Base(filePath),
suffix,
),
)
},
}
}
44 changes: 44 additions & 0 deletions internal/arch/file/should/end_with_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package should_test

import (
"goarkitect/internal/arch/file"
"goarkitect/internal/arch/file/should"
"goarkitect/internal/arch/rule"
"testing"

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

func Test_EndWith(t *testing.T) {
testCases := []struct {
desc string
ruleBuilder *file.RuleBuilder
suffix string
want []rule.Violation
}{
{
desc: "foobar ends with bar",
ruleBuilder: file.One("foobar"),
suffix: "bar",
want: nil,
},
{
desc: "foobar does not end with baz",
ruleBuilder: file.One("foobar"),
suffix: "baz",
want: []rule.Violation{
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)
}
})
}
}
32 changes: 32 additions & 0 deletions internal/arch/file/should/exist.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package should

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

func Exist() *Expression {
return &Expression{
checkViolation: func(filePath string) bool {
if _, err := os.Stat(filePath); err != nil {
if os.IsNotExist(err) {
return true
}

panic(err)
}

return false
},
getViolation: func(filePath string) rule.Violation {
return rule.NewViolation(
fmt.Sprintf(
"file '%s' does not exist",
filepath.Base(filePath),
),
)
},
}
}
Loading

0 comments on commit c0bb128

Please # to comment.