+ * These tokens do not match required criteria because their values do not carry any
+ * information, they do not affect the xpath requests and do not help to get more accurate
+ * results. The values of these nodes are useless. No matter which class you analyze, these
+ * values are always the same.
+ * In addition, they make xpath queries more complex, less readable and less obvious.
+ * 2. Tokens for which the values differ from token names, but values are always constant.
+ * For example:
+ *
+ * These tokens are not used for the same reasons as were described in the previous part.
+ * 3. Tokens for which values are not constant. The values of these nodes are closely related
+ * to a concrete class, method, variable and so on.
+ * For example:
+ *
*
@@ -144,16 +146,13 @@ public List generate() {
}
/**
- * Returns child {@code DetailAst} element of the given root,
- * which has child element with token type equals to {@link TokenTypes#IDENT}.
+ * Returns child {@code DetailAst} element of the given root, which has value attribute.
* @param root {@code DetailAST} root ast
* @return child {@code DetailAst} element of the given root
*/
- private static DetailAST findChildWithIdent(DetailAST root) {
+ private static DetailAST findChildWithValueAttribute(DetailAST root) {
return TokenUtil.findFirstTokenByPredicate(root,
- cur -> {
- return cur.findFirstToken(TokenTypes.IDENT) != null;
- }).orElse(null);
+ XpathUtil::supportsValueAttribute).orElse(null);
}
/**
@@ -162,14 +161,65 @@ private static DetailAST findChildWithIdent(DetailAST root) {
* @return full xpath query for given ast element
*/
private static String generateXpathQuery(DetailAST ast) {
- String xpathQuery = getXpathQuery(null, ast);
- if (!isUniqueAst(ast)) {
- final DetailAST child = findChildWithIdent(ast);
- if (child != null) {
- xpathQuery += "[." + getXpathQuery(ast, child) + ']';
+ final StringBuilder xpathQueryBuilder = new StringBuilder(getXpathQuery(null, ast));
+ if (!isXpathQueryForNodeIsAccurateEnough(ast)) {
+ xpathQueryBuilder.append('[').append(findPositionAmongSiblings(ast)).append(']');
+ }
+ return xpathQueryBuilder.toString();
+ }
+
+ /**
+ * Finds position of the ast element among siblings.
+ * @param ast {@code DetailAST} ast element
+ * @return position of the ast element
+ */
+ private static int findPositionAmongSiblings(DetailAST ast) {
+ DetailAST cur = ast;
+ int pos = 0;
+ while (cur != null) {
+ if (cur.getType() == ast.getType()) {
+ pos++;
+ }
+ cur = cur.getPreviousSibling();
+ }
+ return pos;
+ }
+
+ /**
+ * Checks if ast element has all requirements to have unique xpath query.
+ * @param ast {@code DetailAST} ast element
+ * @return true if ast element will have unique xpath query, false otherwise
+ */
+ private static boolean isXpathQueryForNodeIsAccurateEnough(DetailAST ast) {
+ return !hasAtLeastOneSiblingWithSameTokenType(ast)
+ || XpathUtil.supportsValueAttribute(ast)
+ || findChildWithValueAttribute(ast) != null;
+ }
+
+ /**
+ * Checks if the given ast element has unique {@code TokenTypes} among siblings.
+ * @param ast {@code DetailAST} ast element
+ * @return if the given ast element has unique {@code TokenTypes} among siblings
+ */
+ private static boolean hasAtLeastOneSiblingWithSameTokenType(DetailAST ast) {
+ boolean result = false;
+ DetailAST prev = ast.getPreviousSibling();
+ while (prev != null) {
+ if (prev.getType() == ast.getType()) {
+ result = true;
+ break;
}
+ prev = prev.getPreviousSibling();
}
- return xpathQuery;
+ DetailAST next = ast.getNextSibling();
+ while (next != null) {
+ if (next.getType() == ast.getType()) {
+ result = true;
+ break;
+ }
+ next = next.getNextSibling();
+ }
+ return result;
}
/**
@@ -179,16 +229,14 @@ private static String generateXpathQuery(DetailAST ast) {
private List getMatchingAstElements() {
final List result = new ArrayList<>();
DetailAST curNode = rootAst;
- while (curNode != null && curNode.getLineNo() <= lineNumber) {
+ while (curNode != null) {
if (isMatchingByLineAndColumnAndTokenType(curNode)) {
result.add(curNode);
}
DetailAST toVisit = curNode.getFirstChild();
while (curNode != null && toVisit == null) {
toVisit = curNode.getNextSibling();
- if (toVisit == null) {
- curNode = curNode.getParent();
- }
+ curNode = curNode.getParent();
}
curNode = toVisit;
@@ -209,51 +257,26 @@ private static String getXpathQuery(DetailAST root, DetailAST ast) {
final StringBuilder curNodeQueryBuilder = new StringBuilder(256);
curNodeQueryBuilder.append('/')
.append(TokenUtil.getTokenName(cur.getType()));
- final DetailAST identAst = cur.findFirstToken(TokenTypes.IDENT);
- if (identAst != null) {
+ if (XpathUtil.supportsValueAttribute(cur)) {
curNodeQueryBuilder.append("[@text='")
- .append(identAst.getText())
+ .append(XpathUtil.getValue(cur))
.append("']");
}
+ else {
+ final DetailAST child = findChildWithValueAttribute(cur);
+ if (child != null && child != ast) {
+ curNodeQueryBuilder.append("[.")
+ .append(getXpathQuery(cur, child))
+ .append(']');
+ }
+ }
+
resultBuilder.insert(0, curNodeQueryBuilder);
cur = cur.getParent();
}
return resultBuilder.toString();
}
- /**
- * Checks if the given ast element has unique {@code TokenTypes} among siblings.
- * @param ast {@code DetailAST} ast element
- * @return if the given ast element has unique {@code TokenTypes} among siblings
- */
- private static boolean hasAtLeastOneSiblingWithSameTokenType(DetailAST ast) {
- boolean result = false;
- if (ast.getParent() == null) {
- DetailAST prev = ast.getPreviousSibling();
- while (prev != null) {
- if (prev.getType() == ast.getType()) {
- result = true;
- break;
- }
- prev = prev.getPreviousSibling();
- }
- if (!result) {
- DetailAST next = ast.getNextSibling();
- while (next != null) {
- if (next.getType() == ast.getType()) {
- result = true;
- break;
- }
- next = next.getNextSibling();
- }
- }
- }
- else {
- result = ast.getParent().getChildCount(ast.getType()) > 1;
- }
- return result;
- }
-
/**
* Returns the column number with tabs expanded.
* @param ast {@code DetailAST} root ast
@@ -275,18 +298,4 @@ private boolean isMatchingByLineAndColumnAndTokenType(DetailAST ast) {
&& expandedTabColumn(ast) == columnNumber
&& (tokenType == 0 || tokenType == ast.getType());
}
-
- /**
- * To be sure that generated xpath query will return exactly required ast element, the element
- * should be checked for uniqueness. If ast element has {@link TokenTypes#IDENT} as the child
- * or there is no sibling with the same {@code TokenTypes} then element is supposed to be
- * unique. This method finds if {@code DetailAst} element is unique.
- * @param ast {@code DetailAST} ast element
- * @return if {@code DetailAst} element is unique
- */
- private static boolean isUniqueAst(DetailAST ast) {
- return ast.findFirstToken(TokenTypes.IDENT) != null
- || !hasAtLeastOneSiblingWithSameTokenType(ast);
- }
-
}
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/MainTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/MainTest.java
index 273251973bb3..6fd4112a5492 100644
--- a/src/test/java/com/puppycrawl/tools/checkstyle/MainTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/MainTest.java
@@ -808,9 +808,11 @@ public void testPrintTreeJavadocOption() throws Exception {
@Test
public void testPrintSuppressionOption() throws Exception {
- final String expected = "/CLASS_DEF[@text='InputMainSuppressionsStringPrinter']" + EOL
- + "/CLASS_DEF[@text='InputMainSuppressionsStringPrinter']/MODIFIERS" + EOL
- + "/CLASS_DEF[@text='InputMainSuppressionsStringPrinter']/LITERAL_CLASS" + EOL;
+ final String expected = "/CLASS_DEF[./IDENT[@text='InputMainSuppressionsStringPrinter']]"
+ + EOL
+ + "/CLASS_DEF[./IDENT[@text='InputMainSuppressionsStringPrinter']]/MODIFIERS" + EOL
+ + "/CLASS_DEF[./IDENT[@text='InputMainSuppressionsStringPrinter']]/LITERAL_CLASS"
+ + EOL;
exit.checkAssertionAfterwards(() -> {
assertEquals("Unexpected output log",
@@ -824,14 +826,19 @@ public void testPrintSuppressionOption() throws Exception {
@Test
public void testPrintSuppressionAndTabWidthOption() throws Exception {
- final String expected = "/CLASS_DEF[@text='InputMainSuppressionsStringPrinter']/OBJBLOCK"
- + "/METHOD_DEF[@text='getName']/SLIST/VARIABLE_DEF[@text='var']" + EOL
- + "/CLASS_DEF[@text='InputMainSuppressionsStringPrinter']/OBJBLOCK"
- + "/METHOD_DEF[@text='getName']/SLIST/VARIABLE_DEF[@text='var']/MODIFIERS" + EOL
- + "/CLASS_DEF[@text='InputMainSuppressionsStringPrinter']/OBJBLOCK"
- + "/METHOD_DEF[@text='getName']/SLIST/VARIABLE_DEF[@text='var']/TYPE" + EOL
- + "/CLASS_DEF[@text='InputMainSuppressionsStringPrinter']/OBJBLOCK"
- + "/METHOD_DEF[@text='getName']/SLIST/VARIABLE_DEF[@text='var']/TYPE/LITERAL_INT"
+ final String expected = "/CLASS_DEF[./IDENT[@text='InputMainSuppressionsStringPrinter']]"
+ + "/OBJBLOCK"
+ + "/METHOD_DEF[./IDENT[@text='getName']]/SLIST/VARIABLE_DEF[./IDENT[@text='var']]"
+ + EOL
+ + "/CLASS_DEF[./IDENT[@text='InputMainSuppressionsStringPrinter']]/OBJBLOCK"
+ + "/METHOD_DEF[./IDENT[@text='getName']]/SLIST/VARIABLE_DEF[./IDENT[@text='var']]"
+ + "/MODIFIERS" + EOL
+ + "/CLASS_DEF[./IDENT[@text='InputMainSuppressionsStringPrinter']]/OBJBLOCK"
+ + "/METHOD_DEF[./IDENT[@text='getName']]/SLIST/VARIABLE_DEF[./IDENT[@text='var']]"
+ + "/TYPE" + EOL
+ + "/CLASS_DEF[./IDENT[@text='InputMainSuppressionsStringPrinter']]/OBJBLOCK"
+ + "/METHOD_DEF[./IDENT[@text='getName']]/SLIST/VARIABLE_DEF[./IDENT[@text='var']]"
+ + "/TYPE/LITERAL_INT"
+ EOL;
exit.checkAssertionAfterwards(() -> {
@@ -920,81 +927,81 @@ public void testGenerateXpathSuppressionOptionOne() throws Exception {
+ "" + EOL
+ + " query=\"/CLASS_DEF[./IDENT[@text='InputMainComplexityOverflow']]/OBJBLOCK"
+ + "/METHOD_DEF[./IDENT[@text='provokeNpathIntegerOverflow']]\"/>" + EOL
+ "" + EOL
+ + " query=\"/CLASS_DEF[./IDENT[@text='InputMainComplexityOverflow']]/OBJBLOCK"
+ + "/METHOD_DEF[./IDENT[@text='provokeNpathIntegerOverflow']]/SLIST\"/>" + EOL
+ "" + EOL
+ "" + EOL
+ "" + EOL
+ "" + EOL
+ "" + EOL
+ "" + EOL
+ "" + EOL
+ "" + EOL
+ "" + EOL
+ "" + EOL
+ "" + EOL;
@@ -1020,18 +1027,20 @@ public void testGenerateXpathSuppressionOptionTwo() throws Exception {
+ "" + EOL
+ + " query=\"/CLASS_DEF[./IDENT[@text='InputMainGenerateXpathSuppressions']]"
+ + "/OBJBLOCK/VARIABLE_DEF/IDENT[@text='low']\"/>" + EOL
+ "" + EOL
+ + " query=\"/CLASS_DEF[./IDENT[@text='InputMainGenerateXpathSuppressions']]"
+ + "/OBJBLOCK/METHOD_DEF[./IDENT[@text='test']]/LITERAL_THROWS"
+ + "/IDENT[@text='RuntimeException']\"/>" + EOL
+ "" + EOL
+ "" + EOL;
@@ -1072,8 +1081,9 @@ public void testGenerateXpathSuppressionOptionDefaultTabWidth() throws Exception
+ "" + EOL
+ + " query=\"/CLASS_DEF[./IDENT["
+ + "@text='InputMainGenerateXpathSuppressionsTabWidth']]"
+ + "/OBJBLOCK/VARIABLE_DEF/IDENT[@text='low']\"/>" + EOL
+ "" + EOL;
exit.checkAssertionAfterwards(() -> {
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/SuppressionsStringPrinterTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/SuppressionsStringPrinterTest.java
index 939406373a14..f4e1dbc219be 100644
--- a/src/test/java/com/puppycrawl/tools/checkstyle/SuppressionsStringPrinterTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/SuppressionsStringPrinterTest.java
@@ -47,10 +47,10 @@ public void testIsProperUtilsClass() throws ReflectiveOperationException {
@Test
public void testCorrect() throws Exception {
- final String expected = "/CLASS_DEF[@text='InputSuppressionsStringPrinter']" + EOL
- + "/CLASS_DEF[@text='InputSuppressionsStringPrinter']/MODIFIERS" + EOL
- + "/CLASS_DEF[@text='InputSuppressionsStringPrinter']/MODIFIERS/LITERAL_PUBLIC"
- + EOL;
+ final String expected = "/CLASS_DEF[./IDENT[@text='InputSuppressionsStringPrinter']]" + EOL
+ + "/CLASS_DEF[./IDENT[@text='InputSuppressionsStringPrinter']]/MODIFIERS" + EOL
+ + "/CLASS_DEF[./IDENT[@text='InputSuppressionsStringPrinter']]/MODIFIERS"
+ + "/LITERAL_PUBLIC" + EOL;
final File input = new File(getPath("InputSuppressionsStringPrinter.java"));
final String lineAndColumnNumber = "3:1";
@@ -64,12 +64,12 @@ public void testCorrect() throws Exception {
@Test
public void testCustomTabWidth() throws Exception {
- final String expected = "/CLASS_DEF[@text='InputSuppressionsStringPrinter']/OBJBLOCK"
- + "/METHOD_DEF[@text='toString']" + EOL
- + "/CLASS_DEF[@text='InputSuppressionsStringPrinter']/OBJBLOCK"
- + "/METHOD_DEF[@text='toString']/MODIFIERS" + EOL
- + "/CLASS_DEF[@text='InputSuppressionsStringPrinter']/OBJBLOCK"
- + "/METHOD_DEF[@text='toString']/MODIFIERS/LITERAL_PUBLIC" + EOL;
+ final String expected = "/CLASS_DEF[./IDENT[@text='InputSuppressionsStringPrinter']]"
+ + "/OBJBLOCK/METHOD_DEF[./IDENT[@text='toString']]" + EOL
+ + "/CLASS_DEF[./IDENT[@text='InputSuppressionsStringPrinter']]/OBJBLOCK"
+ + "/METHOD_DEF[./IDENT[@text='toString']]/MODIFIERS" + EOL
+ + "/CLASS_DEF[./IDENT[@text='InputSuppressionsStringPrinter']]/OBJBLOCK"
+ + "/METHOD_DEF[./IDENT[@text='toString']]/MODIFIERS/LITERAL_PUBLIC" + EOL;
final File input = new File(getPath("InputSuppressionsStringPrinter.java"));
final String lineAndColumnNumber = "5:13";
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/XpathFileGeneratorAstFilterTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/XpathFileGeneratorAstFilterTest.java
index 3675eefae3ba..1c2b3edf942f 100644
--- a/src/test/java/com/puppycrawl/tools/checkstyle/XpathFileGeneratorAstFilterTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/XpathFileGeneratorAstFilterTest.java
@@ -68,7 +68,25 @@ public void test() throws Exception {
getPath("InputXpathFileGeneratorAstFilter.java"), message);
Assert.assertEquals("expected xpath",
- "/CLASS_DEF[@text='InputXpathFileGeneratorAstFilter']/OBJBLOCK/LCURLY",
+ "/CLASS_DEF[./IDENT[@text='InputXpathFileGeneratorAstFilter']]/OBJBLOCK/LCURLY",
+ XpathFileGeneratorAstFilter.findCorrespondingXpathQuery(auditEvent));
+ }
+
+ @Test
+ public void testNoXpathQuery() throws Exception {
+ final LocalizedMessage message = new LocalizedMessage(10, 10, TokenTypes.LCURLY,
+ "messages.properties", null, null, SeverityLevel.ERROR, null, LeftCurlyCheck.class,
+ null);
+ final TreeWalkerAuditEvent event = createTreeWalkerAuditEvent(
+ "InputXpathFileGeneratorAstFilter.java", message);
+ final XpathFileGeneratorAstFilter filter = new XpathFileGeneratorAstFilter();
+
+ Assert.assertTrue("filter accepted", filter.accept(event));
+
+ final AuditEvent auditEvent = new AuditEvent(this,
+ getPath("InputXpathFileGeneratorAstFilter.java"), message);
+
+ Assert.assertNull("expected null",
XpathFileGeneratorAstFilter.findCorrespondingXpathQuery(auditEvent));
}
@@ -88,8 +106,8 @@ public void testTabWidth() throws Exception {
getPath("InputXpathFileGeneratorAstFilter.java"), message);
Assert.assertEquals("expected xpath",
- "/CLASS_DEF[@text='InputXpathFileGeneratorAstFilter']/OBJBLOCK"
- + "/METHOD_DEF[@text='tabMethod']/SLIST/LITERAL_RETURN",
+ "/CLASS_DEF[./IDENT[@text='InputXpathFileGeneratorAstFilter']]/OBJBLOCK"
+ + "/METHOD_DEF[./IDENT[@text='tabMethod']]/SLIST/LITERAL_RETURN",
XpathFileGeneratorAstFilter.findCorrespondingXpathQuery(auditEvent));
}
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/XpathFileGeneratorAuditListenerTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/XpathFileGeneratorAuditListenerTest.java
index 0d2b4f472073..29af89e5555f 100644
--- a/src/test/java/com/puppycrawl/tools/checkstyle/XpathFileGeneratorAuditListenerTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/XpathFileGeneratorAuditListenerTest.java
@@ -43,6 +43,7 @@
import com.puppycrawl.tools.checkstyle.checks.coding.NestedForDepthCheck;
import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocVariableCheck;
import com.puppycrawl.tools.checkstyle.checks.whitespace.MethodParamPadCheck;
+import com.puppycrawl.tools.checkstyle.internal.utils.CloseAndFlushTestByteArrayOutputStream;
public class XpathFileGeneratorAuditListenerTest {
@@ -61,6 +62,14 @@ public class XpathFileGeneratorAuditListenerTest {
private static final LocalizedMessage FOURTH_MESSAGE = createLocalizedMessage(5, 5,
TokenTypes.VARIABLE_DEF, "JavadocModuleId", JavadocVariableCheck.class);
+ /**
+ * Output stream to hold the test results. The IntelliJ IDEA issues the AutoCloseableResource
+ * warning here, so it need to be suppressed. The {@code ByteArrayOutputStream} does not hold
+ * any resources that need to be released.
+ */
+ private final CloseAndFlushTestByteArrayOutputStream outStream =
+ new CloseAndFlushTestByteArrayOutputStream();
+
@BeforeClass
public static void constructEvents() throws Exception {
final TreeWalkerAuditEvent event1 = createTreeWalkerAuditEvent(
@@ -157,8 +166,8 @@ public void testCorrectOne() {
+ " files=\"InputXpathFileGeneratorAuditListener.java\"" + EOL
+ " checks=\"LeftCurlyCheck\""
+ EOL
- + " query=\"/CLASS_DEF[@text='InputXpathFileGeneratorAuditListener']/OBJBLOCK"
- + "/LCURLY\"/>" + EOL
+ + " query=\"/CLASS_DEF[./IDENT[@text='InputXpathFileGeneratorAuditListener']]"
+ + "/OBJBLOCK/LCURLY\"/>" + EOL
+ "" + EOL;
verifyOutput(expected, event);
@@ -182,13 +191,14 @@ public void testCorrectTwo() {
+ "" + EOL
+ + " query=\"/CLASS_DEF[./IDENT[@text='InputXpathFileGeneratorAuditListener']]"
+ + "/OBJBLOCK/METHOD_DEF[./IDENT[@text='sort']]\"/>" + EOL
+ "" + EOL
+ + " query=\"/CLASS_DEF[./IDENT[@text='InputXpathFileGeneratorAuditListener']]"
+ + "/OBJBLOCK/METHOD_DEF[./IDENT[@text='sort']]/SLIST/LITERAL_FOR/SLIST"
+ + "/LITERAL_FOR\"/>" + EOL
+ "" + EOL;
verifyOutput(expected, event1, event2);
@@ -215,13 +225,37 @@ public void testOnlyOneMatching() {
+ "" + EOL
+ + " query=\"/CLASS_DEF[./IDENT[@text='InputXpathFileGeneratorAuditListener']]"
+ + "/OBJBLOCK/VARIABLE_DEF[./IDENT[@text='isValid']]\"/>" + EOL
+ "" + EOL;
verifyOutput(expected, event1, event2, event3);
}
+ @Test
+ public void testCloseStream() {
+ final XpathFileGeneratorAuditListener listener =
+ new XpathFileGeneratorAuditListener(outStream,
+ AutomaticBean.OutputStreamOptions.CLOSE);
+ listener.finishLocalSetup();
+ listener.auditStarted(null);
+ listener.auditFinished(null);
+
+ assertEquals("Invalid close count", 1, outStream.getCloseCount());
+ }
+
+ @Test
+ public void testNoCloseStream() {
+ final XpathFileGeneratorAuditListener listener =
+ new XpathFileGeneratorAuditListener(outStream,
+ AutomaticBean.OutputStreamOptions.NONE);
+ listener.finishLocalSetup();
+ listener.auditStarted(null);
+ listener.auditFinished(null);
+
+ assertEquals("Invalid close count", 0, outStream.getCloseCount());
+ }
+
private AuditEvent createAuditEvent(String fileName, int lineNumber, int columnNumber,
Class> sourceClass) {
final LocalizedMessage message =
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/filters/SuppressionXpathSingleFilterTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/filters/SuppressionXpathSingleFilterTest.java
index b97e83d421fa..052feaf239cb 100644
--- a/src/test/java/com/puppycrawl/tools/checkstyle/filters/SuppressionXpathSingleFilterTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/filters/SuppressionXpathSingleFilterTest.java
@@ -57,7 +57,7 @@ protected String getPackageLocation() {
@Test
public void testMatching() throws Exception {
- final String xpath = "/CLASS_DEF[@text='InputSuppressionXpathSingleFilter']";
+ final String xpath = "/CLASS_DEF[./IDENT[@text='InputSuppressionXpathSingleFilter']]";
final SuppressionXpathSingleFilter filter =
createSuppressionXpathSingleFilter("InputSuppressionXpathSingleFilter", "Test",
null, null, xpath);
@@ -101,9 +101,9 @@ public void testNonMatchingColumnNumber() throws Exception {
@Test
public void testComplexQuery() throws Exception {
- final String xpath = "//VARIABLE_DEF[@text='pi' and "
- + "../..[@text='countTokens']] "
- + "| //VARIABLE_DEF[@text='someVariable' and ../..[@text='sum']]";
+ final String xpath = "//VARIABLE_DEF[./IDENT[@text='pi'] and "
+ + "../../IDENT[@text='countTokens']] "
+ + "| //VARIABLE_DEF[./IDENT[@text='someVariable'] and ../../IDENT[@text='sum']]";
final SuppressionXpathSingleFilter filter =
createSuppressionXpathSingleFilter("InputSuppressionXpathSingleFilter", "Test",
null, null, xpath);
@@ -193,7 +193,7 @@ public void testNonMatchingModuleId() throws Exception {
@Test
public void testMatchingModuleId() throws Exception {
- final String xpath = "/CLASS_DEF[@text='InputSuppressionXpathSingleFilter']";
+ final String xpath = "/CLASS_DEF[./IDENT[@text='InputSuppressionXpathSingleFilter']]";
final SuppressionXpathSingleFilter filter =
createSuppressionXpathSingleFilter("InputSuppressionXpathSingleFilter", "Test",
null, "id19", xpath);
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/filters/XpathFilterElementTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/filters/XpathFilterElementTest.java
index c259f5b96c8c..4a5290a28ad6 100644
--- a/src/test/java/com/puppycrawl/tools/checkstyle/filters/XpathFilterElementTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/filters/XpathFilterElementTest.java
@@ -61,7 +61,7 @@ protected String getPackageLocation() {
@Test
public void testMatching() throws Exception {
- final String xpath = "/CLASS_DEF[@text='InputXpathFilterElementSuppressByXpath']";
+ final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathFilterElementSuppressByXpath']]";
final XpathFilterElement filter = new XpathFilterElement(
"InputXpathFilterElementSuppressByXpath", "Test", null, null, xpath);
final TreeWalkerAuditEvent ev = getEvent(3, 0,
@@ -71,7 +71,7 @@ public void testMatching() throws Exception {
@Test
public void testNonMatchingTokenType() throws Exception {
- final String xpath = "//METHOD_DEF[@text='countTokens']";
+ final String xpath = "//METHOD_DEF[./IDENT[@text='countTokens']]";
final XpathFilterElement filter = new XpathFilterElement(
"InputXpathFilterElementSuppressByXpath", "Test", null, null, xpath);
final TreeWalkerAuditEvent ev = getEvent(3, 0,
@@ -81,7 +81,7 @@ public void testNonMatchingTokenType() throws Exception {
@Test
public void testNonMatchingLineNumber() throws Exception {
- final String xpath = "/CLASS_DEF[@text='InputXpathFilterElementSuppressByXpath']";
+ final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathFilterElementSuppressByXpath']]";
final XpathFilterElement filter = new XpathFilterElement(
"InputXpathFilterElementSuppressByXpath", "Test", null, null, xpath);
final TreeWalkerAuditEvent ev = getEvent(100, 0,
@@ -91,7 +91,7 @@ public void testNonMatchingLineNumber() throws Exception {
@Test
public void testNonMatchingColumnNumber() throws Exception {
- final String xpath = "/CLASS_DEF[@text='InputXpathFilterElementSuppressByXpath']";
+ final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathFilterElementSuppressByXpath']]";
final XpathFilterElement filter = new XpathFilterElement(
"InputXpathFilterElementSuppressByXpath", "Test", null, null, xpath);
final TreeWalkerAuditEvent ev = getEvent(3, 100,
@@ -101,9 +101,9 @@ public void testNonMatchingColumnNumber() throws Exception {
@Test
public void testComplexQuery() throws Exception {
- final String xpath = "//VARIABLE_DEF[@text='pi' and "
- + "../..[@text='countTokens']] "
- + "| //VARIABLE_DEF[@text='someVariable' and ../..[@text='sum']]";
+ final String xpath = "//VARIABLE_DEF[./IDENT[@text='pi'] and "
+ + "../../IDENT[@text='countTokens']] "
+ + "| //VARIABLE_DEF[./IDENT[@text='someVariable'] and ../../IDENT[@text='sum']]";
final XpathFilterElement filter = new XpathFilterElement(
"InputXpathFilterElementSuppressByXpath", "Test", null, null, xpath);
final TreeWalkerAuditEvent eventOne = getEvent(5, 8,
@@ -185,7 +185,7 @@ public void testNonMatchingModuleId() throws Exception {
@Test
public void testMatchingModuleId() throws Exception {
- final String xpath = "/CLASS_DEF[@text='InputXpathFilterElementSuppressByXpath']";
+ final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathFilterElementSuppressByXpath']]";
final XpathFilterElement filter = new XpathFilterElement(
"InputXpathFilterElementSuppressByXpath", "Test", null, "id19", xpath);
final LocalizedMessage message =
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/utils/XpathUtilTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/utils/XpathUtilTest.java
new file mode 100644
index 000000000000..28e7193ad928
--- /dev/null
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/utils/XpathUtilTest.java
@@ -0,0 +1,85 @@
+////////////////////////////////////////////////////////////////////////////////
+// checkstyle: Checks Java source code for adherence to a set of rules.
+// Copyright (C) 2001-2019 the original author or authors.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+////////////////////////////////////////////////////////////////////////////////
+
+package com.puppycrawl.tools.checkstyle.utils;
+
+import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.isUtilsClassHasPrivateConstructor;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+import com.puppycrawl.tools.checkstyle.api.DetailAST;
+import com.puppycrawl.tools.checkstyle.api.TokenTypes;
+
+public class XpathUtilTest {
+
+ @Test
+ public void testIsProperUtilsClass() throws ReflectiveOperationException {
+ assertTrue("Constructor is not private",
+ isUtilsClassHasPrivateConstructor(XpathUtil.class, true));
+ }
+
+ @Test
+ public void testSupportsValueAttribute() {
+ assertTrue("Should return true for supported token typs",
+ XpathUtil.supportsValueAttribute(createDetailAST(TokenTypes.IDENT)));
+ assertTrue("Should return true for supported token typs",
+ XpathUtil.supportsValueAttribute(createDetailAST(TokenTypes.NUM_INT)));
+ assertTrue("Should return true for supported token typs",
+ XpathUtil.supportsValueAttribute(createDetailAST(TokenTypes.STRING_LITERAL)));
+ assertTrue("Should return true for supported token typs",
+ XpathUtil.supportsValueAttribute(createDetailAST(TokenTypes.CHAR_LITERAL)));
+ assertTrue("Should return true for supported token typs",
+ XpathUtil.supportsValueAttribute(createDetailAST(TokenTypes.NUM_DOUBLE)));
+ assertFalse("Should return false for unsupported token typs",
+ XpathUtil.supportsValueAttribute(createDetailAST(TokenTypes.VARIABLE_DEF)));
+ assertFalse("Should return false for unsupported token typs",
+ XpathUtil.supportsValueAttribute(createDetailAST(TokenTypes.OBJBLOCK)));
+ assertFalse("Should return true for supported token typs",
+ XpathUtil.supportsValueAttribute(createDetailAST(TokenTypes.LITERAL_CHAR)));
+ }
+
+ @Test
+ public void testGetValue() {
+ assertEquals("Returned value differs from expected", "HELLO WORLD",
+ XpathUtil.getValue(createDetailAST(TokenTypes.STRING_LITERAL, "\"HELLO WORLD\"")));
+ assertEquals("Returned value differs from expected", "123",
+ XpathUtil.getValue(createDetailAST(TokenTypes.NUM_INT, "123")));
+ assertEquals("Returned value differs from expected", "HELLO WORLD",
+ XpathUtil.getValue(createDetailAST(TokenTypes.IDENT, "HELLO WORLD")));
+ assertNotEquals("Returned value differs from expected", "HELLO WORLD",
+ XpathUtil.getValue(createDetailAST(TokenTypes.STRING_LITERAL, "HELLO WORLD")));
+ }
+
+ private static DetailAST createDetailAST(int type) {
+ final DetailAST detailAST = new DetailAST();
+ detailAST.setType(type);
+ return detailAST;
+ }
+
+ private static DetailAST createDetailAST(int type, String text) {
+ final DetailAST detailAST = new DetailAST();
+ detailAST.setType(type);
+ detailAST.setText(text);
+ return detailAST;
+ }
+}
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/xpath/ElementNodeTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/xpath/ElementNodeTest.java
index c9d57a333001..ce956ee84309 100644
--- a/src/test/java/com/puppycrawl/tools/checkstyle/xpath/ElementNodeTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/xpath/ElementNodeTest.java
@@ -21,6 +21,7 @@
import static com.puppycrawl.tools.checkstyle.internal.utils.XpathUtil.getXpathItems;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
@@ -33,7 +34,12 @@
import com.puppycrawl.tools.checkstyle.JavaParser;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
+import net.sf.saxon.om.AxisInfo;
import net.sf.saxon.om.NodeInfo;
+import net.sf.saxon.tree.iter.ArrayIterator;
+import net.sf.saxon.tree.iter.AxisIterator;
+import net.sf.saxon.tree.iter.EmptyIterator;
+import net.sf.saxon.tree.util.Navigator;
public class ElementNodeTest extends AbstractPathTestSupport {
@@ -71,4 +77,91 @@ public void testRootOfElementNode() throws Exception {
root instanceof RootNode);
}
+ @Test
+ public void testGetNodeByValueNumInt() throws Exception {
+ final String xPath = "//NUM_INT[@text = 123]";
+ final List nodes = getXpathItems(xPath, rootNode);
+ assertEquals("Invalid number of nodes", 1, nodes.size());
+ assertEquals("Invalid token type", TokenTypes.NUM_INT,
+ ((AbstractNode) nodes.get(0)).getTokenType());
+ }
+
+ @Test
+ public void testGetNodeByValueStringLiteral() throws Exception {
+ final String xPath = "//STRING_LITERAL[@text = 'HelloWorld']";
+ final List nodes = getXpathItems(xPath, rootNode);
+ assertEquals("Invalid number of nodes", 2, nodes.size());
+ assertEquals("Invalid token type", TokenTypes.STRING_LITERAL,
+ ((AbstractNode) nodes.get(0)).getTokenType());
+ }
+
+ @Test
+ public void testGetNodeByValueWithSameTokenText() throws Exception {
+ final String xPath = "//MODIFIERS[@text = 'MODIFIERS']";
+ final List nodes = getXpathItems(xPath, rootNode);
+ assertEquals("Invalid number of nodes", 0, nodes.size());
+ }
+
+ @Test
+ public void testGetAttributeValue() {
+ final DetailAST detailAST = new DetailAST();
+ detailAST.setType(TokenTypes.IDENT);
+ detailAST.setText("HelloWorld");
+
+ final ElementNode elementNode = new ElementNode(rootNode, rootNode, detailAST);
+
+ assertEquals("Invalid text attribute", "HelloWorld",
+ elementNode.getAttributeValue(null, "text"));
+ }
+
+ @Test
+ public void testGetAttributeValueNoAttribute() {
+ final DetailAST detailAST = new DetailAST();
+ detailAST.setType(TokenTypes.CLASS_DEF);
+ detailAST.setText("HelloWorld");
+
+ final ElementNode elementNode = new ElementNode(rootNode, rootNode, detailAST);
+
+ assertNull("Must be null", elementNode.getAttributeValue(null, "text"));
+ }
+
+ @Test
+ public void testGetAttributeValueWrongAttribute() {
+ final DetailAST detailAST = new DetailAST();
+ detailAST.setType(TokenTypes.IDENT);
+ detailAST.setText("HelloWorld");
+
+ final ElementNode elementNode = new ElementNode(rootNode, rootNode, detailAST);
+
+ assertNull("Must be null", elementNode.getAttributeValue(null, "wroooong"));
+ }
+
+ @Test
+ public void testIterateAxisEmptyChildren() {
+ final DetailAST detailAST = new DetailAST();
+ detailAST.setType(TokenTypes.METHOD_DEF);
+ final ElementNode elementNode = new ElementNode(rootNode, null, detailAST);
+ try (AxisIterator iterator = elementNode.iterateAxis(AxisInfo.CHILD)) {
+ assertTrue("Invalid iterator", iterator instanceof EmptyIterator);
+ }
+ try (AxisIterator iterator = elementNode.iterateAxis(AxisInfo.DESCENDANT)) {
+ assertTrue("Invalid iterator", iterator instanceof EmptyIterator);
+ }
+ }
+
+ @Test
+ public void testIterateAxisWithChildren() {
+ final DetailAST detailAST = new DetailAST();
+ detailAST.setType(TokenTypes.METHOD_DEF);
+ final DetailAST childAst = new DetailAST();
+ childAst.setType(TokenTypes.VARIABLE_DEF);
+ detailAST.addChild(childAst);
+ final ElementNode elementNode = new ElementNode(rootNode, null, detailAST);
+ try (AxisIterator iterator = elementNode.iterateAxis(AxisInfo.CHILD)) {
+ assertTrue("Invalid iterator", iterator instanceof ArrayIterator);
+ }
+ try (AxisIterator iterator = elementNode.iterateAxis(AxisInfo.DESCENDANT)) {
+ assertTrue("Invalid iterator", iterator instanceof Navigator.DescendantEnumeration);
+ }
+ }
}
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/xpath/XpathMapperTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/xpath/XpathMapperTest.java
index a2a5cd2aa581..002ba63a6314 100644
--- a/src/test/java/com/puppycrawl/tools/checkstyle/xpath/XpathMapperTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/xpath/XpathMapperTest.java
@@ -23,6 +23,7 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -155,7 +156,8 @@ public void testComplexQueryThree() throws Exception {
@Test
public void testAttributeOr() throws Exception {
- final String xpath = "//METHOD_DEF[@text='getSomeMethod' or @text='nonExistentMethod']";
+ final String xpath = "//METHOD_DEF[./IDENT[@text='getSomeMethod'] "
+ + "or ./IDENT[@text='nonExistentMethod']]";
final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
final DetailAST expectedClassDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
@@ -170,8 +172,8 @@ public void testAttributeOr() throws Exception {
@Test
public void testAttributeAnd() throws Exception {
- final String xpath = "//METHOD_DEF[@text='callSomeMethod' and "
- + "../..[@text='InputXpathMapperAst']]";
+ final String xpath = "//METHOD_DEF[./IDENT[@text='callSomeMethod'] and "
+ + "../..[./IDENT[@text='InputXpathMapperAst']]]";
final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
final DetailAST expectedClassDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
@@ -185,7 +187,7 @@ public void testAttributeAnd() throws Exception {
@Test
public void testQueryAllElementsWithAttribute() throws Exception {
- final String xpath = "//*[@text]";
+ final String xpath = "//*[./IDENT[@text]]";
final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
final List nodes = getXpathItems(xpath, rootNode);
assertEquals("Invalid number of nodes", 18, nodes.size());
@@ -209,7 +211,7 @@ public void testQueryElementByIndex() throws Exception {
@Test
public void testQueryAllVariableDefinitionsWithAttribute() throws Exception {
- final String xpath = "//VARIABLE_DEF[@*]";
+ final String xpath = "//VARIABLE_DEF[./IDENT[@*]]";
final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
final List nodes = getXpathItems(xpath, rootNode);
assertEquals("Invalid number of nodes", 4, nodes.size());
@@ -225,7 +227,7 @@ public void testQueryAllVariableDefWrongAttribute() throws Exception {
@Test
public void testQueryAllMethodDefinitionsInContext() throws Exception {
- final String objectXpath = "/CLASS_DEF[@text='InputXpathMapperAst']//OBJBLOCK";
+ final String objectXpath = "/CLASS_DEF[./IDENT[@text='InputXpathMapperAst']]//OBJBLOCK";
final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
final List objectNodes = getXpathItems(objectXpath, rootNode);
assertEquals("Invalid number of nodes", 1, objectNodes.size());
@@ -261,7 +263,7 @@ public void testQueryAllClassDefinitions() throws Exception {
@Test
public void testQueryByMethodName() throws Exception {
- final String xpath = "//METHOD_DEF[@text='getSomeMethod']";
+ final String xpath = "//METHOD_DEF[./IDENT[@text='getSomeMethod']]";
final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
final DetailAST expectedMethodDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
@@ -275,7 +277,8 @@ public void testQueryByMethodName() throws Exception {
@Test
public void testQueryMethodDefinitionsByClassName() throws Exception {
- final String xpath = "/CLASS_DEF[@text='InputXpathMapperAst']//OBJBLOCK//METHOD_DEF";
+ final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathMapperAst']]"
+ + "//OBJBLOCK//METHOD_DEF";
final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
final DetailAST expectedMethodDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
@@ -289,8 +292,8 @@ public void testQueryMethodDefinitionsByClassName() throws Exception {
@Test
public void testQueryByClassNameAndMethodName() throws Exception {
- final String xpath = "/CLASS_DEF[@text='InputXpathMapperAst']//OBJBLOCK"
- + "//METHOD_DEF[@text='getSomeMethod']";
+ final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathMapperAst']]//OBJBLOCK"
+ + "//METHOD_DEF[./IDENT[@text='getSomeMethod']]";
final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
final DetailAST expectedMethodDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
@@ -304,7 +307,7 @@ public void testQueryByClassNameAndMethodName() throws Exception {
@Test
public void testQueryClassDefinitionByClassName() throws Exception {
- final String xpath = "/CLASS_DEF[@text='InputXpathMapperAst']";
+ final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathMapperAst']]";
final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
final List nodes = getXpathItems(xpath, rootNode);
final DetailAST[] actual = convertToArray(nodes);
@@ -313,8 +316,6 @@ public void testQueryClassDefinitionByClassName() throws Exception {
final DetailAST[] expected = {expectedClassDefNode};
final ElementNode classDefNode = (ElementNode) nodes.get(0);
assertEquals("Invalid number of nodes", "CLASS_DEF", classDefNode.getStringValue());
- assertEquals("Invalid number of nodes", "InputXpathMapperAst",
- classDefNode.getAttributeValue("", "text"));
assertArrayEquals("Result nodes differ from expected", expected, actual);
}
@@ -336,7 +337,7 @@ public void testQueryWrongXpath() throws Exception {
@Test
public void testQueryAncestor() throws Exception {
- final String xpath = "//VARIABLE_DEF[@text='another']/ancestor::METHOD_DEF";
+ final String xpath = "//VARIABLE_DEF[./IDENT[@text='another']]/ancestor::METHOD_DEF";
final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
final DetailAST expectedMethodDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
@@ -349,7 +350,8 @@ public void testQueryAncestor() throws Exception {
@Test
public void testQueryAncestorOrSelf() throws Exception {
- final String xpath = "//VARIABLE_DEF[@text='another']/ancestor-or-self::VARIABLE_DEF";
+ final String xpath = "//VARIABLE_DEF[./IDENT[@text='another']]"
+ + "/ancestor-or-self::VARIABLE_DEF";
final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
@@ -430,7 +432,7 @@ public void testQueryElementNotImplementedAxis() throws Exception {
@Test
public void testQuerySelf() throws Exception {
- final String objectXpath = "/CLASS_DEF[@text='InputXpathMapperAst']//OBJBLOCK";
+ final String objectXpath = "/CLASS_DEF[./IDENT[@text='InputXpathMapperAst']]//OBJBLOCK";
final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
final List objectNodes = getXpathItems(objectXpath, rootNode);
assertEquals("Invalid number of nodes", 1, objectNodes.size());
@@ -457,17 +459,12 @@ public void testRootWithNullDetailAst() {
@Test
public void testQueryNonExistentAttribute() throws Exception {
- final String xpath = "/CLASS_DEF[@text='InputXpathMapperAst']";
+ final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathMapperAst']]";
final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
final List nodes = getXpathItems(xpath, rootNode);
final ElementNode classDefNode = (ElementNode) nodes.get(0);
- try {
- classDefNode.getAttributeValue("", "noneExistingAttribute");
- fail("Exception is excepted");
- }
- catch (UnsupportedOperationException ex) {
- assertEquals("Invalid number of nodes", "Operation is not supported", ex.getMessage());
- }
+ assertNull("Not existing attribute should have null value",
+ classDefNode.getAttributeValue("", "noneExistingAttribute"));
}
@Test
@@ -480,7 +477,7 @@ public void testQueryRootSelf() throws Exception {
@Test
public void testQueryAnnotation() throws Exception {
- final String xpath = "//ANNOTATION[@text='SuppressWarnings']";
+ final String xpath = "//ANNOTATION[./IDENT[@text='Deprecated']]";
final RootNode rootNode = getRootNode("InputXpathMapperAnnotation.java");
final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
final DetailAST expectedAnnotationNode = getSiblingByType(rootNode.getUnderlyingNode(),
@@ -520,7 +517,7 @@ public void testQueryEnumElementsNumber() throws Exception {
@Test
public void testQueryEnumElementByName() throws Exception {
- final String xpath = "//*[@text='TWO']";
+ final String xpath = "//*[./IDENT[@text='TWO']]";
final RootNode enumRootNode = getRootNode("InputXpathMapperEnum.java");
final DetailAST[] actual = convertToArray(getXpathItems(xpath, enumRootNode));
final DetailAST expectedEnumConstantDefNode = getSiblingByType(
@@ -556,7 +553,7 @@ public void testQueryInterfaceMethodDefNumber() throws Exception {
@Test
public void testQueryInterfaceParameterDef() throws Exception {
- final String xpath = "//PARAMETER_DEF[@text='someVariable']/../..";
+ final String xpath = "//PARAMETER_DEF[./IDENT[@text='someVariable']]/../..";
final RootNode interfaceRootNode = getRootNode("InputXpathMapperInterface.java");
final DetailAST[] actual = convertToArray(getXpathItems(xpath, interfaceRootNode));
final DetailAST expectedMethodDefNode = getSiblingByType(
@@ -571,7 +568,7 @@ public void testQueryInterfaceParameterDef() throws Exception {
@Test
public void testIdent() throws Exception {
- final String xpath = "/CLASS_DEF[@text='InputXpathMapperAst']/IDENT";
+ final String xpath = "/CLASS_DEF/IDENT[@text='InputXpathMapperAst']";
final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
final List nodes = getXpathItems(xpath, rootNode);
final DetailAST[] actual = convertToArray(nodes);
@@ -583,6 +580,212 @@ public void testIdent() throws Exception {
assertArrayEquals("Result nodes differ from expected", expected, actual);
}
+ @Test
+ public void testIdentByValue() throws Exception {
+ final String xpath = "//IDENT[@text='puppycrawl']";
+ final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
+ final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
+ final DetailAST expectedMethodDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
+ TokenTypes.PACKAGE_DEF)
+ .findFirstToken(TokenTypes.DOT)
+ .findFirstToken(TokenTypes.DOT)
+ .findFirstToken(TokenTypes.DOT)
+ .findFirstToken(TokenTypes.DOT)
+ .findFirstToken(TokenTypes.DOT)
+ .findFirstToken(TokenTypes.IDENT)
+ .getNextSibling();
+ final DetailAST[] expected = {expectedMethodDefNode};
+ assertArrayEquals("Result nodes differ from expected", expected, actual);
+ }
+
+ @Test
+ public void testNumVariableByItsValue() throws Exception {
+ final String xpath = "//VARIABLE_DEF[.//NUM_INT[@text=123]]";
+ final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
+ final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
+ final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
+ TokenTypes.CLASS_DEF)
+ .findFirstToken(TokenTypes.OBJBLOCK)
+ .findFirstToken(TokenTypes.METHOD_DEF)
+ .findFirstToken(TokenTypes.SLIST)
+ .findFirstToken(TokenTypes.VARIABLE_DEF);
+ final DetailAST[] expected = {expectedVariableDefNode};
+ assertArrayEquals("Result nodes differ from expected", expected, actual);
+ }
+
+ @Test
+ public void testStringVariableByItsValue() throws Exception {
+ final String xpath = "//VARIABLE_DEF[./ASSIGN/EXPR"
+ + "/STRING_LITERAL[@text='HelloWorld']]";
+ final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
+ final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
+ final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
+ TokenTypes.CLASS_DEF)
+ .findFirstToken(TokenTypes.OBJBLOCK)
+ .findFirstToken(TokenTypes.METHOD_DEF)
+ .findFirstToken(TokenTypes.SLIST)
+ .findFirstToken(TokenTypes.VARIABLE_DEF)
+ .getNextSibling()
+ .getNextSibling();
+ final DetailAST[] expected = {expectedVariableDefNode};
+ assertArrayEquals("Result nodes differ from expected", expected, actual);
+ }
+
+ @Test
+ public void testSameNodesByNameAndByValue() throws Exception {
+ final String xpath1 = "//VARIABLE_DEF[./IDENT[@text='another']]/ASSIGN/EXPR/STRING_LITERAL";
+ final String xpath2 = "//VARIABLE_DEF/ASSIGN/EXPR/STRING_LITERAL[@text='HelloWorld']";
+ final RootNode rootNode = getRootNode("InputXpathMapperAst.java");
+ final DetailAST[] actual1 = convertToArray(getXpathItems(xpath1, rootNode));
+ final DetailAST[] actual2 = convertToArray(getXpathItems(xpath2, rootNode));
+ assertArrayEquals("Result nodes differ from expected", actual1, actual2);
+ }
+
+ @Test
+ public void testMethodDefByAnnotationValue() throws Exception {
+ final String xpath = "//METHOD_DEF[.//ANNOTATION[./IDENT[@text='SuppressWarnings']"
+ + " and .//*[@text='good']]]";
+ final RootNode rootNode = getRootNode("InputXpathMapperAnnotation.java");
+ final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
+ final DetailAST expectedAnnotationNode = getSiblingByType(rootNode.getUnderlyingNode(),
+ TokenTypes.CLASS_DEF)
+ .findFirstToken(TokenTypes.OBJBLOCK)
+ .findFirstToken(TokenTypes.METHOD_DEF)
+ .getNextSibling();
+ final DetailAST[] expected = {expectedAnnotationNode};
+ assertArrayEquals("Result nodes differ from expected", expected, actual);
+ }
+
+ @Test
+ public void testFirstImport() throws Exception {
+ final String xpath = "/IMPORT[1]";
+ final RootNode rootNode = getRootNode("InputXpathMapperPositions.java");
+ final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
+ final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
+ TokenTypes.IMPORT);
+ final DetailAST[] expected = {expectedVariableDefNode};
+ assertArrayEquals("Result nodes differ from expected", expected, actual);
+ }
+
+ @Test
+ public void testSecondImport() throws Exception {
+ final String xpath = "/IMPORT[2]";
+ final RootNode rootNode = getRootNode("InputXpathMapperPositions.java");
+ final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
+ final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
+ TokenTypes.IMPORT).getNextSibling();
+ final DetailAST[] expected = {expectedVariableDefNode};
+ assertArrayEquals("Result nodes differ from expected", expected, actual);
+ }
+
+ @Test
+ public void testThirdImport() throws Exception {
+ final String xpath = "/IMPORT[3]";
+ final RootNode rootNode = getRootNode("InputXpathMapperPositions.java");
+ final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
+ final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
+ TokenTypes.IMPORT).getNextSibling().getNextSibling();
+ final DetailAST[] expected = {expectedVariableDefNode};
+ assertArrayEquals("Result nodes differ from expected", expected, actual);
+ }
+
+ @Test
+ public void testLastImport() throws Exception {
+ final String xpath = "/IMPORT[9]";
+ final RootNode rootNode = getRootNode("InputXpathMapperPositions.java");
+ final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
+ final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
+ TokenTypes.IMPORT)
+ .getNextSibling()
+ .getNextSibling()
+ .getNextSibling()
+ .getNextSibling()
+ .getNextSibling()
+ .getNextSibling()
+ .getNextSibling()
+ .getNextSibling();
+ final DetailAST[] expected = {expectedVariableDefNode};
+ assertArrayEquals("Result nodes differ from expected", expected, actual);
+ }
+
+ @Test
+ public void testFirstCaseGroup() throws Exception {
+ final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathMapperPositions']]"
+ + "/OBJBLOCK/METHOD_DEF[./IDENT[@text='switchMethod']]"
+ + "/SLIST/LITERAL_SWITCH/CASE_GROUP[1]";
+ final RootNode rootNode = getRootNode("InputXpathMapperPositions.java");
+ final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
+ final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
+ TokenTypes.CLASS_DEF)
+ .findFirstToken(TokenTypes.OBJBLOCK)
+ .findFirstToken(TokenTypes.METHOD_DEF)
+ .findFirstToken(TokenTypes.SLIST)
+ .findFirstToken(TokenTypes.LITERAL_SWITCH)
+ .findFirstToken(TokenTypes.CASE_GROUP);
+ final DetailAST[] expected = {expectedVariableDefNode};
+ assertArrayEquals("Result nodes differ from expected", expected, actual);
+ }
+
+ @Test
+ public void testSecondCaseGroup() throws Exception {
+ final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathMapperPositions']]"
+ + "/OBJBLOCK/METHOD_DEF[./IDENT[@text='switchMethod']]"
+ + "/SLIST/LITERAL_SWITCH/CASE_GROUP[2]";
+ final RootNode rootNode = getRootNode("InputXpathMapperPositions.java");
+ final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
+ final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
+ TokenTypes.CLASS_DEF)
+ .findFirstToken(TokenTypes.OBJBLOCK)
+ .findFirstToken(TokenTypes.METHOD_DEF)
+ .findFirstToken(TokenTypes.SLIST)
+ .findFirstToken(TokenTypes.LITERAL_SWITCH)
+ .findFirstToken(TokenTypes.CASE_GROUP)
+ .getNextSibling();
+ final DetailAST[] expected = {expectedVariableDefNode};
+ assertArrayEquals("Result nodes differ from expected", expected, actual);
+ }
+
+ @Test
+ public void testThirdCaseGroup() throws Exception {
+ final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathMapperPositions']]"
+ + "/OBJBLOCK/METHOD_DEF[./IDENT[@text='switchMethod']]"
+ + "/SLIST/LITERAL_SWITCH/CASE_GROUP[3]";
+ final RootNode rootNode = getRootNode("InputXpathMapperPositions.java");
+ final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
+ final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
+ TokenTypes.CLASS_DEF)
+ .findFirstToken(TokenTypes.OBJBLOCK)
+ .findFirstToken(TokenTypes.METHOD_DEF)
+ .findFirstToken(TokenTypes.SLIST)
+ .findFirstToken(TokenTypes.LITERAL_SWITCH)
+ .findFirstToken(TokenTypes.CASE_GROUP)
+ .getNextSibling()
+ .getNextSibling();
+ final DetailAST[] expected = {expectedVariableDefNode};
+ assertArrayEquals("Result nodes differ from expected", expected, actual);
+ }
+
+ @Test
+ public void testFourthCaseGroup() throws Exception {
+ final String xpath = "/CLASS_DEF[./IDENT[@text='InputXpathMapperPositions']]"
+ + "/OBJBLOCK/METHOD_DEF[./IDENT[@text='switchMethod']]"
+ + "/SLIST/LITERAL_SWITCH/CASE_GROUP[4]";
+ final RootNode rootNode = getRootNode("InputXpathMapperPositions.java");
+ final DetailAST[] actual = convertToArray(getXpathItems(xpath, rootNode));
+ final DetailAST expectedVariableDefNode = getSiblingByType(rootNode.getUnderlyingNode(),
+ TokenTypes.CLASS_DEF)
+ .findFirstToken(TokenTypes.OBJBLOCK)
+ .findFirstToken(TokenTypes.METHOD_DEF)
+ .findFirstToken(TokenTypes.SLIST)
+ .findFirstToken(TokenTypes.LITERAL_SWITCH)
+ .findFirstToken(TokenTypes.CASE_GROUP)
+ .getNextSibling()
+ .getNextSibling()
+ .getNextSibling();
+ final DetailAST[] expected = {expectedVariableDefNode};
+ assertArrayEquals("Result nodes differ from expected", expected, actual);
+ }
+
private RootNode getRootNode(String fileName) throws Exception {
final File file = new File(getPath(fileName));
final DetailAST rootAst = JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS);
diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/xpath/XpathQueryGeneratorTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/xpath/XpathQueryGeneratorTest.java
index f01f2fd4019b..c42c1f1451c9 100644
--- a/src/test/java/com/puppycrawl/tools/checkstyle/xpath/XpathQueryGeneratorTest.java
+++ b/src/test/java/com/puppycrawl/tools/checkstyle/xpath/XpathQueryGeneratorTest.java
@@ -69,9 +69,9 @@ public void testClassDef() {
columnNumber, fileText, DEFAULT_TAB_WIDTH);
final List actual = queryGenerator.generate();
final List expected = Arrays.asList(
- "/CLASS_DEF[@text='InputXpathQueryGenerator']",
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/MODIFIERS",
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/MODIFIERS/LITERAL_PUBLIC");
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]",
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/MODIFIERS",
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/MODIFIERS/LITERAL_PUBLIC");
assertEquals("Generated queries do not match expected ones", expected, actual);
}
@@ -83,12 +83,12 @@ public void testMethodDef() {
columnNumber, fileText, DEFAULT_TAB_WIDTH);
final List actual = queryGenerator.generate();
final List expected = Arrays.asList(
- "/CLASS_DEF[@text='InputXpathQueryGenerator']"
- + "/OBJBLOCK/METHOD_DEF[@text='callSomeMethod']",
- "/CLASS_DEF[@text='InputXpathQueryGenerator']"
- + "/OBJBLOCK/METHOD_DEF[@text='callSomeMethod']/MODIFIERS",
- "/CLASS_DEF[@text='InputXpathQueryGenerator']"
- + "/OBJBLOCK/METHOD_DEF[@text='callSomeMethod']/MODIFIERS/LITERAL_PUBLIC");
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK"
+ + "/METHOD_DEF[./IDENT[@text='callSomeMethod']]",
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK"
+ + "/METHOD_DEF[./IDENT[@text='callSomeMethod']]/MODIFIERS",
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK"
+ + "/METHOD_DEF[./IDENT[@text='callSomeMethod']]/MODIFIERS/LITERAL_PUBLIC");
assertEquals("Generated queries do not match expected ones", expected, actual);
}
@@ -100,18 +100,18 @@ public void testVariableDef() {
columnNumber, fileText, DEFAULT_TAB_WIDTH);
final List actual = queryGenerator.generate();
final List expected = Arrays.asList(
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/OBJBLOCK"
- + "/METHOD_DEF[@text='callSomeMethod']/SLIST/LITERAL_FOR"
- + "/SLIST/VARIABLE_DEF[@text='d']",
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/OBJBLOCK"
- + "/METHOD_DEF[@text='callSomeMethod']/SLIST/LITERAL_FOR"
- + "/SLIST/VARIABLE_DEF[@text='d']/MODIFIERS",
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/OBJBLOCK"
- + "/METHOD_DEF[@text='callSomeMethod']/SLIST/LITERAL_FOR"
- + "/SLIST/VARIABLE_DEF[@text='d']/TYPE",
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/OBJBLOCK"
- + "/METHOD_DEF[@text='callSomeMethod']/SLIST/LITERAL_FOR"
- + "/SLIST/VARIABLE_DEF[@text='d']/TYPE/LITERAL_SHORT");
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK/METHOD_DEF["
+ + "./IDENT[@text='callSomeMethod']]/SLIST/LITERAL_FOR/SLIST"
+ + "/VARIABLE_DEF[./IDENT[@text='d']]",
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK/METHOD_DEF["
+ + "./IDENT[@text='callSomeMethod']]/SLIST/LITERAL_FOR/SLIST"
+ + "/VARIABLE_DEF[./IDENT[@text='d']]/MODIFIERS",
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK/METHOD_DEF["
+ + "./IDENT[@text='callSomeMethod']]/SLIST/LITERAL_FOR/SLIST"
+ + "/VARIABLE_DEF[./IDENT[@text='d']]/TYPE",
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK/METHOD_DEF["
+ + "./IDENT[@text='callSomeMethod']]/SLIST/LITERAL_FOR/SLIST"
+ + "/VARIABLE_DEF[./IDENT[@text='d']]/TYPE/LITERAL_SHORT");
assertEquals("Generated queries do not match expected ones", expected, actual);
}
@@ -123,8 +123,8 @@ public void testLcurly() {
columnNumber, fileText, DEFAULT_TAB_WIDTH);
final List actual = queryGenerator.generate();
final List expected = Collections.singletonList(
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/OBJBLOCK/METHOD_DEF[@text='Label']"
- + "/SLIST/LITERAL_SWITCH/LCURLY");
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK/METHOD_DEF["
+ + "./IDENT[@text='Label']]/SLIST/LITERAL_SWITCH/LCURLY");
assertEquals("Generated queries do not match expected ones", expected, actual);
}
@@ -136,8 +136,8 @@ public void testRcurly() {
columnNumber, fileText, DEFAULT_TAB_WIDTH);
final List actual = queryGenerator.generate();
final List expected = Collections.singletonList(
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/OBJBLOCK/INSTANCE_INIT"
- + "/SLIST/RCURLY");
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK"
+ + "/INSTANCE_INIT/SLIST/RCURLY");
assertEquals("Generated queries do not match expected ones", expected, actual);
}
@@ -149,10 +149,10 @@ public void testExpr() {
columnNumber, fileText, DEFAULT_TAB_WIDTH);
final List actual = queryGenerator.generate();
final List expected = Arrays.asList(
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/OBJBLOCK"
- + "/VARIABLE_DEF[@text='mUse4']/ASSIGN/EXPR",
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/OBJBLOCK"
- + "/VARIABLE_DEF[@text='mUse4']/ASSIGN/EXPR/DOT");
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK/VARIABLE_DEF["
+ + "./IDENT[@text='mUse4']]/ASSIGN/EXPR",
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK/VARIABLE_DEF["
+ + "./IDENT[@text='mUse4']]/ASSIGN/EXPR/DOT");
assertEquals("Generated queries do not match expected ones", expected, actual);
}
@@ -164,8 +164,8 @@ public void testLparen() {
columnNumber, fileText, DEFAULT_TAB_WIDTH);
final List actual = queryGenerator.generate();
final List expected = Collections.singletonList(
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/OBJBLOCK"
- + "/METHOD_DEF[@text='callSomeMethod']/LPAREN");
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK"
+ + "/METHOD_DEF[./IDENT[@text='callSomeMethod']]/LPAREN");
assertEquals("Generated queries do not match expected ones", expected, actual);
}
@@ -199,7 +199,7 @@ public void testImport() {
columnNumber, fileText, DEFAULT_TAB_WIDTH);
final List actual = queryGenerator.generate();
final List expected = Collections.singletonList(
- "/IMPORT[./DOT[@text='File']]");
+ "/IMPORT[2]");
assertEquals("Generated queries do not match expected ones", expected, actual);
}
@@ -211,19 +211,19 @@ public void testMethodParams() {
columnNumber, fileText, DEFAULT_TAB_WIDTH);
final List actual = queryGenerator.generate();
final List expected = Arrays.asList(
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/OBJBLOCK"
- + "/METHOD_DEF[@text='saveUser']/PARAMETERS",
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/OBJBLOCK"
- + "/METHOD_DEF[@text='saveUser']/PARAMETERS/PARAMETER_DEF[@text='name']",
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/OBJBLOCK"
- + "/METHOD_DEF[@text='saveUser']/PARAMETERS/PARAMETER_DEF[@text='name']"
- + "/MODIFIERS",
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/OBJBLOCK"
- + "/METHOD_DEF[@text='saveUser']/PARAMETERS/PARAMETER_DEF[@text='name']"
- + "/TYPE[@text='String']",
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/OBJBLOCK"
- + "/METHOD_DEF[@text='saveUser']/PARAMETERS/PARAMETER_DEF[@text='name']"
- + "/TYPE[@text='String']/IDENT");
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK/METHOD_DEF["
+ + "./IDENT[@text='saveUser']]/PARAMETERS",
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK/METHOD_DEF["
+ + "./IDENT[@text='saveUser']]/PARAMETERS/PARAMETER_DEF[./IDENT[@text='name']]",
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK/METHOD_DEF["
+ + "./IDENT[@text='saveUser']]/PARAMETERS/PARAMETER_DEF[./IDENT[@text='name']]"
+ + "/MODIFIERS",
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK/METHOD_DEF["
+ + "./IDENT[@text='saveUser']]/PARAMETERS/PARAMETER_DEF[./IDENT[@text='name']]"
+ + "/TYPE[./IDENT[@text='String']]",
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK/METHOD_DEF["
+ + "./IDENT[@text='saveUser']]/PARAMETERS/PARAMETER_DEF[./IDENT[@text='name']]"
+ + "/TYPE/IDENT[@text='String']");
assertEquals("Generated queries do not match expected ones", expected, actual);
}
@@ -235,8 +235,8 @@ public void testSwitch() {
columnNumber, fileText, DEFAULT_TAB_WIDTH);
final List actual = queryGenerator.generate();
final List expected = Collections.singletonList(
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/OBJBLOCK"
- + "/METHOD_DEF[@text='Label']/SLIST/LITERAL_SWITCH");
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK/METHOD_DEF["
+ + "./IDENT[@text='Label']]/SLIST/LITERAL_SWITCH");
assertEquals("Generated queries do not match expected ones", expected, actual);
}
@@ -248,10 +248,10 @@ public void testSwitchCase() {
columnNumber, fileText, DEFAULT_TAB_WIDTH);
final List actual = queryGenerator.generate();
final List expected = Arrays.asList(
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/OBJBLOCK/METHOD_DEF[@text='Label']"
- + "/SLIST/LITERAL_SWITCH/CASE_GROUP",
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/OBJBLOCK/METHOD_DEF[@text='Label']"
- + "/SLIST/LITERAL_SWITCH/CASE_GROUP/LITERAL_DEFAULT");
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK/METHOD_DEF["
+ + "./IDENT[@text='Label']]/SLIST/LITERAL_SWITCH/CASE_GROUP[1]",
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK/METHOD_DEF["
+ + "./IDENT[@text='Label']]/SLIST/LITERAL_SWITCH/CASE_GROUP/LITERAL_DEFAULT");
assertEquals("Generated queries do not match expected ones", expected, actual);
}
@@ -263,12 +263,12 @@ public void testVariableStringLiteral() {
columnNumber, fileText, DEFAULT_TAB_WIDTH);
final List actual = queryGenerator.generate();
final List expected = Arrays.asList(
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/OBJBLOCK"
- + "/METHOD_DEF[@text='callSomeMethod']/SLIST/VARIABLE_DEF[@text='another']"
- + "/ASSIGN/EXPR",
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/OBJBLOCK"
- + "/METHOD_DEF[@text='callSomeMethod']/SLIST/VARIABLE_DEF[@text='another']"
- + "/ASSIGN/EXPR/STRING_LITERAL");
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK/METHOD_DEF["
+ + "./IDENT[@text='callSomeMethod']]/SLIST/VARIABLE_DEF[./IDENT[@text='another']]"
+ + "/ASSIGN/EXPR[./STRING_LITERAL[@text='HelloWorld']]",
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK/METHOD_DEF["
+ + "./IDENT[@text='callSomeMethod']]/SLIST/VARIABLE_DEF[./IDENT[@text='another']]"
+ + "/ASSIGN/EXPR/STRING_LITERAL[@text='HelloWorld']");
assertEquals("Generated queries do not match expected ones", expected, actual);
}
@@ -280,8 +280,8 @@ public void testComma() {
columnNumber, fileText, DEFAULT_TAB_WIDTH);
final List actual = queryGenerator.generate();
final List expected = Collections.singletonList(
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/OBJBLOCK/METHOD_DEF[@text='foo']"
- + "/SLIST/LITERAL_FOR/FOR_ITERATOR/ELIST/COMMA");
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK/METHOD_DEF["
+ + "./IDENT[@text='foo']]/SLIST/LITERAL_FOR/FOR_ITERATOR/ELIST/COMMA");
assertEquals("Generated queries do not match expected ones", expected, actual);
}
@@ -293,10 +293,10 @@ public void testLiteralVoid() {
columnNumber, fileText, DEFAULT_TAB_WIDTH);
final List actual = queryGenerator.generate();
final List expected = Arrays.asList(
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/OBJBLOCK"
- + "/METHOD_DEF[@text='foo']/TYPE",
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/OBJBLOCK"
- + "/METHOD_DEF[@text='foo']/TYPE/LITERAL_VOID");
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK/METHOD_DEF["
+ + "./IDENT[@text='foo']]/TYPE",
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/OBJBLOCK/METHOD_DEF["
+ + "./IDENT[@text='foo']]/TYPE/LITERAL_VOID");
assertEquals("Generated queries do not match expected ones", expected, actual);
}
@@ -308,7 +308,7 @@ public void testFirstImport() {
columnNumber, fileText, DEFAULT_TAB_WIDTH);
final List actual = queryGenerator.generate();
final List expected = Collections.singletonList(
- "/IMPORT[./DOT[@text='JToolBar']]");
+ "/IMPORT[1]");
assertEquals("Generated queries do not match expected ones", expected, actual);
}
@@ -320,7 +320,19 @@ public void testLastImport() {
columnNumber, fileText, DEFAULT_TAB_WIDTH);
final List actual = queryGenerator.generate();
final List expected = Collections.singletonList(
- "/IMPORT[./DOT[@text='Iterator']]");
+ "/IMPORT[5]");
+ assertEquals("Generated queries do not match expected ones", expected, actual);
+ }
+
+ @Test
+ public void testImportByValue() {
+ final int lineNumber = 4;
+ final int columnNumber = 8;
+ final XpathQueryGenerator queryGenerator = new XpathQueryGenerator(rootAst, lineNumber,
+ columnNumber, fileText, DEFAULT_TAB_WIDTH);
+ final List actual = queryGenerator.generate();
+ final List expected = Collections.singletonList(
+ "/IMPORT/DOT[./IDENT[@text='JToolBar']]/DOT/IDENT[@text='javax']");
assertEquals("Generated queries do not match expected ones", expected, actual);
}
@@ -332,7 +344,7 @@ public void testIdent() {
columnNumber, fileText, DEFAULT_TAB_WIDTH);
final List actual = queryGenerator.generate();
final List expected = Collections.singletonList(
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/IDENT");
+ "/CLASS_DEF/IDENT[@text='InputXpathQueryGenerator']");
assertEquals("Generated queries do not match expected ones", expected, actual);
}
@@ -350,12 +362,12 @@ public void testTabWidthBeforeMethodDef() throws Exception {
columnNumber, testFileText, tabWidth);
final List actual = queryGenerator.generate();
final List expected = Arrays.asList(
- "/CLASS_DEF[@text='InputXpathQueryGeneratorTabWidth']/OBJBLOCK"
- + "/METHOD_DEF[@text='toString']",
- "/CLASS_DEF[@text='InputXpathQueryGeneratorTabWidth']/OBJBLOCK"
- + "/METHOD_DEF[@text='toString']/MODIFIERS",
- "/CLASS_DEF[@text='InputXpathQueryGeneratorTabWidth']/OBJBLOCK"
- + "/METHOD_DEF[@text='toString']/MODIFIERS/LITERAL_PUBLIC");
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGeneratorTabWidth']]/OBJBLOCK"
+ + "/METHOD_DEF[./IDENT[@text='toString']]",
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGeneratorTabWidth']]/OBJBLOCK"
+ + "/METHOD_DEF[./IDENT[@text='toString']]/MODIFIERS",
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGeneratorTabWidth']]/OBJBLOCK"
+ + "/METHOD_DEF[./IDENT[@text='toString']]/MODIFIERS/LITERAL_PUBLIC");
assertEquals("Generated queries do not match expected ones", expected, actual);
}
@@ -373,10 +385,10 @@ public void testTabWidthAfterVoidLiteral() throws Exception {
columnNumber, testFileText, tabWidth);
final List actual = queryGenerator.generate();
final List expected = Arrays.asList(
- "/CLASS_DEF[@text='InputXpathQueryGeneratorTabWidth']/OBJBLOCK"
- + "/METHOD_DEF[@text='getName']/TYPE",
- "/CLASS_DEF[@text='InputXpathQueryGeneratorTabWidth']/OBJBLOCK"
- + "/METHOD_DEF[@text='getName']/TYPE/LITERAL_VOID");
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGeneratorTabWidth']]/OBJBLOCK"
+ + "/METHOD_DEF[./IDENT[@text='getName']]/TYPE",
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGeneratorTabWidth']]/OBJBLOCK"
+ + "/METHOD_DEF[./IDENT[@text='getName']]/TYPE/LITERAL_VOID");
assertEquals("Generated queries do not match expected ones", expected, actual);
}
@@ -394,8 +406,8 @@ public void testTabWidthBeforeSlist() throws Exception {
columnNumber, testFileText, tabWidth);
final List actual = queryGenerator.generate();
final List expected = Collections.singletonList(
- "/CLASS_DEF[@text='InputXpathQueryGeneratorTabWidth']/OBJBLOCK"
- + "/METHOD_DEF[@text='tabAfterMe']/SLIST");
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGeneratorTabWidth']]/OBJBLOCK"
+ + "/METHOD_DEF[./IDENT[@text='tabAfterMe']]/SLIST");
assertEquals("Generated queries do not match expected ones", expected, actual);
}
@@ -413,8 +425,8 @@ public void testTabWidthEndOfLine() throws Exception {
columnNumber, testFileText, tabWidth);
final List actual = queryGenerator.generate();
final List expected = Collections.singletonList(
- "/CLASS_DEF[@text='InputXpathQueryGeneratorTabWidth']/OBJBLOCK"
- + "/VARIABLE_DEF[@text='endLineTab']/SEMI");
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGeneratorTabWidth']]/OBJBLOCK"
+ + "/VARIABLE_DEF[./IDENT[@text='endLineTab']]/SEMI");
assertEquals("Generated queries do not match expected ones", expected, actual);
}
@@ -426,7 +438,7 @@ public void testClassDefWithTokenType() {
columnNumber, TokenTypes.CLASS_DEF, fileText, DEFAULT_TAB_WIDTH);
final List actual = queryGenerator.generate();
final List expected = Collections.singletonList(
- "/CLASS_DEF[@text='InputXpathQueryGenerator']");
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]");
assertEquals("Generated queries do not match expected ones", expected, actual);
}
@@ -440,9 +452,9 @@ public void testConstructorWithTreeWalkerAuditEvent() {
new XpathQueryGenerator(event, DEFAULT_TAB_WIDTH);
final List actual = queryGenerator.generate();
final List expected = Arrays.asList(
- "/CLASS_DEF[@text='InputXpathQueryGenerator']",
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/MODIFIERS",
- "/CLASS_DEF[@text='InputXpathQueryGenerator']/MODIFIERS/LITERAL_PUBLIC");
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]",
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/MODIFIERS",
+ "/CLASS_DEF[./IDENT[@text='InputXpathQueryGenerator']]/MODIFIERS/LITERAL_PUBLIC");
assertEquals("Generated queries do not match expected ones", expected, actual);
}
diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/treewalker/InputTreeWalkerSuppressionXpathFilterAbsolute.xml b/src/test/resources/com/puppycrawl/tools/checkstyle/treewalker/InputTreeWalkerSuppressionXpathFilterAbsolute.xml
index cdb6bc5cf286..41ee95208853 100644
--- a/src/test/resources/com/puppycrawl/tools/checkstyle/treewalker/InputTreeWalkerSuppressionXpathFilterAbsolute.xml
+++ b/src/test/resources/com/puppycrawl/tools/checkstyle/treewalker/InputTreeWalkerSuppressionXpathFilterAbsolute.xml
@@ -4,6 +4,6 @@
"https://checkstyle.org/dtds/suppressions_1_2_xpath_experimental.dtd">
+ query="/CLASS_DEF[./IDENT[@text='InputTreeWalkerSuppressionXpathFilterAbsolute']]/
+ OBJBLOCK/METHOD_DEF[./IDENT[@text='test']]/SLIST" />
diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/xpath/xpathmapper/InputXpathMapperAnnotation.java b/src/test/resources/com/puppycrawl/tools/checkstyle/xpath/xpathmapper/InputXpathMapperAnnotation.java
index e2d86c6d383b..e88216b0c367 100644
--- a/src/test/resources/com/puppycrawl/tools/checkstyle/xpath/xpathmapper/InputXpathMapperAnnotation.java
+++ b/src/test/resources/com/puppycrawl/tools/checkstyle/xpath/xpathmapper/InputXpathMapperAnnotation.java
@@ -1,6 +1,15 @@
package com.puppycrawl.tools.checkstyle.xpath.xpathmapper;
-@SuppressWarnings("test")
+@Deprecated
public class InputXpathMapperAnnotation {
+ @SuppressWarnings("bad")
+ public void test1() {
+
+ }
+
+ @SuppressWarnings("good")
+ public void test2() {
+
+ }
}
diff --git a/src/test/resources/com/puppycrawl/tools/checkstyle/xpath/xpathmapper/InputXpathMapperPositions.java b/src/test/resources/com/puppycrawl/tools/checkstyle/xpath/xpathmapper/InputXpathMapperPositions.java
new file mode 100644
index 000000000000..20a887cf86ca
--- /dev/null
+++ b/src/test/resources/com/puppycrawl/tools/checkstyle/xpath/xpathmapper/InputXpathMapperPositions.java
@@ -0,0 +1,27 @@
+package com.puppycrawl.tools.checkstyle.xpath.xpathmapper;
+
+import java.util.Date;
+import java.util.Scanner;
+import java.lang.StringBuilder;
+import javax.crypto.Cipher;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.stream.Collectors;
+
+public class InputXpathMapperPositions {
+ public void switchMethod() {
+ int i = 23;
+ switch (i) {
+ case 3:
+ break;
+ default:
+ break;
+ case 1:
+ break;
+ case 2:
+ break;
+ }
+ }
+}
diff --git a/src/xdocs/config_filters.xml b/src/xdocs/config_filters.xml
index c20f0acf9d7d..6946b7058ffb 100644
--- a/src/xdocs/config_filters.xml
+++ b/src/xdocs/config_filters.xml
@@ -889,6 +889,19 @@ public class UserService {
all methods with name sayHelloWorld inside FileOne
and FileTwo files:
+
+ Currently, xpath queries support one type of attribute @text.
+ @text - addresses to the value of the node. For example: variable value,
+ annotation value, text content and etc.
+ Only the following token types support @text attribute:
+ TokenTypes.IDENT, TokenTypes.STRING_LITERAL,
+ TokenTypes.CHAR_LITERAL, TokenTypes.NUM_LONG,
+ TokenTypes.NUM_INT, TokenTypes.NUM_DOUBLE,
+ TokenTypes.NUM_FLOAT.
+ These token types were selected because only their values are useful and can be used
+ in xpath queries for more accurate results.
+ Other token types always have constant values.
+
@@ -925,8 +938,8 @@ public class UserService {
Suppress checks for certain methods:
Suppress checks for variable testVariable inside testMethod method
@@ -934,23 +947,24 @@ public class UserService {
In the following sample, violations for LeftCurly check will be suppressed
for classes with name Main or for methods with name calculate.
The following example demonstrates how to suppress RequireThis violations for
variable age inside changeAge method.