| // Copyright 2019 CUE Authors |
| // |
| // 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 trim |
| |
| import ( |
| "flag" |
| "testing" |
| |
| "cuelang.org/go/cue" |
| "cuelang.org/go/cue/ast" |
| "cuelang.org/go/cue/errors" |
| "cuelang.org/go/cue/format" |
| "cuelang.org/go/cue/parser" |
| "cuelang.org/go/internal/cuetxtar" |
| "github.com/rogpeppe/go-internal/txtar" |
| ) |
| |
| var update = flag.Bool("update", false, "update the test files") |
| |
| func TestFiles(t *testing.T) { |
| testCases := []struct { |
| name string |
| in string |
| out string |
| }{{ |
| name: "optional does not remove required", |
| in: ` |
| a: ["aFoo"]: 3 |
| a: aFoo: _ |
| |
| a: { |
| {["aFoo"]: 3} |
| aFoo: _ |
| } |
| |
| ["aFoo"]: 3 |
| aFoo: _ |
| `, |
| out: `a: ["aFoo"]: 3 |
| a: aFoo: _ |
| |
| a: { |
| {["aFoo"]: 3} |
| aFoo: _ |
| } |
| |
| ["aFoo"]: 3 |
| aFoo: _ |
| `, |
| }, { |
| // TODO: make this optional |
| name: "defaults can remove non-defaults", |
| in: ` |
| foo: [string]: a: *1 | int |
| foo: b: a: 1 |
| `, |
| out: `foo: [string]: a: *1 | int |
| foo: b: {} |
| `, |
| }, { |
| name: "remove top-level struct", |
| in: ` |
| a: b: 3 |
| for k, v in a { |
| c: "\(k)": v |
| } |
| c: b: 3 |
| |
| z: { |
| a: b: 3 |
| for k, v in a { |
| c: "\(k)": v |
| } |
| c: b: 3 |
| } |
| `, |
| out: `a: b: 3 |
| for k, v in a { |
| c: "\(k)": v |
| } |
| |
| z: { |
| a: b: 3 |
| for k, v in a { |
| c: "\(k)": v |
| } |
| } |
| `, |
| }, { |
| name: "do not remove field", |
| in: ` |
| {[_]: x: "hello"} |
| a: x: "hello" |
| `, |
| out: ` |
| {[_]: x: "hello"} |
| a: {} |
| `, |
| }, { |
| name: "issue303", |
| in: ` |
| foo: c: true |
| foo: #M |
| #M: c?: bool |
| `, |
| out: `foo: c: true |
| foo: #M |
| #M: c?: bool |
| `, |
| }, { |
| name: "remove due to simplification", |
| in: ` |
| foo: [string]: { |
| t: [string]: { |
| x: >=0 & <=5 |
| } |
| } |
| |
| foo: multipath: { |
| t: [string]: { |
| // Combined with the other constraints, we know the value must be 5 and |
| // thus the entry below can be eliminated. |
| x: >=5 & <=8 & int |
| } |
| |
| t: u: { x: 5 } // TODO: should be t: u: {} |
| } |
| |
| group: { |
| for k, v in foo { |
| comp: "\(k)": v |
| } |
| } |
| |
| `, |
| out: `foo: [string]: { |
| t: [string]: { |
| x: >=0 & <=5 |
| } |
| } |
| |
| foo: multipath: { |
| t: [string]: { |
| |
| x: >=5 & <=8 & int |
| } |
| |
| t: u: {x: 5} |
| } |
| |
| group: { |
| for k, v in foo { |
| comp: "\(k)": v |
| } |
| } |
| `, |
| }, { |
| name: "list removal", |
| in: ` |
| service: [string]: { |
| ports: [{a: 1}, {a: 1}, ...{ extra: 3 }] |
| } |
| service: a: { |
| ports: [{a: 1}, {a: 1, extra: 3}, {}, { extra: 3 }] |
| } |
| `, |
| out: `service: [string]: { |
| ports: [{a: 1}, {a: 1}, ...{extra: 3}] |
| } |
| service: a: { |
| ports: [{}, {extra: 3}, {}, {}] |
| } |
| `, |
| }, { |
| name: "do not overmark comprehension", |
| in: ` |
| foo: multipath: { |
| t: [string]: { x: 5 } |
| |
| // Don't remove u! |
| t: u: { x: 5 } |
| } |
| |
| group: { |
| for k, v in foo { |
| comp: "\(k)": v |
| } |
| } |
| |
| `, |
| out: `foo: multipath: { |
| t: [string]: {x: 5} |
| |
| t: u: {} |
| } |
| |
| group: { |
| for k, v in foo { |
| comp: "\(k)": v |
| } |
| } |
| `, |
| }, { |
| name: "list removal", |
| in: ` |
| service: [string]: { |
| ports: [{a: 1}, {a: 1}, ...{ extra: 3 }] |
| } |
| service: a: { |
| ports: [{a: 1}, {a: 1, extra: 3}, {}, { extra: 3 }] |
| } |
| `, |
| out: `service: [string]: { |
| ports: [{a: 1}, {a: 1}, ...{extra: 3}] |
| } |
| service: a: { |
| ports: [{}, {extra: 3}, {}, {}] |
| } |
| `, |
| // }, { |
| // TODO: This used to work. |
| // name: "remove implied interpolations", |
| // in: ` |
| // foo: [string]: { |
| // a: string |
| // b: "--\(a)--" |
| // } |
| // foo: entry: { |
| // a: "insert" |
| // b: "--insert--" |
| // } |
| // `, |
| // out: ``, |
| }} |
| for _, tc := range testCases { |
| t.Run(tc.name, func(t *testing.T) { |
| f, err := parser.ParseFile("test", tc.in) |
| if err != nil { |
| t.Fatal(err) |
| } |
| r := Runtime{} |
| inst, err := r.CompileFile(f) |
| if err != nil { |
| t.Fatal(err) |
| } |
| err = Files([]*ast.File{f}, inst, &Config{Trace: false}) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| out := formatNode(t, f) |
| if got := string(out); got != tc.out { |
| t.Errorf("\ngot:\n%s\nwant:\n%s", got, tc.out) |
| } |
| }) |
| } |
| } |
| |
| const trace = false |
| |
| func TestData(t *testing.T) { |
| test := cuetxtar.TxTarTest{ |
| Root: "./testdata", |
| Name: "trim", |
| Update: *update, |
| } |
| |
| test.Run(t, func(t *cuetxtar.Test) { |
| a := t.ValidInstances() |
| |
| inst := cue.Build(a[:1])[0] |
| if inst.Err != nil { |
| t.Fatal(inst.Err) |
| } |
| |
| files := a[0].Files |
| |
| err := Files(files, inst, &Config{Trace: trace}) |
| if err != nil { |
| t.WriteErrors(errors.Promote(err, "")) |
| } |
| |
| for _, f := range files { |
| t.WriteFile(f) |
| } |
| }) |
| } |
| |
| func formatNode(t *testing.T, n ast.Node) []byte { |
| t.Helper() |
| |
| b, err := format.Node(n) |
| if err != nil { |
| t.Fatal(err) |
| } |
| return b |
| } |
| |
| // For debugging, do not remove. |
| func TestX(t *testing.T) { |
| in := ` |
| -- in.cue -- |
| ` |
| |
| t.Skip() |
| |
| a := txtar.Parse([]byte(in)) |
| instances := cuetxtar.Load(a, "/tmp/test") |
| |
| inst := cue.Build(instances)[0] |
| if inst.Err != nil { |
| t.Fatal(inst.Err) |
| } |
| |
| files := instances[0].Files |
| |
| err := Files(files, inst, &Config{Trace: false}) |
| if err != nil { |
| t.Fatal(err) |
| } |
| |
| for _, f := range files { |
| b := formatNode(t, f) |
| t.Error(string(b)) |
| } |
| } |