package org.sigmah.shared.computation;
/*
* #%L
* Sigmah
* %%
* Copyright (C) 2010 - 2016 URD
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #L%
*/
import com.google.gwt.user.client.rpc.AsyncCallback;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Assert;
import org.junit.Test;
import org.sigmah.shared.computation.dependency.Dependency;
import org.sigmah.shared.computation.dependency.SingleDependency;
import org.sigmah.shared.computation.value.ComputationError;
import org.sigmah.shared.computation.value.ComputedValue;
import org.sigmah.shared.computation.value.ComputedValues;
import org.sigmah.shared.computation.value.DoubleValue;
import org.sigmah.shared.dto.element.FlexibleElementDTO;
import org.sigmah.shared.dto.element.TextAreaElementDTO;
/**
* Test of Computations.
*
* @author Raphaël Calabro (raphael.calabro@netapsys.fr)
*/
public class ComputationsTest {
/**
* Test of parse method, of class Computations.
*/
@Test
public void testParseAddSub() {
List<FlexibleElementDTO> allElements = Collections.emptyList();
final Computation result = Computations.parse("12 + 3.14 - 4", allElements);
Assert.assertEquals("Computation was not parsed correctly.", "12 + 3.14 - 4", result.toString());
Assert.assertEquals("Computation result is incorrect.", new DoubleValue(12.0 + 3.14 - 4.0), result.computeValue(null));
}
/**
* Test of parse method, of class Computations.
*/
@Test
public void testParseMultDiv() {
List<FlexibleElementDTO> allElements = Collections.emptyList();
final Computation result = Computations.parse("12 + 3.14 * 4 + 8 / 2", allElements);
Assert.assertEquals("Computation was not parsed correctly.", "12 + 3.14 × 4 + 8 ÷ 2", result.toString());
Assert.assertEquals("Computation result is incorrect.", new DoubleValue(12.0 + 3.14 * 4.0 + 8.0 / 2.0), result.computeValue(null));
}
/**
* Test of parse method, of class Computations.
*/
@Test
public void testParseUnary() {
List<FlexibleElementDTO> allElements = Collections.emptyList();
final Computation result = Computations.parse("12 * -3.14 / 4", allElements);
Assert.assertEquals("Computation was not parsed correctly.", "12 × (-3.14 ÷ 4)", result.toString());
Assert.assertEquals("Computation result is incorrect.", new DoubleValue(12.0 * -3.14 / 4.0), result.computeValue(null));
}
/**
* Test of parse method, of class Computations.
*/
@Test
public void testParseContext() {
List<FlexibleElementDTO> allElements = Collections.emptyList();
final Computation result = Computations.parse("(12 + 3.14) * 4", allElements);
Assert.assertEquals("Computation was not parsed correctly.", "(12 + 3.14) × 4", result.toString());
Assert.assertEquals("Computation result is incorrect.", new DoubleValue((12.0 + 3.14) * 4.0), result.computeValue(null));
}
/**
* Test of parse method, of class Computations.
*/
@Test
public void testParseVariable() {
final HashMap<Dependency, ComputedValue> values = new HashMap<>();
values.put(new SingleDependency(9), new DoubleValue(9.0));
values.put(new SingleDependency(42), new DoubleValue(42.0));
final Computation result = Computations.parse("12 * $9 + 3.14 * quarante_2", getAllElements());
Assert.assertEquals("Computation was not parsed correctly.", "12 × $9 + 3.14 × $42", result.toString());
Assert.assertEquals("Computation result is incorrect.", new DoubleValue(12.0 * 9.0 + 3.14 * 42.0), result.computeValue(values));
}
/**
* Test of parse method, of class Computations.
*/
@Test
public void testParseFunction() {
final Computation result = Computations.parse("min(neuf, quarante_2) / max(neuf, quarante_2)", getAllElements());
Assert.assertEquals("Computation was not parsed correctly.", "BAD_FORMULA", result.toString());
}
/**
* Test of parse method, of class Computations.
*/
@Test
public void testDivisionError() {
final HashMap<Dependency, ComputedValue> values = new HashMap<>();
values.put(new SingleDependency(9), new DoubleValue(0.0));
final Computation result = Computations.parse("(12 / $9 + 3.14) * 2", getAllElements());
Assert.assertEquals("Computation was not parsed correctly.", "(12 ÷ $9 + 3.14) × 2", result.toString());
Assert.assertEquals("Computation result is incorrect.", ComputationError.DIVISON_BY_ZERO, result.computeValue(values));
}
/**
* Test of parse method, of class Computations.
*/
@Test
public void testReferenceError() {
final HashMap<Dependency, ComputedValue> values = new HashMap<>();
values.put(new SingleDependency(9), new DoubleValue(9.0));
final Computation result = Computations.parse("12 * $10 + 3.14 * quarante_3", getAllElements());
Assert.assertEquals("Computation was not parsed correctly.", "12 × $10 + 3.14 × quarante_3", result.toString());
Assert.assertEquals("Computation result is incorrect.", ComputationError.BAD_REFERENCE, result.computeValue(values));
}
/**
* Test of parse method, of class Computations.
*/
@Test
public void testBadValue() {
final HashMap<Dependency, ComputedValue> values = new HashMap<>();
values.put(new SingleDependency(9), ComputedValues.from("9,1"));
values.put(new SingleDependency(42), ComputedValues.from("quarante deux"));
final Computation result = Computations.parse("12 * $9 + 3.14 * quarante_2", getAllElements());
Assert.assertEquals("Computation was not parsed correctly.", "12 × $9 + 3.14 × $42", result.toString());
Assert.assertEquals("Computation result is incorrect.", ComputationError.BAD_VALUE, result.computeValue(values));
}
/**
* Test of parse method, of class Computations.
*/
@Test
public void testBadFormula() {
final HashMap<Integer, ComputedValue> values = new HashMap<>();
values.put(9, new DoubleValue(9.0));
values.put(42, new DoubleValue(42.0));
Computation badFunction = Computations.parse("neuf(neuf, quarante_2) / quarante_2(neuf, quarante_2)", getAllElements());
Assert.assertEquals("Computation was not parsed correctly.", "BAD_FORMULA", badFunction.toString());
Assert.assertTrue(badFunction.isBadFormula());
badFunction = Computations.parse("9 /", getAllElements());
Assert.assertEquals("Computation was not parsed correctly.", "BAD_FORMULA", badFunction.toString());
Assert.assertTrue(badFunction.isBadFormula());
badFunction = Computations.parse("9 + + 2", getAllElements());
Assert.assertEquals("Computation was not parsed correctly.", "BAD_FORMULA", badFunction.toString());
Assert.assertTrue(badFunction.isBadFormula());
badFunction = Computations.parse("9 9 + 2", getAllElements());
Assert.assertEquals("Computation was not parsed correctly.", "BAD_FORMULA", badFunction.toString());
Assert.assertTrue(badFunction.isBadFormula());
badFunction = Computations.parse("9 +- 2", getAllElements());
Assert.assertEquals("Computation was not parsed correctly.", "BAD_FORMULA", badFunction.toString());
Assert.assertTrue(badFunction.isBadFormula());
}
/**
* Test of toHumanReadableString method, of class Computation.
*/
@Test
public void testHumanReadableFormat() {
final Computation result = Computations.parse("12 * $9 + 3.14 * quarante_2", getAllElements());
Assert.assertEquals("Computation was not parsed correctly.", "12 × neuf + 3.14 × quarante_2", result.toHumanReadableString());
}
/**
* Test of computeValueWithResolver method, of class Computation.
*/
@Test
public void testComputeWithValueResolver() {
final Computation result = Computations.parse("12 * $9 + 3.14 * quarante_2", getAllElements());
Assert.assertEquals("Computation was not parsed correctly.", "12 × $9 + 3.14 × $42", result.toString());
final double[] values = new double[2];
result.computeValueWithResolver(1, new ValueResolver() {
@Override
public void resolve(Collection<Dependency> dependencies, int containerId, AsyncCallback<Map<Dependency, ComputedValue>> onResult) {
Assert.assertEquals("Elements size is incorrect.", 2, dependencies.size());
final HashMap<Dependency, ComputedValue> map = new HashMap<>();
for (final Dependency dependency : dependencies) {
final SingleDependency singleDependency = (SingleDependency) dependency;
final FlexibleElementDTO element = singleDependency.getFlexibleElement();
final double value = Math.random() * 50;
map.put(dependency, new DoubleValue(value));
if (element.getId() == 9) {
values[0] = value;
} else if(element.getId() == 42) {
values[1] = value;
}
}
onResult.onSuccess(map);
}
}, new AsyncCallback<String>() {
@Override
public void onFailure(Throwable caught) {
Assert.fail();
}
@Override
public void onSuccess(String result) {
Assert.assertEquals("Computation result is incorrect.", new DoubleValue(12 * values[0] + 3.14 * values[1]).toString(), result);
}
});
}
/**
* Creates the list of elements used in the tests.
*
* @return List of flexible elements for the tests.
*/
private List<FlexibleElementDTO> getAllElements() {
List<FlexibleElementDTO> allElements = new ArrayList<FlexibleElementDTO>();
final TextAreaElementDTO element9 = new TextAreaElementDTO();
element9.setId(9);
element9.setCode("neuf");
element9.setType('N');
element9.setIsDecimal(Boolean.TRUE);
allElements.add(element9);
final TextAreaElementDTO element11 = new TextAreaElementDTO();
element11.setId(11);
element11.setCode("onze");
element11.setType('N');
element11.setIsDecimal(Boolean.TRUE);
allElements.add(element11);
final TextAreaElementDTO element24 = new TextAreaElementDTO();
element24.setId(24);
element24.setCode("vingt_4");
element24.setType('N');
element24.setIsDecimal(Boolean.FALSE);
allElements.add(element24);
final TextAreaElementDTO element42 = new TextAreaElementDTO();
element42.setId(42);
element42.setCode("quarante_2");
element42.setType('N');
element42.setIsDecimal(Boolean.FALSE);
allElements.add(element42);
final TextAreaElementDTO element60 = new TextAreaElementDTO();
element60.setId(60);
element60.setCode("soixante");
element60.setType('N');
element60.setIsDecimal(Boolean.TRUE);
allElements.add(element60);
return allElements;
}
/**
* Test of formatRuleForEdition method, of class Computations.
*/
@Test
public void testFormatRuleForEdition() {
Assert.assertNull(Computations.formatRuleForEdition(null, null));
Assert.assertNull(Computations.formatRuleForEdition(" ", null));
Assert.assertEquals("onze + vingt_4", Computations.formatRuleForEdition("$11 + $24", getAllElements()));
}
/**
* Test of formatRuleForServer method, of class Computations.
*/
@Test
public void testFormatRuleForServer() {
Assert.assertNull(Computations.formatRuleForServer(null, null));
Assert.assertNull(Computations.formatRuleForServer(" ", null));
Assert.assertEquals("$11 + $24", Computations.formatRuleForServer("onze + vingt_4", getAllElements()));
}
/**
* Test of formatRuleForServer method, of class Computations.
*/
@Test
public void testFormulaWithFrenchCharacters() {
final TextAreaElementDTO element42 = new TextAreaElementDTO();
element42.setId(42);
element42.setCode("utilisé");
element42.setType('N');
element42.setIsDecimal(Boolean.TRUE);
final TextAreaElementDTO element60 = new TextAreaElementDTO();
element60.setId(60);
element60.setCode("reçu");
element60.setType('N');
element60.setIsDecimal(Boolean.TRUE);
final String rule = Computations.formatRuleForServer("(utilisé / reçu) * 100", Arrays.<FlexibleElementDTO>asList(element42, element60));
Assert.assertEquals("($42 ÷ $60) × 100", rule);
}
/**
* Test of formatRuleForServer method, of class Computations.
*/
@Test
public void testFormulaWithJapaneseCharacters() {
final TextAreaElementDTO element42 = new TextAreaElementDTO();
element42.setId(42);
element42.setCode("使った予算");
element42.setType('N');
element42.setIsDecimal(Boolean.TRUE);
final TextAreaElementDTO element60 = new TextAreaElementDTO();
element60.setId(60);
element60.setCode("頂いた予算");
element60.setType('N');
element60.setIsDecimal(Boolean.TRUE);
final String rule = Computations.formatRuleForServer("(使った予算 / 頂いた予算) * 100", Arrays.<FlexibleElementDTO>asList(element42, element60));
Assert.assertEquals("($42 ÷ $60) × 100", rule);
}
}