Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/modules/libpref/test/gtest/Parser.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "gtest/gtest.h"
8
#include "mozilla/ArrayUtils.h"
9
#include "Preferences.h"
10
11
using namespace mozilla;
12
13
// Keep this in sync with the declaration in Preferences.cpp.
14
//
15
// It's declared here to avoid polluting Preferences.h with test-only stuff.
16
void
17
TestParseError(PrefValueKind aKind, const char* aText, nsCString& aErrorMsg);
18
19
TEST(PrefsParser, Errors)
20
0
{
21
0
  nsAutoCStringN<128> actualErrorMsg;
22
0
23
0
// Use a macro rather than a function so that the line number reported by
24
0
// gtest on failure is useful.
25
0
#define P(kind_, text_, expectedErrorMsg_)                                     \
26
0
  do {                                                                         \
27
0
    TestParseError(kind_, text_, actualErrorMsg);                              \
28
0
    ASSERT_STREQ(expectedErrorMsg_, actualErrorMsg.get());                     \
29
0
  } while (0)
30
0
31
0
#define DEFAULT(text_, expectedErrorMsg_)                                      \
32
0
  P(PrefValueKind::Default, text_, expectedErrorMsg_)
33
0
34
0
#define USER(text_, expectedErrorMsg_)                                         \
35
0
  P(PrefValueKind::User, text_, expectedErrorMsg_)
36
0
37
0
  // clang-format off
38
0
39
0
  //-------------------------------------------------------------------------
40
0
  // Valid syntax. (Other testing of more typical valid syntax and semantics is
41
0
  // done in modules/libpref/test/unit/test_parser.js.)
42
0
  //-------------------------------------------------------------------------
43
0
44
0
  // Normal prefs.
45
0
  DEFAULT(R"(
46
0
pref("bool", true);
47
0
sticky_pref("int", 123);
48
0
user_pref("string", "value");
49
0
    )",
50
0
    ""
51
0
  );
52
0
53
0
  // Totally empty input.
54
0
  DEFAULT("", "");
55
0
56
0
  // Whitespace-only input.
57
0
  DEFAULT(R"(
58
0
59
0
    )" "\v \t \v \f",
60
0
    ""
61
0
  );
62
0
63
0
  // Comment-only inputs.
64
0
  DEFAULT(R"(// blah)", "");
65
0
  DEFAULT(R"(# blah)", "");
66
0
  DEFAULT(R"(/* blah */)", "");
67
0
68
0
  //-------------------------------------------------------------------------
69
0
  // All the lexing errors. (To be pedantic, some of the integer literal
70
0
  // overflows are triggered in the parser, but put them all here so they're all
71
0
  // in the one spot.)
72
0
  //-------------------------------------------------------------------------
73
0
74
0
  // Integer overflow errors.
75
0
  DEFAULT(R"(
76
0
pref("int.ok", 2147483647);
77
0
pref("int.overflow", 2147483648);
78
0
pref("int.ok", +2147483647);
79
0
pref("int.overflow", +2147483648);
80
0
pref("int.ok", -2147483648);
81
0
pref("int.overflow", -2147483649);
82
0
pref("int.overflow", 4294967296);
83
0
pref("int.overflow", +4294967296);
84
0
pref("int.overflow", -4294967296);
85
0
pref("int.overflow", 4294967297);
86
0
pref("int.overflow", 1234567890987654321);
87
0
    )",
88
0
    "test:3: prefs parse error: integer literal overflowed\n"
89
0
    "test:5: prefs parse error: integer literal overflowed\n"
90
0
    "test:7: prefs parse error: integer literal overflowed\n"
91
0
    "test:8: prefs parse error: integer literal overflowed\n"
92
0
    "test:9: prefs parse error: integer literal overflowed\n"
93
0
    "test:10: prefs parse error: integer literal overflowed\n"
94
0
    "test:11: prefs parse error: integer literal overflowed\n"
95
0
    "test:12: prefs parse error: integer literal overflowed\n"
96
0
  );
97
0
98
0
  // Other integer errors.
99
0
  DEFAULT(R"(
100
0
pref("int.unexpected", 100foo);
101
0
pref("int.ok", 0);
102
0
    )",
103
0
    "test:2: prefs parse error: unexpected character in integer literal\n"
104
0
  );
105
0
106
0
  // \x00 is not allowed.
