code: ///////////////////////////////////////////////////////////////////////////////////////////////
  // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
  // Copyright (C) 2001-2023 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;
  
  import static com.google.common.truth.Truth.assertWithMessage;
  
  import java.io.File;
  import java.nio.charset.StandardCharsets;
  import java.util.Map;
  
  import org.junit.jupiter.api.Test;
  
  import com.puppycrawl.tools.checkstyle.api.AuditEvent;
  import com.puppycrawl.tools.checkstyle.api.DetailAST;
  import com.puppycrawl.tools.checkstyle.api.FileContents;
  import com.puppycrawl.tools.checkstyle.api.FileText;
  import com.puppycrawl.tools.checkstyle.api.SeverityLevel;
  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
  import com.puppycrawl.tools.checkstyle.api.Violation;
  import com.puppycrawl.tools.checkstyle.checks.blocks.LeftCurlyCheck;
  import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
  
  public class XpathFileGeneratorAstFilterTest {
  
      @Test
      public void testAcceptNoToken() {
          final Violation violation = new Violation(0, 0, 0, null, null, null, null,
                  null, XpathFileGeneratorAstFilterTest.class, null);
          final TreeWalkerAuditEvent event = new TreeWalkerAuditEvent(null, null, violation, null);
          final XpathFileGeneratorAstFilter filter = new XpathFileGeneratorAstFilter();
          filter.finishLocalSetup();
  
          assertWithMessage("filter accepted")
                  .that(filter.accept(event))
                  .isTrue();
  
          final AuditEvent auditEvent = new AuditEvent(this, "Test.java", violation);
  
          assertWithMessage("filter has no queries")
              .that(XpathFileGeneratorAstFilter.findCorrespondingXpathQuery(auditEvent))
              .isNull();
      }
  
      @Test
      public void test() throws Exception {
          final Violation violation = new Violation(3, 47, TokenTypes.LCURLY,
                  "messages.properties", null, null, SeverityLevel.ERROR, null, LeftCurlyCheck.class,
                  null);
          final TreeWalkerAuditEvent event = createTreeWalkerAuditEvent(
                  "InputXpathFileGeneratorAstFilter.java", violation);
          final XpathFileGeneratorAstFilter filter = new XpathFileGeneratorAstFilter();
          filter.finishLocalSetup();
  
          assertWithMessage("filter accepted")
                  .that(filter.accept(event))
                  .isTrue();
  
          final AuditEvent auditEvent = new AuditEvent(this,
                  getPath("InputXpathFileGeneratorAstFilter.java"), violation);
  
          assertWithMessage("expected xpath")
              .that(XpathFileGeneratorAstFilter.findCorrespondingXpathQuery(auditEvent))
              .isEqualTo("/COMPILATION_UNIT/CLASS_DEF[./IDENT"
                      + "[@text='InputXpathFileGeneratorAstFilter']]/OBJBLOCK/LCURLY");
      }
  
      @Test
      public void testNoXpathQuery() throws Exception {
          final Violation violation = new Violation(10, 10, TokenTypes.LCURLY,
                  "messages.properties", null, null, SeverityLevel.ERROR, null, LeftCurlyCheck.class,
                  null);
          final TreeWalkerAuditEvent event = createTreeWalkerAuditEvent(
                  "InputXpathFileGeneratorAstFilter.java", violation);
          final XpathFileGeneratorAstFilter filter = new XpathFileGeneratorAstFilter();
          filter.finishLocalSetup();
  
          assertWithMessage("filter accepted")
                  .that(filter.accept(event))
                  .isTrue();
  
          final AuditEvent auditEvent = new AuditEvent(this,
                  getPath("InputXpathFileGeneratorAstFilter.java"), violation);
  
          assertWithMessage("expected null")
              .that(XpathFileGeneratorAstFilter.findCorrespondingXpathQuery(auditEvent))
              .isNull();
      }
  
      @Test
      public void testTabWidth() throws Exception {
          final Violation violation = new Violation(6, 7, TokenTypes.LITERAL_RETURN,
                  "messages.properties", null, null, SeverityLevel.ERROR, null,
                  XpathFileGeneratorAstFilterTest.class, null);
          final TreeWalkerAuditEvent event = createTreeWalkerAuditEvent(
                  "InputXpathFileGeneratorAstFilter.java", violation);
          final XpathFileGeneratorAstFilter filter = new XpathFileGeneratorAstFilter();
          filter.finishLocalSetup();
          filter.setTabWidth(6);
  
          assertWithMessage("filter accepted")
                  .that(filter.accept(event))
                  .isTrue();
  
          final AuditEvent auditEvent = new AuditEvent(this,
                  getPath("InputXpathFileGeneratorAstFilter.java"), violation);
  
          assertWithMessage("expected xpath")
              .that(XpathFileGeneratorAstFilter.findCorrespondingXpathQuery(auditEvent))
              .isEqualTo("/COMPILATION_UNIT"
                          + "/CLASS_DEF[./IDENT[@text='InputXpathFileGeneratorAstFilter']]"
                          + "/OBJBLOCK/METHOD_DEF[./IDENT[@text='tabMethod']]/SLIST/LITERAL_RETURN");
      }
  
      /**
       * We cannot reproduce situation when {@code finishLocalSetup} is called
       * twice. So, we have to use reflection to be sure that even in such
       * situation state of the field will be cleared.
       *
       * @throws Exception when code tested throws exception
       */
      @Test
      @SuppressWarnings("unchecked")
      public void testClearState() throws Exception {
          final Violation violation = new Violation(3, 47, TokenTypes.LCURLY,
                  "messages.properties", null, null, SeverityLevel.ERROR, null, LeftCurlyCheck.class,
                  null);
          final TreeWalkerAuditEvent event = createTreeWalkerAuditEvent(
                  "InputXpathFileGeneratorAstFilter.java", violation);
  
          final XpathFileGeneratorAstFilter filter = new XpathFileGeneratorAstFilter();
          filter.finishLocalSetup();
  
          assertWithMessage("State is not cleared on finishLocalSetup")
                  .that(TestUtil.isStatefulFieldClearedDuringLocalSetup(filter, event,
                          "MESSAGE_QUERY_MAP",
                          variableStack -> ((Map<Violation, String>) variableStack).isEmpty()))
                  .isTrue();
      }
  
      private static TreeWalkerAuditEvent createTreeWalkerAuditEvent(String fileName,
              Violation violation) throws Exception {
          final File file = new File(getPath(fileName));
          final FileText fileText = new FileText(file.getAbsoluteFile(), System.getProperty(
                  "file.encoding", StandardCharsets.UTF_8.name()));
          final FileContents fileContents = new FileContents(fileText);
          final DetailAST rootAst = JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS);
  
          return new TreeWalkerAuditEvent(fileContents, fileName, violation, rootAst);
      }
  
      private static String getPath(String filename) {
          return "src/test/resources/com/puppycrawl/tools/checkstyle/xpathfilegeneratorastfilter/"
                  + filename;
      }
  
  }
  