debug_test.go 30 KB

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