107
0
  DEFAULT(R"(
108
0
pref("string.bad-x-escape", "foo\x00bar");
109
0
pref("int.ok", 0);
110
0
    )",
111
0
    "test:2: prefs parse error: \\x00 is not allowed\n"
112
0
  );
113
0
114
0
  // Various bad things after \x: end of string, punctuation, space, newline,
115
0
  // EOF.
116
0
  DEFAULT(R"(
117
0
pref("string.bad-x-escape", "foo\x");
118
0
pref("string.bad-x-escape", "foo\x,bar");
119
0
pref("string.bad-x-escape", "foo\x 12");
120
0
pref("string.bad-x-escape", "foo\x
121
0
12");
122
0
pref("string.bad-x-escape", "foo\x)",
123
0
    "test:2: prefs parse error: malformed \\x escape sequence\n"
124
0
    "test:3: prefs parse error: malformed \\x escape sequence\n"
125
0
    "test:4: prefs parse error: malformed \\x escape sequence\n"
126
0
    "test:5: prefs parse error: malformed \\x escape sequence\n"
127
0
    "test:7: prefs parse error: malformed \\x escape sequence\n"
128
0
  );
129
0
130
0
  // Not enough hex digits.
131
0
  DEFAULT(R"(
132
0
pref("string.bad-x-escape", "foo\x1");
133
0
pref("int.ok", 0);
134
0
    )",
135
0
    "test:2: prefs parse error: malformed \\x escape sequence\n"
136
0
  );
137
0
138
0
  // Invalid hex digit.
139
0
  DEFAULT(R"(
140
0
pref("string.bad-x-escape", "foo\x1G");
141
0
pref("int.ok", 0);
142
0
    )",
143
0
    "test:2: prefs parse error: malformed \\x escape sequence\n"
144
0
  );
145
0
146
0
  // \u0000 is not allowed.
147
0
  // (The string literal is broken in two so that MSVC doesn't complain about
148
0
  // an invalid universal-character-name.)
149
0
  DEFAULT(R"(
150
0
pref("string.bad-u-escape", "foo\)" R"(u0000 bar");
151
0
pref("int.ok", 0);
152
0
    )",
153
0
    "test:2: prefs parse error: \\u0000 is not allowed\n"
154
0
  );
155
0
156
0
  // Various bad things after \u: end of string, punctuation, space, newline,
157
0
  // EOF.
158
0
  DEFAULT(R"(
159
0
pref("string.bad-u-escape", "foo\u");
160
0
pref("string.bad-u-escape", "foo\u,bar");
161
0
pref("string.bad-u-escape", "foo\u 1234");
162
0
pref("string.bad-u-escape", "foo\u
163
0
1234");
164
0
pref("string.bad-u-escape", "foo\u)",
165
0
    "test:2: prefs parse error: malformed \\u escape sequence\n"
166
0
    "test:3: prefs parse error: malformed \\u escape sequence\n"
167
0
    "test:4: prefs parse error: malformed \\u escape sequence\n"
168
0
    "test:5: prefs parse error: malformed \\u escape sequence\n"
169
0
    "test:7: prefs parse error: malformed \\u escape sequence\n"
170
0
  );
171
0
172
0
  // Not enough hex digits.
173
0
  DEFAULT(R"(
174
0
pref("string.bad-u-escape", "foo\u1");
175
0
pref("string.bad-u-escape", "foo\u12");
176
0
pref("string.bad-u-escape", "foo\u123");
177
0
pref("int.ok", 0);
178
0
    )",
179
0
    "test:2: prefs parse error: malformed \\u escape sequence\n"
180
0
    "test:3: prefs parse error: malformed \\u escape sequence\n"
181
0
    "test:4: prefs parse error: malformed \\u escape sequence\n"
182
0
  );
183
0
184
0
  // Invalid hex digit.
185
0
  DEFAULT(R"(
186
0
pref("string.bad-u-escape", "foo\u1G34");
187
0
pref("int.ok", 0);
188
0
    )",
189
0
    "test:2: prefs parse error: malformed \\u escape sequence\n"
190
0
  );
191
0
192
0
  // High surrogate not followed by low surrogate.
193
0
  // (The string literal is broken in two so that MSVC doesn't complain about
194
0
  // an invalid universal-character-name.)
