Refactor blueprint parser nodes to an interface
Refactor the blueprint parser Value object, which contained a Type enum
and members to hold every possible type, into an interface (now called
Expression). Rename the existing Expression object that represented a binary
operator Operator.
Also adds and fixes some new printer test cases with mulitline expressions.
Change-Id: Icf4a20f92c8c2a27f18df8ca515a9d7f282ff133
diff --git a/unpack_test.go b/unpack_test.go
index 3efd447..7b314dd 100644
--- a/unpack_test.go
+++ b/unpack_test.go
@@ -27,7 +27,7 @@
var validUnpackTestCases = []struct {
input string
- output interface{}
+ output []interface{}
errs []error
}{
{`
@@ -36,14 +36,16 @@
blank: "",
}
`,
- struct {
- Name *string
- Blank *string
- Unset *string
- }{
- Name: proptools.StringPtr("abc"),
- Blank: proptools.StringPtr(""),
- Unset: nil,
+ []interface{}{
+ struct {
+ Name *string
+ Blank *string
+ Unset *string
+ }{
+ Name: proptools.StringPtr("abc"),
+ Blank: proptools.StringPtr(""),
+ Unset: nil,
+ },
},
nil,
},
@@ -53,10 +55,12 @@
name: "abc",
}
`,
- struct {
- Name string
- }{
- Name: "abc",
+ []interface{}{
+ struct {
+ Name string
+ }{
+ Name: "abc",
+ },
},
nil,
},
@@ -66,10 +70,12 @@
isGood: true,
}
`,
- struct {
- IsGood bool
- }{
- IsGood: true,
+ []interface{}{
+ struct {
+ IsGood bool
+ }{
+ IsGood: true,
+ },
},
nil,
},
@@ -80,14 +86,16 @@
isBad: false,
}
`,
- struct {
- IsGood *bool
- IsBad *bool
- IsUgly *bool
- }{
- IsGood: proptools.BoolPtr(true),
- IsBad: proptools.BoolPtr(false),
- IsUgly: nil,
+ []interface{}{
+ struct {
+ IsGood *bool
+ IsBad *bool
+ IsUgly *bool
+ }{
+ IsGood: proptools.BoolPtr(true),
+ IsBad: proptools.BoolPtr(false),
+ IsUgly: nil,
+ },
},
nil,
},
@@ -99,14 +107,16 @@
empty: []
}
`,
- struct {
- Stuff []string
- Empty []string
- Nil []string
- }{
- Stuff: []string{"asdf", "jkl;", "qwert", "uiop", "bnm,"},
- Empty: []string{},
- Nil: nil,
+ []interface{}{
+ struct {
+ Stuff []string
+ Empty []string
+ Nil []string
+ }{
+ Stuff: []string{"asdf", "jkl;", "qwert", "uiop", "bnm,"},
+ Empty: []string{},
+ Nil: nil,
+ },
},
nil,
},
@@ -118,13 +128,15 @@
}
}
`,
- struct {
- Nested struct {
- Name string
- }
- }{
- Nested: struct{ Name string }{
- Name: "abc",
+ []interface{}{
+ struct {
+ Nested struct {
+ Name string
+ }
+ }{
+ Nested: struct{ Name string }{
+ Name: "abc",
+ },
},
},
nil,
@@ -137,64 +149,14 @@
}
}
`,
- struct {
- Nested interface{}
- }{
- Nested: &struct{ Name string }{
- Name: "def",
- },
- },
- nil,
- },
-
- {`
- m {
- nested: {
- foo: "abc",
- },
- bar: false,
- baz: ["def", "ghi"],
- }
- `,
- struct {
- Nested struct {
- Foo string
- }
- Bar bool
- Baz []string
- }{
- Nested: struct{ Foo string }{
- Foo: "abc",
- },
- Bar: false,
- Baz: []string{"def", "ghi"},
- },
- nil,
- },
-
- {`
- m {
- nested: {
- foo: "abc",
- },
- bar: false,
- baz: ["def", "ghi"],
- }
- `,
- struct {
- Nested struct {
- Foo string `allowNested:"true"`
- } `blueprint:"filter(allowNested:\"true\")"`
- Bar bool
- Baz []string
- }{
- Nested: struct {
- Foo string `allowNested:"true"`
+ []interface{}{
+ struct {
+ Nested interface{}
}{
- Foo: "abc",
+ Nested: &struct{ Name string }{
+ Name: "def",
+ },
},
- Bar: false,
- Baz: []string{"def", "ghi"},
},
nil,
},
@@ -208,18 +170,76 @@
baz: ["def", "ghi"],
}
`,
- struct {
- Nested struct {
- Foo string
- } `blueprint:"filter(allowNested:\"true\")"`
- Bar bool
- Baz []string
- }{
- Nested: struct{ Foo string }{
- Foo: "",
+ []interface{}{
+ struct {
+ Nested struct {
+ Foo string
+ }
+ Bar bool
+ Baz []string
+ }{
+ Nested: struct{ Foo string }{
+ Foo: "abc",
+ },
+ Bar: false,
+ Baz: []string{"def", "ghi"},
},
- Bar: false,
- Baz: []string{"def", "ghi"},
+ },
+ nil,
+ },
+
+ {`
+ m {
+ nested: {
+ foo: "abc",
+ },
+ bar: false,
+ baz: ["def", "ghi"],
+ }
+ `,
+ []interface{}{
+ struct {
+ Nested struct {
+ Foo string `allowNested:"true"`
+ } `blueprint:"filter(allowNested:\"true\")"`
+ Bar bool
+ Baz []string
+ }{
+ Nested: struct {
+ Foo string `allowNested:"true"`
+ }{
+ Foo: "abc",
+ },
+ Bar: false,
+ Baz: []string{"def", "ghi"},
+ },
+ },
+ nil,
+ },
+
+ {`
+ m {
+ nested: {
+ foo: "abc",
+ },
+ bar: false,
+ baz: ["def", "ghi"],
+ }
+ `,
+ []interface{}{
+ struct {
+ Nested struct {
+ Foo string
+ } `blueprint:"filter(allowNested:\"true\")"`
+ Bar bool
+ Baz []string
+ }{
+ Nested: struct{ Foo string }{
+ Foo: "",
+ },
+ Bar: false,
+ Baz: []string{"def", "ghi"},
+ },
},
[]error{
&Error{
@@ -238,20 +258,22 @@
},
}
`,
- struct {
- EmbeddedStruct
- Nested struct {
+ []interface{}{
+ struct {
EmbeddedStruct
- }
- }{
- EmbeddedStruct: EmbeddedStruct{
- Name: "abc",
- },
- Nested: struct {
- EmbeddedStruct
+ Nested struct {
+ EmbeddedStruct
+ }
}{
EmbeddedStruct: EmbeddedStruct{
- Name: "def",
+ Name: "abc",
+ },
+ Nested: struct {
+ EmbeddedStruct
+ }{
+ EmbeddedStruct: EmbeddedStruct{
+ Name: "def",
+ },
},
},
},
@@ -267,20 +289,22 @@
},
}
`,
- struct {
- EmbeddedInterface
- Nested struct {
+ []interface{}{
+ struct {
EmbeddedInterface
- }
- }{
- EmbeddedInterface: &struct{ Name string }{
- Name: "abc",
- },
- Nested: struct {
- EmbeddedInterface
+ Nested struct {
+ EmbeddedInterface
+ }
}{
EmbeddedInterface: &struct{ Name string }{
- Name: "def",
+ Name: "abc",
+ },
+ Nested: struct {
+ EmbeddedInterface
+ }{
+ EmbeddedInterface: &struct{ Name string }{
+ Name: "def",
+ },
},
},
},
@@ -296,25 +320,27 @@
},
}
`,
- struct {
- Name string
- EmbeddedStruct
- Nested struct {
+ []interface{}{
+ struct {
Name string
EmbeddedStruct
- }
- }{
- Name: "abc",
- EmbeddedStruct: EmbeddedStruct{
- Name: "abc",
- },
- Nested: struct {
- Name string
- EmbeddedStruct
+ Nested struct {
+ Name string
+ EmbeddedStruct
+ }
}{
- Name: "def",
+ Name: "abc",
EmbeddedStruct: EmbeddedStruct{
+ Name: "abc",
+ },
+ Nested: struct {
+ Name string
+ EmbeddedStruct
+ }{
Name: "def",
+ EmbeddedStruct: EmbeddedStruct{
+ Name: "def",
+ },
},
},
},
@@ -330,30 +356,90 @@
},
}
`,
- struct {
- Name string
- EmbeddedInterface
- Nested struct {
+ []interface{}{
+ struct {
Name string
EmbeddedInterface
- }
- }{
- Name: "abc",
- EmbeddedInterface: &struct{ Name string }{
- Name: "abc",
- },
- Nested: struct {
- Name string
- EmbeddedInterface
+ Nested struct {
+ Name string
+ EmbeddedInterface
+ }
}{
- Name: "def",
+ Name: "abc",
EmbeddedInterface: &struct{ Name string }{
+ Name: "abc",
+ },
+ Nested: struct {
+ Name string
+ EmbeddedInterface
+ }{
Name: "def",
+ EmbeddedInterface: &struct{ Name string }{
+ Name: "def",
+ },
},
},
},
nil,
},
+
+ // Variables
+ {`
+ list = ["abc"]
+ string = "def"
+ list_with_variable = [string]
+ m {
+ name: string,
+ list: list,
+ list2: list_with_variable,
+ }
+ `,
+ []interface{}{
+ struct {
+ Name string
+ List []string
+ List2 []string
+ }{
+ Name: "def",
+ List: []string{"abc"},
+ List2: []string{"def"},
+ },
+ },
+ nil,
+ },
+
+ // Multiple property structs
+ {`
+ m {
+ nested: {
+ name: "abc",
+ }
+ }
+ `,
+ []interface{}{
+ struct {
+ Nested struct {
+ Name string
+ }
+ }{
+ Nested: struct{ Name string }{
+ Name: "abc",
+ },
+ },
+ struct {
+ Nested struct {
+ Name string
+ }
+ }{
+ Nested: struct{ Name string }{
+ Name: "abc",
+ },
+ },
+ struct {
+ }{},
+ },
+ nil,
+ },
}
type EmbeddedStruct struct{ Name string }
@@ -362,7 +448,7 @@
func TestUnpackProperties(t *testing.T) {
for _, testCase := range validUnpackTestCases {
r := bytes.NewBufferString(testCase.input)
- file, errs := parser.Parse("", r, nil)
+ file, errs := parser.ParseAndEval("", r, parser.NewScope(nil))
if len(errs) != 0 {
t.Errorf("test case: %s", testCase.input)
t.Errorf("unexpected parse errors:")
@@ -372,30 +458,45 @@
t.FailNow()
}
- module := file.Defs[0].(*parser.Module)
- properties := proptools.CloneProperties(reflect.ValueOf(testCase.output))
- proptools.ZeroProperties(properties.Elem())
- _, errs = unpackProperties(module.Properties, properties.Interface())
- if len(errs) != 0 && len(testCase.errs) == 0 {
- t.Errorf("test case: %s", testCase.input)
- t.Errorf("unexpected unpack errors:")
- for _, err := range errs {
- t.Errorf(" %s", err)
+ for _, def := range file.Defs {
+ module, ok := def.(*parser.Module)
+ if !ok {
+ continue
}
- t.FailNow()
- } else if !reflect.DeepEqual(errs, testCase.errs) {
- t.Errorf("test case: %s", testCase.input)
- t.Errorf("incorrect errors:")
- t.Errorf(" expected: %+v", testCase.errs)
- t.Errorf(" got: %+v", errs)
- }
- output := properties.Elem().Interface()
- if !reflect.DeepEqual(output, testCase.output) {
- t.Errorf("test case: %s", testCase.input)
- t.Errorf("incorrect output:")
- t.Errorf(" expected: %+v", testCase.output)
- t.Errorf(" got: %+v", output)
+ output := []interface{}{}
+ for _, p := range testCase.output {
+ output = append(output, proptools.CloneEmptyProperties(reflect.ValueOf(p)).Interface())
+ }
+ _, errs = unpackProperties(module.Properties, output...)
+ if len(errs) != 0 && len(testCase.errs) == 0 {
+ t.Errorf("test case: %s", testCase.input)
+ t.Errorf("unexpected unpack errors:")
+ for _, err := range errs {
+ t.Errorf(" %s", err)
+ }
+ t.FailNow()
+ } else if !reflect.DeepEqual(errs, testCase.errs) {
+ t.Errorf("test case: %s", testCase.input)
+ t.Errorf("incorrect errors:")
+ t.Errorf(" expected: %+v", testCase.errs)
+ t.Errorf(" got: %+v", errs)
+ }
+
+ if len(output) != len(testCase.output) {
+ t.Fatalf("incorrect number of property structs, expected %d got %d",
+ len(testCase.output), len(output))
+ }
+
+ for i := range output {
+ got := reflect.ValueOf(output[i]).Elem().Interface()
+ if !reflect.DeepEqual(got, testCase.output[i]) {
+ t.Errorf("test case: %s", testCase.input)
+ t.Errorf("incorrect output:")
+ t.Errorf(" expected: %+v", testCase.output[i])
+ t.Errorf(" got: %+v", got)
+ }
+ }
}
}
}