Skip to content

Commit

Permalink
Resolves #153:
Browse files Browse the repository at this point in the history
1. Addressed review comments of the workflow by adding a new parameter as output of default proj list
2. Earlier code was using file system to load class, had to replace with inputStream as jars need classLoader
  • Loading branch information
piyush kumar sadangi authored and romani committed Aug 20, 2024
1 parent 4aeced1 commit a8fc498
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
package com.example.extractor;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
Expand Down Expand Up @@ -76,7 +78,7 @@ public final class CheckstyleExampleExtractor {
/**
* Number of expected arguments when processing a single input file.
*/
private static final int SINGLE_INPUT_FILE_ARG_COUNT = 4;
private static final int SINGLE_INPUT_FILE_ARG_COUNT = 5;

/**
* Index of the "--input-file" flag in the argument array.
Expand All @@ -93,6 +95,16 @@ public final class CheckstyleExampleExtractor {
*/
private static final int OUTPUT_FILE_PATH_INDEX = 3;

/**
* Index of the output file path in the argument array.
*/
private static final int PROJECT_OUTPUT_PATH_INDEX = 4;

/**
* The buffer size for reading and writing files.
*/
private static final int BUFFER_SIZE = 1024;

/**
* Private constructor to prevent instantiation of this utility class.
*/
Expand All @@ -119,8 +131,14 @@ public static void main(final String[] args) throws Exception {
&& "--input-file".equals(args[INPUT_FILE_FLAG_INDEX])) {
// New functionality: process single input file
final String inputFilePath = args[INPUT_FILE_PATH_INDEX];
final String outputFilePath = args[OUTPUT_FILE_PATH_INDEX];
processInputFile(Paths.get(inputFilePath), Paths.get(outputFilePath));
final String configOutputPath = args[OUTPUT_FILE_PATH_INDEX];
final String projectsOutputPath = args[PROJECT_OUTPUT_PATH_INDEX];

// Process input file and generate config
processInputFile(Paths.get(inputFilePath), Paths.get(configOutputPath));

// Output default projects list
outputDefaultProjectsList(projectsOutputPath);
}
else {
// Functionality: process all examples
Expand All @@ -137,13 +155,37 @@ public static void main(final String[] args) throws Exception {
}
}

/**
* Writes the default projects list to the specified file.
*
* @param outputPath the file path to write the list.
* @throws IllegalStateException if I/O error occurs while readin or writing to file
*/
public static void outputDefaultProjectsList(final String outputPath) {
try (InputStream inputStream = CheckstyleExampleExtractor.class
.getResourceAsStream("/list-of-projects.properties");
OutputStream outputStream = Files.newOutputStream(Path.of(outputPath))) {

final byte[] buffer = new byte[BUFFER_SIZE];
int length = inputStream.read(buffer);
while (length > 0) {
outputStream.write(buffer, 0, length);
length = inputStream.read(buffer);
}
}
catch (IOException ex) {
throw new IllegalStateException("Error outputting default projects list", ex);
}
}

/**
* Processes an input file and generates an output file.
*
* @param inputFile The path to the input file
* @param outputFile The path to the output file
* @throws Exception If an error occurs during processing
* @throws IOException if the argument is invalid.
* @throws IllegalArgumentException if the argument is invalid.
* @throws IOException if resource not found
*/
public static void processInputFile(
final Path inputFile,
Expand All @@ -155,11 +197,33 @@ public static void processInputFile(
throw new IOException("Input file does not exist: " + inputFile);
}

// Get the template file path and serialize the configuration
final String templateFilePath = getTemplateFilePathForInputFile(inputFile.toString());
// Parse the input file to determine if it's a TreeWalker check
final TestInputConfiguration testInputConfiguration =
InlineConfigParser.parse(inputFile.toString());
final List<ModuleInputConfiguration> modules =
testInputConfiguration.getChildrenModules();

if (modules.isEmpty()) {
throw new IllegalArgumentException("No modules found in the input file");
}

final ModuleInputConfiguration mainModule = modules.get(0);
final String moduleName = mainModule.getModuleName();
final boolean isTreeWalker = ConfigSerializer.isTreeWalkerCheck(moduleName);

// Get the template file name based on whether it's a TreeWalker check or not
final String templateFileName;
if (isTreeWalker) {
templateFileName = "config-template-treewalker.xml";
}
else {
templateFileName = "config-template-non-treewalker.xml";
}

// Serialize the configuration
final String generatedContent = ConfigSerializer.serializeNonXmlConfigToString(
inputFile.toString(),
templateFilePath
templateFileName
);

// Write the generated content to the output file
Expand Down
91 changes: 80 additions & 11 deletions extractor/src/main/java/com/example/extractor/ConfigSerializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@

package com.example.extractor;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
Expand All @@ -33,6 +37,7 @@
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import java.util.stream.Collectors;

import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
Expand Down Expand Up @@ -93,30 +98,36 @@ private ConfigSerializer() {
* Serializes a configuration to a string from a non-XML format input file.
*
* @param inputFilePath Path to the input file
* @param templateFilePath Path to the template file
* @param templateFileName Path to the template file
* @return Serialized configuration as a string
* @throws IllegalArgumentException If no modules are found in the input file
* @throws Exception If an unexpected error occurs
*/
public static String serializeNonXmlConfigToString(
final String inputFilePath,
final String templateFilePath) throws Exception {
final TestInputConfiguration testInputConfiguration =
InlineConfigParser.parse(inputFilePath);
final List<ModuleInputConfiguration> modules = testInputConfiguration.getChildrenModules();

if (modules.isEmpty()) {
throw new IllegalArgumentException("No modules found in the input file");
final String templateFileName) throws Exception {
if (inputFilePath == null || templateFileName == null) {
throw new IllegalArgumentException(
"Input file path and template resource name must not be null"
);
}

final ModuleInputConfiguration mainModule = modules.get(0);
final ModuleInputConfiguration mainModule = parseAndValidateInputFile(inputFilePath);

final String moduleName = extractSimpleModuleName(mainModule.getModuleName());
final Map<String, String> properties = mainModule.getNonDefaultProperties();

final String template = Files.readString(Path.of(templateFilePath), StandardCharsets.UTF_8);
LOGGER.info("Reading template resource: " + templateFileName);
final String template = readResourceAsString(templateFileName);
if (template == null || template.isEmpty()) {
throw new IllegalArgumentException(
"Failed to read template resource: " + templateFileName
);
}

final Configuration moduleConfig = createConfigurationFromModule(moduleName, properties);
final boolean isTreeWalker = isTreeWalkerCheck(mainModule.getModuleName());

final String baseIndent;
if (isTreeWalker) {
baseIndent = TREE_WALKER_INDENT;
Expand All @@ -126,7 +137,65 @@ public static String serializeNonXmlConfigToString(
}

final String moduleContent = buildSingleModuleContent(moduleConfig, baseIndent);
return TemplateProcessor.replacePlaceholders(template, moduleContent, isTreeWalker);
return TemplateProcessor.replacePlaceholders(template, moduleContent, isTreeWalker) + "\n";
}

/**
* Parses and validates the input file to extract the main module configuration.
*
* @param inputFilePath the path to the input file.
* @return the main {@link ModuleInputConfiguration} extracted from the input file.
* @throws IllegalArgumentException if parsing fails or no valid modules are found.
* @throws Exception if an unexpected error occurs.
*/
private static ModuleInputConfiguration parseAndValidateInputFile(final String inputFilePath)
throws Exception {
LOGGER.info("Parsing input file: " + inputFilePath);
final TestInputConfiguration testInputConfiguration =
InlineConfigParser.parse(inputFilePath);

if (testInputConfiguration == null) {
throw new IllegalArgumentException("Failed to parse input file: " + inputFilePath);
}

final List<ModuleInputConfiguration> modules = testInputConfiguration.getChildrenModules();

if (modules == null || modules.isEmpty()) {
throw new IllegalArgumentException(
"No modules found in the input file: " + inputFilePath
);
}

final ModuleInputConfiguration mainModule = modules.get(0);
if (mainModule == null) {
throw new IllegalArgumentException(
"Main module is null in the input file: " + inputFilePath
);
}

return mainModule;
}

/**
* Reads the content of a resource file as a string.
*
* @param resourceName the name of the resource to be read.
* @return the content of the resource file as a string.
* @throws IOException if the resource is not found or if an I/O error occurs.
*/
private static String readResourceAsString(final String resourceName) throws IOException {
try (InputStream inputStream = Thread.currentThread()
.getContextClassLoader()
.getResourceAsStream(resourceName)) {
if (inputStream == null) {
throw new IOException("Resource not found: " + resourceName);
}
try (BufferedReader reader =
new BufferedReader(new InputStreamReader(inputStream,
StandardCharsets.UTF_8))) {
return reader.lines().collect(Collectors.joining("\n"));
}
}
}

/**
Expand Down
16 changes: 11 additions & 5 deletions extractor/src/test/java/com/example/extractor/MainTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,16 @@ class MainTest {
"src/main/resources/config-template-treewalker.xml";

/**
* The constant for non-Treewalker template file.
* The constant for Treewalker template file for input java file conditions.
*/
private static final String NON_TREEWALKER_TEMPLATE_FILE =
"src/main/resources/config-template-non-treewalker.xml";
private static final String TW_TEMPLATE_FILE_INPUT_JAVA =
"config-template-treewalker.xml";

/**
* The constant for non-Treewalker template file for input java file conditions.
*/
private static final String NTW_TEMPLATE_FILE_INPUT_JAVA =
"config-template-non-treewalker.xml";

/**
* The constant for base path of test resources.
Expand Down Expand Up @@ -255,7 +261,7 @@ void testGeneratedConfigForNonXmlInputWithTreewalker() throws Exception {
+ "/whitespace/methodparampad/Config/expected-config.xml";

final String generatedContent = ConfigSerializer.serializeNonXmlConfigToString(
inputFilePath, TREEWALKER_TEMPLATE_FILE);
inputFilePath, TW_TEMPLATE_FILE_INPUT_JAVA);
final String expectedContent = loadToString(expectedInputFilePath);
assertThat(generatedContent).isEqualTo(expectedContent);
}
Expand All @@ -274,7 +280,7 @@ void testGeneratedConfigForNonXmlInputWithNonTreewalker() throws Exception {
+ "/whitespace/filetabcharacter/Config/expected-config.xml";

final String generatedContent = ConfigSerializer.serializeNonXmlConfigToString(
inputFilePath, NON_TREEWALKER_TEMPLATE_FILE);
inputFilePath, NTW_TEMPLATE_FILE_INPUT_JAVA);
final String expectedContent = loadToString(expectedInputFilePath);
assertThat(generatedContent).isEqualTo(expectedContent);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@

import static com.google.common.truth.Truth.assertThat;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
Expand All @@ -49,6 +51,11 @@ class MainsLauncherTest {
private static final String CHECKSTYLE_CHECKS_BASE_PATH =
"com/puppycrawl/tools/checkstyle/checks";

/**
* The constant for default projects file.
*/
private static final String DEFAULT_PROJECTS_FILE = "list-of-projects.properties";

/**
* Tests the main method of CheckstyleExampleExtractor.
* This test ensures that the main method runs without throwing any exceptions.
Expand All @@ -69,31 +76,48 @@ void testMain() {
*/
@Test
void testMainWithInputFile(@TempDir final Path tempDir) throws Exception {
final String inputFilePath = "src/test/resources/"
+ CHECKSTYLE_CHECKS_BASE_PATH
final String inputFilePath = "src/test/resources/" + CHECKSTYLE_CHECKS_BASE_PATH
+ "/whitespace/methodparampad/InputFile/InputMethodParamPadWhitespaceAround.java";

final String expectedInputFilePath = "src/test/resources/"
+ CHECKSTYLE_CHECKS_BASE_PATH
final String expectedInputFilePath = "src/test/resources/" + CHECKSTYLE_CHECKS_BASE_PATH
+ "/whitespace/methodparampad/Config/expected-config.xml";

final String expectedContent = loadToString(expectedInputFilePath);
final String expectedProjectsContent = loadDefaultProjectsList();

final Path outputFile = tempDir.resolve("output-config.xml");
final Path outputConfigFile = tempDir.resolve("output-config.xml");
final Path outputProjectsFile = tempDir.resolve("output-projects.properties");

assertDoesNotThrow(() -> {
CheckstyleExampleExtractor.main(new String[]{
CHECKSTYLE_REPO_PATH,
"--input-file",
inputFilePath,
outputFile.toString(),
outputConfigFile.toString(),
outputProjectsFile.toString(),
});
});

assertTrue(Files.exists(outputFile), "Output file should be created");
final String generatedContent = Files.readString(outputFile);
assertTrue(Files.exists(outputConfigFile), "Config output file should be created");
assertTrue(Files.exists(outputProjectsFile), "Projects output file should be created");

final String generatedConfigContent = Files.readString(outputConfigFile);
assertThat(generatedConfigContent).isEqualTo(expectedContent);

final String generatedProjectsContent = Files.readString(outputProjectsFile);
assertFalse(generatedProjectsContent.isEmpty(), "Projects file should not be empty");
assertThat(generatedProjectsContent).isEqualTo(expectedProjectsContent);
}

assertThat(generatedContent).isEqualTo(expectedContent);
/**
* Loads the default projects list from the resource file.
*
* @return the content of the projects list as a string.
* @throws IOException if an error occurs while reading the resource.
*/
private String loadDefaultProjectsList() throws IOException {
try (InputStream inputStream = Thread.currentThread().getContextClassLoader()
.getResourceAsStream(DEFAULT_PROJECTS_FILE)) {
return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
}
}

/**
Expand Down

0 comments on commit a8fc498

Please sign in to comment.