debug_test.go 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235
  1. /*
  2. * ECAL
  3. *
  4. * Copyright 2020 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the MIT
  7. * License, If a copy of the MIT License was not distributed with this
  8. * file, You can obtain one at https://opensource.org/licenses/MIT.
  9. */
  10. package interpreter
  11. import (
  12. "encoding/json"
  13. "fmt"
  14. "strconv"
  15. "strings"
  16. "sync"
  17. "testing"
  18. "time"
  19. "devt.de/krotik/common/errorutil"
  20. "devt.de/krotik/ecal/scope"
  21. "devt.de/krotik/ecal/util"
  22. )
  23. func TestSimpleDebugging(t *testing.T) {
  24. var err error
  25. defer func() {
  26. testDebugger = nil
  27. }()
  28. testDebugger = NewECALDebugger(nil)
  29. if _, err = testDebugger.HandleInput("break ECALEvalTest:3"); err != nil {
  30. t.Error("Unexpected result:", err)
  31. return
  32. }
  33. if _, err = testDebugger.HandleInput("break ECALEvalTest:4"); err != nil {
  34. t.Error("Unexpected result:", err)
  35. return
  36. }
  37. if _, err = testDebugger.HandleInput("disablebreak ECALEvalTest:4"); err != nil {
  38. t.Error("Unexpected result:", err)
  39. return
  40. }
  41. wg := &sync.WaitGroup{}
  42. wg.Add(1)
  43. go func() {
  44. _, err = UnitTestEval(`
  45. log("test1")
  46. log("test2")
  47. log("test3")
  48. `, nil)
  49. if err != nil {
  50. t.Error(err)
  51. }
  52. wg.Done()
  53. }()
  54. tid := waitForThreadSuspension(t)
  55. out, err := testDebugger.HandleInput(fmt.Sprintf("status"))
  56. outBytes, _ := json.MarshalIndent(out, "", " ")
  57. outString := string(outBytes)
  58. if err != nil || outString != `{
  59. "breakonstart": false,
  60. "breakpoints": {
  61. "ECALEvalTest:3": true,
  62. "ECALEvalTest:4": false
  63. },
  64. "sources": [
  65. "ECALEvalTest"
  66. ],
  67. "threads": {
  68. "1": {
  69. "callStack": [],
  70. "threadRunning": false
  71. }
  72. }
  73. }` {
  74. t.Error("Unexpected result:", outString, err)
  75. return
  76. }
  77. out, err = testDebugger.HandleInput(fmt.Sprintf("describe %v", tid))
  78. outBytes, _ = json.MarshalIndent(out, "", " ")
  79. outString = string(outBytes)
  80. if err != nil || outString != `{
  81. "callStack": [],
  82. "code": "log(\"test2\")",
  83. "node": {
  84. "allowescapes": false,
  85. "children": [
  86. {
  87. "children": [
  88. {
  89. "allowescapes": true,
  90. "id": 5,
  91. "identifier": false,
  92. "line": 3,
  93. "linepos": 5,
  94. "name": "string",
  95. "pos": 18,
  96. "source": "ECALEvalTest",
  97. "value": "test2"
  98. }
  99. ],
  100. "name": "funccall"
  101. }
  102. ],
  103. "id": 7,
  104. "identifier": true,
  105. "line": 3,
  106. "linepos": 1,
  107. "name": "identifier",
  108. "pos": 14,
  109. "source": "ECALEvalTest",
  110. "value": "log"
  111. },
  112. "threadRunning": false,
  113. "vs": {}
  114. }` {
  115. t.Error("Unexpected result:", outString, err)
  116. return
  117. }
  118. // Continue until the end
  119. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v Resume", tid)); err != nil {
  120. t.Error("Unexpected result:", err)
  121. return
  122. }
  123. wg.Wait()
  124. if err != nil || testlogger.String() != `
  125. test1
  126. test2
  127. test3`[1:] {
  128. t.Error("Unexpected result:", testlogger.String(), err)
  129. return
  130. }
  131. if _, err = testDebugger.HandleInput("rmbreak ECALEvalTest:4"); err != nil {
  132. t.Error("Unexpected result:", err)
  133. return
  134. }
  135. out, err = testDebugger.HandleInput(fmt.Sprintf("status"))
  136. outBytes, _ = json.MarshalIndent(out, "", " ")
  137. outString = string(outBytes)
  138. if err != nil || outString != `{
  139. "breakonstart": false,
  140. "breakpoints": {
  141. "ECALEvalTest:3": true
  142. },
  143. "sources": [
  144. "ECALEvalTest"
  145. ],
  146. "threads": {
  147. "1": {
  148. "callStack": []
  149. }
  150. }
  151. }` {
  152. t.Error("Unexpected result:", outString, err)
  153. return
  154. }
  155. if _, err = testDebugger.HandleInput("break ECALEvalTest:4"); err != nil {
  156. t.Error("Unexpected result:", err)
  157. return
  158. }
  159. if _, err = testDebugger.HandleInput("rmbreak ECALEvalTest"); err != nil {
  160. t.Error("Unexpected result:", err)
  161. return
  162. }
  163. out, err = testDebugger.HandleInput(fmt.Sprintf("status"))
  164. outBytes, _ = json.MarshalIndent(out, "", " ")
  165. outString = string(outBytes)
  166. if err != nil || outString != `{
  167. "breakonstart": false,
  168. "breakpoints": {},
  169. "sources": [
  170. "ECALEvalTest"
  171. ],
  172. "threads": {
  173. "1": {
  174. "callStack": []
  175. }
  176. }
  177. }` {
  178. t.Error("Unexpected result:", outString, err)
  179. return
  180. }
  181. }
  182. func TestConcurrentDebugging(t *testing.T) {
  183. var err error
  184. defer func() {
  185. testDebugger = nil
  186. }()
  187. testDebugger = NewECALDebugger(nil)
  188. if _, err = testDebugger.HandleInput("break ECALEvalTest:5"); err != nil {
  189. t.Error("Unexpected result:", err)
  190. return
  191. }
  192. wg := &sync.WaitGroup{}
  193. wg.Add(2)
  194. erp := NewECALRuntimeProvider("ECALTestRuntime", nil, nil)
  195. vs := scope.NewScope(scope.GlobalScope)
  196. go func() {
  197. _, err = UnitTestEvalWithRuntimeProvider(`
  198. a := 1
  199. b := 1
  200. func test1() {
  201. log("test3")
  202. b := a + 1
  203. }
  204. log("test1")
  205. log("test2")
  206. test1()
  207. log("test4")
  208. `, vs, erp)
  209. if err != nil {
  210. t.Error(err)
  211. }
  212. wg.Done()
  213. }()
  214. go func() {
  215. _, err = UnitTestEvalWithRuntimeProvider(`
  216. a := 1
  217. c := 1
  218. func test2() {
  219. log("test3")
  220. c := a + 1
  221. }
  222. log("test1")
  223. log("test2")
  224. test2()
  225. log("test4")
  226. `, vs, erp)
  227. if err != nil {
  228. t.Error(err)
  229. }
  230. wg.Done()
  231. }()
  232. waitForAllThreadSuspension(t)
  233. out, err := testDebugger.HandleInput(fmt.Sprintf("status"))
  234. outBytes, _ := json.MarshalIndent(out, "", " ")
  235. outString := string(outBytes)
  236. if err != nil || (outString != `{
  237. "breakonstart": false,
  238. "breakpoints": {
  239. "ECALEvalTest:5": true
  240. },
  241. "sources": [
  242. "ECALEvalTest"
  243. ],
  244. "threads": {
  245. "1": {
  246. "callStack": [
  247. "test1() (ECALEvalTest:10)"
  248. ],
  249. "threadRunning": false
  250. },
  251. "2": {
  252. "callStack": [
  253. "test2() (ECALEvalTest:10)"
  254. ],
  255. "threadRunning": false
  256. }
  257. }
  258. }` && outString != `{
  259. "breakonstart": false,
  260. "breakpoints": {
  261. "ECALEvalTest:5": true
  262. },
  263. "sources": [
  264. "ECALEvalTest"
  265. ],
  266. "threads": {
  267. "1": {
  268. "callStack": [
  269. "test2() (ECALEvalTest:10)"
  270. ],
  271. "threadRunning": false
  272. },
  273. "2": {
  274. "callStack": [
  275. "test1() (ECALEvalTest:10)"
  276. ],
  277. "threadRunning": false
  278. }
  279. }
  280. }`) {
  281. t.Error("Unexpected result:", outString, err)
  282. return
  283. }
  284. // Continue until the end
  285. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont 1 Resume")); err != nil {
  286. t.Error("Unexpected result:", err)
  287. return
  288. }
  289. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont 2 Resume")); err != nil {
  290. t.Error("Unexpected result:", err)
  291. return
  292. }
  293. wg.Wait()
  294. if vs.String() != `GlobalScope {
  295. a (float64) : 1
  296. b (float64) : 2
  297. c (float64) : 2
  298. test1 (*interpreter.function) : ecal.function: test1 (Line 4, Pos 1)
  299. test2 (*interpreter.function) : ecal.function: test2 (Line 4, Pos 1)
  300. }` {
  301. t.Error("Unexpected result:", vs)
  302. return
  303. }
  304. }
  305. func waitForThreadSuspension(t *testing.T) uint64 {
  306. var tid uint64
  307. for i := 0; i < 100; i += 1 {
  308. state, err := testDebugger.HandleInput("status")
  309. errorutil.AssertOk(err)
  310. threads := state.(map[string]interface{})["threads"].(map[string]map[string]interface{})
  311. if len(threads) > 0 {
  312. for threadId, status := range threads {
  313. if r, ok := status["threadRunning"]; ok && !r.(bool) {
  314. threadIdNum, _ := strconv.ParseInt(threadId, 10, 0)
  315. tid = uint64(threadIdNum)
  316. return tid
  317. }
  318. }
  319. }
  320. time.Sleep(1 * time.Millisecond)
  321. }
  322. panic("No suspended thread")
  323. }
  324. func waitForAllThreadSuspension(t *testing.T) uint64 {
  325. var tid uint64
  326. for i := 0; i < 100; i += 1 {
  327. state, err := testDebugger.HandleInput("status")
  328. errorutil.AssertOk(err)
  329. threads := state.(map[string]interface{})["threads"].(map[string]map[string]interface{})
  330. if len(threads) > 0 {
  331. allSuspended := true
  332. for _, status := range threads {
  333. if r, ok := status["threadRunning"]; ok && !r.(bool) {
  334. allSuspended = false
  335. break
  336. }
  337. }
  338. if allSuspended {
  339. break
  340. }
  341. }
  342. time.Sleep(1 * time.Millisecond)
  343. }
  344. return tid
  345. }
  346. func TestStepDebugging(t *testing.T) {
  347. var err error
  348. defer func() {
  349. testDebugger = nil
  350. }()
  351. testDebugger = NewECALDebugger(nil)
  352. code := `
  353. log("start")
  354. func fa() {
  355. a := 1
  356. log("a enter")
  357. fb()
  358. log("a exit")
  359. }
  360. func fb() {
  361. b := 2
  362. log("b enter")
  363. fc()
  364. fc(fc())
  365. log("b exit")
  366. }
  367. func fc() {
  368. c := 3
  369. log("c enter")
  370. log("c exit")
  371. }
  372. fa()
  373. func e() {
  374. log("e()")
  375. }
  376. func d() {
  377. e()
  378. }
  379. d(d())
  380. log("finish")
  381. `
  382. if _, err = testDebugger.HandleInput("break ECALEvalTest:10"); err != nil {
  383. t.Error("Unexpected result:", err)
  384. return
  385. }
  386. if _, err = testDebugger.HandleInput("breakonstart true"); err != nil {
  387. t.Error("Unexpected result:", err)
  388. return
  389. }
  390. wg := &sync.WaitGroup{}
  391. wg.Add(1)
  392. go func() {
  393. _, err = UnitTestEval(code, nil)
  394. if err != nil {
  395. t.Error(err)
  396. }
  397. wg.Done()
  398. }()
  399. tid := waitForThreadSuspension(t)
  400. if state := getDebuggerState(tid, t); state != `{
  401. "breakpoints": {
  402. "ECALEvalTest:10": true
  403. },
  404. "code": "log(\"start\")",
  405. "threads": {
  406. "1": {
  407. "callStack": [],
  408. "threadRunning": false
  409. }
  410. },
  411. "vs": {}
  412. }` {
  413. t.Error("Unexpected state:", state)
  414. return
  415. }
  416. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v resume", tid)); err != nil {
  417. t.Error("Unexpected result:", err)
  418. return
  419. }
  420. tid = waitForThreadSuspension(t)
  421. if state := getDebuggerState(tid, t); state != `{
  422. "breakpoints": {
  423. "ECALEvalTest:10": true
  424. },
  425. "code": "b := 2",
  426. "threads": {
  427. "1": {
  428. "callStack": [
  429. "fa() (ECALEvalTest:21)",
  430. "fb() (ECALEvalTest:6)"
  431. ],
  432. "threadRunning": false
  433. }
  434. },
  435. "vs": {}
  436. }` {
  437. t.Error("Unexpected state:", state)
  438. return
  439. }
  440. // Step in without a function
  441. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v stepin", tid)); err != nil {
  442. t.Error("Unexpected result:", err)
  443. return
  444. }
  445. tid = waitForThreadSuspension(t)
  446. if state := getDebuggerState(tid, t); state != `{
  447. "breakpoints": {
  448. "ECALEvalTest:10": true
  449. },
  450. "code": "log(\"b enter\")",
  451. "threads": {
  452. "1": {
  453. "callStack": [
  454. "fa() (ECALEvalTest:21)",
  455. "fb() (ECALEvalTest:6)"
  456. ],
  457. "threadRunning": false
  458. }
  459. },
  460. "vs": {
  461. "b": 2
  462. }
  463. }` {
  464. t.Error("Unexpected state:", state)
  465. return
  466. }
  467. // Normal step over
  468. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v stepover", tid)); err != nil {
  469. t.Error("Unexpected result:", err)
  470. return
  471. }
  472. tid = waitForThreadSuspension(t)
  473. if state := getDebuggerState(tid, t); state != `{
  474. "breakpoints": {
  475. "ECALEvalTest:10": true
  476. },
  477. "code": "fc()",
  478. "threads": {
  479. "1": {
  480. "callStack": [
  481. "fa() (ECALEvalTest:21)",
  482. "fb() (ECALEvalTest:6)"
  483. ],
  484. "threadRunning": false
  485. }
  486. },
  487. "vs": {
  488. "b": 2
  489. }
  490. }` {
  491. t.Error("Unexpected state:", state)
  492. return
  493. }
  494. // Normal step in
  495. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v stepin", tid)); err != nil {
  496. t.Error("Unexpected result:", err)
  497. return
  498. }
  499. tid = waitForThreadSuspension(t)
  500. if state := getDebuggerState(tid, t); state != `{
  501. "breakpoints": {
  502. "ECALEvalTest:10": true
  503. },
  504. "code": "c := 3",
  505. "threads": {
  506. "1": {
  507. "callStack": [
  508. "fa() (ECALEvalTest:21)",
  509. "fb() (ECALEvalTest:6)",
  510. "fc() (ECALEvalTest:12)"
  511. ],
  512. "threadRunning": false
  513. }
  514. },
  515. "vs": {}
  516. }` {
  517. t.Error("Unexpected state:", state)
  518. return
  519. }
  520. // Normal step out
  521. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v stepout", tid)); err != nil {
  522. t.Error("Unexpected result:", err)
  523. return
  524. }
  525. tid = waitForThreadSuspension(t)
  526. if state := getDebuggerState(tid, t); state != `{
  527. "breakpoints": {
  528. "ECALEvalTest:10": true
  529. },
  530. "code": "fc(fc())",
  531. "threads": {
  532. "1": {
  533. "callStack": [
  534. "fa() (ECALEvalTest:21)",
  535. "fb() (ECALEvalTest:6)"
  536. ],
  537. "threadRunning": false
  538. }
  539. },
  540. "vs": {
  541. "b": 2
  542. }
  543. }` {
  544. t.Error("Unexpected state:", state)
  545. return
  546. }
  547. // Step in and step out - we should end up on the same line as before
  548. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v stepin", tid)); err != nil {
  549. t.Error("Unexpected result:", err)
  550. return
  551. }
  552. tid = waitForThreadSuspension(t)
  553. if state := getDebuggerState(tid, t); state != `{
  554. "breakpoints": {
  555. "ECALEvalTest:10": true
  556. },
  557. "code": "c := 3",
  558. "threads": {
  559. "1": {
  560. "callStack": [
  561. "fa() (ECALEvalTest:21)",
  562. "fb() (ECALEvalTest:6)",
  563. "fc() (ECALEvalTest:13)"
  564. ],
  565. "threadRunning": false
  566. }
  567. },
  568. "vs": {}
  569. }` {
  570. t.Error("Unexpected state:", state)
  571. return
  572. }
  573. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v stepout", tid)); err != nil {
  574. t.Error("Unexpected result:", err)
  575. return
  576. }
  577. tid = waitForThreadSuspension(t)
  578. if state := getDebuggerState(tid, t); state != `{
  579. "breakpoints": {
  580. "ECALEvalTest:10": true
  581. },
  582. "code": "fc(fc())",
  583. "threads": {
  584. "1": {
  585. "callStack": [
  586. "fa() (ECALEvalTest:21)",
  587. "fb() (ECALEvalTest:6)"
  588. ],
  589. "threadRunning": false
  590. }
  591. },
  592. "vs": {
  593. "b": 2
  594. }
  595. }` {
  596. t.Error("Unexpected state:", state)
  597. return
  598. }
  599. // Normal step out
  600. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v stepout", tid)); err != nil {
  601. t.Error("Unexpected result:", err)
  602. return
  603. }
  604. tid = waitForThreadSuspension(t)
  605. if state := getDebuggerState(tid, t); state != `{
  606. "breakpoints": {
  607. "ECALEvalTest:10": true
  608. },
  609. "code": "log(\"a exit\")",
  610. "threads": {
  611. "1": {
  612. "callStack": [
  613. "fa() (ECALEvalTest:21)"
  614. ],
  615. "threadRunning": false
  616. }
  617. },
  618. "vs": {
  619. "a": 1
  620. }
  621. }` {
  622. t.Error("Unexpected state:", state)
  623. return
  624. }
  625. // Set a new breakpoint
  626. if _, err = testDebugger.HandleInput("break ECALEvalTest:28"); err != nil {
  627. t.Error("Unexpected result:", err)
  628. return
  629. }
  630. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v Resume", tid)); err != nil {
  631. t.Error("Unexpected result:", err)
  632. return
  633. }
  634. tid = waitForThreadSuspension(t)
  635. if state := getDebuggerState(tid, t); state != `{
  636. "breakpoints": {
  637. "ECALEvalTest:10": true,
  638. "ECALEvalTest:28": true
  639. },
  640. "code": "d(d())",
  641. "threads": {
  642. "1": {
  643. "callStack": [],
  644. "threadRunning": false
  645. }
  646. },
  647. "vs": {
  648. "d": "ecal.function: d (Line 25, Pos 1)",
  649. "e": "ecal.function: e (Line 22, Pos 1)",
  650. "fa": "ecal.function: fa (Line 3, Pos 1)",
  651. "fb": "ecal.function: fb (Line 9, Pos 1)",
  652. "fc": "ecal.function: fc (Line 16, Pos 1)"
  653. }
  654. }` {
  655. t.Error("Unexpected state:", state)
  656. return
  657. }
  658. // Normal step over
  659. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v stepover", tid)); err != nil {
  660. t.Error("Unexpected result:", err)
  661. return
  662. }
  663. tid = waitForThreadSuspension(t)
  664. if state := getDebuggerState(tid, t); state != `{
  665. "breakpoints": {
  666. "ECALEvalTest:10": true,
  667. "ECALEvalTest:28": true
  668. },
  669. "code": "d(d())",
  670. "threads": {
  671. "1": {
  672. "callStack": [],
  673. "threadRunning": false
  674. }
  675. },
  676. "vs": {
  677. "d": "ecal.function: d (Line 25, Pos 1)",
  678. "e": "ecal.function: e (Line 22, Pos 1)",
  679. "fa": "ecal.function: fa (Line 3, Pos 1)",
  680. "fb": "ecal.function: fb (Line 9, Pos 1)",
  681. "fc": "ecal.function: fc (Line 16, Pos 1)"
  682. }
  683. }` {
  684. t.Error("Unexpected state:", state)
  685. return
  686. }
  687. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v stepover", tid)); err != nil {
  688. t.Error("Unexpected result:", err)
  689. return
  690. }
  691. tid = waitForThreadSuspension(t)
  692. if state := getDebuggerState(tid, t); state != `{
  693. "breakpoints": {
  694. "ECALEvalTest:10": true,
  695. "ECALEvalTest:28": true
  696. },
  697. "code": "log(\"finish\")",
  698. "threads": {
  699. "1": {
  700. "callStack": [],
  701. "threadRunning": false
  702. }
  703. },
  704. "vs": {
  705. "d": "ecal.function: d (Line 25, Pos 1)",
  706. "e": "ecal.function: e (Line 22, Pos 1)",
  707. "fa": "ecal.function: fa (Line 3, Pos 1)",
  708. "fb": "ecal.function: fb (Line 9, Pos 1)",
  709. "fc": "ecal.function: fc (Line 16, Pos 1)"
  710. }
  711. }` {
  712. t.Error("Unexpected state:", state)
  713. return
  714. }
  715. // Continue until the end
  716. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v Resume", tid)); err != nil {
  717. t.Error("Unexpected result:", err)
  718. return
  719. }
  720. wg.Wait()
  721. if err != nil || testlogger.String() != `
  722. start
  723. a enter
  724. b enter
  725. c enter
  726. c exit
  727. c enter
  728. c exit
  729. c enter
  730. c exit
  731. b exit
  732. a exit
  733. e()
  734. e()
  735. finish`[1:] {
  736. t.Error("Unexpected result:", testlogger.String(), err)
  737. return
  738. }
  739. }
  740. func getDebuggerState(tid uint64, t *testing.T) string {
  741. out, err := testDebugger.HandleInput(fmt.Sprintf("status"))
  742. if err != nil {
  743. t.Error(err)
  744. return ""
  745. }
  746. outMap := out.(map[string]interface{})
  747. out, err = testDebugger.HandleInput(fmt.Sprintf("describe %v", tid))
  748. if err != nil {
  749. t.Error(err)
  750. return ""
  751. }
  752. outMap2 := out.(map[string]interface{})
  753. outMap["vs"] = outMap2["vs"]
  754. outMap["code"] = outMap2["code"]
  755. delete(outMap, "breakonstart")
  756. delete(outMap, "sources")
  757. outBytes, _ := json.MarshalIndent(outMap, "", " ")
  758. return string(outBytes)
  759. }
  760. func TestInjectAndExtractDebugging(t *testing.T) {
  761. var err error
  762. defer func() {
  763. testDebugger = nil
  764. }()
  765. vs := scope.NewScope(scope.GlobalScope)
  766. testDebugger = NewECALDebugger(vs)
  767. if _, err = testDebugger.HandleInput("break ECALEvalTest:5"); err != nil {
  768. t.Error("Unexpected result:", err)
  769. return
  770. }
  771. wg := &sync.WaitGroup{}
  772. wg.Add(1)
  773. go func() {
  774. _, err = UnitTestEval(`
  775. b := 49
  776. func myfunc() {
  777. a := 56
  778. log("test2 a=", a)
  779. }
  780. log("test1")
  781. myfunc()
  782. log("test3 b=", b)
  783. `, vs)
  784. if err != nil {
  785. t.Error(err)
  786. }
  787. wg.Done()
  788. }()
  789. tid := waitForThreadSuspension(t)
  790. out, err := testDebugger.HandleInput(fmt.Sprintf("status"))
  791. outBytes, _ := json.MarshalIndent(out, "", " ")
  792. outString := string(outBytes)
  793. if err != nil || outString != `{
  794. "breakonstart": false,
  795. "breakpoints": {
  796. "ECALEvalTest:5": true
  797. },
  798. "sources": [
  799. "ECALEvalTest"
  800. ],
  801. "threads": {
  802. "1": {
  803. "callStack": [
  804. "myfunc() (ECALEvalTest:8)"
  805. ],
  806. "threadRunning": false
  807. }
  808. }
  809. }` {
  810. t.Error("Unexpected result:", outString, err)
  811. return
  812. }
  813. out, err = testDebugger.HandleInput(fmt.Sprintf("describe %v", tid))
  814. outBytes, _ = json.MarshalIndent(out, "", " ")
  815. outString = string(outBytes)
  816. if err != nil || outString != `{
  817. "callStack": [
  818. "myfunc() (ECALEvalTest:8)"
  819. ],
  820. "code": "log(\"test2 a=\", a)",
  821. "node": {
  822. "allowescapes": false,
  823. "children": [
  824. {
  825. "children": [
  826. {
  827. "allowescapes": true,
  828. "id": 5,
  829. "identifier": false,
  830. "line": 5,
  831. "linepos": 6,
  832. "name": "string",
  833. "pos": 39,
  834. "source": "ECALEvalTest",
  835. "value": "test2 a="
  836. },
  837. {
  838. "allowescapes": false,
  839. "id": 7,
  840. "identifier": true,
  841. "line": 5,
  842. "linepos": 18,
  843. "name": "identifier",
  844. "pos": 51,
  845. "source": "ECALEvalTest",
  846. "value": "a"
  847. }
  848. ],
  849. "name": "funccall"
  850. }
  851. ],
  852. "id": 7,
  853. "identifier": true,
  854. "line": 5,
  855. "linepos": 2,
  856. "name": "identifier",
  857. "pos": 35,
  858. "source": "ECALEvalTest",
  859. "value": "log"
  860. },
  861. "threadRunning": false,
  862. "vs": {
  863. "a": 56
  864. }
  865. }` {
  866. t.Error("Unexpected result:", outString, err)
  867. return
  868. }
  869. if _, err := testDebugger.HandleInput(fmt.Sprintf("extract %v a foo", tid)); err != nil {
  870. t.Error("Unexpected result:", err)
  871. return
  872. }
  873. if _, err := testDebugger.HandleInput(fmt.Sprintf("inject %v a x := b + 1; x", tid)); err != nil {
  874. t.Error("Unexpected result:", err)
  875. return
  876. }
  877. // Continue until the end
  878. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v Resume", tid)); err != nil {
  879. t.Error("Unexpected result:", err)
  880. return
  881. }
  882. wg.Wait()
  883. if vs.String() != `
  884. GlobalScope {
  885. b (float64) : 49
  886. foo (float64) : 56
  887. myfunc (*interpreter.function) : ecal.function: myfunc (Line 3, Pos 1)
  888. }`[1:] {
  889. t.Error("Unexpected result:", vs.String(), err)
  890. return
  891. }
  892. if testlogger.String() != `
  893. test1
  894. test2 a=50
  895. test3 b=49`[1:] {
  896. t.Error("Unexpected result:", testlogger.String(), err)
  897. return
  898. }
  899. }
  900. func TestSimpleStacktrace(t *testing.T) {
  901. res, err := UnitTestEval(`
  902. func a() {
  903. b()
  904. }
  905. func b() {
  906. c()
  907. }
  908. func c() {
  909. raise("testerror")
  910. }
  911. a()
  912. `, nil)
  913. if err == nil {
  914. t.Error("Unexpected result: ", res, err)
  915. return
  916. }
  917. ss := err.(util.TraceableRuntimeError)
  918. if out := fmt.Sprintf("%v\n %v", err.Error(), strings.Join(ss.GetTraceString(), "\n ")); out != `
  919. ECAL error in ECALTestRuntime: testerror () (Line:9 Pos:2)
  920. raise("testerror") (ECALEvalTest:9)
  921. c() (ECALEvalTest:6)
  922. b() (ECALEvalTest:3)
  923. a() (ECALEvalTest:11)`[1:] {
  924. t.Error("Unexpected output:", out)
  925. return
  926. }
  927. }
  928. func TestDebugDocstrings(t *testing.T) {
  929. for k, v := range DebugCommandsMap {
  930. if res := v.DocString(); res == "" {
  931. t.Error("Docstring missing for ", k)
  932. return
  933. }
  934. }
  935. }
  936. func TestDebuggingErrorInput(t *testing.T) {
  937. var err error
  938. defer func() {
  939. testDebugger = nil
  940. }()
  941. vs := scope.NewScope(scope.GlobalScope)
  942. testDebugger = NewECALDebugger(vs)
  943. if _, err = testDebugger.HandleInput("uuu"); err == nil ||
  944. err.Error() != `Unknown command: uuu` {
  945. t.Error("Unexpected result:", err)
  946. return
  947. }
  948. if _, err = testDebugger.HandleInput("break"); err == nil ||
  949. err.Error() != `Need a break target (<source>:<line>) as first parameter` {
  950. t.Error("Unexpected result:", err)
  951. return
  952. }
  953. if _, err = testDebugger.HandleInput("break foo"); err == nil ||
  954. err.Error() != `Invalid break target - should be <source>:<line>` {
  955. t.Error("Unexpected result:", err)
  956. return
  957. }
  958. if _, err = testDebugger.HandleInput("rmbreak"); err == nil ||
  959. err.Error() != `Need a break target (<source>[:<line>]) as first parameter` {
  960. t.Error("Unexpected result:", err)
  961. return
  962. }
  963. if _, err = testDebugger.HandleInput("disablebreak"); err == nil ||
  964. err.Error() != `Need a break target (<source>:<line>) as first parameter` {
  965. t.Error("Unexpected result:", err)
  966. return
  967. }
  968. if _, err = testDebugger.HandleInput("disablebreak foo"); err == nil ||
  969. err.Error() != `Invalid break target - should be <source>:<line>` {
  970. t.Error("Unexpected result:", err)
  971. return
  972. }
  973. if _, err = testDebugger.HandleInput("break ECALEvalTest:3"); err != nil {
  974. t.Error("Unexpected result:", err)
  975. return
  976. }
  977. wg := &sync.WaitGroup{}
  978. wg.Add(1)
  979. go func() {
  980. _, err = UnitTestEval(`
  981. a:=1
  982. log("test1")
  983. log("test2")
  984. log("test3")
  985. `, vs)
  986. if err != nil {
  987. t.Error(err)
  988. }
  989. wg.Done()
  990. }()
  991. tid := waitForThreadSuspension(t)
  992. out, err := testDebugger.HandleInput(fmt.Sprintf("status"))
  993. outBytes, _ := json.MarshalIndent(out, "", " ")
  994. outString := string(outBytes)
  995. if err != nil || outString != `{
  996. "breakonstart": false,
  997. "breakpoints": {
  998. "ECALEvalTest:3": true
  999. },
  1000. "sources": [
  1001. "ECALEvalTest"
  1002. ],
  1003. "threads": {
  1004. "1": {
  1005. "callStack": [],
  1006. "threadRunning": false
  1007. }
  1008. }
  1009. }` {
  1010. t.Error("Unexpected result:", outString, err)
  1011. return
  1012. }
  1013. if _, err = testDebugger.HandleInput("cont foo"); err == nil ||
  1014. err.Error() != `Need a thread ID and a command Resume, StepIn, StepOver or StepOut` {
  1015. t.Error("Unexpected result:", err)
  1016. return
  1017. }
  1018. if _, err = testDebugger.HandleInput("cont foo bar"); err == nil ||
  1019. err.Error() != `Parameter 1 should be a number` {
  1020. t.Error("Unexpected result:", err)
  1021. return
  1022. }
  1023. if _, err = testDebugger.HandleInput("cont 99 bar"); err == nil ||
  1024. err.Error() != `Invalid command bar - must be resume, stepin, stepover or stepout` {
  1025. t.Error("Unexpected result:", err)
  1026. return
  1027. }
  1028. if _, err = testDebugger.HandleInput("describe"); err == nil ||
  1029. err.Error() != `Need a thread ID` {
  1030. t.Error("Unexpected result:", err)
  1031. return
  1032. }
  1033. if _, err = testDebugger.HandleInput(fmt.Sprintf("extract %v foo", tid)); err == nil ||
  1034. err.Error() != `Need a thread ID, a variable name and a destination variable name` {
  1035. t.Error("Unexpected result:", err)
  1036. return
  1037. }
  1038. if _, err = testDebugger.HandleInput(fmt.Sprintf("extract %v _foo foo", tid)); err == nil ||
  1039. err.Error() != `Variable names may only contain [a-zA-Z] and [a-zA-Z0-9] from the second character` {
  1040. t.Error("Unexpected result:", err)
  1041. return
  1042. }
  1043. if _, err = testDebugger.HandleInput(fmt.Sprintf("extract %v foo foo", tid)); err == nil ||
  1044. err.Error() != `No such value foo` {
  1045. t.Error("Unexpected result:", err)
  1046. return
  1047. }
  1048. if _, err = testDebugger.HandleInput(fmt.Sprintf("inject %v", tid)); err == nil ||
  1049. err.Error() != `Need a thread ID, a variable name and an expression` {
  1050. t.Error("Unexpected result:", err)
  1051. return
  1052. }
  1053. testDebugger.(*ecalDebugger).globalScope = nil
  1054. if _, err = testDebugger.HandleInput(fmt.Sprintf("extract %v foo foo", tid)); err == nil ||
  1055. err.Error() != `Cannot access global scope` {
  1056. t.Error("Unexpected result:", err)
  1057. return
  1058. }
  1059. if _, err = testDebugger.HandleInput(fmt.Sprintf("inject %v foo foo", tid)); err == nil ||
  1060. err.Error() != `Cannot access global scope` {
  1061. t.Error("Unexpected result:", err)
  1062. return
  1063. }
  1064. }