blob: 0f6f9015523ca5a6d2e91f42eebcc81e68796873 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package codifier
import (
"fmt"
"testing"
)
// Blackbox testing. In contrast to the other specific tests, this test checks
// expected output for a given input and a given sequence of Proc operators. For
// each test, a new operator is initialized containing the input string, the
// function applies the operators, and the result is compared to the expected
// string.
func TestOperators(t *testing.T) {
tests := []struct {
fn func(i string) *Proc
in, rExp string
}{
{func(i string) *Proc { return NewProcFromString(i) },
"a",
"a"},
// Note that when we find g("a"), the scope string that we store in
// p.replacement includes the the type/name, the braces, and everything
// inside the {}:`1g("a"){g("b"){g("c"){a}}}`. So here, the ones, which are
// outside, are not changed.
{func(i string) *Proc {
return NewProcFromString(i).ScopeNamed("a").Change("1", "2").
ApplyChanges()
},
`1 g("a"){g("b"){g("c"){a}}}1`,
`1 g("a"){g("b"){g("c"){a}}}1`},
// However, because the type/name is included in the scope string, it's
// possible to change all of the types of a scope at once including the
// found one and the ones inside the found scope. Here, all of the g()
// types are changed to g2.
{func(i string) *Proc {
return NewProcFromString(i).ScopeNamed("a").Change("g", "g2").
ApplyChanges()
},
`2g("a"){g("b"){g("c"){a}}}`,
`2g2("a"){g2("b"){g2("c"){a}}}`},
// So for more specificity, drill into another scope. Here, after scoping
// down to the scope named b, it and its child scope types are renamed to
// g2, but the parent is not.
{func(i string) *Proc {
return NewProcFromString(i).ScopeNamed("a").ScopeNamed("b").
Change("g", "g2").ApplyChanges()
},
`3g("a"){g("b"){g("c"){a}}}`,
`3g("a"){g2("b"){g2("c"){a}}}`},
// It's possible to change the name of a scope after it's found. In this
// case, the simple Change() replacement operator is used. In practice, use
// the ChangeName() operator.
{func(i string) *Proc {
return NewProcFromString(i).ScopeNamed("a").ScopeNamed("b").
Change("b", "c2").ApplyChanges()
}, `4g("a"){g("b"){g("c"){a}}}`, `4g("a"){g("c2"){g("c"){a}}}`},
// Here, the scopes are fully drilled into, then the contents changed.
{func(i string) *Proc {
return NewProcFromString(i).ScopeNamed("a").ScopeNamed("b").
ScopeNamed("c").Change("a", "c2").ApplyChanges()
},
`5g("a"){g("b"){g("c"){a}}}`,
`5g("a"){g("b"){g("c"){c2}}}`},
}
for i, tt := range tests {
testname := fmt.Sprintf("(%q)[%d]", tt.in, i)
t.Run(testname, func(t *testing.T) {
p := tt.fn(tt.in)
if p == nil {
t.Errorf("want %s, got p == nil", tt.rExp)
} else {
rOut := p.replacement
if rOut != tt.rExp {
t.Errorf("want %s, got %s)", tt.rExp, rOut)
}
}
})
}
}