195
0
  DEFAULT(R"(
196
0
pref("string.bad-u-surrogate", "foo\)" R"(ud83c,blah");
197
0
pref("int.ok", 0);
198
0
    )",
199
0
    "test:2: prefs parse error: expected low surrogate after high surrogate\n"
200
0
  );
201
0
202
0
  // High surrogate followed by invalid low surrogate.
203
0
  // (The string literal is broken in two so that MSVC doesn't complain about
204
0
  // an invalid universal-character-name.)
205
0
  DEFAULT(R"(
206
0
pref("string.bad-u-surrogate", "foo\)" R"(ud83c\u1234");
207
0
pref("int.ok", 0);
208
0
    )",
209
0
    "test:2: prefs parse error: invalid low surrogate after high surrogate\n"
210
0
  );
211
0
212
0
  // Low surrogate not preceded by high surrogate.
213
0
  // (The string literal is broken in two so that MSVC doesn't complain about
214
0
  // an invalid universal-character-name.)
215
0
  DEFAULT(R"(
216
0
pref("string.bad-u-surrogate", "foo\)" R"(udc00");
217
0
pref("int.ok", 0);
218
0
    )",
219
0
    "test:2: prefs parse error: expected high surrogate before low surrogate\n"
220
0
  );
221
0
222
0
  // Unlike in JavaScript, \b, \f, \t, \v aren't allowed.
223
0
  DEFAULT(R"(
224
0
pref("string.bad-escape", "foo\b");
225
0
pref("string.bad-escape", "foo\f");
226
0
pref("string.bad-escape", "foo\t");
227
0
pref("string.bad-escape", "foo\v");
228
0
pref("int.ok", 0);
229
0
    )",
230
0
    "test:2: prefs parse error: unexpected escape sequence character after '\\'\n"
231
0
    "test:3: prefs parse error: unexpected escape sequence character after '\\'\n"
232
0
    "test:4: prefs parse error: unexpected escape sequence character after '\\'\n"
233
0
    "test:5: prefs parse error: unexpected escape sequence character after '\\'\n"
234
0
  );
235
0
236
0
  // Various bad things after \: non-special letter, number, punctuation,
237
0
  // space, newline, EOF.
