Home | History | Annotate | Download | only in kati
      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