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> \\""); 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\">"\\""</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\">"\\`"</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\">"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\">"hello"</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 <x/y.h> 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 <vector> 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> <<a href=\"/source/s?path=abc.h\">abc.h</a>>"}, 2991161d3e8SAdam Hornacek {"#include <abc/def.h>", "#<b>include</b> <<a href=\"/source/s?path=abc/\">abc</a>/" + 3001161d3e8SAdam Hornacek "<a href=\"/source/s?path=abc/def.h\">def.h</a>>"}, 301b5840353SAdam Hornáček {"#include \"abc.h\"", "#<b>include</b> "<a href=\"/source/s?path=abc.h\">abc.h</a>""}, 3021161d3e8SAdam Hornacek {"#include \"abc/def.h\"", "#<b>include</b> "<a href=\"/source/s?path=abc/\">abc</a>/" + 3031161d3e8SAdam Hornacek "<a href=\"/source/s?path=abc/def.h\">def.h</a>""}, 304b5840353SAdam Hornáček {"#include <vector>", "#<b>include</b> <<a href=\"/source/s?path=vector\">vector</a>>"}, 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("<<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'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\">'some string'</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> << 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\">@"\\some_windows_path_in_a_string\\"</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&c=d\">" + 448b5840353SAdam Hornáček "http://www.example.com/?a=b&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