Skip to content

Commit

Permalink
Polishing
Browse files Browse the repository at this point in the history
  • Loading branch information
valfirst committed Oct 10, 2024
1 parent 4c087e0 commit d2f7ae0
Show file tree
Hide file tree
Showing 11 changed files with 137 additions and 199 deletions.
43 changes: 8 additions & 35 deletions vividus-plugin-csv/src/main/java/org/vividus/csv/CsvReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,12 @@

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;

import org.apache.commons.csv.CSVFormat;
Expand All @@ -46,43 +43,19 @@ public CsvReader(CSVFormat csvFormat)
this.csvFormat = csvFormat;
}

public List<Map<String, String>> readCsvFile(Path path, String... header) throws IOException
{
try (Reader reader = new InputStreamReader(Files.newInputStream(path), StandardCharsets.UTF_8))
{
return collectCsv(reader, header);
}
}

public List<Map<String, String>> readCsvString(String csvString, String... header) throws IOException
{
return readCsvBytes(csvString.getBytes(StandardCharsets.UTF_8), header);
}

public List<Map<String, String>> readCsvBytes(byte[] csvAsBytes, String... header) throws IOException
{
try (Reader reader = new InputStreamReader(new ByteArrayInputStream(csvAsBytes),
StandardCharsets.UTF_8))
{
return collectCsv(reader, header);
}
return readCsvStream(new ByteArrayInputStream(csvString.getBytes(StandardCharsets.UTF_8)), header);
}

public List<CSVRecord> readCsvFile(URL resourceUrl, String... header) throws IOException
public List<Map<String, String>> readCsvStream(InputStream inputStream, String... header) throws IOException
{
try (Reader reader = new InputStreamReader(resourceUrl.openStream(), StandardCharsets.UTF_8))
try (Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8))
{
return readCsvFile(reader, header).toList();
CSVFormat formatWithHeaders = csvFormat.builder().setHeader(header).build();
return StreamSupport.stream(formatWithHeaders.parse(reader).spliterator(), false)
.map(CSVRecord::toMap)
.toList();
}
}

private List<Map<String, String>> collectCsv(Reader reader, String... header) throws IOException
{
return readCsvFile(reader, header).map(CSVRecord::toMap).toList();
}

