mirror of
https://github.com/frosch95/SmartCSV.fx.git
synced 2026-04-11 13:38:23 +02:00
Merge remote-tracking branch 'remotes/origin/feature/header_validation'
This commit is contained in:
@@ -16,6 +16,7 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
testCompile group: 'junit', name: 'junit', version: '4.12'
|
||||
testCompile group: 'org.hamcrest', name: 'hamcrest-library', version: '1.3'
|
||||
testCompile group: 'org.mockito', name: 'mockito-all', version: '1.10.19'
|
||||
compile group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.4.5'
|
||||
compile group: 'org.springframework', name:'spring-context', version: '4.2.3.RELEASE'
|
||||
|
||||
@@ -32,27 +32,26 @@ import javafx.concurrent.Task;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.event.EventHandler;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Label;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.scene.control.TableView;
|
||||
import javafx.scene.control.*;
|
||||
import javafx.scene.layout.AnchorPane;
|
||||
import javafx.scene.layout.BorderPane;
|
||||
import javafx.stage.FileChooser;
|
||||
import ninja.javafx.smartcsv.FileReader;
|
||||
import ninja.javafx.smartcsv.csv.CSVFileReader;
|
||||
import ninja.javafx.smartcsv.csv.CSVFileWriter;
|
||||
import ninja.javafx.smartcsv.fx.list.ValidationErrorListCell;
|
||||
import ninja.javafx.smartcsv.fx.table.ObservableMapValueFactory;
|
||||
import ninja.javafx.smartcsv.fx.table.ValidationCellFactory;
|
||||
import ninja.javafx.smartcsv.fx.table.model.CSVModel;
|
||||
import ninja.javafx.smartcsv.fx.table.model.CSVValue;
|
||||
import ninja.javafx.smartcsv.fx.table.model.CSVRow;
|
||||
import ninja.javafx.smartcsv.fx.table.model.CSVValue;
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
import ninja.javafx.smartcsv.validation.ValidationFileReader;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
@@ -83,15 +82,22 @@ public class SmartCSVController extends FXMLController {
|
||||
@FXML
|
||||
private Label stateline;
|
||||
|
||||
@FXML
|
||||
private ListView errorList;
|
||||
|
||||
@FXML
|
||||
private AnchorPane tableWrapper;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// injections
|
||||
// members
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private ValidationCellFactory cellFactory = new ValidationCellFactory();
|
||||
private ValidationCellFactory cellFactory;
|
||||
private final LoadCSVService loadCSVService = new LoadCSVService();
|
||||
private final SaveCSVService saveCSVService = new SaveCSVService();
|
||||
private CSVModel model;
|
||||
private TableView<CSVRow> tableView;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -99,8 +105,13 @@ public class SmartCSVController extends FXMLController {
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void initialize(URL location, ResourceBundle resources) {
|
||||
public void initialize(URL location, ResourceBundle resourceBundle) {
|
||||
cellFactory = new ValidationCellFactory(resourceBundle);
|
||||
stateline.setVisible(false);
|
||||
errorList.setCellFactory(param -> new ValidationErrorListCell(resourceBundle));
|
||||
errorList.getSelectionModel().selectedItemProperty().addListener(
|
||||
observable -> scrollToError()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -215,7 +226,7 @@ public class SmartCSVController extends FXMLController {
|
||||
model = csvLoader.getData();
|
||||
model.setValidator(validationLoader.getValidator());
|
||||
|
||||
TableView<CSVRow> tableView = new TableView<>();
|
||||
tableView = new TableView<>();
|
||||
|
||||
for (String column: model.getHeader()) {
|
||||
addColumn(column, tableView);
|
||||
@@ -223,7 +234,14 @@ public class SmartCSVController extends FXMLController {
|
||||
tableView.getItems().setAll(model.getRows());
|
||||
tableView.setEditable(true);
|
||||
|
||||
applicationPane.setCenter(tableView);
|
||||
AnchorPane.setBottomAnchor(tableView, 0.0);
|
||||
AnchorPane.setTopAnchor(tableView, 0.0);
|
||||
AnchorPane.setLeftAnchor(tableView, 0.0);
|
||||
AnchorPane.setRightAnchor(tableView, 0.0);
|
||||
tableWrapper.getChildren().setAll(tableView);
|
||||
|
||||
|
||||
errorList.setItems(model.getValidationError());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -248,6 +266,17 @@ public class SmartCSVController extends FXMLController {
|
||||
tableView.getColumns().add(column);
|
||||
}
|
||||
|
||||
private void scrollToError() {
|
||||
ValidationError entry = (ValidationError)errorList.getSelectionModel().getSelectedItem();
|
||||
if (entry != null) {
|
||||
if (entry.getLineNumber() != null) {
|
||||
tableView.scrollTo(entry.getLineNumber());
|
||||
tableView.getSelectionModel().select(entry.getLineNumber());
|
||||
} else {
|
||||
tableView.scrollTo(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// inner class
|
||||
@@ -277,7 +306,7 @@ public class SmartCSVController extends FXMLController {
|
||||
try {
|
||||
fileReader.read(file);
|
||||
runLater(SmartCSVController.this::resetContent);
|
||||
} catch (IOException ex) {
|
||||
} catch (Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
@@ -300,7 +329,7 @@ public class SmartCSVController extends FXMLController {
|
||||
try {
|
||||
csvFileWriter.saveFile(model);
|
||||
runLater(SmartCSVController.this::resetContent);
|
||||
} catch (IOException ex) {
|
||||
} catch (Throwable ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
package ninja.javafx.smartcsv.fx.list;
|
||||
|
||||
import javafx.scene.control.ListCell;
|
||||
import javafx.scene.text.Text;
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import static ninja.javafx.smartcsv.fx.util.I18nValidationUtil.getI18nValidatioMessage;
|
||||
|
||||
/**
|
||||
* TODO: DESCRIPTION!!!
|
||||
*/
|
||||
public class ValidationErrorListCell extends ListCell<ValidationError> {
|
||||
|
||||
private ResourceBundle resourceBundle;
|
||||
|
||||
public ValidationErrorListCell(ResourceBundle resourceBundle) {
|
||||
this.resourceBundle = resourceBundle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateItem(ValidationError validationError, boolean empty) {
|
||||
super.updateItem(validationError, empty);
|
||||
if (empty) {
|
||||
clearContent();
|
||||
} else {
|
||||
addContent(validationError);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void clearContent() {
|
||||
setText(null);
|
||||
setGraphic(null);
|
||||
}
|
||||
|
||||
private void addContent(ValidationError validationError) {
|
||||
setText(null);
|
||||
Text text = new Text(getI18nValidatioMessage(resourceBundle, validationError));
|
||||
text.setWrappingWidth(180);
|
||||
setGraphic(text);
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,10 @@ import javafx.scene.input.KeyCode;
|
||||
import ninja.javafx.smartcsv.fx.table.model.CSVRow;
|
||||
import ninja.javafx.smartcsv.fx.table.model.CSVValue;
|
||||
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import static javafx.application.Platform.runLater;
|
||||
import static ninja.javafx.smartcsv.fx.util.I18nValidationUtil.getI18nValidatioMessage;
|
||||
|
||||
/**
|
||||
* Created by Andreas on 27.11.2015.
|
||||
@@ -42,6 +45,11 @@ import static javafx.application.Platform.runLater;
|
||||
public class EditableValidationCell extends TableCell<CSVRow, CSVValue> {
|
||||
|
||||
private ValueTextField textField;
|
||||
private ResourceBundle resourceBundle;
|
||||
|
||||
public EditableValidationCell(ResourceBundle resourceBundle) {
|
||||
this.resourceBundle = resourceBundle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startEdit() {
|
||||
@@ -64,12 +72,12 @@ public class EditableValidationCell extends TableCell<CSVRow, CSVValue> {
|
||||
protected void updateItem(CSVValue item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
|
||||
if (item == null || item.getValid().isValid() || isEditing()) {
|
||||
if (item == null || item.getValidationError() == null || isEditing()) {
|
||||
setStyle("");
|
||||
setTooltip(null);
|
||||
} else if (!item.getValid().isValid()) {
|
||||
} else if (item.getValidationError() != null) {
|
||||
setStyle("-fx-background-color: #ff8888");
|
||||
setTooltip(new Tooltip(item.getValid().error()));
|
||||
setTooltip(new Tooltip(getI18nValidatioMessage(resourceBundle, item.getValidationError())));
|
||||
}
|
||||
|
||||
if (item == null || empty) {
|
||||
|
||||
@@ -29,17 +29,24 @@ package ninja.javafx.smartcsv.fx.table;
|
||||
import javafx.scene.control.TableCell;
|
||||
import javafx.scene.control.TableColumn;
|
||||
import javafx.util.Callback;
|
||||
import ninja.javafx.smartcsv.fx.table.model.CSVModel;
|
||||
import ninja.javafx.smartcsv.fx.table.model.CSVRow;
|
||||
import ninja.javafx.smartcsv.fx.table.model.CSVValue;
|
||||
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
/**
|
||||
* Created by Andreas on 18.11.2015.
|
||||
*/
|
||||
public class ValidationCellFactory implements Callback<TableColumn<CSVRow, CSVValue>, TableCell<CSVRow, CSVValue>> {
|
||||
|
||||
private ResourceBundle resourceBundle;
|
||||
|
||||
public ValidationCellFactory(ResourceBundle resourceBundle) {
|
||||
this.resourceBundle = resourceBundle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableCell<CSVRow, CSVValue> call(TableColumn<CSVRow, CSVValue> param) {
|
||||
return new EditableValidationCell();
|
||||
return new EditableValidationCell(resourceBundle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ package ninja.javafx.smartcsv.fx.table.model;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import ninja.javafx.smartcsv.validation.ValidationState;
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
import ninja.javafx.smartcsv.validation.Validator;
|
||||
|
||||
/**
|
||||
@@ -41,6 +41,7 @@ public class CSVModel {
|
||||
private ObservableList<CSVRow> rows = FXCollections.observableArrayList();
|
||||
private String[] header;
|
||||
private String filepath;
|
||||
private ObservableList<ValidationError> validationError = FXCollections.observableArrayList();
|
||||
|
||||
public CSVModel(String filepath) {
|
||||
this.filepath = filepath;
|
||||
@@ -71,6 +72,10 @@ public class CSVModel {
|
||||
return rows;
|
||||
}
|
||||
|
||||
public ObservableList<ValidationError> getValidationError() {
|
||||
return validationError;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds a new and empty row
|
||||
* @return the new row
|
||||
@@ -89,6 +94,7 @@ public class CSVModel {
|
||||
*/
|
||||
public void setHeader(String[] header) {
|
||||
this.header = header;
|
||||
revalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,18 +110,37 @@ public class CSVModel {
|
||||
* walks through the data and validates each value
|
||||
*/
|
||||
private void revalidate() {
|
||||
for (CSVRow row: rows) {
|
||||
validationError.clear();
|
||||
|
||||
if (header != null && validator != null) {
|
||||
addValidationError(validator.isHeaderValid(header));
|
||||
}
|
||||
|
||||
for (int lineNumber = 0; lineNumber < rows.size(); lineNumber++) {
|
||||
CSVRow row = rows.get(lineNumber);
|
||||
row.setValidator(validator);
|
||||
for (String column: row.getColumns().keySet()) {
|
||||
CSVValue value = row.getColumns().get(column).getValue();
|
||||
value.setValidator(validator);
|
||||
if (validator != null) {
|
||||
value.setValid(validator.isValid(column, value.getValue()));
|
||||
ValidationError validationError = validator.isValid(column, value.getValue(), lineNumber);
|
||||
if (validationError != null) {
|
||||
addValidationError(validationError);
|
||||
value.setValidationError(validationError);
|
||||
} else {
|
||||
value.setValid(new ValidationState());
|
||||
value.setValidationError(null);
|
||||
}
|
||||
} else {
|
||||
value.setValidationError(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addValidationError(ValidationError validationError) {
|
||||
if (validationError != null) {
|
||||
this.validationError.add(validationError);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ package ninja.javafx.smartcsv.fx.table.model;
|
||||
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import ninja.javafx.smartcsv.validation.ValidationState;
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
import ninja.javafx.smartcsv.validation.Validator;
|
||||
|
||||
/**
|
||||
@@ -41,7 +41,7 @@ public class CSVValue {
|
||||
private int rowNumber;
|
||||
private String column;
|
||||
private StringProperty value = new SimpleStringProperty();
|
||||
private ValidationState valid = new ValidationState();
|
||||
private ValidationError valid;
|
||||
|
||||
/**
|
||||
* single value of a cell
|
||||
@@ -89,7 +89,7 @@ public class CSVValue {
|
||||
*/
|
||||
public void setValue(String value) {
|
||||
if (validator != null) {
|
||||
valid = validator.isValid(column, value);
|
||||
valid = validator.isValid(column, value, rowNumber);
|
||||
}
|
||||
this.value.set(value);
|
||||
}
|
||||
@@ -98,7 +98,7 @@ public class CSVValue {
|
||||
* returns if the value is valid to the rules of the validator
|
||||
* @return
|
||||
*/
|
||||
public ValidationState getValid() {
|
||||
public ValidationError getValidationError() {
|
||||
return valid;
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ public class CSVValue {
|
||||
* sets the state if a value is valid or not
|
||||
* @param valid the validation state
|
||||
*/
|
||||
protected void setValid(ValidationState valid) {
|
||||
protected void setValidationError(ValidationError valid) {
|
||||
this.valid = valid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
package ninja.javafx.smartcsv.fx.util;
|
||||
|
||||
import ninja.javafx.smartcsv.validation.ValidationError;
|
||||
import ninja.javafx.smartcsv.validation.ValidationMessage;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.util.List;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
import static java.text.MessageFormat.format;
|
||||
|
||||
/**
|
||||
* This class makes validation messages readable in supported languages
|
||||
*/
|
||||
public class I18nValidationUtil {
|
||||
|
||||
public static String getI18nValidatioMessage(ResourceBundle resourceBundle, ValidationError error) {
|
||||
|
||||
List<ValidationMessage> validationMessages = error.getMessages();
|
||||
StringWriter message = new StringWriter();
|
||||
for (ValidationMessage validationMessage: validationMessages) {
|
||||
if (resourceBundle.containsKey(validationMessage.getKey())) {
|
||||
String resourceText = resourceBundle.getString(validationMessage.getKey());
|
||||
if (validationMessage.getParameters().length > 0) {
|
||||
message.append(format(resourceText, validationMessage.getParameters())).append("\n");
|
||||
} else {
|
||||
message.append(resourceText).append("\n");
|
||||
}
|
||||
} else {
|
||||
message.append(validationMessage.getKey()).append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return message.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,26 +26,45 @@
|
||||
|
||||
package ninja.javafx.smartcsv.validation;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Andreas on 28.11.2015.
|
||||
* This class holds all the error messages
|
||||
* for a single cell and the information in
|
||||
* which row the cell is
|
||||
*/
|
||||
public class ValidationState {
|
||||
private boolean valid = true;
|
||||
private StringWriter messages = new StringWriter();
|
||||
public class ValidationError {
|
||||
|
||||
public void invalidate(String message) {
|
||||
valid = false;
|
||||
messages.append(message).append('\n');
|
||||
private List<ValidationMessage> messages = new ArrayList<>();
|
||||
private Integer lineNumber;
|
||||
|
||||
private ValidationError(Integer lineNumber) {
|
||||
this.lineNumber = lineNumber;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return valid;
|
||||
public static ValidationError withLineNumber(int lineNumber) {
|
||||
return new ValidationError(lineNumber);
|
||||
}
|
||||
|
||||
public String error() {
|
||||
return messages.toString();
|
||||
public static ValidationError withoutLineNumber() {
|
||||
return new ValidationError(-1);
|
||||
}
|
||||
|
||||
public Integer getLineNumber() {
|
||||
return lineNumber;
|
||||
}
|
||||
|
||||
public List<ValidationMessage> getMessages() {
|
||||
return messages;
|
||||
}
|
||||
|
||||
public ValidationError add(String key, String... parameters) {
|
||||
messages.add(new ValidationMessage(key, parameters));
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return messages.isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
package ninja.javafx.smartcsv.validation;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* TODO: DESCRIPTION!!!
|
||||
*/
|
||||
public class ValidationMessage {
|
||||
|
||||
private String key;
|
||||
private String[] parameters;
|
||||
|
||||
public ValidationMessage(String key, String... parameters) {
|
||||
this.key = key;
|
||||
this.parameters = parameters;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public String[] getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
ValidationMessage that = (ValidationMessage) o;
|
||||
|
||||
if (key != null ? !key.equals(that.key) : that.key != null) return false;
|
||||
// Probably incorrect - comparing Object[] arrays with Arrays.equals
|
||||
return Arrays.equals(parameters, that.parameters);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = key != null ? key.hashCode() : 0;
|
||||
result = 31 * result + Arrays.hashCode(parameters);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ValidationMessage{" +
|
||||
"key='" + key + '\'' +
|
||||
", parameters=" + Arrays.toString(parameters) +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -33,6 +33,7 @@ import groovy.lang.Script;
|
||||
import org.codehaus.groovy.control.CompilationFailedException;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.apache.commons.validator.GenericValidator.*;
|
||||
@@ -73,22 +74,31 @@ public class Validator {
|
||||
* checks if the value is valid for the column configuration
|
||||
* @param column the column name
|
||||
* @param value the value to check
|
||||
* @return ValidationState with information if valid and if not which error happened
|
||||
* @return ValidationError with information if valid and if not which getMessage happened
|
||||
*/
|
||||
public ValidationState isValid(String column, String value) {
|
||||
ValidationState result = new ValidationState();
|
||||
public ValidationError isValid(String column, String value, Integer lineNumber) {
|
||||
ValidationError result = null;
|
||||
if (validationConfig != null) {
|
||||
Config columnConfig = getColumnConfig(column);
|
||||
Config columnSectionConfig = getColumnSectionConfig();
|
||||
if (columnSectionConfig != null) {
|
||||
Config columnConfig = getColumnConfig(columnSectionConfig, column);
|
||||
if (columnConfig != null) {
|
||||
checkBlankOrNull(columnConfig, value, result);
|
||||
|
||||
ValidationError error = ValidationError.withLineNumber(lineNumber);
|
||||
checkBlankOrNull(columnConfig, value, error);
|
||||
if (value != null) {
|
||||
checkRegularExpression(columnConfig, value, result);
|
||||
checkAlphaNumeric(columnConfig, value, result);
|
||||
checkDate(columnConfig, value, result);
|
||||
checkMaxLength(columnConfig, value, result);
|
||||
checkMinLength(columnConfig, value, result);
|
||||
checkInteger(columnConfig, value, result);
|
||||
checkGroovy(column, columnConfig, value, result);
|
||||
checkRegularExpression(columnConfig, value, error);
|
||||
checkAlphaNumeric(columnConfig, value, error);
|
||||
checkDate(columnConfig, value, error);
|
||||
checkMaxLength(columnConfig, value, error);
|
||||
checkMinLength(columnConfig, value, error);
|
||||
checkInteger(columnConfig, value, error);
|
||||
checkGroovy(column, columnConfig, value, error);
|
||||
}
|
||||
|
||||
if (!error.isEmpty()) {
|
||||
result = error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,7 +110,7 @@ public class Validator {
|
||||
// private methods
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void checkGroovy(String column, Config columnConfig, String value, ValidationState result) {
|
||||
private void checkGroovy(String column, Config columnConfig, String value, ValidationError error) {
|
||||
String groovyScript = getString(columnConfig, "groovy");
|
||||
if (groovyScript != null) {
|
||||
|
||||
@@ -118,15 +128,15 @@ public class Validator {
|
||||
try {
|
||||
groovyResult = script.run();
|
||||
} catch (CompilationFailedException e) {
|
||||
result.invalidate("groovy script '"+groovyScript+"' throws exception: "+e.getMessage());
|
||||
error.add("validation.message.groovy.exception", groovyScript, e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (groovyResult == null) {
|
||||
result.invalidate("groovy script '"+groovyScript+"' returns null");
|
||||
error.add("validation.message.groovy.return.null", groovyScript);
|
||||
}
|
||||
|
||||
if (!isScriptResultTrue(groovyResult)) {
|
||||
result.invalidate(groovyResult.toString());
|
||||
error.add(groovyResult.toString());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -136,70 +146,75 @@ public class Validator {
|
||||
return groovyResult.equals(true) || groovyResult.toString().trim().toLowerCase().equals("true");
|
||||
}
|
||||
|
||||
private void checkBlankOrNull(Config columnConfig, String value, ValidationState result) {
|
||||
private void checkBlankOrNull(Config columnConfig, String value, ValidationError error) {
|
||||
if (getBoolean(columnConfig, "not empty")) {
|
||||
if (isBlankOrNull(value)) {
|
||||
result.invalidate("should not be empty");
|
||||
error.add("validation.message.not.empty");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkInteger(Config columnConfig, String value, ValidationState result) {
|
||||
private void checkInteger(Config columnConfig, String value, ValidationError error) {
|
||||
if (getBoolean(columnConfig, "integer")) {
|
||||
if (!isInt(value)) {
|
||||
result.invalidate("should be an integer");
|
||||
error.add("validation.message.integer");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkMinLength(Config columnConfig, String value, ValidationState result) {
|
||||
private void checkMinLength(Config columnConfig, String value, ValidationError error) {
|
||||
Integer minLength = getInteger(columnConfig, "minlength");
|
||||
if (minLength != null) {
|
||||
if (!minLength(value, minLength)) {
|
||||
result.invalidate("has not min length of " + minLength);
|
||||
error.add("validation.message.min.length", minLength.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkMaxLength(Config columnConfig, String value, ValidationState result) {
|
||||
private void checkMaxLength(Config columnConfig, String value, ValidationError error) {
|
||||
Integer maxLength = getInteger(columnConfig, "maxlength");
|
||||
if (maxLength != null) {
|
||||
if (!maxLength(value, maxLength)) {
|
||||
result.invalidate("has not max length of " + maxLength);
|
||||
error.add("validation.message.max.length", maxLength.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkDate(Config columnConfig, String value, ValidationState result) {
|
||||
private void checkDate(Config columnConfig, String value, ValidationError error) {
|
||||
String dateformat = getString(columnConfig, "date");
|
||||
if (dateformat != null && !dateformat.trim().isEmpty()) {
|
||||
if (!isDate(value, dateformat, true)) {
|
||||
result.invalidate("is not a date of format " + dateformat);
|
||||
error.add("validation.message.date.format", dateformat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkAlphaNumeric(Config columnConfig, String value, ValidationState result) {
|
||||
private void checkAlphaNumeric(Config columnConfig, String value, ValidationError error) {
|
||||
if (getBoolean(columnConfig, "alphanumeric")) {
|
||||
if (!matchRegexp(value, "[0-9a-zA-Z]*")) {
|
||||
result.invalidate("should not be alphanumeric");
|
||||
error.add("validation.message.alphanumeric");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkRegularExpression(Config columnConfig, String value, ValidationState result) {
|
||||
private void checkRegularExpression(Config columnConfig, String value, ValidationError error) {
|
||||
String regexp = getString(columnConfig, "regexp");
|
||||
if (regexp != null && !regexp.trim().isEmpty()) {
|
||||
if (!matchRegexp(value, regexp)) {
|
||||
result.invalidate("does not match " + regexp);
|
||||
error.add("validation.message.regexp", regexp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Config getColumnConfig(String column) {
|
||||
return validationConfig.hasPath(column) ? validationConfig.getConfig(column) : null;
|
||||
private Config getColumnSectionConfig() {
|
||||
return validationConfig.hasPath("columns") ? validationConfig.getConfig("columns") : null;
|
||||
}
|
||||
|
||||
private Config getColumnConfig(Config columnSectionConfig, String column) {
|
||||
return columnSectionConfig.hasPath(column) ? columnSectionConfig.getConfig(column) : null;
|
||||
}
|
||||
|
||||
|
||||
private String getString(Config columnConfig, String path) {
|
||||
return columnConfig.hasPath(path) ? columnConfig.getString(path) : null;
|
||||
}
|
||||
@@ -213,4 +228,39 @@ public class Validator {
|
||||
return columnConfig.hasPath(path) && columnConfig.getBoolean(path);
|
||||
}
|
||||
|
||||
public ValidationError isHeaderValid(String[] headerNames) {
|
||||
ValidationError result = null;
|
||||
if (validationConfig != null) {
|
||||
if (validationConfig.hasPath("headers")) {
|
||||
Config headerSectionConfig = validationConfig.getConfig("headers");
|
||||
if (headerSectionConfig.hasPath("list")) {
|
||||
List<String> headerConfig = headerSectionConfig.getStringList("list");
|
||||
if (headerConfig != null) {
|
||||
if (headerNames.length != headerConfig.size()) {
|
||||
result = ValidationError.withoutLineNumber().add("validation.message.header.length",
|
||||
Integer.toString(headerNames.length),
|
||||
Integer.toString(headerConfig.size()));
|
||||
return result;
|
||||
}
|
||||
|
||||
ValidationError error = ValidationError.withoutLineNumber();
|
||||
|
||||
for(int i=0; i<headerConfig.size(); i++) {
|
||||
String header = headerConfig.get(i);
|
||||
if (!header.equals(headerNames[i])) {
|
||||
error.add("validation.message.header.match",
|
||||
Integer.toString(i),
|
||||
header,
|
||||
headerNames[i]);
|
||||
}
|
||||
}
|
||||
if (!error.isEmpty()) {
|
||||
result = error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,25 +12,20 @@
|
||||
<children>
|
||||
<MenuBar>
|
||||
<menus>
|
||||
<Menu mnemonicParsing="false" text="File">
|
||||
<Menu mnemonicParsing="false" text="%menu.file">
|
||||
<items>
|
||||
<MenuItem mnemonicParsing="false" onAction="#openCsv" text="Open CSV" />
|
||||
<MenuItem mnemonicParsing="false" onAction="#openConfig" text="Open Validation Config" />
|
||||
<MenuItem mnemonicParsing="false" onAction="#openCsv" text="%menu.open.csv" />
|
||||
<MenuItem mnemonicParsing="false" onAction="#openConfig" text="%menu.open.config" />
|
||||
<SeparatorMenuItem mnemonicParsing="false" />
|
||||
<MenuItem mnemonicParsing="false" onAction="#saveCsv" text="Save" />
|
||||
<MenuItem mnemonicParsing="false" onAction="#saveAsCsv" text="Save As" />
|
||||
<MenuItem mnemonicParsing="false" onAction="#saveCsv" text="%menu.save" />
|
||||
<MenuItem mnemonicParsing="false" onAction="#saveAsCsv" text="%menu.save.as" />
|
||||
<SeparatorMenuItem mnemonicParsing="false" />
|
||||
<MenuItem mnemonicParsing="false" onAction="#close" text="Close" />
|
||||
<MenuItem mnemonicParsing="false" onAction="#close" text="%menu.close" />
|
||||
</items>
|
||||
</Menu>
|
||||
<Menu mnemonicParsing="false" text="Edit">
|
||||
<Menu mnemonicParsing="false" text="%menu.help">
|
||||
<items>
|
||||
<MenuItem mnemonicParsing="false" text="Delete" />
|
||||
</items>
|
||||
</Menu>
|
||||
<Menu mnemonicParsing="false" text="Help">
|
||||
<items>
|
||||
<MenuItem mnemonicParsing="false" onAction="#about" text="About" />
|
||||
<MenuItem mnemonicParsing="false" onAction="#about" text="%menu.about" />
|
||||
</items>
|
||||
</Menu>
|
||||
</menus>
|
||||
@@ -39,10 +34,26 @@
|
||||
</VBox>
|
||||
</top>
|
||||
<center>
|
||||
<TableView fx:id="tableView" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
|
||||
<SplitPane dividerPositions="0.8" prefHeight="160.0" prefWidth="200.0" BorderPane.alignment="CENTER">
|
||||
<items>
|
||||
<AnchorPane fx:id="tableWrapper">
|
||||
<TableView fx:id="tableView" prefHeight="200.0" prefWidth="200.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" BorderPane.alignment="CENTER">
|
||||
<columns>
|
||||
</columns>
|
||||
</TableView>
|
||||
</AnchorPane>
|
||||
<VBox>
|
||||
<children>
|
||||
<Label text="%title.validation.errors">
|
||||
<padding>
|
||||
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0" />
|
||||
</padding>
|
||||
</Label>
|
||||
<ListView fx:id="errorList" minWidth="10.0" prefWidth="200.0" VBox.vgrow="ALWAYS" />
|
||||
</children>
|
||||
</VBox>
|
||||
</items>
|
||||
</SplitPane>
|
||||
</center>
|
||||
<bottom>
|
||||
<HBox spacing="8.0" BorderPane.alignment="CENTER">
|
||||
@@ -54,4 +65,6 @@
|
||||
</BorderPane.margin>
|
||||
</HBox>
|
||||
</bottom>
|
||||
<left>
|
||||
</left>
|
||||
</BorderPane>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
menu.open.csv = Open CSV File
|
||||
menu.open.config = Open Validation Config
|
||||
menu.save = Save
|
||||
menu.save.as = Save As ...
|
||||
menu.close = Close
|
||||
menu.about = About
|
||||
menu.file = File
|
||||
menu.edit = Edit
|
||||
menu.help = Help
|
||||
title.validation.errors = Validation Errors:
|
||||
|
||||
# validaton messages
|
||||
validation.message.not.empty = should not be empty
|
||||
validation.message.integer = should be an integer
|
||||
validation.message.alphanumeric = should be alphanumeric
|
||||
validation.message.groovy.exception = groovy script '{0}' throws exception: {1}
|
||||
validation.message.groovy.return.null = groovy script '{0}' returns null
|
||||
validation.message.min.length = has not min length of {0}
|
||||
validation.message.max.length = has not max length of {0}
|
||||
validation.message.date.format = is not a date of format {0}
|
||||
validation.message.regexp = does not match {0}
|
||||
|
||||
validation.message.header.length = number of headers is not correct! there are {0} but there should be {1}
|
||||
validation.message.header.match = header number {0} does not match "{1}" should be "{3}"
|
||||
@@ -1,52 +1,32 @@
|
||||
menu.title.import.gpx = Importiere GPX
|
||||
menu.title.file = Datei
|
||||
menu.title.quit = Beenden
|
||||
menu.title.help = Hilfe
|
||||
menu.title.settings = Einstellungen
|
||||
menu.title.about = \u00dcber GeoFroggerFX
|
||||
menu.title.plugins = Plugins
|
||||
menu.title.list = Listen
|
||||
menu.title.list.new = Liste anlegen
|
||||
menu.title.list.delete = Liste l\u00F6schen
|
||||
# ae = u00e4
|
||||
# Ae = u00c4
|
||||
# oe = u00f6
|
||||
# Oe =u00d6
|
||||
# ue = u00fc
|
||||
# Ue = u00dc
|
||||
# ss = u00df
|
||||
|
||||
menu.title.sort = Sortieren
|
||||
menu.title.filter = Filtern
|
||||
menu.open.csv = CSV Datei \u00f6ffnen
|
||||
menu.open.config = Pr\u00fcfkonfiguration \u00f6ffnen
|
||||
menu.save = Speichern
|
||||
menu.save.as = Speichern als ...
|
||||
menu.close = Beenden
|
||||
menu.about = \u00dcber ...
|
||||
menu.file = Datei
|
||||
menu.edit = Bearbeiten
|
||||
menu.help = Hilfe
|
||||
title.validation.errors = Fehler in der Datei:
|
||||
|
||||
label.text.cache.list=Liste:
|
||||
label.text.cache.list.count=Anzahl:
|
||||
label.text.name=Name:
|
||||
label.text.difficulty=Schwierigkeit:
|
||||
label.text.terrain=Gel\u00E4nde
|
||||
label.text.placedBy=Platziert von:
|
||||
label.text.owner=Betreut von:
|
||||
label.text.date=Datum:
|
||||
label.text.type=Typ:
|
||||
label.text.container=Gr\u00F6\u00dfe:
|
||||
label.text.shortdescription=Kurze Beschreibung:
|
||||
label.text.htmldescription=HTML Beschreibung
|
||||
label.text.longdescription=Lange Beschreibung:
|
||||
# validaton messages
|
||||
validation.message.not.empty = Darf nicht leer sein.
|
||||
validation.message.integer = Muss eine Zahl sein.
|
||||
validation.message.alphanumeric = Darf nur Zahlen und Buchstaben enthalten.
|
||||
validation.message.groovy.exception = groovy script '{0}' wirft folgenden Fehler: {1}
|
||||
validation.message.groovy.return.null = groovy script '{0}' meldet "null"
|
||||
validation.message.min.length = Hat nicht die minimale L\u00e4nge von {0}
|
||||
validation.message.max.length = Hat nicht die maximale L\u00e4nge von {0}
|
||||
validation.message.date.format = Das Datumsformat entspricht nicht {0}
|
||||
validation.message.regexp = entspricht nicht dem regul\u00e4ren Ausdruck {0}
|
||||
|
||||
tab.text.descriptions=Beschreibungen
|
||||
tab.text.general=Allgemein
|
||||
|
||||
sort.cache.name = GC Code
|
||||
sort.cache.type = Art
|
||||
sort.cache.difficulty = Schwierigkeitsgrad
|
||||
sort.cache.terrain = Gel\u00E4nde
|
||||
sort.cache.placedBy = Platziert von
|
||||
sort.cache.owner = Betreut von
|
||||
|
||||
dialog.title.about = Über
|
||||
dialog.title.new_list = Neue Liste
|
||||
dialog.label.listname = Name der Liste:
|
||||
dialog.msg.list.does.exist = Diese Liste existiert schon!
|
||||
dialog.title.delete_list = Liste löschen
|
||||
|
||||
all.caches = Alle Caches
|
||||
|
||||
status.load.all.caches.from.db = Lade alle Caches von der Datenbank.
|
||||
status.all.cache.lists.loaded = Alle Listen geladen.
|
||||
status.load.caches.from.db = Lade Caches von der Datenbank.
|
||||
status.all.caches.loaded = Alle Caches geladen.
|
||||
status.store.all.caches = Speichere Caches in Datenbank.
|
||||
status.all.caches.stored = Alle Caches in der Datenbank gespeichert.
|
||||
validation.message.header.length = Anzahl der \u00dcberschriften ist nicht korrekt! Es sind {0} aber es sollten {1} sein
|
||||
validation.message.header.match = \u00dcberschrift in Spalte {0} stimmt nicht. "{1}" sollte "{3}" sein
|
||||
@@ -1,53 +0,0 @@
|
||||
menu.title.import.gpx = Import GPX
|
||||
menu.title.file = File
|
||||
menu.title.quit = Quit
|
||||
menu.title.help = Help
|
||||
menu.title.settings = Settings
|
||||
menu.title.about = About GeoFroggerFX
|
||||
menu.title.plugins = Plugins
|
||||
menu.title.list = Lists
|
||||
menu.title.list.new = New list
|
||||
menu.title.list.delete = Delete list
|
||||
|
||||
|
||||
menu.title.sort = Sort
|
||||
menu.title.filter = Filter
|
||||
|
||||
label.text.cache.list=List:
|
||||
label.text.cache.list.count=Number:
|
||||
label.text.name=Name:
|
||||
label.text.difficulty=Difficulty:
|
||||
label.text.terrain=Terrain:
|
||||
label.text.placedBy=Placed By:
|
||||
label.text.owner=Owner:
|
||||
label.text.date=Date:
|
||||
label.text.type=Type:
|
||||
label.text.container=Container:
|
||||
label.text.shortdescription=Short description:
|
||||
label.text.htmldescription=HTML Description
|
||||
label.text.longdescription=Long description:
|
||||
|
||||
tab.text.descriptions=Descriptions
|
||||
tab.text.general=General
|
||||
|
||||
sort.cache.name = GC Code
|
||||
sort.cache.type = Type
|
||||
sort.cache.difficulty = Difficulty
|
||||
sort.cache.terrain = Terrain
|
||||
sort.cache.placedBy = Placed by
|
||||
sort.cache.owner = Owner
|
||||
|
||||
dialog.title.about = About
|
||||
dialog.title.new_list = New list
|
||||
dialog.label.listname = Name of list:
|
||||
dialog.msg.list.does.exist = List does already exist!
|
||||
dialog.title.delete_list = Delete list
|
||||
|
||||
all.caches = All caches
|
||||
|
||||
status.load.all.caches.from.db = Load cache lists from database.
|
||||
status.all.cache.lists.loaded = All cache lists loaded.
|
||||
status.load.caches.from.db = Load caches from database.
|
||||
status.all.caches.loaded = All caches loaded.
|
||||
status.store.all.caches = Store caches in database.
|
||||
status.all.caches.stored = All caches are stored in database.
|
||||
@@ -88,7 +88,7 @@ public class CSVModelTest {
|
||||
sut.setValidator(validator);
|
||||
|
||||
// assertion
|
||||
verify(validator).isValid(TESTHEADER, TESTVALUE);
|
||||
verify(validator).isValid(TESTHEADER, TESTVALUE, 0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -4,6 +4,8 @@ import ninja.javafx.smartcsv.validation.Validator;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
@@ -53,6 +55,6 @@ public class CSVValueTest {
|
||||
sut.setValue(VALUE);
|
||||
|
||||
// assertion
|
||||
verify(validator).isValid(COLUMN, VALUE);
|
||||
verify(validator).isValid(eq(COLUMN), eq(VALUE), anyInt());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package ninja.javafx.smartcsv.validation;
|
||||
|
||||
import com.typesafe.config.Config;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
public class ConfigMock {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// constants
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
private static final String HEADER_SECTION_KEY = "headers";
|
||||
private static final String COLUMN_SECTION_KEY = "columns";
|
||||
private static final String LIST_KEY = "list";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// mocks
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
public static Config headerSectionConfig(String[] headerNames) {
|
||||
|
||||
Config headerSectionConfig = mock(Config.class);
|
||||
Config listConfig = mock(Config.class);
|
||||
|
||||
when(headerSectionConfig.hasPath(HEADER_SECTION_KEY)).thenReturn(true);
|
||||
when(headerSectionConfig.getConfig(HEADER_SECTION_KEY)).thenReturn(listConfig);
|
||||
|
||||
when(listConfig.hasPath(LIST_KEY)).thenReturn(true);
|
||||
when(listConfig.getStringList(LIST_KEY)).thenReturn(asList(headerNames));
|
||||
|
||||
return headerSectionConfig;
|
||||
}
|
||||
|
||||
|
||||
public static Config columnSectionConfig(String column, String validation, Object value) {
|
||||
|
||||
Config columnSectionConfig = mock(Config.class);
|
||||
Config columnConfig = mock(Config.class);
|
||||
Config validatorConfig = mock(Config.class);
|
||||
|
||||
when(columnSectionConfig.hasPath(COLUMN_SECTION_KEY)).thenReturn(true);
|
||||
when(columnSectionConfig.getConfig(COLUMN_SECTION_KEY)).thenReturn(columnConfig);
|
||||
|
||||
when(columnConfig.hasPath(column)).thenReturn(true);
|
||||
when(columnConfig.getConfig(column)).thenReturn(validatorConfig);
|
||||
|
||||
when(validatorConfig.hasPath(validation)).thenReturn(true);
|
||||
if (value instanceof Boolean) {
|
||||
when(validatorConfig.getBoolean(validation)).thenReturn((Boolean) value);
|
||||
} else if (value instanceof String) {
|
||||
when(validatorConfig.getString(validation)).thenReturn((String) value);
|
||||
} else if (value instanceof Integer) {
|
||||
when(validatorConfig.getInt(validation)).thenReturn((Integer) value);
|
||||
}
|
||||
|
||||
return columnSectionConfig;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2015 javafx.ninja <info@javafx.ninja>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
package ninja.javafx.smartcsv.validation;
|
||||
|
||||
import com.typesafe.config.Config;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static ninja.javafx.smartcsv.validation.ConfigMock.headerSectionConfig;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* unit test for header validator
|
||||
*/
|
||||
@RunWith(Parameterized.class)
|
||||
public class HeaderValidationTest {
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// parameters
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
private Config config;
|
||||
private Boolean expectedResult;
|
||||
private List<ValidationMessage> expectedErrors;
|
||||
private String[] headerNames;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// subject under test
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
private Validator sut;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// parameterized constructor
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
public HeaderValidationTest(String[] configHeaderNames,
|
||||
String[] headerNames,
|
||||
Boolean expectedResult,
|
||||
List<ValidationMessage> expectedErrors) {
|
||||
this.config = headerSectionConfig(configHeaderNames);
|
||||
this.headerNames = headerNames;
|
||||
this.expectedResult = expectedResult;
|
||||
this.expectedErrors = expectedErrors;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// init
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@Before
|
||||
public void initialize() {
|
||||
sut = new Validator(config);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// tests
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@Test
|
||||
public void validation() {
|
||||
// execution
|
||||
ValidationError result = sut.isHeaderValid(headerNames);
|
||||
|
||||
// assertion
|
||||
assertThat(result == null, is(expectedResult));
|
||||
if (!expectedResult) {
|
||||
assertTrue(result.getMessages().containsAll(expectedErrors));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// parameters for tests
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@Parameterized.Parameters
|
||||
public static Collection validationConfigurations() {
|
||||
return asList(new Object[][] {
|
||||
{ new String[] {}, new String[] {}, true, null },
|
||||
{ new String[] {"a"}, new String[] {"a"}, true, null },
|
||||
{ new String[] {"a"}, new String[] {"b"}, false, singletonList(new ValidationMessage("validation.message.header.match", "0", "a", "b"))},
|
||||
{ new String[] {"a"}, new String[] {"a","b"}, false, singletonList(new ValidationMessage("validation.message.header.length", "2", "1"))},
|
||||
{ new String[] {"a", "b"}, new String[] {"b", "a"}, false, asList(new ValidationMessage("validation.message.header.match", "0", "a", "b"), new ValidationMessage("validation.message.header.match", "1", "b", "a")) }
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -9,10 +9,10 @@ import org.junit.runners.Parameterized;
|
||||
import java.util.Collection;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static ninja.javafx.smartcsv.validation.ConfigMock.columnSectionConfig;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* unit test for validator
|
||||
@@ -27,7 +27,7 @@ public class ValidatorTest {
|
||||
private String column;
|
||||
private String value;
|
||||
private Boolean expectedResult;
|
||||
private String expectedError;
|
||||
private ValidationMessage expectedError;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -45,8 +45,8 @@ public class ValidatorTest {
|
||||
String column,
|
||||
String value,
|
||||
Boolean expectedResult,
|
||||
String expectedError) {
|
||||
this.config = config(configcolumn, configValidation, configValue);
|
||||
ValidationMessage expectedError) {
|
||||
this.config = columnSectionConfig(configcolumn, configValidation, configValue);
|
||||
this.column = column;
|
||||
this.value = value;
|
||||
this.expectedResult = expectedResult;
|
||||
@@ -69,38 +69,15 @@ public class ValidatorTest {
|
||||
@Test
|
||||
public void validation() {
|
||||
// execution
|
||||
ValidationState result = sut.isValid(column, value);
|
||||
ValidationError result = sut.isValid(column, value, 0);
|
||||
|
||||
// assertion
|
||||
assertThat(result.isValid(), is(expectedResult));
|
||||
assertThat(result == null, is(expectedResult));
|
||||
if (!expectedResult) {
|
||||
assertThat(result.error(), is(expectedError));
|
||||
assertThat(result.getMessages(), contains(expectedError));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// mocks
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
private Config config(String column, String validation, Object value) {
|
||||
|
||||
Config columnConfig = mock(Config.class);
|
||||
Config validatorConfig = mock(Config.class);
|
||||
|
||||
when(columnConfig.hasPath(column)).thenReturn(true);
|
||||
when(columnConfig.getConfig(column)).thenReturn(validatorConfig);
|
||||
|
||||
when(validatorConfig.hasPath(validation)).thenReturn(true);
|
||||
if (value instanceof Boolean) {
|
||||
when(validatorConfig.getBoolean(validation)).thenReturn((Boolean) value);
|
||||
} else if (value instanceof String) {
|
||||
when(validatorConfig.getString(validation)).thenReturn((String) value);
|
||||
} else if (value instanceof Integer) {
|
||||
when(validatorConfig.getInt(validation)).thenReturn((Integer)value);
|
||||
}
|
||||
|
||||
return columnConfig;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// parameters for tests
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -108,22 +85,22 @@ public class ValidatorTest {
|
||||
public static Collection validationConfigurations() {
|
||||
return asList(new Object[][] {
|
||||
{ "column", "not empty", true, "column", "value", true, null },
|
||||
{ "column", "not empty", true, "column", "", false, "should not be empty\n" },
|
||||
{ "column", "not empty", true, "column", null, false, "should not be empty\n" },
|
||||
{ "column", "not empty", true, "column", "", false, new ValidationMessage("validation.message.not.empty") },
|
||||
{ "column", "not empty", true, "column", null, false, new ValidationMessage("validation.message.not.empty") },
|
||||
{ "column", "integer", true, "column", "999", true, null },
|
||||
{ "column", "integer", true, "column", "a", false, "should be an integer\n" },
|
||||
{ "column", "integer", true, "column", "a", false, new ValidationMessage("validation.message.integer") },
|
||||
{ "column", "minlength", 2, "column", "12", true, null },
|
||||
{ "column", "minlength", 2, "column", "1", false, "has not min length of 2\n" },
|
||||
{ "column", "minlength", 2, "column", "1", false, new ValidationMessage("validation.message.min.length", "2") },
|
||||
{ "column", "maxlength", 2, "column", "12", true, null },
|
||||
{ "column", "maxlength", 2, "column", "123", false, "has not max length of 2\n" },
|
||||
{ "column", "maxlength", 2, "column", "123", false, new ValidationMessage("validation.message.max.length", "2") },
|
||||
{ "column", "date", "yyyyMMdd", "column", "20151127", true, null },
|
||||
{ "column", "date", "yyyyMMdd", "column", "27.11.2015", false, "is not a date of format yyyyMMdd\n" },
|
||||
{ "column", "date", "yyyyMMdd", "column", "27.11.2015", false, new ValidationMessage("validation.message.date.format", "yyyyMMdd") },
|
||||
{ "column", "alphanumeric", true, "column", "abcABC123", true, null },
|
||||
{ "column", "alphanumeric", true, "column", "-abcABC123", false, "should not be alphanumeric\n" },
|
||||
{ "column", "alphanumeric", true, "column", "-abcABC123", false, new ValidationMessage("validation.message.alphanumeric") },
|
||||
{ "column", "regexp", "[a-z]*", "column", "abc", true, null },
|
||||
{ "column", "regexp", "[a-z]*", "column", "abcA", false, "does not match [a-z]*\n" },
|
||||
{ "column", "regexp", "[a-z]*", "column", "abcA", false, new ValidationMessage("validation.message.regexp", "[a-z]*") },
|
||||
{ "column", "groovy", "value.contains('a')? 'true' : 'no a inside'", "column", "abcdef", true, null },
|
||||
{ "column", "groovy", "value.contains('a')? 'true' : 'no a inside'", "column", "bcdefg", false, "no a inside\n" },
|
||||
{ "column", "groovy", "value.contains('a')? 'true' : 'no a inside'", "column", "bcdefg", false, new ValidationMessage("no a inside") },
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user