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.checks.header;
  
  import static com.google.common.truth.Truth.assertWithMessage;
  import static com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck.MSG_MISMATCH;
  import static com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck.MSG_MISSING;
  import static org.junit.jupiter.api.Assertions.assertThrows;
  import static org.mockito.Mockito.mockConstruction;
  import static org.mockito.Mockito.when;
  
  import java.io.File;
  import java.io.IOException;
  import java.io.LineNumberReader;
  import java.net.URI;
  import java.util.Set;
  
  import org.junit.jupiter.api.Test;
  import org.junit.jupiter.api.io.TempDir;
  import org.mockito.MockedConstruction;
  
  import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
  import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
  import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
  import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
  import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
  
  public class HeaderCheckTest extends AbstractModuleTestSupport {
  
      @TempDir
      public File temporaryFolder;
  
      @Override
      protected String getPackageLocation() {
          return "com/puppycrawl/tools/checkstyle/checks/header/header";
      }
  
      @Test
      public void testStaticHeader() throws Exception {
          final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
          checkConfig.addProperty("headerFile", getPath("InputHeaderjava.header"));
          checkConfig.addProperty("ignoreLines", "");
          final String[] expected = {
              "1: " + getCheckMessage(MSG_MISSING),
          };
          verify(checkConfig, getPath("InputHeader.java"), expected);
      }
  
      @Test
      public void testNoHeader() throws Exception {
          final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
  
          createChecker(checkConfig);
          final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
          verify(checkConfig, getPath("InputHeaderRegexp.java"), expected);
      }
  
      @Test
      public void testWhitespaceHeader() throws Exception {
          final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
          checkConfig.addProperty("header", "\n    \n");
  
          createChecker(checkConfig);
          final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
          verify(checkConfig, getPath("InputHeaderRegexp.java"), expected);
      }
  
      @Test
      public void testNonExistentHeaderFile() throws Exception {
          final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
          checkConfig.addProperty("headerFile", getPath("nonExistent.file"));
          final CheckstyleException ex = assertThrows(CheckstyleException.class, () -> {
              createChecker(checkConfig);
          });
          assertWithMessage("Invalid exception message")
                  .that(ex)
                  .hasMessageThat()
                          .startsWith("cannot initialize module"
                              + " com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck"
                              + " - illegal value ");
          assertWithMessage("Invalid cause exception message")
                  .that(ex)
                  .hasCauseThat()
                  .hasCauseThat()
                  .hasCauseThat()
                  .hasMessageThat()
                          .startsWith("Unable to find: ");
      }
  
      @Test
      public void testInvalidCharset() throws Exception {
          final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
          checkConfig.addProperty("headerFile", getPath("InputHeaderjava.header"));
          checkConfig.addProperty("charset", "XSO-8859-1");
          final CheckstyleException ex = assertThrows(CheckstyleException.class, () -> {
              createChecker(checkConfig);
          });
          assertWithMessage("Invalid exception message")
                  .that(ex)
                  .hasMessageThat()
                          .isEqualTo("cannot initialize module"
                                  + " com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck"
                                  + " - Cannot set property 'charset' to 'XSO-8859-1'");
          assertWithMessage("Invalid cause exception message")
                  .that(ex)
                  .hasCauseThat()
                  .hasCauseThat()
                  .hasCauseThat()
                  .hasMessageThat()
                          .startsWith("unsupported charset: 'XSO-8859-1'");
      }
  
      @Test
      public void testEmptyFilename() {
          final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
          checkConfig.addProperty("headerFile", "");
          final CheckstyleException ex = assertThrows(CheckstyleException.class, () -> {
              createChecker(checkConfig);
          });
          assertWithMessage("Invalid exception message")
                  .that(ex)
                  .hasMessageThat()
                          .isEqualTo("cannot initialize module"
                                  + " com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck"
                                  + " - Cannot set property 'headerFile' to ''");
          assertWithMessage("Invalid cause exception message")
                  .that(ex)
                  .hasCauseThat()
                  .hasCauseThat()
                  .hasCauseThat()
                  .hasMessageThat()
                          .isEqualTo("property 'headerFile' is missing or invalid in module"
                                  + " com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck");
      }
  
      @Test
      public void testNullFilename() {
          final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
          checkConfig.addProperty("headerFile", null);
          final CheckstyleException ex = assertThrows(CheckstyleException.class, () -> {
              createChecker(checkConfig);
          });
          assertWithMessage("Invalid exception message")
                  .that(ex)
                  .hasMessageThat()
                          .isEqualTo("cannot initialize module"
                                  + " com.puppycrawl.tools.checkstyle.checks.header.HeaderCheck"
                                  + " - Cannot set property 'headerFile' to 'null'");
      }
  
      @Test
      public void testNotMatch() throws Exception {
          final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
          checkConfig.addProperty("headerFile", getPath("InputHeaderjava.header"));
          checkConfig.addProperty("ignoreLines", "");
          final String[] expected = {
              "2: " + getCheckMessage(MSG_MISMATCH,
                      "// checkstyle: Checks Java source code and other text files for adherence to a"
                          + " set of rules."),
          };
          verify(checkConfig, getPath("InputHeaderjava2.header"), expected);
      }
  
      @Test
      public void testIgnore() throws Exception {
          final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
          checkConfig.addProperty("headerFile", getPath("InputHeaderjava.header"));
          checkConfig.addProperty("ignoreLines", "2");
          final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
          verify(checkConfig, getPath("InputHeaderjava2.header"), expected);
      }
  
      @Test
      public void testSetHeaderTwice() {
          final HeaderCheck check = new HeaderCheck();
          check.setHeader("Header");
          final IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> {
              check.setHeader("Header2");
          });
          assertWithMessage("Invalid exception message")
                  .that(ex)
                  .hasMessageThat()
                          .isEqualTo("header has already been set - "
                                  + "set either header or headerFile, not both");
      }
  
      @Test
      public void testIoExceptionWhenLoadingHeaderFile() throws Exception {
          final HeaderCheck check = new HeaderCheck();
          check.setHeaderFile(new URI("test://bad"));
  
          final ReflectiveOperationException ex = assertThrows(ReflectiveOperationException.class,
              () -> TestUtil.invokeMethod(check, "loadHeaderFile"));
          assertWithMessage("Invalid exception cause message")
              .that(ex)
                  .hasCauseThat()
                      .hasMessageThat()
                      .startsWith("unable to load header file ");
      }
  
      @Test
      public void testCacheHeaderFile() throws Exception {
          final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
          checkConfig.addProperty("headerFile", getPath("InputHeaderjava.header"));
  
          final DefaultConfiguration checkerConfig = createRootConfig(checkConfig);
          final File cacheFile = File.createTempFile("junit", null, temporaryFolder);
          checkerConfig.addProperty("cacheFile", cacheFile.getPath());
  
          final String[] expected = {
              "1: " + getCheckMessage(MSG_MISSING),
          };
  
          verify(checkerConfig, getPath("InputHeader.java"), expected);
          // One more time to use cache.
          verify(checkerConfig, getPath("InputHeader.java"), expected);
      }
  
      @Test
      public void testCacheHeaderWithoutFile() throws Exception {
          final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
          checkConfig.addProperty("header", "Test");
  
          final DefaultConfiguration checkerConfig = createRootConfig(checkConfig);
          final File cacheFile = File.createTempFile("junit", null, temporaryFolder);
          checkerConfig.addProperty("cacheFile", cacheFile.getPath());
  
          final String[] expected = {
              "1: " + getCheckMessage(MSG_MISMATCH, "Test"),
          };
  
          verify(checkerConfig, getPath("InputHeader.java"), expected);
      }
  
      @Test
      public void testIgnoreLinesSorted() throws Exception {
          final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
          checkConfig.addProperty("headerFile", getPath("InputHeaderjava.header"));
          checkConfig.addProperty("ignoreLines", "4,2,3");
          final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
          verify(checkConfig, getPath("InputHeaderjava3.header"), expected);
      }
  
      @Test
      public void testLoadHeaderFileTwice() {
          final HeaderCheck check = new HeaderCheck();
          check.setHeader("Header");
          final ReflectiveOperationException ex = assertThrows(ReflectiveOperationException.class,
                  () -> TestUtil.invokeMethod(check, "loadHeaderFile"));
          assertWithMessage("Invalid exception cause message")
                  .that(ex)
                  .hasCauseThat()
                          .hasMessageThat()
                                  .isEqualTo("header has already been set - "
                                      + "set either header or headerFile, not both");
      }
  
      @Test
      public void testHeaderIsValidWithBlankLines() throws Exception {
          final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
          checkConfig.addProperty("headerFile", getPath("InputHeaderjava.blank-lines.header"));
          verify(checkConfig, getPath("InputHeaderBlankLines.java"));
      }
  
      @Test
      public void testHeaderIsValidWithBlankLinesBlockStyle() throws Exception {
          final DefaultConfiguration checkConfig = createModuleConfig(HeaderCheck.class);
          checkConfig.addProperty("headerFile", getPath("InputHeaderjava.blank-lines2.header"));
          verify(checkConfig, getPath("InputHeaderBlankLines2.java"));
      }
  
      @Test
      public void testExternalResource() throws Exception {
          final HeaderCheck check = new HeaderCheck();
          final URI uri = CommonUtil.getUriByFilename(getPath("InputHeaderjava.header"));
          check.setHeaderFile(uri);
          final Set<String> results = check.getExternalResourceLocations();
          assertWithMessage("Invalid result size")
              .that(results.size())
              .isEqualTo(1);
          assertWithMessage("Invalid resource location")
              .that(results.iterator().next())
              .isEqualTo(uri.toString());
      }
  
      @Test
      public void testIoExceptionWhenLoadingHeader() {
          final HeaderCheck check = new HeaderCheck();
          try (MockedConstruction<LineNumberReader> mocked = mockConstruction(
                  LineNumberReader.class, (mock, context) -> {
                      when(mock.readLine()).thenThrow(IOException.class);
                  })) {
              final IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> {
                  check.setHeader("header");
              });
              assertWithMessage("Invalid exception cause")
                      .that(ex)
                      .hasCauseThat()
                              .isInstanceOf(IOException.class);
              assertWithMessage("Invalid exception message")
                      .that(ex)
                      .hasMessageThat()
                              .isEqualTo("unable to load header");
          }
      }
  
  }
  