diff --git a/pkg/specter/artifactproc.go b/pkg/specter/artifactproc.go index 6d8c18d..014e593 100644 --- a/pkg/specter/artifactproc.go +++ b/pkg/specter/artifactproc.go @@ -1,3 +1,17 @@ +// Copyright 2024 Morébec +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package specter import ( @@ -81,9 +95,9 @@ func (n ProcessorArtifactRegistry) FindAll() ([]ArtifactRegistryEntry, error) { type ArtifactProcessingContext struct { context.Context - Specifications SpecificationGroup - Artifacts []Artifact - Logger Logger + Units UnitGroup + Artifacts []Artifact + Logger Logger ArtifactRegistry ProcessorArtifactRegistry processorName string diff --git a/pkg/specter/artifactproc_fileartifact.go b/pkg/specter/artifactproc_fileartifact.go index 60afa41..c253e78 100644 --- a/pkg/specter/artifactproc_fileartifact.go +++ b/pkg/specter/artifactproc_fileartifact.go @@ -39,7 +39,7 @@ const DefaultWriteMode WriteMode = WriteOnceMode var _ Artifact = (*FileArtifact)(nil) -// FileArtifact is a data structure that can be used by a SpecificationProcessor to generate file artifacts +// FileArtifact is a data structure that can be used by a UnitProcessor to generate file artifacts // that can be written by the FileArtifactProcessor. type FileArtifact struct { Path string diff --git a/pkg/specter/assembly.go b/pkg/specter/assembly.go index 795e90a..5e2aad0 100644 --- a/pkg/specter/assembly.go +++ b/pkg/specter/assembly.go @@ -47,15 +47,15 @@ func WithSourceLoaders(loaders ...SourceLoader) PipelineOption { } } -// WithLoaders configures the SpecificationLoader of a Pipeline instance. -func WithLoaders(loaders ...SpecificationLoader) PipelineOption { +// WithLoaders configures the UnitLoader of a Pipeline instance. +func WithLoaders(loaders ...UnitLoader) PipelineOption { return func(s *Pipeline) { s.Loaders = append(s.Loaders, loaders...) } } -// WithProcessors configures the SpecProcess of a Pipeline instance. -func WithProcessors(processors ...SpecificationProcessor) PipelineOption { +// WithProcessors configures the UnitProcess of a Pipeline instance. +func WithProcessors(processors ...UnitProcessor) PipelineOption { return func(s *Pipeline) { s.Processors = append(s.Processors, processors...) } diff --git a/pkg/specter/assembly_test.go b/pkg/specter/assembly_test.go index 940a802..31de00f 100644 --- a/pkg/specter/assembly_test.go +++ b/pkg/specter/assembly_test.go @@ -34,7 +34,7 @@ func TestWithSourceLoaders(t *testing.T) { } func TestWithLoaders(t *testing.T) { - loader := &specterutils.HCLGenericSpecLoader{} + loader := &specterutils.HCLGenericUnitLoader{} s := NewPipeline(WithLoaders(loader)) require.Contains(t, s.Loaders, loader) } diff --git a/pkg/specter/common.go b/pkg/specter/common.go index 11a31b3..63c1f61 100644 --- a/pkg/specter/common.go +++ b/pkg/specter/common.go @@ -1,8 +1,22 @@ +// Copyright 2024 Morébec +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package specter type ArtifactID string -// Artifact represents a result or output generated by a SpecificationProcessor. +// Artifact represents a result or output generated by a UnitProcessor. // An artifact is a unit of data or information produced as part of the processing workflow. // It can be a transient, in-memory object, or it might represent more permanent entities such as // files on disk, records in a database, deployment units, or other forms of data artifacts. diff --git a/pkg/specter/pipeline.go b/pkg/specter/pipeline.go index 1cf87b1..8587102 100644 --- a/pkg/specter/pipeline.go +++ b/pkg/specter/pipeline.go @@ -32,15 +32,15 @@ const RunThrough RunMode = "run-through" const defaultRunMode = PreviewMode const SourceLoadingFailedErrorCode = "specter.source_loading_failed" -const SpecificationLoadingFailedErrorCode = "specter.specification_loading_failed" -const SpecificationProcessingFailedErrorCode = "specter.specification_processing_failed" +const UnitLoadingFailedErrorCode = "specter.unit_loading_failed" +const UnitProcessingFailedErrorCode = "specter.unit_processing_failed" const ArtifactProcessingFailedErrorCode = "specter.artifact_processing_failed" // Pipeline is the service responsible to run a specter pipeline. type Pipeline struct { SourceLoaders []SourceLoader - Loaders []SpecificationLoader - Processors []SpecificationProcessor + Loaders []UnitLoader + Processors []UnitProcessor ArtifactProcessors []ArtifactProcessor ArtifactRegistry ArtifactRegistry Logger Logger @@ -53,7 +53,7 @@ type PipelineResult struct { SourceLocations []string Sources []Source - Specifications []Specification + Units []Unit Artifacts []Artifact RunMode RunMode } @@ -92,18 +92,18 @@ func (p Pipeline) Run(ctx context.Context, sourceLocations []string, runMode Run return result, e } - // Load Specifications - result.Specifications, err = p.loadSpecifications(ctx, result.Sources) + // Load Units + result.Units, err = p.loadUnits(ctx, result.Sources) if err != nil { - e := errors.WrapWithMessage(err, SpecificationLoadingFailedErrorCode, "failed loading specifications") + e := errors.WrapWithMessage(err, UnitLoadingFailedErrorCode, "failed loading units") p.Logger.Error(e.Error()) return result, e } - // Process Specifications - result.Artifacts, err = p.processSpecifications(ctx, result.Specifications) + // Process Units + result.Artifacts, err = p.processUnits(ctx, result.Units) if err != nil { - e := errors.WrapWithMessage(err, SpecificationProcessingFailedErrorCode, "failed processing specifications") + e := errors.WrapWithMessage(err, UnitProcessingFailedErrorCode, "failed processing units") p.Logger.Error(e.Error()) return result, e } @@ -114,7 +114,7 @@ func (p Pipeline) Run(ctx context.Context, sourceLocations []string, runMode Run } // Process Artifact - if err = p.processArtifacts(ctx, result.Specifications, result.Artifacts); err != nil { + if err = p.processArtifacts(ctx, result.Units, result.Artifacts); err != nil { e := errors.WrapWithMessage(err, ArtifactProcessingFailedErrorCode, "failed processing artifacts") p.Logger.Error(e.Error()) return result, e @@ -131,7 +131,7 @@ func (p Pipeline) logResult(run PipelineResult) { p.Logger.Info(fmt.Sprintf("Run time: %s", run.ExecutionTime())) p.Logger.Info(fmt.Sprintf("Number of source locations: %d", len(run.SourceLocations))) p.Logger.Info(fmt.Sprintf("Number of sources: %d", len(run.Sources))) - p.Logger.Info(fmt.Sprintf("Number of specifications: %d", len(run.Specifications))) + p.Logger.Info(fmt.Sprintf("Number of units: %d", len(run.Units))) p.Logger.Info(fmt.Sprintf("Number of artifacts: %d", len(run.Artifacts))) } @@ -171,12 +171,12 @@ func (p Pipeline) loadSources(ctx context.Context, sourceLocations []string) ([] return sources, errors.GroupOrNil(errs) } -// loadSpecifications performs the loading of Specifications. -func (p Pipeline) loadSpecifications(ctx context.Context, sources []Source) ([]Specification, error) { - p.Logger.Info("\nLoading specifications ...") +// loadUnits performs the loading of Units. +func (p Pipeline) loadUnits(ctx context.Context, sources []Source) ([]Unit, error) { + p.Logger.Info("\nLoading units ...") - // Load specifications - var specifications []Specification + // Load units + var units []Unit var sourcesNotLoaded []Source errs := errors.NewGroup(errors.InternalErrorCode) @@ -190,14 +190,14 @@ func (p Pipeline) loadSpecifications(ctx context.Context, sources []Source) ([]S continue } - loadedSpecs, err := l.Load(src) + loadedUnits, err := l.Load(src) if err != nil { p.Logger.Error(err.Error()) errs = errs.Append(err) continue } - specifications = append(specifications, loadedSpecs...) + units = append(units, loadedUnits...) wasLoaded = true } @@ -211,24 +211,24 @@ func (p Pipeline) loadSpecifications(ctx context.Context, sources []Source) ([]S p.Logger.Warning(fmt.Sprintf("%q could not be loaded.", src)) } - p.Logger.Warning("%d specifications were not loaded.") + p.Logger.Warning("%d units were not loaded.") } - p.Logger.Info(fmt.Sprintf("%d specifications loaded.", len(specifications))) + p.Logger.Info(fmt.Sprintf("%d units loaded.", len(units))) - return specifications, errors.GroupOrNil(errs) + return units, errors.GroupOrNil(errs) } -// processSpecifications sends the specifications to processors. -func (p Pipeline) processSpecifications(ctx context.Context, specs []Specification) ([]Artifact, error) { +// processUnits sends the units to processors. +func (p Pipeline) processUnits(ctx context.Context, units []Unit) ([]Artifact, error) { pctx := ProcessingContext{ - Context: ctx, - Specifications: specs, - Artifacts: nil, - Logger: p.Logger, + Context: ctx, + Units: units, + Artifacts: nil, + Logger: p.Logger, } - p.Logger.Info("\nProcessing specifications ...") + p.Logger.Info("\nProcessing units ...") for _, processor := range p.Processors { if err := ctx.Err(); err != nil { return nil, err @@ -245,12 +245,12 @@ func (p Pipeline) processSpecifications(ctx context.Context, specs []Specificati p.Logger.Info(fmt.Sprintf("-> %s", o.ID())) } - p.Logger.Success("Specifications processed successfully.") + p.Logger.Success("Units processed successfully.") return pctx.Artifacts, nil } // processArtifacts sends a list of ProcessingArtifacts to the registered ArtifactProcessors. -func (p Pipeline) processArtifacts(ctx context.Context, specifications []Specification, artifacts []Artifact) error { +func (p Pipeline) processArtifacts(ctx context.Context, units []Unit, artifacts []Artifact) error { if p.ArtifactRegistry == nil { p.ArtifactRegistry = &InMemoryArtifactRegistry{} } @@ -273,10 +273,10 @@ func (p Pipeline) processArtifacts(ctx context.Context, specifications []Specifi processorName := processor.Name() artifactCtx := ArtifactProcessingContext{ - Context: ctx, - Specifications: specifications, - Artifacts: artifacts, - Logger: p.Logger, + Context: ctx, + Units: units, + Artifacts: artifacts, + Logger: p.Logger, ArtifactRegistry: ProcessorArtifactRegistry{ processorName: processorName, registry: p.ArtifactRegistry, diff --git a/pkg/specter/pipeline_test.go b/pkg/specter/pipeline_test.go index 2a53069..2d557af 100644 --- a/pkg/specter/pipeline_test.go +++ b/pkg/specter/pipeline_test.go @@ -31,7 +31,7 @@ func TestRunResult_ExecutionTime(t *testing.T) { require.Equal(t, r.ExecutionTime(), time.Hour*1) } -func TestSpecter_Run(t *testing.T) { +func TestUnitter_Run(t *testing.T) { testDay := time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC) type given struct { @@ -71,12 +71,12 @@ func TestSpecter_Run(t *testing.T) { }, then: then{ expectedRunResult: PipelineResult{ - RunMode: PreviewMode, - Sources: nil, - Specifications: nil, - Artifacts: nil, - StartedAt: testDay, - EndedAt: testDay, + RunMode: PreviewMode, + Sources: nil, + Units: nil, + Artifacts: nil, + StartedAt: testDay, + EndedAt: testDay, }, expectedError: assert.NoError, }, @@ -97,12 +97,12 @@ func TestSpecter_Run(t *testing.T) { }, then: then{ expectedRunResult: PipelineResult{ - RunMode: PreviewMode, - Sources: nil, - Specifications: nil, - Artifacts: nil, - StartedAt: testDay, - EndedAt: testDay, + RunMode: PreviewMode, + Sources: nil, + Units: nil, + Artifacts: nil, + StartedAt: testDay, + EndedAt: testDay, }, expectedError: assert.NoError, }, @@ -123,12 +123,12 @@ func TestSpecter_Run(t *testing.T) { }, then: then{ expectedRunResult: PipelineResult{ - RunMode: PreviewMode, - Sources: nil, - Specifications: nil, - Artifacts: nil, - StartedAt: testDay, - EndedAt: testDay, + RunMode: PreviewMode, + Sources: nil, + Units: nil, + Artifacts: nil, + StartedAt: testDay, + EndedAt: testDay, }, expectedError: assert.NoError, }, diff --git a/pkg/specter/specloading.go b/pkg/specter/specloading.go index 5a6be93..5ea2d70 100644 --- a/pkg/specter/specloading.go +++ b/pkg/specter/specloading.go @@ -14,56 +14,56 @@ package specter -// UnsupportedSourceErrorCode ErrorSeverity code returned by a SpecificationLoader when a given loader does not support a certain source. +// UnsupportedSourceErrorCode ErrorSeverity code returned by a UnitLoader when a given loader does not support a certain source. const UnsupportedSourceErrorCode = "specter.spec_loading.unsupported_source" -// SpecificationLoader is a service responsible for loading Specifications from Sources. -type SpecificationLoader interface { - // Load loads a slice of Specification from a Source, or returns an error if it encountered a failure. - Load(s Source) ([]Specification, error) +// UnitLoader is a service responsible for loading Units from Sources. +type UnitLoader interface { + // Load loads a slice of Unit from a Source, or returns an error if it encountered a failure. + Load(s Source) ([]Unit, error) // SupportsSource indicates if this loader supports a certain source or not. SupportsSource(s Source) bool } -type SpecificationType string +type UnitType string -type SpecificationName string +type UnitName string -// Specification is a general purpose data structure to represent a specification as loaded from a file regardless of the loader +// Unit is a general purpose data structure to represent a unit as loaded from a file regardless of the loader // used. -// It is the responsibility of the application using specter to convert a specification to an appropriate data structure representing the intent of a -// given Specification. -type Specification interface { - // Name returns the unique Name of this specification. - Name() SpecificationName +// It is the responsibility of the application using specter to convert a unit to an appropriate data structure representing the intent of a +// given Unit. +type Unit interface { + // Name returns the unique Name of this unit. + Name() UnitName - // Type returns the type of this specification. - Type() SpecificationType + // Type returns the type of this unit. + Type() UnitType - // Description of this specification. + // Description of this unit. Description() string - // Source returns the source of this specification. + // Source returns the source of this unit. Source() Source - // SetSource sets the source of the specification. + // SetSource sets the source of the unit. // This method should only be used by loaders. SetSource(s Source) } -// SpecificationGroup Represents a list of Specification. -type SpecificationGroup []Specification +// UnitGroup Represents a list of Unit. +type UnitGroup []Unit -func NewSpecGroup(s ...Specification) SpecificationGroup { - g := SpecificationGroup{} +func NewUnitGroup(s ...Unit) UnitGroup { + g := UnitGroup{} return append(g, s...) } // Merge Allows merging a group with another one. -func (g SpecificationGroup) Merge(group SpecificationGroup) SpecificationGroup { +func (g UnitGroup) Merge(group UnitGroup) UnitGroup { merged := g - typeNameIndex := map[SpecificationName]any{} + typeNameIndex := map[UnitName]any{} for _, s := range g { typeNameIndex[s.Name()] = nil } @@ -77,9 +77,9 @@ func (g SpecificationGroup) Merge(group SpecificationGroup) SpecificationGroup { return merged } -// Select allows filtering the group for certain specifications. -func (g SpecificationGroup) Select(p func(s Specification) bool) SpecificationGroup { - r := SpecificationGroup{} +// Select allows filtering the group for certain units. +func (g UnitGroup) Select(p func(s Unit) bool) UnitGroup { + r := UnitGroup{} for _, s := range g { if p(s) { r = append(r, s) @@ -89,13 +89,13 @@ func (g SpecificationGroup) Select(p func(s Specification) bool) SpecificationGr return r } -func (g SpecificationGroup) SelectType(t SpecificationType) SpecificationGroup { - return g.Select(func(s Specification) bool { +func (g UnitGroup) SelectType(t UnitType) UnitGroup { + return g.Select(func(s Unit) bool { return s.Type() == t }) } -func (g SpecificationGroup) SelectName(t SpecificationName) Specification { +func (g UnitGroup) SelectName(t UnitName) Unit { for _, s := range g { if s.Name() == t { return s @@ -105,8 +105,8 @@ func (g SpecificationGroup) SelectName(t SpecificationName) Specification { return nil } -func (g SpecificationGroup) SelectNames(names ...SpecificationName) SpecificationGroup { - return g.Select(func(s Specification) bool { +func (g UnitGroup) SelectNames(names ...UnitName) UnitGroup { + return g.Select(func(s Unit) bool { for _, name := range names { if s.Name() == name { return true @@ -116,8 +116,8 @@ func (g SpecificationGroup) SelectNames(names ...SpecificationName) Specificatio }) } -func (g SpecificationGroup) Exclude(p func(s Specification) bool) SpecificationGroup { - r := SpecificationGroup{} +func (g UnitGroup) Exclude(p func(s Unit) bool) UnitGroup { + r := UnitGroup{} for _, s := range g { if !p(s) { r = append(r, s) @@ -127,14 +127,14 @@ func (g SpecificationGroup) Exclude(p func(s Specification) bool) SpecificationG return r } -func (g SpecificationGroup) ExcludeType(t SpecificationType) SpecificationGroup { - return g.Exclude(func(s Specification) bool { +func (g UnitGroup) ExcludeType(t UnitType) UnitGroup { + return g.Exclude(func(s Unit) bool { return s.Type() == t }) } -func (g SpecificationGroup) ExcludeNames(names ...SpecificationName) SpecificationGroup { - return g.Exclude(func(s Specification) bool { +func (g UnitGroup) ExcludeNames(names ...UnitName) UnitGroup { + return g.Exclude(func(s Unit) bool { for _, name := range names { if s.Name() == name { return true @@ -144,8 +144,8 @@ func (g SpecificationGroup) ExcludeNames(names ...SpecificationName) Specificati }) } -// MapSpecGroup performs a map operation on a SpecificationGroup -func MapSpecGroup[T any](g SpecificationGroup, p func(s Specification) T) []T { +// MapUnitGroup performs a map operation on a UnitGroup +func MapUnitGroup[T any](g UnitGroup, p func(s Unit) T) []T { var mapped []T for _, s := range g { mapped = append(mapped, p(s)) diff --git a/pkg/specter/specloading_test.go b/pkg/specter/specloading_test.go index 6ac1a1e..020cd7a 100644 --- a/pkg/specter/specloading_test.go +++ b/pkg/specter/specloading_test.go @@ -21,37 +21,37 @@ import ( "testing" ) -// Test cases for NewSpecGroup -func TestNewSpecGroup(t *testing.T) { +// Test cases for NewUnitGroup +func TestNewUnitGroup(t *testing.T) { tests := []struct { name string - given []Specification - when func() SpecificationGroup - then func(SpecificationGroup) bool + given []Unit + when func() UnitGroup + then func(UnitGroup) bool }{ { - name: "GIVEN no specifications WHEN calling NewSpecGroup THEN return an empty group", - given: []Specification{}, - when: func() SpecificationGroup { - return NewSpecGroup() + name: "GIVEN no units WHEN calling NewUnitGroup THEN return an empty group", + given: []Unit{}, + when: func() UnitGroup { + return NewUnitGroup() }, - then: func(result SpecificationGroup) bool { + then: func(result UnitGroup) bool { return len(result) == 0 }, }, { - name: "GIVEN multiple specifications WHEN calling NewSpecGroup THEN return a group with those specifications", - given: []Specification{ - &SpecificationStub{name: "spec1", typeName: "type", source: Source{}}, - &SpecificationStub{name: "spec2", typeName: "type", source: Source{}}, - }, - when: func() SpecificationGroup { - return NewSpecGroup( - &SpecificationStub{name: "spec1", typeName: "type", source: Source{}}, - &SpecificationStub{name: "spec2", typeName: "type", source: Source{}}, + name: "GIVEN multiple units WHEN calling NewUnitGroup THEN return a group with those units", + given: []Unit{ + &UnitStub{name: "spec1", typeName: "type", source: Source{}}, + &UnitStub{name: "spec2", typeName: "type", source: Source{}}, + }, + when: func() UnitGroup { + return NewUnitGroup( + &UnitStub{name: "spec1", typeName: "type", source: Source{}}, + &UnitStub{name: "spec2", typeName: "type", source: Source{}}, ) }, - then: func(result SpecificationGroup) bool { + then: func(result UnitGroup) bool { return len(result) == 2 && result[0].Name() == "spec1" && result[1].Name() == "spec2" @@ -70,38 +70,38 @@ func TestNewSpecGroup(t *testing.T) { } // Test cases for merge -func TestSpecificationGroup_Merge(t *testing.T) { +func TestUnitGroup_Merge(t *testing.T) { tests := []struct { name string - given SpecificationGroup - when SpecificationGroup - then SpecificationGroup + given UnitGroup + when UnitGroup + then UnitGroup }{ { - name: "GIVEN two disjoint groups THEN return a group with all specifications", - given: NewSpecGroup( - &SpecificationStub{name: "spec1", typeName: "type", source: Source{}}, + name: "GIVEN two disjoint groups THEN return a group with all units", + given: NewUnitGroup( + &UnitStub{name: "spec1", typeName: "type", source: Source{}}, ), - when: NewSpecGroup( - &SpecificationStub{name: "spec2", typeName: "type", source: Source{}}, + when: NewUnitGroup( + &UnitStub{name: "spec2", typeName: "type", source: Source{}}, ), - then: NewSpecGroup( - &SpecificationStub{name: "spec1", typeName: "type", source: Source{}}, - &SpecificationStub{name: "spec2", typeName: "type", source: Source{}}, + then: NewUnitGroup( + &UnitStub{name: "spec1", typeName: "type", source: Source{}}, + &UnitStub{name: "spec2", typeName: "type", source: Source{}}, ), }, { - name: "GIVEN two groups with overlapping specifications THEN return a group without duplicates", - given: NewSpecGroup( - &SpecificationStub{name: "spec1", typeName: "type", source: Source{}}, + name: "GIVEN two groups with overlapping units THEN return a group without duplicates", + given: NewUnitGroup( + &UnitStub{name: "spec1", typeName: "type", source: Source{}}, ), - when: NewSpecGroup( - &SpecificationStub{name: "spec1", typeName: "type", source: Source{}}, - &SpecificationStub{name: "spec2", typeName: "type", source: Source{}}, + when: NewUnitGroup( + &UnitStub{name: "spec1", typeName: "type", source: Source{}}, + &UnitStub{name: "spec2", typeName: "type", source: Source{}}, ), - then: NewSpecGroup( - &SpecificationStub{name: "spec1", typeName: "type", source: Source{}}, - &SpecificationStub{name: "spec2", typeName: "type", source: Source{}}, + then: NewUnitGroup( + &UnitStub{name: "spec1", typeName: "type", source: Source{}}, + &UnitStub{name: "spec2", typeName: "type", source: Source{}}, ), }, } @@ -114,34 +114,34 @@ func TestSpecificationGroup_Merge(t *testing.T) { } } -func TestSpecificationGroup_Select(t *testing.T) { +func TestUnitGroup_Select(t *testing.T) { tests := []struct { name string - given SpecificationGroup - when func(s Specification) bool - then SpecificationGroup + given UnitGroup + when func(s Unit) bool + then UnitGroup }{ { - name: "GIVEN no specifications matches, THEN return an empty group", - given: SpecificationGroup{ - &SpecificationStub{name: "spec2name", typeName: "type", source: Source{}}, + name: "GIVEN no units matches, THEN return an empty group", + given: UnitGroup{ + &UnitStub{name: "spec2name", typeName: "type", source: Source{}}, }, - when: func(s Specification) bool { + when: func(s Unit) bool { return false }, - then: SpecificationGroup{}, + then: UnitGroup{}, }, { - name: "GIVEN specifications matches, THEN return a group with only matching specifications", - given: SpecificationGroup{ - &SpecificationStub{name: "spec1", typeName: "type", source: Source{}}, - &SpecificationStub{name: "spec2", typeName: "type", source: Source{}}, + name: "GIVEN units matches, THEN return a group with only matching units", + given: UnitGroup{ + &UnitStub{name: "spec1", typeName: "type", source: Source{}}, + &UnitStub{name: "spec2", typeName: "type", source: Source{}}, }, - when: func(s Specification) bool { + when: func(s Unit) bool { return s.Name() == "spec2" }, - then: SpecificationGroup{ - &SpecificationStub{name: "spec2", typeName: "type", source: Source{}}, + then: UnitGroup{ + &UnitStub{name: "spec2", typeName: "type", source: Source{}}, }, }, } @@ -153,30 +153,30 @@ func TestSpecificationGroup_Select(t *testing.T) { } } -func TestSpecificationGroup_SelectType(t *testing.T) { +func TestUnitGroup_SelectType(t *testing.T) { tests := []struct { name string - given SpecificationGroup - when SpecificationType - then SpecificationGroup + given UnitGroup + when UnitType + then UnitGroup }{ { - name: "GIVEN no specifications matches, THEN return an empty group", - given: SpecificationGroup{ - &SpecificationStub{name: "spec2name", typeName: "type", source: Source{}}, + name: "GIVEN no units matches, THEN return an empty group", + given: UnitGroup{ + &UnitStub{name: "spec2name", typeName: "type", source: Source{}}, }, when: "not_found", - then: SpecificationGroup{}, + then: UnitGroup{}, }, { - name: "GIVEN a specification matches, THEN return a group with matching specification", - given: SpecificationGroup{ - &SpecificationStub{name: "spec1", typeName: "type1", source: Source{}}, - &SpecificationStub{name: "spec2", typeName: "type2", source: Source{}}, + name: "GIVEN a unit matches, THEN return a group with matching unit", + given: UnitGroup{ + &UnitStub{name: "spec1", typeName: "type1", source: Source{}}, + &UnitStub{name: "spec2", typeName: "type2", source: Source{}}, }, when: "type1", - then: SpecificationGroup{ - &SpecificationStub{name: "spec1", typeName: "type1", source: Source{}}, + then: UnitGroup{ + &UnitStub{name: "spec1", typeName: "type1", source: Source{}}, }, }, } @@ -188,34 +188,34 @@ func TestSpecificationGroup_SelectType(t *testing.T) { } } -func TestSpecificationGroup_SelectName(t *testing.T) { +func TestUnitGroup_SelectName(t *testing.T) { tests := []struct { name string - given SpecificationGroup - when SpecificationName - then Specification + given UnitGroup + when UnitName + then Unit }{ { - name: "GIVEN a group with multiple specifications WHEN selecting an existing name THEN return the corresponding specification", - given: NewSpecGroup( - &SpecificationStub{name: "spec1", typeName: "type", source: Source{}}, - &SpecificationStub{name: "spec2", typeName: "type", source: Source{}}, + name: "GIVEN a group with multiple units WHEN selecting an existing name THEN return the corresponding unit", + given: NewUnitGroup( + &UnitStub{name: "spec1", typeName: "type", source: Source{}}, + &UnitStub{name: "spec2", typeName: "type", source: Source{}}, ), when: "spec2", - then: &SpecificationStub{name: "spec2", typeName: "type", source: Source{}}, + then: &UnitStub{name: "spec2", typeName: "type", source: Source{}}, }, { - name: "GIVEN a group with multiple specifications WHEN selecting a non-existent name THEN return nil", - given: NewSpecGroup( - &SpecificationStub{name: "spec1", typeName: "type", source: Source{}}, - &SpecificationStub{name: "spec2", typeName: "type", source: Source{}}, + name: "GIVEN a group with multiple units WHEN selecting a non-existent name THEN return nil", + given: NewUnitGroup( + &UnitStub{name: "spec1", typeName: "type", source: Source{}}, + &UnitStub{name: "spec2", typeName: "type", source: Source{}}, ), when: "spec3", then: nil, }, { name: "GIVEN an empty group WHEN selecting a name THEN return nil", - given: NewSpecGroup(), + given: NewUnitGroup(), when: "spec1", then: nil, }, @@ -229,30 +229,30 @@ func TestSpecificationGroup_SelectName(t *testing.T) { } } -func TestSpecificationGroup_SelectNames(t *testing.T) { +func TestUnitGroup_SelectNames(t *testing.T) { tests := []struct { name string - given SpecificationGroup - when []SpecificationName - then SpecificationGroup + given UnitGroup + when []UnitName + then UnitGroup }{ { - name: "GIVEN no specifications matches, THEN return a group with no values", - given: SpecificationGroup{ - &SpecificationStub{name: "name", typeName: "type", source: Source{}}, + name: "GIVEN no units matches, THEN return a group with no values", + given: UnitGroup{ + &UnitStub{name: "name", typeName: "type", source: Source{}}, }, - when: []SpecificationName{"not_found"}, - then: SpecificationGroup{}, + when: []UnitName{"not_found"}, + then: UnitGroup{}, }, { - name: "GIVEN a specification matches, THEN return a group with matching specification", - given: SpecificationGroup{ - &SpecificationStub{name: "spec1", typeName: "type", source: Source{}}, - &SpecificationStub{name: "spec2", typeName: "type", source: Source{}}, + name: "GIVEN a unit matches, THEN return a group with matching unit", + given: UnitGroup{ + &UnitStub{name: "spec1", typeName: "type", source: Source{}}, + &UnitStub{name: "spec2", typeName: "type", source: Source{}}, }, - when: []SpecificationName{"spec1"}, - then: SpecificationGroup{ - &SpecificationStub{name: "spec1", typeName: "type", source: Source{}}, + when: []UnitName{"spec1"}, + then: UnitGroup{ + &UnitStub{name: "spec1", typeName: "type", source: Source{}}, }, }, } @@ -264,35 +264,35 @@ func TestSpecificationGroup_SelectNames(t *testing.T) { } } -func TestSpecificationGroup_Exclude(t *testing.T) { +func TestUnitGroup_Exclude(t *testing.T) { tests := []struct { name string - given SpecificationGroup - when func(s Specification) bool - then SpecificationGroup + given UnitGroup + when func(s Unit) bool + then UnitGroup }{ { - name: "GIVEN no specifications matches, THEN return a group with the same values", - given: SpecificationGroup{ - &SpecificationStub{name: "name", typeName: "type", source: Source{}}, + name: "GIVEN no units matches, THEN return a group with the same values", + given: UnitGroup{ + &UnitStub{name: "name", typeName: "type", source: Source{}}, }, - when: func(s Specification) bool { + when: func(s Unit) bool { return false }, - then: SpecificationGroup{ - &SpecificationStub{name: "name", typeName: "type", source: Source{}}, + then: UnitGroup{ + &UnitStub{name: "name", typeName: "type", source: Source{}}, }, }, { - name: "GIVEN specifications matches, THEN return a group without matching specifications", - given: SpecificationGroup{ - &SpecificationStub{name: "spec1", typeName: "type", source: Source{}}, - &SpecificationStub{name: "spec2", typeName: "type", source: Source{}}, + name: "GIVEN units matches, THEN return a group without matching units", + given: UnitGroup{ + &UnitStub{name: "spec1", typeName: "type", source: Source{}}, + &UnitStub{name: "spec2", typeName: "type", source: Source{}}, }, - when: func(s Specification) bool { + when: func(s Unit) bool { return true }, - then: SpecificationGroup{}, + then: UnitGroup{}, }, } for _, tt := range tests { @@ -303,32 +303,32 @@ func TestSpecificationGroup_Exclude(t *testing.T) { } } -func TestSpecificationGroup_ExcludeType(t *testing.T) { +func TestUnitGroup_ExcludeType(t *testing.T) { tests := []struct { name string - given SpecificationGroup - when SpecificationType - then SpecificationGroup + given UnitGroup + when UnitType + then UnitGroup }{ { - name: "GIVEN no specifications matches, THEN return a group with the same values", - given: SpecificationGroup{ - &SpecificationStub{name: "spec2name", typeName: "type", source: Source{}}, + name: "GIVEN no units matches, THEN return a group with the same values", + given: UnitGroup{ + &UnitStub{name: "spec2name", typeName: "type", source: Source{}}, }, when: "not_found", - then: SpecificationGroup{ - &SpecificationStub{name: "spec2name", typeName: "type", source: Source{}}, + then: UnitGroup{ + &UnitStub{name: "spec2name", typeName: "type", source: Source{}}, }, }, { - name: "GIVEN a specification matches, THEN return a group without matching specification", - given: SpecificationGroup{ - &SpecificationStub{name: "spec1", typeName: "type1", source: Source{}}, - &SpecificationStub{name: "spec2", typeName: "type2", source: Source{}}, + name: "GIVEN a unit matches, THEN return a group without matching unit", + given: UnitGroup{ + &UnitStub{name: "spec1", typeName: "type1", source: Source{}}, + &UnitStub{name: "spec2", typeName: "type2", source: Source{}}, }, when: "type1", - then: SpecificationGroup{ - &SpecificationStub{name: "spec2", typeName: "type2", source: Source{}}, + then: UnitGroup{ + &UnitStub{name: "spec2", typeName: "type2", source: Source{}}, }, }, } @@ -340,32 +340,32 @@ func TestSpecificationGroup_ExcludeType(t *testing.T) { } } -func TestSpecificationGroup_ExcludeNames(t *testing.T) { +func TestUnitGroup_ExcludeNames(t *testing.T) { tests := []struct { name string - given SpecificationGroup - when []SpecificationName - then SpecificationGroup + given UnitGroup + when []UnitName + then UnitGroup }{ { - name: "GIVEN no specifications matches, THEN return a group with the same values", - given: SpecificationGroup{ - &SpecificationStub{name: "spec2name", typeName: "type", source: Source{}}, + name: "GIVEN no units matches, THEN return a group with the same values", + given: UnitGroup{ + &UnitStub{name: "spec2name", typeName: "type", source: Source{}}, }, - when: []SpecificationName{"not_found"}, - then: SpecificationGroup{ - &SpecificationStub{name: "spec2name", typeName: "type", source: Source{}}, + when: []UnitName{"not_found"}, + then: UnitGroup{ + &UnitStub{name: "spec2name", typeName: "type", source: Source{}}, }, }, { - name: "GIVEN a specification matches, THEN return a group without matching specification", - given: SpecificationGroup{ - &SpecificationStub{name: "spec1", typeName: "type", source: Source{}}, - &SpecificationStub{name: "spec2", typeName: "type", source: Source{}}, + name: "GIVEN a unit matches, THEN return a group without matching unit", + given: UnitGroup{ + &UnitStub{name: "spec1", typeName: "type", source: Source{}}, + &UnitStub{name: "spec2", typeName: "type", source: Source{}}, }, - when: []SpecificationName{"spec1"}, - then: SpecificationGroup{ - &SpecificationStub{name: "spec2", typeName: "type", source: Source{}}, + when: []UnitName{"spec1"}, + then: UnitGroup{ + &UnitStub{name: "spec2", typeName: "type", source: Source{}}, }, }, } @@ -377,39 +377,39 @@ func TestSpecificationGroup_ExcludeNames(t *testing.T) { } } -func TestMapSpecGroup(t *testing.T) { +func TestMapUnitGroup(t *testing.T) { tests := []struct { name string - given SpecificationGroup - when func(Specification) string + given UnitGroup + when func(Unit) string then []string }{ { - name: "GIVEN a group with multiple specifications WHEN mapped to their names THEN return a slice of specification names", - given: NewSpecGroup( - &SpecificationStub{name: "spec1", typeName: "type", source: Source{}}, - &SpecificationStub{name: "spec2", typeName: "type", source: Source{}}, + name: "GIVEN a group with multiple units WHEN mapped to their names THEN return a slice of unit names", + given: NewUnitGroup( + &UnitStub{name: "spec1", typeName: "type", source: Source{}}, + &UnitStub{name: "spec2", typeName: "type", source: Source{}}, ), - when: func(s Specification) string { + when: func(s Unit) string { return string(s.Name()) }, then: []string{"spec1", "spec2"}, }, { name: "GIVEN an empty group WHEN mapped THEN return a nil slice", - given: NewSpecGroup(), - when: func(s Specification) string { + given: NewUnitGroup(), + when: func(s Unit) string { return string(s.Name()) }, then: nil, }, { - name: "GIVEN a group with multiple specifications WHEN mapped to a constant value THEN return a slice of that value", - given: NewSpecGroup( - &SpecificationStub{name: "spec1", typeName: "type", source: Source{}}, - &SpecificationStub{name: "spec2", typeName: "type", source: Source{}}, + name: "GIVEN a group with multiple units WHEN mapped to a constant value THEN return a slice of that value", + given: NewUnitGroup( + &UnitStub{name: "spec1", typeName: "type", source: Source{}}, + &UnitStub{name: "spec2", typeName: "type", source: Source{}}, ), - when: func(s Specification) string { + when: func(s Unit) string { return "constant" }, then: []string{"constant", "constant"}, @@ -418,7 +418,7 @@ func TestMapSpecGroup(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := MapSpecGroup(tt.given, tt.when) + got := MapUnitGroup(tt.given, tt.when) assert.Equal(t, tt.then, got) }) } diff --git a/pkg/specter/specproc.go b/pkg/specter/specproc.go index 8853ea1..2aa6ff9 100644 --- a/pkg/specter/specproc.go +++ b/pkg/specter/specproc.go @@ -18,9 +18,9 @@ import "context" type ProcessingContext struct { context.Context - Specifications SpecificationGroup - Artifacts []Artifact - Logger Logger + Units UnitGroup + Artifacts []Artifact + Logger Logger } // Artifact returns an artifact by its ID. @@ -33,20 +33,20 @@ func (c ProcessingContext) Artifact(id ArtifactID) Artifact { return nil } -// SpecificationProcessor are services responsible for performing work using Specifications +// UnitProcessor are services responsible for performing work using Units // and which can possibly generate artifacts. -type SpecificationProcessor interface { +type UnitProcessor interface { // Name returns the unique name of this processor. // This name can appear in logs to report information about a given processor. Name() string - // Process processes a group of specifications. + // Process processes a group of units. Process(ctx ProcessingContext) ([]Artifact, error) } -// ArtifactProcessor are services responsible for processing artifacts of SpecProcessors. +// ArtifactProcessor are services responsible for processing artifacts of UnitProcessors. type ArtifactProcessor interface { - // Process performs the processing of artifacts generated by SpecificationProcessor. + // Process performs the processing of artifacts generated by UnitProcessor. Process(ctx ArtifactProcessingContext) error // Name returns the name of this processor. diff --git a/pkg/specter/specter_test.go b/pkg/specter/specter_test.go index 728a50e..627ee8b 100644 --- a/pkg/specter/specter_test.go +++ b/pkg/specter/specter_test.go @@ -1,3 +1,17 @@ +// Copyright 2024 Morébec +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package specter_test import ( @@ -23,32 +37,32 @@ func RequireErrorWithCode(c string) require.ErrorAssertionFunc { } } -var _ specter.Specification = (*SpecificationStub)(nil) +var _ specter.Unit = (*UnitStub)(nil) -type SpecificationStub struct { - name specter.SpecificationName - typeName specter.SpecificationType +type UnitStub struct { + name specter.UnitName + typeName specter.UnitType source specter.Source desc string } -func (s *SpecificationStub) Name() specter.SpecificationName { +func (s *UnitStub) Name() specter.UnitName { return s.name } -func (s *SpecificationStub) Type() specter.SpecificationType { +func (s *UnitStub) Type() specter.UnitType { return s.typeName } -func (s *SpecificationStub) Description() string { +func (s *UnitStub) Description() string { return s.desc } -func (s *SpecificationStub) Source() specter.Source { +func (s *UnitStub) Source() specter.Source { return s.source } -func (s *SpecificationStub) SetSource(src specter.Source) { +func (s *UnitStub) SetSource(src specter.Source) { s.source = src } diff --git a/pkg/specter/srcloading.go b/pkg/specter/srcloading.go index a71e24b..c0e9105 100644 --- a/pkg/specter/srcloading.go +++ b/pkg/specter/srcloading.go @@ -26,7 +26,7 @@ import ( // SourceFormat represents the format or syntax of a source. type SourceFormat string -// Source represents the source code that was used to load a given specification. +// Source represents the source code that was used to load a given unit. type Source struct { // Location of the source, this can be a local file or a remote file. Location string diff --git a/pkg/specterutils/README.md b/pkg/specterutils/README.md index aba9c3c..79942e4 100644 --- a/pkg/specterutils/README.md +++ b/pkg/specterutils/README.md @@ -1,12 +1,12 @@ -# SpecterUtils +# UnitterUtils -SpecterUtils is a collection of utilities and extensions for the Specter library, designed to enhance and extend its +UnitterUtils is a collection of utilities and extensions for the Unitter library, designed to enhance and extend its functionality. This package includes various "batteries included" features, such as linting and dependency resolution, -that complement the core features of Specter. +that complement the core features of Unitter. Overview -SpecterUtils provides additional tools and utilities that integrate with Specter. -It aims to enhance the capabilities of Specter without being part of the core package. +UnitterUtils provides additional tools and utilities that integrate with Unitter. +It aims to enhance the capabilities of Unitter without being part of the core package. These utilities help with tasks such as linting your specifications and resolving dependencies, making your development process smoother and more efficient. diff --git a/pkg/specterutils/depresolve.go b/pkg/specterutils/depresolve.go index 2ebc8c6..52a616e 100644 --- a/pkg/specterutils/depresolve.go +++ b/pkg/specterutils/depresolve.go @@ -23,20 +23,20 @@ import ( const ResolvedDependenciesArtifactID = "_resolved_dependencies" -// ResolvedDependencies represents an ordered list of Specification that should be processed in that specific order to avoid +// ResolvedDependencies represents an ordered list of Unit that should be processed in that specific order to avoid // unresolved types. -type ResolvedDependencies specter.SpecificationGroup +type ResolvedDependencies specter.UnitGroup func (r ResolvedDependencies) ID() specter.ArtifactID { return ResolvedDependenciesArtifactID } type DependencyProvider interface { - Supports(s specter.Specification) bool - Provide(s specter.Specification) []specter.SpecificationName + Supports(s specter.Unit) bool + Provide(s specter.Unit) []specter.UnitName } -var _ specter.SpecificationProcessor = DependencyResolutionProcessor{} +var _ specter.UnitProcessor = DependencyResolutionProcessor{} type DependencyResolutionProcessor struct { providers []DependencyProvider @@ -54,8 +54,8 @@ func (p DependencyResolutionProcessor) Process(ctx specter.ProcessingContext) ([ ctx.Logger.Info("\nResolving dependencies...") var nodes []dependencyNode - for _, s := range ctx.Specifications { - node := dependencyNode{Specification: s, Dependencies: nil} + for _, s := range ctx.Units { + node := dependencyNode{Unit: s, Dependencies: nil} for _, provider := range p.providers { if !provider.Supports(s) { continue @@ -80,9 +80,9 @@ func GetResolvedDependenciesFromContext(ctx specter.ProcessingContext) ResolvedD return specter.GetContextArtifact[ResolvedDependencies](ctx, ResolvedDependenciesArtifactID) } -type dependencySet map[specter.SpecificationName]struct{} +type dependencySet map[specter.UnitName]struct{} -func newDependencySet(dependencies ...specter.SpecificationName) dependencySet { +func newDependencySet(dependencies ...specter.UnitName) dependencySet { deps := dependencySet{} for _, d := range dependencies { deps[d] = struct{}{} @@ -105,12 +105,12 @@ func (s dependencySet) diff(o dependencySet) dependencySet { } type dependencyNode struct { - Specification specter.Specification - Dependencies dependencySet + Unit specter.Unit + Dependencies dependencySet } -func (d dependencyNode) SpecificationName() specter.SpecificationName { - return d.Specification.Name() +func (d dependencyNode) UnitName() specter.UnitName { + return d.Unit.Name() } type dependencyGraph []dependencyNode @@ -123,13 +123,13 @@ func (g dependencyGraph) resolve() (ResolvedDependencies, error) { var resolved ResolvedDependencies // Look up of nodes to their typeName Names. - specByTypeNames := map[specter.SpecificationName]specter.Specification{} + specByTypeNames := map[specter.UnitName]specter.Unit{} // Map nodes to dependencies - dependenciesByTypeNames := map[specter.SpecificationName]dependencySet{} + dependenciesByTypeNames := map[specter.UnitName]dependencySet{} for _, n := range g { - specByTypeNames[n.SpecificationName()] = n.Specification - dependenciesByTypeNames[n.SpecificationName()] = n.Dependencies + specByTypeNames[n.UnitName()] = n.Unit + dependenciesByTypeNames[n.UnitName()] = n.Dependencies } // The algorithm simply processes all nodes and tries to find the ones that have no dependencies. @@ -137,7 +137,7 @@ func (g dependencyGraph) resolve() (ResolvedDependencies, error) { // If no unresolvable or circular dependency is found, the node is considered resolved. // And processing retries with the remaining dependent nodes. for len(dependenciesByTypeNames) != 0 { - var typeNamesWithNoDependencies []specter.SpecificationName + var typeNamesWithNoDependencies []specter.UnitName for typeName, dependencies := range dependenciesByTypeNames { if len(dependencies) == 0 { typeNamesWithNoDependencies = append(typeNamesWithNoDependencies, typeName) @@ -200,18 +200,18 @@ func (g dependencyGraph) resolve() (ResolvedDependencies, error) { // This interface can be used in conjunction with the HasDependenciesProvider // to easily resolve dependencies. type HasDependencies interface { - specter.Specification - Dependencies() []specter.SpecificationName + specter.Unit + Dependencies() []specter.UnitName } type HasDependenciesProvider struct{} -func (h HasDependenciesProvider) Supports(s specter.Specification) bool { +func (h HasDependenciesProvider) Supports(s specter.Unit) bool { _, ok := s.(HasDependencies) return ok } -func (h HasDependenciesProvider) Provide(s specter.Specification) []specter.SpecificationName { +func (h HasDependenciesProvider) Provide(s specter.Unit) []specter.UnitName { d, ok := s.(HasDependencies) if !ok { return nil diff --git a/pkg/specterutils/depresolve_test.go b/pkg/specterutils/depresolve_test.go index 7a90b71..e0a3288 100644 --- a/pkg/specterutils/depresolve_test.go +++ b/pkg/specterutils/depresolve_test.go @@ -26,25 +26,25 @@ import ( // MockDependencyProvider is a mock implementation of DependencyProvider for testing. type MockDependencyProvider struct { - supportFunc func(s specter.Specification) bool - provideFunc func(s specter.Specification) []specter.SpecificationName + supportFunc func(s specter.Unit) bool + provideFunc func(s specter.Unit) []specter.UnitName } -func (m *MockDependencyProvider) Supports(s specter.Specification) bool { +func (m *MockDependencyProvider) Supports(s specter.Unit) bool { return m.supportFunc(s) } -func (m *MockDependencyProvider) Provide(s specter.Specification) []specter.SpecificationName { +func (m *MockDependencyProvider) Provide(s specter.Unit) []specter.UnitName { return m.provideFunc(s) } func TestDependencyResolutionProcessor_Process(t *testing.T) { type args struct { - specifications []specter.Specification + specifications []specter.Unit providers []DependencyProvider } - spec1 := NewGenericSpecification("spec1", "type", specter.Source{}) - spec2 := NewGenericSpecification("spec2", "type", specter.Source{}) + spec1 := NewGenericUnit("spec1", "type", specter.Source{}) + spec2 := NewGenericUnit("spec2", "type", specter.Source{}) tests := []struct { name string given args @@ -65,26 +65,26 @@ func TestDependencyResolutionProcessor_Process(t *testing.T) { given: args{ providers: []DependencyProvider{ &MockDependencyProvider{ - supportFunc: func(s specter.Specification) bool { + supportFunc: func(s specter.Unit) bool { return false }, - provideFunc: func(s specter.Specification) []specter.SpecificationName { + provideFunc: func(s specter.Unit) []specter.UnitName { return nil }, }, &MockDependencyProvider{ - supportFunc: func(s specter.Specification) bool { + supportFunc: func(s specter.Unit) bool { return s.Type() == "type" }, - provideFunc: func(s specter.Specification) []specter.SpecificationName { + provideFunc: func(s specter.Unit) []specter.UnitName { if s.Name() == "spec1" { - return []specter.SpecificationName{"spec2"} + return []specter.UnitName{"spec2"} } return nil }, }, }, - specifications: specter.SpecificationGroup{ + specifications: specter.UnitGroup{ spec1, spec2, }, @@ -100,20 +100,20 @@ func TestDependencyResolutionProcessor_Process(t *testing.T) { given: args{ providers: []DependencyProvider{ &MockDependencyProvider{ - supportFunc: func(s specter.Specification) bool { + supportFunc: func(s specter.Unit) bool { return s.Type() == "type" }, - provideFunc: func(s specter.Specification) []specter.SpecificationName { + provideFunc: func(s specter.Unit) []specter.UnitName { if s.Name() == "spec1" { - return []specter.SpecificationName{"spec2"} + return []specter.UnitName{"spec2"} } else if s.Name() == "spec2" { - return []specter.SpecificationName{"spec1"} + return []specter.UnitName{"spec1"} } return nil }, }, }, - specifications: specter.SpecificationGroup{ + specifications: specter.UnitGroup{ spec1, spec2, }, @@ -126,15 +126,15 @@ func TestDependencyResolutionProcessor_Process(t *testing.T) { given: args{ providers: []DependencyProvider{ &MockDependencyProvider{ - supportFunc: func(s specter.Specification) bool { + supportFunc: func(s specter.Unit) bool { return s.Type() == "type" }, - provideFunc: func(s specter.Specification) []specter.SpecificationName { - return []specter.SpecificationName{"spec3"} + provideFunc: func(s specter.Unit) []specter.UnitName { + return []specter.UnitName{"spec3"} }, }, }, - specifications: specter.SpecificationGroup{ + specifications: specter.UnitGroup{ spec1, spec2, // spec2 is not provided }, @@ -148,7 +148,7 @@ func TestDependencyResolutionProcessor_Process(t *testing.T) { processor := NewDependencyResolutionProcessor(tt.given.providers...) ctx := specter.ProcessingContext{ - Specifications: tt.given.specifications, + Units: tt.given.specifications, Logger: specter.NewDefaultLogger(specter.DefaultLoggerConfig{ DisableColors: true, Writer: os.Stdout, @@ -183,12 +183,12 @@ func TestGetResolvedDependenciesFromContext(t *testing.T) { given: specter.ProcessingContext{ Artifacts: []specter.Artifact{ ResolvedDependencies{ - NewGenericSpecification("name", "type", specter.Source{}), + NewGenericUnit("name", "type", specter.Source{}), }, }, }, want: ResolvedDependencies{ - NewGenericSpecification("name", "type", specter.Source{}), + NewGenericUnit("name", "type", specter.Source{}), }, }, { @@ -219,49 +219,49 @@ func TestDependencyResolutionProcessor_Name(t *testing.T) { assert.NotEqual(t, "", p.Name()) } -type hasDependencySpec struct { +type hasDependencyUnit struct { source specter.Source - dependencies []specter.SpecificationName + dependencies []specter.UnitName } -func (h *hasDependencySpec) Name() specter.SpecificationName { +func (h *hasDependencyUnit) Name() specter.UnitName { return "spec" } -func (h *hasDependencySpec) Type() specter.SpecificationType { +func (h *hasDependencyUnit) Type() specter.UnitType { return "spec" } -func (h *hasDependencySpec) Description() string { +func (h *hasDependencyUnit) Description() string { return "description" } -func (h *hasDependencySpec) Source() specter.Source { +func (h *hasDependencyUnit) Source() specter.Source { return h.source } -func (h *hasDependencySpec) SetSource(s specter.Source) { +func (h *hasDependencyUnit) SetSource(s specter.Source) { h.source = s } -func (h *hasDependencySpec) Dependencies() []specter.SpecificationName { +func (h *hasDependencyUnit) Dependencies() []specter.UnitName { return h.dependencies } func TestHasDependenciesProvider_Supports(t *testing.T) { tests := []struct { name string - given specter.Specification + given specter.Unit then bool }{ { name: "GIVEN specification not implementing HasDependencies THEN return false", - given: &GenericSpecification{}, + given: &GenericUnit{}, then: false, }, { name: "GIVEN specification implementing HasDependencies THEN return false", - given: &hasDependencySpec{}, + given: &hasDependencyUnit{}, then: true, }, } @@ -276,18 +276,18 @@ func TestHasDependenciesProvider_Supports(t *testing.T) { func TestHasDependenciesProvider_Provide(t *testing.T) { tests := []struct { name string - given specter.Specification - then []specter.SpecificationName + given specter.Unit + then []specter.UnitName }{ { name: "GIVEN specification not implementing HasDependencies THEN return nil", - given: &GenericSpecification{}, + given: &GenericUnit{}, then: nil, }, { name: "GIVEN specification implementing HasDependencies THEN return dependencies", - given: &hasDependencySpec{dependencies: []specter.SpecificationName{"spec1"}}, - then: []specter.SpecificationName{"spec1"}, + given: &hasDependencyUnit{dependencies: []specter.UnitName{"spec1"}}, + then: []specter.UnitName{"spec1"}, }, } for _, tt := range tests { diff --git a/pkg/specterutils/genericspec.go b/pkg/specterutils/genericspec.go index 41a294e..774573c 100644 --- a/pkg/specterutils/genericspec.go +++ b/pkg/specterutils/genericspec.go @@ -1,3 +1,17 @@ +// Copyright 2024 Morébec +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package specterutils import ( @@ -6,24 +20,24 @@ import ( "github.com/zclconf/go-cty/cty" ) -// GenericSpecification is a generic implementation of a Specification that saves its attributes in a list of attributes for introspection. +// GenericUnit is a generic implementation of a Unit that saves its attributes in a list of attributes for introspection. // these can be useful for loaders that are looser in what they allow. -type GenericSpecification struct { - name specter.SpecificationName - typ specter.SpecificationType +type GenericUnit struct { + name specter.UnitName + typ specter.UnitType source specter.Source - Attributes []GenericSpecAttribute + Attributes []GenericUnitAttribute } -func NewGenericSpecification(name specter.SpecificationName, typ specter.SpecificationType, source specter.Source) *GenericSpecification { - return &GenericSpecification{name: name, typ: typ, source: source} +func NewGenericUnit(name specter.UnitName, typ specter.UnitType, source specter.Source) *GenericUnit { + return &GenericUnit{name: name, typ: typ, source: source} } -func (s *GenericSpecification) SetSource(src specter.Source) { +func (s *GenericUnit) SetSource(src specter.Source) { s.source = src } -func (s *GenericSpecification) Description() string { +func (s *GenericUnit) Description() string { if !s.HasAttribute("description") { return "" } @@ -32,20 +46,20 @@ func (s *GenericSpecification) Description() string { return attr.Value.String() } -func (s *GenericSpecification) Name() specter.SpecificationName { +func (s *GenericUnit) Name() specter.UnitName { return s.name } -func (s *GenericSpecification) Type() specter.SpecificationType { +func (s *GenericUnit) Type() specter.UnitType { return s.typ } -func (s *GenericSpecification) Source() specter.Source { +func (s *GenericUnit) Source() specter.Source { return s.source } // Attribute returns an attribute by its FilePath or nil if it was not found. -func (s *GenericSpecification) Attribute(name string) *GenericSpecAttribute { +func (s *GenericUnit) Attribute(name string) *GenericUnitAttribute { for _, a := range s.Attributes { if a.Name == name { return &a @@ -56,7 +70,7 @@ func (s *GenericSpecification) Attribute(name string) *GenericSpecAttribute { } // HasAttribute indicates if a specification has a certain attribute or not. -func (s *GenericSpecification) HasAttribute(name string) bool { +func (s *GenericUnit) HasAttribute(name string) bool { for _, a := range s.Attributes { if a.Name == name { return true @@ -73,9 +87,9 @@ const ( Unknown = "any" ) -// GenericSpecAttribute represents an attribute of a specification. +// GenericUnitAttribute represents an attribute of a specification. // It relies on cty.Value to represent the loaded value. -type GenericSpecAttribute struct { +type GenericUnitAttribute struct { Name string Value AttributeValue } @@ -105,7 +119,7 @@ var _ AttributeValue = ObjectValue{} // ObjectValue represents a type of attribute value that is a nested data structure as opposed to a scalar value. type ObjectValue struct { Type AttributeType - Attributes []GenericSpecAttribute + Attributes []GenericUnitAttribute } func (o ObjectValue) String() string { diff --git a/pkg/specterutils/genericspec_test.go b/pkg/specterutils/genericspec_test.go index fd7dbfe..96f7234 100644 --- a/pkg/specterutils/genericspec_test.go +++ b/pkg/specterutils/genericspec_test.go @@ -22,16 +22,16 @@ import ( "testing" ) -func TestGenericSpecification_Description(t *testing.T) { +func TestGenericUnit_Description(t *testing.T) { tests := []struct { name string - given *specterutils.GenericSpecification + given *specterutils.GenericUnit then string }{ { name: "GIVEN a specification with a description attribute THEN return the description", - given: &specterutils.GenericSpecification{ - Attributes: []specterutils.GenericSpecAttribute{ + given: &specterutils.GenericUnit{ + Attributes: []specterutils.GenericUnitAttribute{ { Name: "description", Value: specterutils.GenericValue{Value: cty.StringVal("This is a test specification")}, @@ -42,15 +42,15 @@ func TestGenericSpecification_Description(t *testing.T) { }, { name: "GIVEN a specification without a description attribute THEN return an empty string", - given: &specterutils.GenericSpecification{ - Attributes: []specterutils.GenericSpecAttribute{}, + given: &specterutils.GenericUnit{ + Attributes: []specterutils.GenericUnitAttribute{}, }, then: "", }, { name: "GIVEN a specification with a non-string description THEN return an empty string", - given: &specterutils.GenericSpecification{ - Attributes: []specterutils.GenericSpecAttribute{ + given: &specterutils.GenericUnit{ + Attributes: []specterutils.GenericUnitAttribute{ { Name: "description", Value: specterutils.GenericValue{Value: cty.NumberIntVal(42)}, // Not a string value @@ -69,17 +69,17 @@ func TestGenericSpecification_Description(t *testing.T) { } } -func TestGenericSpecification_Attribute(t *testing.T) { +func TestGenericUnit_Attribute(t *testing.T) { tests := []struct { name string - given *specterutils.GenericSpecification + given *specterutils.GenericUnit when string - then *specterutils.GenericSpecAttribute + then *specterutils.GenericUnitAttribute }{ { name: "GIVEN a specification with a specific attribute WHEN Attribute is called THEN return the attribute", - given: &specterutils.GenericSpecification{ - Attributes: []specterutils.GenericSpecAttribute{ + given: &specterutils.GenericUnit{ + Attributes: []specterutils.GenericUnitAttribute{ { Name: "attr1", Value: specterutils.GenericValue{Value: cty.StringVal("value1")}, @@ -87,15 +87,15 @@ func TestGenericSpecification_Attribute(t *testing.T) { }, }, when: "attr1", - then: &specterutils.GenericSpecAttribute{ + then: &specterutils.GenericUnitAttribute{ Name: "attr1", Value: specterutils.GenericValue{Value: cty.StringVal("value1")}, }, }, { name: "GIVEN a specification without the specified attribute WHEN Attribute is called THEN return nil", - given: &specterutils.GenericSpecification{ - Attributes: []specterutils.GenericSpecAttribute{}, + given: &specterutils.GenericUnit{ + Attributes: []specterutils.GenericUnitAttribute{}, }, when: "nonexistent", then: nil, @@ -110,17 +110,17 @@ func TestGenericSpecification_Attribute(t *testing.T) { } } -func TestGenericSpecification_HasAttribute(t *testing.T) { +func TestGenericUnit_HasAttribute(t *testing.T) { tests := []struct { name string - given *specterutils.GenericSpecification + given *specterutils.GenericUnit when string then bool }{ { name: "GIVEN a specification with a specific attribute WHEN HasAttribute is called THEN return true", - given: &specterutils.GenericSpecification{ - Attributes: []specterutils.GenericSpecAttribute{ + given: &specterutils.GenericUnit{ + Attributes: []specterutils.GenericUnitAttribute{ { Name: "attr1", Value: specterutils.GenericValue{Value: cty.StringVal("value1")}, @@ -132,8 +132,8 @@ func TestGenericSpecification_HasAttribute(t *testing.T) { }, { name: "GIVEN a specification without the specified attribute WHEN HasAttribute is called THEN return false", - given: &specterutils.GenericSpecification{ - Attributes: []specterutils.GenericSpecAttribute{}, + given: &specterutils.GenericUnit{ + Attributes: []specterutils.GenericUnitAttribute{}, }, when: "nonexistent", then: false, @@ -148,16 +148,16 @@ func TestGenericSpecification_HasAttribute(t *testing.T) { } } -func TestGenericSpecification_SetSource(t *testing.T) { +func TestGenericUnit_SetSource(t *testing.T) { tests := []struct { name string - given *specterutils.GenericSpecification + given *specterutils.GenericUnit when specter.Source then specter.Source }{ { name: "GIVEN a specification WHEN SetSource is called THEN updates the source", - given: specterutils.NewGenericSpecification("name", "type", specter.Source{Location: "initial/path"}), + given: specterutils.NewGenericUnit("name", "type", specter.Source{Location: "initial/path"}), when: specter.Source{Location: "new/path"}, then: specter.Source{Location: "new/path"}, }, @@ -172,7 +172,7 @@ func TestGenericSpecification_SetSource(t *testing.T) { } func TestObjectValue_String(t *testing.T) { - o := specterutils.ObjectValue{Type: "hello", Attributes: []specterutils.GenericSpecAttribute{ + o := specterutils.ObjectValue{Type: "hello", Attributes: []specterutils.GenericUnitAttribute{ {Name: "hello", Value: specterutils.GenericValue{Value: cty.StringVal("world")}}, }} assert.Equal(t, "ObjectValue{Type: hello, Attributes: [{hello world}]}", o.String()) diff --git a/pkg/specterutils/hcl.go b/pkg/specterutils/hcl.go index 0646552..0b13da7 100644 --- a/pkg/specterutils/hcl.go +++ b/pkg/specterutils/hcl.go @@ -31,28 +31,28 @@ const ( const InvalidHCLErrorCode = "specter.spec_loading.invalid_hcl" -// NewHCLGenericSpecLoader this SpecificationLoader will load all Specifications to instances of GenericSpecification. -func NewHCLGenericSpecLoader() *HCLGenericSpecLoader { - return &HCLGenericSpecLoader{ +// NewHCLGenericUnitLoader this UnitLoader will load all Units to instances of GenericUnit. +func NewHCLGenericUnitLoader() *HCLGenericUnitLoader { + return &HCLGenericUnitLoader{ Parser: *hclparse.NewParser(), } } -// HCLGenericSpecLoader this SpecificationLoader loads Specifications as GenericSpecification. -type HCLGenericSpecLoader struct { +// HCLGenericUnitLoader this UnitLoader loads Units as GenericUnit. +type HCLGenericUnitLoader struct { hclparse.Parser } -func (l HCLGenericSpecLoader) SupportsSource(s specter.Source) bool { +func (l HCLGenericUnitLoader) SupportsSource(s specter.Source) bool { return s.Format == HCLSourceFormat } -func (l HCLGenericSpecLoader) Load(s specter.Source) ([]specter.Specification, error) { +func (l HCLGenericUnitLoader) Load(s specter.Source) ([]specter.Unit, error) { ctx := &hcl.EvalContext{ Variables: map[string]cty.Value{}, } - // Although the caller is responsible for calling HCLGenericSpecLoader.SupportsSource, guard against it. + // Although the caller is responsible for calling HCLGenericUnitLoader.SupportsSource, guard against it. if !l.SupportsSource(s) { return nil, errors.NewWithMessage( specter.UnsupportedSourceErrorCode, @@ -69,7 +69,7 @@ func (l HCLGenericSpecLoader) Load(s specter.Source) ([]specter.Specification, e return nil, errors.Wrap(diags, InvalidHCLErrorCode) } - var specifications []specter.Specification + var specifications []specter.Unit body := file.Body.(*hclsyntax.Body) for _, block := range body.Blocks { @@ -106,9 +106,9 @@ func (l HCLGenericSpecLoader) Load(s specter.Source) ([]specter.Specification, e } // Create specification and add to list - specifications = append(specifications, &GenericSpecification{ - name: specter.SpecificationName(block.Labels[0]), - typ: specter.SpecificationType(block.Type), + specifications = append(specifications, &GenericUnit{ + name: specter.UnitName(block.Labels[0]), + typ: specter.UnitType(block.Type), source: s, Attributes: specAttributes, }) @@ -124,8 +124,8 @@ func (l HCLGenericSpecLoader) Load(s specter.Source) ([]specter.Specification, e return specifications, errors.GroupOrNil(group) } -func (l HCLGenericSpecLoader) extractAttributesFromBlock(ctx *hcl.EvalContext, block *hclsyntax.Block) ([]GenericSpecAttribute, hcl.Diagnostics) { - var attrs []GenericSpecAttribute +func (l HCLGenericUnitLoader) extractAttributesFromBlock(ctx *hcl.EvalContext, block *hclsyntax.Block) ([]GenericUnitAttribute, hcl.Diagnostics) { + var attrs []GenericUnitAttribute var diags hcl.Diagnostics @@ -137,7 +137,7 @@ func (l HCLGenericSpecLoader) extractAttributesFromBlock(ctx *hcl.EvalContext, b continue } - attrs = append(attrs, GenericSpecAttribute{ + attrs = append(attrs, GenericUnitAttribute{ Name: a.Name, Value: GenericValue{value}, }) @@ -156,7 +156,7 @@ func (l HCLGenericSpecLoader) extractAttributesFromBlock(ctx *hcl.EvalContext, b continue } - attrs = append(attrs, GenericSpecAttribute{ + attrs = append(attrs, GenericUnitAttribute{ Name: bName, Value: ObjectValue{ Type: AttributeType(b.Type), @@ -168,11 +168,11 @@ func (l HCLGenericSpecLoader) extractAttributesFromBlock(ctx *hcl.EvalContext, b return attrs, diags } -type HCLSpecLoaderFileConfigurationProvider func() HCLFileConfig +type HCLUnitLoaderFileConfigurationProvider func() HCLFileConfig // HCLFileConfig interface that is to be implemented to define the structure of HCL specification files. type HCLFileConfig interface { - Specifications() []specter.Specification + Units() []specter.Unit } // HCLVariableConfig represents a block configuration that allows defining variables. @@ -182,16 +182,16 @@ type HCLVariableConfig struct { Value cty.Value `hcl:"value"` } -// HCLSpecLoader this loader allows to load Specifications to typed structs by providing a HCLFileConfig. -type HCLSpecLoader struct { +// HCLUnitLoader this loader allows to load Units to typed structs by providing a HCLFileConfig. +type HCLUnitLoader struct { // represents the structure of a file that this HCL loader should support. parser *hclparse.Parser - fileConfigProvider HCLSpecLoaderFileConfigurationProvider + fileConfigProvider HCLUnitLoaderFileConfigurationProvider evalCtx *hcl.EvalContext } -func NewHCLSpecLoader(fileConfigProvider HCLSpecLoaderFileConfigurationProvider) *HCLSpecLoader { - return &HCLSpecLoader{ +func NewHCLUnitLoader(fileConfigProvider HCLUnitLoaderFileConfigurationProvider) *HCLUnitLoader { + return &HCLUnitLoader{ fileConfigProvider: fileConfigProvider, evalCtx: &hcl.EvalContext{ Variables: map[string]cty.Value{}, @@ -200,8 +200,8 @@ func NewHCLSpecLoader(fileConfigProvider HCLSpecLoaderFileConfigurationProvider) } } -func (l HCLSpecLoader) Load(s specter.Source) ([]specter.Specification, error) { - // Although the caller is responsible for calling HCLGenericSpecLoader.SupportsSource, guard against it. +func (l HCLUnitLoader) Load(s specter.Source) ([]specter.Unit, error) { + // Although the caller is responsible for calling HCLGenericUnitLoader.SupportsSource, guard against it. if !l.SupportsSource(s) { return nil, errors.NewWithMessage( specter.UnsupportedSourceErrorCode, @@ -244,13 +244,13 @@ func (l HCLSpecLoader) Load(s specter.Source) ([]specter.Specification, error) { } // Set source for all specifications - specifications := fileConf.Specifications() + specifications := fileConf.Units() for _, sp := range specifications { sp.SetSource(s) } return specifications, nil } -func (l HCLSpecLoader) SupportsSource(s specter.Source) bool { +func (l HCLUnitLoader) SupportsSource(s specter.Source) bool { return s.Format == HCLSourceFormat } diff --git a/pkg/specterutils/hcl_test.go b/pkg/specterutils/hcl_test.go index 7c73f88..c4321d0 100644 --- a/pkg/specterutils/hcl_test.go +++ b/pkg/specterutils/hcl_test.go @@ -22,7 +22,7 @@ import ( "testing" ) -func TestHCLGenericSpecLoader_SupportsSource(t *testing.T) { +func TestHCLGenericUnitLoader_SupportsSource(t *testing.T) { type when struct { source specter.Source } @@ -51,19 +51,19 @@ func TestHCLGenericSpecLoader_SupportsSource(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - l := NewHCLGenericSpecLoader() + l := NewHCLGenericUnitLoader() assert.Equalf(t, tt.then.supports, l.SupportsSource(tt.when.source), "SupportsSource(%v)", tt.when.source) }) } } -func TestHCLGenericSpecLoader_Load(t *testing.T) { +func TestHCLGenericUnitLoader_Load(t *testing.T) { type when struct { source specter.Source } type then struct { - expectedSpecifications []specter.Specification - expectedError require.ErrorAssertionFunc + expectedUnits []specter.Unit + expectedError require.ErrorAssertionFunc } mockFile := HclConfigMock{} @@ -82,8 +82,8 @@ func TestHCLGenericSpecLoader_Load(t *testing.T) { }, }, then: then{ - expectedSpecifications: nil, - expectedError: require.NoError, + expectedUnits: nil, + expectedError: require.NoError, }, }, { @@ -92,8 +92,8 @@ func TestHCLGenericSpecLoader_Load(t *testing.T) { source: mockFile.source(), }, then: then{ - expectedSpecifications: []specter.Specification{ - mockFile.genericSpecification(), + expectedUnits: []specter.Unit{ + mockFile.genericUnit(), }, expectedError: require.NoError, }, @@ -106,8 +106,8 @@ func TestHCLGenericSpecLoader_Load(t *testing.T) { }, }, then: then{ - expectedSpecifications: nil, - expectedError: RequireErrorWithCode(specter.UnsupportedSourceErrorCode), + expectedUnits: nil, + expectedError: RequireErrorWithCode(specter.UnsupportedSourceErrorCode), }, }, { @@ -121,8 +121,8 @@ con st = var o }, }, then: then{ - expectedSpecifications: nil, - expectedError: RequireErrorWithCode(InvalidHCLErrorCode), + expectedUnits: nil, + expectedError: RequireErrorWithCode(InvalidHCLErrorCode), }, }, { @@ -137,8 +137,8 @@ block { }, }, then: then{ - expectedSpecifications: nil, - expectedError: RequireErrorWithCode(InvalidHCLErrorCode), + expectedUnits: nil, + expectedError: RequireErrorWithCode(InvalidHCLErrorCode), }, }, // ATTRIBUTES @@ -155,8 +155,8 @@ specType "specName" { }, }, then: then{ - expectedSpecifications: nil, - expectedError: RequireErrorWithCode(InvalidHCLErrorCode), + expectedUnits: nil, + expectedError: RequireErrorWithCode(InvalidHCLErrorCode), }, }, { @@ -174,36 +174,36 @@ specType "specName" { }, }, then: then{ - expectedSpecifications: nil, - expectedError: RequireErrorWithCode(InvalidHCLErrorCode), + expectedUnits: nil, + expectedError: RequireErrorWithCode(InvalidHCLErrorCode), }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - l := NewHCLGenericSpecLoader() + l := NewHCLGenericUnitLoader() - actualSpecifications, err := l.Load(tt.when.source) + actualUnits, err := l.Load(tt.when.source) if tt.then.expectedError != nil { tt.then.expectedError(t, err) } else { require.NoError(t, err) } - assert.Equal(t, tt.then.expectedSpecifications, actualSpecifications) + assert.Equal(t, tt.then.expectedUnits, actualUnits) }) } } // CUSTOM CONFIG FILES // -func TestHCLSpecLoader_Load(t *testing.T) { +func TestHCLUnitLoader_Load(t *testing.T) { type when struct { source specter.Source } type then struct { - expectedSpecifications []specter.Specification - expectedError require.ErrorAssertionFunc + expectedUnits []specter.Unit + expectedError require.ErrorAssertionFunc } mockFile := HclConfigMock{} @@ -222,8 +222,8 @@ func TestHCLSpecLoader_Load(t *testing.T) { }, }, then: then{ - expectedSpecifications: nil, - expectedError: require.NoError, + expectedUnits: nil, + expectedError: require.NoError, }, }, { @@ -234,8 +234,8 @@ func TestHCLSpecLoader_Load(t *testing.T) { }, }, then: then{ - expectedSpecifications: nil, - expectedError: RequireErrorWithCode(specter.UnsupportedSourceErrorCode), + expectedUnits: nil, + expectedError: RequireErrorWithCode(specter.UnsupportedSourceErrorCode), }, }, { @@ -249,8 +249,8 @@ con st = var o }, }, then: then{ - expectedSpecifications: nil, - expectedError: RequireErrorWithCode(InvalidHCLErrorCode), + expectedUnits: nil, + expectedError: RequireErrorWithCode(InvalidHCLErrorCode), }, }, { @@ -259,26 +259,26 @@ con st = var o source: mockFile.source(), }, then: then{ - expectedSpecifications: []specter.Specification{ - mockFile.genericSpecification(), + expectedUnits: []specter.Unit{ + mockFile.genericUnit(), }, }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - l := NewHCLSpecLoader(func() HCLFileConfig { + l := NewHCLUnitLoader(func() HCLFileConfig { return &HclConfigMock{} }) - actualSpecifications, err := l.Load(tt.when.source) + actualUnits, err := l.Load(tt.when.source) if tt.then.expectedError != nil { tt.then.expectedError(t, err) } else { require.NoError(t, err) } - assert.Equal(t, tt.then.expectedSpecifications, actualSpecifications) + assert.Equal(t, tt.then.expectedUnits, actualUnits) }) } } @@ -307,26 +307,26 @@ service "specter" { `) } -func (m *HclConfigMock) Specifications() []specter.Specification { - return []specter.Specification{ - m.genericSpecification(), +func (m *HclConfigMock) Units() []specter.Unit { + return []specter.Unit{ + m.genericUnit(), } } -func (m *HclConfigMock) genericSpecification() *GenericSpecification { - spec := NewGenericSpecification("specter", "service", m.source()) +func (m *HclConfigMock) genericUnit() *GenericUnit { + spec := NewGenericUnit("specter", "service", m.source()) - spec.Attributes = append(spec.Attributes, GenericSpecAttribute{ + spec.Attributes = append(spec.Attributes, GenericUnitAttribute{ Name: "image", Value: GenericValue{ Value: cty.StringVal("specter:1.0.0"), }, }) - spec.Attributes = append(spec.Attributes, GenericSpecAttribute{ + spec.Attributes = append(spec.Attributes, GenericUnitAttribute{ Name: "dev", Value: ObjectValue{ Type: "environment", - Attributes: []GenericSpecAttribute{ + Attributes: []GenericUnitAttribute{ { Name: "MYSQL_ROOT_PASSWORD", Value: GenericValue{ diff --git a/pkg/specterutils/linting.go b/pkg/specterutils/linting.go index 55a86c8..6f9c3d4 100644 --- a/pkg/specterutils/linting.go +++ b/pkg/specterutils/linting.go @@ -24,8 +24,8 @@ import ( const LinterResultArtifactID = "_linting_processor_results" -// UndefinedSpecificationName constant used to test against undefined SpecificationName. -const UndefinedSpecificationName specter.SpecificationName = "" +// UndefinedUnitName constant used to test against undefined UnitName. +const UndefinedUnitName specter.UnitName = "" const LintingErrorCode = "specter.spec_processing.linting_error" @@ -37,10 +37,10 @@ const ( ) type LintingProcessor struct { - linters []SpecificationLinter + linters []UnitLinter } -func NewLintingProcessor(linters ...SpecificationLinter) *LintingProcessor { +func NewLintingProcessor(linters ...UnitLinter) *LintingProcessor { return &LintingProcessor{linters: linters} } @@ -49,10 +49,10 @@ func (l LintingProcessor) Name() string { } func (l LintingProcessor) Process(ctx specter.ProcessingContext) (artifacts []specter.Artifact, err error) { - linter := CompositeSpecificationLinter(l.linters...) + linter := CompositeUnitLinter(l.linters...) ctx.Logger.Info("\nLinting specifications ...") - lr := linter.Lint(ctx.Specifications) + lr := linter.Lint(ctx.Units) artifacts = append(artifacts, lr) @@ -70,7 +70,7 @@ func (l LintingProcessor) Process(ctx specter.ProcessingContext) (artifacts []sp } if !lr.HasWarnings() && !lr.HasErrors() { - ctx.Logger.Success("Specifications linted successfully.") + ctx.Logger.Success("Units linted successfully.") } return artifacts, err @@ -131,21 +131,21 @@ func (s LinterResultSet) HasWarnings() bool { return len(s.Warnings()) != 0 } -// SpecificationLinter represents a function responsible for linting specifications. -type SpecificationLinter interface { - Lint(specifications specter.SpecificationGroup) LinterResultSet +// UnitLinter represents a function responsible for linting specifications. +type UnitLinter interface { + Lint(specifications specter.UnitGroup) LinterResultSet } -// SpecificationLinterFunc implementation of a SpecificationLinter that relies on a func -type SpecificationLinterFunc func(specifications specter.SpecificationGroup) LinterResultSet +// UnitLinterFunc implementation of a UnitLinter that relies on a func +type UnitLinterFunc func(specifications specter.UnitGroup) LinterResultSet -func (l SpecificationLinterFunc) Lint(specifications specter.SpecificationGroup) LinterResultSet { +func (l UnitLinterFunc) Lint(specifications specter.UnitGroup) LinterResultSet { return l(specifications) } -// CompositeSpecificationLinter A Composite linter is responsible for running multiple linters as one. -func CompositeSpecificationLinter(linters ...SpecificationLinter) SpecificationLinterFunc { - return func(specifications specter.SpecificationGroup) LinterResultSet { +// CompositeUnitLinter A Composite linter is responsible for running multiple linters as one. +func CompositeUnitLinter(linters ...UnitLinter) UnitLinterFunc { + return func(specifications specter.UnitGroup) LinterResultSet { var result LinterResultSet for _, linter := range linters { lr := linter.Lint(specifications) @@ -155,13 +155,13 @@ func CompositeSpecificationLinter(linters ...SpecificationLinter) SpecificationL } } -// SpecificationMustNotHaveUndefinedNames ensures that no specification has an undefined name -func SpecificationMustNotHaveUndefinedNames(severity LinterResultSeverity) SpecificationLinterFunc { - return func(specifications specter.SpecificationGroup) LinterResultSet { +// UnitMustNotHaveUndefinedNames ensures that no specification has an undefined name +func UnitMustNotHaveUndefinedNames(severity LinterResultSeverity) UnitLinterFunc { + return func(specifications specter.UnitGroup) LinterResultSet { var result LinterResultSet for _, s := range specifications { - if s.Name() == UndefinedSpecificationName { + if s.Name() == UndefinedUnitName { result = append(result, LinterResult{ Severity: severity, Message: fmt.Sprintf("specification at %q has an undefined name", s.Source().Location), @@ -173,14 +173,14 @@ func SpecificationMustNotHaveUndefinedNames(severity LinterResultSeverity) Speci } } -// SpecificationsMustHaveUniqueNames ensures that names are unique amongst specifications. -func SpecificationsMustHaveUniqueNames(severity LinterResultSeverity) SpecificationLinterFunc { - return func(specifications specter.SpecificationGroup) LinterResultSet { +// UnitsMustHaveUniqueNames ensures that names are unique amongst specifications. +func UnitsMustHaveUniqueNames(severity LinterResultSeverity) UnitLinterFunc { + return func(specifications specter.UnitGroup) LinterResultSet { var result LinterResultSet // Where key is the type FilePath and the array contains all the specification file locations where it was encountered. - encounteredNames := map[specter.SpecificationName][]string{} + encounteredNames := map[specter.UnitName][]string{} for _, s := range specifications { if _, found := encounteredNames[s.Name()]; found { @@ -217,9 +217,9 @@ func SpecificationsMustHaveUniqueNames(severity LinterResultSeverity) Specificat } } -// SpecificationsMustHaveDescriptionAttribute ensures that all specifications have a description. -func SpecificationsMustHaveDescriptionAttribute(severity LinterResultSeverity) SpecificationLinterFunc { - return func(specifications specter.SpecificationGroup) LinterResultSet { +// UnitsMustHaveDescriptionAttribute ensures that all specifications have a description. +func UnitsMustHaveDescriptionAttribute(severity LinterResultSeverity) UnitLinterFunc { + return func(specifications specter.UnitGroup) LinterResultSet { var result LinterResultSet for _, s := range specifications { if s.Description() == "" { @@ -233,9 +233,9 @@ func SpecificationsMustHaveDescriptionAttribute(severity LinterResultSeverity) S } } -// SpecificationsDescriptionsMustStartWithACapitalLetter ensures that specification descriptions start with a capital letter. -func SpecificationsDescriptionsMustStartWithACapitalLetter(severity LinterResultSeverity) SpecificationLinterFunc { - return func(specifications specter.SpecificationGroup) LinterResultSet { +// UnitsDescriptionsMustStartWithACapitalLetter ensures that specification descriptions start with a capital letter. +func UnitsDescriptionsMustStartWithACapitalLetter(severity LinterResultSeverity) UnitLinterFunc { + return func(specifications specter.UnitGroup) LinterResultSet { var result LinterResultSet for _, s := range specifications { if s.Description() != "" { @@ -253,9 +253,9 @@ func SpecificationsDescriptionsMustStartWithACapitalLetter(severity LinterResult } } -// SpecificationsDescriptionsMustEndWithPeriod ensures that specification descriptions end with a period. -func SpecificationsDescriptionsMustEndWithPeriod(severity LinterResultSeverity) SpecificationLinterFunc { - return func(specifications specter.SpecificationGroup) LinterResultSet { +// UnitsDescriptionsMustEndWithPeriod ensures that specification descriptions end with a period. +func UnitsDescriptionsMustEndWithPeriod(severity LinterResultSeverity) UnitLinterFunc { + return func(specifications specter.UnitGroup) LinterResultSet { var result LinterResultSet for _, s := range specifications { if !strings.HasSuffix(s.Description(), ".") { diff --git a/pkg/specterutils/linting_test.go b/pkg/specterutils/linting_test.go index e2010dc..23f3a69 100644 --- a/pkg/specterutils/linting_test.go +++ b/pkg/specterutils/linting_test.go @@ -23,18 +23,18 @@ import ( "testing" ) -func TestSpecificationsDescriptionsMustStartWithACapitalLetter(t *testing.T) { +func TestUnitsDescriptionsMustStartWithACapitalLetter(t *testing.T) { tests := []struct { name string - given specter.SpecificationGroup + given specter.UnitGroup then LinterResultSet }{ { name: "GIVEN specification starting with an upper case letter THEN return empty result set", - given: specter.SpecificationGroup{ - &GenericSpecification{ + given: specter.UnitGroup{ + &GenericUnit{ name: "test", - Attributes: []GenericSpecAttribute{ + Attributes: []GenericUnitAttribute{ { Name: "description", Value: GenericValue{cty.StringVal("It starts with UPPERCASE")}, @@ -45,10 +45,10 @@ func TestSpecificationsDescriptionsMustStartWithACapitalLetter(t *testing.T) { }, { name: "GIVEN specification starting with lower case letter THEN return error", - given: specter.SpecificationGroup{ - &GenericSpecification{ + given: specter.UnitGroup{ + &GenericUnit{ name: "test", - Attributes: []GenericSpecAttribute{ + Attributes: []GenericUnitAttribute{ { Name: "description", Value: GenericValue{cty.StringVal("it starts with lowercase")}, @@ -66,25 +66,25 @@ func TestSpecificationsDescriptionsMustStartWithACapitalLetter(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - linter := SpecificationsDescriptionsMustStartWithACapitalLetter(ErrorSeverity) + linter := UnitsDescriptionsMustStartWithACapitalLetter(ErrorSeverity) result := linter.Lint(tt.given) require.Equal(t, tt.then, result) }) } } -func TestSpecificationsDescriptionsMustEndWithPeriod(t *testing.T) { +func TestUnitsDescriptionsMustEndWithPeriod(t *testing.T) { tests := []struct { name string - given specter.SpecificationGroup + given specter.UnitGroup then LinterResultSet }{ { name: "GIVEN specification ending with period THEN return empty result set", - given: specter.SpecificationGroup{ - &GenericSpecification{ + given: specter.UnitGroup{ + &GenericUnit{ name: "test", - Attributes: []GenericSpecAttribute{ + Attributes: []GenericUnitAttribute{ { Name: "description", Value: GenericValue{cty.StringVal("it ends with period.")}, @@ -95,10 +95,10 @@ func TestSpecificationsDescriptionsMustEndWithPeriod(t *testing.T) { }, { name: "GIVEN specification not ending with period THEN return error", - given: specter.SpecificationGroup{ - &GenericSpecification{ + given: specter.UnitGroup{ + &GenericUnit{ name: "test", - Attributes: []GenericSpecAttribute{ + Attributes: []GenericUnitAttribute{ { Name: "description", Value: GenericValue{cty.StringVal("it starts with lowercase")}, @@ -116,25 +116,25 @@ func TestSpecificationsDescriptionsMustEndWithPeriod(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - linter := SpecificationsDescriptionsMustEndWithPeriod(ErrorSeverity) + linter := UnitsDescriptionsMustEndWithPeriod(ErrorSeverity) result := linter.Lint(tt.given) require.Equal(t, tt.then, result) }) } } -func TestSpecificationsMustHaveDescriptionAttribute(t *testing.T) { +func TestUnitsMustHaveDescriptionAttribute(t *testing.T) { tests := []struct { name string - given specter.SpecificationGroup + given specter.UnitGroup then LinterResultSet }{ { name: "GIVEN specification with a description THEN return empty result set", - given: specter.SpecificationGroup{ - &GenericSpecification{ + given: specter.UnitGroup{ + &GenericUnit{ name: "test", - Attributes: []GenericSpecAttribute{ + Attributes: []GenericUnitAttribute{ { Name: "description", Value: GenericValue{cty.StringVal("I have a description")}, @@ -145,8 +145,8 @@ func TestSpecificationsMustHaveDescriptionAttribute(t *testing.T) { }, { name: "GIVEN specification with no description ", - given: specter.SpecificationGroup{ - &GenericSpecification{ + given: specter.UnitGroup{ + &GenericUnit{ name: "test", }, }, @@ -159,10 +159,10 @@ func TestSpecificationsMustHaveDescriptionAttribute(t *testing.T) { }, { name: "GIVEN specification with an empty description THEN return error", - given: specter.SpecificationGroup{ - &GenericSpecification{ + given: specter.UnitGroup{ + &GenericUnit{ name: "test", - Attributes: []GenericSpecAttribute{ + Attributes: []GenericUnitAttribute{ { Name: "description", Value: GenericValue{cty.StringVal("")}, @@ -180,37 +180,37 @@ func TestSpecificationsMustHaveDescriptionAttribute(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - linter := SpecificationsMustHaveDescriptionAttribute(ErrorSeverity) + linter := UnitsMustHaveDescriptionAttribute(ErrorSeverity) result := linter.Lint(tt.given) require.Equal(t, tt.then, result) }) } } -func TestSpecificationsMustHaveUniqueNames(t *testing.T) { +func TestUnitsMustHaveUniqueNames(t *testing.T) { tests := []struct { name string - given specter.SpecificationGroup + given specter.UnitGroup then LinterResultSet }{ { name: "GIVEN specifications with unique names THEN return empty result set", - given: specter.SpecificationGroup{ - &GenericSpecification{ + given: specter.UnitGroup{ + &GenericUnit{ name: "test", }, - &GenericSpecification{ + &GenericUnit{ name: "test2", }, }, }, { name: "GIVEN specifications with non-unique names THEN return error", - given: specter.SpecificationGroup{ - &GenericSpecification{ + given: specter.UnitGroup{ + &GenericUnit{ name: "test", }, - &GenericSpecification{ + &GenericUnit{ name: "test", }, }, @@ -224,31 +224,31 @@ func TestSpecificationsMustHaveUniqueNames(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - linter := SpecificationsMustHaveUniqueNames(ErrorSeverity) + linter := UnitsMustHaveUniqueNames(ErrorSeverity) result := linter.Lint(tt.given) require.Equal(t, tt.then, result) }) } } -func TestSpecificationMustNotHaveUndefinedNames(t *testing.T) { +func TestUnitMustNotHaveUndefinedNames(t *testing.T) { tests := []struct { name string - given specter.SpecificationGroup + given specter.UnitGroup then LinterResultSet }{ { name: "GIVEN specification with a name THEN return empty result set", - given: specter.SpecificationGroup{ - &GenericSpecification{ + given: specter.UnitGroup{ + &GenericUnit{ name: "test", }, }, }, { name: "GIVEN specification with no name THEN return error ", - given: specter.SpecificationGroup{ - &GenericSpecification{ + given: specter.UnitGroup{ + &GenericUnit{ name: "", }, }, @@ -262,17 +262,17 @@ func TestSpecificationMustNotHaveUndefinedNames(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - linter := SpecificationMustNotHaveUndefinedNames(ErrorSeverity) + linter := UnitMustNotHaveUndefinedNames(ErrorSeverity) result := linter.Lint(tt.given) require.Equal(t, tt.then, result) }) } } -func TestCompositeSpecificationLinter(t *testing.T) { +func TestCompositeUnitLinter(t *testing.T) { type args struct { - linters []SpecificationLinter - specifications specter.SpecificationGroup + linters []UnitLinter + specifications specter.UnitGroup } tests := []struct { name string @@ -282,15 +282,15 @@ func TestCompositeSpecificationLinter(t *testing.T) { { name: "GIVEN valid specifications THEN return empty result set", given: args{ - linters: []SpecificationLinter{ - SpecificationMustNotHaveUndefinedNames(ErrorSeverity), - SpecificationsDescriptionsMustStartWithACapitalLetter(ErrorSeverity), - SpecificationsDescriptionsMustEndWithPeriod(ErrorSeverity), + linters: []UnitLinter{ + UnitMustNotHaveUndefinedNames(ErrorSeverity), + UnitsDescriptionsMustStartWithACapitalLetter(ErrorSeverity), + UnitsDescriptionsMustEndWithPeriod(ErrorSeverity), }, - specifications: specter.SpecificationGroup{ - &GenericSpecification{ + specifications: specter.UnitGroup{ + &GenericUnit{ name: "test", - Attributes: []GenericSpecAttribute{ + Attributes: []GenericUnitAttribute{ { Name: "description", Value: GenericValue{cty.StringVal("This is a Description.")}, @@ -303,13 +303,13 @@ func TestCompositeSpecificationLinter(t *testing.T) { { name: "GIVEN invalid specifications THEN return empty result set", given: args{ - linters: []SpecificationLinter{ - SpecificationMustNotHaveUndefinedNames(ErrorSeverity), - SpecificationsDescriptionsMustStartWithACapitalLetter(ErrorSeverity), - SpecificationsDescriptionsMustEndWithPeriod(ErrorSeverity), + linters: []UnitLinter{ + UnitMustNotHaveUndefinedNames(ErrorSeverity), + UnitsDescriptionsMustStartWithACapitalLetter(ErrorSeverity), + UnitsDescriptionsMustEndWithPeriod(ErrorSeverity), }, - specifications: specter.SpecificationGroup{ - &GenericSpecification{ + specifications: specter.UnitGroup{ + &GenericUnit{ name: "", }, }, @@ -333,7 +333,7 @@ func TestCompositeSpecificationLinter(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - linter := CompositeSpecificationLinter(tt.given.linters...) + linter := CompositeUnitLinter(tt.given.linters...) result := linter.Lint(tt.given.specifications) require.Equal(t, tt.then, result) }) @@ -478,7 +478,7 @@ func TestLintingProcessor_Name(t *testing.T) { func TestLintingProcessor_Process(t *testing.T) { type args struct { - linters []SpecificationLinter + linters []UnitLinter ctx specter.ProcessingContext } tests := []struct { @@ -503,14 +503,14 @@ func TestLintingProcessor_Process(t *testing.T) { { name: "GIVEN a processing context with specifications that raise warnings THEN return a processing artifact with the result set", given: args{ - linters: []SpecificationLinter{ - SpecificationLinterFunc(func(specifications specter.SpecificationGroup) LinterResultSet { + linters: []UnitLinter{ + UnitLinterFunc(func(specifications specter.UnitGroup) LinterResultSet { return LinterResultSet{{Severity: WarningSeverity, Message: "a warning"}} }), }, ctx: specter.ProcessingContext{ - Specifications: []specter.Specification{NewGenericSpecification("spec", "spec_type", specter.Source{})}, - Logger: specter.NewDefaultLogger(specter.DefaultLoggerConfig{}), + Units: []specter.Unit{NewGenericUnit("spec", "spec_type", specter.Source{})}, + Logger: specter.NewDefaultLogger(specter.DefaultLoggerConfig{}), }, }, then: []specter.Artifact{ @@ -520,14 +520,14 @@ func TestLintingProcessor_Process(t *testing.T) { { name: "GIVEN a processing context that will raise errors THEN return errors", given: args{ - linters: []SpecificationLinter{ - SpecificationLinterFunc(func(specifications specter.SpecificationGroup) LinterResultSet { + linters: []UnitLinter{ + UnitLinterFunc(func(specifications specter.UnitGroup) LinterResultSet { return LinterResultSet{{Severity: ErrorSeverity, Message: assert.AnError.Error()}} }), }, ctx: specter.ProcessingContext{ - Specifications: []specter.Specification{NewGenericSpecification("spec", "spec_type", specter.Source{})}, - Logger: specter.NewDefaultLogger(specter.DefaultLoggerConfig{}), + Units: []specter.Unit{NewGenericUnit("spec", "spec_type", specter.Source{})}, + Logger: specter.NewDefaultLogger(specter.DefaultLoggerConfig{}), }, }, then: []specter.Artifact{ @@ -538,8 +538,8 @@ func TestLintingProcessor_Process(t *testing.T) { { name: "GIVEN a processing context that will raise both errors and warnings THEN return errors and warnings", given: args{ - linters: []SpecificationLinter{ - SpecificationLinterFunc(func(specifications specter.SpecificationGroup) LinterResultSet { + linters: []UnitLinter{ + UnitLinterFunc(func(specifications specter.UnitGroup) LinterResultSet { return LinterResultSet{ { Severity: ErrorSeverity, Message: assert.AnError.Error(), @@ -551,8 +551,8 @@ func TestLintingProcessor_Process(t *testing.T) { }), }, ctx: specter.ProcessingContext{ - Specifications: []specter.Specification{NewGenericSpecification("spec", "spec_type", specter.Source{})}, - Logger: specter.NewDefaultLogger(specter.DefaultLoggerConfig{}), + Units: []specter.Unit{NewGenericUnit("spec", "spec_type", specter.Source{})}, + Logger: specter.NewDefaultLogger(specter.DefaultLoggerConfig{}), }, }, then: []specter.Artifact{ diff --git a/pkg/specterutils/specterutils_test.go b/pkg/specterutils/specterutils_test.go index 192aadf..0850cac 100644 --- a/pkg/specterutils/specterutils_test.go +++ b/pkg/specterutils/specterutils_test.go @@ -1,3 +1,17 @@ +// Copyright 2024 Morébec +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package specterutils import ( diff --git a/pkg/specterutils/specversion.go b/pkg/specterutils/specversion.go index b77ef15..e08b5b9 100644 --- a/pkg/specterutils/specversion.go +++ b/pkg/specterutils/specversion.go @@ -19,18 +19,18 @@ import ( "github.com/morebec/specter/pkg/specter" ) -type SpecificationVersion string +type UnitVersion string type HasVersion interface { - specter.Specification + specter.Unit - Version() SpecificationVersion + Version() UnitVersion } -func HasVersionMustHaveAVersionLinter(severity LinterResultSeverity) SpecificationLinter { - return SpecificationLinterFunc(func(specifications specter.SpecificationGroup) LinterResultSet { +func HasVersionMustHaveAVersionLinter(severity LinterResultSeverity) UnitLinter { + return UnitLinterFunc(func(specifications specter.UnitGroup) LinterResultSet { var r LinterResultSet - specs := specifications.Select(func(s specter.Specification) bool { + specs := specifications.Select(func(s specter.Unit) bool { if _, ok := s.(HasVersion); ok { return true } diff --git a/pkg/specterutils/specversion_test.go b/pkg/specterutils/specversion_test.go index ea3d637..e7275e9 100644 --- a/pkg/specterutils/specversion_test.go +++ b/pkg/specterutils/specversion_test.go @@ -20,72 +20,72 @@ import ( "testing" ) -// Mock implementations for the Specification and HasVersion interfaces +// Mock implementations for the Unit and HasVersion interfaces -var _ specter.Specification = (*mockSpecification)(nil) +var _ specter.Unit = (*mockUnit)(nil) -type mockSpecification struct { - name specter.SpecificationName +type mockUnit struct { + name specter.UnitName description string source specter.Source - version SpecificationVersion - typeName specter.SpecificationType + version UnitVersion + typeName specter.UnitType } -func (m *mockSpecification) Name() specter.SpecificationName { +func (m *mockUnit) Name() specter.UnitName { return m.name } -func (m *mockSpecification) Type() specter.SpecificationType { +func (m *mockUnit) Type() specter.UnitType { return m.typeName } -func (m *mockSpecification) Description() string { +func (m *mockUnit) Description() string { return m.description } -func (m *mockSpecification) SetSource(s specter.Source) { +func (m *mockUnit) SetSource(s specter.Source) { m.source = s } -func (m *mockSpecification) Source() specter.Source { +func (m *mockUnit) Source() specter.Source { return m.source } -func (m *mockSpecification) Version() SpecificationVersion { +func (m *mockUnit) Version() UnitVersion { return m.version } func TestHasVersionMustHaveAVersionLinter(t *testing.T) { tests := []struct { name string - when specter.SpecificationGroup + when specter.UnitGroup expectedResults LinterResultSet givenSeverity LinterResultSeverity }{ { name: "WHEN some specification does not implement HasVersion, THEN ignore said specification", - when: specter.SpecificationGroup{ - &mockSpecification{name: "spec1", version: "v1"}, - NewGenericSpecification("not-versioned", "spec", specter.Source{}), + when: specter.UnitGroup{ + &mockUnit{name: "spec1", version: "v1"}, + NewGenericUnit("not-versioned", "spec", specter.Source{}), }, givenSeverity: WarningSeverity, expectedResults: LinterResultSet(nil), }, { name: "WHEN all specifications have a version THEN return no warnings or errors", - when: specter.SpecificationGroup{ - &mockSpecification{name: "spec1", version: "v1"}, - &mockSpecification{name: "spec2", version: "v2"}, + when: specter.UnitGroup{ + &mockUnit{name: "spec1", version: "v1"}, + &mockUnit{name: "spec2", version: "v2"}, }, givenSeverity: WarningSeverity, expectedResults: LinterResultSet(nil), }, { name: "WHEN one specification is missing a version and severity is Warning THEN return a warning", - when: specter.SpecificationGroup{ - &mockSpecification{name: "spec1", version: "v1"}, - &mockSpecification{name: "spec2", version: ""}, + when: specter.UnitGroup{ + &mockUnit{name: "spec1", version: "v1"}, + &mockUnit{name: "spec2", version: ""}, }, givenSeverity: WarningSeverity, expectedResults: LinterResultSet{ @@ -97,9 +97,9 @@ func TestHasVersionMustHaveAVersionLinter(t *testing.T) { }, { name: "WHEN one specification is missing a version and severity is error THEN return an error", - when: specter.SpecificationGroup{ - &mockSpecification{name: "spec1", version: "v1"}, - &mockSpecification{name: "spec2", version: ""}, + when: specter.UnitGroup{ + &mockUnit{name: "spec1", version: "v1"}, + &mockUnit{name: "spec2", version: ""}, }, givenSeverity: ErrorSeverity, expectedResults: LinterResultSet{ @@ -111,9 +111,9 @@ func TestHasVersionMustHaveAVersionLinter(t *testing.T) { }, { name: "multiple specifications are missing versions", - when: specter.SpecificationGroup{ - &mockSpecification{name: "spec1", version: ""}, - &mockSpecification{name: "spec2", version: ""}, + when: specter.UnitGroup{ + &mockUnit{name: "spec1", version: ""}, + &mockUnit{name: "spec2", version: ""}, }, givenSeverity: ErrorSeverity, expectedResults: LinterResultSet{