debug_test.go 28 KB

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