/*******************************************************************************
 * Copyright (C) 2018 xlate.io LLC, http://www.xlate.io
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package io.xlate.validation.constraintvalidation;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.validation.ConstraintValidatorContext;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

import io.xlate.validation.constraints.Expression;
import io.xlate.validation.internal.constraintvalidators.ExpressionValidator;

@ExtendWith(MockitoExtension.class)
@RunWith(JUnitPlatform.class)
class ExpressionValidatorTest {

    ExpressionValidator target;

    @Mock ConstraintValidatorContext context;

    @Mock Expression annotation;

    @BeforeEach
    void initialize() {
        target = new ExpressionValidator();
        Mockito.when(annotation.node()).thenReturn("");
    }

    @Test
    void testLiteralTrue() {
        Mockito.when(annotation.value()).thenReturn("true");
        target.initialize(annotation);
        Assertions.assertTrue(target.isValid(null, context));
    }

    @Test
    void testLiteralFalse() {
        Mockito.when(annotation.value()).thenReturn("false");
        target.initialize(annotation);
        Assertions.assertFalse(target.isValid(null, context));
    }

    @Test
    void testStringIdentityTrue() {
        Mockito.when(annotation.value()).thenReturn("'I' == 'I'");
        target.initialize(annotation);
        Assertions.assertTrue(target.isValid(null, context));
    }

    @Test
    void testNumericComparison() {
        Mockito.when(annotation.value()).thenReturn("self.smaller lt self.larger");
        Map<String, Integer> data = new HashMap<>();
        data.put("smaller", 1);
        data.put("larger", 2);
        target.initialize(annotation);
        Assertions.assertTrue(target.isValid(data, context));
    }

    @Test
    void testDateComparison() {
        Mockito.when(annotation.value()).thenReturn("self.earlier lt self.later");
        Map<String, Date> data = new HashMap<>();
        data.put("earlier", new Date(1));
        data.put("later", new Date());
        target.initialize(annotation);
        Assertions.assertTrue(target.isValid(data, context));
    }

    @Test
    void testDivision() {
        Mockito.when(annotation.value()).thenReturn("3 div 4 eq 0.75");
        Map<String, Date> data = new HashMap<>();
        data.put("earlier", new Date(1));
        data.put("later", new Date());
        target.initialize(annotation);
        Assertions.assertTrue(target.isValid(data, context));
    }
}

@@ -204,19 +204,16 @@
 r modify
-%0A *
  it unde
@@ -213,16 +213,19 @@
 it under
+%0A *
  the ter
@@ -280,19 +280,16 @@
 ublished
-%0A *
  by the 
@@ -292,16 +292,19 @@
 the Free
+%0A *
  Softwar
@@ -352,19 +352,16 @@
 ense, or
-%0A *
  (at you
@@ -373,16 +373,19 @@
 ion) any
+%0A *
  later v
@@ -461,19 +461,16 @@
  useful,
-%0A *
  but WIT
@@ -473,16 +473,19 @@
  WITHOUT
+%0A *
  ANY WAR
@@ -527,19 +527,16 @@
 ranty of
-%0A *
  MERCHAN
@@ -554,16 +554,19 @@
  FITNESS
+%0A *
  FOR A P
@@ -587,17 +587,16 @@
 OSE.
- 
  See the
 %0A * 
@@ -591,19 +591,16 @@
  See the
-%0A *
  GNU Aff
@@ -634,16 +634,19 @@
 for more
+%0A *
  details
@@ -926,24 +926,86 @@
 alidation;%0A%0A
+import static org.junit.jupiter.api.Assertions.assertThrows;%0A%0A
 import java.
@@ -1064,16 +1064,71 @@
 l.Map;%0A%0A
+import javax.validation.ConstraintDefinitionException;%0A
 import j
@@ -1797,16 +1797,20 @@
    @Mock
+%0A   
  Constra
@@ -1848,16 +1848,20 @@
    @Mock
+%0A   
  Express
@@ -3726,11 +3726,361 @@
 );%0A    %7D
+%0A%0A    @Test%0A    void testNonBoolean() %7B%0A        Mockito.when(annotation.value()).thenReturn(%22'a string, not a Boolean'%22);%0A        Map%3CString, Date%3E data = new HashMap%3C%3E();%0A        target.initialize(annotation);%0A        assertThrows(ConstraintDefinitionException.class, () -%3E %7B%0A            target.isValid(data, context);%0A        %7D, %22a message%22);%0A    %7D
 %0A%7D%0A

Add unit test for non-Boolean expressions