github.com/openconfig/goyang@v1.4.5/pkg/yang/lex_test.go (about) 1 // Copyright 2015 Google Inc. 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 yang 16 17 import ( 18 "bytes" 19 "runtime" 20 "testing" 21 ) 22 23 // line returns the line number from which it was called. 24 // Used to mark where test entries are in the source. 25 func line() int { 26 _, _, line, _ := runtime.Caller(1) 27 return line 28 29 } 30 31 // Equal returns true if t and tt are equal (have the same code and text), 32 // false if not. 33 func (t *token) Equal(tt *token) bool { 34 return t.code == tt.code && t.Text == tt.Text 35 } 36 37 // T Creates a new token from the provided code and string. 38 func T(c code, text string) *token { return &token{code: c, Text: text} } 39 40 func TestLex(t *testing.T) { 41 Tests: 42 for _, tt := range []struct { 43 line int 44 in string 45 tokens []*token 46 }{ 47 {line(), "", nil}, 48 {line(), "bob", []*token{ 49 T(tUnquoted, "bob"), 50 }}, 51 {line(), "bob //bob", []*token{ 52 T(tUnquoted, "bob"), 53 }}, 54 {line(), "/the/path", []*token{ 55 T(tUnquoted, "/the/path"), 56 }}, 57 {line(), "+the/path", []*token{ 58 T(tUnquoted, "+the/path"), 59 }}, 60 {line(), "+the+path", []*token{ 61 T(tUnquoted, "+the+path"), 62 }}, 63 {line(), "+ the/path", []*token{ 64 T(tUnquoted, "+"), 65 T(tUnquoted, "the/path"), 66 }}, 67 {line(), "{bob}", []*token{ 68 T('{', "{"), 69 T(tUnquoted, "bob"), 70 T('}', "}"), 71 }}, 72 {line(), "bob;fred", []*token{ 73 T(tUnquoted, "bob"), 74 T(';', ";"), 75 T(tUnquoted, "fred"), 76 }}, 77 {line(), "\t bob\t; fred ", []*token{ 78 T(tUnquoted, "bob"), 79 T(';', ";"), 80 T(tUnquoted, "fred"), 81 }}, 82 {line(), ` 83 bob; 84 fred 85 `, []*token{ 86 T(tUnquoted, "bob"), 87 T(';', ";"), 88 T(tUnquoted, "fred"), 89 }}, 90 {line(), ` 91 // This is a comment 92 bob; 93 fred 94 `, []*token{ 95 T(tUnquoted, "bob"), 96 T(';', ";"), 97 T(tUnquoted, "fred"), 98 }}, 99 {line(), ` 100 /* This is a comment */ 101 bob; 102 fred 103 `, []*token{ 104 T(tUnquoted, "bob"), 105 T(';', ";"), 106 T(tUnquoted, "fred"), 107 }}, 108 {line(), ` 109 /* 110 * This is a comment 111 */ 112 bob; 113 fred 114 `, []*token{ 115 T(tUnquoted, "bob"), 116 T(';', ";"), 117 T(tUnquoted, "fred"), 118 }}, 119 {line(), ` 120 bob; // This is bob 121 fred // This is fred 122 `, []*token{ 123 T(tUnquoted, "bob"), 124 T(';', ";"), 125 T(tUnquoted, "fred"), 126 }}, 127 {line(), ` 128 pattern '[a-zA-Z0-9!#$%&'+"'"+'*+/=?^_` + "`" + `{|}~-]+'; 129 `, []*token{ 130 T(tUnquoted, "pattern"), 131 T(tString, "[a-zA-Z0-9!#$%&"), 132 T(tUnquoted, "+"), 133 T(tString, "'"), 134 T(tUnquoted, "+"), 135 T(tString, "*+/=?^_`{|}~-]+"), 136 T(';', ";"), 137 }}, 138 {line(), ` 139 // tab indent both lines 140 "Broken 141 line" 142 `, []*token{ 143 T(tString, "Broken\nline"), 144 }}, 145 {line(), ` 146 // tab indent both lines, trailing spaces and tabs 147 "Broken 148 line" 149 `, []*token{ 150 T(tString, "Broken\nline"), 151 }}, 152 {line(), ` 153 // tab indent first line, spaces and tab second line 154 "Broken 155 line" 156 `, []*token{ 157 T(tString, "Broken\nline"), 158 }}, 159 {line(), ` 160 // tab indent first line, spaces second linfe 161 "Broken 162 line" 163 `, []*token{ 164 T(tString, "Broken\nline"), 165 }}, 166 {line(), ` 167 // extra space in second line 168 "Broken 169 space" 170 `, []*token{ 171 T(tString, "Broken\n space"), 172 }}, 173 {line(), ` 174 // spaces first line, tab on second 175 "Broken 176 space" 177 `, []*token{ 178 T(tString, "Broken\nspace"), 179 }}, 180 {line(), ` 181 // Odd indenting 182 "Broken 183 space" 184 `, []*token{ 185 T(tString, "Broken\nspace"), 186 }}, 187 {line(), ` 188 // Odd indenting 189 "Broken \t 190 space with trailing space" 191 `, []*token{ 192 T(tString, "Broken\nspace with trailing space"), 193 }}, 194 } { 195 l := newLexer(tt.in, "") 196 // l.debug = true 197 for i := 0; ; i++ { 198 token := l.NextToken() 199 if token == nil { 200 if len(tt.tokens) != i { 201 t.Errorf("%d: got %d tokens, want %d", tt.line, i, len(tt.tokens)) 202 } 203 continue Tests 204 } 205 if len(tt.tokens) > i && !token.Equal(tt.tokens[i]) { 206 t.Errorf("%d, %d: got (%v, %q) want (%v, %q)", tt.line, i, token.code, token.Text, tt.tokens[i].code, tt.tokens[i].Text) 207 } 208 } 209 } 210 } 211 212 func TestLexErrors(t *testing.T) { 213 for _, tt := range []struct { 214 line int 215 in string 216 errcnt int 217 errs string 218 }{ 219 {line(), 220 `1: "no closing quote`, 221 1, 222 `test.yang:1:4: missing closing " 223 `, 224 }, 225 {line(), 226 `1: on another line 227 2: there is "no closing quote\"`, 228 1, 229 `test.yang:2:13: missing closing " 230 `, 231 }, 232 {line(), 233 `1: 234 2: "Mares eat oats," 235 3: "And does eat oats," 236 4: "But little lambs eat ivy," 237 5: "and if I were a little lamb," 238 6: "I'ld eat ivy too. 239 5: So saith the sage.`, 240 1, 241 `test.yang:6:4: missing closing " 242 `, 243 }, 244 {line(), 245 `1: 246 2: "Quoted string" 247 3: "Missing quote 248 4: "Another quoted string" 249 `, 250 1, 251 `test.yang:4:26: missing closing " 252 `, 253 }, 254 {line(), 255 `1: 256 2: 'Quoted string' 257 3: 'Missing quote 258 4: 'Another quoted string' 259 `, 260 1, 261 `test.yang:4:26: missing closing ' 262 `, 263 }, 264 {line(), 265 `1: "Quoted string\" 266 2: Missing end-quote\q`, 267 2, 268 `test.yang:2:21: invalid escape sequence: \q 269 test.yang:1:4: missing closing " 270 `, 271 }, 272 {line(), 273 `/* This is a comment 274 without an ending. 275 `, 276 1, 277 `test.yang:1:1: missing closing */ 278 `, 279 }, 280 {line(), 281 // Two errors too many. 282 `yang-version 1.1;description "\/\/\/\/\/\/\/\/\/\/";`, 283 9, 284 `test.yang:1:31: invalid escape sequence: \/ 285 test.yang:1:33: invalid escape sequence: \/ 286 test.yang:1:35: invalid escape sequence: \/ 287 test.yang:1:37: invalid escape sequence: \/ 288 test.yang:1:39: invalid escape sequence: \/ 289 test.yang:1:41: invalid escape sequence: \/ 290 test.yang:1:43: invalid escape sequence: \/ 291 test.yang:1:45: invalid escape sequence: \/ 292 ` + tooMany, 293 }, 294 } { 295 l := newLexer(tt.in, "test.yang") 296 errbuf := &bytes.Buffer{} 297 l.errout = errbuf 298 for l.NextToken() != nil { 299 300 } 301 if l.errcnt != tt.errcnt { 302 t.Errorf("%d: got %d errors, want %v", tt.line, l.errcnt, tt.errcnt) 303 } 304 errs := errbuf.String() 305 if errs != tt.errs { 306 t.Errorf("%d: got errors:\n%s\nwant:\n%s", tt.line, errs, tt.errs) 307 } 308 } 309 }