Skip to content

Commit

Permalink
Add HasVersion interface and linter
Browse files Browse the repository at this point in the history
  • Loading branch information
jwillp committed Aug 22, 2024
1 parent 782d328 commit b616316
Show file tree
Hide file tree
Showing 3 changed files with 155 additions and 1 deletion.
37 changes: 37 additions & 0 deletions specversion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package specter

import "fmt"

type SpecificationVersion string

type HasVersion interface {
Specification

Version() SpecificationVersion
}

func HasVersionMustHaveAVersionLinter(severity LinterResultSeverity) SpecificationLinter {
return SpecificationLinterFunc(func(specifications SpecificationGroup) LinterResultSet {
var r LinterResultSet
specs := specifications.Select(func(s Specification) bool {
if _, ok := s.(HasVersion); ok {
return true
}

return false
})

for _, spec := range specs {
s := spec.(HasVersion)
if s.Version() != "" {
continue
}

r = append(r, LinterResult{
Severity: severity,
Message: fmt.Sprintf("specification %q at %q should have a version", spec.Name(), spec.Source().Location),
})
}
return r
})
}
115 changes: 115 additions & 0 deletions specversion_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package specter

import (
"github.com/stretchr/testify/assert"
"testing"
)

// Mock implementations for the Specification and HasVersion interfaces

var _ Specification = (*mockSpecification)(nil)

type mockSpecification struct {
name SpecificationName
description string
source Source
version SpecificationVersion
typeName SpecificationType
}

func (m *mockSpecification) Name() SpecificationName {
return m.name
}

func (m *mockSpecification) Type() SpecificationType {
return m.typeName
}

func (m *mockSpecification) Description() string {
return m.description
}

func (m *mockSpecification) SetSource(s Source) {
m.source = s
}

func (m *mockSpecification) Source() Source {
return m.source
}

func (m *mockSpecification) Version() SpecificationVersion {
return m.version
}

func TestHasVersionMustHaveAVersionLinter(t *testing.T) {
tests := []struct {
name string
given SpecificationGroup
expectedResults LinterResultSet
severity LinterResultSeverity
}{
{
name: "GIVEN all specifications have a version THEN return no warnings or errors",
given: SpecificationGroup{
&mockSpecification{name: "spec1", version: "v1"},
&mockSpecification{name: "spec2", version: "v2"},
},
severity: WarningSeverity,
expectedResults: LinterResultSet(nil),
},
{
name: "GIVEN one specification is missing a version and severity is Warning THEN return a warning",
given: SpecificationGroup{
&mockSpecification{name: "spec1", version: "v1"},
&mockSpecification{name: "spec2", version: ""},
},
severity: WarningSeverity,
expectedResults: LinterResultSet{
{
Severity: WarningSeverity,
Message: `specification "spec2" at "" should have a version`,
},
},
},
{
name: "GIVEN one specification is missing a version and severity is error THEN return an error",
given: SpecificationGroup{
&mockSpecification{name: "spec1", version: "v1"},
&mockSpecification{name: "spec2", version: ""},
},
severity: ErrorSeverity,
expectedResults: LinterResultSet{
{
Severity: ErrorSeverity,
Message: `specification "spec2" at "" should have a version`,
},
},
},
{
name: "multiple specifications are missing versions",
given: SpecificationGroup{
&mockSpecification{name: "spec1", version: ""},
&mockSpecification{name: "spec2", version: ""},
},
severity: ErrorSeverity,
expectedResults: LinterResultSet{
{
Severity: ErrorSeverity,
Message: `specification "spec1" at "" should have a version`,
},
{
Severity: ErrorSeverity,
Message: `specification "spec2" at "" should have a version`,
},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
linter := HasVersionMustHaveAVersionLinter(tt.severity)
results := linter.Lint(tt.given)
assert.Equal(t, tt.expectedResults, results)
})
}
}
4 changes: 3 additions & 1 deletion util.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package specter

import "context"
import (
"context"
)

// CheckContextDone checks if the context has been canceled or timed out.
// If the context is done, it returns the context error, which can be either
Expand Down

0 comments on commit b616316

Please sign in to comment.