debug_test.go 31 KB

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