/*
* Copyright 2016 Skynav, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY SKYNAV, INC. AND ITS CONTRIBUTORS “AS IS” AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL SKYNAV, INC. OR ITS CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.skynav.ttv.util;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
public class ConditionTestCases {
private static final String[][] validConditions = {
{ "0", "LITERAL(#N(0))" },
{ "0.", "LITERAL(#N(0.))" },
{ ".0", "LITERAL(#N(.0))" },
{ "0.0", "LITERAL(#N(0.0))" },
{ "0.0E0", "LITERAL(#N(0.0E0))" },
{ "0.0E+0", "LITERAL(#N(0.0E+0))" },
{ "0.0E-0", "LITERAL(#N(0.0E-0))" },
{ "1", "LITERAL(#N(1))" },
{ "123", "LITERAL(#N(123))" },
{ "123.", "LITERAL(#N(123.))" },
{ "123.456", "LITERAL(#N(123.456))" },
{ "true", "LITERAL(#B(true))" },
{ "false", "LITERAL(#B(false))" },
{ "\"a b c\"", "LITERAL(#S(a b c))" },
{ "\'a b c\'", "LITERAL(#S(a b c))" },
{ "\'\\\'\'", "LITERAL(#S(\'))" },
{ "\'\\\"\'", "LITERAL(#S(\"))" },
{ "x", "LITERAL(#I(x))" },
{ "x*y+z", "ADD(MULTIPLY(LITERAL(#I(x)),LITERAL(#I(y))),LITERAL(#I(z)))" },
{ "x * y + z", "ADD(MULTIPLY(LITERAL(#I(x)),LITERAL(#I(y))),LITERAL(#I(z)))" },
{ "x+y*z", "ADD(LITERAL(#I(x)),MULTIPLY(LITERAL(#I(y)),LITERAL(#I(z))))" },
{ "x + y * z", "ADD(LITERAL(#I(x)),MULTIPLY(LITERAL(#I(y)),LITERAL(#I(z))))" },
{ "f(x)", "APPLY(LITERAL(#I(f)),GROUP(LITERAL(#I(x))))" },
{ "f ( x )", "APPLY(LITERAL(#I(f)),GROUP(LITERAL(#I(x))))" },
{ "f(x,y,z)", "APPLY(LITERAL(#I(f)),GROUP(LITERAL(#I(z)),LITERAL(#I(y)),LITERAL(#I(x))))" },
{ "f ( x, y, z )", "APPLY(LITERAL(#I(f)),GROUP(LITERAL(#I(z)),LITERAL(#I(y)),LITERAL(#I(x))))" },
{ "f(g(x))", "APPLY(LITERAL(#I(f)),GROUP(APPLY(LITERAL(#I(g)),GROUP(LITERAL(#I(x))))))" },
{ "f ( g ( x ) )", "APPLY(LITERAL(#I(f)),GROUP(APPLY(LITERAL(#I(g)),GROUP(LITERAL(#I(x))))))" },
};
@Test
public void testValidConditions() throws Exception {
for (String[] spec : validConditions) {
String condition = spec[0];
String expected = spec[1];
try {
Condition c = Condition.valueOf(condition);
assertNotNull(c);
if (expected != null)
assertEquals(expected, c.toString());
} catch (Condition.ParserException e) {
fail("unexpected condition invalidity: \"" + condition + "\": " + e.getMessage());
}
}
}
private static final Object[][] boundParameterBindings = {
{ "forced", Boolean.FALSE },
{ "mediaAspectRatio", Double.valueOf(16.0/9.0) },
{ "mediaLanguage", "en" },
{ "userLanguage", "en" },
};
private static final Object[][] evaluatedConditionBindings = {
// constant bindings
{ "i", Integer.valueOf(1) },
{ "j", Integer.valueOf(2) },
{ "k", Integer.valueOf(3) },
{ "p", Boolean.FALSE },
{ "q", Boolean.TRUE },
{ "s", "s" },
{ "u", "u u" },
{ "v", "v v v" },
{ "x", Double.valueOf(1.1) },
{ "y", Double.valueOf(2.2) },
{ "z", Double.valueOf(3.3) },
{ "PI", Double.valueOf(Math.PI) },
{ "ZERO", Integer.valueOf(0) },
// function bindings
{ "log10", new TestFunctionLog10() },
{ "pow10", new TestFunctionPow10() },
};
private static class TestFunctionLog10 implements Condition.EvaluatorFunction {
public Object apply(Condition.EvaluatorState state, List<Object> arguments) {
if (arguments.size() < 1)
throw new Condition.BadOperandCountException(arguments.size(), 1, 1);
else {
Class<?> operandClass = Number.class;
Object o0 = arguments.get(0);
if (Condition.checkCompatibleOperand(o0, operandClass)) {
o0 = Condition.convertCompatibleOperand(o0, operandClass);
assertTrue(o0 instanceof Number);
return Double.valueOf(Math.log10(((Number) o0).doubleValue()));
} else
throw new Condition.IncompatibleOperandException(o0, operandClass);
}
}
}
private static class TestFunctionPow10 implements Condition.EvaluatorFunction {
public Object apply(Condition.EvaluatorState state, List<Object> arguments) {
if (arguments.size() < 1)
throw new Condition.BadOperandCountException(arguments.size(), 1, 1);
else {
Class<?> operandClass = Number.class;
Object o0 = arguments.get(0);
if (Condition.checkCompatibleOperand(o0, operandClass)) {
o0 = Condition.convertCompatibleOperand(o0, operandClass);
assertTrue(o0 instanceof Number);
return Double.valueOf(Math.pow(10, ((Number) o0).doubleValue()));
} else
throw new Condition.IncompatibleOperandException(o0, operandClass);
}
}
}
private static final Object[][] evaluatedConditions = {
{ "i == 1", Boolean.TRUE },
{ "j == 2", Boolean.TRUE },
{ "k == 3", Boolean.TRUE },
{ "p", Boolean.FALSE },
{ "p == false", Boolean.TRUE },
{ "q", Boolean.TRUE },
{ "q == true", Boolean.TRUE },
{ "s == 's'", Boolean.TRUE },
{ "u == 'u u'", Boolean.TRUE },
{ "v == 'v v v'", Boolean.TRUE },
{ "x == 1.1", Boolean.TRUE },
{ "y == 2.2", Boolean.TRUE },
{ "z == 3.3", Boolean.TRUE },
{ "PI > 3", Boolean.TRUE },
{ "PI < 22/7", Boolean.TRUE },
{ "PI - 3.141592653589792 < 1.5E-15", Boolean.TRUE },
{ "ZERO == 0", Boolean.TRUE },
{ "ZERO == 0.0", Boolean.TRUE },
{ "ZERO != 0", Boolean.FALSE },
{ "ZERO != 0.0", Boolean.FALSE },
{ "ZERO != 1", Boolean.TRUE },
{ "ZERO != 0.1", Boolean.TRUE },
{ "(0) == 0", Boolean.TRUE },
{ "log10(1000) == 3", Boolean.TRUE },
{ "log10(pow10(3)) == 3", Boolean.TRUE },
{ "pow10(3) == 1000", Boolean.TRUE },
{ "pow10(log10(1000)) == 1000", Boolean.TRUE },
{ "parameter('forced') == false", Boolean.TRUE },
{ "parameter('mediaAspectRatio') == 16/9", Boolean.TRUE },
{ "parameter('mediaLanguage') == 'en'", Boolean.TRUE },
{ "parameter('userLanguage') == 'en'", Boolean.TRUE },
};
@Test
public void testEvaluatedConditions() throws Exception {
Map<String,Object> mp = new java.util.HashMap<String,Object>();
Map<String,Object> bp = new java.util.HashMap<String,Object>();
for (Object[] spec : boundParameterBindings) {
String name = (String) spec[0];
Object value = spec[1];
bp.put(name, value);
}
Set<String> sf = new java.util.HashSet<String>();
Condition.EvaluatorState state = Condition.makeEvaluatorState(mp, bp, sf);
for (Object[] spec : evaluatedConditionBindings) {
String identifier = (String) spec[0];
Object value = spec[1];
state.setBinding(identifier, value);
}
for (Object[] spec : evaluatedConditions) {
String condition = (String) spec[0];
Boolean expected = (Boolean) spec[1];
try {
Condition c = Condition.valueOf(condition);
assertNotNull(c);
boolean actual = c.evaluate(state);
assertEquals(condition, expected, actual);
} catch (Condition.ParserException e) {
fail("unexpected condition invalidity: \"" + condition + "\": " + e.getMessage());
} catch (Condition.EvaluatorException e) {
fail("unexpected condition evaluation: \"" + condition + "\": " + e.getMessage());
}
}
}
private static final String[][] invalidConditions = {
{ "~", "remaining input \"~\"" },
{ "00", "expected #E, got #N(0), remaining input \"0\"" },
{ "\"a b c", "remaining input \"\"a b c\"" },
{ "\'a b c", "remaining input \"\'a b c\"" },
};
@Test
public void testInvalidConditions() throws Exception {
for (String[] spec : invalidConditions) {
String condition = spec[0];
String expected = spec[1];
try {
Condition c = Condition.valueOf(condition);
assertNull(c);
fail("unexpected condition validity: \"" + condition + "\"");
} catch (Condition.ParserException e) {
if (expected != null)
assertEquals(expected, e.getMessage());
}
}
}
}