package com.indeed.proctor.common;

import com.google.common.collect.Sets;
import com.indeed.proctor.common.el.MulticontextReadOnlyVariableMapper;
import com.indeed.proctor.common.model.ConsumableTestDefinition;
import com.indeed.proctor.common.model.TestBucket;
import org.apache.el.ExpressionFactoryImpl;
import org.junit.Assert;
import org.junit.Test;

import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.el.VariableMapper;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.junit.Assert.assertTrue;

public class TestRuleVerifyUtils {

    private ExpressionFactory expressionFactory = new ExpressionFactoryImpl();

    private ELContext setUpElContextWithContext(final Map<String, Object> context, final String testRule) {
        final List<TestBucket> buckets = TestProctorUtils.fromCompactBucketFormat("inactive:-1,control:0,test:1");
        final ConsumableTestDefinition testDefVal1 = TestProctorUtils.constructDefinition(buckets,
                TestProctorUtils.fromCompactAllocationFormat(String.format("%s|-1:0.5,0:0.5,1:0.0", testRule), "-1:0.25,0:0.5,1:0.25"));
        final Map<String, ValueExpression> testConstants = ProctorUtils.convertToValueExpressionMap(expressionFactory, testDefVal1.getConstants());

        final ProvidedContext providedContext = new ProvidedContext(ProctorUtils.convertToValueExpressionMap(expressionFactory, context), true);
        final VariableMapper variableMapper = new MulticontextReadOnlyVariableMapper(testConstants, providedContext.getContext());

        final RuleEvaluator ruleEvaluator = new RuleEvaluator(expressionFactory, RuleEvaluator.FUNCTION_MAPPER, testDefVal1.getConstants());
        return ruleEvaluator.createELContext(variableMapper);
    }

    private void verifyRule(final String testRule, final Object[][] context, final String[] absentIdentifiers) throws InvalidRuleException {
        final Map<String, Object> contextMap = new HashMap<>();
        for (final Object[] c : context) {
            contextMap.put((String)c[0], c[1]);
        }
        final ELContext elContext = setUpElContextWithContext(contextMap, testRule);
        RuleVerifyUtils.verifyRule(testRule, true, expressionFactory, elContext, Sets.newHashSet(absentIdentifiers));
    }

    private void exceptValidRule(final String testRule, final Object[][] context, final String[] absentIdentifiers) {
        try {
            verifyRule(testRule, context, absentIdentifiers);

            /** no exception was thrown **/
            assertTrue(true);
        } catch (final InvalidRuleException el) {
            /** exception should not be thrown. **/
            Assert.fail();
        }

    }
    private void exceptInvalidRule(final String testRule, final Object[][] context, final String[] absentIdentifiers) {
        try {
            verifyRule(testRule, context, absentIdentifiers);

            /** exception should be thrown until here. **/
            Assert.fail();
        } catch (final InvalidRuleException el) {
            /** expected **/
            assertTrue(true);
        }
    }

    @Test
    public void testVerifyRulesNormal() {
        exceptValidRule(
                "${browser != 'IE9'}",
                new Object[][] {
                        {"browser", "IE"},
                },
                new String[] {
                }
        );

    }

    @Test
    public void testVerifyRulesWithoutContext() {
        exceptInvalidRule(
                "${browser != 'IE9'}",
                new Object[][] {
                },
                new String[] {
                }
        );
    }

    @Test
    public void testVerifyRulesWithAbsentIdentifiers() {
        exceptValidRule(
                "${browser != 'IE9'}",
                new Object[][]{
                },
                new String[]{
                        "browser",
                }
        );
    }

    @Test
    public void testVerifyAndRuleNormal() {
        exceptValidRule(
                "${browser == 'IE9' && country == 'US'}",
                new Object[][]{
                        { "browser", "IE" },
                        { "country", "JP" },
                },
                new String[]{
                }
        );
    }

    @Test
    public void testVerifyAndRuleWithoutContext() {
        exceptInvalidRule(
                "${browser == 'IE9' && country == 'US'}",
                new Object[][]{
                        { "browser", "IE" },
                },
                new String[]{
                }
        );
        exceptInvalidRule(
                "${browser == 'IE9' && country == 'US'}",
                new Object[][]{
                        { "country", "US" },
                },
                new String[]{
                }
        );
        exceptInvalidRule(
                "${browser == 'IE9' && country == 'US'}",
                new Object[][]{
                },
                new String[]{
                        "browser",
                }
        );
        exceptInvalidRule(
                "${browser == 'IE9' && country == 'US'}",
                new Object[][]{
                },
                new String[]{
                        "country",
                }
        );
    }

    @Test
    public void testVerifyAndRuleWithAbsentIdentifers() {
        exceptValidRule(
                "${browser == 'IE9' && country == 'US'}",
                new Object[][]{
                        { "browser", "IE" },
                },
                new String[]{
                        "country",
                }
        );
        exceptValidRule(
                "${browser == 'IE9' && country == 'US'}",
                new Object[][]{
                        { "country", "JP" },
                },
                new String[]{
                        "browser",
                }
        );
        exceptValidRule(
                "${browser == 'IE9' && country == 'US'}",
                new Object[][]{
                },
                new String[]{
                        "browser",
                        "country",
                }
        );
    }
}
@@ -2338,19 +2338,19 @@
  void ex
-cep
+pec
 tValidRu
@@ -2753,19 +2753,19 @@
  void ex
-cep
+pec
 tInvalid
@@ -3197,35 +3197,35 @@
 l() %7B%0A        ex
-cep
+pec
 tValidRule(%0A    
@@ -3484,35 +3484,35 @@
 t() %7B%0A        ex
-cep
+pec
 tInvalidRule(%0A  
@@ -3736,35 +3736,35 @@
 s() %7B%0A        ex
-cep
+pec
 tValidRule(%0A    
@@ -4006,35 +4006,35 @@
 l() %7B%0A        ex
-cep
+pec
 tValidRule(%0A    
@@ -4358,35 +4358,35 @@
 t() %7B%0A        ex
-cep
+pec
 tInvalidRule(%0A  
@@ -4598,35 +4598,35 @@
    );%0A        ex
-cep
+pec
 tInvalidRule(%0A  
@@ -4838,35 +4838,35 @@
    );%0A        ex
-cep
+pec
 tInvalidRule(%0A  
@@ -5076,19 +5076,19 @@
       ex
-cep
+pec
 tInvalid
@@ -5373,35 +5373,35 @@
 s() %7B%0A        ex
-cep
+pec
 tValidRule(%0A    
@@ -5646,35 +5646,35 @@
    );%0A        ex
-cep
+pec
 tValidRule(%0A    
@@ -5927,19 +5927,19 @@
       ex
-cep
+pec
 tValidRu

Fix a typo in a test method name