1 // Copyright 2015 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 package kati 16 17 import ( 18 "reflect" 19 "testing" 20 ) 21 22 func TestRuleParser(t *testing.T) { 23 for _, tc := range []struct { 24 in string 25 tsv *assignAST 26 rhs expr 27 want rule 28 assign *assignAST 29 err string 30 }{ 31 { 32 in: "foo: bar", 33 want: rule{ 34 outputs: []string{"foo"}, 35 inputs: []string{"bar"}, 36 }, 37 }, 38 { 39 in: "foo: bar baz", 40 want: rule{ 41 outputs: []string{"foo"}, 42 inputs: []string{"bar", "baz"}, 43 }, 44 }, 45 { 46 in: "foo:: bar", 47 want: rule{ 48 outputs: []string{"foo"}, 49 inputs: []string{"bar"}, 50 isDoubleColon: true, 51 }, 52 }, 53 { 54 in: "foo", 55 err: "*** missing separator.", 56 }, 57 { 58 in: "%.o: %.c", 59 want: rule{ 60 outputs: []string{}, 61 outputPatterns: []pattern{pattern{suffix: ".o"}}, 62 inputs: []string{"%.c"}, 63 }, 64 }, 65 { 66 in: "foo %.o: %.c", 67 err: "*** mixed implicit and normal rules: deprecated syntax", 68 }, 69 { 70 in: "foo.o: %.o: %.c %.h", 71 want: rule{ 72 outputs: []string{"foo.o"}, 73 outputPatterns: []pattern{pattern{suffix: ".o"}}, 74 inputs: []string{"%.c", "%.h"}, 75 }, 76 }, 77 { 78 in: "%.x: %.y: %.z", 79 err: "*** mixed implicit and normal rules: deprecated syntax", 80 }, 81 { 82 in: "foo.o: : %.c", 83 err: "*** missing target pattern.", 84 }, 85 { 86 in: "foo.o: %.o %.o: %.c", 87 err: "*** multiple target patterns.", 88 }, 89 { 90 in: "foo.o: foo.o: %.c", 91 err: "*** target pattern contains no '%'.", 92 }, 93 { 94 in: "foo: bar | baz", 95 want: rule{ 96 outputs: []string{"foo"}, 97 inputs: []string{"bar"}, 98 orderOnlyInputs: []string{"baz"}, 99 }, 100 }, 101 { 102 in: "foo: CFLAGS =", 103 rhs: expr{literal("-g")}, 104 want: rule{ 105 outputs: []string{"foo"}, 106 }, 107 assign: &assignAST{ 108 lhs: literal("CFLAGS"), 109 rhs: literal("-g"), 110 op: "=", 111 }, 112 }, 113 { 114 in: "foo:", 115 tsv: &assignAST{ 116 lhs: literal("CFLAGS"), 117 rhs: literal("-g"), 118 op: "=", 119 }, 120 want: rule{ 121 outputs: []string{"foo"}, 122 }, 123 assign: &assignAST{ 124 lhs: literal("CFLAGS"), 125 rhs: literal("-g"), 126 op: "=", 127 }, 128 }, 129 { 130 in: "foo: CFLAGS=", 131 rhs: expr{literal("-g")}, 132 want: rule{ 133 outputs: []string{"foo"}, 134 }, 135 assign: &assignAST{ 136 lhs: literal("CFLAGS"), 137 rhs: literal("-g"), 138 op: "=", 139 }, 140 }, 141 { 142 in: "foo: CFLAGS :=", 143 rhs: expr{literal("-g")}, 144 want: rule{ 145 outputs: []string{"foo"}, 146 }, 147 assign: &assignAST{ 148 lhs: literal("CFLAGS"), 149 rhs: literal("-g"), 150 op: ":=", 151 }, 152 }, 153 { 154 in: "%.o: CFLAGS :=", 155 rhs: expr{literal("-g")}, 156 want: rule{ 157 outputs: []string{}, 158 outputPatterns: []pattern{pattern{suffix: ".o"}}, 159 }, 160 assign: &assignAST{ 161 lhs: literal("CFLAGS"), 162 rhs: literal("-g"), 163 op: ":=", 164 }, 165 }, 166 { 167 in: "%.o:", 168 tsv: &assignAST{ 169 lhs: literal("CFLAGS"), 170 rhs: literal("-g"), 171 op: ":=", 172 }, 173 want: rule{ 174 outputs: []string{}, 175 outputPatterns: []pattern{pattern{suffix: ".o"}}, 176 }, 177 assign: &assignAST{ 178 lhs: literal("CFLAGS"), 179 rhs: literal("-g"), 180 op: ":=", 181 }, 182 }, 183 /* TODO 184 { 185 in: "foo.o: %.c: %.c", 186 err: "*** target 'foo.o' doesn't match the target pattern", 187 }, 188 */ 189 } { 190 got := &rule{} 191 assign, err := got.parse([]byte(tc.in), tc.tsv, tc.rhs) 192 if tc.err != "" { 193 if err == nil { 194 t.Errorf(`r.parse(%q, %v)=_, <nil>, want _, %q`, tc.in, tc.rhs, tc.err) 195 continue 196 } 197 if got, want := err.Error(), tc.err; got != want { 198 t.Errorf(`r.parse(%q, %v)=_, %s, want %s`, tc.in, tc.rhs, got, want) 199 } 200 continue 201 } 202 if err != nil { 203 t.Errorf(`r.parse(%q, %v)=_, %v; want nil error`, tc.in, tc.rhs, err) 204 continue 205 } 206 if !reflect.DeepEqual(*got, tc.want) { 207 t.Errorf(`r.parse(%q, %v); r=%#v, want %#v`, tc.in, tc.rhs, *got, tc.want) 208 } 209 if tc.assign != nil { 210 if assign == nil { 211 t.Errorf(`r.parse(%q, %v)=<nil>; want=%#v`, tc.in, tc.rhs, tc.assign) 212 continue 213 } 214 if got, want := assign, tc.assign; !reflect.DeepEqual(got, want) { 215 t.Errorf(`r.parse(%q, %v)=%#v; want=%#v`, tc.in, tc.rhs, got, want) 216 } 217 continue 218 } 219 if assign != nil { 220 t.Errorf(`r.parse(%q, %v)=%v; want=<nil>`, tc.in, tc.rhs, assign) 221 } 222 } 223 } 224