Commit a294e06e authored by jcechace's avatar jcechace
Browse files

Initial project assignment

parents
# Created by .ignore support plugin (hsz.mobi)
### Java template
*.class
# Package Files #
*.jar
*.war
*.ear
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
*.iml
## Directory-based project format:
.idea/
## File-based project format:
*.ipr
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
### Maven template
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
### NetBeans template
nbproject/private/
build/
nbbuild/
dist/
nbdist/
nbactions.xml
nb-configuration.xml
.nb-gradle/
# Vim
*.un~
# OS X .DS_Store
.DS_Store
image: maven:3-jdk-11
build:
script:
- mvn clean install -B -Dcheckstyle.fail=true
tags:
- shared-fi
<?xml version="1.0"?>
<!DOCTYPE module PUBLIC
"-//Puppy Crawl//DTD Check Configuration 1.3//EN"
"http://www.puppycrawl.com/dtds/configuration_1_3.dtd">
<module name="Checker">
<!--<property name="fileExtensions" value="java, xml, properties"/>-->
<!-- Checks for whitespace -->
<!-- See http://checkstyle.sf.net/config_whitespace.html -->
<module name="FileTabCharacter"/>
<module name="TreeWalker">
<!-- Checks for Javadoc comments. -->
<!-- See http://checkstyle.sf.net/config_javadoc.html -->
<module name="JavadocMethod">
<property name="scope" value="public"/>
<property name="allowMissingPropertyJavadoc" value="true"/>
</module>
<module name="JavadocType">
<property name="scope" value="public"/>
</module>
<module name="JavadocStyle">
<property name="scope" value="public"/>
<property name="checkFirstSentence" value="false"/>
</module>
<!-- Checks for Naming Conventions. -->
<!-- See http://checkstyle.sf.net/config_naming.html -->
<module name="ConstantName"/>
<module name="LocalFinalVariableName"/>
<module name="LocalVariableName"/>
<module name="MemberName"/>
<module name="MethodName"/>
<module name="PackageName"/>
<module name="ParameterName"/>
<module name="StaticVariableName"/>
<module name="TypeName"/>
<!-- Checks for imports -->
<!-- See http://checkstyle.sf.net/config_import.html -->
<module name="AvoidStarImport"/>
<module name="IllegalImport"/> <!-- defaults to sun.* packages -->
<module name="RedundantImport"/>
<module name="UnusedImports"/>
<!-- Checks for Size Violations. -->
<!-- See http://checkstyle.sf.net/config_sizes.html -->
<module name="LineLength">
<property name="max" value="120"/>
</module>
<module name="MethodLength">
<property name="max" value="50"/>
<property name="countEmpty" value="false"/>
</module>
<module name="ParameterNumber"/>
<!-- Modifier Checks -->
<!-- See http://checkstyle.sf.net/config_modifier.html -->
<module name="ModifierOrder"/>
<module name="RedundantModifier"/>
<!-- Checks for blocks. You know, those {}'s -->
<!-- See http://checkstyle.sf.net/config_blocks.html -->
<module name="AvoidNestedBlocks"/>
<module name="LeftCurly">
<property name="option" value="eol"/>
</module>
<module name="NeedBraces">
<property name="allowSingleLineStatement" value="false"/>
</module>
<module name="RightCurly"/>
<!-- Checks for common coding problems -->
<!-- See http://checkstyle.sf.net/config_coding.html -->
<module name="EmptyStatement"/>
<module name="EqualsHashCode"/>
<module name="MissingSwitchDefault"/>
<module name="SimplifyBooleanExpression"/>
<module name="SimplifyBooleanReturn"/>
<!-- Checks for class design -->
<!-- See http://checkstyle.sf.net/config_design.html -->
<module name="FinalClass"/>
<module name="InterfaceIsType"/>
<module name="VisibilityModifier">
<property name="protectedAllowed" value="true"/>
</module>
<!-- Miscellaneous other checks. -->
<!-- See http://checkstyle.sf.net/config_misc.html -->
<module name="ArrayTypeStyle"/>
</module>
</module>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cz.muni.fi.pb162</groupId>
<artifactId>homework03-2021</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<checkstyle.fail>true</checkstyle.fail>
<!-- dependency versions -->
<version.plugin.checkstyle>2.17</version.plugin.checkstyle>
<version.plugin.source>2.4</version.plugin.source>
<version.junit>5.6.2</version.junit>
<version.mockito>3.9.0</version.mockito>
<version.assertj>3.19.0</version.assertj>
<version.jcommander>1.78</version.jcommander>
<version.system-labda>1.2.0</version.system-labda>
</properties>
<dependencies>
<dependency>
<groupId>com.beust</groupId>
<artifactId>jcommander</artifactId>
<version>${version.jcommander}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${version.junit}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${version.assertj}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>${version.mockito}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-inline</artifactId>
<version>${version.mockito}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.stefanbirkner</groupId>
<artifactId>system-lambda</artifactId>
<version>${version.system-labda}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Include sources into JAR -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>${version.plugin.source}</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Executable jar -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>application</finalName>
<shadedArtifactAttached>true</shadedArtifactAttached>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>cz.muni.fi.pb162.hw03.app.impl.Application</mainClass>
</transformer>
</transformers>
<filters>
<filter>
<artifact>com.beust:jcommander</artifact>
<excludes>
<exclude>META-INF/*.MF</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
<!-- surefire Config -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
</configuration>
</plugin>
<!-- Check code style -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>${version.plugin.checkstyle}</version>
<executions>
<execution>
<id>validate</id>
<phase>validate</phase>
<configuration>
<configLocation>pb162_codestyle.xml</configLocation>
<encoding>UTF-8</encoding>
<consoleOutput>true</consoleOutput>
<failOnViolation>${checkstyle.fail}</failOnViolation>
<violationSeverity>warning</violationSeverity>
<includeTestSourceDirectory>false</includeTestSourceDirectory>
<excludes>*/**/Demo</excludes>
</configuration>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
package cz.muni.fi.pb162.hw03.csv;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
/**
* CSV Parser able to either open a source of CSV data or to directly read all the data
*/
public interface CsvParser {
/**
* Default delimiter is a comma
*/
String DEFAULT_DELIMITER = ",";
/**
* Default character encoding
*/
Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
/**
* Opens {@link CsvReader} from given path to read data from
*
* @param path file path
* @return instance of @{CsvReader} capable of reading plain CSV data
* @throws IOException on any IO error
*/
CsvReader<List<String>> open(Path path) throws IOException;
/**
* Opens {@link CsvReader} from given {@link InputStream} to read CSV data from
*
* @param is source of data
* @return instance of @{CsvReader} capable of reading plain CSV data
* @throws IOException on any IO error
*/
CsvReader<List<String>> open(InputStream is) throws IOException;
/**
* Opens {@link CsvReader} from given {@link InputStream} to read CSV data with header from
*
* @param path file path
* @return instance of @{CsvReader} capable of reading CSV data <strong>with header</strong>
* @throws IOException on any IO error
*/
CsvReader<Map<String, String>> openWithHeader(Path path) throws IOException;
/**
* Opens {@link CsvReader} from given {@link InputStream} to read CSV data with header from
*
* @param is source of data
* @return instance of @{CsvReader} capable of reading CSV data <strong>with header</strong>
* @throws IOException on any IO error
*/
CsvReader<Map<String, String>> openWithHeader(InputStream is) throws IOException;
/**
* Reads all CSV data from given path
*
* @param path file path
* @return read CSV data
* @throws IOException on any IO error
*/
List<List<String>> readAll(Path path) throws IOException;
/**
* Reads all CSV data <strong>with header</strong> from given path
*
* @param path file path
* @return read CSV data <strong>with header</strong>
* @throws IOException on any IO error
*/
List<Map<String, String>> readAllWithHeader(Path path) throws IOException;
}
package cz.muni.fi.pb162.hw03.csv;
import java.io.Closeable;
import java.io.IOException;
import java.util.function.Consumer;
/**
* Interface for classes providing the capability of reading CSV data
*
* @param <T> type parameter of {@link #read()} result
*/
public interface CsvReader<T> extends Closeable {
/**
* Reads single line of CSV data
* Trims leading and trailing whitespaces around row entries
*
* @return process line of CSV
* @throws IOException on any IO error
*/
T read() throws IOException;
/**
* Consumes each line of CSV data
*
* @param consumer consumer called with each line of CSV
* @throws IOException on any IO error
*/
void forEach(Consumer<T> consumer) throws IOException;
}
package cz.muni.fi.pb162.hw03.csv;
/**
* Error messages
*/
public final class Messages {
private Messages() {
// intentionally private to prevent instantiation
}
public static final String INVALID_FORMAT = "Invalid file format";
}
package cz.muni.fi.pb162.hw03.csv.impl;
import cz.muni.fi.pb162.hw03.csv.CsvParser;
import java.nio.charset.Charset;
/**
* Factory class for CSV processing
*/
public final class CsvToolkit {
private CsvToolkit() {
// intentionally private to prevent instantiation
}
/**
* Creates instance of {@link CsvParser} with default delimiter and charset
*
* @return parser
*/
public static CsvParser parser() {
throw new UnsupportedOperationException("Implement this method!");
}
/**
* Creates instance of {@link CsvParser} with given delimiter
*
* @param delimiter value delimiter
* @param charset character encoding
* @return parser
*/
public static CsvParser parser(String delimiter, Charset charset) {
throw new UnsupportedOperationException("Implement this method!");
}
}
package cz.muni.fi.pb162.hw03;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
public class TestUtils {
private TestUtils() {
}
public static Path resourcePath(String path) throws URISyntaxException {
return Paths.get(TestUtils.class.getResource(path).toURI());
}
}
\ No newline at end of file
package cz.muni.fi.pb162.hw03.csv;
import cz.muni.fi.pb162.hw03.csv.impl.CsvToolkit;
import org.assertj.core.api.SoftAssertions;
import org.assertj.core.api.junit.jupiter.InjectSoftAssertions;
import org.assertj.core.api.junit.jupiter.SoftAssertionsExtension;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import static cz.muni.fi.pb162.hw03.TestUtils.resourcePath;
@ExtendWith(SoftAssertionsExtension.class)
public class CsvParserEncodingTest {
@InjectSoftAssertions
private SoftAssertions softly;
private CsvParser parser;
@BeforeEach
void setUp() {
parser = CsvToolkit.parser(",", Charset.forName("ISO-8859-2"));
}
@Test
@DisplayName("Loads plain CSV data with Latin 2 encoding")
public void plainCsv() throws Exception {
List<List<String>> data = parser.readAll(resourcePath("/plain_iso-8859-2.csv"));
softly.assertThat(data).containsExactlyElementsOf(List.of(
List.of("příliš", "žluťoučký", "kůň"),
List.of("úpěl", "ďábelské", "ódy")
));
}
@Test
@DisplayName("Loads plain CSV data with Latin 2 encoding")
public void plainCsvWithReader() throws Exception {
var expected = List.of(
List.of("příliš", "žluťoučký", "kůň"),
List.of("úpěl", "ďábelské", "ódy")
);
List<List<String>> actual = new ArrayList<>();
try (var reader = parser.open((resourcePath("/plain_iso-8859-2.csv")))) {
reader.forEach(actual::add);
softly.assertThat(reader.read()).isNull();
}
softly.assertThat(actual).containsExactlyElementsOf(expected);
}
}
package cz.muni.fi.pb162.hw03.csv;
import cz.muni.fi.pb162.hw03.csv.impl.CsvToolkit;
import org.assertj.core.api.SoftAssertions;
import org.assertj.core.api.junit.jupiter.InjectSoftAssertions;
import org.assertj.core.api.junit.jupiter.SoftAssertionsExtension;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import static cz.muni.fi.pb162.hw03.TestUtils.resourcePath;
@ExtendWith(SoftAssertionsExtension.class)
public class CsvParserTest {
@InjectSoftAssertions
private SoftAssertions softly;
private CsvParser parser;
@BeforeEach
void setUp() {
parser = CsvToolkit.parser(",", StandardCharsets.UTF_8);
}
@Test
@DisplayName("Loads plain CSV data")
public void plainCsv() throws Exception {
List<List<String>> data = parser.readAll(resourcePath("/plain.csv"));
softly.assertThat(data).containsExactlyElementsOf(List.of(
List.of("1", "H", "Hydrogen", "gas", "nonmetal", "1766"),
List.of("2", "He", "Helium", "gas", "noble gas", "1868"),
List.of("3", "Li", "Lithium", "solid", "alkali metal", "1817")
));
}
@Test
@DisplayName("Loads plain CSV data with different row lengths")
public void plainCsvDifferentRowLength() throws Exception {
List<List<String>> data = parser.readAll(resourcePath("/plain_broken.csv"));
softly.assertThat(data).containsExactlyElementsOf(List.of(
List.of("1", "H", "Hydrogen", "gas", "nonmetal", "1766"),
List.of("2", "He", "Helium", "gas", "noble gas", "1868", "broken")
));
}
@Test
@DisplayName("Loads CSV data with header as plain")
public void headedCsvAsPlain() throws Exception {
List<List<String>> data = parser.readAll(resourcePath("/header.csv"));
softly.assertThat(data).containsExactlyElementsOf(List.of(
List.of("atomicNumber", "symbol", "name", "standardState", "groupBlock", "yearDiscovered"),
List.of("1", "H", "Hydrogen", "gas", "nonmetal", "1766"),
List.of("2", "He", "Helium", "gas", "noble gas", "1868"),
List.of("3", "Li", "Lithium", "solid", "alkali metal", "1817"),