xref: /OpenGrok/opengrok-indexer/src/test/java/org/opengrok/indexer/analysis/JFlexXrefTest.java (revision 750b3115a5b8976536ee4dccce497eb97b7a4c9b)
1b5840353SAdam Hornáček /*
2b5840353SAdam Hornáček  * CDDL HEADER START
3b5840353SAdam Hornáček  *
4b5840353SAdam Hornáček  * The contents of this file are subject to the terms of the
5b5840353SAdam Hornáček  * Common Development and Distribution License (the "License").
6b5840353SAdam Hornáček  * You may not use this file except in compliance with the License.
7b5840353SAdam Hornáček  *
8b5840353SAdam Hornáček  * See LICENSE.txt included in this distribution for the specific
9b5840353SAdam Hornáček  * language governing permissions and limitations under the License.
10b5840353SAdam Hornáček  *
11b5840353SAdam Hornáček  * When distributing Covered Code, include this CDDL HEADER in each
12b5840353SAdam Hornáček  * file and include the License file at LICENSE.txt.
13b5840353SAdam Hornáček  * If applicable, add the following below this CDDL HEADER, with the
14b5840353SAdam Hornáček  * fields enclosed by brackets "[]" replaced with your own identifying
15b5840353SAdam Hornáček  * information: Portions Copyright [yyyy] [name of copyright owner]
16b5840353SAdam Hornáček  *
17b5840353SAdam Hornáček  * CDDL HEADER END
18b5840353SAdam Hornáček  */
19b5840353SAdam Hornáček 
20b5840353SAdam Hornáček /*
21c6f0939bSAdam Hornacek  * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved.
22*750b3115SChris Fraire  * Portions Copyright (c) 2017, 2021, Chris Fraire <cfraire@me.com>.
23b5840353SAdam Hornáček  */
249805b761SAdam Hornáček package org.opengrok.indexer.analysis;
25b5840353SAdam Hornáček 
26b5840353SAdam Hornáček import java.io.File;
27b5840353SAdam Hornáček import java.io.FileInputStream;
28b5840353SAdam Hornáček import java.io.IOException;
29b5840353SAdam Hornáček import java.io.InputStream;
30b5840353SAdam Hornáček import java.io.InputStreamReader;
31b5840353SAdam Hornáček import java.io.Reader;
32b5840353SAdam Hornáček import java.io.StringReader;
33b5840353SAdam Hornáček import java.io.StringWriter;
34c6f0939bSAdam Hornacek import java.nio.charset.StandardCharsets;
35b5840353SAdam Hornáček import java.util.Arrays;
36b5840353SAdam Hornáček import javax.xml.parsers.DocumentBuilderFactory;
37b5840353SAdam Hornáček import org.apache.lucene.document.Document;
3852d10766SAdam Hornacek import org.junit.jupiter.api.AfterAll;
3952d10766SAdam Hornacek import org.junit.jupiter.api.BeforeAll;
4052d10766SAdam Hornacek import org.junit.jupiter.api.Test;
419805b761SAdam Hornáček import org.opengrok.indexer.analysis.c.CXref;
429805b761SAdam Hornáček import org.opengrok.indexer.analysis.c.CxxXref;
439805b761SAdam Hornáček import org.opengrok.indexer.analysis.csharp.CSharpXref;
449805b761SAdam Hornáček import org.opengrok.indexer.analysis.document.TroffXref;
459805b761SAdam Hornáček import org.opengrok.indexer.analysis.executables.JavaClassAnalyzerFactory;
469805b761SAdam Hornáček import org.opengrok.indexer.analysis.fortran.FortranXref;
479805b761SAdam Hornáček import org.opengrok.indexer.analysis.haskell.HaskellXref;
489805b761SAdam Hornáček import org.opengrok.indexer.analysis.java.JavaXref;
499805b761SAdam Hornáček import org.opengrok.indexer.analysis.lisp.LispXref;
509805b761SAdam Hornáček import org.opengrok.indexer.analysis.perl.PerlXref;
519805b761SAdam Hornáček import org.opengrok.indexer.analysis.plain.PlainXref;
529805b761SAdam Hornáček import org.opengrok.indexer.analysis.plain.XMLXref;
539805b761SAdam Hornáček import org.opengrok.indexer.analysis.scala.ScalaXref;
549805b761SAdam Hornáček import org.opengrok.indexer.analysis.sh.ShXref;
559805b761SAdam Hornáček import org.opengrok.indexer.analysis.sql.SQLXref;
569805b761SAdam Hornáček import org.opengrok.indexer.analysis.tcl.TclXref;
579805b761SAdam Hornáček import org.opengrok.indexer.analysis.uue.UuencodeXref;
581cd4fdc4SChris Fraire 
5952d10766SAdam Hornacek import static org.junit.jupiter.api.Assertions.assertEquals;
6052d10766SAdam Hornacek import static org.junit.jupiter.api.Assertions.assertTrue;
619805b761SAdam Hornáček import static org.opengrok.indexer.util.CustomAssertions.assertLinesEqual;
629805b761SAdam Hornáček import org.opengrok.indexer.util.TestRepository;
63b5840353SAdam Hornáček import org.xml.sax.InputSource;
64b5840353SAdam Hornáček 
65b5840353SAdam Hornáček /**
66b5840353SAdam Hornáček  * Unit tests for JFlexXref.
67b5840353SAdam Hornáček  */
68b5840353SAdam Hornáček public class JFlexXrefTest {
69b5840353SAdam Hornáček 
70b5840353SAdam Hornáček     private static Ctags ctags;
71b5840353SAdam Hornáček     private static TestRepository repository;
72b5840353SAdam Hornáček 
73b5840353SAdam Hornáček     /**
74b5840353SAdam Hornáček      * This is what we expect to find at the beginning of the first line
75b5840353SAdam Hornáček      * returned by an xref.
76b5840353SAdam Hornáček      */
77b5840353SAdam Hornáček     private static final String FIRST_LINE_PREAMBLE =
78b5840353SAdam Hornáček                 "<a class=\"l\" name=\"1\" href=\"#1\">1</a>";
79b5840353SAdam Hornáček 
8052d10766SAdam Hornacek     @BeforeAll
setUpClass()81b5840353SAdam Hornáček     public static void setUpClass() throws Exception {
82b5840353SAdam Hornáček         ctags = new Ctags();
83b5840353SAdam Hornáček         repository = new TestRepository();
842bcacabbSAdam Hornacek         repository.create(JFlexXrefTest.class.getClassLoader().getResource("sources"));
85b5840353SAdam Hornáček     }
86b5840353SAdam Hornáček 
8752d10766SAdam Hornacek     @AfterAll
tearDownClass()889c92ca95SChris Fraire     public static void tearDownClass() {
89b5840353SAdam Hornáček         ctags.close();
90b5840353SAdam Hornáček         ctags = null;
91b5840353SAdam Hornáček         repository.destroy();
92b5840353SAdam Hornáček     }
93b5840353SAdam Hornáček 
94b5840353SAdam Hornáček     /**
95b5840353SAdam Hornáček      * Regression test case for bug #15890. Check that we get the expected the
96b5840353SAdam Hornáček      * expected line count from input with some special characters that used
97b5840353SAdam Hornáček      * to cause trouble.
98b5840353SAdam Hornáček      */
99b5840353SAdam Hornáček     @Test
testBug15890LineCount()1002bcacabbSAdam Hornacek     void testBug15890LineCount() throws Exception {
101b5840353SAdam Hornáček         String fileContents =
102b5840353SAdam Hornáček                 "line 1\n" +
103b5840353SAdam Hornáček                 "line 2\n" +
104b5840353SAdam Hornáček                 "line 3\n" +
105b5840353SAdam Hornáček                 "line 4 with \u000B char\n" +
106b5840353SAdam Hornáček                 "line 5 with \u000C char\n" +
107b5840353SAdam Hornáček                 "line 6 with \u0085 char\n" +
108b5840353SAdam Hornáček                 "line 7 with \u2028 char\n" +
109b5840353SAdam Hornáček                 "line 8 with \u2029 char\n" +
110b5840353SAdam Hornáček                 "line 9\n";
111b5840353SAdam Hornáček 
112b5840353SAdam Hornáček         bug15890LineCount(new JFlexXref(new CXref(new StringReader(fileContents))));
113b5840353SAdam Hornáček         bug15890LineCount(new JFlexXref(new CxxXref(new StringReader(fileContents))));
114b5840353SAdam Hornáček         bug15890LineCount(new JFlexXref(new LispXref(new StringReader(fileContents))));
115b5840353SAdam Hornáček         bug15890LineCount(new JFlexXref(new JavaXref(new StringReader(fileContents))));
116b5840353SAdam Hornáček         bug15890LineCount(new JFlexXref(new ScalaXref(new StringReader(fileContents))));
117b5840353SAdam Hornáček         bug15890LineCount(new JFlexXref(new FortranXref(new StringReader(fileContents))));
118b5840353SAdam Hornáček         bug15890LineCount(new JFlexXref(new HaskellXref(new StringReader(fileContents))));
119b5840353SAdam Hornáček         bug15890LineCount(new JFlexXref(new XMLXref(new StringReader(fileContents))));
120b5840353SAdam Hornáček         bug15890LineCount(new JFlexXref(new ShXref(new StringReader(fileContents))));
121b5840353SAdam Hornáček         bug15890LineCount(new JFlexXref(new TclXref(new StringReader(fileContents))));
122b5840353SAdam Hornáček         bug15890LineCount(new JFlexXref(new SQLXref(new StringReader(fileContents))));
123b5840353SAdam Hornáček         bug15890LineCount(new TroffXref(new StringReader(fileContents)));
124b5840353SAdam Hornáček         bug15890LineCount(new JFlexXref(new PlainXref(new StringReader(fileContents))));
125b5840353SAdam Hornáček         bug15890LineCount(new JFlexXref(new PerlXref(new StringReader(fileContents))));
126b5840353SAdam Hornáček     }
127b5840353SAdam Hornáček 
128b5840353SAdam Hornáček     /**
129b5840353SAdam Hornáček      * Helper method that checks the line count for
130b5840353SAdam Hornáček      * {@link #testBug15890LineCount()}.
131b5840353SAdam Hornáček      *
132b5840353SAdam Hornáček      * @param xref an instance of the xref class to test
133b5840353SAdam Hornáček      */
bug15890LineCount(JFlexXref xref)134b5840353SAdam Hornáček     private void bug15890LineCount(JFlexXref xref) throws Exception {
135b5840353SAdam Hornáček         final int EXP_N = 10;
136b5840353SAdam Hornáček         StringWriter out = new StringWriter();
137b5840353SAdam Hornáček         xref.write(out);
138b5840353SAdam Hornáček         if (EXP_N != xref.getLineNumber()) {
139b5840353SAdam Hornáček             System.out.println(out.toString());
14052d10766SAdam Hornacek             assertEquals(EXP_N, xref.getLineNumber(), "xref line count");
141b5840353SAdam Hornáček         }
142b5840353SAdam Hornáček     }
143b5840353SAdam Hornáček 
144b5840353SAdam Hornáček     /**
145b5840353SAdam Hornáček      * Helper method that checks the line count for
146b5840353SAdam Hornáček      * {@link #testBug15890LineCount()}.
147b5840353SAdam Hornáček      *
148b5840353SAdam Hornáček      * @param xref an instance of the xref class to test
149b5840353SAdam Hornáček      */
bug15890LineCount(JFlexNonXref xref)150b5840353SAdam Hornáček     private void bug15890LineCount(JFlexNonXref xref) throws Exception {
151b5840353SAdam Hornáček         xref.write(new StringWriter());
152b5840353SAdam Hornáček         assertEquals(10, xref.getLineNumber());
153b5840353SAdam Hornáček     }
154b5840353SAdam Hornáček 
155b5840353SAdam Hornáček     /**
156b5840353SAdam Hornáček      * Regression test case for bug #15890. Check that an anchor is correctly
157b5840353SAdam Hornáček      * inserted for definitions that appear after some special characters that
158b5840353SAdam Hornáček      * used to cause trouble.
159b5840353SAdam Hornáček      */
160b5840353SAdam Hornáček     @Test
testBug15890Anchor()1612bcacabbSAdam Hornacek     void testBug15890Anchor() throws Exception {
162b5840353SAdam Hornáček         bug15890Anchor(CXref.class, "c/bug15890.c");
163b5840353SAdam Hornáček         bug15890Anchor(CxxXref.class, "c/bug15890.c");
164b5840353SAdam Hornáček         bug15890Anchor(HaskellXref.class, "haskell/bug15890.hs");
165b5840353SAdam Hornáček         bug15890Anchor(LispXref.class, "lisp/bug15890.lisp");
166b5840353SAdam Hornáček         bug15890Anchor(JavaXref.class, "java/bug15890.java");
167b5840353SAdam Hornáček     }
168b5840353SAdam Hornáček 
169b5840353SAdam Hornáček     /**
170b5840353SAdam Hornáček      * Helper method for {@link #testBug15890Anchor()}.
171b5840353SAdam Hornáček      *
172*750b3115SChris Fraire      * @param klass the Xref subclass to test
173b5840353SAdam Hornáček      * @param path path to input file with a definition
174b5840353SAdam Hornáček      */
bug15890Anchor(Class<? extends JFlexSymbolMatcher> klass, String path)175c6f0939bSAdam Hornacek     private void bug15890Anchor(Class<? extends JFlexSymbolMatcher> klass, String path) throws Exception {
176b5840353SAdam Hornáček         File file = new File(repository.getSourceRoot() + File.separator + path);
177b5840353SAdam Hornáček         Definitions defs = ctags.doCtags(file.getAbsolutePath());
178b5840353SAdam Hornáček 
179b5840353SAdam Hornáček         // Input files contain non-ascii characters and are encoded in UTF-8
180c6f0939bSAdam Hornacek         try (Reader in = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)) {
181b5840353SAdam Hornáček 
182c6f0939bSAdam Hornacek             JFlexXref xref = new JFlexXref(klass.getConstructor(Reader.class).newInstance(in));
183b5840353SAdam Hornáček             xref.setDefs(defs);
184b5840353SAdam Hornáček 
185b5840353SAdam Hornáček             StringWriter out = new StringWriter();
186b5840353SAdam Hornáček             xref.write(out);
187b5840353SAdam Hornáček             String outstr = out.toString();
188b5840353SAdam Hornáček             boolean hasAnchor = outstr.contains("\" name=\"bug15890\"/><a href=");
18952d10766SAdam Hornacek             assertTrue(hasAnchor, "No bug15890 anchor found for " + path + ":\n" + outstr);
190b5840353SAdam Hornáček         }
191b5840353SAdam Hornáček     }
192b5840353SAdam Hornáček 
193b5840353SAdam Hornáček     /**
194b5840353SAdam Hornáček      * Regression test case for bug #14663, which used to break syntax
195b5840353SAdam Hornáček      * highlighting in ShXref.
196b5840353SAdam Hornáček      */
197b5840353SAdam Hornáček     @Test
testBug14663()1982bcacabbSAdam Hornacek     void testBug14663() throws Exception {
199b5840353SAdam Hornáček         // \" should not start a new string literal
200b5840353SAdam Hornáček         assertXrefLine(ShXref.class, "echo \\\"", "<b>echo</b> \\&quot;");
201b5840353SAdam Hornáček         // \" should not terminate a string literal
202b5840353SAdam Hornáček         assertXrefLine(ShXref.class, "echo \"\\\"\"",
203b5840353SAdam Hornáček                 "<b>echo</b> <span class=\"s\">&quot;\\&quot;&quot;</span>");
204b5840353SAdam Hornáček         // \` should not start a command substitution
205b5840353SAdam Hornáček         assertXrefLine(ShXref.class, "echo \\`", "<b>echo</b> \\`");
206b5840353SAdam Hornáček         // \` should not start command substitution inside a string
207b5840353SAdam Hornáček         assertXrefLine(ShXref.class, "echo \"\\`\"",
208b5840353SAdam Hornáček                 "<b>echo</b> <span class=\"s\">&quot;\\`&quot;</span>");
209b5840353SAdam Hornáček         // \` should not terminate command substitution
210b5840353SAdam Hornáček         assertXrefLine(ShXref.class, "echo `\\``",
211b5840353SAdam Hornáček                 "<b>echo</b> `\\``");
212b5840353SAdam Hornáček         // $# should not start a comment
213b5840353SAdam Hornáček         assertXrefLine(ShXref.class, "$#", "$#");
214b5840353SAdam Hornáček     }
215b5840353SAdam Hornáček 
216b5840353SAdam Hornáček     /**
217b5840353SAdam Hornáček      * Helper method that checks that the expected output is produced for a
218b5840353SAdam Hornáček      * line with the specified xref class. Fails if the output is not as
219b5840353SAdam Hornáček      * expected.
220b5840353SAdam Hornáček      *
221b5840353SAdam Hornáček      * @param xrefClass xref class to test
222b5840353SAdam Hornáček      * @param inputLine the source code line to parse
223b5840353SAdam Hornáček      * @param expectedOutput the expected output from the xreffer
224b5840353SAdam Hornáček      */
assertXrefLine(Class<? extends JFlexSymbolMatcher> xrefClass, String inputLine, String expectedOutput)225b5840353SAdam Hornáček     private void assertXrefLine(Class<? extends JFlexSymbolMatcher> xrefClass,
226b5840353SAdam Hornáček             String inputLine, String expectedOutput) throws Exception {
227b5840353SAdam Hornáček         JFlexXref xref = new JFlexXref(xrefClass.getConstructor(Reader.class).
228b5840353SAdam Hornáček             newInstance(new StringReader(inputLine)));
229b5840353SAdam Hornáček 
230b5840353SAdam Hornáček         StringWriter output = new StringWriter();
231b5840353SAdam Hornáček         xref.write(output);
232b5840353SAdam Hornáček 
233b5840353SAdam Hornáček         assertLinesEqual("xref " + xrefClass.getSimpleName(),
234b5840353SAdam Hornáček             FIRST_LINE_PREAMBLE + expectedOutput, output.toString());
235b5840353SAdam Hornáček     }
236b5840353SAdam Hornáček 
237b5840353SAdam Hornáček     /**
238b5840353SAdam Hornáček      * Regression test case for bug #16883. Some of the state used to survive
239b5840353SAdam Hornáček      * across invocations in ShXref, so that a syntax error in one file might
240b5840353SAdam Hornáček      * cause broken highlighting in subsequent files. Test that the instance
241b5840353SAdam Hornáček      * is properly reset now.
242b5840353SAdam Hornáček      */
243b5840353SAdam Hornáček     @Test
bug16883()2442bcacabbSAdam Hornacek     void bug16883() throws Exception {
245b5840353SAdam Hornáček         final String ECHO_QUOT_XYZ = "echo \"xyz";
246b5840353SAdam Hornáček         // Analyze a script with broken syntax (unterminated string literal)
247b5840353SAdam Hornáček         JFlexXref xref = new JFlexXref(new ShXref(
248b5840353SAdam Hornáček             new StringReader(ECHO_QUOT_XYZ)));
249b5840353SAdam Hornáček         StringWriter out = new StringWriter();
250b5840353SAdam Hornáček         xref.write(out);
251b5840353SAdam Hornáček         assertLinesEqual("Unterminated string:\n" + ECHO_QUOT_XYZ,
252b5840353SAdam Hornáček             FIRST_LINE_PREAMBLE +
253b5840353SAdam Hornáček             "<b>echo</b> <span class=\"s\">&quot;xyz</span>", out.toString());
254b5840353SAdam Hornáček 
255b5840353SAdam Hornáček         // Reuse the xref and verify that the broken syntax in the previous
256b5840353SAdam Hornáček         // file doesn't cause broken highlighting in the next file
257b5840353SAdam Hornáček         out = new StringWriter();
258b5840353SAdam Hornáček         String contents = "echo \"hello\"";
259b5840353SAdam Hornáček         xref.setReader(new StringReader(new String(contents.toCharArray())));
260b5840353SAdam Hornáček         xref.reset();
261b5840353SAdam Hornáček         xref.write(out);
262b5840353SAdam Hornáček         assertLinesEqual("reused ShXref after broken syntax",
263b5840353SAdam Hornáček             FIRST_LINE_PREAMBLE +
264b5840353SAdam Hornáček             "<b>echo</b> <span class=\"s\">&quot;hello&quot;</span>",
265b5840353SAdam Hornáček             out.toString());
266b5840353SAdam Hornáček     }
267b5840353SAdam Hornáček 
268b5840353SAdam Hornáček     /**
269b5840353SAdam Hornáček      * Test the handling of #include in C and C++. In particular, these issues
270b5840353SAdam Hornáček      * are tested:
2714a04c503SChris Fraire      * <p>
272b5840353SAdam Hornáček      * <ul>
273b5840353SAdam Hornáček      *
274b5840353SAdam Hornáček      * <li>
275b5840353SAdam Hornáček      * Verify that we use breadcrumb path for both #include &lt;x/y.h&gt; and
276b5840353SAdam Hornáček      * #include "x/y.h" in C and C++ (bug #17817)
277b5840353SAdam Hornáček      * </li>
278b5840353SAdam Hornáček      *
279b5840353SAdam Hornáček      * <li>
280b5840353SAdam Hornáček      * Verify that the link generated for #include &lt;vector&gt; performs a
281b5840353SAdam Hornáček      * path search (bug #17816)
282b5840353SAdam Hornáček      * </li>
283b5840353SAdam Hornáček      *
284b5840353SAdam Hornáček      * </ul>
285b5840353SAdam Hornáček      */
286b5840353SAdam Hornáček     @Test
testCXrefInclude()2872bcacabbSAdam Hornacek     void testCXrefInclude() throws Exception {
288b5840353SAdam Hornáček         testCXrefInclude(CXref.class);
289b5840353SAdam Hornáček     }
290b5840353SAdam Hornáček 
291b5840353SAdam Hornáček     @Test
testCxxXrefInclude()2922bcacabbSAdam Hornacek     void testCxxXrefInclude() throws Exception {
293b5840353SAdam Hornáček         testCXrefInclude(CxxXref.class);
294b5840353SAdam Hornáček     }
295b5840353SAdam Hornáček 
testCXrefInclude(Class<? extends JFlexSymbolMatcher> klass)296b5840353SAdam Hornáček     private void testCXrefInclude(Class<? extends JFlexSymbolMatcher> klass) throws Exception {
297b5840353SAdam Hornáček         String[][] testData = {
298b5840353SAdam Hornáček             {"#include <abc.h>", "#<b>include</b> &lt;<a href=\"/source/s?path=abc.h\">abc.h</a>&gt;"},
2991161d3e8SAdam Hornacek             {"#include <abc/def.h>", "#<b>include</b> &lt;<a href=\"/source/s?path=abc/\">abc</a>/" +
3001161d3e8SAdam Hornacek                     "<a href=\"/source/s?path=abc/def.h\">def.h</a>&gt;"},
301b5840353SAdam Hornáček             {"#include \"abc.h\"", "#<b>include</b> &quot;<a href=\"/source/s?path=abc.h\">abc.h</a>&quot;"},
3021161d3e8SAdam Hornacek             {"#include \"abc/def.h\"", "#<b>include</b> &quot;<a href=\"/source/s?path=abc/\">abc</a>/" +
3031161d3e8SAdam Hornacek                     "<a href=\"/source/s?path=abc/def.h\">def.h</a>&quot;"},
304b5840353SAdam Hornáček             {"#include <vector>", "#<b>include</b> &lt;<a href=\"/source/s?path=vector\">vector</a>&gt;"},
305b5840353SAdam Hornáček         };
306b5840353SAdam Hornáček 
307b5840353SAdam Hornáček         for (String[] s : testData) {
308b5840353SAdam Hornáček             StringReader in = new StringReader(s[0]);
309b5840353SAdam Hornáček             StringWriter out = new StringWriter();
310b5840353SAdam Hornáček             JFlexXref xref = new JFlexXref(klass.getConstructor(Reader.class).
311b5840353SAdam Hornáček                 newInstance(in));
312b5840353SAdam Hornáček             xref.write(out);
313b5840353SAdam Hornáček             assertEquals(FIRST_LINE_PREAMBLE + s[1], out.toString());
314b5840353SAdam Hornáček         }
315b5840353SAdam Hornáček     }
316b5840353SAdam Hornáček 
317b5840353SAdam Hornáček     /**
318b5840353SAdam Hornáček      * Verify that template parameters are treated as class names rather than
319b5840353SAdam Hornáček      * filenames.
320b5840353SAdam Hornáček      */
321b5840353SAdam Hornáček     @Test
testCxxXrefTemplateParameters()3222bcacabbSAdam Hornacek     void testCxxXrefTemplateParameters() throws Exception {
323b5840353SAdam Hornáček         StringReader in = new StringReader("#include <vector>\nclass MyClass;\nstd::vector<MyClass> *v;");
324b5840353SAdam Hornáček         StringWriter out = new StringWriter();
325b5840353SAdam Hornáček         JFlexXref xref = new JFlexXref(new CxxXref(in));
326b5840353SAdam Hornáček         xref.write(out);
32752d10766SAdam Hornacek         assertTrue(out.toString().contains("&lt;<a href=\"/source/s?defs=MyClass\""),
32852d10766SAdam Hornacek                 "Link to search for definition of class not found");
329b5840353SAdam Hornáček     }
330b5840353SAdam Hornáček 
331b5840353SAdam Hornáček     /**
332b5840353SAdam Hornáček      * Verify that ShXref handles here-documents. Bug #18198.
333b5840353SAdam Hornáček      */
334b5840353SAdam Hornáček     @Test
testShXrefHeredoc()3352bcacabbSAdam Hornacek     void testShXrefHeredoc() throws IOException {
336b5840353SAdam Hornáček         final String SH_HERE_DOC = "cat<<EOF\n" +
337b5840353SAdam Hornáček             "This shouldn't cause any problem.\n" +
338b5840353SAdam Hornáček             "EOF\n" +
339b5840353SAdam Hornáček             "var='some string'\n";
340b5840353SAdam Hornáček         StringReader in = new StringReader(
341b5840353SAdam Hornáček                 SH_HERE_DOC);
342b5840353SAdam Hornáček 
343b5840353SAdam Hornáček         JFlexXref xref = new JFlexXref(new ShXref(in));
344b5840353SAdam Hornáček         StringWriter out = new StringWriter();
345b5840353SAdam Hornáček         xref.write(out);
346b5840353SAdam Hornáček 
347b5840353SAdam Hornáček         String xout = out.toString();
348b5840353SAdam Hornáček         String[] result = xout.split("\n");
349b5840353SAdam Hornáček 
350b5840353SAdam Hornáček         // The single-quote on line 2 shouldn't start a string literal.
35152d10766SAdam Hornacek         assertTrue(result[1].endsWith("This shouldn&apos;t cause any problem."), "Line 2 of:\n" + xout);
352b5840353SAdam Hornáček 
353b5840353SAdam Hornáček         // The string literal on line 4 should be recognized as one.
35452d10766SAdam Hornacek         assertTrue(result[3].endsWith("=<span class=\"s\">&apos;some string&apos;</span>"), "Line 4 of:\n" + xout);
355b5840353SAdam Hornáček     }
356b5840353SAdam Hornáček 
357b5840353SAdam Hornáček     /**
358b5840353SAdam Hornáček      * Test that JavaXref handles empty Java comments. Bug #17885.
359b5840353SAdam Hornáček      */
360b5840353SAdam Hornáček     @Test
testEmptyJavaComment()3612bcacabbSAdam Hornacek     void testEmptyJavaComment() throws IOException {
362b5840353SAdam Hornáček         StringReader in = new StringReader("/**/\nclass xyz { }\n");
363b5840353SAdam Hornáček         JFlexXref xref = new JFlexXref(new JavaXref(in));
364b5840353SAdam Hornáček         StringWriter out = new StringWriter();
365b5840353SAdam Hornáček         xref.write(out);
366b5840353SAdam Hornáček         // Verify that the comment's <span> block is terminated.
367b5840353SAdam Hornáček         assertTrue(out.toString().contains("<span class=\"c\">/**/</span>"));
368b5840353SAdam Hornáček     }
369b5840353SAdam Hornáček 
370b5840353SAdam Hornáček     @Test
bug18586()3712bcacabbSAdam Hornacek     void bug18586() throws IOException, InterruptedException {
372b5840353SAdam Hornáček         String filename = repository.getSourceRoot() + "/sql/bug18586.sql";
373c6f0939bSAdam Hornacek         try (Reader in = new InputStreamReader(new FileInputStream(filename), StandardCharsets.UTF_8)) {
374b5840353SAdam Hornáček             JFlexXref xref = new JFlexXref(new SQLXref(in));
375b5840353SAdam Hornáček             xref.setDefs(ctags.doCtags(filename));
376b5840353SAdam Hornáček             // The next call used to fail with an ArrayIndexOutOfBoundsException.
377b5840353SAdam Hornáček             xref.write(new StringWriter());
378b5840353SAdam Hornáček         }
379c6f0939bSAdam Hornacek     }
380b5840353SAdam Hornáček 
381b5840353SAdam Hornáček     /**
382b5840353SAdam Hornáček      * Test that unterminated heredocs don't cause infinite loop in ShXref.
383b5840353SAdam Hornáček      * This originally became a problem after upgrade to JFlex 1.5.0.
384b5840353SAdam Hornáček      */
385b5840353SAdam Hornáček     @Test
unterminatedHeredoc()3862bcacabbSAdam Hornacek     void unterminatedHeredoc() throws IOException {
387b5840353SAdam Hornáček         JFlexXref xref = new JFlexXref(new ShXref(new StringReader(
388b5840353SAdam Hornáček                 "cat << EOF\nunterminated heredoc")));
389b5840353SAdam Hornáček 
390b5840353SAdam Hornáček         StringWriter out = new StringWriter();
391b5840353SAdam Hornáček 
392b5840353SAdam Hornáček         // The next call used to loop forever.
393b5840353SAdam Hornáček         xref.write(out);
394b5840353SAdam Hornáček 
395b5840353SAdam Hornáček         assertEquals("<a class=\"l\" name=\"1\" href=\"#1\">1</a>"
396b5840353SAdam Hornáček             + "<a href=\"/source/s?defs=cat\" class=\"intelliWindow-symbol\" data-definition-place=\"undefined-in-file\">cat</a> &lt;&lt; EOF"
397b5840353SAdam Hornáček             + "<span class=\"s\">\n"
398b5840353SAdam Hornáček             + "<a class=\"l\" name=\"2\" href=\"#2\">2</a>"
399b5840353SAdam Hornáček             + "unterminated heredoc</span>",
400b5840353SAdam Hornáček             out.toString());
401b5840353SAdam Hornáček     }
402b5840353SAdam Hornáček 
403b5840353SAdam Hornáček     /**
404b5840353SAdam Hornáček      * Truncated uuencoded files used to cause infinite loops. Verify that
405b5840353SAdam Hornáček      * they work now.
406b5840353SAdam Hornáček      */
407b5840353SAdam Hornáček     @Test
truncatedUuencodedFile()4082bcacabbSAdam Hornacek     void truncatedUuencodedFile() throws IOException {
409b5840353SAdam Hornáček         JFlexXref xref = new JFlexXref(new UuencodeXref(
410b5840353SAdam Hornáček                 new StringReader("begin 644 test.txt\n")));
411b5840353SAdam Hornáček 
412b5840353SAdam Hornáček         // Generating the xref used to loop forever.
413b5840353SAdam Hornáček         StringWriter out = new StringWriter();
414b5840353SAdam Hornáček         xref.write(out);
415b5840353SAdam Hornáček 
416b5840353SAdam Hornáček         assertLinesEqual("UuencodeXref truncated",
417b5840353SAdam Hornáček                 "<a class=\"l\" name=\"1\" href=\"#1\">1</a>"
418b5840353SAdam Hornáček                 + "<strong>begin</strong> <em>644</em> "
419a5cf78b2SChris Fraire                 + "<a href=\"/source/s?full=test.txt\">test.txt</a>"
420b5840353SAdam Hornáček                 + "<span class=\"c\">\n"
421b5840353SAdam Hornáček                 + "<a class=\"l\" name=\"2\" href=\"#2\">2</a></span>",
422b5840353SAdam Hornáček                 out.toString());
423b5840353SAdam Hornáček     }
424b5840353SAdam Hornáček 
425b5840353SAdam Hornáček     /**
4261161d3e8SAdam Hornacek      * Test that CSharpXref correctly handles verbatim strings that end with backslash.
427b5840353SAdam Hornáček      */
428b5840353SAdam Hornáček     @Test
testCsharpXrefVerbatimString()4292bcacabbSAdam Hornacek     void testCsharpXrefVerbatimString() throws IOException {
430b5840353SAdam Hornáček         StringReader in = new StringReader("test(@\"\\some_windows_path_in_a_string\\\");");
431b5840353SAdam Hornáček         JFlexXref xref = new JFlexXref(new CSharpXref(in));
432b5840353SAdam Hornáček         StringWriter out = new StringWriter();
433b5840353SAdam Hornáček         xref.write(out);
434b5840353SAdam Hornáček         assertTrue(out.toString().contains("<span class=\"s\">@&quot;\\some_windows_path_in_a_string\\&quot;</span>"));
435b5840353SAdam Hornáček     }
436b5840353SAdam Hornáček 
437b5840353SAdam Hornáček     /**
438b5840353SAdam Hornáček      * Test that special characters in URLs are escaped in the xref.
439b5840353SAdam Hornáček      */
440b5840353SAdam Hornáček     @Test
testEscapeLink()4412bcacabbSAdam Hornacek     void testEscapeLink() throws IOException {
442b5840353SAdam Hornáček         StringReader in = new StringReader("http://www.example.com/?a=b&c=d");
443b5840353SAdam Hornáček         JFlexXref xref = new JFlexXref(new PlainXref(in));
444b5840353SAdam Hornáček         StringWriter out = new StringWriter();
445b5840353SAdam Hornáček         xref.write(out);
446b5840353SAdam Hornáček         assertTrue(out.toString().contains(
447b5840353SAdam Hornáček                 "<a href=\"http://www.example.com/?a=b&amp;c=d\">" +
448b5840353SAdam Hornáček                 "http://www.example.com/?a=b&amp;c=d</a>"));
449b5840353SAdam Hornáček     }
450b5840353SAdam Hornáček 
451b5840353SAdam Hornáček     /**
452b5840353SAdam Hornáček      * Test that JFlex rules that contain quotes don't cause invalid xref
453b5840353SAdam Hornáček      * to be produced.
454b5840353SAdam Hornáček      */
455b5840353SAdam Hornáček     @Test
testJFlexRule()4562bcacabbSAdam Hornacek     void testJFlexRule() throws Exception {
457b5840353SAdam Hornáček         StringReader in = new StringReader("\\\" { yybegin(STRING); }");
458b5840353SAdam Hornáček         // JFlex files are usually analyzed with CAnalyzer.
459b5840353SAdam Hornáček         JFlexXref xref = new JFlexXref(new CXref(in));
460b5840353SAdam Hornáček         StringWriter out = new StringWriter();
461b5840353SAdam Hornáček         xref.write(out);
462b5840353SAdam Hornáček         // Verify that the xref is well-formed XML. Used to throw
463b5840353SAdam Hornáček         // SAXParseException: The element type "span" must be terminated
464b5840353SAdam Hornáček         // by the matching end-tag "</span>".
465b5840353SAdam Hornáček         DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(
466b5840353SAdam Hornáček                 new InputSource(new StringReader("<doc>" + out + "</doc>")));
467b5840353SAdam Hornáček     }
468b5840353SAdam Hornáček 
469b5840353SAdam Hornáček     /**
470b5840353SAdam Hornáček      * Unterminated string literals or comments made CXref produce output
471b5840353SAdam Hornáček      * that was not valid XML, due to missing end tags. Test that it is no
472b5840353SAdam Hornáček      * longer so.
473b5840353SAdam Hornáček      */
474b5840353SAdam Hornáček     @Test
testUnterminatedElements()4752bcacabbSAdam Hornacek     void testUnterminatedElements() throws Exception {
476b5840353SAdam Hornáček         for (String str : Arrays.asList("#define STR \"abc\n",
477b5840353SAdam Hornáček                                         "void f(); /* unterminated comment\n",
478b5840353SAdam Hornáček                                         "const char c = 'x\n")) {
479b5840353SAdam Hornáček             StringReader in = new StringReader(str);
480b5840353SAdam Hornáček             JFlexXref xref = new JFlexXref(new CXref(in));
481b5840353SAdam Hornáček             StringWriter out = new StringWriter();
482b5840353SAdam Hornáček             xref.write(out);
483b5840353SAdam Hornáček             // Used to throw SAXParseException.
484b5840353SAdam Hornáček             DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(
485b5840353SAdam Hornáček                 new InputSource(new StringReader("<doc>" + out + "</doc>")));
486b5840353SAdam Hornáček         }
487b5840353SAdam Hornáček     }
488b5840353SAdam Hornáček 
489b5840353SAdam Hornáček     /**
490b5840353SAdam Hornáček      * Test that JavaClassAnalyzer produces well-formed output.
491b5840353SAdam Hornáček      */
492b5840353SAdam Hornáček     @Test
testJavaClassAnalyzer()4932bcacabbSAdam Hornacek     void testJavaClassAnalyzer() throws Exception {
494b5840353SAdam Hornáček         StreamSource src = new StreamSource() {
495b5840353SAdam Hornáček             @Override public InputStream getStream() throws IOException {
496b5840353SAdam Hornáček                 final String path = "/" +
497b5840353SAdam Hornáček                     StringWriter.class.getName().replace('.', '/') +
498b5840353SAdam Hornáček                     ".class";
499b5840353SAdam Hornáček                 return StringWriter.class.getResourceAsStream(path);
500b5840353SAdam Hornáček             }
501b5840353SAdam Hornáček         };
502b5840353SAdam Hornáček         Document doc = new Document();
503b5840353SAdam Hornáček         StringWriter out = new StringWriter();
504b5840353SAdam Hornáček         JavaClassAnalyzerFactory.DEFAULT_INSTANCE.getAnalyzer().analyze(
505b5840353SAdam Hornáček             doc, src, out);
506b5840353SAdam Hornáček         // Used to throw SAXParseException.
507b5840353SAdam Hornáček         DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(
508b5840353SAdam Hornáček                 new InputSource(new StringReader("<doc>" + out + "</doc>")));
509b5840353SAdam Hornáček     }
510b5840353SAdam Hornáček 
511b5840353SAdam Hornáček     /**
512b5840353SAdam Hornáček      * Test that special characters in Fortran files are escaped.
513b5840353SAdam Hornáček      */
514b5840353SAdam Hornáček     @Test
testFortranSpecialCharacters()5152bcacabbSAdam Hornacek     void testFortranSpecialCharacters() throws Exception {
516b5840353SAdam Hornáček         JFlexXref xref = new JFlexXref(new FortranXref(
517b5840353SAdam Hornáček             new StringReader("<?php?>")));
518b5840353SAdam Hornáček         StringWriter out = new StringWriter();
519b5840353SAdam Hornáček         xref.write(out);
520b5840353SAdam Hornáček         // Used to throw SAXParseException.
521b5840353SAdam Hornáček         DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(
522b5840353SAdam Hornáček             new InputSource(new StringReader("<doc>" + out + "</doc>")));
523b5840353SAdam Hornáček     }
524b5840353SAdam Hornáček }
525