private Stream<CSVRecord> readCsvFile(Reader reader, String... header) throws IOException
{
return StreamSupport.stream(csvFormat.builder().setHeader(header).build().parse(reader).spliterator(), false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import static java.util.stream.Collectors.toList;
import static org.apache.commons.lang3.Validate.isTrue;
import static org.apache.commons.lang3.Validate.notEmpty;
import static org.vividus.util.ResourceUtils.loadResourceOrFileAsByteArray;
import static org.vividus.util.ResourceUtils.loadResourceOrFileAsStream;

import java.io.IOException;
import java.io.UncheckedIOException;
Expand Down Expand Up @@ -77,41 +77,34 @@ public String transform(String tableAsString, TableParsers tableParsers, TablePr
csvFormat = csvFormat.builder().setDelimiter(delimiter.charAt(0)).build();
}

List<Map<String, String>> result = VARIABLE_NAME_PROPERTY.equals(sourceKey)
? readCsvFromVariable(csvFormat, sourceValue)
: readCsvFromFile(csvFormat, sourceValue);
return ExamplesTableProcessor.buildExamplesTable(result.get(0).keySet(), extractValues(result),
tableProperties, true);
}

private List<Map<String, String>> readCsvFromFile(CSVFormat csvFormat, String path)
{
try
{
return new CsvReader(csvFormat).readCsvBytes(loadResourceOrFileAsByteArray(path));
List<Map<String, String>> result = VARIABLE_NAME_PROPERTY.equals(sourceKey)
? readCsvFromVariable(csvFormat, sourceValue)
: readCsvFromFile(csvFormat, sourceValue);
return ExamplesTableProcessor.buildExamplesTable(result.get(0).keySet(), extractValues(result),
tableProperties, true);
}
catch (IOException e)
{
throw new UncheckedIOException("Problem during CSV file reading", e);
throw new UncheckedIOException("Problem during CSV data reading", e);
}
}

private List<Map<String, String>> readCsvFromVariable(CSVFormat csvFormat, String variableName)
private List<Map<String, String>> readCsvFromFile(CSVFormat csvFormat, String path) throws IOException
{
try
{
String variableValue = variableContext.getVariable(variableName);
isTrue(StringUtils.isNotEmpty(variableValue), "Variable '%s' is not set or empty."
+ " Please check that variable is defined and has 'global' or 'next_batches' scope", variableName);
List<Map<String, String>> result = new CsvReader(csvFormat).readCsvString(variableValue);
notEmpty(result, "Unable to create examples table based on '%s' variable value."
+ " Please check that value has proper csv format", variableName);
return result;
}
catch (IOException e)
{
throw new UncheckedIOException("Problem during CSV String reading", e);
}
return new CsvReader(csvFormat).readCsvStream(loadResourceOrFileAsStream(path));
}

private List<Map<String, String>> readCsvFromVariable(CSVFormat csvFormat, String variableName) throws IOException
{
String variableValue = variableContext.getVariable(variableName);
isTrue(StringUtils.isNotEmpty(variableValue), "Variable '%s' is not set or empty."
+ " Please check that variable is defined and has 'global' or 'next_batches' scope", variableName);
List<Map<String, String>> result = new CsvReader(csvFormat).readCsvString(variableValue);
notEmpty(result, "Unable to create examples table based on '%s' variable value."
+ " Please check that value has proper csv format", variableName);
return result;
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2023 the original author or authors.
* Copyright 2019-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -19,15 +19,10 @@
import static org.junit.jupiter.api.Assertions.assertEquals;

import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;

import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVRecord;
import org.junit.jupiter.api.Test;

class CsvReaderTests
Expand All @@ -41,56 +36,30 @@ class CsvReaderTests
SECOND_VALUE);
private static final List<Map<String, String>> CSV_RECORDS = List.of(CSV_RECORD);

private final CsvReader csvReader = new CsvReader();

@Test
void testReadCsvFromPath() throws IOException, URISyntaxException
{
Path filePath = Paths.get(getCsvResource().toURI());
List<Map<String, String>> result = csvReader.readCsvFile(filePath, FIRST_HEADER, SECOND_HEADER);
assertEquals(CSV_RECORDS, result);
}

@Test
void testReadCsvWithEscapedDataFromPath() throws IOException, URISyntaxException
void testReadCsvWithEscapedDataFromPath() throws IOException
{
Path filePath = Paths.get(getCsvResource("unittest-escaped.csv").toURI());
var csvFormat = CSVFormat.DEFAULT.builder().setDelimiter(',').setEscape('\\').build();
List<Map<String, String>> result = new CsvReader(csvFormat).readCsvFile(filePath, FIRST_HEADER, SECOND_HEADER);
assertEquals(List.of(Map.of(FIRST_HEADER, FIRST_VALUE, SECOND_HEADER, "value2 with \" inside")), result);
try (var inputStream = getClass().getResourceAsStream("unittest-escaped.csv"))
{
var csvFormat = CSVFormat.DEFAULT.builder().setDelimiter(',').setEscape('\\').build();
var result = new CsvReader(csvFormat).readCsvStream(inputStream, FIRST_HEADER, SECOND_HEADER);
assertEquals(List.of(Map.of(FIRST_HEADER, FIRST_VALUE, SECOND_HEADER, "value2 with \" inside")), result);
}
}

@Test
void testReadCsvFromStringWithoutHeaders() throws IOException
{
String csv = FIRST_VALUE + COMMA + SECOND_VALUE;
List<Map<String, String>> result = csvReader.readCsvString(csv, FIRST_HEADER, SECOND_HEADER);
var csv = FIRST_VALUE + COMMA + SECOND_VALUE;
var result = new CsvReader().readCsvString(csv, FIRST_HEADER, SECOND_HEADER);
assertEquals(CSV_RECORDS, result);
}

@Test
void testReadCsvFromStringWithHeaders() throws IOException
{
String csv = FIRST_HEADER + COMMA + SECOND_HEADER + "\n" + FIRST_VALUE + COMMA + SECOND_VALUE;
List<Map<String, String>> result = csvReader.readCsvString(csv);
var csv = FIRST_HEADER + COMMA + SECOND_HEADER + "\n" + FIRST_VALUE + COMMA + SECOND_VALUE;
var result = new CsvReader().readCsvString(csv);
assertEquals(CSV_RECORDS, result);
}

@Test
void testReadCsvFromUrl() throws IOException
{
URL url = getCsvResource();
List<CSVRecord> result = csvReader.readCsvFile(url, FIRST_HEADER, SECOND_HEADER);
assertEquals(CSV_RECORDS, result.stream().map(CSVRecord::toMap).toList());
}

private URL getCsvResource()
{
return getCsvResource("unittest.csv");
}

private URL getCsvResource(String resourceName)
{
return getClass().getResource(resourceName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.params.provider.Arguments.arguments;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mockConstruction;
import static org.mockito.Mockito.when;
import static org.vividus.util.ResourceUtils.loadResourceOrFileAsByteArray;

import java.io.IOException;
import java.io.UncheckedIOException;
Expand Down Expand Up @@ -141,25 +141,23 @@ void shouldThrowErrorIfInvalidParametersAreProvided(String propertiesAsString, S

@SuppressWarnings("try")
@Test
void testCsvFileReaderExceptionCatching() throws IOException
void testCsvFileReaderExceptionCatching()
{
var csvFileName = "org/vividus/csv/transformer/test.csv";
var tableProperties = new TableProperties("path=" + csvFileName, keywords, converters);

byte[] csvResourceAsBytes = loadResourceOrFileAsByteArray(csvFileName);
var ioException = new IOException();
try (MockedConstruction<CsvReader> ignored = mockConstruction(CsvReader.class,
(mock, context) -> {
assertEquals(1, context.getCount());
assertEquals(List.of(CSVFormat.DEFAULT), context.arguments());
when(mock.readCsvBytes(csvResourceAsBytes)).thenThrow(ioException);
when(mock.readCsvStream(any())).thenThrow(ioException);
}))
{
var transformer = new CsvTableTransformer(CSVFormat.DEFAULT, variableContext);
var exception = assertThrows(UncheckedIOException.class,
() -> transformer.transform(EMPTY_EXAMPLES_TABLE, null, tableProperties));
assertEquals("Problem during CSV file reading", exception.getMessage());
assertEquals(ioException, exception.getCause());
assertException(exception, ioException);
}
}

Expand Down Expand Up @@ -207,8 +205,13 @@ void testCsvReaderReadCsvStringExceptionCatching()
var transformer = new CsvTableTransformer(CSVFormat.DEFAULT, variableContext);
var exception = assertThrows(UncheckedIOException.class,
() -> transformer.transform(EMPTY_EXAMPLES_TABLE, null, tableProperties));
assertEquals("Problem during CSV String reading", exception.getMessage());
assertEquals(ioException, exception.getCause());
assertException(exception, ioException);
}
}

private static void assertException(UncheckedIOException exception, IOException expectedCause)
{
assertEquals("Problem during CSV data reading", exception.getMessage());
assertEquals(expectedCause, exception.getCause());
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;

import org.apache.commons.lang3.function.FailableSupplier;
import org.jbehave.core.model.ExamplesTable.TableProperties;
import org.jbehave.core.model.TableParsers;
import org.jsoup.Connection;
Expand Down Expand Up @@ -67,7 +68,7 @@ public String transform(String table, TableParsers parsers, TableProperties tabl
PAGE_URL_PROPERTY_KEY, VARIABLE_NAME_PROPERTY_KEY, PATH_PROPERTY_KEY);
String sourceKey = entry.getKey();
String sourceValue = entry.getValue();
Supplier<Document> documentSuppler;
FailableSupplier<Document, IOException> documentSuppler;
if (VARIABLE_NAME_PROPERTY_KEY.equals(sourceKey))
{
documentSuppler = () -> Jsoup.parse((String) variableContext.getVariable(sourceValue));
Expand All @@ -80,7 +81,8 @@ else if (PAGE_URL_PROPERTY_KEY.equals(sourceKey))
}
else
{
documentSuppler = () -> Jsoup.parse(ResourceUtils.loadResourceOrFileAsString(sourceValue));
documentSuppler = () -> Jsoup.parse(ResourceUtils.loadResourceOrFileAsStream(sourceValue),
StandardCharsets.UTF_8.name(), "");
}

String column = tableProperties.getMandatoryNonBlankProperty("column", String.class);
Expand All @@ -105,28 +107,28 @@ else if (lastSegment.startsWith("@"))
getter = Element::outerHtml;
}

return documentSuppler.get().selectXpath(xpathSelector)
try
{
return documentSuppler.get().selectXpath(xpathSelector)
.stream()
.map(getter)
.collect(collectingAndThen(toList(), attrs -> ExamplesTableProcessor
.buildExamplesTableFromColumns(List.of(column), List.of(attrs),
tableProperties)));
}

private Document createDocument(String pageUrl)
{
try
{
Connection connection = Jsoup.connect(pageUrl);
httpConfiguration.ifPresent(cfg -> connection.headers(cfg.getHeaders()));
return connection.get();
}
catch (IOException e)
{
throw new UncheckedIOException(e);
}
}

private Document createDocument(String pageUrl) throws IOException
{
Connection connection = Jsoup.connect(pageUrl);
httpConfiguration.ifPresent(cfg -> connection.headers(cfg.getHeaders()));
return connection.get();
}

public static final class HttpConfiguration
{
private Map<String, String> headers;
Expand Down
Loading

0 comments on commit d2f7ae0

Please sign in to comment.