238
0
  DEFAULT(R"(
239
0
pref("string.bad-escape", "foo\Q");
240
0
pref("string.bad-escape", "foo\1");
241
0
pref("string.bad-escape", "foo\,");
242
0
pref("string.bad-escape", "foo\ n");
243
0
pref("string.bad-escape", "foo\
244
0
n");
245
0
pref("string.bad-escape", "foo\)",
246
0
    "test:2: prefs parse error: unexpected escape sequence character after '\\'\n"
247
0
    "test:3: prefs parse error: unexpected escape sequence character after '\\'\n"
248
0
    "test:4: prefs parse error: unexpected escape sequence character after '\\'\n"
249
0
    "test:5: prefs parse error: unexpected escape sequence character after '\\'\n"
250
0
    "test:6: prefs parse error: unexpected escape sequence character after '\\'\n"
251
0
    "test:8: prefs parse error: unexpected escape sequence character after '\\'\n"
252
0
  );
253
0
254
0
  // Unterminated string literals.
255
0
256
0
  // Simple case.
257
0
  DEFAULT(R"(
258
0
pref("string.unterminated-string", "foo
259
0
    )",
260
0
    "test:3: prefs parse error: unterminated string literal\n"
261
0
  );
262
0
263
0
  // Alternative case; `int` comes after the string and is seen as a keyword.
264
0
  // The parser then skips to the ';', so no error about the unterminated
265
0
  // string is issued.
266
0
  DEFAULT(R"(
267
0
pref("string.unterminated-string", "foo);
268
0
pref("int.ok", 0);
269
0
    )",
270
0
    "test:3: prefs parse error: unknown keyword\n"
271
0
  );
272
0
273
0
  // Mismatched quotes (1).
274
0
  DEFAULT(R"(
275
0
pref("string.unterminated-string", "foo');
276
0
    )",
277
0
    "test:3: prefs parse error: unterminated string literal\n"
278
0
  );
279
0
280
0
  // Mismatched quotes (2).
281
0
  DEFAULT(R"(
282
0
pref("string.unterminated-string", 'foo");
283
0
    )",
284
0
    "test:3: prefs parse error: unterminated string literal\n"
285
0
  );
286
0
287
0
  // Unknown keywords.
288
0
  DEFAULT(R"(
289
0
foo;
290
0
preff("string.bad-keyword", true);
291
0
ticky_pref("string.bad-keyword", true);
292
0
User_pref("string.bad-keyword", true);
293
0
pref("string.bad-keyword", TRUE);
294
0
    )",
295
0
    "test:2: prefs parse error: unknown keyword\n"
296
0
    "test:3: prefs parse error: unknown keyword\n"
297
0
    "test:4: prefs parse error: unknown keyword\n"
298
0
    "test:5: prefs parse error: unknown keyword\n"
299
0
    "test:6: prefs parse error: unknown keyword\n"
300
0
  );
301
0
302
0
  // Unterminated C-style comment.
303
0
  DEFAULT(R"(
304
0
/* comment
305
0
    )",
306
0
    "test:3: prefs parse error: unterminated /* comment\n"
307
0
  );
308
0
309
0
  // Malformed comments (single slashes), followed by whitespace, newline, EOF.
310
0
  DEFAULT(R"(
311
0
/ comment;
312
0
/
313
0
; /)",
314
0
    "test:2: prefs parse error: expected '/' or '*' after '/'\n"
315
0
    "test:3: prefs parse error: expected '/' or '*' after '/'\n"
316
0
    "test:4: prefs parse error: expected '/' or '*' after '/'\n"
317
0
  );
318
0
319
0
  // C++-style comment ending in EOF (1).
320
0
  DEFAULT(R"(
321
0
// comment)",
322
0
    ""
323
0
  );
324
0
325
0
  // C++-style comment ending in EOF (2).
326
0
  DEFAULT(R"(
327
0
//)",
328
0
    ""
329
0
  );
330
0
331
0
  // Various unexpected characters.
332
0
  DEFAULT(R"(
333
0
pref("unexpected.chars", &true);
334
0
pref("unexpected.chars" : true);
335
0
@pref("unexpected.chars", true);
336
0
pref["unexpected.chars": true];
337
0
    )",
338
0
    "test:2: prefs parse error: unexpected character\n"
339
0
    "test:3: prefs parse error: unexpected character\n"
340
0
    "test:4: prefs parse error: unexpected character\n"
341
0
    "test:5: prefs parse error: unexpected character\n"
342
0
  );
343
0
344
0
  //-------------------------------------------------------------------------
345
0
  // All the parsing errors.
346
0
  //-------------------------------------------------------------------------
347
0
348
0
  DEFAULT(R"(
349
0
"pref"("parse.error": true);
350
0
pref1("parse.error": true);
351
0
pref(123: true);
352
0
pref("parse.error" true);
353
0
pref("parse.error", pref);
354
0
pref("parse.error", -true);
355
0
pref("parse.error", +"value");
356
0
pref("parse.error", true,);
357
0
pref("parse.error", true;
358
0
pref("parse.error", true, sticky, locked;
359
0
pref("parse.error", true)
360
0
pref("int.ok", 1);
361
0
pref("parse.error", true))",
362
0
    "test:2: prefs parse error: expected pref specifier at start of pref definition\n"
363
0
    "test:3: prefs parse error: expected '(' after pref specifier\n"
364
0
    "test:4: prefs parse error: expected pref name after '('\n"
365
0
    "test:5: prefs parse error: expected ',' after pref name\n"
366
0
    "test:6: prefs parse error: expected pref value after ','\n"
367
0
    "test:7: prefs parse error: expected integer literal after '-'\n"
368
0
    "test:8: prefs parse error: expected integer literal after '+'\n"
369
0
    "test:9: prefs parse error: expected pref attribute after ','\n"
370
0
    "test:10: prefs parse error: expected ',' or ')' after pref value\n"
371
0
    "test:11: prefs parse error: expected ',' or ')' after pref attribute\n"
372
0
    "test:13: prefs parse error: expected ';' after ')'\n"
373
0
    "test:14: prefs parse error: expected ';' after ')'\n"
374
0
  );
375
0
376
0
  USER(R"(
377
0
pref("parse.error", true;
378
0
pref("int.ok", 1);
379
0
    )",
380
0
    "test:2: prefs parse error: expected ')' after pref value\n"
381
0
  );
382
0
383
0
  // Parse errors involving unexpected EOF.
384
0
385
0
  DEFAULT(R"(
386
0
pref)",
387
0
    "test:2: prefs parse error: expected '(' after pref specifier\n"
388
0
  );
389
0
390
0
  DEFAULT(R"(
391
0
pref()",
392
0
    "test:2: prefs parse error: expected pref name after '('\n"
393
0
  );
394
0
395
0
  DEFAULT(R"(
396
0
pref("parse.error")",
397
0
    "test:2: prefs parse error: expected ',' after pref name\n"
398
0
  );
399
0
400
0
  DEFAULT(R"(
401
0
pref("parse.error",)",
402
0
    "test:2: prefs parse error: expected pref value after ','\n"
403
0
  );
404
0
405
0
  DEFAULT(R"(
406
0
pref("parse.error", -)",
407
0
    "test:2: prefs parse error: expected integer literal after '-'\n"
408
0
  );
409
0
410
0
  DEFAULT(R"(
411
0
pref("parse.error", +)",
412
0
    "test:2: prefs parse error: expected integer literal after '+'\n"
413
0
  );
414
0
415
0
  DEFAULT(R"(
416
0
pref("parse.error", true)",
417
0
    "test:2: prefs parse error: expected ',' or ')' after pref value\n"
418
0
  );
419
0
420
0
  USER(R"(
421
0
pref("parse.error", true)",
422
0
    "test:2: prefs parse error: expected ')' after pref value\n"
423
0
  );
424
0
425
0
  DEFAULT(R"(
426
0
pref("parse.error", true,)",
427
0
    "test:2: prefs parse error: expected pref attribute after ','\n"
428
0
  );
429
0
430
0
  DEFAULT(R"(
431
0
pref("parse.error", true, sticky)",
432
0
    "test:2: prefs parse error: expected ',' or ')' after pref attribute\n"
433
0
  );
434
0
435
0
  DEFAULT(R"(
436
0
pref("parse.error", true))",
437
0
    "test:2: prefs parse error: expected ';' after ')'\n"
438
0
  );
439
0
440
0
  // This is something we saw in practice with the old parser, which allowed
441
0
  // repeated semicolons.
442
0
  DEFAULT(R"(
443
0
pref("parse.error", true);;
444
0
pref("parse.error", true, locked);;;
445
0
pref("parse.error", true, sticky, locked);;;;
446
0
pref("int.ok", 0);
447
0
    )",
448
0
    "test:2: prefs parse error: expected pref specifier at start of pref definition\n"
449
0
    "test:3: prefs parse error: expected pref specifier at start of pref definition\n"
450
0
    "test:3: prefs parse error: expected pref specifier at start of pref definition\n"
451
0
    "test:4: prefs parse error: expected pref specifier at start of pref definition\n"
452
0
    "test:4: prefs parse error: expected pref specifier at start of pref definition\n"
453
0
    "test:4: prefs parse error: expected pref specifier at start of pref definition\n"
454
0
  );
455
0
456
0
  //-------------------------------------------------------------------------
457
0
  // Invalid syntax after various newline combinations, for the purpose of
458
0
  // testing that line numbers are correct.
459
0
  //-------------------------------------------------------------------------
460
0
461
0
  // In all of the following we have a \n, a \r, a \r\n, and then an error, so
462
0
  // the error is on line 4. (Note: these ones don't use raw string literals
463
0
  // because MSVC somehow swallows any \r that appears in them.)
464
0
465
0
  DEFAULT("\n \r \r\n bad",
466
0
    "test:4: prefs parse error: unknown keyword\n"
467
0
  );
468
0
469
0
  DEFAULT("#\n#\r#\r\n bad",
470
0
    "test:4: prefs parse error: unknown keyword\n"
471
0
  );
472
0
473
0
  DEFAULT("//\n//\r//\r\n bad",
474
0
    "test:4: prefs parse error: unknown keyword\n"
475
0
  );
476
0
477
0
  DEFAULT("/*\n \r \r\n*/ bad",
478
0
    "test:4: prefs parse error: unknown keyword\n"
479
0
  );
480
0
481
0
  // Note: the escape sequences do *not* affect the line number.
482
0
  DEFAULT("pref(\"foo\\n\n foo\\r\r foo\\r\\n\r\n foo\", bad);",
483
0
    "test:4: prefs parse error: unknown keyword\n"
484
0
  );
485
0
486
0
  // clang-format on
487
0
}