/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * See LICENSE.txt included in this distribution for the specific * language governing permissions and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at LICENSE.txt. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. */ package org.opensolaris.opengrok.analysis; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.opensolaris.opengrok.analysis.c.CXref; import org.opensolaris.opengrok.analysis.c.CxxXref; import org.opensolaris.opengrok.analysis.document.TroffXref; import org.opensolaris.opengrok.analysis.fortran.FortranXref; import org.opensolaris.opengrok.analysis.java.JavaXref; import org.opensolaris.opengrok.analysis.lisp.LispXref; import org.opensolaris.opengrok.analysis.perl.PerlXref; import org.opensolaris.opengrok.analysis.plain.PlainXref; import org.opensolaris.opengrok.analysis.plain.XMLXref; import org.opensolaris.opengrok.analysis.sh.ShXref; import org.opensolaris.opengrok.analysis.sql.SQLXref; import org.opensolaris.opengrok.analysis.tcl.TclXref; import org.opensolaris.opengrok.configuration.RuntimeEnvironment; import org.opensolaris.opengrok.util.TestRepository; import org.opensolaris.opengrok.web.Prefix; /** * Unit tests for JFlexXref. */ public class JFlexXrefTest { private static Ctags ctags; private static TestRepository repository; /** * This is what we expect to find at the beginning of the first line * returned by an xref. */ public static final String FIRST_LINE_PREAMBLE = "
"; /** the end of each line in an xref file */ public static final String LINE_SUFFIX = ""; /** the end of an xref file */ public static final String EOS = ""; @SuppressWarnings("javadoc") @BeforeClass public static void setUpClass() throws Exception { ctags = new Ctags(); ctags.setBinary(RuntimeEnvironment.getConfig().getCtags()); repository = new TestRepository(); repository.create(JFlexXrefTest.class.getResourceAsStream( "/org/opensolaris/opengrok/index/source.zip")); } @SuppressWarnings({ "javadoc", "unused" }) @AfterClass public static void tearDownClass() throws Exception { ctags.close(); ctags = null; repository.destroy(); } /** * Regression test case for bug #15890. Check that we get the expected the * expected line count from input with some special characters that used * to cause trouble. * @throws Exception */ @SuppressWarnings("static-method") @Test public void testBug15890LineCount() throws Exception { String fileContents = "line 1\n" + "line 2\n" + "line 3\n" + "line 4 with \u000B char\n" + "line 5 with \u000C char\n" + "line 6 with \u0085 char\n" + "line 7 with \u2028 char\n" + "line 8 with \u2029 char\n" + "line 9\n"; bug15890LineCount(new CXref(new StringReader(fileContents))); bug15890LineCount(new CxxXref(new StringReader(fileContents))); bug15890LineCount(new LispXref(new StringReader(fileContents))); bug15890LineCount(new JavaXref(new StringReader(fileContents))); bug15890LineCount(new FortranXref(new StringReader(fileContents))); bug15890LineCount(new XMLXref(new StringReader(fileContents))); bug15890LineCount(new ShXref(new StringReader(fileContents))); bug15890LineCount(new TclXref(new StringReader(fileContents))); bug15890LineCount(new SQLXref(new StringReader(fileContents))); bug15890LineCount(new TroffXref(new StringReader(fileContents))); bug15890LineCount(new PlainXref(new StringReader(fileContents))); bug15890LineCount(new PerlXref(new StringReader(fileContents))); } /** * Helper method that checks the line count for * {@link #testBug15890LineCount()}. * * @param xref an instance of the xref class to test */ @SuppressWarnings("resource") private static void bug15890LineCount(JFlexXref xref) throws Exception { xref.write(new XrefWriter(new StringWriter())); assertEquals(10, xref.getLineNumber()); } /** * Regression test case for bug #15890. Check that an anchor is correctly * inserted for definitions that appear after some special characters that * used to cause trouble. * @throws Exception */ @SuppressWarnings("static-method") @Test public void testBug15890Anchor() throws Exception { bug15890Anchor(CXref.class, "c/bug15890.c"); bug15890Anchor(CxxXref.class, "c/bug15890.c"); bug15890Anchor(LispXref.class, "lisp/bug15890.lisp"); bug15890Anchor(JavaXref.class, "java/bug15890.java"); } /** * Helper method for {@link #testBug15890Anchor()}. * * @param klass the Xref sub-class to test * @param path path to input file with a definition */ @SuppressWarnings("resource") private static void bug15890Anchor(Class klass, String path) throws Exception { File file = new File(repository.getSourceRoot() + File.separator + path); Definitions defs = ctags.doCtags(file.getAbsolutePath() + "\n"); // Input files contain non-ascii characters and are encoded in UTF-8 Reader in = new InputStreamReader(new FileInputStream(file), "UTF-8"); JFlexXref xref = klass.getConstructor(Reader.class).newInstance(in); xref.setDefs(defs); StringWriter out = new StringWriter(); xref.write(new XrefWriter(out)); //TODO improve below to reflect all possible classes of a definition assertTrue( "No anchor found", out.toString().contains("\" name=\"bug15890\"/>echo \\\""); // \" should not terminate a string literal assertXrefLine(ShXref.class, "echo \"\\\"\"", "echo \"\\\"\""); // \` should not start a command substitution assertXrefLine(ShXref.class, "echo \\`", "echo \\`"); // \` should not start command substitution inside a string assertXrefLine(ShXref.class, "echo \"\\`\"", "echo \"\\`\""); // \` should not terminate command substitution assertXrefLine(ShXref.class, "echo `\\``", "echo `\\``"); // $# should not start a comment assertXrefLine(ShXref.class, "$#", "$#"); } /** * Helper method that checks that the expected output is produced for a * line with the specified xref class. Fails if the output is not as * expected. * * @param xrefClass xref class to test * @param inputLine the source code line to parse * @param expectedOutput the expected output from the xreffer */ @SuppressWarnings("resource") private static void assertXrefLine(Class xrefClass, String inputLine, String expectedOutput) throws Exception { JFlexXref xref = xrefClass.getConstructor(Reader.class).newInstance( new StringReader(inputLine)); StringWriter output = new StringWriter(); xref.write(new XrefWriter(output)); assertEquals(FIRST_LINE_PREAMBLE + expectedOutput + LINE_SUFFIX + EOS, output.toString()); } /** * Regression test case for bug #16883. Some of the state used to survive * across invocations in ShXref, so that a syntax error in one file might * cause broken highlighting in subsequent files. Test that the instance * is properly reset now. * @throws Exception */ @SuppressWarnings({ "static-method", "resource" }) @Test public void bug16883() throws Exception { // Analyze a script with broken syntax (unterminated string literal) ShXref xref = new ShXref(new StringReader("echo \"xyz")); StringWriter out = new StringWriter(); xref.write(new XrefWriter(out)); assertEquals(FIRST_LINE_PREAMBLE + "echo \"xyz" + LINE_SUFFIX + EOS, out.toString()); // Reuse the xref and verify that the broken syntax in the previous // file doesn't cause broken highlighting in the next file out = new StringWriter(); String contents = "echo \"hello\""; xref.reInit(contents.toCharArray(), contents.length()); xref.write(new XrefWriter(out)); assertEquals(FIRST_LINE_PREAMBLE + "echo \"hello\"" + LINE_SUFFIX + EOS, out.toString()); } /** *

