/*
* Copyright (c) 2017 OBiBa. All rights reserved.
*
* This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.obiba.magma.datasource.excel;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.junit.Test;
import org.obiba.core.util.FileUtil;
import org.obiba.magma.Category;
import org.obiba.magma.Datasource;
import org.obiba.magma.Initialisable;
import org.obiba.magma.MagmaRuntimeException;
import org.obiba.magma.ValueTable;
import org.obiba.magma.ValueTableWriter;
import org.obiba.magma.ValueTableWriter.VariableWriter;
import org.obiba.magma.Variable;
import org.obiba.magma.support.DatasourceParsingException;
import org.obiba.magma.support.Disposables;
import org.obiba.magma.test.AbstractMagmaTest;
import org.obiba.magma.type.IntegerType;
import org.obiba.magma.type.TextType;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import static org.fest.assertions.api.Assertions.assertThat;
@SuppressWarnings({ "OverlyLongMethod", "ReuseOfLocalVariable", "ResultOfMethodCallIgnored", "PMD.NcssMethodCount" })
@edu.umd.cs.findbugs.annotations.SuppressWarnings("RV_RETURN_VALUE_IGNORED_BAD_PRACTICE")
public class ExcelDatasourceTest extends AbstractMagmaTest {
/**
* Test: missing columns, default values and user named columns. See:
* http://wiki.obiba.org/confluence/display/CAG/Excel+Datasource+Improvements
*/
@Test
public void test_read() {
Datasource datasource = new ExcelDatasource("user-defined",
FileUtil.getFileFromResource("org/obiba/magma/datasource/excel/user-defined.xls"));
datasource.initialise();
ValueTable table = datasource.getValueTable("Table1");
assertThat(table).isNotNull();
assertThat(table.getEntityType()).isEqualTo("Participant");
assertThat(table.getVariables()).hasSize(4);
assertThat(table.getVariableCount()).isEqualTo(4);
Variable variable = table.getVariable("Var1");
assertThat(variable.getValueType()).isEqualTo(IntegerType.get());
assertThat(variable.getEntityType()).isEqualTo("Participant");
assertThat(variable.getUnit()).isNull();
assertThat(variable.getMimeType()).isNull();
assertThat(variable.isRepeatable()).isFalse();
assertThat(variable.getOccurrenceGroup()).isNull();
assertThat(variable.getAttributes()).hasSize(1);
assertThat(variable.getAttributeStringValue("foo")).isEqualTo("bar");
assertThat(variable.getCategories()).hasSize(2);
for(Category category : variable.getCategories()) {
assertThat(category.getCode()).isNull();
assertThat(category.isMissing()).isFalse();
if("C1".equals(category.getName())) {
assertThat(category.getAttributes()).hasSize(1);
assertThat(category.getAttributeStringValue("toto")).isEqualTo("tata");
} else {
assertThat(category.getAttributes()).isEmpty();
}
}
variable = table.getVariable("Var2");
assertThat(variable.getValueType()).isEqualTo(IntegerType.get());
assertThat(variable.getAttributes()).isEmpty();
assertThat(variable.getCategories()).isEmpty();
variable = table.getVariable("Var3");
assertThat(variable.getValueType()).isEqualTo(TextType.get());
variable = table.getVariable("Var4");
assertThat(variable.getValueType()).isEqualTo(TextType.get());
}
@Test
public void test_read_bogus() {
Initialisable datasource = new ExcelDatasource("user-defined-bogus",
FileUtil.getFileFromResource("org/obiba/magma/datasource/excel/user-defined-bogus.xls"));
try {
datasource.initialise();
} catch(DatasourceParsingException dpe) {
assertThat(dpe.hasChildren()).isTrue();
List<DatasourceParsingException> errors = dpe.getChildrenAsList();
assertThat(errors).hasSize(10);
assertDatasourceParsingException("DuplicateCategoryName", "[Categories, 4, Table1, Var1, C2]", errors.get(0));
assertDatasourceParsingException("CategoryNameRequired", "[Categories, 5, Table1, Var1]", errors.get(1));
assertDatasourceParsingException("DuplicateCategoryName", "[Categories, 7, Table1, Var2, C1]", errors.get(2));
assertDatasourceParsingException("VariableNameRequired", "[Variables, 6, Table1]", errors.get(3));
assertDatasourceParsingException("DuplicateVariableName", "[Variables, 7, Table1, Var1]", errors.get(4));
assertDatasourceParsingException("VariableNameCannotContainColon", "[Variables, 8, Table1, Foo:Bar]", errors.get(5));
assertDatasourceParsingException("UnknownValueType", "[Variables, 9, Table1, Var5, Numerical]", errors.get(6));
assertDatasourceParsingException("CategoryVariableNameRequired", "[Categories, 9, Table1]", errors.get(7));
assertDatasourceParsingException("CategoryVariableNameRequired", "[Categories, 10, Table1]", errors.get(8));
assertDatasourceParsingException("VariableNameRequired", "[Variables, 10, Table2]", errors.get(9));
}
}
@Test
public void test_read_write_without_table_column() throws IOException {
Datasource datasource = new ExcelDatasource("user-defined-no-table-column",
FileUtil.getFileFromResource("org/obiba/magma/datasource/excel/user-defined-no-table-column.xls"));
datasource.initialise();
assertThat(datasource.getValueTables()).hasSize(1);
ValueTable table = datasource.getValueTable(ExcelDatasource.DEFAULT_TABLE_NAME);
assertThat(table).isNotNull();
assertThat(table.getVariables()).hasSize(3);
assertThat(table.getVariableCount()).isEqualTo(3);
assertThat(table.getVariable("Var1").getCategories()).hasSize(3);
// test that writing variable & category when some columns are missing does not fail
Variable testVariable = Variable.Builder.newVariable("test-variable", TextType.get(), "Participant")
.addCategories("test-category").build();
writeVariableToDatasource(datasource, ExcelDatasource.DEFAULT_TABLE_NAME, testVariable);
}
@Test
public void test_read_write_without_meta() throws IOException {
Datasource datasource = new ExcelDatasource("user-defined-no-meta",
FileUtil.getFileFromResource("org/obiba/magma/datasource/excel/user-defined-no-meta.xls"));
datasource.initialise();
assertThat(datasource.getValueTables()).hasSize(0);
// test that writing variable & category when some columns are missing does not fail
Variable testVariable = Variable.Builder.newVariable("test-variable", TextType.get(), "Participant")
.addCategories("test-category").build();
writeVariableToDatasource(datasource, "Table1", testVariable);
}
@Test
public void test_read_mixed_meta() throws IOException {
Datasource datasource = new ExcelDatasource("user-defined-mixed-meta",
FileUtil.getFileFromResource("org/obiba/magma/datasource/excel/user-defined-mixed-meta.xls"));
datasource.initialise();
assertThat(datasource.getValueTables()).hasSize(1);
ValueTable table = datasource.getValueTable("Table1");
assertThat(table).isNotNull();
assertThat(table.getVariables()).hasSize(2);
assertThat(table.getVariableCount()).isEqualTo(2);
Variable variable = table.getVariable("Var1");
assertThat(variable.getValueType()).isEqualTo(IntegerType.get());
assertThat(variable.getCategories()).hasSize(2);
variable = table.getVariable("Var2");
assertThat(variable.getValueType()).isEqualTo(IntegerType.get());
assertThat(variable.getCategories()).isEmpty();
}
@Test
public void test_read_bogus_without_table_column() {
Initialisable datasource = new ExcelDatasource("user-defined-bogus-no-table-column",
FileUtil.getFileFromResource("org/obiba/magma/datasource/excel/user-defined-bogus-no-table-column.xls"));
try {
datasource.initialise();
} catch(MagmaRuntimeException e) {
if(e.getCause() instanceof DatasourceParsingException) {
DatasourceParsingException dpe = (DatasourceParsingException) e.getCause();
assertThat(dpe.hasChildren()).isTrue();
List<DatasourceParsingException> errors = dpe.getChildrenAsList();
assertThat(errors).hasSize(8);
}
}
}
@Test
public void test_write_variable_is_read_back() throws IOException {
File tmpExcelFile = createTempFile(".xlsx");
Variable testVariable = Variable.Builder.newVariable("test-variable", TextType.get(), "Participant").build();
ExcelDatasource datasource = new ExcelDatasource("test", tmpExcelFile);
datasource.initialise();
writeVariableToDatasource(datasource, "test-table", testVariable);
datasource.dispose();
datasource = new ExcelDatasource("test", tmpExcelFile);
datasource.initialise();
assertThat(datasource.getValueTable("test-table")).isNotNull();
assertThat(datasource.getValueTable("test-table").getVariable("test-variable")).isNotNull();
Disposables.silentlyDispose(datasource);
tmpExcelFile.delete();
}
@Test
public void test_write_variable_multiple_times_OPAL_232() throws IOException {
File tmpExcelFile = createTempFile(".xlsx");
Variable testVariable = Variable.Builder.newVariable("test-variable", TextType.get(), "Participant").build();
ExcelDatasource datasource = new ExcelDatasource("test", tmpExcelFile);
datasource.initialise();
writeVariableToDatasource(datasource, "test-table", testVariable);
datasource.dispose();
datasource = new ExcelDatasource("test", tmpExcelFile);
datasource.initialise();
writeVariableToDatasource(datasource, "test-table", testVariable);
datasource.dispose();
datasource = new ExcelDatasource("test", tmpExcelFile);
datasource.initialise();
ValueTable valueTable = datasource.getValueTable("test-table");
assertThat(valueTable.getVariables()).hasSize(1);
assertThat(valueTable.getVariableCount()).isEqualTo(1);
Disposables.silentlyDispose(datasource);
tmpExcelFile.delete();
}
@Test
public void test_strings_can_be_written_OPAL_238() throws IOException {
File tmp = createTempFile(".xlsx");
Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet();
int rowIndex = 0;
for(String str : readStrings("org/obiba/magma/datasource/excel/opal-238-strings.txt")) {
sheet.createRow(rowIndex++).createCell(0).setCellValue(str);
}
try(FileOutputStream outputStream = new FileOutputStream(tmp)) {
workbook.write(outputStream);
}
try(FileInputStream inputStream = new FileInputStream(tmp)) {
new XSSFWorkbook(inputStream);
}
tmp.delete();
}
@Test
public void test_create_datasource_on_empty_excel_file() {
Initialisable datasource = new ExcelDatasource("empty",
FileUtil.getFileFromResource("org/obiba/magma/datasource/excel/empty.xls"));
datasource.initialise();
}
@Test
public void test_read_long_table_names() {
ExcelDatasource datasource = new ExcelDatasource("long",
FileUtil.getFileFromResource("org/obiba/magma/datasource/excel/long-table-names.xlsx"));
datasource.initialise();
Set<String> c = datasource.getVariablesCustomAttributeNames();
assertThat(c.size()).isEqualTo(22);
assertLongTableNames(datasource);
}
@Test
public void test_write_long_table_names() {
Datasource datasource = new ExcelDatasource("long",
FileUtil.getFileFromResource("org/obiba/magma/datasource/excel/long-table-names.xlsx"));
datasource.initialise();
File testFile = new File("target/long-table-names.xlsx");
if(testFile.exists()) testFile.delete();
ExcelDatasource datasource2 = new ExcelDatasource("long2", testFile);
datasource2.initialise();
for(ValueTable table : datasource.getValueTables()) {
try(ValueTableWriter tableWriter = datasource2.createWriter(table.getName(), table.getEntityType());
VariableWriter variableWriter = tableWriter.writeVariables()) {
for(Variable variable : table.getVariables()) {
variableWriter.writeVariable(variable);
}
}
}
datasource2.dispose();
datasource2 = new ExcelDatasource("long2", testFile);
datasource2.initialise();
assertLongTableNames(datasource2);
}
@Test
@SuppressWarnings("ConstantConditions")
public void test_read_empty_rows() {
Datasource datasource = new ExcelDatasource("empty-rows",
FileUtil.getFileFromResource("org/obiba/magma/datasource/excel/empty-rows.xls"));
datasource.initialise();
ValueTable table = datasource.getValueTable("table1");
assertThat(table).isNotNull();
assertThat(table.getEntityType()).isEqualTo("Participant");
assertThat(table.getVariables()).hasSize(2);
assertThat(table.getVariableCount()).isEqualTo(2);
Variable var1 = table.getVariable("var1");
assertThat(var1.getValueType()).isEqualTo(TextType.get());
assertThat(var1.getAttributes()).hasSize(1);
assertThat(var1.getAttribute("label").getLocale()).isEqualTo(Locale.ENGLISH);
assertThat(var1.getAttribute("label").getValue().toString()).isEqualTo("Variable 1");
assertThat(var1.getEntityType()).isEqualTo("Participant");
assertThat(var1.getUnit()).isNull();
assertThat(var1.getMimeType()).isNull();
assertThat(var1.isRepeatable()).isFalse();
assertThat(var1.getOccurrenceGroup()).isNull();
assertThat(var1.getCategories()).hasSize(2);
Category cat1 = var1.getCategory("cat1");
assertThat(cat1).isNotNull();
assertThat(cat1.getCode()).isNull();
assertThat(cat1.isMissing()).isFalse();
assertThat(cat1.getAttributes()).hasSize(1);
assertThat(cat1.getAttribute("label").getLocale()).isEqualTo(Locale.ENGLISH);
assertThat(cat1.getAttribute("label").getValue().toString()).isEqualTo("Categorie 1");
Category cat2 = var1.getCategory("cat2");
assertThat(cat2).isNotNull();
assertThat(cat2.getCode()).isNull();
assertThat(cat2.isMissing()).isFalse();
assertThat(cat2.getAttributes()).hasSize(1);
assertThat(cat2.getAttribute("label").getLocale()).isEqualTo(Locale.ENGLISH);
assertThat(cat2.getAttribute("label").getValue().toString()).isEqualTo("Categorie 2");
Variable var2 = table.getVariable("var2");
assertThat(var2.getValueType()).isEqualTo(TextType.get());
assertThat(var2.getAttributes()).hasSize(1);
assertThat(var2.getAttribute("label").getLocale()).isEqualTo(Locale.ENGLISH);
assertThat(var2.getAttribute("label").getValue().toString()).isEqualTo("Variable 2");
assertThat(var2.getCategories()).isEmpty();
}
private void assertLongTableNames(ExcelDatasource datasource) {
ValueTable table = datasource.getValueTable("ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF");
assertThat(table).isNotNull();
assertThat(table.getEntityType()).isEqualTo("Participant");
assertThat(table.getVariable("FATHER_COUNTRY_BIRTH_LONG")).isNotNull();
assertThat(table.getVariable("FATHER_COUNTRY_BIRTH_SHORT")).isNotNull();
assertThat(table.getVariable("MOTHER_COUNTRY_BIRTH_LONG")).isNotNull();
assertThat(table.getVariable("MOTHER_COUNTRY_BIRTH_SHORT")).isNotNull();
table = datasource.getValueTable("ABCDEFGHIJKLMNOPQRSTUVWXYZABCDE");
assertThat(table).isNotNull();
assertThat(table.getEntityType()).isEqualTo("Participant");
assertThat(table.getVariable("GENERIC_132")).isNotNull();
assertThat(table.getVariable("GENERIC_134")).isNotNull();
assertThat(datasource.getValueTableNames()).hasSize(2);
}
private Iterable<String> readStrings(String filename) throws IOException {
return Files.readLines(FileUtil.getFileFromResource(filename), Charsets.UTF_8);
}
private File createTempFile(String suffix) throws IOException {
File tmpFile = File.createTempFile("test", suffix);
tmpFile.delete();
// tmpFile.deleteOnExit();
return tmpFile;
}
private void writeVariableToDatasource(Datasource datasource, String tableName, Variable testVariable)
throws IOException {
try(ValueTableWriter tableWriter = datasource.createWriter(tableName, "Participant");
VariableWriter variableWriter = tableWriter.writeVariables()) {
variableWriter.writeVariable(testVariable);
}
}
private void assertDatasourceParsingException(String expectedKey, String expectedParameters,
DatasourceParsingException dpe) {
assertThat(dpe.getKey()).isEqualTo(expectedKey);
assertThat(dpe.getParameters().toString()).isEqualTo(expectedParameters);
}
}