Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions policy/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,22 @@ func (p *Policy) SetMetadata(name string, value any) {
p.metadata[name] = value
}

// GetExplanationOutputPolicy returns a copy of the policy, except the output of each match block
// is replaced by the expression in the explanation field.
func (p *Policy) GetExplanationOutputPolicy() *Policy {
ep := Policy{
name: p.name,
semantic: p.semantic,
info: &*p.info,
metadata: p.metadata,
source: &*p.source,
}
if p.rule != nil {
ep.rule = p.rule.getExplanationOutputRule()
}
return &ep
}

// NewRule creates a Rule instance.
func NewRule() *Rule {
return &Rule{
Expand Down Expand Up @@ -165,6 +181,28 @@ func (r *Rule) AddVariable(v *Variable) {
r.variables = append(r.variables, v)
}

func (r *Rule) getExplanationOutputRule() *Rule {
if r == nil {
return nil
}
er := Rule{
id: r.id,
description: r.description,
}
for _, variable := range r.variables {
er.variables = append(er.variables, &*variable)
}
for _, match := range r.matches {
em := Match{
condition: match.condition,
output: match.explanation,
rule: match.rule.getExplanationOutputRule(),
}
er.matches = append(er.matches, &em)
}
return &er
}

// NewVariable creates a variable instance.
func NewVariable() *Variable {
return &Variable{}
Expand Down
52 changes: 52 additions & 0 deletions policy/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,55 @@ rule:
}
}
}

func TestGetExplanationOutputPolicy(t *testing.T) {
tst := `
rule:
match:
- condition: "false"
rule:
match:
- condition: "1 > 2"
output: "false"
explanation: "'bad_inner'"
- output: "true"
explanation: "'good_inner'"
- output: "true"
explanation: "'good_outer'"
`

parser, err := NewParser()
if err != nil {
t.Fatalf("NewParser() failed: %v", err)
}
policy, iss := parser.Parse(StringSource(tst, "<input>"))
if iss != nil {
t.Fatalf("Parse() failed: %v", err)
}

explanationPolicy := policy.GetExplanationOutputPolicy()

want := "'bad_inner'"
got := explanationPolicy.Rule().Matches()[0].rule.Matches()[0].output.Value
if got != want {
t.Errorf("First inner output = %v, wanted %v", got, want)
}

want = "1 > 2"
got = explanationPolicy.Rule().Matches()[0].rule.Matches()[0].condition.Value
if got != want {
t.Errorf("First inner condition = %v, wanted %v", got, want)
}

want = "'good_inner'"
got = explanationPolicy.Rule().Matches()[0].rule.Matches()[1].output.Value
if got != want {
t.Errorf("Second inner output = %v, wanted %v", got, want)
}

want = "'good_outer'"
got = explanationPolicy.Rule().Matches()[1].output.Value
if got != want {
t.Errorf("Second outer output = %v, wanted %v", got, want)
}
}