* Test the handling of #include in C and C++. In particular, these issues * are tested: *

* *
    * *
  • * Verify that we use breadcrumb path for both #include <x/y.h> and * #include "x/y.h" in C and C++ (bug #17817) *
  • * *
  • * Verify that the link generated for #include <vector> performs a * path search (bug #17816) *
  • * *
* @throws Exception */ @SuppressWarnings("static-method") @Test public void testCXrefInclude() throws Exception { testCXrefInclude(CXref.class); testCXrefInclude(CxxXref.class); } @SuppressWarnings("resource") private static void testCXrefInclude(Class klass) throws Exception { String[][] testData = { {"#include ", "#include <
abc.h>"}, {"#include ", "#include <abc/def.h>"}, {"#include \"abc.h\"", "#include \"abc.h\""}, {"#include \"abc/def.h\"", "#include \"abc/def.h\""}, {"#include ", "#include <vector>"}, }; for (String[] s : testData) { StringReader in = new StringReader(s[0]); StringWriter out = new StringWriter(); JFlexXref xref = klass.getConstructor(Reader.class).newInstance(in); xref.write(new XrefWriter(out)); assertEquals(FIRST_LINE_PREAMBLE + s[1] + LINE_SUFFIX + EOS, out.toString()); } } /** * Verify that ShXref handles here-documents. Bug #18198. * @throws IOException */ @SuppressWarnings({ "static-method", "resource" }) @Test public void testShXrefHeredoc() throws IOException { StringReader in = new StringReader( "cat<" + (LINE_SUFFIX + EOS).split("\n")[0])); // The string literal on line 4 should be recognized as one. assertTrue(result[4], result[4].endsWith("='some string'" + (LINE_SUFFIX + EOS).split("\n")[0])); } /** * Test that JavaXref handles empty Java comments. Bug #17885. * @throws IOException */ @SuppressWarnings({ "static-method", "resource" }) @Test public void testEmptyJavaComment() throws IOException { StringReader in = new StringReader("/**/\nclass xyz { }\n"); JavaXref xref = new JavaXref(in); StringWriter out = new StringWriter(); xref.write(new XrefWriter(out)); // Verify that the comment's block is terminated. assertTrue(out.toString().contains("/**/")); } @SuppressWarnings({ "static-method", "javadoc", "resource" }) @Test public void bug18586() throws IOException { String filename = repository.getSourceRoot() + "/sql/bug18586.sql"; FileInputStream fis = new FileInputStream(filename); SQLXref xref = new SQLXref(fis); xref.setDefs(ctags.doCtags(filename + "\n")); // The next call used to fail with an ArrayIndexOutOfBoundsException. xref.write(new XrefWriter(new StringWriter())); fis.close(); } }