Skip to content

Commit

Permalink
added size validator
Browse files Browse the repository at this point in the history
  • Loading branch information
ismailbayram committed Nov 13, 2023
1 parent b852531 commit aa0e4fb
Show file tree
Hide file tree
Showing 14 changed files with 174 additions and 7 deletions.
7 changes: 7 additions & 0 deletions .bigpicture.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@
"*_test.go"
]
}
},
{
"type": "size",
"args": {
"module": "/internal",
"max": 49.9
}
}
]
}
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ BigPicture allows you to define these rules in a `.bigpicture.json` file and val
- [FunctionValidator](#functionvalidator)
- [InstabilityValidator](#instabilityvalidator)
- [FileNameValidator](#filenamevalidator)
- [SizeValidator](#sizevalidator)
- [Contribution](#contribution)

# Installation
Expand Down Expand Up @@ -203,6 +204,19 @@ Checks if the package has files which do not match the given regular expression.
}
```

### SizeValidator
Checks the percentage size of the packages under the given directory according to the lines of code.

```json
{
"type": "size",
"args": {
"module": "/internal",
"max": 25
}
}
```


# Contribution
There are many ways in which you can participate in this project, for example:
Expand Down
2 changes: 2 additions & 0 deletions internal/browser/go.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,11 @@ func (b *GoBrowser) browse(parentPath string, parentNode *graph.Node) {
node := graph.NewNode(fName, path, graph.Dir, nil)
b.tree.Nodes[node.Path] = node
b.browse(path, node)
parentNode.LineCount += node.LineCount
} else if strings.HasSuffix(fName, ".go") {
node := b.parseFile(path, parentNode)
b.tree.Nodes[node.Path] = node
parentNode.LineCount += node.LineCount
}
}
}
Expand Down
14 changes: 13 additions & 1 deletion internal/browser/go_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ func TestGoBrowser_ParseFile(t *testing.T) {
assert.Equal(t, "/internal/config", node.ImportRaw[1])
assert.Equal(t, "/internal/graph", node.ImportRaw[2])
assert.Equal(t, "/internal/server", node.ImportRaw[3])

assert.Equal(t, 110, node.LineCount)
}

func TestGoBrowser_Browse(t *testing.T) {
Expand All @@ -55,6 +57,16 @@ func TestGoBrowser_browse(t *testing.T) {
).(*GoBrowser)

browser.browse("./internal/browser", browser.tree.Root)

assert.Equal(t, 9, len(browser.tree.Nodes))

browser = NewBrowser(
LangGo,
graph.NewTree("root"),
[]string{},
"/",
).(*GoBrowser)

browser.browse("./internal/config", browser.tree.Root)
assert.Equal(t, 3, len(browser.tree.Nodes))
assert.Equal(t, 94, browser.tree.Root.LineCount)
}
2 changes: 2 additions & 0 deletions internal/browser/java.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,11 @@ func (b *JavaBrowser) browse(parentPath string, parentNode *graph.Node) {
node := graph.NewNode(fName, path, graph.Dir, nil)
b.tree.Nodes[node.Path] = node
b.browse(path, node)
parentNode.LineCount += node.LineCount
} else if strings.HasSuffix(fName, ".java") {
node := b.parseFile(path, parentNode)
b.tree.Nodes[node.Path] = node
parentNode.LineCount += node.LineCount
}
}
}
Expand Down
1 change: 1 addition & 0 deletions internal/browser/java_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,5 @@ func TestJavaBrowser_browse(t *testing.T) {
browser.browse("src/main/com/shashi/service", browser.tree.Root)

assert.Equal(t, 8, len(browser.tree.Nodes))
assert.Equal(t, browser.tree.Root.LineCount, 493)
}
2 changes: 2 additions & 0 deletions internal/browser/python.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,11 @@ func (b *PythonBrowser) browse(parentPath string, parentNode *graph.Node) {
node := graph.NewNode(fName, path, graph.Dir, nil)
b.tree.Nodes[node.Path] = node
b.browse(path, node)
parentNode.LineCount += node.LineCount
} else if strings.HasSuffix(fName, ".py") {
node := b.parseFile(path, parentNode)
b.tree.Nodes[node.Path] = node
parentNode.LineCount += node.LineCount
}
}
}
Expand Down
1 change: 1 addition & 0 deletions internal/browser/python_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,5 @@ func TestPythonBrowser_browse(t *testing.T) {
browser.browse("base/", browser.tree.Root)

assert.Equal(t, 6, len(browser.tree.Nodes))
assert.Equal(t, browser.tree.Root.LineCount, 191)
}
2 changes: 1 addition & 1 deletion internal/validators/linecount.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func NewLineCountValidator(args map[string]any, tree *graph.Tree) (*LineCountVal

func (v *LineCountValidator) Validate() error {
for _, node := range v.tree.Nodes {
if isIgnored(v.args.Ignore, node.Path) {
if isIgnored(v.args.Ignore, node.Path) || node.Type == graph.Dir {
continue
}

Expand Down
10 changes: 5 additions & 5 deletions internal/validators/linecount_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ func TestNewLineCountValidator(t *testing.T) {

func TestLineCountValidator_Validate(t *testing.T) {
tree := graph.NewTree("root")
tree.Nodes["a"] = graph.NewNode("a", "a", graph.Dir, []string{})
tree.Nodes["b"] = graph.NewNode("b", "b", graph.Dir, []string{})
tree.Nodes["a"] = graph.NewNode("a", "a", graph.File, []string{})
tree.Nodes["b"] = graph.NewNode("b", "b", graph.File, []string{})
tree.Nodes["a"].LineCount = 100
tree.Nodes["b"].LineCount = 200

Expand All @@ -58,12 +58,12 @@ func TestLineCountValidator_Validate(t *testing.T) {
"browser/go",
})
tree.Nodes["config"] = graph.NewNode("config", "config", graph.Dir, []string{})
tree.Nodes["config/subconfig"] = graph.NewNode("subconfig", "config/subconfig", graph.Dir, []string{})
tree.Nodes["config/subconfig"] = graph.NewNode("subconfig", "config/subconfig", graph.File, []string{})
tree.Nodes["config/subconfig"].LineCount = 200
tree.Nodes["browser"] = graph.NewNode("browser", "browser", graph.Dir, []string{
tree.Nodes["browser"] = graph.NewNode("browser", "browser", graph.File, []string{
"config/subconfig",
})
tree.Nodes["browser/go"] = graph.NewNode("go", "browser/go", graph.Dir, []string{
tree.Nodes["browser/go"] = graph.NewNode("go", "browser/go", graph.File, []string{
"config/subconfig",
})

Expand Down
62 changes: 62 additions & 0 deletions internal/validators/size.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package validators

import (
"fmt"
"github.com/ismailbayram/bigpicture/internal/graph"
"strings"
)

type SizeValidatorArgs struct {
Module string `json:"module" validate:"required=true"`
Max float64 `json:"max" validate:"required=true,min=1"`
Ignore []string `json:"ignore"`
}

type SizeValidator struct {
args *SizeValidatorArgs
tree *graph.Tree
}

func NewSizeValidator(args map[string]any, tree *graph.Tree) (*SizeValidator, error) {
validatorArgs := &SizeValidatorArgs{}
if err := validateArgs(args, validatorArgs); err != nil {
return nil, err
}

if len(validatorArgs.Module) > 1 && strings.HasSuffix(validatorArgs.Module, "/*") {
validatorArgs.Module = validatorArgs.Module[:len(validatorArgs.Module)-2]
}

module, err := validatePath(validatorArgs.Module, tree)
if err != nil {
return nil, err
}
validatorArgs.Module = module

return &SizeValidator{
args: validatorArgs,
tree: tree,
}, nil
}

func (v *SizeValidator) Validate() error {
totalSize := v.tree.Nodes[v.args.Module].LineCount

for _, node := range v.tree.Nodes {
if isIgnored(v.args.Ignore, node.Path) || node.Type == graph.File {
continue
}

nodeSizePercent := float64(node.LineCount) / float64(totalSize) * 100

if node.Parent == v.args.Module && nodeSizePercent > v.args.Max {
return fmt.Errorf(
"Size of module '%s' is %.2f%%, but maximum allowed is %.2f%%",
node.Path,
nodeSizePercent,
v.args.Max,
)
}
}
return nil
}
58 changes: 58 additions & 0 deletions internal/validators/size_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package validators

import (
"github.com/ismailbayram/bigpicture/internal/graph"
"github.com/stretchr/testify/assert"
"testing"
)

func TestNewSizeValidator(t *testing.T) {
tree := graph.NewTree("root")
tree.Nodes["a"] = graph.NewNode("a", "a", graph.Dir, []string{})
tree.Nodes["b"] = graph.NewNode("b", "b", graph.Dir, []string{})
tree.Nodes["a"].LineCount = 100
tree.Nodes["b"].LineCount = 200

args := map[string]any{}
_, err := NewSizeValidator(args, nil)
assert.Equal(t, "module is required and must be string", err.Error())

args = map[string]any{"module": "a"}
_, err = NewSizeValidator(args, nil)
assert.Equal(t, "max is required and must be float64", err.Error())

args = map[string]any{"module": "a", "max": "wrong"}
_, err = NewSizeValidator(args, nil)
assert.Equal(t, "max is required and must be float64", err.Error())

args = map[string]any{"module": "wrong", "max": float64(100)}
_, err = NewSizeValidator(args, tree)
assert.Equal(t, "'wrong' is not a valid module. Path should start with /", err.Error())

args = map[string]any{"module": "a", "max": float64(100)}
validator, err := NewSizeValidator(args, tree)
assert.Nil(t, err)
assert.Equal(t, "a", validator.args.Module)
assert.Equal(t, float64(100), validator.args.Max)
}

func TestSizeValidator_Validate(t *testing.T) {
tree := graph.NewTree("root")
tree.Nodes["."].LineCount = 600
tree.Nodes["/dir1"] = graph.NewNode("dir1", "/dir1", graph.Dir, []string{})
tree.Nodes["/dir1"].LineCount = 100
tree.Nodes["/dir2"] = graph.NewNode("dir2", "/dir2", graph.Dir, []string{})
tree.Nodes["/dir2"].LineCount = 200
tree.Nodes["/dir3"] = graph.NewNode("dir3", "/dir3", graph.Dir, []string{})
tree.Nodes["/dir3"].LineCount = 300

args := map[string]any{"module": ".", "max": float64(40)}
validator, _ := NewSizeValidator(args, tree)
err := validator.Validate()
assert.Equal(t, "Size of module '/dir3' is 50.00%, but maximum allowed is 40.00%", err.Error())

args = map[string]any{"module": ".", "max": float64(50)}
validator, _ = NewSizeValidator(args, tree)
err = validator.Validate()
assert.Nil(t, err)
}
2 changes: 2 additions & 0 deletions internal/validators/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ func NewValidator(t string, args map[string]any, tree *graph.Tree) (Validator, e
return NewFunctionValidator(args, tree)
case "file_name":
return NewFileNameValidator(args, tree)
case "size":
return NewSizeValidator(args, tree)
default:
return nil, fmt.Errorf("unknown validator type: %s", t)
}
Expand Down
4 changes: 4 additions & 0 deletions internal/validators/validators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ func TestNewValidator(t *testing.T) {
assert.Nil(t, err)
assert.IsType(t, &FileNameValidator{}, validator)

validator, err = NewValidator("size", map[string]any{"module": "a", "max": float64(10)}, tree)
assert.Nil(t, err)
assert.IsType(t, &SizeValidator{}, validator)

validator, err = NewValidator("unknown", map[string]any{}, tree)
assert.NotNil(t, err)
assert.Nil(t, validator)
Expand Down

0 comments on commit aa0e4fb

Please sign in to comment.