| // 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) |
| } |
| } |
| }) |
| } |
| } |