1 // Copyright 2017 Google Inc. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // This file implements the logic of bpfix and also provides a programmatic interface 16 17 package bpfix 18 19 import ( 20 "bytes" 21 "fmt" 22 "strings" 23 "testing" 24 25 "reflect" 26 27 "github.com/google/blueprint/parser" 28 ) 29 30 // TODO(jeffrygaston) remove this when position is removed from ParseNode (in b/38325146) and we can directly do reflect.DeepEqual 31 func printListOfStrings(items []string) (text string) { 32 if len(items) == 0 { 33 return "[]" 34 } 35 return fmt.Sprintf("[\"%s\"]", strings.Join(items, "\", \"")) 36 37 } 38 39 func buildTree(local_include_dirs []string, export_include_dirs []string) (file *parser.File, errs []error) { 40 // TODO(jeffrygaston) use the builder class when b/38325146 is done 41 input := fmt.Sprintf(`cc_library_shared { 42 name: "iAmAModule", 43 local_include_dirs: %s, 44 export_include_dirs: %s, 45 } 46 `, 47 printListOfStrings(local_include_dirs), printListOfStrings(export_include_dirs)) 48 tree, errs := parser.Parse("", strings.NewReader(input), parser.NewScope(nil)) 49 if len(errs) > 0 { 50 errs = append([]error{fmt.Errorf("failed to parse:\n%s", input)}, errs...) 51 } 52 return tree, errs 53 } 54 55 func implFilterListTest(t *testing.T, local_include_dirs []string, export_include_dirs []string, expectedResult []string) { 56 // build tree 57 tree, errs := buildTree(local_include_dirs, export_include_dirs) 58 if len(errs) > 0 { 59 t.Error("failed to build tree") 60 for _, err := range errs { 61 t.Error(err) 62 } 63 t.Fatalf("%d parse errors", len(errs)) 64 } 65 66 fixer := NewFixer(tree) 67 68 // apply simplifications 69 err := fixer.simplifyKnownPropertiesDuplicatingEachOther() 70 if len(errs) > 0 { 71 t.Fatal(err) 72 } 73 74 // lookup legacy property 75 mod := fixer.tree.Defs[0].(*parser.Module) 76 _, found := mod.GetProperty("local_include_dirs") 77 if !found { 78 t.Fatalf("failed to include key local_include_dirs in parse tree") 79 } 80 81 // check that the value for the legacy property was updated to the correct value 82 errorHeader := fmt.Sprintf("\nFailed to correctly simplify key 'local_include_dirs' in the presence of 'export_include_dirs.'\n"+ 83 "original local_include_dirs: %q\n"+ 84 "original export_include_dirs: %q\n"+ 85 "expected result: %q\n"+ 86 "actual result: ", 87 local_include_dirs, export_include_dirs, expectedResult) 88 result, ok := mod.GetProperty("local_include_dirs") 89 if !ok { 90 t.Fatal(errorHeader + "property not found") 91 } 92 93 listResult, ok := result.Value.(*parser.List) 94 if !ok { 95 t.Fatalf("%sproperty is not a list: %v", errorHeader, listResult) 96 } 97 98 actualExpressions := listResult.Values 99 actualValues := make([]string, 0) 100 for _, expr := range actualExpressions { 101 str := expr.(*parser.String) 102 actualValues = append(actualValues, str.Value) 103 } 104 105 if !reflect.DeepEqual(actualValues, expectedResult) { 106 t.Fatalf("%s%q\nlists are different", errorHeader, actualValues) 107 } 108 } 109 110 func TestSimplifyKnownVariablesDuplicatingEachOther(t *testing.T) { 111 // TODO use []Expression{} once buildTree above can support it (which is after b/38325146 is done) 112 implFilterListTest(t, []string{"include"}, []string{"include"}, []string{}) 113 implFilterListTest(t, []string{"include1"}, []string{"include2"}, []string{"include1"}) 114 implFilterListTest(t, []string{"include1", "include2", "include3", "include4"}, []string{"include2"}, 115 []string{"include1", "include3", "include4"}) 116 implFilterListTest(t, []string{}, []string{"include"}, []string{}) 117 implFilterListTest(t, []string{}, []string{}, []string{}) 118 } 119 120 func TestMergeMatchingProperties(t *testing.T) { 121 tests := []struct { 122 name string 123 in string 124 out string 125 }{ 126 { 127 name: "empty", 128 in: ` 129 java_library { 130 name: "foo", 131 static_libs: [], 132 static_libs: [], 133 } 134 `, 135 out: ` 136 java_library { 137 name: "foo", 138 static_libs: [], 139 } 140 `, 141 }, 142 { 143 name: "single line into multiline", 144 in: ` 145 java_library { 146 name: "foo", 147 static_libs: [ 148 "a", 149 "b", 150 ], 151 //c1 152 static_libs: ["c" /*c2*/], 153 } 154 `, 155 out: ` 156 java_library { 157 name: "foo", 158 static_libs: [ 159 "a", 160 "b", 161 "c", /*c2*/ 162 ], 163 //c1 164 } 165 `, 166 }, 167 { 168 name: "multiline into multiline", 169 in: ` 170 java_library { 171 name: "foo", 172 static_libs: [ 173 "a", 174 "b", 175 ], 176 //c1 177 static_libs: [ 178 //c2 179 "c", //c3 180 "d", 181 ], 182 } 183 `, 184 out: ` 185 java_library { 186 name: "foo", 187 static_libs: [ 188 "a", 189 "b", 190 //c2 191 "c", //c3 192 "d", 193 ], 194 //c1 195 } 196 `, 197 }, 198 } 199 200 for _, test := range tests { 201 t.Run(test.name, func(t *testing.T) { 202 expected, err := Reformat(test.out) 203 if err != nil { 204 t.Error(err) 205 } 206 207 in, err := Reformat(test.in) 208 if err != nil { 209 t.Error(err) 210 } 211 212 tree, errs := parser.Parse("<testcase>", bytes.NewBufferString(in), parser.NewScope(nil)) 213 if errs != nil { 214 t.Fatal(errs) 215 } 216 217 fixer := NewFixer(tree) 218 219 got := "" 220 prev := "foo" 221 passes := 0 222 for got != prev && passes < 10 { 223 err := fixer.mergeMatchingModuleProperties() 224 if err != nil { 225 t.Fatal(err) 226 } 227 228 out, err := parser.Print(fixer.tree) 229 if err != nil { 230 t.Fatal(err) 231 } 232 233 prev = got 234 got = string(out) 235 passes++ 236 } 237 238 if got != expected { 239 t.Errorf("failed testcase '%s'\ninput:\n%s\n\nexpected:\n%s\ngot:\n%s\n", 240 test.name, in, expected, got) 241 } 242 243 }) 244 } 245 } 246