scanner_test.go 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490
  1. package scanner
  2. import (
  3. "bytes"
  4. _ "embed"
  5. "fmt"
  6. "strings"
  7. "testing"
  8. "github.com/stretchr/testify/assert"
  9. "github.com/wuntsong-org/go-zero-plus/tools/goctlwt/pkg/parser/api/assertx"
  10. "github.com/wuntsong-org/go-zero-plus/tools/goctlwt/pkg/parser/api/token"
  11. )
  12. func Test_readData(t *testing.T) {
  13. testData := []struct {
  14. input interface{}
  15. expected interface{}
  16. }{
  17. {
  18. input: []byte("foo"),
  19. expected: []byte("foo"),
  20. },
  21. {
  22. input: bytes.NewBufferString("foo"),
  23. expected: []byte("foo"),
  24. },
  25. {
  26. input: "foo",
  27. expected: []byte("foo"),
  28. },
  29. {
  30. input: "",
  31. expected: []byte{},
  32. },
  33. {
  34. input: strings.NewReader("foo"),
  35. expected: fmt.Errorf("unsupported type: *strings.Reader"),
  36. },
  37. }
  38. for _, v := range testData {
  39. actual, err := readData("", v.input)
  40. if err != nil {
  41. assert.Equal(t, v.expected.(error).Error(), err.Error())
  42. } else {
  43. assert.Equal(t, v.expected, actual)
  44. }
  45. }
  46. }
  47. func TestNewScanner(t *testing.T) {
  48. testData := []struct {
  49. filename string
  50. src interface{}
  51. expected interface{}
  52. }{
  53. {
  54. filename: "foo",
  55. src: "foo",
  56. expected: "foo",
  57. },
  58. {
  59. filename: "foo",
  60. src: "",
  61. expected: missingInput,
  62. },
  63. }
  64. for _, v := range testData {
  65. s, err := NewScanner(v.filename, v.src)
  66. if err != nil {
  67. assert.Equal(t, v.expected.(error).Error(), err.Error())
  68. } else {
  69. assert.Equal(t, v.expected, s.filename)
  70. }
  71. }
  72. }
  73. func TestScanner_NextToken_lineComment(t *testing.T) {
  74. var testData = []token.Token{
  75. {
  76. Type: token.COMMENT,
  77. Text: "//",
  78. Position: token.Position{
  79. Filename: "foo.api",
  80. Line: 1,
  81. Column: 1,
  82. },
  83. },
  84. {
  85. Type: token.COMMENT,
  86. Text: "//foo",
  87. Position: token.Position{
  88. Filename: "foo.api",
  89. Line: 2,
  90. Column: 1,
  91. },
  92. },
  93. {
  94. Type: token.COMMENT,
  95. Text: "//bar",
  96. Position: token.Position{
  97. Filename: "foo.api",
  98. Line: 3,
  99. Column: 1,
  100. },
  101. },
  102. {
  103. Type: token.COMMENT,
  104. Text: "///",
  105. Position: token.Position{
  106. Filename: "foo.api",
  107. Line: 4,
  108. Column: 1,
  109. },
  110. },
  111. {
  112. Type: token.COMMENT,
  113. Text: "////",
  114. Position: token.Position{
  115. Filename: "foo.api",
  116. Line: 5,
  117. Column: 1,
  118. },
  119. },
  120. {
  121. Type: token.QUO,
  122. Text: "/",
  123. Position: token.Position{
  124. Filename: "foo.api",
  125. Line: 6,
  126. Column: 1,
  127. },
  128. },
  129. token.EofToken,
  130. }
  131. var input = "//\n//foo\n//bar\n///\n////\n/"
  132. s, err := NewScanner("foo.api", input)
  133. assert.NoError(t, err)
  134. for _, expected := range testData {
  135. actual, err := s.NextToken()
  136. assert.NoError(t, err)
  137. assert.Equal(t, expected, actual)
  138. }
  139. }
  140. func TestScanner_NextToken_document(t *testing.T) {
  141. var testData = []token.Token{
  142. {
  143. Type: token.DOCUMENT,
  144. Text: "/**/",
  145. Position: token.Position{
  146. Filename: "foo.api",
  147. Line: 1,
  148. Column: 1,
  149. },
  150. },
  151. {
  152. Type: token.DOCUMENT,
  153. Text: "/***/",
  154. Position: token.Position{
  155. Filename: "foo.api",
  156. Line: 1,
  157. Column: 6,
  158. },
  159. },
  160. {
  161. Type: token.DOCUMENT,
  162. Text: "/*-*/",
  163. Position: token.Position{
  164. Filename: "foo.api",
  165. Line: 1,
  166. Column: 12,
  167. },
  168. },
  169. {
  170. Type: token.DOCUMENT,
  171. Text: "/*/*/",
  172. Position: token.Position{
  173. Filename: "foo.api",
  174. Line: 1,
  175. Column: 18,
  176. },
  177. },
  178. {
  179. Type: token.DOCUMENT,
  180. Text: "/*////*/",
  181. Position: token.Position{
  182. Filename: "foo.api",
  183. Line: 1,
  184. Column: 24,
  185. },
  186. },
  187. {
  188. Type: token.DOCUMENT,
  189. Text: "/*foo*/",
  190. Position: token.Position{
  191. Filename: "foo.api",
  192. Line: 2,
  193. Column: 1,
  194. },
  195. },
  196. {
  197. Type: token.DOCUMENT,
  198. Text: "/*---*/",
  199. Position: token.Position{
  200. Filename: "foo.api",
  201. Line: 3,
  202. Column: 1,
  203. },
  204. },
  205. {
  206. Type: token.DOCUMENT,
  207. Text: "/*\n*/",
  208. Position: token.Position{
  209. Filename: "foo.api",
  210. Line: 4,
  211. Column: 1,
  212. },
  213. },
  214. {
  215. Type: token.QUO,
  216. Text: "/",
  217. Position: token.Position{
  218. Filename: "foo.api",
  219. Line: 5,
  220. Column: 1,
  221. },
  222. },
  223. token.EofToken,
  224. }
  225. var input = "/**/ /***/ /*-*/ /*/*/ /*////*/ \n/*foo*/\n/*---*/\n/*\n*/\n/"
  226. s, err := NewScanner("foo.api", input)
  227. assert.NoError(t, err)
  228. for _, expected := range testData {
  229. actual, err := s.NextToken()
  230. assert.NoError(t, err)
  231. assert.Equal(t, expected, actual)
  232. }
  233. }
  234. func TestScanner_NextToken_invalid_document(t *testing.T) {
  235. var testData = []string{
  236. "/*",
  237. "/**",
  238. "/***",
  239. "/*/",
  240. "/*/*",
  241. "/*/**",
  242. }
  243. for _, v := range testData {
  244. s, err := NewScanner("foo.api", v)
  245. assert.NoError(t, err)
  246. _, err = s.NextToken()
  247. assertx.Error(t, err)
  248. }
  249. }
  250. func TestScanner_NextToken_operator(t *testing.T) {
  251. var testData = []token.Token{
  252. {
  253. Type: token.SUB,
  254. Text: "-",
  255. Position: token.Position{
  256. Filename: "foo.api",
  257. Line: 1,
  258. Column: 1,
  259. },
  260. },
  261. {
  262. Type: token.MUL,
  263. Text: "*",
  264. Position: token.Position{
  265. Filename: "foo.api",
  266. Line: 1,
  267. Column: 2,
  268. },
  269. },
  270. {
  271. Type: token.LPAREN,
  272. Text: "(",
  273. Position: token.Position{
  274. Filename: "foo.api",
  275. Line: 1,
  276. Column: 3,
  277. },
  278. },
  279. {
  280. Type: token.LBRACE,
  281. Text: "{",
  282. Position: token.Position{
  283. Filename: "foo.api",
  284. Line: 1,
  285. Column: 4,
  286. },
  287. },
  288. {
  289. Type: token.COMMA,
  290. Text: ",",
  291. Position: token.Position{
  292. Filename: "foo.api",
  293. Line: 1,
  294. Column: 5,
  295. },
  296. },
  297. {
  298. Type: token.DOT,
  299. Text: ".",
  300. Position: token.Position{
  301. Filename: "foo.api",
  302. Line: 1,
  303. Column: 6,
  304. },
  305. },
  306. {
  307. Type: token.RPAREN,
  308. Text: ")",
  309. Position: token.Position{
  310. Filename: "foo.api",
  311. Line: 1,
  312. Column: 7,
  313. },
  314. },
  315. {
  316. Type: token.RBRACE,
  317. Text: "}",
  318. Position: token.Position{
  319. Filename: "foo.api",
  320. Line: 1,
  321. Column: 8,
  322. },
  323. },
  324. {
  325. Type: token.SEMICOLON,
  326. Text: ";",
  327. Position: token.Position{
  328. Filename: "foo.api",
  329. Line: 1,
  330. Column: 9,
  331. },
  332. },
  333. {
  334. Type: token.COLON,
  335. Text: ":",
  336. Position: token.Position{
  337. Filename: "foo.api",
  338. Line: 1,
  339. Column: 10,
  340. },
  341. },
  342. {
  343. Type: token.ASSIGN,
  344. Text: "=",
  345. Position: token.Position{
  346. Filename: "foo.api",
  347. Line: 1,
  348. Column: 11,
  349. },
  350. },
  351. {
  352. Type: token.ELLIPSIS,
  353. Text: "...",
  354. Position: token.Position{
  355. Filename: "foo.api",
  356. Line: 1,
  357. Column: 12,
  358. },
  359. },
  360. }
  361. s, err := NewScanner("foo.api", "-*({,.)};:=...")
  362. assert.NoError(t, err)
  363. for _, expected := range testData {
  364. actual, err := s.NextToken()
  365. assert.NoError(t, err)
  366. assert.Equal(t, expected, actual)
  367. }
  368. }
  369. func TestScanner_NextToken_at(t *testing.T) {
  370. t.Run("valid", func(t *testing.T) {
  371. var testData = []token.Token{
  372. {
  373. Type: token.AT_DOC,
  374. Text: "@doc",
  375. Position: token.Position{
  376. Filename: "foo.api",
  377. Line: 1,
  378. Column: 1,
  379. },
  380. },
  381. {
  382. Type: token.AT_HANDLER,
  383. Text: "@handler",
  384. Position: token.Position{
  385. Filename: "foo.api",
  386. Line: 1,
  387. Column: 5,
  388. },
  389. },
  390. {
  391. Type: token.AT_SERVER,
  392. Text: "@server",
  393. Position: token.Position{
  394. Filename: "foo.api",
  395. Line: 1,
  396. Column: 13,
  397. },
  398. },
  399. {
  400. Type: token.AT_HANDLER,
  401. Text: "@handler",
  402. Position: token.Position{
  403. Filename: "foo.api",
  404. Line: 2,
  405. Column: 1,
  406. },
  407. },
  408. {
  409. Type: token.AT_SERVER,
  410. Text: "@server",
  411. Position: token.Position{
  412. Filename: "foo.api",
  413. Line: 3,
  414. Column: 1,
  415. },
  416. },
  417. }
  418. s, err := NewScanner("foo.api", "@doc@handler@server\n@handler\n@server")
  419. assert.NoError(t, err)
  420. for _, expected := range testData {
  421. actual, err := s.NextToken()
  422. assert.NoError(t, err)
  423. assert.Equal(t, expected, actual)
  424. }
  425. })
  426. t.Run("invalid", func(t *testing.T) {
  427. var testData = []string{
  428. "@h",
  429. "@ha",
  430. "@han",
  431. "@hand",
  432. "@handl",
  433. "@handle",
  434. "@handlerr",
  435. "@hhandler",
  436. "@foo",
  437. "@sserver",
  438. "@serverr",
  439. "@d",
  440. "@do",
  441. "@docc",
  442. }
  443. for _, v := range testData {
  444. s, err := NewScanner("foo.api", v)
  445. assert.NoError(t, err)
  446. _, err = s.NextToken()
  447. assertx.Error(t, err)
  448. }
  449. })
  450. }
  451. func TestScanner_NextToken_ident(t *testing.T) {
  452. var testData = []token.Token{
  453. {
  454. Type: token.IDENT,
  455. Text: "foo",
  456. Position: token.Position{
  457. Filename: "foo.api",
  458. Line: 1,
  459. Column: 1,
  460. },
  461. },
  462. {
  463. Type: token.IDENT,
  464. Text: "bar",
  465. Position: token.Position{
  466. Filename: "foo.api",
  467. Line: 1,
  468. Column: 5,
  469. },
  470. },
  471. {
  472. Type: token.IDENT,
  473. Text: "go",
  474. Position: token.Position{
  475. Filename: "foo.api",
  476. Line: 2,
  477. Column: 1,
  478. },
  479. },
  480. {
  481. Type: token.IDENT,
  482. Text: "func",
  483. Position: token.Position{
  484. Filename: "foo.api",
  485. Line: 2,
  486. Column: 4,
  487. },
  488. },
  489. {
  490. Type: token.IDENT,
  491. Text: "_",
  492. Position: token.Position{
  493. Filename: "foo.api",
  494. Line: 3,
  495. Column: 1,
  496. },
  497. },
  498. {
  499. Type: token.IDENT,
  500. Text: "_go",
  501. Position: token.Position{
  502. Filename: "foo.api",
  503. Line: 4,
  504. Column: 1,
  505. },
  506. },
  507. {
  508. Type: token.IDENT,
  509. Text: "info",
  510. Position: token.Position{
  511. Filename: "foo.api",
  512. Line: 5,
  513. Column: 1,
  514. },
  515. },
  516. {
  517. Type: token.IDENT,
  518. Text: "goo",
  519. Position: token.Position{
  520. Filename: "foo.api",
  521. Line: 6,
  522. Column: 1,
  523. },
  524. },
  525. {
  526. Type: token.IDENT,
  527. Text: "vvar",
  528. Position: token.Position{
  529. Filename: "foo.api",
  530. Line: 6,
  531. Column: 5,
  532. },
  533. },
  534. {
  535. Type: token.IDENT,
  536. Text: "imports",
  537. Position: token.Position{
  538. Filename: "foo.api",
  539. Line: 6,
  540. Column: 10,
  541. },
  542. },
  543. {
  544. Type: token.IDENT,
  545. Text: "go1",
  546. Position: token.Position{
  547. Filename: "foo.api",
  548. Line: 7,
  549. Column: 1,
  550. },
  551. },
  552. }
  553. s, err := NewScanner("foo.api", "foo bar\ngo func\n_\n_go\ninfo\ngoo vvar imports\ngo1")
  554. assert.NoError(t, err)
  555. for _, expected := range testData {
  556. actual, err := s.NextToken()
  557. assert.NoError(t, err)
  558. assert.Equal(t, expected, actual)
  559. }
  560. }
  561. func TestScanner_NextToken_Key(t *testing.T) {
  562. var testData = []token.Token{
  563. {
  564. Type: token.IDENT,
  565. Text: "foo",
  566. Position: token.Position{
  567. Filename: "foo.api",
  568. Line: 1,
  569. Column: 1,
  570. },
  571. },
  572. {
  573. Type: token.KEY,
  574. Text: "foo:",
  575. Position: token.Position{
  576. Filename: "foo.api",
  577. Line: 2,
  578. Column: 1,
  579. },
  580. },
  581. {
  582. Type: token.KEY,
  583. Text: "bar:",
  584. Position: token.Position{
  585. Filename: "foo.api",
  586. Line: 3,
  587. Column: 1,
  588. },
  589. },
  590. {
  591. Type: token.COLON,
  592. Text: ":",
  593. Position: token.Position{
  594. Filename: "foo.api",
  595. Line: 3,
  596. Column: 5,
  597. },
  598. },
  599. {
  600. Type: token.IDENT,
  601. Text: "interface",
  602. Position: token.Position{
  603. Filename: "foo.api",
  604. Line: 4,
  605. Column: 1,
  606. },
  607. },
  608. {
  609. Type: token.ANY,
  610. Text: "interface{}",
  611. Position: token.Position{
  612. Filename: "foo.api",
  613. Line: 5,
  614. Column: 1,
  615. },
  616. },
  617. {
  618. Type: token.LBRACE,
  619. Text: "{",
  620. Position: token.Position{
  621. Filename: "foo.api",
  622. Line: 5,
  623. Column: 12,
  624. },
  625. },
  626. }
  627. s, err := NewScanner("foo.api", "foo\nfoo:\nbar::\ninterface\ninterface{}{")
  628. assert.NoError(t, err)
  629. for _, expected := range testData {
  630. actual, err := s.NextToken()
  631. assert.NoError(t, err)
  632. assert.Equal(t, expected, actual)
  633. }
  634. }
  635. func TestScanner_NextToken_int(t *testing.T) {
  636. var testData = []token.Token{
  637. {
  638. Type: token.INT,
  639. Text: `123`,
  640. Position: token.Position{
  641. Filename: "foo.api",
  642. Line: 1,
  643. Column: 1,
  644. },
  645. },
  646. {
  647. Type: token.INT,
  648. Text: `234`,
  649. Position: token.Position{
  650. Filename: "foo.api",
  651. Line: 1,
  652. Column: 5,
  653. },
  654. },
  655. {
  656. Type: token.INT,
  657. Text: `123`,
  658. Position: token.Position{
  659. Filename: "foo.api",
  660. Line: 2,
  661. Column: 1,
  662. },
  663. },
  664. {
  665. Type: token.INT,
  666. Text: `234`,
  667. Position: token.Position{
  668. Filename: "foo.api",
  669. Line: 3,
  670. Column: 1,
  671. },
  672. },
  673. }
  674. s, err := NewScanner("foo.api", "123 234\n123\n234a")
  675. assert.NoError(t, err)
  676. for _, expected := range testData {
  677. actual, err := s.NextToken()
  678. assert.NoError(t, err)
  679. assert.Equal(t, expected, actual)
  680. }
  681. }
  682. func TestScanner_NextToken_duration(t *testing.T) {
  683. t.Run("ns", func(t *testing.T) {
  684. var testData = []token.Token{
  685. {
  686. Type: token.DURATION,
  687. Text: `1ns`,
  688. Position: token.Position{
  689. Filename: "foo.api",
  690. Line: 1,
  691. Column: 1,
  692. },
  693. },
  694. {
  695. Type: token.DURATION,
  696. Text: `10ns`,
  697. Position: token.Position{
  698. Filename: "foo.api",
  699. Line: 2,
  700. Column: 1,
  701. },
  702. },
  703. {
  704. Type: token.DURATION,
  705. Text: `100ns`,
  706. Position: token.Position{
  707. Filename: "foo.api",
  708. Line: 3,
  709. Column: 1,
  710. },
  711. },
  712. }
  713. s, err := NewScanner("foo.api", "1ns\n10ns\n100ns")
  714. assert.NoError(t, err)
  715. for _, expected := range testData {
  716. actual, err := s.NextToken()
  717. assert.NoError(t, err)
  718. assert.Equal(t, expected, actual)
  719. }
  720. })
  721. t.Run("µs", func(t *testing.T) {
  722. var testData = []token.Token{
  723. {
  724. Type: token.DURATION,
  725. Text: `1µs`,
  726. Position: token.Position{
  727. Filename: "foo.api",
  728. Line: 1,
  729. Column: 1,
  730. },
  731. },
  732. {
  733. Type: token.DURATION,
  734. Text: `10µs`,
  735. Position: token.Position{
  736. Filename: "foo.api",
  737. Line: 2,
  738. Column: 1,
  739. },
  740. },
  741. {
  742. Type: token.DURATION,
  743. Text: `100µs`,
  744. Position: token.Position{
  745. Filename: "foo.api",
  746. Line: 3,
  747. Column: 1,
  748. },
  749. },
  750. {
  751. Type: token.DURATION,
  752. Text: `1µs1ns`,
  753. Position: token.Position{
  754. Filename: "foo.api",
  755. Line: 4,
  756. Column: 1,
  757. },
  758. },
  759. {
  760. Type: token.DURATION,
  761. Text: `1µs10ns`,
  762. Position: token.Position{
  763. Filename: "foo.api",
  764. Line: 5,
  765. Column: 1,
  766. },
  767. },
  768. }
  769. s, err := NewScanner("foo.api", "1µs\n10µs\n100µs\n1µs1ns\n1µs10ns")
  770. assert.NoError(t, err)
  771. for _, expected := range testData {
  772. actual, err := s.NextToken()
  773. assert.NoError(t, err)
  774. assert.Equal(t, expected, actual)
  775. }
  776. })
  777. t.Run("ms", func(t *testing.T) {
  778. var testData []token.Token
  779. var source interface{} = "1ms\n10ms\n100ms\n1ms1µs\n1ms10µs\n1ms1ns\n1ms10ns\n1ms1µs1ns\n1ms1µs10ns\n1ms10µs1ns\n1ms10µs10ns"
  780. for idx, seg := range strings.FieldsFunc(source.(string), func(r rune) bool {
  781. return r == '\n'
  782. }) {
  783. testData = append(testData, token.Token{
  784. Type: token.DURATION,
  785. Text: seg,
  786. Position: token.Position{
  787. Filename: "foo.api",
  788. Line: idx + 1,
  789. Column: 1,
  790. },
  791. })
  792. }
  793. s, err := NewScanner("foo.api", source)
  794. assert.NoError(t, err)
  795. for _, expected := range testData {
  796. actual, err := s.NextToken()
  797. assert.NoError(t, err)
  798. assert.Equal(t, expected, actual)
  799. }
  800. })
  801. t.Run("s", func(t *testing.T) {
  802. var testData []token.Token
  803. var source interface{} = "1s\n10s\n100s\n1s1ms\n1s10ms\n1s100ms\n1s1ms1µs\n1s10ms10µs\n1s100ms100µs\n" +
  804. "1s100ms100µs1ns\n1s100ms100µs10ns\n1s100ms100µs100ns\n1s1µs\n1s10µs\n1s100µs\n1s1µs1ns\n1s10µs10ns\n" +
  805. "1s100µs100ns\n1s1ms1µs1ns\n1s10ms10µs10ns\n1s100ms100µs100ns\n1s1ns\n1s10ns\n1s100ns"
  806. for idx, seg := range strings.FieldsFunc(source.(string), func(r rune) bool {
  807. return r == '\n'
  808. }) {
  809. testData = append(testData, token.Token{
  810. Type: token.DURATION,
  811. Text: seg,
  812. Position: token.Position{
  813. Filename: "foo.api",
  814. Line: idx + 1,
  815. Column: 1,
  816. },
  817. })
  818. }
  819. s, err := NewScanner("foo.api", source)
  820. assert.NoError(t, err)
  821. for _, expected := range testData {
  822. actual, err := s.NextToken()
  823. assert.NoError(t, err)
  824. assert.Equal(t, expected, actual)
  825. }
  826. })
  827. t.Run("m", func(t *testing.T) {
  828. var testData []token.Token
  829. var source interface{} = "1m\n10m\n100m\n1m1s\n1m10s\n1m100s\n1m1s1ms\n1m10s10ms\n1m100s100ms\n" +
  830. "1m1s1ms1µs\n1m10s10ms10µs\n1m100s100ms100µs\n1m1s1ms1µs1ns\n1m1s1ms1µs10ns\n1m1s1ms1µs100ns\n" +
  831. "1m1s1µs\n1m1ns\n1m10ms10µs100ns"
  832. list := strings.FieldsFunc(source.(string), func(r rune) bool {
  833. return r == '\n'
  834. })
  835. for idx, seg := range list {
  836. testData = append(testData, token.Token{
  837. Type: token.DURATION,
  838. Text: seg,
  839. Position: token.Position{
  840. Filename: "foo.api",
  841. Line: idx + 1,
  842. Column: 1,
  843. },
  844. })
  845. }
  846. s, err := NewScanner("foo.api", source)
  847. assert.NoError(t, err)
  848. for _, expected := range testData {
  849. actual, err := s.NextToken()
  850. assert.NoError(t, err)
  851. assert.Equal(t, expected, actual)
  852. }
  853. })
  854. t.Run("h", func(t *testing.T) {
  855. var testData []token.Token
  856. var source interface{} = "1h\n10h\n100h\n" +
  857. "1h1m\n10h10m\n100h100m\n" +
  858. "1h1m1s\n10h10m10s\n100h100m100s\n" +
  859. "1h1m1s1ms\n10h10m10s10ms\n100h100m100s100ms\n" +
  860. "1h1m1s1ms1µs\n10h10m10s10ms10µs\n100h100m100s100ms100µs\n" +
  861. "1h1m1s1ms1µs1ns\n10h10m10s10ms10µs10ns\n100h100m100s100ms100µs100ns\n" +
  862. "1h10ns\n1h100µs\n10h10s\n10h10ms\n10h10m10µs"
  863. list := strings.FieldsFunc(source.(string), func(r rune) bool {
  864. return r == '\n'
  865. })
  866. for idx, seg := range list {
  867. testData = append(testData, token.Token{
  868. Type: token.DURATION,
  869. Text: seg,
  870. Position: token.Position{
  871. Filename: "foo.api",
  872. Line: idx + 1,
  873. Column: 1,
  874. },
  875. })
  876. }
  877. s, err := NewScanner("foo.api", source)
  878. assert.NoError(t, err)
  879. for _, expected := range testData {
  880. actual, err := s.NextToken()
  881. assert.NoError(t, err)
  882. assert.Equal(t, expected, actual)
  883. }
  884. })
  885. }
  886. func TestScanner_NextToken_string(t *testing.T) {
  887. t.Run("valid", func(t *testing.T) {
  888. var testData = []token.Token{
  889. {
  890. Type: token.STRING,
  891. Text: `""`,
  892. Position: token.Position{
  893. Filename: "foo.api",
  894. Line: 1,
  895. Column: 1,
  896. },
  897. },
  898. {
  899. Type: token.STRING,
  900. Text: `"foo"`,
  901. Position: token.Position{
  902. Filename: "foo.api",
  903. Line: 1,
  904. Column: 3,
  905. },
  906. },
  907. {
  908. Type: token.STRING,
  909. Text: `"foo\nbar"`,
  910. Position: token.Position{
  911. Filename: "foo.api",
  912. Line: 1,
  913. Column: 8,
  914. },
  915. },
  916. }
  917. s, err := NewScanner("foo.api", `"""foo""foo\nbar"`)
  918. assert.NoError(t, err)
  919. for _, expected := range testData {
  920. actual, err := s.NextToken()
  921. assert.NoError(t, err)
  922. assert.Equal(t, expected, actual)
  923. }
  924. })
  925. t.Run("invalid", func(t *testing.T) {
  926. var testData = []string{
  927. `"`,
  928. `"foo`,
  929. `"
  930. `,
  931. }
  932. for _, v := range testData {
  933. s, err := NewScanner("foo.api", v)
  934. assert.NoError(t, err)
  935. _, err = s.NextToken()
  936. assertx.Error(t, err)
  937. }
  938. })
  939. }
  940. func TestScanner_NextToken_rawString(t *testing.T) {
  941. t.Run("valid", func(t *testing.T) {
  942. var testData = []token.Token{
  943. {
  944. Type: token.RAW_STRING,
  945. Text: "``",
  946. Position: token.Position{
  947. Filename: "foo.api",
  948. Line: 1,
  949. Column: 1,
  950. },
  951. },
  952. {
  953. Type: token.RAW_STRING,
  954. Text: "`foo`",
  955. Position: token.Position{
  956. Filename: "foo.api",
  957. Line: 1,
  958. Column: 3,
  959. },
  960. },
  961. {
  962. Type: token.RAW_STRING,
  963. Text: "`foo bar`",
  964. Position: token.Position{
  965. Filename: "foo.api",
  966. Line: 1,
  967. Column: 8,
  968. },
  969. },
  970. }
  971. s, err := NewScanner("foo.api", "```foo``foo bar`")
  972. assert.NoError(t, err)
  973. for _, expected := range testData {
  974. actual, err := s.NextToken()
  975. assert.NoError(t, err)
  976. assert.Equal(t, expected, actual)
  977. }
  978. })
  979. t.Run("invalid", func(t *testing.T) {
  980. var testData = []string{
  981. "`",
  982. "`foo",
  983. "` ",
  984. }
  985. for _, v := range testData {
  986. s, err := NewScanner("foo.api", v)
  987. assert.NoError(t, err)
  988. _, err = s.NextToken()
  989. assertx.Error(t, err)
  990. }
  991. })
  992. }
  993. func TestScanner_NextToken_anyCase(t *testing.T) {
  994. t.Run("case1", func(t *testing.T) {
  995. var testData = []string{
  996. "#",
  997. "$",
  998. "^",
  999. "好",
  1000. "|",
  1001. }
  1002. for _, v := range testData {
  1003. s, err := NewScanner("foo.api", v)
  1004. assert.NoError(t, err)
  1005. tok, err := s.NextToken()
  1006. assert.NoError(t, err)
  1007. fmt.Println(tok.String())
  1008. assert.Equal(t, token.ILLEGAL, tok.Type)
  1009. }
  1010. })
  1011. t.Run("case2", func(t *testing.T) {
  1012. s, err := NewScanner("foo.api", `好の`)
  1013. assert.NoError(t, err)
  1014. for {
  1015. tok, err := s.NextToken()
  1016. if tok.Type == token.EOF {
  1017. break
  1018. }
  1019. assert.NoError(t, err)
  1020. fmt.Println(tok)
  1021. }
  1022. })
  1023. t.Run("case3", func(t *testing.T) {
  1024. s, err := NewScanner("foo.api", `foo`)
  1025. assert.NoError(t, err)
  1026. for {
  1027. tok, err := s.NextToken()
  1028. if tok.Type == token.EOF {
  1029. break
  1030. }
  1031. assert.NoError(t, err)
  1032. fmt.Println(tok)
  1033. }
  1034. })
  1035. }
  1036. //go:embed test.api
  1037. var testInput string
  1038. func TestScanner_NextToken(t *testing.T) {
  1039. position := func(line, column int) token.Position {
  1040. return token.Position{
  1041. Filename: "test.api",
  1042. Line: line,
  1043. Column: column,
  1044. }
  1045. }
  1046. var testData = []token.Token{
  1047. {
  1048. Type: token.IDENT,
  1049. Text: "syntax",
  1050. Position: position(1, 1),
  1051. },
  1052. {
  1053. Type: token.ASSIGN,
  1054. Text: "=",
  1055. Position: position(1, 8),
  1056. },
  1057. {
  1058. Type: token.STRING,
  1059. Text: `"v1"`,
  1060. Position: position(1, 10),
  1061. },
  1062. {
  1063. Type: token.IDENT,
  1064. Text: `info`,
  1065. Position: position(3, 1),
  1066. },
  1067. {
  1068. Type: token.LPAREN,
  1069. Text: `(`,
  1070. Position: position(3, 5),
  1071. },
  1072. {
  1073. Type: token.KEY,
  1074. Text: `title:`,
  1075. Position: position(4, 5),
  1076. },
  1077. {
  1078. Type: token.STRING,
  1079. Text: `"type title here"`,
  1080. Position: position(4, 12),
  1081. },
  1082. {
  1083. Type: token.KEY,
  1084. Text: `desc:`,
  1085. Position: position(5, 5),
  1086. },
  1087. {
  1088. Type: token.STRING,
  1089. Text: `"type desc here"`,
  1090. Position: position(5, 11),
  1091. },
  1092. {
  1093. Type: token.KEY,
  1094. Text: `author:`,
  1095. Position: position(6, 5),
  1096. },
  1097. {
  1098. Type: token.STRING,
  1099. Text: `"type author here"`,
  1100. Position: position(6, 13),
  1101. },
  1102. {
  1103. Type: token.KEY,
  1104. Text: `email:`,
  1105. Position: position(7, 5),
  1106. },
  1107. {
  1108. Type: token.STRING,
  1109. Text: `"type email here"`,
  1110. Position: position(7, 12),
  1111. },
  1112. {
  1113. Type: token.KEY,
  1114. Text: `version:`,
  1115. Position: position(8, 5),
  1116. },
  1117. {
  1118. Type: token.STRING,
  1119. Text: `"type version here"`,
  1120. Position: position(8, 14),
  1121. },
  1122. {
  1123. Type: token.RPAREN,
  1124. Text: `)`,
  1125. Position: position(9, 1),
  1126. },
  1127. {
  1128. Type: token.IDENT,
  1129. Text: `type`,
  1130. Position: position(12, 1),
  1131. },
  1132. {
  1133. Type: token.IDENT,
  1134. Text: `request`,
  1135. Position: position(12, 6),
  1136. },
  1137. {
  1138. Type: token.LBRACE,
  1139. Text: `{`,
  1140. Position: position(12, 14),
  1141. },
  1142. {
  1143. Type: token.COMMENT,
  1144. Text: `// TODO: add members here and delete this comment`,
  1145. Position: position(13, 5),
  1146. },
  1147. {
  1148. Type: token.RBRACE,
  1149. Text: `}`,
  1150. Position: position(14, 1),
  1151. },
  1152. {
  1153. Type: token.IDENT,
  1154. Text: `type`,
  1155. Position: position(16, 1),
  1156. },
  1157. {
  1158. Type: token.IDENT,
  1159. Text: `response`,
  1160. Position: position(16, 6),
  1161. },
  1162. {
  1163. Type: token.LBRACE,
  1164. Text: `{`,
  1165. Position: position(16, 15),
  1166. },
  1167. {
  1168. Type: token.COMMENT,
  1169. Text: `// TODO: add members here and delete this comment`,
  1170. Position: position(17, 5),
  1171. },
  1172. {
  1173. Type: token.RBRACE,
  1174. Text: `}`,
  1175. Position: position(18, 1),
  1176. },
  1177. {
  1178. Type: token.AT_SERVER,
  1179. Text: `@server`,
  1180. Position: position(20, 1),
  1181. },
  1182. {
  1183. Type: token.LPAREN,
  1184. Text: `(`,
  1185. Position: position(20, 8),
  1186. },
  1187. {
  1188. Type: token.KEY,
  1189. Text: `jwt:`,
  1190. Position: position(21, 5),
  1191. },
  1192. {
  1193. Type: token.IDENT,
  1194. Text: `Auth`,
  1195. Position: position(21, 10),
  1196. },
  1197. {
  1198. Type: token.KEY,
  1199. Text: `group:`,
  1200. Position: position(22, 5),
  1201. },
  1202. {
  1203. Type: token.IDENT,
  1204. Text: `template`,
  1205. Position: position(22, 12),
  1206. },
  1207. {
  1208. Type: token.RPAREN,
  1209. Text: `)`,
  1210. Position: position(23, 1),
  1211. },
  1212. {
  1213. Type: token.IDENT,
  1214. Text: `service`,
  1215. Position: position(24, 1),
  1216. },
  1217. {
  1218. Type: token.IDENT,
  1219. Text: `template`,
  1220. Position: position(24, 9),
  1221. },
  1222. {
  1223. Type: token.LBRACE,
  1224. Text: `{`,
  1225. Position: position(24, 18),
  1226. },
  1227. {
  1228. Type: token.AT_DOC,
  1229. Text: `@doc`,
  1230. Position: position(25, 5),
  1231. },
  1232. {
  1233. Type: token.STRING,
  1234. Text: `"foo"`,
  1235. Position: position(25, 10),
  1236. },
  1237. {
  1238. Type: token.DOCUMENT,
  1239. Text: `/*foo*/`,
  1240. Position: position(25, 16),
  1241. },
  1242. {
  1243. Type: token.AT_HANDLER,
  1244. Text: `@handler`,
  1245. Position: position(26, 5),
  1246. },
  1247. {
  1248. Type: token.IDENT,
  1249. Text: `handlerName`,
  1250. Position: position(26, 14),
  1251. },
  1252. {
  1253. Type: token.COMMENT,
  1254. Text: `// TODO: replace handler name and delete this comment`,
  1255. Position: position(26, 26),
  1256. },
  1257. {
  1258. Type: token.IDENT,
  1259. Text: `get`,
  1260. Position: position(27, 5),
  1261. },
  1262. {
  1263. Type: token.QUO,
  1264. Text: `/`,
  1265. Position: position(27, 9),
  1266. },
  1267. {
  1268. Type: token.IDENT,
  1269. Text: `users`,
  1270. Position: position(27, 10),
  1271. },
  1272. {
  1273. Type: token.QUO,
  1274. Text: `/`,
  1275. Position: position(27, 15),
  1276. },
  1277. {
  1278. Type: token.IDENT,
  1279. Text: `id`,
  1280. Position: position(27, 16),
  1281. },
  1282. {
  1283. Type: token.QUO,
  1284. Text: `/`,
  1285. Position: position(27, 18),
  1286. },
  1287. {
  1288. Type: token.COLON,
  1289. Text: `:`,
  1290. Position: position(27, 19),
  1291. },
  1292. {
  1293. Type: token.IDENT,
  1294. Text: `userId`,
  1295. Position: position(27, 20),
  1296. },
  1297. {
  1298. Type: token.LPAREN,
  1299. Text: `(`,
  1300. Position: position(27, 27),
  1301. },
  1302. {
  1303. Type: token.IDENT,
  1304. Text: `request`,
  1305. Position: position(27, 28),
  1306. },
  1307. {
  1308. Type: token.RPAREN,
  1309. Text: `)`,
  1310. Position: position(27, 35),
  1311. },
  1312. {
  1313. Type: token.IDENT,
  1314. Text: `returns`,
  1315. Position: position(27, 37),
  1316. },
  1317. {
  1318. Type: token.LPAREN,
  1319. Text: `(`,
  1320. Position: position(27, 45),
  1321. },
  1322. {
  1323. Type: token.IDENT,
  1324. Text: `response`,
  1325. Position: position(27, 46),
  1326. },
  1327. {
  1328. Type: token.RPAREN,
  1329. Text: `)`,
  1330. Position: position(27, 54),
  1331. },
  1332. }
  1333. scanner, err := NewScanner("test.api", testInput)
  1334. assert.NoError(t, err)
  1335. for _, v := range testData {
  1336. actual, err := scanner.NextToken()
  1337. assert.NoError(t, err)
  1338. assert.Equal(t, v, actual)
  1339. }
  1340. }
  1341. func TestScanner_NextToken_type(t *testing.T) {
  1342. var testData = []token.Token{
  1343. {
  1344. Type: token.IDENT,
  1345. Text: "foo",
  1346. Position: token.Position{
  1347. Filename: "foo.api",
  1348. Line: 1,
  1349. Column: 1,
  1350. },
  1351. },
  1352. {
  1353. Type: token.IDENT,
  1354. Text: "string",
  1355. Position: token.Position{
  1356. Filename: "foo.api",
  1357. Line: 1,
  1358. Column: 5,
  1359. },
  1360. },
  1361. {
  1362. Type: token.RAW_STRING,
  1363. Text: "`json:\"foo\"`",
  1364. Position: token.Position{
  1365. Filename: "foo.api",
  1366. Line: 1,
  1367. Column: 12,
  1368. },
  1369. },
  1370. {
  1371. Type: token.IDENT,
  1372. Text: "bar",
  1373. Position: token.Position{
  1374. Filename: "foo.api",
  1375. Line: 2,
  1376. Column: 1,
  1377. },
  1378. },
  1379. {
  1380. Type: token.LBRACK,
  1381. Text: "[",
  1382. Position: token.Position{
  1383. Filename: "foo.api",
  1384. Line: 2,
  1385. Column: 5,
  1386. },
  1387. },
  1388. {
  1389. Type: token.RBRACK,
  1390. Text: "]",
  1391. Position: token.Position{
  1392. Filename: "foo.api",
  1393. Line: 2,
  1394. Column: 6,
  1395. },
  1396. },
  1397. {
  1398. Type: token.IDENT,
  1399. Text: "int",
  1400. Position: token.Position{
  1401. Filename: "foo.api",
  1402. Line: 2,
  1403. Column: 7,
  1404. },
  1405. },
  1406. {
  1407. Type: token.IDENT,
  1408. Text: "baz",
  1409. Position: token.Position{
  1410. Filename: "foo.api",
  1411. Line: 3,
  1412. Column: 1,
  1413. },
  1414. },
  1415. {
  1416. Type: token.IDENT,
  1417. Text: "map",
  1418. Position: token.Position{
  1419. Filename: "foo.api",
  1420. Line: 3,
  1421. Column: 5,
  1422. },
  1423. },
  1424. {
  1425. Type: token.LBRACK,
  1426. Text: "[",
  1427. Position: token.Position{
  1428. Filename: "foo.api",
  1429. Line: 3,
  1430. Column: 8,
  1431. },
  1432. },
  1433. {
  1434. Type: token.IDENT,
  1435. Text: "string",
  1436. Position: token.Position{
  1437. Filename: "foo.api",
  1438. Line: 3,
  1439. Column: 9,
  1440. },
  1441. },
  1442. {
  1443. Type: token.RBRACK,
  1444. Text: "]",
  1445. Position: token.Position{
  1446. Filename: "foo.api",
  1447. Line: 3,
  1448. Column: 15,
  1449. },
  1450. },
  1451. {
  1452. Type: token.IDENT,
  1453. Text: "int",
  1454. Position: token.Position{
  1455. Filename: "foo.api",
  1456. Line: 3,
  1457. Column: 16,
  1458. },
  1459. },
  1460. }
  1461. var input = "foo string `json:\"foo\"`\nbar []int\nbaz map[string]int"
  1462. scanner, err := NewScanner("foo.api", input)
  1463. assert.NoError(t, err)
  1464. for _, v := range testData {
  1465. actual, err := scanner.NextToken()
  1466. assert.NoError(t, err)
  1467. assert.Equal(t, v, actual)
  1468. }
  1469. }