debug_test.go 27 KB

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