1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package eu.simuline.m2latex.core;
20
21 import eu.simuline.m2latex.mojo.MavenLogWrapper;
22 import eu.simuline.m2latex.mojo.PdfMojo;
23
24 import java.io.File;
25 import java.io.FileFilter;
26
27
28 import java.io.IOException;
29
30 import org.apache.maven.plugin.logging.Log;
31 import org.apache.maven.plugin.logging.SystemStreamLog;
32
33 import static org.mockito.Mockito.mock;
34 import static org.mockito.Mockito.RETURNS_SMART_NULLS;
35 import static org.mockito.Mockito.when;
36 import static org.mockito.Mockito.doNothing;
37 import static org.mockito.Mockito.doThrow;
38 import static org.mockito.Mockito.doCallRealMethod;
39 import static org.mockito.Mockito.verify;
40 import static org.mockito.Mockito.spy;
41 import static org.mockito.Mockito.verifyNoMoreInteractions;
42 import static org.mockito.Mockito.atLeastOnce;
43 import static org.mockito.Mockito.inOrder;
44
45 import static org.mockito.ArgumentMatchers.any;
46 import static org.mockito.ArgumentMatchers.anyString;
47 import static org.mockito.ArgumentMatchers.isNull;
48 import static org.mockito.ArgumentMatchers.eq;
49 import static org.mockito.AdditionalMatchers.aryEq;
50
51 import org.mockito.InOrder;
52
53 import org.mockito.stubbing.Answer;
54 import org.mockito.invocation.InvocationOnMock;
55
56 import org.junit.Test;
57 import org.junit.Ignore;
58 import org.junit.Before;
59 import org.junit.After;
60
61
62
63
64
65
66
67 public class LatexProcessorTest {
68
69 private final static File WORKING_DIR =
70 new File(System.getProperty("testResourcesDir"));
71
72
73
74
75 private final static FileFilter FILTER_FALSE = new FileFilter() {
76 public boolean accept(File pathname) {
77 return false;
78 }
79 };
80
81 private final CommandExecutor executor = mock(CommandExecutor.class,
82 RETURNS_SMART_NULLS);
83
84
85
86 private final TexFileUtils fileUtils = mock(TexFileUtils.class,
87 RETURNS_SMART_NULLS);
88
89
90
91
92 private final InOrder inOrder = inOrder(this.executor, this.fileUtils);
93
94 private final Settings settings = new Settings();
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124 private final LogWrapper log =
125 spy(new MavenLogWrapper(new SystemStreamLog()));
126
127 private final LatexProcessor processor = new LatexProcessor
128 (this.settings, this.executor, this.log, this.fileUtils,new PdfMojo());
129
130
131
132
133 private File texFile = new File(WORKING_DIR, "test.tex");
134 private File pdfFile = new File(WORKING_DIR, "test.pdf");
135 private File dviFile = new File(WORKING_DIR, "test.dvi");
136
137 private File dviPdfFile = new File
138 (WORKING_DIR, "test."+settings.getPdfViaDvi().getLatexOutputFormat());
139 private File htmlFile= new File(WORKING_DIR, "test.html");
140 private File auxFile = new File(WORKING_DIR, "test.aux");
141 private File logFile = new File(WORKING_DIR, "test.log");
142
143 private File bblFile = new File(WORKING_DIR, "test.bbl");
144 private File blgFile = new File(WORKING_DIR, "test.blg");
145
146 private File idxFile = new File(WORKING_DIR, "test.idx");
147 private File indFile = new File(WORKING_DIR, "test.ind");
148 private File ilgFile = new File(WORKING_DIR, "test.ilg");
149
150
151
152 private File glsFile = new File(WORKING_DIR, "test.gls");
153 private File gloFile = new File(WORKING_DIR, "test.glo");
154 private File glgFile = new File(WORKING_DIR, "test.glg");
155
156 private File xxxFile = new File(WORKING_DIR, "test");
157
158
159 private File tocFile = new File(WORKING_DIR, "test.toc");
160 private File lofFile = new File(WORKING_DIR, "test.lof");
161 private File lotFile = new File(WORKING_DIR, "test.lot");
162
163 public LatexProcessorTest() {
164
165
166
167
168 doThrow(new AssertionError("Found error. "))
169 .when(this.log).error(anyString());
170 doThrow(new AssertionError("Found warning. "))
171 .when(this.log).warn(anyString());
172 doCallRealMethod().when(this.log).info(anyString());
173 doNothing().when(this.log).debug(anyString());
174 }
175
176
177
178 private static void cleanWorkingDir() {
179 assert WORKING_DIR.isDirectory() : "Expected directory. ";
180 File[] files = WORKING_DIR.listFiles();
181 assert files != null : "Working directory is not readable. ";
182 for (File file : files) {
183 if (!file.isHidden()) {
184 file.delete();
185 }
186 }
187 }
188
189 @Before public void setUp() throws IOException {
190 cleanWorkingDir();
191
192
193 this.logFile.createNewFile();
194 this.blgFile.createNewFile();
195
196 }
197
198 @After public void tearDown() throws IOException {
199 cleanWorkingDir();
200 }
201
202
203
204 @Test public void testProcessLatexSimple() throws BuildFailureException {
205
206 mockProcessLatex2pdf(false, false, false);
207
208 this.processor.processLatex2pdf(this.texFile);
209 verifyProcessLatex2pdf(false, false, false);
210 verifyNoMoreInteractions(this.executor);
211 verifyNoMoreInteractions(this.fileUtils);
212
213 }
214
215
216 @Test public void testProcessLatexWithBibtex()
217 throws BuildFailureException {
218
219 mockProcessLatex2pdf(true, false, false);
220
221 this.processor.processLatex2pdf(this.texFile);
222 verifyProcessLatex2pdf(true, false, false);
223 verifyNoMoreInteractions(this.executor);
224 verifyNoMoreInteractions(this.fileUtils);
225
226 }
227
228
229 @Test public void testProcessLatex2html() throws BuildFailureException {
230
231 mockProcessLatex2html(false, false, false);
232
233 this.processor.processLatex2html(this.texFile);
234
235 verifyProcessLatex2html(false, false, false);
236 verifyNoMoreInteractions(this.executor);
237 verifyNoMoreInteractions(this.fileUtils);
238
239 }
240
241 private void mockProcessLatex2pdf(boolean needBibtex,
242 boolean needMakeIndex,
243 boolean needMakeGlossaries)
244 throws BuildFailureException {
245
246 mockConstrLatexMainDesc();
247 assert !this.settings.getPdfViaDvi().isViaDvi();
248
249 mockProcessLatex2devCore(needBibtex, needMakeIndex, needMakeGlossaries);
250
251 when(this.fileUtils.matchInFile(this.logFile,
252 LatexProcessor.PATTERN_OUFULL_HVBOX))
253 .thenReturn(Boolean.FALSE);
254
255 when(this.fileUtils.matchInFile(this.logFile,
256 this.settings.getPatternWarnLatex()))
257 .thenReturn(Boolean.FALSE);
258 }
259
260 private void verifyProcessLatex2pdf(boolean needBibtex,
261 boolean needMakeIndex,
262 boolean needMakeGlossary)
263 throws BuildFailureException {
264
265 verifyConstrLatexMainDesc();
266 assert !this.settings.getPdfViaDvi().isViaDvi();
267
268 verifyProcessLatex2devCore(needBibtex, needMakeIndex, needMakeGlossary);
269
270 this.inOrder.verify(this.fileUtils).matchInFile
271 (this.logFile, LatexProcessor.PATTERN_OUFULL_HVBOX);
272 this.inOrder.verify(this.fileUtils).matchInFile
273 (this.logFile, this.settings.getPatternWarnLatex());
274 }
275
276 private void mockProcessLatex2html(boolean needBibtex,
277 boolean needMakeIndex,
278 boolean needMakeGlossaries)
279 throws BuildFailureException {
280
281 mockConstrLatexMainDesc();
282 mockPreProcessLatex2dev(needBibtex, needMakeIndex, needMakeGlossaries);
283 mockRunLatex2html();
284 }
285
286 private void verifyProcessLatex2html(boolean needBibtex,
287 boolean needMakeIndex,
288 boolean needMakeGlossary)
289 throws BuildFailureException {
290
291 verifyConstrLatexMainDesc();
292 verifyPreProcessLatex2dev(needBibtex, needMakeIndex, needMakeGlossary);
293 verifyRunLatex2html();
294 }
295
296 private void mockConstrLatexMainDesc() {
297
298
299 File texFile = this.texFile;
300 when(this.fileUtils.replaceSuffix(texFile, LatexProcessor.SUFFIX_VOID))
301 .thenReturn(this.xxxFile);
302 when(this.fileUtils.replaceSuffix(texFile, LatexProcessor.SUFFIX_PDF))
303 .thenReturn(this.pdfFile);
304 when(this.fileUtils.replaceSuffix(texFile, LatexProcessor.SUFFIX_DVI))
305 .thenReturn(this.dviFile);
306 when(this.fileUtils.replaceSuffix(texFile, LatexProcessor.SUFFIX_LOG))
307 .thenReturn(this.logFile);
308
309 when(this.fileUtils.replaceSuffix(texFile, LatexProcessor.SUFFIX_IDX))
310 .thenReturn(this.idxFile);
311 when(this.fileUtils.replaceSuffix(texFile, LatexProcessor.SUFFIX_IND))
312 .thenReturn(this.indFile);
313 when(this.fileUtils.replaceSuffix(texFile, LatexProcessor.SUFFIX_ILG))
314 .thenReturn(this.ilgFile);
315
316 when(this.fileUtils.replaceSuffix(texFile, LatexProcessor.SUFFIX_GLS))
317 .thenReturn(this.glsFile);
318 when(this.fileUtils.replaceSuffix(texFile, LatexProcessor.SUFFIX_GLO))
319 .thenReturn(this.gloFile);
320 when(this.fileUtils.replaceSuffix(texFile, LatexProcessor.SUFFIX_GLG))
321 .thenReturn(this.glgFile);
322 }
323
324 private void verifyConstrLatexMainDesc() {
325
326 String[] suffixes = new String[] {
327 LatexProcessor.SUFFIX_VOID,
328 LatexProcessor.SUFFIX_PDF,
329 LatexProcessor.SUFFIX_DVI,
330 LatexProcessor.SUFFIX_LOG,
331 LatexProcessor.SUFFIX_IDX,
332 LatexProcessor.SUFFIX_IND,
333 LatexProcessor.SUFFIX_ILG,
334 LatexProcessor.SUFFIX_GLS,
335 LatexProcessor.SUFFIX_GLO,
336 LatexProcessor.SUFFIX_GLG
337 };
338 for (int idx = 0; idx < suffixes.length; idx++) {
339
340
341
342
343
344
345 verify(this.fileUtils, atLeastOnce())
346 .replaceSuffix(this.texFile, suffixes[idx]);
347 }
348 }
349
350
351
352
353 private void mockPreProcessLatex2dev(boolean needBibtex,
354 boolean needMakeIndex,
355 boolean needMakeGlossaries)
356 throws BuildFailureException {
357 assert !needMakeIndex && !needMakeGlossaries;
358
359
360 mockRunLatex();
361
362
363
364
365 mockRunBibtexByNeed(needBibtex);
366 mockRunMakeIndexByNeed(needMakeIndex);
367 mockRunMakeGlossaryByNeed(needMakeGlossaries);
368
369 if (needBibtex) {
370 return;
371 }
372
373
374
375 assert !this.tocFile.exists()
376 && !this.lofFile.exists()
377 && !this.lotFile.exists();
378
379
380 File texFile = this.texFile;
381 when(this.fileUtils.replaceSuffix(texFile, LatexProcessor.SUFFIX_TOC))
382 .thenReturn(this.tocFile);
383 when(this.fileUtils.replaceSuffix(texFile, LatexProcessor.SUFFIX_LOF))
384 .thenReturn(this.lofFile);
385 when(this.fileUtils.replaceSuffix(texFile, LatexProcessor.SUFFIX_LOT))
386 .thenReturn(this.lotFile);
387 }
388
389 private void verifyPreProcessLatex2dev(boolean needBibtex,
390 boolean needMakeIndex,
391 boolean needMakeGlossaries)
392 throws BuildFailureException {
393 assert !needMakeIndex && !needMakeGlossaries;
394
395
396 verifyRunLatex();
397
398
399 verifyRunBibtexByNeed(needBibtex);
400 verifyRunMakeIndexByNeed(needMakeIndex);
401 verifyRunMakeGlossaryByNeed(needMakeGlossaries);
402
403 if (needBibtex) {
404 return;
405 }
406
407
408
409 assert !this.tocFile.exists()
410 && !this.lofFile.exists()
411 && !this.lotFile.exists();
412
413
414
415
416
417 String[] suffixes = new String[] {
418 LatexProcessor.SUFFIX_TOC,
419 LatexProcessor.SUFFIX_LOF,
420 LatexProcessor.SUFFIX_LOT
421 };
422 for (int idx = 0; idx < suffixes.length; idx++) {
423 this.inOrder.verify(this.fileUtils)
424 .replaceSuffix(this.texFile, suffixes[idx]);
425 }
426 }
427
428
429 private void mockProcessLatex2devCore(boolean needBibtex,
430 boolean needMakeIndex,
431 boolean needMakeGlossaries)
432 throws BuildFailureException {
433
434 assert !needMakeIndex && !needMakeGlossaries;
435 assert !this.tocFile.exists()
436 && !this.lofFile.exists()
437 && !this.lotFile.exists();
438
439 assert this.settings.getMaxNumReRunsLatex() == 5;
440
441 mockPreProcessLatex2dev(needBibtex, needMakeIndex, needMakeGlossaries);
442
443
444
445
446
447
448 if (needBibtex) {
449
450 mockRunLatex();
451
452
453 mockNeedRun(false, this.settings.getPatternReRunMakeIndex());
454 mockRunLatex();
455 mockNeedRun(false, this.settings.getPatternReRunLatex());
456
457 mockNeedRun(false, this.settings.getPatternReRunMakeIndex());
458
459 } else {
460 mockNeedRun(false, this.settings.getPatternReRunLatex());
461
462 mockNeedRun(false, this.settings.getPatternReRunMakeIndex());
463
464
465 }
466 }
467
468
469 private void verifyProcessLatex2devCore(boolean needBibtex,
470 boolean needMakeIndex,
471 boolean needMakeGlossary)
472 throws BuildFailureException {
473
474 assert !needMakeIndex && !needMakeGlossary;
475 assert !this.tocFile.exists()
476 && !this.lofFile.exists()
477 && !this.lotFile.exists();
478
479 assert this.settings.getMaxNumReRunsLatex() == 5;
480
481 verifyPreProcessLatex2dev(needBibtex, needMakeIndex, needMakeGlossary);
482
483
484
485
486
487
488 if (needBibtex) {
489
490 verifyRunLatex();
491
492
493 verifyNeedRun(this.logFile,
494 this.settings.getPatternReRunMakeIndex());
495 verifyRunLatex();
496 verifyNeedRun(this.logFile,
497 this.settings.getPatternReRunLatex());
498
499 verifyNeedRun(this.logFile,
500 this.settings.getPatternReRunMakeIndex());
501
502 } else {
503 verifyNeedRun(this.logFile,
504 this.settings.getPatternReRunLatex());
505
506 verifyNeedRun(this.logFile,
507 this.settings.getPatternReRunMakeIndex());
508
509
510 }
511 }
512
513 private void mockNeedRun(Boolean retVal, String pattern)
514 throws BuildFailureException {
515
516 when(this.fileUtils.matchInFile(this.logFile, pattern))
517 .thenReturn(retVal);
518 }
519
520 private void verifyNeedRun(File file, String pattern)
521 throws BuildFailureException {
522
523
524 verify(this.fileUtils, atLeastOnce()).matchInFile(file, pattern);
525 }
526
527 private void mockRunBibtexByNeed(Boolean runBibtex)
528 throws BuildFailureException {
529
530 when(this.fileUtils.replaceSuffix
531 (this.texFile, LatexProcessor.SUFFIX_AUX))
532 .thenReturn(this.auxFile);
533 when(this.fileUtils.matchInFile
534 (this.auxFile, LatexProcessor.PATTERN_NEED_BIBTEX_RUN))
535 .thenReturn(runBibtex);
536
537
538
539 if (!runBibtex) {
540
541
542 return;
543 }
544
545
546
547 when(this.fileUtils.replaceSuffix(this.texFile,
548 LatexProcessor.SUFFIX_BBL))
549 .thenReturn(this.bblFile);
550
551
552
553
554
555
556
557
558
559
560
561 when(this.fileUtils.replaceSuffix(this.texFile,
562 LatexProcessor.SUFFIX_BLG))
563 .thenReturn(this.blgFile);
564
565 when(this.fileUtils.matchInFile(this.blgFile,
566 this.settings.getPatternErrBibtex()))
567 .thenReturn(Boolean.FALSE);
568 when(this.fileUtils.matchInFile(this.blgFile,
569 this.settings.getPatternWarnBibtex()))
570 .thenReturn(Boolean.FALSE);
571 }
572
573 private void verifyRunBibtexByNeed(Boolean runBibtex)
574 throws BuildFailureException {
575
576 this.inOrder.verify(this.fileUtils)
577 .replaceSuffix(this.texFile, LatexProcessor.SUFFIX_AUX);
578 verifyNeedRun(this.auxFile, LatexProcessor.PATTERN_NEED_BIBTEX_RUN);
579
580 if (!runBibtex) {
581 return;
582 }
583
584 this.inOrder.verify(this.fileUtils)
585 .replaceSuffix(this.texFile, LatexProcessor.SUFFIX_BBL);
586 this.inOrder.verify(this.executor)
587 .execute(eq(WORKING_DIR),
588 isNull(),
589 eq(this.settings.getBibtexCommand()),
590 aryEq(LatexProcessor.buildArguments
591 (this.settings.getBibtexOptions(), this.auxFile)),
592 eq(this.bblFile));
593
594
595 this.inOrder.verify(this.fileUtils)
596 .replaceSuffix(this.texFile, LatexProcessor.SUFFIX_BLG);
597
598 this.inOrder.verify(this.fileUtils)
599 .matchInFile(this.blgFile, this.settings.getPatternErrBibtex());
600 this.inOrder.verify(this.fileUtils)
601 .matchInFile(this.blgFile, this.settings.getPatternWarnBibtex());
602 }
603
604 private void mockRunMakeIndexByNeed(boolean runMakeIndex)
605 throws BuildFailureException {
606
607 when(this.fileUtils.getFileFilterReplace(this.idxFile, "-.+"))
608 .thenReturn(FILTER_FALSE);
609
610 when(this.fileUtils.listFilesOrWarn(WORKING_DIR, FILTER_FALSE))
611 .thenReturn(new File[0]);
612
613 assert !runMakeIndex;
614
615 if (!runMakeIndex) {
616 return;
617 }
618 mockRunMakeIndex();
619 }
620
621 private void verifyRunMakeIndexByNeed(boolean runMakeIndex)
622 throws BuildFailureException {
623
624 this.inOrder.verify(this.fileUtils)
625 .getFileFilterReplace(this.idxFile, "-.+");
626 this.inOrder.verify(this.fileUtils)
627 .listFilesOrWarn(WORKING_DIR, FILTER_FALSE);
628
629 assert !runMakeIndex;
630
631 if (!runMakeIndex) {
632 return;
633 }
634 verifyRunMakeIndex();
635 }
636
637 private void mockRunMakeIndex() throws BuildFailureException {
638 assert false;
639
640
641
642
643
644
645
646
647
648
649
650 when(this.fileUtils.matchInFile(this.ilgFile,
651 this.settings.getPatternErrMakeIndex()))
652 .thenReturn(Boolean.FALSE);
653 }
654
655 private void verifyRunMakeIndex() throws BuildFailureException {
656 assert false;
657
658 this.inOrder.verify(this.executor)
659 .execute(eq(WORKING_DIR),
660 isNull(),
661 eq(this.settings.getMakeIndexCommand()),
662 aryEq(LatexProcessor.buildArguments
663 (this.settings.getMakeIndexOptions(), this.idxFile)),
664 eq(this.indFile));
665 this.inOrder.verify(this.fileUtils)
666 .matchInFile(this.ilgFile, this.settings.getPatternErrMakeIndex());
667 }
668
669 private void mockRunMakeGlossaryByNeed(boolean runMakeGlossaries)
670 throws BuildFailureException {
671
672 assert !runMakeGlossaries;
673 if (!runMakeGlossaries) {
674 return;
675 }
676 assert false;
677
678
679
680
681
682
683
684
685
686
687
688 when(this.fileUtils.matchInFile
689 (this.glgFile, this.settings.getPatternErrMakeGlossaries()))
690 .thenReturn(Boolean.FALSE);
691 }
692
693 private void verifyRunMakeGlossaryByNeed(boolean runMakeGlossaries)
694 throws BuildFailureException {
695
696 assert !runMakeGlossaries;
697 if (!runMakeGlossaries) {
698 return;
699 }
700 assert false;
701
702 this.inOrder.verify(this.executor)
703 .execute(eq(WORKING_DIR),
704 isNull(),
705 eq(this.settings.getMakeGlossariesCommand()),
706 aryEq(LatexProcessor.buildArguments
707 (this.settings.getMakeGlossariesOptions(),
708 this.xxxFile)),
709 eq(this.glsFile));
710 this.inOrder.verify(this.fileUtils)
711 .matchInFile(this.ilgFile,
712 this.settings.getPatternErrMakeGlossaries());
713 }
714
715 private void mockRunLatex() throws BuildFailureException {
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730 when(this.fileUtils.matchInFile(this.logFile,
731 this.settings.getPatternErrLatex()))
732 .thenReturn(Boolean.FALSE);
733 }
734
735 private void verifyRunLatex() throws BuildFailureException {
736
737
738
739 verify(this.executor, atLeastOnce())
740 .execute(eq(WORKING_DIR),
741 isNull(),
742 eq(this.settings.getLatex2pdfCommand()),
743 aryEq(LatexProcessor.buildLatexArguments
744 (this.settings,
745 this.settings.getPdfViaDvi(),
746 this.texFile)),
747 eq(this.dviPdfFile));
748
749
750
751 verify(this.fileUtils, atLeastOnce())
752 .matchInFile(this.logFile, this.settings.getPatternErrLatex());
753 }
754
755 private void mockRunLatex2html() throws BuildFailureException {
756
757 when(this.fileUtils.replaceSuffix(this.texFile,
758 LatexProcessor.SUFFIX_HTML))
759 .thenReturn(this.htmlFile);
760
761
762
763
764
765
766
767
768
769
770
771 when(this.fileUtils.matchInFile(this.logFile,
772 this.settings.getPatternErrLatex()))
773 .thenReturn(Boolean.FALSE);
774 when(this.fileUtils.matchInFile(this.logFile,
775 LatexProcessor.PATTERN_OUFULL_HVBOX))
776 .thenReturn(Boolean.FALSE);
777 when(this.fileUtils.matchInFile(this.logFile,
778 this.settings.getPatternWarnLatex()))
779 .thenReturn(Boolean.FALSE);
780 }
781
782 private void verifyRunLatex2html() throws BuildFailureException {
783 this.inOrder.verify(this.fileUtils)
784 .replaceSuffix(this.texFile, LatexProcessor.SUFFIX_HTML);
785 this.inOrder.verify(this.executor)
786 .execute(eq(WORKING_DIR),
787 isNull(),
788 eq(this.settings.getTex4htCommand()),
789 aryEq(LatexProcessor.buildHtlatexArguments
790 (this.settings, this.texFile)),
791 eq(this.htmlFile));
792 String[] patterns = new String[] {
793 this.settings.getPatternErrLatex(),
794 LatexProcessor.PATTERN_OUFULL_HVBOX,
795 this.settings.getPatternWarnLatex()
796 };
797 for (int idx = 0; idx < patterns.length; idx++) {
798 this.inOrder.verify(this.fileUtils)
799 .matchInFile(this.logFile, patterns[idx]);
800 }
801 }
802 }