debug_test.go 24 KB

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