OILS / osh / cmd_parse_test.py View on Github | oilshell.org

1491 lines, 810 significant
1#!/usr/bin/env python2
2"""
3cmd_parse_test.py: Tests for cmd_parse.py
4"""
5
6import unittest
7
8from _devbuild.gen.id_kind_asdl import Id, Id_str
9from _devbuild.gen.syntax_asdl import command_e, for_iter_e, pat_e
10from asdl import format as fmt
11from core import error
12from core import state
13from core import test_lib
14from display import ui
15from frontend import lexer
16
17from osh import word_
18
19
20def _assertParseMethod(test, code_str, method, expect_success=True):
21 arena = test_lib.MakeArena('<cmd_parse_test>')
22 errfmt = ui.ErrorFormatter()
23 c_parser = test_lib.InitCommandParser(code_str, arena=arena)
24 m = getattr(c_parser, method)
25 try:
26 node = m()
27
28 except error.Parse as e:
29 errfmt.PrettyPrintError(e)
30 if expect_success:
31 test.fail('%r failed' % code_str)
32 node = None
33 else:
34 fmt.PrettyPrint(node)
35 if not expect_success:
36 test.fail('Expected %r to fail ' % code_str)
37
38 return node
39
40
41def _assert_ParseCommandListError(test, code_str):
42 arena = test_lib.MakeArena('<cmd_parse_test>')
43 errfmt = ui.ErrorFormatter()
44 c_parser = test_lib.InitCommandParser(code_str, arena=arena)
45
46 try:
47 node = c_parser._ParseCommandLine()
48 except error.Parse as e:
49 errfmt.PrettyPrintError(e)
50 else:
51 print('UNEXPECTED:')
52 fmt.PrettyPrint(node)
53 test.fail("Expected %r to fail" % code_str)
54
55
56#
57# Successes
58#
59# (These differences might not matter, but preserve the diversity for now)
60
61
62def assertParseSimpleCommand(test, code_str):
63 return _assertParseMethod(test, code_str, 'ParseSimpleCommand')
64
65
66def assertParsePipeline(test, code_str):
67 return _assertParseMethod(test, code_str, 'ParsePipeline')
68
69
70def assertParseAndOr(test, code_str):
71 return _assertParseMethod(test, code_str, 'ParseAndOr')
72
73
74def assert_ParseCommandLine(test, code_str):
75 return _assertParseMethod(test, code_str, '_ParseCommandLine')
76
77
78def assert_ParseCommandList(test, code_str):
79 node = _assertParseMethod(test, code_str, '_ParseCommandList')
80 if len(node.children) == 1:
81 return node.children[0]
82 else:
83 return node
84
85
86def assertParseRedirect(test, code_str):
87 return _assertParseMethod(test, code_str, 'ParseRedirect')
88
89
90#
91# Failures
92#
93
94#def assertFailSimpleCommand(test, code_str):
95# return _assertParseMethod(test, code_str, 'ParseSimpleCommand',
96# expect_success=False)
97#
98#def assertFailCommandLine(test, code_str):
99# return _assertParseMethod(test, code_str, '_ParseCommandLine',
100# expect_success=False)
101
102
103def assertFailCommandList(test, code_str):
104 return _assertParseMethod(test,
105 code_str,
106 '_ParseCommandList',
107 expect_success=False)
108
109
110#def assertFailRedirect(test, code_str):
111# return _assertParseMethod(test, code_str, 'ParseRedirect',
112# expect_success=False)
113
114
115class SimpleCommandTest(unittest.TestCase):
116
117 def testParseSimpleCommand1(self):
118 node = assertParseSimpleCommand(self, 'ls foo')
119 self.assertEqual(2, len(node.words), node.words)
120
121 node = assertParseSimpleCommand(self, 'FOO=bar ls foo')
122 self.assertEqual(2, len(node.words))
123 self.assertEqual(1, len(node.more_env))
124
125 node = assertParseSimpleCommand(
126 self, 'FOO=bar >output.txt SPAM=eggs ls foo')
127 self.assertEqual(1, len(node.redirects))
128
129 self.assertEqual(2, len(node.child.words))
130 self.assertEqual(2, len(node.child.more_env))
131
132 node = assertParseSimpleCommand(
133 self, 'FOO=bar >output.txt SPAM=eggs ls foo >output2.txt')
134 self.assertEqual(2, len(node.redirects))
135
136 self.assertEqual(2, len(node.child.words))
137 self.assertEqual(2, len(node.child.more_env))
138
139 def testMultipleGlobalShAssignments(self):
140 node = assert_ParseCommandList(self, 'ONE=1 TWO=2')
141 self.assertEqual(command_e.ShAssignment, node.tag())
142 self.assertEqual(2, len(node.pairs))
143
144 def testOnlyRedirect(self):
145 # This just touches the file
146 node = assert_ParseCommandList(self, '>out.txt')
147 self.assertEqual(command_e.Redirect, node.tag())
148 self.assertEqual(1, len(node.redirects))
149
150 self.assertEqual(command_e.NoOp, node.child.tag())
151
152 def testParseRedirectInTheMiddle(self):
153 node = assert_ParseCommandList(self, 'echo >out.txt 1 2 3')
154 self.assertEqual(command_e.Redirect, node.tag())
155 self.assertEqual(1, len(node.redirects))
156
157 self.assertEqual(command_e.Simple, node.child.tag())
158 self.assertEqual(4, len(node.child.words))
159
160 def testParseRedirectBeforeShAssignment(self):
161 # Write ENV to a file
162 node = assert_ParseCommandList(self, '>out.txt PYTHONPATH=. env')
163 self.assertEqual(command_e.Redirect, node.tag())
164 self.assertEqual(1, len(node.redirects))
165
166 self.assertEqual(command_e.Simple, node.child.tag())
167 self.assertEqual(1, len(node.child.words))
168 self.assertEqual(1, len(node.child.more_env))
169
170 def testParseAdjacentDoubleQuotedWords(self):
171 node = assertParseSimpleCommand(self,
172 'echo "one"two "three""four" five')
173 self.assertEqual(4, len(node.words))
174
175
176class OldStaticParsing(object):
177
178 def testRedirectsInShAssignment(self):
179 err = _assert_ParseCommandListError(self, 'x=1 >/dev/null')
180 err = _assert_ParseCommandListError(self, 'echo hi; x=1 >/dev/null')
181 err = _assert_ParseCommandListError(self, 'declare x=1 >/dev/null')
182
183 def testParseShAssignment(self):
184 node = assert_ParseCommandList(self, 'local foo=bar spam eggs one=1')
185 self.assertEqual(4, len(node.pairs))
186
187 node = assert_ParseCommandList(self, 'foo=bar')
188 self.assertEqual(1, len(node.pairs))
189
190 # This is not valid since env isn't respected
191 assertFailCommandList(self, 'FOO=bar local foo=$(env)')
192
193 def testExport(self):
194 # This is the old static parsing. Probably need to revisit.
195 return
196 node = assert_ParseCommandList(self, 'export ONE=1 TWO=2 THREE')
197 self.assertEqual(command_e.ShAssignment, node.tag())
198 self.assertEqual(3, len(node.pairs))
199
200 def testReadonly(self):
201 return
202 node = assert_ParseCommandList(self, 'readonly ONE=1 TWO=2 THREE')
203 self.assertEqual(command_e.ShAssignment, node.tag())
204 self.assertEqual(3, len(node.pairs))
205
206
207def assertHereDocToken(test, expected_token_val, node):
208 """A sanity check for some ad hoc tests."""
209 test.assertEqual(1, len(node.redirects))
210 h = node.redirects[0].arg
211 test.assertEqual(expected_token_val, lexer.LazyStr(h.stdin_parts[0]))
212
213
214class HereDocTest(unittest.TestCase):
215 """NOTE: These ares come from tests/09-here-doc.sh, but add assertions."""
216
217 def testUnquotedHereDoc(self):
218 # Unquoted here docs use the double quoted context.
219 node = assert_ParseCommandLine(self, """\
220cat <<EOF
221$v
222"two
223EOF
224""")
225 self.assertEqual(1, len(node.redirects))
226 h = node.redirects[0].arg
227 # 4 literal parts: VarSub, newline, right ", "two\n"
228 self.assertEqual(4, len(h.stdin_parts))
229
230 def testQuotedHereDocs(self):
231 # Quoted here doc
232 node = assert_ParseCommandLine(self, """\
233cat <<"EOF"
234$v
235"two
236EOF
237""")
238 self.assertEqual(1, len(node.redirects))
239 h = node.redirects[0].arg
240 self.assertEqual(2, len(h.stdin_parts)) # 2 literal parts
241
242 node = assert_ParseCommandLine(
243 self, """\
244cat <<'EOF'
245single-quoted: $var
246EOF
247""")
248 self.assertEqual(1, len(node.redirects))
249 h = node.redirects[0].arg
250 self.assertEqual(1, len(h.stdin_parts)) # 1 line, one literal part
251
252 # \ escape
253 node = assert_ParseCommandLine(
254 self, r"""\
255cat <<EO\F
256single-quoted: $var
257EOF
258""")
259 self.assertEqual(1, len(node.redirects))
260 h = node.redirects[0].arg
261 self.assertEqual(1, len(h.stdin_parts)) # 1 line, one literal part
262
263 def testLeadingTabs(self):
264 node = assert_ParseCommandLine(
265 self, """\
266\tcat <<-EOF
267\tone tab then foo: $foo
268\tEOF
269echo hi
270""")
271 self.assertEqual(node.tag(), command_e.Redirect)
272 assertHereDocToken(self, 'one tab then foo: ', node)
273
274 def testHereDocInPipeline(self):
275 # Pipe and command on SAME LINE
276 node = assert_ParseCommandLine(
277 self, """\
278cat <<EOF | tac
279PIPE 1
280PIPE 2
281EOF
282""")
283 self.assertEqual(2, len(node.children))
284 assertHereDocToken(self, 'PIPE 1\n', node.children[0])
285
286 # Pipe command AFTER here doc
287 node = assert_ParseCommandLine(
288 self, """\
289cat <<EOF |
290PIPE 1
291PIPE 2
292EOF
293tac
294""")
295 self.assertEqual(2, len(node.children))
296 assertHereDocToken(self, 'PIPE 1\n', node.children[0])
297
298 def testTwoHereDocsInPipeline(self):
299 # Pipeline with two here docs
300 node = assert_ParseCommandList(
301 self, """\
302cat <<EOF1 | tac <<EOF2
303PIPE A1
304PIPE A2
305EOF1
306PIPE B1
307PIPE B2
308EOF2
309""")
310 self.assertEqual(2, len(node.children))
311 assertHereDocToken(self, 'PIPE A1\n', node.children[0])
312 assertHereDocToken(self, 'PIPE B1\n', node.children[1])
313
314 def testHereDocInAndOrChain(self):
315 # || command AFTER here doc
316 node = assert_ParseCommandLine(
317 self, """\
318cat <<EOF ||
319PIPE 1
320PIPE 2
321EOF
322echo hi
323""")
324 self.assertEqual(2, len(node.children))
325 assertHereDocToken(self, 'PIPE 1\n', node.children[0])
326
327 # && and command on SAME LINE
328 node = assert_ParseCommandLine(
329 self, """\
330cat <<EOF && echo hi
331PIPE 1
332PIPE 2
333EOF
334""")
335 self.assertEqual(2, len(node.children))
336 assertHereDocToken(self, 'PIPE 1\n', node.children[0])
337
338 node = assert_ParseCommandLine(
339 self, """\
340tac <<EOF1 && tac <<EOF2
341PIPE A1
342PIPE A2
343EOF1
344PIPE B1
345PIPE B2
346EOF2
347echo
348""")
349 self.assertEqual(2, len(node.children))
350 assertHereDocToken(self, 'PIPE A1\n', node.children[0])
351 assertHereDocToken(self, 'PIPE B1\n', node.children[1])
352
353 def testHereDocInSequence(self):
354 # PROBLEM: _ParseCommandList vs _ParseCommandLine
355 # _ParseCommandLine only used interactively. _ParseCommandList is used by
356 # ParseFile.
357
358 # command AFTER here doc
359 node = assert_ParseCommandList(
360 self, """\
361cat <<EOF ;
362PIPE 1
363PIPE 2
364EOF
365echo hi
366""")
367 self.assertEqual(node.tag(), command_e.CommandList)
368 self.assertEqual(2, len(node.children), repr(node))
369 assertHereDocToken(self, 'PIPE 1\n', node.children[0].child)
370
371 def testHereDocInSequence2(self):
372 # ; and command on SAME LINE
373 node = assert_ParseCommandList(
374 self, """\
375cat <<EOF ; echo hi
376PIPE 1
377PIPE 2
378EOF
379""")
380 self.assertEqual(node.tag(), command_e.CommandList)
381 self.assertEqual(2, len(node.children))
382 assertHereDocToken(self, 'PIPE 1\n', node.children[0].child)
383
384 def testCommandSubInHereDoc(self):
385 node = assert_ParseCommandLine(
386 self, """\
387cat <<EOF
3881 $(echo 2
389echo 3) 4
390EOF
391""")
392 self.assertEqual(1, len(node.redirects))
393 self.assertEqual(1, len(node.child.words))
394
395
396class ArrayTest(unittest.TestCase):
397
398 def testArrayLiteral(self):
399 # Empty array
400 node = assert_ParseCommandList(self, 'empty=()')
401 self.assertEqual(['empty'], [p.lhs.name for p in node.pairs])
402 self.assertEqual([], node.pairs[0].rhs.parts[0].words) # No words
403 self.assertEqual(command_e.ShAssignment, node.tag())
404
405 # Array with 3 elements
406 node = assert_ParseCommandList(self, 'array=(a b c)')
407 self.assertEqual(['array'], [p.lhs.name for p in node.pairs])
408 self.assertEqual(3, len(node.pairs[0].rhs.parts[0].words))
409 self.assertEqual(command_e.ShAssignment, node.tag())
410
411 # Array literal can't come after word
412 # Now caught at runtime
413 #assertFailCommandList(self,
414 # 'ls array=(a b c)')
415
416 # Word can't come after array literal
417 assertFailCommandList(self, 'array=(a b c) ls')
418
419 # Two array literals
420 node = assert_ParseCommandList(self, 'array=(a b c); array2=(d e f)')
421 self.assertEqual(2, len(node.children))
422 a2 = node.children[1]
423 self.assertEqual(['array2'], [p.lhs.name for p in a2.pairs])
424
425
426class RedirectTest(unittest.TestCase):
427
428 def testParseRedirects1(self):
429 node = assertParseSimpleCommand(self, '>out.txt cat 1>&2')
430 self.assertEqual(2, len(node.redirects))
431 self.assertEqual(1, len(node.child.words))
432
433 node = assertParseSimpleCommand(self, ' cat <&3')
434 self.assertEqual(1, len(node.redirects))
435 self.assertEqual(1, len(node.child.words))
436
437 def testParseFilenameRedirect(self):
438 node = assertParseRedirect(self, '>out.txt cat')
439
440 def testDescriptorRedirect(self):
441 node = assertParseRedirect(self, '1>& 2 cat')
442
443 def testHereDoc(self):
444 node = assertParseRedirect(self, """\
445<<EOF cat
446hi
447EOF
448""")
449
450 def testHereDocStrip(self):
451 node = assertParseRedirect(self, """\
452<<-EOF cat
453hi
454EOF
455""")
456
457 def testParseRedirectList(self):
458 node = assertParseRedirect(self, """\
459<<EOF >out.txt cat
460hi
461EOF
462""")
463
464 def testParseCommandWithLeadingRedirects(self):
465 node = assertParseSimpleCommand(self, """\
466<<EOF >out.txt cat
467hi
468EOF
469""")
470 self.assertEqual(2, len(node.redirects))
471 self.assertEqual(1, len(node.child.words))
472
473 def testClobberRedirect(self):
474 node = assertParseSimpleCommand(self, 'echo hi >| clobbered.txt')
475
476
477class CommandParserTest(unittest.TestCase):
478
479 def testParsePipeline(self):
480 node = assertParsePipeline(self, 'ls foo')
481 self.assertEqual(2, len(node.words))
482
483 node = assertParsePipeline(self, 'ls foo|wc -l')
484 self.assertEqual(2, len(node.children))
485 self.assertEqual(command_e.Pipeline, node.tag())
486
487 node = assertParsePipeline(self, '! echo foo | grep foo')
488 self.assertEqual(2, len(node.children))
489 self.assertEqual(command_e.Pipeline, node.tag())
490 self.assertTrue(node.negated)
491
492 node = assertParsePipeline(self, 'ls foo|wc -l|less')
493 self.assertEqual(3, len(node.children))
494 self.assertEqual(command_e.Pipeline, node.tag())
495
496 _assertParseMethod(self,
497 'ls foo|',
498 'ParsePipeline',
499 expect_success=False)
500
501 def testParsePipelineBash(self):
502 node = assert_ParseCommandList(self, 'ls | cat |& cat')
503 self.assertEqual(command_e.Pipeline, node.tag())
504 self.assertEqual(2, len(node.ops))
505 self.assertEqual(Id.Op_Pipe, node.ops[0].id)
506 self.assertEqual(Id.Op_PipeAmp, node.ops[1].id)
507
508 node = assert_ParseCommandList(self, 'ls |& cat | cat')
509 self.assertEqual(command_e.Pipeline, node.tag())
510 self.assertEqual(2, len(node.ops))
511 self.assertEqual(Id.Op_PipeAmp, node.ops[0].id)
512 self.assertEqual(Id.Op_Pipe, node.ops[1].id)
513
514 node = assert_ParseCommandList(self, 'ls |& cat |& cat')
515 self.assertEqual(command_e.Pipeline, node.tag())
516 self.assertEqual(2, len(node.ops))
517 self.assertEqual(Id.Op_PipeAmp, node.ops[0].id)
518 self.assertEqual(Id.Op_PipeAmp, node.ops[1].id)
519
520 def testParseAndOr(self):
521 node = assertParseAndOr(self, 'ls foo')
522 self.assertEqual(2, len(node.words))
523
524 node = assertParseAndOr(self, 'ls foo|wc -l')
525 self.assertEqual(2, len(node.children))
526 self.assertEqual(command_e.Pipeline, node.tag())
527
528 node = assertParseAndOr(self, 'ls foo || die')
529 self.assertEqual(2, len(node.children))
530 self.assertEqual(command_e.AndOr, node.tag())
531
532 node = assertParseAndOr(self, 'ls foo|wc -l || die')
533 self.assertEqual(2, len(node.children))
534 self.assertEqual(command_e.AndOr, node.tag())
535
536 def testParseCommand(self):
537 c_parser = test_lib.InitCommandParser('ls foo')
538 node = c_parser.ParseCommand()
539 self.assertEqual(2, len(node.words))
540 print(node)
541
542 c_parser = test_lib.InitCommandParser('fun() { echo hi; }')
543 node = c_parser.ParseCommand()
544 print(node)
545 self.assertEqual(command_e.ShFunction, node.tag())
546
547 def test_ParseCommandLine(self):
548 node = assert_ParseCommandLine(self, 'ls foo 2>/dev/null')
549 self.assertEqual(2, len(node.child.words))
550
551 node = assert_ParseCommandLine(self, 'ls foo|wc -l')
552 self.assertEqual(command_e.Pipeline, node.tag())
553
554 node = assert_ParseCommandLine(self, 'ls foo|wc -l || die')
555 self.assertEqual(command_e.AndOr, node.tag())
556
557 node = assert_ParseCommandLine(self, 'ls foo|wc -l || die; ls /')
558 self.assertEqual(command_e.CommandList, node.tag())
559 self.assertEqual(2, len(node.children)) # two top level things
560
561 def test_ParseCommandList(self):
562 node = assert_ParseCommandList(self, 'ls foo')
563 self.assertEqual(2, len(node.words))
564
565 node = assert_ParseCommandList(self, 'ls foo|wc -l || die; ls /')
566 self.assertEqual(command_e.CommandList, node.tag())
567 self.assertEqual(2, len(node.children))
568
569 node = assert_ParseCommandList(
570 self, """\
571ls foo | wc -l || echo fail ;
572echo bar | wc -c || echo f2
573""")
574 self.assertEqual(command_e.CommandList, node.tag())
575 self.assertEqual(2, len(node.children))
576
577 # TODO: Check that we get (LIST (AND_OR (PIPELINE (COMMAND ...)))) here.
578 # We want all levels.
579
580 def testParseCase(self):
581 # Empty case
582 node = assert_ParseCommandLine(self, """\
583case foo in
584esac
585""")
586 self.assertEqual(command_e.Case, node.tag())
587 self.assertEqual(0, len(node.arms))
588
589 # TODO: Test all these. Probably need to add newlines too.
590 # case foo esac # INVALID
591 # case foo in esac
592 # case foo in foo) esac
593 # case foo in foo) ;; esac
594 # case foo in foo) echo hi ;; esac
595 # case foo in foo) echo hi; ;; esac
596
597 node = assert_ParseCommandLine(
598 self, """\
599case word in
600 foo|foo2|foo3) echo hi ;;
601esac
602""")
603 self.assertEqual(command_e.Case, node.tag())
604 self.assertEqual(1, len(node.arms))
605
606 node = assert_ParseCommandLine(
607 self, """\
608case word in foo) echo one-line ;; esac
609""")
610 self.assertEqual(command_e.Case, node.tag())
611 self.assertEqual(1, len(node.arms))
612
613 node = assert_ParseCommandLine(
614 self, """\
615case word in
616 foo) echo foo ;;
617 bar) echo bar ;;
618esac
619""")
620 self.assertEqual(command_e.Case, node.tag())
621 self.assertEqual(2, len(node.arms))
622
623 node = assert_ParseCommandLine(
624 self, """\
625case word in
626 foo) echo foo ;; # NO TRAILING ;; but trailing ;
627 bar) echo bar ;
628esac
629""")
630 self.assertEqual(command_e.Case, node.tag())
631 self.assertEqual(2, len(node.arms))
632
633 node = assert_ParseCommandLine(
634 self, """\
635case word in
636 foo) echo foo ;; # NO TRAILING ;;
637 bar) echo bar
638esac
639""")
640 self.assertEqual(command_e.Case, node.tag())
641 self.assertEqual(2, len(node.arms))
642
643 def testParseYshCase(self):
644 # Empty case
645 node = assert_ParseCommandLine(self, """\
646case (x) {
647}
648""")
649 self.assertEqual(command_e.Case, node.tag())
650 self.assertEqual(0, len(node.arms))
651
652 node = assert_ParseCommandLine(
653 self, """\
654case (x) {
655 (else) { echo hi; }
656}
657""")
658 self.assertEqual(command_e.Case, node.tag())
659 self.assertEqual(1, len(node.arms))
660 self.assertEqual(pat_e.Else, node.arms[0].pattern.tag())
661
662 node = assert_ParseCommandLine(
663 self, """\
664case (x) {
665(2) | (3) { echo hi; }
666}
667""")
668 self.assertEqual(command_e.Case, node.tag())
669 self.assertEqual(1, len(node.arms))
670 pattern = node.arms[0].pattern
671 self.assertEqual(pat_e.YshExprs, pattern.tag())
672
673 self.assertEqual(2, len(pattern.exprs))
674
675 node = assert_ParseCommandLine(
676 self, """\
677case (x) {
678 bare | x | 'string' { echo hi; }
679}
680""")
681 self.assertEqual(command_e.Case, node.tag())
682 self.assertEqual(1, len(node.arms))
683 pattern = node.arms[0].pattern
684 self.assertEqual(pat_e.Words, pattern.tag())
685 self.assertEqual(3, len(pattern.words))
686
687 node = assert_ParseCommandLine(
688 self, """\
689case (x) {
690 / d+ / { echo space; }
691 /d+/ { echo space2; }
692}
693""")
694 self.assertEqual(command_e.Case, node.tag())
695 self.assertEqual(2, len(node.arms))
696
697 pattern0 = node.arms[0].pattern
698 self.assertEqual(pat_e.Eggex, pattern0.tag())
699
700 pattern1 = node.arms[1].pattern
701 self.assertEqual(pat_e.Eggex, pattern1.tag())
702
703 node = assert_ParseCommandLine(self, """\
704case (x) {
705 word { = x }
706}
707""")
708 self.assertEqual(command_e.Case, node.tag())
709 self.assertEqual(1, len(node.arms))
710
711 arm = node.arms[0]
712 self.assertEqual(Id.Lit_Chars, arm.left.id)
713
714 node = assert_ParseCommandLine(
715 self, """\
716case (x) {
717 /'eggex'/ { = x }
718}
719""")
720 self.assertEqual(command_e.Case, node.tag())
721 self.assertEqual(1, len(node.arms))
722
723 arm = node.arms[0]
724 self.assertEqual(Id.Arith_Slash, arm.left.id)
725
726 node = assert_ParseCommandLine(
727 self, """\
728case (x) {
729 ('expr') { = x }
730}
731""")
732 self.assertEqual(command_e.Case, node.tag())
733 self.assertEqual(1, len(node.arms))
734
735 arm = node.arms[0]
736 self.assertEqual(Id.Op_LParen, arm.left.id)
737
738 node = assert_ParseCommandLine(self, """\
739case (x) {
740 (else) { = x }
741}
742""")
743 self.assertEqual(command_e.Case, node.tag())
744 self.assertEqual(1, len(node.arms))
745
746 arm = node.arms[0]
747 self.assertEqual(Id.Op_LParen, arm.left.id)
748
749 def testParseWhile(self):
750 node = assert_ParseCommandList(
751 self, """\
752while true; do
753 echo hi
754 break
755done
756""")
757
758 node = assert_ParseCommandList(
759 self, """\
760while true # comment
761do # comment
762 echo hi # comment
763 break # comment
764done # comment
765""")
766
767 def testParseUntil(self):
768 node = assert_ParseCommandList(
769 self, """\
770until false; do
771 echo hi
772 break
773done
774""")
775
776 def testParseFor(self):
777 node = assert_ParseCommandList(
778 self, """\
779for i in 1 2 3; do
780 echo $i
781done
782""")
783 self.assertEqual(3, len(node.iterable.words))
784
785 # Don't iterate over anything!
786 node = assert_ParseCommandList(self, """\
787for i in ; do
788 echo $i
789done
790""")
791 self.assertEqual(0, len(node.iterable.words))
792
793 # Iterate over the default
794 node = assert_ParseCommandList(self, """\
795for i; do echo $i; done
796""")
797 self.assertEqual(for_iter_e.Args, node.iterable.tag())
798
799 # Iterate over the default, over multiple lines
800 node = assert_ParseCommandList(self, """\
801for i
802do
803 echo $i
804done
805""")
806 self.assertEqual(for_iter_e.Args, node.iterable.tag())
807
808 def testParseForExpression(self):
809 node = assert_ParseCommandList(
810 self, """\
811for ((i=0; i<5; ++i)); do
812 echo $i
813done
814""")
815 self.assertEqual(Id.Arith_Equal, node.init.op_id)
816 self.assertEqual(Id.Arith_Less, node.cond.op.id)
817 self.assertEqual(Id.Arith_DPlus, node.update.op_id)
818 self.assertEqual(command_e.DoGroup, node.body.tag())
819
820 # Now without the ; OR a newline
821 node = assert_ParseCommandList(
822 self, """\
823for ((i=0; i<5; ++i)) do
824 echo $i
825done
826""")
827 self.assertEqual(Id.Arith_Equal, node.init.op_id)
828 self.assertEqual(Id.Arith_Less, node.cond.op.id)
829 self.assertEqual(Id.Arith_DPlus, node.update.op_id)
830 self.assertEqual(command_e.DoGroup, node.body.tag())
831
832 node = assert_ParseCommandList(self, """\
833for ((;;)); do
834 echo $i
835done
836""")
837 self.assertEqual(command_e.DoGroup, node.body.tag())
838
839 def testParseCommandSub(self):
840 # Two adjacent command subs
841 node = assertParseSimpleCommand(self, 'echo $(echo 12)$(echo 34)')
842 self.assertEqual(2, len(node.words))
843
844 # Two adjacent command subs, quoted
845 node = assertParseSimpleCommand(self, 'echo "$(echo 12)$(echo 34)"')
846 self.assertEqual(2, len(node.words))
847
848 def testParseTildeSub(self):
849 node = assert_ParseCommandList(
850 self,
851 "ls ~ ~root ~/src ~/src/foo ~root/src ~weird!name/blah!blah ")
852
853 def testParseDBracket(self):
854 node = assert_ParseCommandList(self, '[[ $# -gt 1 ]]')
855
856 # Bash allows embedded newlines in some places, but not all
857 node = assert_ParseCommandList(self, """\
858[[ $# -gt 1 &&
859
860foo ]]""")
861
862 # Newline needs to be Id.Op_Newline!
863 node = assert_ParseCommandList(
864 self, """\
865if [[ $# -gt 1 ]]
866then
867 echo hi
868fi
869""")
870
871 # Doh, technically this works!
872 # [[ =~ =~ =~ ]]; echo $?
873 # 0
874
875 def testParseDParen(self):
876 node = assert_ParseCommandList(self, '(( 1 + 2 ))')
877
878 def testParseDBracketRegex(self):
879 node = assert_ParseCommandList(self, '[[ foo =~ foo ]]')
880 self.assertEqual(Id.BoolBinary_EqualTilde, node.expr.op_id)
881
882 node = assert_ParseCommandList(self, '[[ foo =~ (foo|bar) ]]')
883 self.assertEqual(Id.BoolBinary_EqualTilde, node.expr.op_id)
884 right = node.expr.right
885 self.assertEqual(1, len(right.parts))
886
887 def testParseIf(self):
888 node = assert_ParseCommandList(self, 'if true; then echo yes; fi')
889 # Subshell in condition
890 node = assert_ParseCommandList(self, 'if (true); then echo yes; fi')
891
892 def testParseFunction(self):
893 node = assert_ParseCommandList(self, 'foo() { echo hi; }')
894
895 node = assert_ParseCommandList(self, 'foo() ( echo hi )')
896 node = assert_ParseCommandList(self,
897 'foo() for i in x; do echo $i; done')
898
899 # KSH FUNCTION
900 node = assert_ParseCommandList(self, 'function foo { echo hi; }')
901 node = assert_ParseCommandList(self, 'function foo () { echo hi; }')
902
903 node = assert_ParseCommandList(self, 'function foo() ( echo hi )')
904 node = assert_ParseCommandList(
905 self, 'function foo() for i in x; do echo $i; done')
906
907 # No () is OK here!
908 node = assert_ParseCommandList(
909 self, 'function foo for i in x; do echo $i; done')
910
911 # Redirects
912 node = assert_ParseCommandList(self,
913 'foo() { echo hi; } 1>&2 2>/dev/null')
914 self.assertEqual(command_e.Redirect, node.body.tag())
915 self.assertEqual(2, len(node.body.redirects))
916
917 def testParseKeyword(self):
918 # NOTE: It chooses the longest match, which is Lit_Chars>
919 node = assert_ParseCommandList(self, 'ifFOO')
920
921
922class NestedParensTest(unittest.TestCase):
923 """Test the hard $() and () nesting.
924
925 Meanings of ):
926
927 ( echo x ) # subshell (cmd_parse)
928 echo $(echo x) # command substitution (word_parse)
929 (( )) # end arith command (cmd_parse)
930 $(( )) # end arith sub (word_parse))
931 a=(1 2 3) # array literal and assoc array literal
932 a[1*(2+3)]=x # grouping in arith context
933 fun() { echo x ; } # function def
934
935 case x in x) echo x ;; esac # case, with balanced or unbalanced
936 case x in (x) echo x ;; esac
937 """
938
939 def testParseSubshell(self):
940 node = assert_ParseCommandLine(self, '(cd /; echo PWD 1); echo PWD 2')
941 self.assertEqual(2, len(node.children))
942 self.assertEqual(command_e.CommandList, node.tag())
943
944 def testParseBraceGroup(self):
945 node = assert_ParseCommandLine(self, '{ cd /; echo PWD; }')
946 self.assertEqual(2, len(node.children))
947 self.assertEqual(command_e.BraceGroup, node.tag())
948
949 node = assert_ParseCommandLine(self, '{ cd /; echo PWD; }; echo PWD')
950 self.assertEqual(2, len(node.children))
951 self.assertEqual(command_e.CommandList, node.tag())
952
953 def testUnquotedComSub(self):
954 # CommandSub with two Literal instances surrounding it
955 node = assertParseSimpleCommand(self, 'echo ab$(echo hi)cd ef')
956 self.assertEqual(3, len(node.words))
957
958 def testNestedComSub(self):
959 node = assertParseSimpleCommand(self,
960 'echo $(one$(echo two)one) three')
961 self.assertEqual(3, len(node.words))
962
963 def testArithSubWithin(self):
964 # Within com sub
965 node = assertParseSimpleCommand(self, 'echo $(echo $((1+2)))')
966 self.assertEqual(command_e.Simple, node.tag())
967 self.assertEqual(2, len(node.words))
968
969 # Within subshell
970 node = assert_ParseCommandList(self, '(echo $((1+2)))')
971 self.assertEqual(command_e.Subshell, node.tag())
972 self.assertEqual(command_e.Simple, node.child.tag())
973
974 def testArithGroupingWithin(self):
975 # Within com sub
976 node = assertParseSimpleCommand(self, 'echo $(echo $((1*(2+3))) )')
977 self.assertEqual(command_e.Simple, node.tag())
978 self.assertEqual(2, len(node.words))
979
980 # Within subshell
981 node = assert_ParseCommandList(self, '(echo $((1*(2+3))) )')
982 self.assertEqual(command_e.Subshell, node.tag())
983 self.assertEqual(command_e.Simple, node.child.tag())
984
985 def testLhsArithGroupingWithin(self):
986 # Within Arith sub
987 node = assertParseSimpleCommand(self, 'echo $((a[1*(2+3)]=x))')
988 self.assertEqual(2, len(node.words))
989
990 # Within Command Sub -- NOT IMPLEMENTED
991 return
992 node = assertParseSimpleCommand(self, 'echo $(a[1*(2+3)]=x)')
993 self.assertEqual(2, len(node.words))
994
995 def testShFunctionWithin(self):
996 node = assert_ParseCommandList(self, 'echo $(fun() { echo hi; }; fun)')
997 self.assertEqual(command_e.Simple, node.tag())
998 self.assertEqual(2, len(node.words))
999
1000 node = assert_ParseCommandList(self, '(fun() { echo hi; }; fun)')
1001 self.assertEqual(command_e.Subshell, node.tag())
1002 self.assertEqual(command_e.CommandList, node.child.tag())
1003
1004 def testArrayLiteralWithin(self):
1005 node = assert_ParseCommandList(self, 'echo $(array=(a b c))')
1006 self.assertEqual(command_e.Simple, node.tag())
1007 self.assertEqual(2, len(node.words))
1008
1009 node = assert_ParseCommandList(self, '(array=(a b c))')
1010 self.assertEqual(command_e.Subshell, node.tag())
1011 self.assertEqual(command_e.ShAssignment, node.child.tag())
1012
1013 def testSubshellWithinComSub(self):
1014 node = assert_ParseCommandList(
1015 self,
1016 'echo one; echo $( (cd /; echo subshell_PWD); echo comsub_PWD); echo two'
1017 )
1018 self.assertEqual(command_e.CommandList, node.tag())
1019 self.assertEqual(3, len(node.children)) # 3 echo statements
1020
1021 # TODO: Need a way to test the literal value of a word
1022 #words = [w.UnquotedLiteralValue() for w in node.children[2].words]
1023 #print(words)
1024
1025 def testCaseWithinComSub(self):
1026 node = assert_ParseCommandList(
1027 self, 'echo $( case foo in one) echo comsub;; esac)')
1028 self.assertEqual(2, len(node.words))
1029
1030 node = assert_ParseCommandList(
1031 self, """\
1032echo $(
1033case foo in one) echo comsub1;; esac
1034case bar in two) echo comsub2;; esac
1035)
1036""")
1037 self.assertEqual(2, len(node.words))
1038
1039 def testComsubWithinCaseWithinComSub(self):
1040 # Comsub within case within comsub
1041 node = assert_ParseCommandList(
1042 self,
1043 'echo one; echo $( case one in $(echo one)) echo $(comsub);; esac ); echo two'
1044 )
1045 self.assertEqual(command_e.CommandList, node.tag())
1046 # Top level should have 3 echo statements
1047 self.assertEqual(3, len(node.children))
1048
1049 def testComSubWithinDoubleQuotes(self):
1050 # CommandSub with two Literal instances surrounding it
1051 node = assertParseSimpleCommand(self,
1052 'echo "double $(echo hi) quoted" two')
1053 self.assertEqual(3, len(node.words))
1054
1055 def testEmptyCaseWithinSubshell(self):
1056 node = assert_ParseCommandList(self, """\
1057( case foo in
1058 esac
1059)
1060""")
1061 self.assertEqual(command_e.Subshell, node.tag())
1062
1063 def testBalancedCaseWithin(self):
1064 # With leading ( in case. This one doesn't cause problems! We don't need
1065 # the MaybeUnreadOne() lexer hack.
1066 node = assert_ParseCommandList(
1067 self, """\
1068$( case foo in
1069 (one) echo hi ;;
1070 esac
1071)
1072""")
1073 self.assertEqual(command_e.Simple, node.tag())
1074
1075 node = assert_ParseCommandList(
1076 self, """\
1077( case foo in
1078 (one) echo hi ;;
1079 esac
1080)
1081""")
1082 self.assertEqual(command_e.Subshell, node.tag())
1083
1084 def testUnbalancedCaseWithin(self):
1085 # With leading ( in case. This one doesn't cause problems! We don't need
1086 # the MaybeUnreadOne() lexer hack.
1087 node = assert_ParseCommandList(
1088 self, """\
1089$( case foo in
1090 one) echo hi ;;
1091 esac
1092)
1093""")
1094 self.assertEqual(command_e.Simple, node.tag())
1095
1096 node = assert_ParseCommandList(
1097 self, """\
1098( case foo in
1099 one) echo hi ;;
1100 esac
1101)
1102""")
1103 self.assertEqual(command_e.Subshell, node.tag())
1104
1105 def testForExpressionWithin(self):
1106 # With leading ( in case. This one doesn't cause problems! We don't need
1107 # the MaybeUnreadOne() lexer hack.
1108 node = assert_ParseCommandList(
1109 self, """\
1110$( for ((i=0; i<3; ++i)); do
1111 echo hi
1112 done
1113)
1114""")
1115 self.assertEqual(command_e.Simple, node.tag())
1116
1117 node = assert_ParseCommandList(
1118 self, """\
1119( for ((i=0; i<3; ++i)); do
1120 echo hi
1121 done
1122)
1123""")
1124 self.assertEqual(command_e.Subshell, node.tag())
1125
1126
1127class RealBugsTest(unittest.TestCase):
1128
1129 def testGitBug(self):
1130 # Original bug from git codebase. Case in subshell.
1131 node = assert_ParseCommandList(
1132 self, """\
1133( cd "$PACKDIR" &&
1134 for e in $existing
1135 do
1136 case " $fullbases " in
1137 *" $e "*) ;;
1138 *) rm -f "$e.pack" "$e.idx" "$e.keep" ;;
1139 esac
1140 done
1141)
1142""")
1143 self.assertEqual(command_e.Subshell, node.tag())
1144
1145 def testParseCase3(self):
1146 # Bug from git codebase. NOT a comment token.
1147 node = assert_ParseCommandLine(
1148 self, """\
1149case "$fd,$command" in
1150 3,#*|3,)
1151 # copy comments
1152 ;;
1153esac
1154""")
1155 self.assertEqual(command_e.Case, node.tag())
1156
1157 def testGitComment(self):
1158 # ;# is a comment! Gah.
1159 # Conclusion: Comments are NOT LEXICAL. They are part of word parsing.
1160
1161 node = assert_ParseCommandList(
1162 self, """\
1163. "$TEST_DIRECTORY"/diff-lib.sh ;# test-lib chdir's into trash
1164""")
1165 self.assertEqual(command_e.Sentence, node.tag())
1166 self.assertEqual(2, len(node.child.words))
1167
1168 # This is NOT a comment
1169 node = assert_ParseCommandList(self, """\
1170echo foo#bar
1171""")
1172 self.assertEqual(command_e.Simple, node.tag())
1173 self.assertEqual(2, len(node.words))
1174 _, s, _ = word_.StaticEval(node.words[1])
1175 self.assertEqual('foo#bar', s)
1176
1177 # This is a comment
1178 node = assert_ParseCommandList(self, """\
1179echo foo #comment
1180""")
1181 self.assertEqual(command_e.Simple, node.tag())
1182 self.assertEqual(2, len(node.words))
1183 _, s, _ = word_.StaticEval(node.words[1])
1184 self.assertEqual('foo', s)
1185
1186 # Empty comment
1187 node = assert_ParseCommandList(self, """\
1188echo foo #
1189""")
1190 self.assertEqual(command_e.Simple, node.tag())
1191 self.assertEqual(2, len(node.words))
1192 _, s, _ = word_.StaticEval(node.words[1])
1193 self.assertEqual('foo', s)
1194
1195 def testChromeIfSubshell(self):
1196 node = assert_ParseCommandList(
1197 self, """\
1198if true; then (
1199 echo hi
1200)
1201fi
1202""")
1203 self.assertEqual(command_e.If, node.tag())
1204
1205 node = assert_ParseCommandList(
1206 self, """\
1207while true; do {
1208 echo hi
1209 break
1210} done
1211""")
1212 self.assertEqual(command_e.WhileUntil, node.tag())
1213 self.assertEqual(Id.KW_While, node.keyword.id)
1214
1215 node = assert_ParseCommandList(
1216 self, """\
1217if true; then (
1218 echo hi
1219) fi
1220""")
1221 self.assertEqual(command_e.If, node.tag())
1222
1223 # Related: two fi's in a row, found in Chrome configure. Compound commands
1224 # are special; don't need newlines.
1225 node = assert_ParseCommandList(
1226 self, """\
1227if true; then
1228 if true; then
1229 echo hi
1230 fi fi
1231echo hi
1232""")
1233 self.assertEqual(command_e.CommandList, node.tag())
1234
1235 def testBackticks(self):
1236 # Another empty command sub
1237 node = assert_ParseCommandList(self, """\
1238echo $()
1239""")
1240
1241 # Simplest case
1242 node = assert_ParseCommandList(self, """\
1243echo ``
1244""")
1245
1246 # Found in the wild.
1247 # Just a comment trick found in sandstorm
1248 node = assert_ParseCommandList(
1249 self, """\
1250cmd \
1251 flag `# comment` \
1252 flag2
1253""")
1254
1255 # Empty should be allowed
1256 node = assert_ParseCommandList(self, """\
1257FOO="bar"`
1258 `"baz"
1259""")
1260
1261 def testQuineDb(self):
1262 # Need to handle the DOLLAR_SQ lex state
1263 node = assert_ParseCommandList(
1264 self, r"""\
1265case foo in
1266$'\'')
1267 ret+="\\"\'
1268 ;;
1269esac
1270""")
1271 self.assertEqual(command_e.Case, node.tag())
1272
1273 node = assert_ParseCommandList(self, r"""\
1274$'abc\ndef'
1275""")
1276 self.assertEqual(command_e.Simple, node.tag())
1277 self.assertEqual(1, len(node.words))
1278 w = node.words[0]
1279 self.assertEqual(1, len(w.parts))
1280 p = w.parts[0]
1281
1282 self.assertEqual('abc\ndef', p.sval)
1283
1284 def testArithConstants(self):
1285 # Found in Gherkin
1286 node = assert_ParseCommandList(
1287 self, r"""\
1288 [[ -n "${marks[${tag_marker}002${cons_ptr}]}" ]];
1289""")
1290 # Dynamic constant
1291 node = assert_ParseCommandList(self, r"""\
1292echo $(( 0x$foo ))
1293""")
1294
1295 def testBacktickCommentHack(self):
1296 # Found in sandstorm.
1297 # The problem here is that the comment goes to the end of the line, which
1298 # eats up the closing backtick! We could change the mode of the lexer
1299 # inside a command sub, or possibly just ignore this use case.
1300 return
1301
1302 node = assert_ParseCommandList(
1303 self, r"""\
1304openssl \
1305 -newkey rsa:4096 `# Create a new RSA key of length 4096 bits.` \
1306 `# Sandcats just needs the CN= (common name) in the request.` \
1307 -subj "/CN=*.${SS_HOSTNAME}/"
1308""")
1309
1310 def testArrayLiteralFromSetup(self):
1311 # Found in setup.shl/bin/setup -- this is the "Parsing Bash is
1312 # Undecidable" problem.
1313 err = _assert_ParseCommandListError(
1314 self, """\
1315errcmd=( "${SETUP_STATE[$err.cmd]}" )
1316""")
1317
1318 # Double quotes fix it.
1319 node = assert_ParseCommandList(
1320 self, r"""\
1321errcmd=( "${SETUP_STATE["$err.cmd"]}" )
1322""")
1323
1324
1325class ErrorLocationsTest(unittest.TestCase):
1326
1327 def testCommand(self):
1328 """Enumerating errors in cmd_parse.py."""
1329
1330 err = _assert_ParseCommandListError(self, 'ls <')
1331
1332 err = _assert_ParseCommandListError(self, 'ls < <')
1333
1334 # Word parse error in command parser
1335 err = _assert_ParseCommandListError(self, r'echo foo$(ls <)bar')
1336
1337 err = _assert_ParseCommandListError(self, r'BAD_ENV=(1 2 3) ls')
1338
1339 # This needs more context
1340 err = _assert_ParseCommandListError(
1341 self, 'for ((i=1; i<)); do echo $i; done')
1342
1343 err = _assert_ParseCommandListError(
1344 self, 'for ((i=1; i<5; ++i)) OOPS echo $i; ERR')
1345
1346 # After semi
1347 err = _assert_ParseCommandListError(
1348 self, 'for ((i=1; i<5; ++i)); OOPS echo $i; ERR')
1349
1350 err = _assert_ParseCommandListError(
1351 self, 'for $bad in 1 2; do echo hi; done')
1352
1353 err = _assert_ParseCommandListError(self, 'for foo BAD')
1354
1355 err = _assert_ParseCommandListError(self, 'if foo; then echo hi; z')
1356
1357 err = _assert_ParseCommandListError(self,
1358 'foo$(invalid) () { echo hi; }')
1359
1360 def testErrorInHereDoc(self):
1361 return
1362 # Here doc body. Hm this should be failing. Does it just fail to get
1363 # filled?
1364 err = _assert_ParseCommandListError(self, """cat <<EOF
1365$(echo <)
1366EOF
1367""")
1368 return
1369
1370 def testBool(self):
1371 """Enumerating errors in bool_parse.py."""
1372 err = _assert_ParseCommandListError(self, '[[ foo bar ]]')
1373 err = _assert_ParseCommandListError(self, '[[ foo -eq ]]')
1374
1375 # error in word
1376 err = _assert_ParseCommandListError(self, '[[ foo$(echo <) -eq foo ]]')
1377
1378 return
1379 # NOTE: This was disabled because of escaping.
1380 # Invalid regex
1381 err = _assert_ParseCommandListError(self, '[[ foo =~ \( ]]')
1382
1383 def testArith(self):
1384 """Enumerating errors in arith_parse.py."""
1385 err = _assert_ParseCommandListError(self, '(( 1 + ))')
1386
1387 def testArraySyntax(self):
1388 err = _assert_ParseCommandListError(self, 'A= (1 2)')
1389
1390 def testEofInDoubleQuoted(self):
1391 err = _assert_ParseCommandListError(self, 'foo="" echo "bar ')
1392
1393 def testQuotesInFunctionName(self):
1394 err = _assert_ParseCommandListError(
1395 self, """\
1396 foo"bar" () {
1397 echo hi
1398 }
1399 """)
1400
1401 def testForLoopName(self):
1402 err = _assert_ParseCommandListError(
1403 self, """\
1404 for [ i = 1; i < 10; i++ ]
1405 """)
1406 err = _assert_ParseCommandListError(self, """\
1407 for = in a
1408 """)
1409
1410 def testHereDocCommandSub(self):
1411 # Originally from spec/09-here-doc.sh.
1412 err = _assert_ParseCommandListError(
1413 self, """\
1414for x in 1 2 $(cat <<EOF
1415THREE
1416EOF); do
1417 echo for word $x
1418done
1419""")
1420
1421 def testForLoopEof(self):
1422 err = _assert_ParseCommandListError(self, "for x in 1 2 $(")
1423
1424
1425class ParserInteractionsTest(unittest.TestCase):
1426
1427 def _dumpLexerState(self, lexer):
1428 print("----")
1429 print(lexer.line_lexer.src_line.content)
1430 print(" " * lexer.line_lexer.line_pos + "^ We are here")
1431 print("----")
1432
1433 def testBraceGroup(self):
1434 code_str = '{ echo hello; } '
1435
1436 c_parser = test_lib.InitCommandParser(code_str)
1437 lexer = c_parser.lexer
1438
1439 c_parser.ParseBraceGroup()
1440
1441 if 0:
1442 self._dumpLexerState(lexer)
1443
1444 # We should be at the end of the line:
1445 # '{ echo hello; } '
1446 # ^ Which is here
1447 self.assertEqual(len(lexer.line_lexer.src_line.content),
1448 lexer.line_lexer.line_pos)
1449
1450 next_id = c_parser.w_parser.LookPastSpace()
1451 self.assertEqual(next_id, Id.Unknown_Tok, Id_str(next_id))
1452
1453 def testYSHBraceGroup(self):
1454 code_str = '{ echo hello } '
1455
1456 c_parser = test_lib.InitCommandParser(code_str)
1457 c_parser.parse_opts = state.MakeOilOpts() # place parser in YSH mode
1458 lexer = c_parser.lexer
1459
1460 c_parser.ParseBraceGroup()
1461
1462 if 0:
1463 self._dumpLexerState(lexer)
1464
1465 self.assertEqual(len(lexer.line_lexer.src_line.content),
1466 lexer.line_lexer.line_pos)
1467
1468 next_id = c_parser.w_parser.LookPastSpace()
1469 self.assertEqual(next_id, Id.Unknown_Tok)
1470
1471 def testCmd2Expr2Cmd(self):
1472 code_str = '{ = hello } '
1473
1474 c_parser = test_lib.InitCommandParser(code_str)
1475 c_parser.parse_opts = state.MakeOilOpts() # place parser in YSH mode
1476 lexer = c_parser.lexer
1477
1478 c_parser.ParseBraceGroup()
1479
1480 if 0:
1481 self._dumpLexerState(lexer)
1482
1483 self.assertEqual(len(lexer.line_lexer.src_line.content),
1484 lexer.line_lexer.line_pos)
1485
1486 next_id = c_parser.w_parser.LookPastSpace()
1487 self.assertEqual(next_id, Id.Unknown_Tok)
1488
1489
1490if __name__ == '__main__':
1491 unittest.main()