/* Copyright 2009-2016 David Hadka
*
* This file is part of the MOEA Framework.
*
* The MOEA Framework is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* The MOEA Framework is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the MOEA Framework. If not, see <http://www.gnu.org/licenses/>.
*/
package org.moeaframework.analysis.sensitivity;
import java.io.File;
import java.io.IOException;
import java.util.Properties;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.moeaframework.TestUtils;
import org.moeaframework.core.FrameworkException;
import org.moeaframework.core.Population;
import org.moeaframework.core.Problem;
import org.moeaframework.core.Settings;
import org.moeaframework.core.Solution;
import org.moeaframework.core.variable.BinaryVariable;
import org.moeaframework.core.variable.Grammar;
import org.moeaframework.core.variable.Permutation;
import org.moeaframework.core.variable.RealVariable;
import org.moeaframework.problem.AbstractProblem;
/**
* Tests the {@link ResultFileReader} class.
*/
public class ResultFileReaderTest {
/**
* A valid result file.
*/
public static final String COMPLETE =
"# Problem = Test\n" +
"# Variables = 3\n" +
"# Objectives = 2\n" +
"0.0 00100 2,1,0 0.0 1.0\n" +
"1.0 01000 1,0,2 1.0 0.0\n" +
"#\n" +
"0.0 00100 2,1,0 0.0 1.0\n" +
"1.0 01000 1,0,2 1.0 0.0\n" +
"#\n";
/**
* A valid result file with extra whitespace on lines.
*/
public static final String COMPLETE_WHITESPACE =
"# Problem = Test\n" +
"# Variables = 3\n" +
"# Objectives = 2\n" +
" 0.0 00100 2,1,0 0.0 1.0\n" +
"\t\t1.0 01000 1,0,2 1.0 0.0\n" +
"#\n" +
"0.0 00100 2,1,0 \t 0.0 1.0\n" +
"\t 1.0 01000 1,0,2 1.0 0.0 \t\n" +
"#\n";
/**
* A valid result file but without decision variables.
*/
public static final String COMPLETE_NOVARIABLES =
"# Problem = Test\n" +
"# Objectives = 2\n" +
"0.0 1.0\n" +
"1.0 0.0\n" +
"#\n" +
"0.0 1.0\n" +
"1.0 0.0\n" +
"#\n";
/**
* A valid result file but without the header.
*/
public static final String COMPLETE_NOHEADER =
"0.0 00100 2,1,0 0.0 1.0\n" +
"1.0 01000 1,0,2 1.0 0.0\n" +
"#\n" +
"0.0 00100 2,1,0 0.0 1.0\n" +
"1.0 01000 1,0,2 1.0 0.0\n" +
"#\n";
/**
* A valid result file with multiple pound characters separating entries
*/
public static final String MULTIPOUND =
"# Problem = Test\n" +
"# Variables = 3\n" +
"# Objectives = 2\n" +
"0.0 00100 2,1,0 0.0 1.0\n" +
"1.0 01000 1,0,2 1.0 0.0\n" +
"#\n#\n" +
"0.0 00100 2,1,0 0.0 1.0\n" +
"1.0 01000 1,0,2 1.0 0.0\n" +
"#\n#\n";
/**
* A valid result file with properties.
*/
public static final String COMPLETE_PROPERTIES =
"# Problem = Test\n" +
"# Variables = 3\n" +
"# Objectives = 2\n" +
"//foo=bar\n" +
"//answer=42\n" +
"0.0 00100 2,1,0 0.0 1.0\n" +
"1.0 01000 1,0,2 1.0 0.0\n" +
"#\n";
/**
* A valid result file with no properties.
*/
public static final String NO_PROPERTIES =
"# Problem = Test\n" +
"# Variables = 3\n" +
"# Objectives = 2\n" +
"0.0 00100 2,1,0 0.0 1.0\n" +
"1.0 01000 1,0,2 1.0 0.0\n" +
"#\n";
/**
* A valid result file with empty properties.
*/
public static final String EMPTY_PROPERTIES =
"# Problem = Test\n" +
"# Variables = 3\n" +
"# Objectives = 2\n" +
"//\n" +
"0.0 00100 2,1,0 0.0 1.0\n" +
"1.0 01000 1,0,2 1.0 0.0\n" +
"#\n";
/**
* A valid result file with the old style properties.
*/
public static final String OLDSTYLE_PROPERTIES =
"# Problem = Test\n" +
"# Variables = 3\n" +
"# Objectives = 2\n" +
"// foo\n" +
"0.0 00100 2,1,0 0.0 1.0\n" +
"1.0 01000 1,0,2 1.0 0.0\n" +
"#\n";
/**
* An empty, but valid, result file.
*/
public static final String EMPTY = "";
/**
* A valid result file with empty entries.
*/
public static final String EMPTY_ENTRY =
"# Problem = Test\n" +
"# Variables = 3\n" +
"# Objectives = 2\n" +
"0.0 00100 2,1,0 0.0 1.0\n" +
"1.0 01000 1,0,2 1.0 0.0\n" +
"#\n" +
"//\n" +
"#\n" +
"0.0 00100 2,1,0 0.0 1.0\n" +
"1.0 01000 1,0,2 1.0 0.0\n" +
"#";
/**
* A valid result file containing just the header and no entries.
*/
public static final String ONLY_HEADER =
"# Problem = Test\n" +
"# Variables = 3\n" +
"# Objectives = 2\n";
/**
* An incomplete result file, missing the trailing # character.
*/
public static final String INCOMPLETE1 =
"# Problem = Test\n" +
"# Variables = 3\n" +
"# Objectives = 2\n" +
"0.0 00100 2,1,0 0.0 1.0\n" +
"1.0 01000 1,0,2 1.0 0.0\n" +
"#\n" +
"0.0 00100 2,1,0 0.0 1.0\n";
/**
* An incomplete result file, containing an empty line.
*/
public static final String INCOMPLETE2 =
"# Problem = Test\n" +
"# Variables = 3\n" +
"# Objectives = 2\n" +
"0.0 00100 2,1,0 0.0 1.0\n" +
"1.0 01000 1,0,2 1.0 0.0\n" +
"#\n" +
"0.0 00100 2,1,0 0.0 1.0\n" +
"\n" +
"1.0 01000 1,0,2 1.0 0.0\n" +
"#";
/**
* An incomplete result file, containing an incomplete entry.
*/
public static final String INCOMPLETE3 =
"# Problem = Test\n" +
"# Variables = 3\n" +
"# Objectives = 2\n" +
"0.0 00100 2,1,0 0.0 1.0\n" +
"1.0 01000 1,0,2 1.0 0.0\n" +
"#\n" +
"0.0 00100 2,1,0\n" +
"1.0 01000 1,0,2 1.0 0.0\n" +
"#";
/**
* An incomplete result file, containing unparseable data.
*/
public static final String INCOMPLETE4 =
"# Problem = Test\n" +
"# Variables = 3\n" +
"# Objectives = 2\n" +
"0.0 00100 2,1,0 0.0 1.0\n" +
"1.0 01000 1,0,2 1.0 0.0\n" +
"#\n" +
"0.0 00100 2,1,0 0.0foo 1.0\n" +
"1.0 01000 1,0,2 1.0 0.0\n" +
"#";
/**
* The problem used for testing.
*/
private Problem problem;
/**
* The expected result from reading a complete input.
*/
private Population population;
/**
* Creates the problem used for testing.
*/
@Before
public void setUp() {
problem = new AbstractProblem(3, 2, 1) {
@Override
public void evaluate(Solution solution) {
throw new UnsupportedOperationException();
}
@Override
public Solution newSolution() {
Solution solution = new Solution(3, 2, 1);
solution.setVariable(0, new RealVariable(0.0, 1.0));
solution.setVariable(1, new BinaryVariable(5));
solution.setVariable(2, new Permutation(3));
return solution;
}
};
Solution solution1 = problem.newSolution();
((RealVariable)solution1.getVariable(0)).setValue(0.0);
((BinaryVariable)solution1.getVariable(1)).set(2, true);
((Permutation)solution1.getVariable(2)).swap(0, 2);
solution1.setObjectives(new double[] { 0.0, 1.0 });
Solution solution2 = problem.newSolution();
((RealVariable)solution2.getVariable(0)).setValue(1.0);
((BinaryVariable)solution2.getVariable(1)).set(1, true);
((Permutation)solution2.getVariable(2)).swap(0, 1);
solution2.setObjectives(new double[] { 1.0, 0.0 });
population = new Population();
population.add(solution1);
population.add(solution2);
}
/**
* Removes references to shared objects so they can be garbage collected.
*/
@After
public void tearDown() {
problem = null;
population = null;
}
/**
* Tests if a valid result file is read correctly.
*
* @throws IOException should not occur
*/
@Test
public void testReaderComplete() throws IOException {
ResultFileReader reader = null;
try {
reader = new ResultFileReader(problem, TestUtils.createTempFile(
COMPLETE));
validateComplete(reader);
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* Tests if a valid result file with extra whitespace on lines is read
* correctly.
*
* @throws IOException should not occur
*/
@Test
public void testReaderCompleteWhitespace() throws IOException {
ResultFileReader reader = null;
try {
reader = new ResultFileReader(problem, TestUtils.createTempFile(
COMPLETE_WHITESPACE));
validateComplete(reader);
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* Tests if a valid result file containing no decision variables is read
* correctly.
*
* @throws IOException should not occur
*/
@Test
public void testReaderCompleteNoVariables() throws IOException {
ResultFileReader reader = null;
try {
reader = new ResultFileReader(problem, TestUtils.createTempFile(
COMPLETE_NOVARIABLES));
validateCompleteNoVariables(reader);
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* Tests if a valid result file containing no header lines is read
* correctly.
*
* @throws IOException should not occur
*/
@Test
public void testReaderCompleteNoHeader() throws IOException {
ResultFileReader reader = null;
try {
reader = new ResultFileReader(problem, TestUtils.createTempFile(
COMPLETE_NOHEADER));
validateComplete(reader);
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* Tests if a valid result file with multiple {@code #} characters
* separating entries is read correctly.
*
* @throws IOException should not occur
*/
@Test
public void testReaderMultipound() throws IOException {
ResultFileReader reader = null;
try {
reader = new ResultFileReader(problem, TestUtils.createTempFile(
MULTIPOUND));
validateComplete(reader);
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* Tests if a valid result file with properties is read correctly.
*
* @throws IOException should not occur
*/
@Test
public void testReaderCompleteProperties() throws IOException {
ResultFileReader reader = null;
Properties properties = new Properties();
properties.setProperty("foo", "bar");
properties.setProperty("answer", "42");
try {
reader = new ResultFileReader(problem, TestUtils.createTempFile(
COMPLETE_PROPERTIES));
validateProperties(reader, properties);
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* Tests if a valid result file with no properties is read correctly.
*
* @throws IOException should not occur
*/
@Test
public void testReaderNoProperties() throws IOException {
ResultFileReader reader = null;
Properties properties = new Properties();
try {
reader = new ResultFileReader(problem, TestUtils.createTempFile(
NO_PROPERTIES));
validateProperties(reader, properties);
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* Tests if a valid result file with empty properties is read correctly.
*
* @throws IOException should not occur
*/
@Test
public void testReaderEmptyProperties() throws IOException {
ResultFileReader reader = null;
Properties properties = new Properties();
try {
reader = new ResultFileReader(problem, TestUtils.createTempFile(
EMPTY_PROPERTIES));
validateProperties(reader, properties);
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* Tests if a valid result file with the old style comment is read
* correctly. The old comment is meaningless, but this is to test
* backwards compatibility to ensure the remainder is still processed.
*
* @throws IOException should not occur
*/
@Test
public void testReaderOldStyleProperties() throws IOException {
ResultFileReader reader = null;
Properties properties = new Properties();
properties.setProperty("foo", "");
try {
reader = new ResultFileReader(problem, TestUtils.createTempFile(
OLDSTYLE_PROPERTIES));
validateProperties(reader, properties);
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* Tests if a valid result file containing no content is read correctly.
*
* @throws IOException should not occur
*/
@Test
public void testReaderEmpty() throws IOException {
ResultFileReader reader = null;
try {
reader = new ResultFileReader(problem, TestUtils.createTempFile(
EMPTY));
validateEmpty(reader);
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* Tests if a valid result file with an empty entry is handled correctly.
*
* @throws IOException should not occur
*/
@Test
public void testReaderEmptyEntry() throws IOException {
ResultFileReader reader = null;
try {
reader = new ResultFileReader(problem, TestUtils.createTempFile(
EMPTY_ENTRY));
validateEmptyEntry(reader);
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* Tests if a valid result file containing only the header is read
* correctly.
*
* @throws IOException should not occur
*/
@Test
public void testReaderOnlyHeader() throws IOException {
ResultFileReader reader = null;
try {
reader = new ResultFileReader(problem, TestUtils.createTempFile(
ONLY_HEADER));
validateEmpty(reader);
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* Tests if an incomplete result file missing the trailing {@code #}
* character is handled correctly.
*
* @throws IOException should not occur
*/
@Test
public void testReaderIncomplete1() throws IOException {
ResultFileReader reader = null;
try {
reader = new ResultFileReader(problem, TestUtils.createTempFile(
INCOMPLETE1));
validateIncomplete(reader);
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* Tests if an invalid result file containing a blank line is handled
* correctly.
*
* @throws IOException should not occur
*/
@Test
public void testReaderIncomplete2() throws IOException {
ResultFileReader reader = null;
try {
reader = new ResultFileReader(problem, TestUtils.createTempFile(
INCOMPLETE2));
validateIncomplete(reader);
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* Tests if an invalid result file with a partial line is handled correctly.
*
* @throws IOException should not occur
*/
@Test
public void testReaderIncomplete3() throws IOException {
ResultFileReader reader = null;
try {
reader = new ResultFileReader(problem, TestUtils.createTempFile(
INCOMPLETE3));
validateIncomplete(reader);
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* Tests if an invalid result file containing unparseable data is handled
* correctly.
*
* @throws IOException should not occur
*/
@Test
public void testReaderIncomplete4() throws IOException {
ResultFileReader reader = null;
try {
reader = new ResultFileReader(problem, TestUtils.createTempFile(
INCOMPLETE4));
validateIncomplete(reader);
} finally {
if (reader != null) {
reader.close();
}
}
}
/**
* Validates a complete result file.
*
* @param reader the result reader
* @throws IOException should not occur
*/
private void validateComplete(ResultFileReader reader) throws IOException {
Assert.assertTrue(reader.hasNext());
TestUtils.assertEquals(population, reader.next().getPopulation());
Assert.assertTrue(reader.hasNext());
TestUtils.assertEquals(population, reader.next().getPopulation());
Assert.assertFalse(reader.hasNext());
Assert.assertFalse(reader.hasNext());
}
/**
* Validates a complete result file that does not contain decision
* variables.
*
* @param reader the result reader
* @throws IOException should not occur
*/
private void validateCompleteNoVariables(ResultFileReader reader)
throws IOException {
population.clear();
population.add(new Solution(new double[] { 0.0, 1.0 }));
population.add(new Solution(new double[] { 1.0, 0.0 }));
Assert.assertTrue(reader.hasNext());
TestUtils.assertEquals(population, reader.next().getPopulation());
Assert.assertTrue(reader.hasNext());
TestUtils.assertEquals(population, reader.next().getPopulation());
Assert.assertFalse(reader.hasNext());
Assert.assertFalse(reader.hasNext());
}
/**
* Validates an empty result file.
*
* @param reader the result reader
* @throws IOException should not occur
*/
private void validateEmpty(ResultFileReader reader) throws IOException {
Assert.assertFalse(reader.hasNext());
Assert.assertFalse(reader.hasNext());
}
/**
* Validates a result file missing an entry.
*
* @param reader the result reader
* @throws IOException should not occur
*/
private void validateEmptyEntry(ResultFileReader reader)
throws IOException {
Assert.assertTrue(reader.hasNext());
TestUtils.assertEquals(population, reader.next().getPopulation());
Assert.assertTrue(reader.hasNext());
Assert.assertEquals(0, reader.next().getPopulation().size());
Assert.assertTrue(reader.hasNext());
TestUtils.assertEquals(population, reader.next().getPopulation());
Assert.assertFalse(reader.hasNext());
Assert.assertFalse(reader.hasNext());
}
/**
* Validates an incomplete result file.
*
* @param reader the result reader
* @throws IOException should not occur
*/
private void validateIncomplete(ResultFileReader reader)
throws IOException {
Assert.assertTrue(reader.hasNext());
TestUtils.assertEquals(population, reader.next().getPopulation());
Assert.assertFalse(reader.hasNext());
Assert.assertFalse(reader.hasNext());
}
/**
* Validates properties.
*
* @param reader the result reader
* @throws IOException should not occur
*/
private void validateProperties(ResultFileReader reader,
Properties properties) throws IOException {
while (reader.hasNext()) {
Assert.assertEquals(properties, reader.next().getProperties());
}
}
@Test
public void testDecode() throws IOException {
File file = TestUtils.createTempFile();
ResultFileReader reader = null;
try {
reader = new ResultFileReader(problem, file);
RealVariable rv = new RealVariable(0.0, 1.0);
reader.decode(rv, "0.5");
Assert.assertEquals(0.5, rv.getValue(), Settings.EPS);
BinaryVariable bv = new BinaryVariable(5);
reader.decode(bv, "00100");
Assert.assertEquals(1, bv.cardinality());
Assert.assertTrue(bv.get(2));
Permutation p = new Permutation(5);
reader.decode(p, "2,0,1,4,3");
Assert.assertArrayEquals(new int[] { 2, 0, 1, 4, 3 }, p.toArray());
//grammars technically have valid encodings, but this tests the
//unsupported decision variable type entry
Grammar g = new Grammar(5);
reader.decode(g, "-");
} finally {
if (reader != null) {
reader.close();
}
}
}
@Test(expected = NumberFormatException.class)
public void testDecodeInvalidReal() throws IOException {
File file = TestUtils.createTempFile();
ResultFileReader reader = null;
try {
reader = new ResultFileReader(problem, file);
RealVariable rv = new RealVariable(0.0, 1.0);
reader.decode(rv, "0.5foo");
} finally {
if (reader != null) {
reader.close();
}
}
}
@Test(expected = FrameworkException.class)
public void testDecodeInvalidBinary1() throws IOException {
File file = TestUtils.createTempFile();
ResultFileReader reader = null;
try {
reader = new ResultFileReader(problem, file);
BinaryVariable bv = new BinaryVariable(5);
reader.decode(bv, "001");
} finally {
if (reader != null) {
reader.close();
}
}
}
@Test(expected = FrameworkException.class)
public void testDecodeInvalidBinary2() throws IOException {
File file = TestUtils.createTempFile();
ResultFileReader reader = null;
try {
reader = new ResultFileReader(problem, file);
BinaryVariable bv = new BinaryVariable(5);
reader.decode(bv, "00200");
Assert.assertEquals(1, bv.cardinality());
Assert.assertTrue(bv.get(2));
} finally {
if (reader != null) {
reader.close();
}
}
}
@Test(expected = FrameworkException.class)
public void testDecodeInvalidPermutation1() throws IOException {
File file = TestUtils.createTempFile();
ResultFileReader reader = null;
try {
reader = new ResultFileReader(problem, file);
Permutation p = new Permutation(5);
reader.decode(p, "2,0,1");
} finally {
if (reader != null) {
reader.close();
}
}
}
@Test(expected = FrameworkException.class)
public void testDecodeInvalidPermutation2() throws IOException {
File file = TestUtils.createTempFile();
ResultFileReader reader = null;
try {
reader = new ResultFileReader(problem, file);
Permutation p = new Permutation(5);
reader.decode(p, "2,0,1,5,3");
} finally {
if (reader != null) {
reader.close();
}
}
}
}