debugger.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  1. #!/usr/bin/python
  2. # Copyright 2016 Steven Watanabe
  3. # Distributed under the Boost Software License, Version 1.0.
  4. # (See accompanying file LICENSE.txt or https://www.bfgroup.xyz/b2/LICENSE.txt)
  5. # Test for the debugger
  6. import BoostBuild
  7. import TestCmd
  8. import re
  9. def split_stdin_stdout(text):
  10. """stdin is all text after the prompt up to and including
  11. the next newline. Everything else is stdout. stdout
  12. may contain regular expressions enclosed in {{}}."""
  13. prompt = re.escape('(b2db) ')
  14. pattern = re.compile('(?<=%s)(.*\n)' % prompt)
  15. text = text.replace("{{bjam}}", "{{.*}}b2{{(?:\\.exe)?}}")
  16. stdin = ''.join(re.findall(pattern, text))
  17. stdout = re.sub(pattern, '', text)
  18. outside_pattern = re.compile(r'(?:\A|(?<=\}\}))(?:[^\{]|(?:\{(?!\{)))*(?:(?=\{\{)|\Z)')
  19. def escape_line(line):
  20. line = re.sub(outside_pattern, lambda m: re.escape(m.group(0)), line)
  21. return re.sub(r'\{\{|\}\}', '', line)
  22. stdout = '\n'.join([escape_line(line) for line in stdout.split('\n')])
  23. return (stdin,stdout)
  24. def run(tester, io):
  25. (input,output) = split_stdin_stdout(io)
  26. tester.run_build_system(stdin=input, stdout=output, match=TestCmd.match_re)
  27. def make_tester():
  28. return BoostBuild.Tester(["-dconsole"], pass_toolset=False, pass_d0=False,
  29. use_test_config=False, ignore_toolset_requirements=False, match=TestCmd.match_re)
  30. def test_run():
  31. t = make_tester()
  32. t.write("test.jam", """\
  33. UPDATE ;
  34. """)
  35. run(t, """\
  36. (b2db) run -ftest.jam
  37. Starting program: {{bjam}} -ftest.jam
  38. Child {{\d+}} exited with status 0
  39. (b2db) quit
  40. """)
  41. t.cleanup()
  42. def test_exit_status():
  43. t = make_tester()
  44. t.write("test.jam", """\
  45. EXIT : 1 ;
  46. """)
  47. run(t, """\
  48. (b2db) run -ftest.jam
  49. Starting program: {{bjam}} -ftest.jam
  50. Child {{\d+}} exited with status 1
  51. (b2db) quit
  52. """)
  53. t.cleanup()
  54. def test_step():
  55. t = make_tester()
  56. t.write("test.jam", """\
  57. rule g ( )
  58. {
  59. a = 1 ;
  60. b = 2 ;
  61. }
  62. rule f ( )
  63. {
  64. g ;
  65. c = 3 ;
  66. }
  67. f ;
  68. """)
  69. run(t, """\
  70. (b2db) break f
  71. Breakpoint 1 set at f
  72. (b2db) run -ftest.jam
  73. Starting program: {{bjam}} -ftest.jam
  74. Breakpoint 1, f ( ) at test.jam:8
  75. 8 g ;
  76. (b2db) step
  77. 3 a = 1 ;
  78. (b2db) step
  79. 4 b = 2 ;
  80. (b2db) step
  81. 9 c = 3 ;
  82. (b2db) quit
  83. """)
  84. t.cleanup()
  85. # Note: step doesn't need to worry about breakpoints,
  86. # as it always stops at the next line executed.
  87. def test_next():
  88. t = make_tester()
  89. t.write("test.jam", """\
  90. rule g ( )
  91. {
  92. a = 1 ;
  93. }
  94. rule f ( )
  95. {
  96. g ;
  97. b = 2 ;
  98. c = 3 ;
  99. }
  100. rule h ( )
  101. {
  102. f ;
  103. g ;
  104. }
  105. h ;
  106. d = 4 ;
  107. """)
  108. run(t, """\
  109. (b2db) break f
  110. Breakpoint 1 set at f
  111. (b2db) run -ftest.jam
  112. Starting program: {{bjam}} -ftest.jam
  113. Breakpoint 1, f ( ) at test.jam:7
  114. 7 g ;
  115. (b2db) next
  116. 8 b = 2 ;
  117. (b2db) next
  118. 9 c = 3 ;
  119. (b2db) next
  120. 14 g ;
  121. (b2db) next
  122. 17 d = 4 ;
  123. (b2db) quit
  124. """)
  125. t.cleanup()
  126. def test_next_breakpoint():
  127. """next should stop if it encounters a breakpoint.
  128. If the normal end point happens to be a breakpoint,
  129. then it should be reported as normal stepping."""
  130. t = make_tester()
  131. t.write("test.jam", """\
  132. rule f ( recurse ? )
  133. {
  134. if $(recurse) { f ; }
  135. a = 1 ;
  136. }
  137. rule g ( )
  138. {
  139. b = 2 ;
  140. }
  141. f true ;
  142. g ;
  143. """)
  144. run(t, """\
  145. (b2db) break f
  146. Breakpoint 1 set at f
  147. (b2db) break g
  148. Breakpoint 2 set at g
  149. (b2db) break test.jam:4
  150. Breakpoint 3 set at test.jam:4
  151. (b2db) run -ftest.jam
  152. Starting program: {{bjam}} -ftest.jam
  153. Breakpoint 1, f ( true ) at test.jam:3
  154. 3 if $(recurse) { f ; }
  155. (b2db) next
  156. Breakpoint 1, f ( ) at test.jam:3
  157. 3 if $(recurse) { f ; }
  158. (b2db) next
  159. 4 a = 1 ;
  160. (b2db) next
  161. 4 a = 1 ;
  162. (b2db) next
  163. 11 g ;
  164. (b2db) next
  165. Breakpoint 2, g ( ) at test.jam:8
  166. 8 b = 2 ;
  167. (b2db) quit
  168. """)
  169. t.cleanup()
  170. def test_finish():
  171. t = make_tester()
  172. t.write("test.jam", """\
  173. rule f ( )
  174. {
  175. a = 1 ;
  176. }
  177. rule g ( )
  178. {
  179. f ;
  180. b = 2 ;
  181. i ;
  182. }
  183. rule h ( )
  184. {
  185. g ;
  186. i ;
  187. }
  188. rule i ( )
  189. {
  190. c = 3 ;
  191. }
  192. h ;
  193. d = 4 ;
  194. """)
  195. run(t, """\
  196. (b2db) break f
  197. Breakpoint 1 set at f
  198. (b2db) run -ftest.jam
  199. Starting program: {{bjam}} -ftest.jam
  200. Breakpoint 1, f ( ) at test.jam:3
  201. 3 a = 1 ;
  202. (b2db) finish
  203. 8 b = 2 ;
  204. (b2db) finish
  205. 14 i ;
  206. (b2db) finish
  207. 21 d = 4 ;
  208. (b2db) quit
  209. """)
  210. t.cleanup()
  211. def test_finish_breakpoints():
  212. """finish should stop when it reaches a breakpoint."""
  213. t = make_tester()
  214. t.write("test.jam", """\
  215. rule f ( recurse * )
  216. {
  217. if $(recurse)
  218. {
  219. a = [ f $(recurse[2-]) ] ;
  220. }
  221. }
  222. rule g ( list * )
  223. {
  224. for local v in $(list)
  225. {
  226. x = $(v) ;
  227. }
  228. }
  229. f 1 2 ;
  230. g 1 2 ;
  231. """)
  232. run(t, """\
  233. (b2db) break test.jam:5
  234. Breakpoint 1 set at test.jam:5
  235. (b2db) break test.jam:12
  236. Breakpoint 2 set at test.jam:12
  237. (b2db) run -ftest.jam
  238. Starting program: {{bjam}} -ftest.jam
  239. Breakpoint 1, f ( 1 2 ) at test.jam:5
  240. 5 a = [ f $(recurse[2-]) ] ;
  241. (b2db) finish
  242. Breakpoint 1, f ( 2 ) at test.jam:5
  243. 5 a = [ f $(recurse[2-]) ] ;
  244. (b2db) finish
  245. 5 a = [ f $(recurse[2-]) ] ;
  246. (b2db) finish
  247. 16 g 1 2 ;
  248. (b2db) finish
  249. Breakpoint 2, g ( 1 2 ) at test.jam:12
  250. 12 x = $(v) ;
  251. (b2db) finish
  252. Breakpoint 2, g ( 1 2 ) at test.jam:12
  253. 12 x = $(v) ;
  254. (b2db) quit
  255. """)
  256. t.cleanup()
  257. def test_continue_breakpoints():
  258. """continue should stop when it reaches a breakpoint"""
  259. t = make_tester()
  260. t.write("test.jam", """\
  261. rule f ( recurse * )
  262. {
  263. if $(recurse)
  264. {
  265. a = [ f $(recurse[2-]) ] ;
  266. }
  267. }
  268. rule g ( list * )
  269. {
  270. for local v in $(list)
  271. {
  272. x = $(v) ;
  273. }
  274. }
  275. f 1 2 ;
  276. g 1 2 ;
  277. """)
  278. run(t, """\
  279. (b2db) break test.jam:5
  280. Breakpoint 1 set at test.jam:5
  281. (b2db) break test.jam:12
  282. Breakpoint 2 set at test.jam:12
  283. (b2db) run -ftest.jam
  284. Starting program: {{bjam}} -ftest.jam
  285. Breakpoint 1, f ( 1 2 ) at test.jam:5
  286. 5 a = [ f $(recurse[2-]) ] ;
  287. (b2db) continue
  288. Breakpoint 1, f ( 2 ) at test.jam:5
  289. 5 a = [ f $(recurse[2-]) ] ;
  290. (b2db) continue
  291. Breakpoint 1, f ( 1 2 ) at test.jam:5
  292. 5 a = [ f $(recurse[2-]) ] ;
  293. (b2db) continue
  294. Breakpoint 2, g ( 1 2 ) at test.jam:12
  295. 12 x = $(v) ;
  296. (b2db) continue
  297. Breakpoint 2, g ( 1 2 ) at test.jam:12
  298. 12 x = $(v) ;
  299. (b2db) quit
  300. """)
  301. t.cleanup()
  302. def test_breakpoints():
  303. """Tests the interaction between the following commands:
  304. break, clear, delete, disable, enable"""
  305. t = make_tester()
  306. t.write("test.jam", """\
  307. rule f ( )
  308. {
  309. a = 1 ;
  310. }
  311. rule g ( )
  312. {
  313. b = 2 ;
  314. }
  315. rule h ( )
  316. {
  317. c = 3 ;
  318. d = 4 ;
  319. }
  320. f ;
  321. g ;
  322. h ;
  323. UPDATE ;
  324. """)
  325. run(t, """\
  326. (b2db) break f
  327. Breakpoint 1 set at f
  328. (b2db) run -ftest.jam
  329. Starting program: {{bjam}} -ftest.jam
  330. Breakpoint 1, f ( ) at test.jam:3
  331. 3 a = 1 ;
  332. (b2db) kill
  333. (b2db) break g
  334. Breakpoint 2 set at g
  335. (b2db) disable 1
  336. (b2db) run -ftest.jam
  337. Starting program: {{bjam}} -ftest.jam
  338. Breakpoint 2, g ( ) at test.jam:7
  339. 7 b = 2 ;
  340. (b2db) kill
  341. (b2db) enable 1
  342. (b2db) run -ftest.jam
  343. Starting program: {{bjam}} -ftest.jam
  344. Breakpoint 1, f ( ) at test.jam:3
  345. 3 a = 1 ;
  346. (b2db) kill
  347. (b2db) delete 1
  348. (b2db) run -ftest.jam
  349. Starting program: {{bjam}} -ftest.jam
  350. Breakpoint 2, g ( ) at test.jam:7
  351. 7 b = 2 ;
  352. (b2db) kill
  353. (b2db) break test.jam:12
  354. Breakpoint 3 set at test.jam:12
  355. (b2db) clear g
  356. Deleted breakpoint 2
  357. (b2db) run -ftest.jam
  358. Starting program: {{bjam}} -ftest.jam
  359. Breakpoint 3, h ( ) at test.jam:12
  360. 12 d = 4 ;
  361. (b2db) kill
  362. (b2db) clear test.jam:12
  363. Deleted breakpoint 3
  364. (b2db) run -ftest.jam
  365. Starting program: {{bjam}} -ftest.jam
  366. Child {{\d+}} exited with status 0
  367. (b2db) quit
  368. """)
  369. t.cleanup()
  370. def test_breakpoints_running():
  371. """Tests that breakpoints can be added and modified
  372. while the program is running."""
  373. t = make_tester()
  374. t.write("test.jam", """\
  375. rule f ( )
  376. {
  377. a = 1 ;
  378. }
  379. rule g ( )
  380. {
  381. b = 2 ;
  382. }
  383. rule h ( )
  384. {
  385. c = 3 ;
  386. d = 4 ;
  387. }
  388. f ;
  389. g ;
  390. h ;
  391. UPDATE ;
  392. """)
  393. run(t, """\
  394. (b2db) break test.jam:14
  395. Breakpoint 1 set at test.jam:14
  396. (b2db) run -ftest.jam
  397. Starting program: {{bjam}} -ftest.jam
  398. Breakpoint 1, module scope at test.jam:14
  399. 14 f ;
  400. (b2db) break f
  401. Breakpoint 2 set at f
  402. (b2db) continue
  403. Breakpoint 2, f ( ) at test.jam:3
  404. 3 a = 1 ;
  405. (b2db) kill
  406. (b2db) run -ftest.jam
  407. Starting program: {{bjam}} -ftest.jam
  408. Breakpoint 1, module scope at test.jam:14
  409. 14 f ;
  410. (b2db) break g
  411. Breakpoint 3 set at g
  412. (b2db) disable 2
  413. (b2db) continue
  414. Breakpoint 3, g ( ) at test.jam:7
  415. 7 b = 2 ;
  416. (b2db) kill
  417. (b2db) run -ftest.jam
  418. Starting program: {{bjam}} -ftest.jam
  419. Breakpoint 1, module scope at test.jam:14
  420. 14 f ;
  421. (b2db) enable 2
  422. (b2db) continue
  423. Breakpoint 2, f ( ) at test.jam:3
  424. 3 a = 1 ;
  425. (b2db) kill
  426. (b2db) run -ftest.jam
  427. Starting program: {{bjam}} -ftest.jam
  428. Breakpoint 1, module scope at test.jam:14
  429. 14 f ;
  430. (b2db) delete 2
  431. (b2db) continue
  432. Breakpoint 3, g ( ) at test.jam:7
  433. 7 b = 2 ;
  434. (b2db) kill
  435. (b2db) run -ftest.jam
  436. Starting program: {{bjam}} -ftest.jam
  437. Breakpoint 1, module scope at test.jam:14
  438. 14 f ;
  439. (b2db) break test.jam:12
  440. Breakpoint 4 set at test.jam:12
  441. (b2db) clear g
  442. Deleted breakpoint 3
  443. (b2db) continue
  444. Breakpoint 4, h ( ) at test.jam:12
  445. 12 d = 4 ;
  446. (b2db) kill
  447. (b2db) run -ftest.jam
  448. Starting program: {{bjam}} -ftest.jam
  449. Breakpoint 1, module scope at test.jam:14
  450. 14 f ;
  451. (b2db) clear test.jam:12
  452. Deleted breakpoint 4
  453. (b2db) continue
  454. Child {{\d+}} exited with status 0
  455. (b2db) quit
  456. """)
  457. t.cleanup()
  458. def test_backtrace():
  459. t = make_tester()
  460. t.write("test.jam", """\
  461. rule f ( x * : y * : z * )
  462. {
  463. return $(x) ;
  464. }
  465. rule g ( x * : y * : z * )
  466. {
  467. return [ f $(x) : $(y) : $(z) ] ;
  468. }
  469. g 1 : 2 : 3 ;
  470. """)
  471. run(t, """\
  472. (b2db) break f
  473. Breakpoint 1 set at f
  474. (b2db) run -ftest.jam
  475. Starting program: {{bjam}} -ftest.jam
  476. Breakpoint 1, f ( 1 : 2 : 3 ) at test.jam:3
  477. 3 return $(x) ;
  478. (b2db) backtrace
  479. #0 in f ( 1 : 2 : 3 ) at test.jam:3
  480. #1 in g ( 1 : 2 : 3 ) at test.jam:7
  481. #2 in module scope at test.jam:9
  482. (b2db) quit
  483. """)
  484. t.cleanup()
  485. def test_print():
  486. t = make_tester()
  487. t.write("test.jam", """\
  488. rule f ( args * )
  489. {
  490. return $(args) ;
  491. }
  492. f x ;
  493. f x y ;
  494. """)
  495. run(t, """\
  496. (b2db) break f
  497. Breakpoint 1 set at f
  498. (b2db) run -ftest.jam
  499. Starting program: {{bjam}} -ftest.jam
  500. Breakpoint 1, f ( x ) at test.jam:3
  501. 3 return $(args) ;
  502. (b2db) print $(args)
  503. x
  504. (b2db) continue
  505. Breakpoint 1, f ( x y ) at test.jam:3
  506. 3 return $(args) ;
  507. (b2db) print $(args)
  508. x y
  509. (b2db) disable 1
  510. (b2db) print [ f z ]
  511. z
  512. (b2db) quit
  513. """)
  514. t.cleanup()
  515. def test_run_running():
  516. t = make_tester()
  517. t.write("test.jam", """\
  518. UPDATE ;
  519. """)
  520. run(t, """\
  521. (b2db) break test.jam:1
  522. Breakpoint 1 set at test.jam:1
  523. (b2db) run -ftest.jam
  524. Starting program: {{bjam}} -ftest.jam
  525. Breakpoint 1, module scope at test.jam:1
  526. 1 UPDATE ;
  527. (b2db) run -ftest.jam
  528. Child {{\d+}} exited with status 0
  529. Starting program: {{bjam}} -ftest.jam
  530. Breakpoint 1, module scope at test.jam:1
  531. 1 UPDATE ;
  532. (b2db) quit
  533. """)
  534. t.cleanup()
  535. def test_error_not_running():
  536. t = make_tester()
  537. run(t, """\
  538. (b2db) continue
  539. The program is not being run.
  540. (b2db) step
  541. The program is not being run.
  542. (b2db) next
  543. The program is not being run.
  544. (b2db) finish
  545. The program is not being run.
  546. (b2db) kill
  547. The program is not being run.
  548. (b2db) backtrace
  549. The program is not being run.
  550. (b2db) print 1
  551. The program is not being run.
  552. (b2db) quit
  553. """)
  554. t.cleanup()
  555. def test_bad_arguments():
  556. t = make_tester()
  557. t.write("test.jam", """\
  558. UPDATE ;
  559. """)
  560. run(t, """\
  561. (b2db) break test.jam:1
  562. Breakpoint 1 set at test.jam:1
  563. (b2db) run -ftest.jam
  564. Starting program: {{bjam}} -ftest.jam
  565. Breakpoint 1, module scope at test.jam:1
  566. 1 UPDATE ;
  567. (b2db) continue 1
  568. Too many arguments to continue.
  569. (b2db) step 1
  570. Too many arguments to step.
  571. (b2db) next 1
  572. Too many arguments to next.
  573. (b2db) finish 1
  574. Too many arguments to finish.
  575. (b2db) break
  576. Missing argument to break.
  577. (b2db) break x y
  578. Too many arguments to break.
  579. (b2db) disable
  580. Missing argument to disable.
  581. (b2db) disable 1 2
  582. Too many arguments to disable.
  583. (b2db) disable x
  584. Invalid breakpoint number x.
  585. (b2db) disable 2
  586. Unknown breakpoint 2.
  587. (b2db) enable
  588. Missing argument to enable.
  589. (b2db) enable 1 2
  590. Too many arguments to enable.
  591. (b2db) enable x
  592. Invalid breakpoint number x.
  593. (b2db) enable 2
  594. Unknown breakpoint 2.
  595. (b2db) delete
  596. Missing argument to delete.
  597. (b2db) delete 1 2
  598. Too many arguments to delete.
  599. (b2db) delete x
  600. Invalid breakpoint number x.
  601. (b2db) delete 2
  602. Unknown breakpoint 2.
  603. (b2db) clear
  604. Missing argument to clear.
  605. (b2db) clear test.jam:1 test.jam:1
  606. Too many arguments to clear.
  607. (b2db) clear test.jam:2
  608. No breakpoint at test.jam:2.
  609. (b2db) quit
  610. """)
  611. t.cleanup()
  612. def test_unknown_command():
  613. t = make_tester()
  614. run(t, """\
  615. (b2db) xyzzy
  616. Unknown command: xyzzy
  617. (b2db) gnusto rezrov
  618. Unknown command: gnusto
  619. (b2db) quit
  620. """)
  621. t.cleanup()
  622. test_run()
  623. test_exit_status()
  624. test_step()
  625. test_next()
  626. test_next_breakpoint()
  627. test_finish()
  628. test_finish_breakpoints()
  629. test_continue_breakpoints()
  630. test_breakpoints()
  631. test_breakpoints_running()
  632. test_backtrace()
  633. test_print()
  634. test_run_running()
  635. test_error_not_running()
  636. test_bad_arguments()
  637. test_unknown_command()