debug_test.go 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360
  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(x) {
  355. a := 1
  356. log("a enter")
  357. fb(x)
  358. log("a exit")
  359. }
  360. func fb(x) {
  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(1)
  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(1) (ECALEvalTest:21)",
  430. "fb(x) (ECALEvalTest:6)"
  431. ],
  432. "threadRunning": false
  433. }
  434. },
  435. "vs": {
  436. "x": 1
  437. }
  438. }` {
  439. t.Error("Unexpected state:", state)
  440. return
  441. }
  442. // Step in without a function
  443. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v stepin", tid)); err != nil {
  444. t.Error("Unexpected result:", err)
  445. return
  446. }
  447. tid = waitForThreadSuspension(t)
  448. if state := getDebuggerState(tid, t); state != `{
  449. "breakpoints": {
  450. "ECALEvalTest:10": true
  451. },
  452. "code": "log(\"b enter\")",
  453. "threads": {
  454. "1": {
  455. "callStack": [
  456. "fa(1) (ECALEvalTest:21)",
  457. "fb(x) (ECALEvalTest:6)"
  458. ],
  459. "threadRunning": false
  460. }
  461. },
  462. "vs": {
  463. "b": 2,
  464. "x": 1
  465. }
  466. }` {
  467. t.Error("Unexpected state:", state)
  468. return
  469. }
  470. // Normal step over
  471. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v stepover", tid)); err != nil {
  472. t.Error("Unexpected result:", err)
  473. return
  474. }
  475. tid = waitForThreadSuspension(t)
  476. if state := getDebuggerState(tid, t); state != `{
  477. "breakpoints": {
  478. "ECALEvalTest:10": true
  479. },
  480. "code": "fc()",
  481. "threads": {
  482. "1": {
  483. "callStack": [
  484. "fa(1) (ECALEvalTest:21)",
  485. "fb(x) (ECALEvalTest:6)"
  486. ],
  487. "threadRunning": false
  488. }
  489. },
  490. "vs": {
  491. "b": 2,
  492. "x": 1
  493. }
  494. }` {
  495. t.Error("Unexpected state:", state)
  496. return
  497. }
  498. // Normal step in
  499. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v stepin", tid)); err != nil {
  500. t.Error("Unexpected result:", err)
  501. return
  502. }
  503. tid = waitForThreadSuspension(t)
  504. if state := getDebuggerState(tid, t); state != `{
  505. "breakpoints": {
  506. "ECALEvalTest:10": true
  507. },
  508. "code": "c := 3",
  509. "threads": {
  510. "1": {
  511. "callStack": [
  512. "fa(1) (ECALEvalTest:21)",
  513. "fb(x) (ECALEvalTest:6)",
  514. "fc() (ECALEvalTest:12)"
  515. ],
  516. "threadRunning": false
  517. }
  518. },
  519. "vs": {}
  520. }` {
  521. t.Error("Unexpected state:", state)
  522. return
  523. }
  524. // Normal step out
  525. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v stepout", tid)); err != nil {
  526. t.Error("Unexpected result:", err)
  527. return
  528. }
  529. tid = waitForThreadSuspension(t)
  530. if state := getDebuggerState(tid, t); state != `{
  531. "breakpoints": {
  532. "ECALEvalTest:10": true
  533. },
  534. "code": "fc(fc())",
  535. "threads": {
  536. "1": {
  537. "callStack": [
  538. "fa(1) (ECALEvalTest:21)",
  539. "fb(x) (ECALEvalTest:6)"
  540. ],
  541. "threadRunning": false
  542. }
  543. },
  544. "vs": {
  545. "b": 2,
  546. "x": 1
  547. }
  548. }` {
  549. t.Error("Unexpected state:", state)
  550. return
  551. }
  552. // Step in and step out - we should end up on the same line as before
  553. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v stepin", tid)); err != nil {
  554. t.Error("Unexpected result:", err)
  555. return
  556. }
  557. tid = waitForThreadSuspension(t)
  558. if state := getDebuggerState(tid, t); state != `{
  559. "breakpoints": {
  560. "ECALEvalTest:10": true
  561. },
  562. "code": "c := 3",
  563. "threads": {
  564. "1": {
  565. "callStack": [
  566. "fa(1) (ECALEvalTest:21)",
  567. "fb(x) (ECALEvalTest:6)",
  568. "fc() (ECALEvalTest:13)"
  569. ],
  570. "threadRunning": false
  571. }
  572. },
  573. "vs": {}
  574. }` {
  575. t.Error("Unexpected state:", state)
  576. return
  577. }
  578. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v stepout", tid)); err != nil {
  579. t.Error("Unexpected result:", err)
  580. return
  581. }
  582. tid = waitForThreadSuspension(t)
  583. if state := getDebuggerState(tid, t); state != `{
  584. "breakpoints": {
  585. "ECALEvalTest:10": true
  586. },
  587. "code": "fc(fc())",
  588. "threads": {
  589. "1": {
  590. "callStack": [
  591. "fa(1) (ECALEvalTest:21)",
  592. "fb(x) (ECALEvalTest:6)"
  593. ],
  594. "threadRunning": false
  595. }
  596. },
  597. "vs": {
  598. "b": 2,
  599. "x": 1
  600. }
  601. }` {
  602. t.Error("Unexpected state:", state)
  603. return
  604. }
  605. // Normal step out
  606. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v stepout", tid)); err != nil {
  607. t.Error("Unexpected result:", err)
  608. return
  609. }
  610. tid = waitForThreadSuspension(t)
  611. if state := getDebuggerState(tid, t); state != `{
  612. "breakpoints": {
  613. "ECALEvalTest:10": true
  614. },
  615. "code": "log(\"a exit\")",
  616. "threads": {
  617. "1": {
  618. "callStack": [
  619. "fa(1) (ECALEvalTest:21)"
  620. ],
  621. "threadRunning": false
  622. }
  623. },
  624. "vs": {
  625. "a": 1,
  626. "x": 1
  627. }
  628. }` {
  629. t.Error("Unexpected state:", state)
  630. return
  631. }
  632. // Set a new breakpoint
  633. if _, err = testDebugger.HandleInput("break ECALEvalTest:28"); err != nil {
  634. t.Error("Unexpected result:", err)
  635. return
  636. }
  637. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v Resume", tid)); err != nil {
  638. t.Error("Unexpected result:", err)
  639. return
  640. }
  641. tid = waitForThreadSuspension(t)
  642. if state := getDebuggerState(tid, t); state != `{
  643. "breakpoints": {
  644. "ECALEvalTest:10": true,
  645. "ECALEvalTest:28": true
  646. },
  647. "code": "d(d())",
  648. "threads": {
  649. "1": {
  650. "callStack": [],
  651. "threadRunning": false
  652. }
  653. },
  654. "vs": {
  655. "d": "ecal.function: d (Line 25, Pos 1)",
  656. "e": "ecal.function: e (Line 22, Pos 1)",
  657. "fa": "ecal.function: fa (Line 3, Pos 1)",
  658. "fb": "ecal.function: fb (Line 9, Pos 1)",
  659. "fc": "ecal.function: fc (Line 16, Pos 1)"
  660. }
  661. }` {
  662. t.Error("Unexpected state:", state)
  663. return
  664. }
  665. // Normal step over
  666. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v stepover", tid)); err != nil {
  667. t.Error("Unexpected result:", err)
  668. return
  669. }
  670. tid = waitForThreadSuspension(t)
  671. if state := getDebuggerState(tid, t); state != `{
  672. "breakpoints": {
  673. "ECALEvalTest:10": true,
  674. "ECALEvalTest:28": true
  675. },
  676. "code": "d(d())",
  677. "threads": {
  678. "1": {
  679. "callStack": [],
  680. "threadRunning": false
  681. }
  682. },
  683. "vs": {
  684. "d": "ecal.function: d (Line 25, Pos 1)",
  685. "e": "ecal.function: e (Line 22, Pos 1)",
  686. "fa": "ecal.function: fa (Line 3, Pos 1)",
  687. "fb": "ecal.function: fb (Line 9, Pos 1)",
  688. "fc": "ecal.function: fc (Line 16, Pos 1)"
  689. }
  690. }` {
  691. t.Error("Unexpected state:", state)
  692. return
  693. }
  694. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v stepover", tid)); err != nil {
  695. t.Error("Unexpected result:", err)
  696. return
  697. }
  698. tid = waitForThreadSuspension(t)
  699. if state := getDebuggerState(tid, t); state != `{
  700. "breakpoints": {
  701. "ECALEvalTest:10": true,
  702. "ECALEvalTest:28": true
  703. },
  704. "code": "log(\"finish\")",
  705. "threads": {
  706. "1": {
  707. "callStack": [],
  708. "threadRunning": false
  709. }
  710. },
  711. "vs": {
  712. "d": "ecal.function: d (Line 25, Pos 1)",
  713. "e": "ecal.function: e (Line 22, Pos 1)",
  714. "fa": "ecal.function: fa (Line 3, Pos 1)",
  715. "fb": "ecal.function: fb (Line 9, Pos 1)",
  716. "fc": "ecal.function: fc (Line 16, Pos 1)"
  717. }
  718. }` {
  719. t.Error("Unexpected state:", state)
  720. return
  721. }
  722. // Continue until the end
  723. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v Resume", tid)); err != nil {
  724. t.Error("Unexpected result:", err)
  725. return
  726. }
  727. wg.Wait()
  728. if err != nil || testlogger.String() != `
  729. start
  730. a enter
  731. b enter
  732. c enter
  733. c exit
  734. c enter
  735. c exit
  736. c enter
  737. c exit
  738. b exit
  739. a exit
  740. e()
  741. e()
  742. finish`[1:] {
  743. t.Error("Unexpected result:", testlogger.String(), err)
  744. return
  745. }
  746. }
  747. func TestStepDebuggingWithImport(t *testing.T) {
  748. var err error
  749. defer func() {
  750. testDebugger = nil
  751. }()
  752. testDebugger = NewECALDebugger(nil)
  753. il := &util.MemoryImportLocator{Files: make(map[string]string)}
  754. il.Files["foo/bar"] = `
  755. func myfunc(n) {
  756. if (n <= 1) {
  757. return n
  758. }
  759. n := n + 1
  760. return n
  761. }
  762. `
  763. code := `
  764. a := 1
  765. import "foo/bar" as foobar
  766. log("start")
  767. a := foobar.myfunc(a)
  768. log("finish: ", a)
  769. `
  770. if _, err = testDebugger.HandleInput("break ECALEvalTest:4"); err != nil {
  771. t.Error("Unexpected result:", err)
  772. return
  773. }
  774. if _, err = testDebugger.HandleInput("break foo/bar:4"); err != nil {
  775. t.Error("Unexpected result:", err)
  776. return
  777. }
  778. wg := &sync.WaitGroup{}
  779. wg.Add(1)
  780. go func() {
  781. _, err = UnitTestEvalAndASTAndImport(code, nil, "", il)
  782. if err != nil {
  783. t.Error(err)
  784. }
  785. wg.Done()
  786. }()
  787. tid := waitForThreadSuspension(t)
  788. if state := getDebuggerState(tid, t); state != `{
  789. "breakpoints": {
  790. "ECALEvalTest:4": true,
  791. "foo/bar:4": true
  792. },
  793. "code": "log(\"start\")",
  794. "threads": {
  795. "1": {
  796. "callStack": [],
  797. "threadRunning": false
  798. }
  799. },
  800. "vs": {
  801. "a": 1,
  802. "foobar": {
  803. "myfunc": "ecal.function: myfunc (Line 2, Pos 1)"
  804. }
  805. }
  806. }` {
  807. t.Error("Unexpected state:", state)
  808. return
  809. }
  810. // Resume execution
  811. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v resume", tid)); err != nil {
  812. t.Error("Unexpected result:", err)
  813. return
  814. }
  815. tid = waitForThreadSuspension(t)
  816. if state := getDebuggerState(tid, t); state != `{
  817. "breakpoints": {
  818. "ECALEvalTest:4": true,
  819. "foo/bar:4": true
  820. },
  821. "code": "return n",
  822. "threads": {
  823. "1": {
  824. "callStack": [
  825. "myfunc(a) (ECALEvalTest:5)"
  826. ],
  827. "threadRunning": false
  828. }
  829. },
  830. "vs": {
  831. "n": 1
  832. }
  833. }` {
  834. t.Error("Unexpected state:", state)
  835. return
  836. }
  837. // Continue until the end
  838. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v Resume", tid)); err != nil {
  839. t.Error("Unexpected result:", err)
  840. return
  841. }
  842. wg.Wait()
  843. if err != nil || testlogger.String() != `
  844. start
  845. finish: 1`[1:] {
  846. t.Error("Unexpected result:", testlogger.String(), err)
  847. return
  848. }
  849. }
  850. func getDebuggerState(tid uint64, t *testing.T) string {
  851. out, err := testDebugger.HandleInput(fmt.Sprintf("status"))
  852. if err != nil {
  853. t.Error(err)
  854. return ""
  855. }
  856. outMap := out.(map[string]interface{})
  857. out, err = testDebugger.HandleInput(fmt.Sprintf("describe %v", tid))
  858. if err != nil {
  859. t.Error(err)
  860. return ""
  861. }
  862. outMap2 := out.(map[string]interface{})
  863. outMap["vs"] = outMap2["vs"]
  864. outMap["code"] = outMap2["code"]
  865. delete(outMap, "breakonstart")
  866. delete(outMap, "sources")
  867. outBytes, _ := json.MarshalIndent(outMap, "", " ")
  868. return string(outBytes)
  869. }
  870. func TestInjectAndExtractDebugging(t *testing.T) {
  871. var err error
  872. defer func() {
  873. testDebugger = nil
  874. }()
  875. vs := scope.NewScope(scope.GlobalScope)
  876. testDebugger = NewECALDebugger(vs)
  877. if _, err = testDebugger.HandleInput("break ECALEvalTest:5"); err != nil {
  878. t.Error("Unexpected result:", err)
  879. return
  880. }
  881. wg := &sync.WaitGroup{}
  882. wg.Add(1)
  883. go func() {
  884. _, err = UnitTestEval(`
  885. b := 49
  886. func myfunc() {
  887. a := 56
  888. log("test2 a=", a)
  889. }
  890. log("test1")
  891. myfunc()
  892. log("test3 b=", b)
  893. `, vs)
  894. if err != nil {
  895. t.Error(err)
  896. }
  897. wg.Done()
  898. }()
  899. tid := waitForThreadSuspension(t)
  900. out, err := testDebugger.HandleInput(fmt.Sprintf("status"))
  901. outBytes, _ := json.MarshalIndent(out, "", " ")
  902. outString := string(outBytes)
  903. if err != nil || outString != `{
  904. "breakonstart": false,
  905. "breakpoints": {
  906. "ECALEvalTest:5": true
  907. },
  908. "sources": [
  909. "ECALEvalTest"
  910. ],
  911. "threads": {
  912. "1": {
  913. "callStack": [
  914. "myfunc() (ECALEvalTest:8)"
  915. ],
  916. "threadRunning": false
  917. }
  918. }
  919. }` {
  920. t.Error("Unexpected result:", outString, err)
  921. return
  922. }
  923. out, err = testDebugger.HandleInput(fmt.Sprintf("describe %v", tid))
  924. outBytes, _ = json.MarshalIndent(out, "", " ")
  925. outString = string(outBytes)
  926. if err != nil || outString != `{
  927. "callStack": [
  928. "myfunc() (ECALEvalTest:8)"
  929. ],
  930. "code": "log(\"test2 a=\", a)",
  931. "node": {
  932. "allowescapes": false,
  933. "children": [
  934. {
  935. "children": [
  936. {
  937. "allowescapes": true,
  938. "id": 5,
  939. "identifier": false,
  940. "line": 5,
  941. "linepos": 6,
  942. "name": "string",
  943. "pos": 39,
  944. "source": "ECALEvalTest",
  945. "value": "test2 a="
  946. },
  947. {
  948. "allowescapes": false,
  949. "id": 7,
  950. "identifier": true,
  951. "line": 5,
  952. "linepos": 18,
  953. "name": "identifier",
  954. "pos": 51,
  955. "source": "ECALEvalTest",
  956. "value": "a"
  957. }
  958. ],
  959. "name": "funccall"
  960. }
  961. ],
  962. "id": 7,
  963. "identifier": true,
  964. "line": 5,
  965. "linepos": 2,
  966. "name": "identifier",
  967. "pos": 35,
  968. "source": "ECALEvalTest",
  969. "value": "log"
  970. },
  971. "threadRunning": false,
  972. "vs": {
  973. "a": 56
  974. }
  975. }` {
  976. t.Error("Unexpected result:", outString, err)
  977. return
  978. }
  979. if _, err := testDebugger.HandleInput(fmt.Sprintf("extract %v a foo", tid)); err != nil {
  980. t.Error("Unexpected result:", err)
  981. return
  982. }
  983. if _, err := testDebugger.HandleInput(fmt.Sprintf("inject %v a x := b + 1; x", tid)); err != nil {
  984. t.Error("Unexpected result:", err)
  985. return
  986. }
  987. // Continue until the end
  988. if _, err := testDebugger.HandleInput(fmt.Sprintf("cont %v Resume", tid)); err != nil {
  989. t.Error("Unexpected result:", err)
  990. return
  991. }
  992. wg.Wait()
  993. if vs.String() != `
  994. GlobalScope {
  995. b (float64) : 49
  996. foo (float64) : 56
  997. myfunc (*interpreter.function) : ecal.function: myfunc (Line 3, Pos 1)
  998. }`[1:] {
  999. t.Error("Unexpected result:", vs.String(), err)
  1000. return
  1001. }
  1002. if testlogger.String() != `
  1003. test1
  1004. test2 a=50
  1005. test3 b=49`[1:] {
  1006. t.Error("Unexpected result:", testlogger.String(), err)
  1007. return
  1008. }
  1009. }
  1010. func TestSimpleStacktrace(t *testing.T) {
  1011. res, err := UnitTestEval(`
  1012. func a() {
  1013. b()
  1014. }
  1015. func b() {
  1016. c()
  1017. }
  1018. func c() {
  1019. raise("testerror")
  1020. }
  1021. a()
  1022. `, nil)
  1023. if err == nil {
  1024. t.Error("Unexpected result: ", res, err)
  1025. return
  1026. }
  1027. ss := err.(util.TraceableRuntimeError)
  1028. if out := fmt.Sprintf("%v\n %v", err.Error(), strings.Join(ss.GetTraceString(), "\n ")); out != `
  1029. ECAL error in ECALTestRuntime: testerror () (Line:9 Pos:2)
  1030. raise("testerror") (ECALEvalTest:9)
  1031. c() (ECALEvalTest:6)
  1032. b() (ECALEvalTest:3)
  1033. a() (ECALEvalTest:11)`[1:] {
  1034. t.Error("Unexpected output:", out)
  1035. return
  1036. }
  1037. }
  1038. func TestDebugDocstrings(t *testing.T) {
  1039. for k, v := range DebugCommandsMap {
  1040. if res := v.DocString(); res == "" {
  1041. t.Error("Docstring missing for ", k)
  1042. return
  1043. }
  1044. }
  1045. }
  1046. func TestDebuggingErrorInput(t *testing.T) {
  1047. var err error
  1048. defer func() {
  1049. testDebugger = nil
  1050. }()
  1051. vs := scope.NewScope(scope.GlobalScope)
  1052. testDebugger = NewECALDebugger(vs)
  1053. if _, err = testDebugger.HandleInput("uuu"); err == nil ||
  1054. err.Error() != `Unknown command: uuu` {
  1055. t.Error("Unexpected result:", err)
  1056. return
  1057. }
  1058. if _, err = testDebugger.HandleInput("break"); err == nil ||
  1059. err.Error() != `Need a break target (<source>:<line>) as first parameter` {
  1060. t.Error("Unexpected result:", err)
  1061. return
  1062. }
  1063. if _, err = testDebugger.HandleInput("break foo"); err == nil ||
  1064. err.Error() != `Invalid break target - should be <source>:<line>` {
  1065. t.Error("Unexpected result:", err)
  1066. return
  1067. }
  1068. if _, err = testDebugger.HandleInput("rmbreak"); err == nil ||
  1069. err.Error() != `Need a break target (<source>[:<line>]) as first parameter` {
  1070. t.Error("Unexpected result:", err)
  1071. return
  1072. }
  1073. if _, err = testDebugger.HandleInput("disablebreak"); err == nil ||
  1074. err.Error() != `Need a break target (<source>:<line>) as first parameter` {
  1075. t.Error("Unexpected result:", err)
  1076. return
  1077. }
  1078. if _, err = testDebugger.HandleInput("disablebreak foo"); err == nil ||
  1079. err.Error() != `Invalid break target - should be <source>:<line>` {
  1080. t.Error("Unexpected result:", err)
  1081. return
  1082. }
  1083. if _, err = testDebugger.HandleInput("break ECALEvalTest:3"); err != nil {
  1084. t.Error("Unexpected result:", err)
  1085. return
  1086. }
  1087. wg := &sync.WaitGroup{}
  1088. wg.Add(1)
  1089. go func() {
  1090. _, err = UnitTestEval(`
  1091. a:=1
  1092. log("test1")
  1093. log("test2")
  1094. log("test3")
  1095. `, vs)
  1096. if err != nil {
  1097. t.Error(err)
  1098. }
  1099. wg.Done()
  1100. }()
  1101. tid := waitForThreadSuspension(t)
  1102. out, err := testDebugger.HandleInput(fmt.Sprintf("status"))
  1103. outBytes, _ := json.MarshalIndent(out, "", " ")
  1104. outString := string(outBytes)
  1105. if err != nil || outString != `{
  1106. "breakonstart": false,
  1107. "breakpoints": {
  1108. "ECALEvalTest:3": true
  1109. },
  1110. "sources": [
  1111. "ECALEvalTest"
  1112. ],
  1113. "threads": {
  1114. "1": {
  1115. "callStack": [],
  1116. "threadRunning": false
  1117. }
  1118. }
  1119. }` {
  1120. t.Error("Unexpected result:", outString, err)
  1121. return
  1122. }
  1123. if _, err = testDebugger.HandleInput("cont foo"); err == nil ||
  1124. err.Error() != `Need a thread ID and a command Resume, StepIn, StepOver or StepOut` {
  1125. t.Error("Unexpected result:", err)
  1126. return
  1127. }
  1128. if _, err = testDebugger.HandleInput("cont foo bar"); err == nil ||
  1129. err.Error() != `Parameter 1 should be a number` {
  1130. t.Error("Unexpected result:", err)
  1131. return
  1132. }
  1133. if _, err = testDebugger.HandleInput("cont 99 bar"); err == nil ||
  1134. err.Error() != `Invalid command bar - must be resume, stepin, stepover or stepout` {
  1135. t.Error("Unexpected result:", err)
  1136. return
  1137. }
  1138. if _, err = testDebugger.HandleInput("describe"); err == nil ||
  1139. err.Error() != `Need a thread ID` {
  1140. t.Error("Unexpected result:", err)
  1141. return
  1142. }
  1143. if _, err = testDebugger.HandleInput(fmt.Sprintf("extract %v foo", tid)); err == nil ||
  1144. err.Error() != `Need a thread ID, a variable name and a destination variable name` {
  1145. t.Error("Unexpected result:", err)
  1146. return
  1147. }
  1148. if _, err = testDebugger.HandleInput(fmt.Sprintf("extract %v _foo foo", tid)); err == nil ||
  1149. err.Error() != `Variable names may only contain [a-zA-Z] and [a-zA-Z0-9] from the second character` {
  1150. t.Error("Unexpected result:", err)
  1151. return
  1152. }
  1153. if _, err = testDebugger.HandleInput(fmt.Sprintf("extract %v foo foo", tid)); err == nil ||
  1154. err.Error() != `No such value foo` {
  1155. t.Error("Unexpected result:", err)
  1156. return
  1157. }
  1158. if _, err = testDebugger.HandleInput(fmt.Sprintf("inject %v", tid)); err == nil ||
  1159. err.Error() != `Need a thread ID, a variable name and an expression` {
  1160. t.Error("Unexpected result:", err)
  1161. return
  1162. }
  1163. testDebugger.(*ecalDebugger).globalScope = nil
  1164. if _, err = testDebugger.HandleInput(fmt.Sprintf("extract %v foo foo", tid)); err == nil ||
  1165. err.Error() != `Cannot access global scope` {
  1166. t.Error("Unexpected result:", err)
  1167. return
  1168. }
  1169. if _, err = testDebugger.HandleInput(fmt.Sprintf("inject %v foo foo", tid)); err == nil ||
  1170. err.Error() != `Cannot access global scope` {
  1171. t.Error("Unexpected result:", err)
  1172. return
  1173. }
  1174. }