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.meta;
  
  import static com.google.common.truth.Truth.assertWithMessage;
  import static com.puppycrawl.tools.checkstyle.meta.JavadocMetadataScraper.MSG_DESC_MISSING;
  
  import java.nio.file.Files;
  import java.nio.file.Path;
  import java.nio.file.Paths;
  import java.util.Arrays;
  import java.util.LinkedHashSet;
  import java.util.Set;
  import java.util.regex.Matcher;
  import java.util.regex.Pattern;
  import java.util.stream.Collectors;
  import java.util.stream.Stream;
  
  import org.itsallcode.io.Capturable;
  import org.itsallcode.junit.sysextensions.SystemOutGuard;
  import org.junit.jupiter.api.Test;
  import org.junit.jupiter.api.extension.ExtendWith;
  
  import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
  import com.puppycrawl.tools.checkstyle.internal.utils.CheckUtil;
  
  @ExtendWith(SystemOutGuard.class)
  public final class MetadataGeneratorUtilTest extends AbstractModuleTestSupport {
  
      private final Set<String> modulesContainingNoMetadataFile = Set.of(
              "Checker",
              "TreeWalker",
              "JavadocMetadataScraper"
      );
  
      @Override
      protected String getPackageLocation() {
          return null;
      }
  
      /**
       * Generates metadata for checkstyle modules and verifies number of
       * generated metadata modules match the number of checkstyle modules.
       * Also verifies whether every checkstyle module contains description.
       *
       * @param systemOut wrapper for {@code System.out}
       * @throws Exception if exception occurs during generating metadata or
       *                   if an I/O error is thrown when accessing the starting file.
       * @noinspection UseOfSystemOutOrSystemErr
       * @noinspectionreason UseOfSystemOutOrSystemErr - generation of metadata
       *      requires {@code System.out} for error messages
       */
      @Test
      public void testMetadataFilesGenerationAllFiles(@SystemOutGuard.SysOut Capturable systemOut)
              throws Exception {
          systemOut.captureMuted();
  
          MetadataGeneratorUtil.generate(System.getProperty("user.dir")
                          + "/src/main/java/com/puppycrawl/tools/checkstyle",
                  System.out, "checks", "filters", "filefilters");
  
          final String[] expectedErrorMessages = {
              "31: " + getCheckMessage(MSG_DESC_MISSING, "AbstractSuperCheck"),
              "45: " + getCheckMessage(MSG_DESC_MISSING, "AbstractHeaderCheck"),
              "42: " + getCheckMessage(MSG_DESC_MISSING, "AbstractJavadocCheck"),
              "45: " + getCheckMessage(MSG_DESC_MISSING, "AbstractClassCouplingCheck"),
              "26: " + getCheckMessage(MSG_DESC_MISSING, "AbstractAccessControlNameCheck"),
              "30: " + getCheckMessage(MSG_DESC_MISSING, "AbstractNameCheck"),
              "30: " + getCheckMessage(MSG_DESC_MISSING, "AbstractParenPadCheck"),
          };
  
          final String[] actualViolations = systemOut.getCapturedData().split("\\n");
          final Pattern violationExtractingPattern = Pattern.compile("((?<=:)\\d.*:.*(?=\\s\\[))");
  
          Arrays.setAll(actualViolations, id -> {
              final Matcher matcher = violationExtractingPattern.matcher(actualViolations[id]);
              matcher.find();
              return matcher.group(1);
          });
  
          assertWithMessage("Expected and actual errors do not match")
                  .that(expectedErrorMessages)
                  .asList()
                  .containsExactlyElementsIn(actualViolations);
  
          final Set<String> metaFiles;
          try (Stream<Path> fileStream = Files.walk(
                  Paths.get(System.getProperty("user.dir") + "/src/main/resources/com/puppycrawl"
                          + "/tools/checkstyle/meta"))) {
              metaFiles = fileStream
                      .filter(Files::isRegularFile)
                      .filter(path -> !path.toString().endsWith(".properties"))
                      .map(MetadataGeneratorUtilTest::getMetaFileName)
                      .sorted()
                      .collect(Collectors.toCollection(LinkedHashSet::new));
          }
          final Set<String> checkstyleModules =
                  CheckUtil.getSimpleNames(CheckUtil.getCheckstyleModules())
                  .stream()
                  .sorted()
                  .collect(Collectors.toCollection(LinkedHashSet::new));
          checkstyleModules.removeAll(modulesContainingNoMetadataFile);
          assertWithMessage("Number of generated metadata files dont match with "
                  + "number of checkstyle module")
                  .that(metaFiles)
                  .isEqualTo(checkstyleModules);
      }
  
      /**
       * Get meta file name from full file name.
       *
       * @param file file to process
       * @return meta file name
       */
      private static String getMetaFileName(Path file) {
          final String fileName = file.getFileName().toString();
          final int lengthToOmit;
          if (fileName.contains("Check")) {
              lengthToOmit = "Check.xml".length();
          }
          else {
              lengthToOmit = ".xml".length();
          }
          return fileName.substring(0, fileName.length() - lengthToOmit);
      }
  }
  