logParserTests.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546
  1. import { expect } from 'chai'
  2. import LatexLogParser from '../../../../frontend/js/ide/log-parser/latex-log-parser'
  3. import BibLogParser from '../../../../frontend/js/ide/log-parser/bib-log-parser'
  4. const fixturePath = '../../helpers/fixtures/logs/'
  5. const fs = require('fs')
  6. const path = require('path')
  7. describe('logParser', function (done) {
  8. before(function () {
  9. this.errorLog = fs.readFileSync(
  10. path.resolve(__dirname, fixturePath + 'errors.log'),
  11. {
  12. encoding: 'utf8',
  13. flag: 'r',
  14. }
  15. )
  16. this.warningLog = fs.readFileSync(
  17. path.resolve(__dirname, fixturePath + 'warnings.log'),
  18. {
  19. encoding: 'utf8',
  20. flag: 'r',
  21. }
  22. )
  23. this.badBoxesLog = fs.readFileSync(
  24. path.resolve(__dirname, fixturePath + 'bad-boxes.log'),
  25. {
  26. encoding: 'utf8',
  27. flag: 'r',
  28. }
  29. )
  30. this.biberWarningsLog = fs.readFileSync(
  31. path.resolve(__dirname, fixturePath + 'biber-warnings.log'),
  32. { encoding: 'utf8', flag: 'r' }
  33. )
  34. this.natbibWarningsLog = fs.readFileSync(
  35. path.resolve(__dirname, fixturePath + 'natbib-warnings.log'),
  36. { encoding: 'utf8', flag: 'r' }
  37. )
  38. this.geometryWarningsLog = fs.readFileSync(
  39. path.resolve(__dirname, fixturePath + 'geometry-warnings.log'),
  40. { encoding: 'utf8', flag: 'r' }
  41. )
  42. this.captionWarningsLog = fs.readFileSync(
  43. path.resolve(__dirname, fixturePath + 'caption-warnings.log'),
  44. { encoding: 'utf8', flag: 'r' }
  45. )
  46. this.runawayArgumentsLog = fs.readFileSync(
  47. path.resolve(__dirname, fixturePath + 'runaway-arguments.log'),
  48. { encoding: 'utf8', flag: 'r' }
  49. )
  50. this.biberBlg = fs.readFileSync(
  51. path.resolve(__dirname, fixturePath + 'biber.blg'),
  52. {
  53. encoding: 'utf8',
  54. flag: 'r',
  55. }
  56. )
  57. this.bibtexBlg = fs.readFileSync(
  58. path.resolve(__dirname, fixturePath + 'bibtex.blg'),
  59. {
  60. encoding: 'utf8',
  61. flag: 'r',
  62. }
  63. )
  64. this.fileLineErrorLog = fs.readFileSync(
  65. path.resolve(__dirname, fixturePath + 'file-line-error.log'),
  66. {
  67. encoding: 'utf8',
  68. flag: 'r',
  69. }
  70. )
  71. this.filenamesLog = fs.readFileSync(
  72. path.resolve(__dirname, fixturePath + 'filenames.log'),
  73. {
  74. encoding: 'utf8',
  75. flag: 'r',
  76. }
  77. )
  78. })
  79. it('should parse errors', function () {
  80. const latexParser = new LatexLogParser(this.errorLog, {
  81. ignoreDuplicates: true,
  82. })
  83. const errors = latexParser.parse().errors
  84. const expectedErrors = [
  85. [29, 'Undefined control sequence.'] + '',
  86. [
  87. 30,
  88. 'LaTeX Error: \\begin{equation} on input line 28 ended by \\end{equaion}.',
  89. ] + '',
  90. [30, 'Missing $ inserted.'] + '',
  91. [30, 'Display math should end with $$.'] + '',
  92. [46, 'Extra }, or forgotten \\right.'] + '',
  93. [46, 'Missing \\right. inserted.'] + '',
  94. [46, 'Missing } inserted.'] + '',
  95. ]
  96. expect(errors.length).to.equal(expectedErrors.length)
  97. for (var i = 0; i < errors.length; i++) {
  98. expect(
  99. expectedErrors.indexOf([errors[i].line, errors[i].message] + '')
  100. ).to.equal(i)
  101. }
  102. })
  103. it('should parse Badbox errors', function () {
  104. const latexParser = new LatexLogParser(this.badBoxesLog)
  105. const errors = latexParser.parse().typesetting
  106. const expectedErrors = [
  107. [9, 'Overfull \\hbox (29.11179pt too wide) in paragraph at lines 9--10'] +
  108. '',
  109. [11, 'Underfull \\hbox (badness 10000) in paragraph at lines 11--13'] +
  110. '',
  111. [27, 'Overfull \\vbox (12.00034pt too high) detected at line 27'] + '',
  112. [46, 'Underfull \\vbox (badness 10000) detected at line 46'] + '',
  113. [54, 'Underfull \\hbox (badness 10000) in paragraph at lines 54--55'] +
  114. '',
  115. [58, 'Underfull \\hbox (badness 10000) in paragraph at lines 58--60'] +
  116. '',
  117. ]
  118. expect(errors.length).to.equal(expectedErrors.length)
  119. for (var i = 0; i < errors.length; i++) {
  120. expect(
  121. expectedErrors.indexOf([errors[i].line, errors[i].message] + '')
  122. ).to.equal(i)
  123. }
  124. })
  125. it('should parse Warnings', function () {
  126. const latexParser = new LatexLogParser(this.warningLog)
  127. const errors = latexParser.parse().warnings
  128. const expectedErrors = [
  129. [
  130. 7,
  131. "Citation `Lambert:2010iw' on page 1 undefined on input line 7.",
  132. 'compiles/d1585ce575dea4cab55f784a22a88652/sections/introduction.tex',
  133. ] + '',
  134. [
  135. 7,
  136. "Citation `Lambert:2010iw' on page 1 undefined on input line 7.",
  137. 'compiles/d1585ce575dea4cab55f784a22a88652/sections/introduction.tex',
  138. ] + '',
  139. [
  140. 72,
  141. "Citation `Manton:2004tk' on page 3 undefined on input line 72.",
  142. 'compiles/d1585ce575dea4cab55f784a22a88652/sections/instantons.tex',
  143. ] + '',
  144. [
  145. 108,
  146. "Citation `Atiyah1978' on page 4 undefined on input line 108.",
  147. 'compiles/d1585ce575dea4cab55f784a22a88652/sections/instantons.tex',
  148. ] + '',
  149. [
  150. 176,
  151. "Citation `Dorey:1996hu' on page 5 undefined on input line 176.",
  152. 'compiles/d1585ce575dea4cab55f784a22a88652/sections/instantons.tex',
  153. ] + '',
  154. [
  155. 3,
  156. "Citation `Manton1982' on page 8 undefined on input line 3.",
  157. 'compiles/d1585ce575dea4cab55f784a22a88652/sections/moduli_space_approximation.tex',
  158. ] + '',
  159. [
  160. 21,
  161. "Citation `Weinberg:2006rq' on page 9 undefined on input line 21.",
  162. 'compiles/d1585ce575dea4cab55f784a22a88652/sections/moduli_space_approximation.tex',
  163. ] + '',
  164. [
  165. 192,
  166. "Citation `Bak:1999sv' on page 12 undefined on input line 192.",
  167. 'compiles/d1585ce575dea4cab55f784a22a88652/sections/moduli_space_approximation.tex',
  168. ] + '',
  169. [
  170. 9,
  171. "Citation `Peeters:2001np' on page 13 undefined on input line 9.",
  172. 'compiles/d1585ce575dea4cab55f784a22a88652/sections/dynamics_of_single_instanton.tex',
  173. ] + '',
  174. [
  175. 27,
  176. "Citation `Osborn:1981yf' on page 15 undefined on input line 27.",
  177. 'compiles/d1585ce575dea4cab55f784a22a88652/sections/dynamics_of_two_instantons.tex',
  178. ] + '',
  179. [
  180. 27,
  181. "Citation `Peeters:2001np' on page 15 undefined on input line 27.",
  182. 'compiles/d1585ce575dea4cab55f784a22a88652/sections/dynamics_of_two_instantons.tex',
  183. ] + '',
  184. [
  185. 20,
  186. "Citation `Osborn:1981yf' on page 22 undefined on input line 20.",
  187. 'compiles/d1585ce575dea4cab55f784a22a88652/sections/appendices.tex',
  188. ] + '',
  189. [
  190. 103,
  191. "Citation `Osborn:1981yf' on page 23 undefined on input line 103.",
  192. 'compiles/d1585ce575dea4cab55f784a22a88652/sections/appendices.tex',
  193. ] + '',
  194. [
  195. 103,
  196. "Citation `Peeters:2001np' on page 23 undefined on input line 103.",
  197. 'compiles/d1585ce575dea4cab55f784a22a88652/sections/appendices.tex',
  198. ] + '',
  199. [
  200. 352,
  201. "Citation `Peeters:2001np' on page 27 undefined on input line 352.",
  202. 'compiles/d1585ce575dea4cab55f784a22a88652/sections/appendices.tex',
  203. ] + '',
  204. ]
  205. // there logs display an additional summary error for undefined references
  206. const offsetErrorLen = errors.length - 1
  207. expect(offsetErrorLen).to.equal(expectedErrors.length)
  208. for (var i = 0; i < offsetErrorLen; i++) {
  209. expect(expectedErrors[i]).to.equal(
  210. [errors[i].line, errors[i].message, errors[i].file] + ''
  211. )
  212. }
  213. })
  214. it('should parse Biber warnings', function () {
  215. const latexParser = new LatexLogParser(this.biberWarningsLog)
  216. const errors = latexParser.parse().warnings
  217. const expectedErrors = [
  218. [
  219. null,
  220. 'Package biblatex Warning: No "backend" specified, using Biber backend. To use BibTeX, load biblatex with the "backend=bibtex" option.',
  221. '/usr/local/texlive/2013/texmf-dist/tex/latex/biblatex/biblatex.sty',
  222. ] + '',
  223. [
  224. null,
  225. 'Package biblatex Warning: The following entry could not be found in the database: Missing3 Please verify the spelling and rerun LaTeX afterwards.',
  226. '/compile/output.bbl',
  227. ] + '',
  228. [
  229. null,
  230. 'Package biblatex Warning: The following entry could not be found in the database: Missing2 Please verify the spelling and rerun LaTeX afterwards.',
  231. '/compile/output.bbl',
  232. ] + '',
  233. [
  234. null,
  235. 'Package biblatex Warning: The following entry could not be found in the database: Missing1 Please verify the spelling and rerun LaTeX afterwards.',
  236. '/compile/output.bbl',
  237. ] + '',
  238. ]
  239. expect(errors.length).to.equal(expectedErrors.length)
  240. for (var i = 0; i < errors.length; i++) {
  241. expect(expectedErrors[i]).to.equal(
  242. [errors[i].line, errors[i].message, errors[i].file] + ''
  243. )
  244. }
  245. })
  246. it('should parse Natbib warnings', function () {
  247. const latexParser = new LatexLogParser(this.natbibWarningsLog)
  248. const errors = latexParser.parse().warnings
  249. var expectedErrors = [
  250. [
  251. 6,
  252. "Package natbib Warning: Citation `blah' on page 1 undefined on input line 6.",
  253. '/compile/main.tex',
  254. ] + '',
  255. [
  256. null,
  257. 'Package natbib Warning: There were undefined citations.',
  258. '/compile/main.tex',
  259. ] + '',
  260. ]
  261. expect(errors.length).to.equal(expectedErrors.length)
  262. for (var i = 0; i < errors.length; i++) {
  263. expect(expectedErrors[i]).to.equal(
  264. [errors[i].line, errors[i].message, errors[i].file] + ''
  265. )
  266. }
  267. })
  268. it('should parse Geometry warnings', function () {
  269. const latexParser = new LatexLogParser(this.geometryWarningsLog)
  270. const errors = latexParser.parse().warnings
  271. var expectedErrors = [
  272. [
  273. null,
  274. "Package geometry Warning: Over-specification in `h'-direction. `width' (597.50787pt) is ignored.",
  275. '/compile/main.tex',
  276. ] + '',
  277. [
  278. null,
  279. "Package geometry Warning: Over-specification in `v'-direction. `height' (845.04684pt) is ignored.",
  280. '/compile/main.tex',
  281. ] + '',
  282. ]
  283. expect(errors.length).to.equal(expectedErrors.length)
  284. for (var i = 0; i < errors.length; i++) {
  285. expect(expectedErrors[i]).to.equal(
  286. [errors[i].line, errors[i].message, errors[i].file] + ''
  287. )
  288. }
  289. })
  290. it('should parse Caption warnings', function () {
  291. const latexParser = new LatexLogParser(this.captionWarningsLog)
  292. const errors = latexParser.parse().warnings
  293. var expectedErrors = [
  294. [
  295. null,
  296. 'Package caption Warning: Unsupported document class (or package) detected, usage of the caption package is not recommended. See the caption package documentation for explanation.',
  297. '/usr/local/texlive/2014/texmf-dist/tex/latex/caption/caption.sty',
  298. ] + '',
  299. [
  300. 46,
  301. "Package caption Warning: The option `hypcap=true' will be ignored for this particular \\caption on input line 46. See the caption package documentation for explanation.",
  302. '/compile/main.tex',
  303. ] + '',
  304. ]
  305. expect(errors.length).to.equal(expectedErrors.length)
  306. for (var i = 0; i < errors.length; i++) {
  307. expect(expectedErrors[i]).to.equal(
  308. [errors[i].line, errors[i].message, errors[i].file] + ''
  309. )
  310. }
  311. })
  312. it('should parse Runaway Arguments', function () {
  313. const latexParser = new LatexLogParser(this.runawayArgumentsLog)
  314. const errors = latexParser.parse().errors
  315. var expectedErrors = [
  316. [null, 'Runaway argument?', '/compile/runaway_argument.tex'] + '',
  317. [null, 'Emergency stop.', '/compile/runaway_argument.tex'] + '',
  318. ]
  319. expect(errors.length).to.equal(expectedErrors.length)
  320. for (var i = 0; i < errors.length; i++) {
  321. expect(expectedErrors[i]).to.equal(
  322. [errors[i].line, errors[i].message, errors[i].file] + ''
  323. )
  324. }
  325. })
  326. it('should parse filenames', function () {
  327. const latexParser = new LatexLogParser(this.filenamesLog)
  328. var { errors, warnings, typesetting } = latexParser.parse()
  329. var expectedErrors = [
  330. [
  331. 1,
  332. 'Undefined control sequence.',
  333. '/compile/a folder with spaces/a subfolder with spaces/a subsubfolder with spaces/another file with spaces.tex',
  334. ] + '',
  335. ]
  336. var expectedWarnings = [
  337. [
  338. 9,
  339. "Citation `Peeters:2001np' on page 13 undefined on input line 9.",
  340. '/compile/main',
  341. ] + '',
  342. ]
  343. var expectedTypesetting = [
  344. [
  345. 123,
  346. 'Overfull \\hbox (4.56pt too wide) in paragraph at lines 123--456',
  347. '/compile/otherfile',
  348. ] + '',
  349. ]
  350. expect(expectedErrors.length).to.equal(errors.length)
  351. expect(warnings.length).to.equal(warnings.length)
  352. expect(typesetting.length).to.equal(typesetting.length)
  353. for (var i = 0; i < errors.length; i++) {
  354. expect(expectedErrors[i]).to.equal(
  355. [errors[i].line, errors[i].message, errors[i].file] + ''
  356. )
  357. }
  358. for (var j = 0; i < warnings.length; i++) {
  359. expect(expectedWarnings[j]).to.equal(
  360. [warnings[j].line, warnings[j].message, warnings[j].file] + ''
  361. )
  362. }
  363. for (var k = 0; i < typesetting.length; i++) {
  364. expect(expectedTypesetting[k]).to.equal(
  365. [typesetting[k].line, typesetting[k].message, typesetting[k].file] + ''
  366. )
  367. }
  368. })
  369. it('should perform file line error parsing', function () {
  370. const latexParser = new LatexLogParser(this.fileLineErrorLog)
  371. const errors = latexParser.parse().errors
  372. var expectedErrors = [
  373. [
  374. 1,
  375. 'Undefined control sequence.',
  376. '/compile/a folder with spaces/a subfolder with spaces/a subsubfolder with spaces/another file with spaces.tex',
  377. ] + '',
  378. ]
  379. expect(errors.length).to.equal(expectedErrors.length)
  380. for (var i = 0; i < errors.length; i++) {
  381. expect(expectedErrors[i]).to.equal(
  382. [errors[i].line, errors[i].message, errors[i].file] + ''
  383. )
  384. }
  385. })
  386. it('should ignore duplicates', function () {
  387. var latexParser = new LatexLogParser(this.errorLog)
  388. var errors = latexParser.parse().errors
  389. // duplicates included
  390. expect(errors.length).to.equal(10)
  391. latexParser = new LatexLogParser(this.errorLog, { ignoreDuplicates: true })
  392. errors = latexParser.parse().errors
  393. // duplicates excluded
  394. expect(errors.length).to.equal(7)
  395. })
  396. it('should get file paths', function () {
  397. var latexParser = new LatexLogParser(this.errorLog)
  398. var errors = latexParser.parse().errors
  399. for (var i = 0; i < errors.length; i++) {
  400. expect(errors[i].file).to.equal(
  401. 'compiles/dff0c37d892f346e58fc14975a16bf69/sections/appendices.tex'
  402. )
  403. }
  404. latexParser = new LatexLogParser(this.badBoxesLog)
  405. errors = latexParser.parse().all
  406. for (var j = 0; j < errors.length; j++) {
  407. expect(errors[j].file).to.equal(
  408. 'compiles/b6cf470376785e64ad84c57e3296c912/logs/bad-boxes.tex'
  409. )
  410. }
  411. })
  412. it('should parse a typical biber .blg file', function () {
  413. const bibParser = new BibLogParser(this.biberBlg, {})
  414. const result = bibParser.parse()
  415. expect(typeof result).to.equal('object')
  416. expect(result.all.length).to.equal(14)
  417. expect(result.errors.length).to.equal(1)
  418. expect(result.warnings.length).to.equal(2)
  419. const error = result.errors[0]
  420. expect(error.level).to.equal('error')
  421. expect(error.line).to.equal('8')
  422. expect(error.file).to.equal('bibliography.bib')
  423. expect(error.message).to.equal(
  424. 'syntax error: at end of input, expected end of entry ("}" or ")") (skipping to next "@")'
  425. )
  426. })
  427. it('should throw an error when non-biblog passed to BibLogParser', function (done) {
  428. const bibParser = new BibLogParser(this.captionWarningsLog, {})
  429. try {
  430. bibParser.parse()
  431. } catch (e) {
  432. expect(e).to.exist
  433. done()
  434. }
  435. })
  436. it('should throw an error when empty string passed to BibLogParser', function (done) {
  437. const bibParser = new BibLogParser('', {})
  438. try {
  439. bibParser.parse()
  440. } catch (e) {
  441. expect(e).to.exist
  442. done()
  443. }
  444. })
  445. it('should throw an error when non-string passed to BibLogParser', function (done) {
  446. try {
  447. const bibParser = new BibLogParser({ a: 1 }, {})
  448. bibParser.parse()
  449. } catch (e) {
  450. expect(e).to.exist
  451. done()
  452. }
  453. })
  454. it('should parse a typical bibtex .blg file', function () {
  455. const bibParser = new BibLogParser(this.bibtexBlg, {})
  456. const result = bibParser.parse()
  457. expect(typeof result).to.equal('object')
  458. expect(result.all.length).to.equal(13)
  459. expect(result.warnings.length).to.equal(6)
  460. const firstWarning = result.warnings[0]
  461. expect(firstWarning.file).to.equal('references.bib')
  462. expect(firstWarning.line).to.equal('152')
  463. expect(firstWarning.level).to.equal('warning')
  464. expect(firstWarning.message).to.equal(
  465. 'string name "something" is undefined'
  466. )
  467. const thirdWarning = result.warnings[2]
  468. expect(thirdWarning.message).to.equal(
  469. "can't use both author and editor fields in Binney87"
  470. )
  471. expect(result.errors.length).to.equal(7)
  472. const firstError = result.errors[0]
  473. expect(firstError.file).to.equal('references.bib')
  474. expect(firstError.line).to.equal('196')
  475. expect(firstError.level).to.equal('error')
  476. expect(
  477. firstError.message.indexOf("I was expecting a `,' or a `}'")
  478. ).to.equal(0)
  479. expect(
  480. firstError.message.indexOf('(Error may have been on previous line)') > 0
  481. ).to.equal(true)
  482. const crossReferenceError = result.errors[5]
  483. expect(crossReferenceError.level).to.equal('error')
  484. expect(
  485. crossReferenceError.message.indexOf('A bad cross reference')
  486. ).to.equal(0)
  487. const styleError = result.errors[6]
  488. expect(styleError.level).to.equal('error')
  489. expect(
  490. styleError.message.indexOf("I couldn't open style file aa.bst")
  491. ).to.equal(0)
  492. })
  493. })