Skip to content

Commit

Permalink
Sync with Cecille's PR, but in handlebars format
Browse files Browse the repository at this point in the history
  • Loading branch information
hasty committed Oct 25, 2024
1 parent 8f1f1b1 commit 27937d8
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 54 deletions.
73 changes: 47 additions & 26 deletions testplan/conformance.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,34 +40,55 @@ func conformanceHelper(doc conformance.ReferenceStore, cluster matter.Cluster, c
return raymond.SafeString(b.String())
}

func renderChoice(c *conformance.Optional, b *strings.Builder) {
// PICS tool does not support + style conformances, so unless this is a "pick one" choice,
//render as fully optional, we'll check the choice conformance properly in the tests.
o := conformance.ChoiceExactLimit{Limit: 1}
if c.Choice != nil && o.Equal(c.Choice.Limit) {
b.WriteRune('.')
b.WriteString(c.Choice.ASCIIDocString())
}
}

func renderConformance(cs conformance.Set, b *strings.Builder, doc conformance.ReferenceStore, cluster *matter.Cluster, formatter conformanceEntityFormatter) {
for _, c := range cs {
switch c := c.(type) {
case *conformance.Mandatory:
if c.Expression == nil {
b.WriteString("M")
continue
}
renderExpression(b, doc, cluster, c.Expression, formatter)
case *conformance.Optional:
if c.Expression == nil {
b.WriteString("O")
if c.Choice != nil {
b.WriteRune('.')
b.WriteString(c.Choice.ASCIIDocString())
}
continue
}
b.WriteRune('[')
renderExpression(b, doc, cluster, c.Expression, formatter)
b.WriteRune(']')
if c.Choice != nil {
b.WriteRune('.')
b.WriteString(c.Choice.ASCIIDocString())
}
// PICS tool can't handle otherwise conformances, so render anything with an otherwise conformance as optional for the purposes of the
// test plan PICS. This can be fully evaluated in the tests.
// The only exception is if it is provisional, which should be rendered as X.
if len(cs) != 1 {
switch cs[0].(type) {
case *conformance.Provisional:
b.WriteRune('X')
default:
b.WriteString(fmt.Sprintf("unknown conformance: %T", c))
b.WriteString("{PICS_S}: O")
}
return
}
switch c := cs[0].(type) {
case *conformance.Mandatory:
if c.Expression == nil {
b.WriteString("{PICS_S}: M")
return
}
renderExpression(b, doc, cluster, c.Expression, formatter)
case *conformance.Optional:
if c.Expression == nil {
b.WriteString("{PICS_S}: O")
renderChoice(c, b)
return
}
renderExpression(b, doc, cluster, c.Expression, formatter)
b.WriteString(": O")
renderChoice(c, b)
case *conformance.Provisional:
b.WriteRune('X')
case *conformance.Disallowed:
b.WriteRune('X')
case *conformance.Deprecated:
b.WriteRune('X')
case *conformance.Described:
b.WriteString("{PICS_S}: O")
default:
b.WriteString(fmt.Sprintf("unknown conformance: %T", c))
}
}

Expand All @@ -87,7 +108,7 @@ func renderExpression(b *strings.Builder, doc conformance.ReferenceStore, cluste
b.WriteString(renderReference(doc, exp.Reference, formatter))
case *conformance.LogicalExpression:
if exp.Not {
b.WriteRune('!')
b.WriteString("NOT")
}
b.WriteRune('(')
renderExpression(b, doc, cluster, exp.Left, formatter)
Expand Down
44 changes: 31 additions & 13 deletions testplan/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,20 @@ import (
"github.com/project-chip/alchemy/matter/types"
)

type GeneratorOption func(g *Generator)

type Generator struct {
testPlanRoot string
templateRoot string
overwrite bool
}

func TemplateRoot(templateRoot string) func(*Generator) {
return func(g *Generator) {
g.templateRoot = templateRoot
}
}

func (sp Generator) Name() string {
return "Generating test plans"
}
Expand All @@ -46,7 +55,7 @@ func (sp *Generator) Process(cxt context.Context, input *pipeline.Data[*spec.Doc
destinations := buildDestinations(sp.testPlanRoot, entities, doc.Errata().TestPlan)

var t *raymond.Template
t, err = loadTemplate()
t, err = sp.loadTemplate()
if err != nil {
return
}
Expand Down Expand Up @@ -100,8 +109,12 @@ func (sp *Generator) Process(cxt context.Context, input *pipeline.Data[*spec.Doc
return
}

func NewGenerator(testPlanRoot string, overwrite bool) *Generator {
return &Generator{testPlanRoot: testPlanRoot, overwrite: overwrite}
func NewGenerator(testPlanRoot string, overwrite bool, options ...GeneratorOption) *Generator {
g := &Generator{testPlanRoot: testPlanRoot, overwrite: overwrite}
for _, o := range options {
o(g)
}
return g
}

func getTestPlanPath(testplanRoot string, name string) string {
Expand Down Expand Up @@ -133,20 +146,25 @@ func buildDestinations(testplanRoot string, entities []types.Entity, errata erra
switch e := e.(type) {
case *matter.ClusterGroup:
for _, c := range e.Clusters {
fileName := strings.ToLower(strcase.ToSnake(c.Name))
newPath := getTestPlanPath(testplanRoot, fileName)
destinations[newPath] = c
destinations[getTestPlanPathForCluster(testplanRoot, c, errata)] = c
}
case *matter.Cluster:
var newPath string
if errata.TestPlanPath != "" {
newPath = filepath.Join(testplanRoot, errata.TestPlanPath)
} else {
newPath = getTestPlanPath(testplanRoot, strings.ToLower(strcase.ToSnake(e.Name)))
}
destinations[newPath] = e
destinations[getTestPlanPathForCluster(testplanRoot, e, errata)] = e
}
}
return

}

func getTestPlanPathForCluster(testplanRoot string, cluster *matter.Cluster, errata errata.TestPlan) string {
if len(errata.TestPlanPaths) > 0 {
tpp, ok := errata.TestPlanPaths[cluster.Name]
if ok {
return filepath.Join(testplanRoot, tpp.Path)
}
}
if errata.TestPlanPath != "" {
return filepath.Join(testplanRoot, errata.TestPlanPath)
}
return getTestPlanPath(testplanRoot, strings.ToLower(strcase.ToSnake(cluster.Name)))
}
20 changes: 16 additions & 4 deletions testplan/identifiers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package testplan

import (
"fmt"
"strings"

"github.com/iancoleman/strcase"
"github.com/mailgun/raymond/v2"
"github.com/project-chip/alchemy/internal/handlebars"
"github.com/project-chip/alchemy/matter"
Expand All @@ -23,14 +23,14 @@ func entityIdentifier(entity types.Entity) string {
case *matter.Field:
switch entity.EntityType() {
case types.EntityTypeAttribute:
return fmt.Sprintf("A_%s", strcase.ToScreamingSnake(entity.Name))
return fmt.Sprintf("A_%s", strings.ToUpper(matter.CaseWithSeparator(entity.Name, '_')))
}
case *matter.Feature:
return fmt.Sprintf("F_%s", entity.Code)
case *matter.Event:
return fmt.Sprintf("E_%s", strcase.ToScreamingSnake(entity.Name))
return fmt.Sprintf("E_%s", strings.ToUpper(matter.CaseWithSeparator(entity.Name, '_')))
case *matter.Command:
return fmt.Sprintf("C_%s", strcase.ToScreamingSnake(entity.Name))
return fmt.Sprintf("C_%s", strings.ToUpper(matter.CaseWithSeparator(entity.Name, '_')))
}
return fmt.Sprintf("UNKNOWN_TYPE_%T", entity)
}
Expand All @@ -50,6 +50,18 @@ func entityIdentifierPaddedHelper(list any, entity types.Entity) raymond.SafeStr
return raymond.SafeString(fmt.Sprintf("%-*s", longest, entityIdentifier(entity)))
}

func entityIdentifierPaddingHelper(list any, entity types.Entity) raymond.SafeString {
var longest int
for entity := range handlebars.Iterate[types.Entity](list) {
id := entityIdentifier(entity)
if len(id) > longest {
longest = len(id)
}
}
id := entityIdentifier(entity)
return raymond.SafeString(strings.Repeat(" ", longest-len(id)))
}

func idHelper(id matter.Number, options *raymond.Options) raymond.SafeString {
format := options.HashStr("format")
if format == "" {
Expand Down
11 changes: 8 additions & 3 deletions testplan/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package testplan
import (
"embed"
"fmt"
"io/fs"
"path/filepath"
"strings"

Expand All @@ -21,9 +22,12 @@ type templateContext struct {
ReferenceStore conformance.ReferenceStore
}

func loadTemplate() (*raymond.Template, error) {
func (sp *Generator) loadTemplate() (*raymond.Template, error) {
t, err := template.Do(func() (*raymond.Template, error) {
files, err := templateFiles.ReadDir("templates")

ov := handlebars.NewOverlay(sp.templateRoot, templateFiles)

files, err := ov.ReadDir("templates")
if err != nil {
return nil, err
}
Expand All @@ -43,6 +47,7 @@ func loadTemplate() (*raymond.Template, error) {
t.RegisterHelper("shortId", shortIdHelper)
t.RegisterHelper("entityId", entityIdentifierHelper)
t.RegisterHelper("entityIdPadded", entityIdentifierPaddedHelper)
t.RegisterHelper("entityIdPadding", entityIdentifierPaddingHelper)
t.RegisterHelper("dataType", dataTypeHelper)
t.RegisterHelper("dataTypeArticle", dataTypeArticleHelper)
t.RegisterHelper("ifHasQuality", ifHasQualityHelper)
Expand All @@ -57,7 +62,7 @@ func loadTemplate() (*raymond.Template, error) {
continue
}
name := file.Name()
val, err := templateFiles.ReadFile(filepath.Join("templates/", name))
val, err := fs.ReadFile(ov, filepath.Join("templates/", name))
if err != nil {
return nil, fmt.Errorf("error reading template file %s: %w", name, err)
}
Expand Down
9 changes: 7 additions & 2 deletions testplan/templates/attributes.handlebars
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,19 @@


{{#each attributes}}
:PICS_S{{entityIdPadded attributes this}} : {PICS_S}.A{{id this.ID}}({{#brace}}{{entityId this}}{{/brace}})
:PICS_S{{id this.ID}}{{entityIdPadding attributes this}} : {PICS_S}.A{{id this.ID}}({{#brace}}{{entityId this}}{{/brace}})
{{/each}}


{{#each attributes}}
:PICS_S{{id this.ID}}_CONFORMANCE{{entityIdPadding attributes this}} : {PICS_S}.A{{id this.ID}}({{#brace}}{{entityId this}}{{/brace}})
{{/each}}


|===
| *Variable* | *Description* | *Mandatory/Optional* | *Notes/Additional Constraints*
{{#each attributes}}
| {{#brace}}PICS_S{{entityId this}}{{/brace}}| {devimp} the _{{#brace}}{{entityId this}}{{/brace}}_ attribute?| {{#if this.conformance}}{PICS_S}: {{picsConformance context.referenceStore cluster this.conformance}}{{/if}} |
| {{#brace}}PICS_S{{entityId this}}{{/brace}}| {devimp} the _{{#brace}}{{entityId this}}{{/brace}}_ attribute?| {{#if this.conformance}}{{picsConformance context.referenceStore cluster this.conformance}}{{/if}} |
{{/each}}
|===

Expand Down
4 changes: 2 additions & 2 deletions testplan/templates/commands.handlebars
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
|===
| *Variable* | *Description* | *Mandatory/Optional* | *Notes/Additional Constraints*
{{#each commandsAccepted}}
| {{#brace}}PICS_S{{entityId this}}{{/brace}} | {devimp} the _{{#brace}}{{entityId this}}{{/brace}}_ command?| {{#if this.conformance}}{PICS_S}: {{picsConformance context.referenceStore cluster this.conformance}}{{/if}} |
| {{#brace}}PICS_S{{entityId this}}{{/brace}} | {devimp} the _{{#brace}}{{entityId this}}{{/brace}}_ command?| {{#if this.conformance}}{{picsConformance context.referenceStore cluster this.conformance}}{{/if}} |
{{/each}}
|===

Expand All @@ -35,7 +35,7 @@
|===
| *Variable* | *Description* | *Mandatory/Optional* | *Notes/Additional Constraints*
{{#each commandsGenerated}}
| {{#brace}}PICS_S{{entityId this}}{{/brace}} | {devimp} sending the _{{#brace}}{{entityId this}}{{/brace}}_ command?| {{#if this.conformance}}{PICS_S}: {{picsConformance context.referenceStore cluster this.conformance}}{{/if}} |
| {{#brace}}PICS_S{{entityId this}}{{/brace}} | {devimp} sending the _{{#brace}}{{entityId this}}{{/brace}}_ command?| {{#if this.conformance}}{{picsConformance context.referenceStore cluster this.conformance}}{{/if}} |
{{/each}}
|===

Expand Down
10 changes: 7 additions & 3 deletions testplan/templates/events.handlebars
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,21 @@


{{#each events}}
:{{entityIdPadded events this}}: {{raw this.Name}}
:{{entityId this}}{{entityIdPadding events this}}: {{raw this.Name}}
{{/each}}

{{#each events}}
:PICS_S{{entityIdPadded events this}} : {PICS_S}.E{{id this.ID}}({{#brace}}{{entityId this}}{{/brace}})
:PICS_S{{entityId this}}{{entityIdPaddin events this}} : {PICS_S}.E{{id this.ID}}({{#brace}}{{entityId this}}{{/brace}})
{{/each}}

{{#each events}}
:PICS_S{{entityId this}}_CONFORMANCE{{entityIdPaddin events this}} : {PICS_S}.E{{id this.ID}}({{#brace}}{{entityId this}}{{/brace}})
{{/each}}

|===
| *Variable* | *Description* | *Mandatory/Optional* | *Notes/Additional Constraints*
{{#each events}}
| {{#brace}}PICS_S{{entityId this}}{{/brace}} | {devimp} sending the _{{#brace}}{{entityId this}}{{/brace}}_ event?| {{#if this.conformance}}{PICS_S}: {{picsConformance context.referenceStore cluster this.conformance}}{{/if}} |
| {{#brace}}PICS_S{{entityId this}}{{/brace}} | {devimp} sending the _{{#brace}}{{entityId this}}{{/brace}}_ event?| {{#if this.conformance}}{{picsConformance context.referenceStore cluster this.conformance}}{{/if}} |
{{/each}}
|===

Expand Down
6 changes: 5 additions & 1 deletion testplan/templates/features.handlebars
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@
:PICS_SF_{{raw this.Code}}: {PICS_S}.F{{format @index "%02d"}}({{#brace}}F_{{raw this.Code}}{{/brace}})
{{/each}}

{{#each features}}
:PICS_SF_{{raw this.Code}}_CONFORMANCE: {PICS_S}.F{{format @index "%02d"}}({{#brace}}F_{{raw this.Code}}{{/brace}})
{{/each}}

|===
| *Variable* | *Description* | *Mandatory/Optional* | *Notes/Additional Constraints*
{{#each features}}
| {PICS_SF_{{raw this.Code ~}}
} | {devsup} | {{raw this.Summary}} | {{#if this.Conformance}}{PICS_S}: {{conformance context.referenceStore cluster this.Conformance}}{{/if}}
} | {devsup} | {{raw this.Summary}} | {{#if this.Conformance}}{{conformance context.referenceStore cluster this.Conformance}}{{/if}}
{{/each}}
|===

Expand Down
1 change: 1 addition & 0 deletions testplan/templates/test_plan.handlebars
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ This section covers the {clustername} Cluster Test Plan related PICS items that
|===
| *Variable* | *Description* | *Mandatory/Optional* | *Notes/Additional Constraints*
| {PICS_S} | {devimp} the {clustername} cluster as a server? | O |
| {PICS_C} | {devimp} the {clustername} cluster as a client? | O |
|===

=== Server
Expand Down

0 comments on commit 27937d8

Please sign in to comment.