@Test
 public void testLastOrderDateRule() throws Exception {
   final BTGRuleModel rule = createRule("testRule");
   final BTGOperandModel leftOperand = createLastOrderDateOperand("lastOrderDate");
   final BTGOperandModel rightOperand =
       createReferenceDateOperand("reference date", IntervalResolution.MINUTE, Integer.valueOf(1));
   rule.setConditions(
       Collections.singletonList(
           createExpression(
               leftOperand, createOperator(DateExpressionEvaluator.GREATER_THAN), rightOperand)));
   modelService.save(rule);
   userService.setCurrentUser(customerA);
   Assert.assertFalse(
       "rule should evaluate FALSE without any orders",
       ruleEvaluator.evaluate(
           customerA,
           rule,
           new BTGEvaluationContext(
               BTGConditionEvaluationScope.OFFLINE,
               BTGEvaluationMethod.OPTIMIZED,
               BTGResultScope.PERMANENT)));
   placeTestOrder(TYSKIE);
   Assert.assertTrue(
       "rule should evaluate TRUE with last order placed before",
       ruleEvaluator.evaluate(
           customerA,
           rule,
           new BTGEvaluationContext(
               BTGConditionEvaluationScope.OFFLINE,
               BTGEvaluationMethod.OPTIMIZED,
               BTGResultScope.PERMANENT)));
 }
  @Test
  public void testEachOrderTotalRuleEvaluation() throws Exception {
    final BTGRuleModel rule = createRule("testRule");

    final BTGOperandModel leftOperand =
        createOrderOperand(BTGEachOrderTotalSumOperandModel.class, 2, "");
    final BTGOperandModel rightOperand = createPriceReferenceOperand(10, EUR);
    rule.setConditions(
        Collections.singletonList(
            createExpression(
                leftOperand, createOperator(PriceExpressionEvaluator.GREATER_THAN), rightOperand)));
    modelService.save(rule);
    userService.setCurrentUser(customerA);

    Assert.assertFalse(
        "Rule should evaluate false without any order",
        ruleEvaluator.evaluate(
            customerA,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.ONLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));
    placeTestOrder(TYSKIE, NONFULFILLING_PRODUCT_TEMPLATE + 3); // total 9

    Assert.assertFalse(
        "Rule should evaluate false : only one order with total 9",
        ruleEvaluator.evaluate(
            customerA,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.ONLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));
    placeTestOrder(AUGISTINER, NONFULFILLING_PRODUCT_TEMPLATE + 5); // total 11
    Assert.assertFalse(
        "Rule should evaluate false : 2 last orders (9, 11)",
        ruleEvaluator.evaluate(
            customerA,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.ONLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));
    placeTestOrder(
        AUGISTINER,
        NONFULFILLING_PRODUCT_TEMPLATE + 9,
        NONFULFILLING_PRODUCT_TEMPLATE + 0); // total 10,5
    Assert.assertTrue(
        "Rule should evaluate true : 2 last orders (11, 10,5)",
        ruleEvaluator.evaluate(
            customerA,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.ONLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));
  }
  @Test
  public void testProductInOrderRuleEvaluation() throws Exception {
    final BTGRuleModel rule = createRule("testRule");
    // in 3 last orders
    final BTGOperandModel leftOperand = createProductsInOrdersOperand(3, "orderTestOperand");
    // these two products must be
    final BTGOperandModel rightOperand = createProductsOperand(TYSKIE, HACKERPSCHORR);
    rule.setConditions(
        Collections.singletonList(
            createExpression(leftOperand, createOperator("contains"), rightOperand)));
    modelService.save(rule);

    userService.setCurrentUser(customerB);
    Assert.assertFalse(
        "Rule should evaluate false without any order",
        ruleEvaluator.evaluate(
            customerB,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.ONLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));
    placeTestOrder(HACKERPSCHORR);
    Assert.assertFalse(
        "Rule should evaluate FALSE with only HACKERPSCHORR ordered",
        ruleEvaluator.evaluate(
            customerB,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.ONLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));
    placeTestOrder(TYSKIE);
    Assert.assertTrue(
        "Rule should evaluate TRUE with HACKERPSCHORR and ZYWIEC ordered ",
        ruleEvaluator.evaluate(
            customerB,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.ONLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));
    placeTestOrder(AUGISTINER);
    placeTestOrder(AUGISTINER);

    placeTestOrder(HACKERPSCHORR, TYSKIE);
    Assert.assertTrue(
        "Rule should evaluate TRUE with HACKERPSCHORR and ZYWIEC ordered in one order",
        ruleEvaluator.evaluate(
            customerB,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.ONLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));
  }
  @Test
  public void testCategoriesInOrderRuleEvaluation() throws Exception {
    final BTGRuleModel rule = createRule("testRule");
    // in 3 last orders
    final BTGOperandModel leftOperand = createCategoriesinOrderOperand("testOPerand", false, 2);
    // these two products must be
    final BTGOperandModel rightOperand =
        createBTGReferenceCategoriesOperand(SOFTDRINKS_ONLINE, POLISHBEERS_ONLINE);
    rule.setConditions(
        Collections.singletonList(
            createExpression(leftOperand, createOperator("contains"), rightOperand)));
    modelService.save(rule);

    userService.setCurrentUser(customerC);

    Assert.assertFalse(
        "Rule should evaluate false without any order",
        ruleEvaluator.evaluate(
            customerC,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.ONLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));
    placeTestOrder(HACKERPSCHORR, AUGISTINER); // germanBeers
    placeTestOrder(TYSKIE); // traditionalBeers

    Assert.assertFalse(
        "Rule should evaluate FALSE",
        ruleEvaluator.evaluate(
            customerC,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.ONLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));
    placeTestOrder(NONFULFILLING_PRODUCT_TEMPLATE + 9); // softdrink;
    Assert.assertTrue(
        "Rule should evaluate TRUE",
        ruleEvaluator.evaluate(
            customerC,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.ONLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));
  }
  @Test
  public void testViewedProducts() throws Exception {
    BTGRuleModel rule;

    // without viewed products
    rule = createRule("testRule1");
    rule.setConditions(
        Collections.singletonList(
            createExpression(
                createOperand(BTGViewedProductsOperandModel.class, "test"),
                createOperator("contains"),
                createProductsOperand(AUGISTINER))));
    modelService.save(rule);

    Assert.assertFalse(
        "Rule should evaluate false without any products",
        ruleEvaluator.evaluate(
            customerA,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.ONLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));

    // with one viewed product
    getRuleDataContainerForProducts().add(getProduct(AUGISTINER).getPk().toString());

    rule = createRule("testRule2");
    rule.setConditions(
        Collections.singletonList(
            createExpression(
                createOperand(BTGViewedProductsOperandModel.class, "test"),
                createOperator("contains"),
                createProductsOperand(AUGISTINER))));
    modelService.save(rule);

    Assert.assertTrue(
        "Rule should evaluate true with a product",
        ruleEvaluator.evaluate(
            customerA,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.ONLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));
  }
  @Test
  public void testOrderNumberRule() throws Exception {
    final BTGRuleModel rule = createRule("testRule");
    final BTGOperandModel leftOperand =
        createNumberOfOrdersOperand(null, null, "numberOfOrdersoperand");
    final BTGOperandModel rightOperand = createIntLiteralOperand(Integer.valueOf(2));
    rule.setConditions(
        Collections.singletonList(
            createExpression(
                leftOperand, createOperator(NumericExpressionEvaluator.EQUALS), rightOperand)));
    modelService.save(rule);

    userService.setCurrentUser(customerB);
    Assert.assertFalse(
        "rule should evaluate FALSE without any orders",
        ruleEvaluator.evaluate(
            customerB,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.OFFLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));

    placeTestOrder(AUGISTINER);
    Assert.assertFalse(
        "rule should evaluate FALSE with only 1 order in history",
        ruleEvaluator.evaluate(
            customerB,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.OFFLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));

    placeTestOrder(NONFULFILLING_PRODUCT_TEMPLATE + 5);
    Assert.assertTrue(
        "rule should evaluate TRUE with only 2 order in history",
        ruleEvaluator.evaluate(
            customerB,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.OFFLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));
  }
  @Test
  public void testOrderRuleEvaluation() throws Exception {
    final BTGRuleModel rule = createRule("testRule");
    rule.setConditions(
        Collections.singletonList(
            createExpression(
                createOrderOperand(BTGOrderTotalSumOperandModel.class, 2, ""),
                createOperator(PriceExpressionEvaluator.EQUALS),
                createPriceReferenceOperand(5, EUR))));
    modelService.save(rule);
    userService.setCurrentUser(customerA);

    Assert.assertFalse(
        "Rule should evaluate false without any order",
        ruleEvaluator.evaluate(
            customerA,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.ONLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));
    placeTestOrder(TYSKIE);
    Assert.assertTrue(
        "Rule should evaluate true with an order of total:5",
        ruleEvaluator.evaluate(
            customerA,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.ONLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));
    placeTestOrder(AUGISTINER);
    Assert.assertFalse(
        "Rule should evaluate false with an order of total:10",
        ruleEvaluator.evaluate(
            customerB,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.ONLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));
  }
  @Test
  public void testUrlParameters() throws Exception {
    final RuleDataContainer<HashMap<String, String[]>> ruleDataContainer =
        getRuleDataContainerForUrlParameters();

    BTGRuleModel rule;

    // without viewed products
    rule = createRule("testRule1");
    rule.setConditions(
        Collections.singletonList(
            createExpression(
                createOperand(BTGUrlParameterOperandModel.class, "test"),
                createOperator("contains"),
                createKeyValuePairListOperand("keyValuePairs", "param1", "param2=test"))));
    modelService.save(rule);

    Assert.assertFalse(
        ruleEvaluator.evaluate(
            customerA,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.ONLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));

    // with one parameter
    ruleDataContainer.clear();
    HashMap<String, String[]> paramMap = new ParamMapBuilder().add("param1").toMap();
    getRuleDataContainerForUrlParameters().add(paramMap);

    rule = createRule("testRule2");
    rule.setConditions(
        Collections.singletonList(
            createExpression(
                createOperand(BTGUrlParameterOperandModel.class, "test"),
                createOperator("containsAny"),
                createKeyValuePairListOperand("keyValuePairs", "param1", "param2=test"))));
    modelService.save(rule);

    Assert.assertTrue(
        ruleEvaluator.evaluate(
            customerA,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.ONLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));

    // with two parameters
    ruleDataContainer.clear();
    paramMap = new ParamMapBuilder().add("param1", "").add("param2", "test").toMap();
    getRuleDataContainerForUrlParameters().add(paramMap);

    rule = createRule("testRule3");
    rule.setConditions(
        Collections.singletonList(
            createExpression(
                createOperand(BTGUrlParameterOperandModel.class, "test"),
                createOperator("contains"),
                createKeyValuePairListOperand("keyValuePairs", "param1", "param2=test"))));
    modelService.save(rule);

    Assert.assertTrue(
        ruleEvaluator.evaluate(
            customerA,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.ONLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));

    // with two parameters with multiple values
    ruleDataContainer.clear();
    paramMap =
        new ParamMapBuilder().add("param1", "testVal").add("param2", "testVal", "test").toMap();
    getRuleDataContainerForUrlParameters().add(paramMap);

    rule = createRule("testRule3");
    rule.setConditions(
        Collections.singletonList(
            createExpression(
                createOperand(BTGUrlParameterOperandModel.class, "test"),
                createOperator("contains"),
                createKeyValuePairListOperand("keyValuePairs", "param1", "param2=test"))));
    modelService.save(rule);

    Assert.assertTrue(
        ruleEvaluator.evaluate(
            customerA,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.ONLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));

    // not contains
    ruleDataContainer.clear();
    paramMap =
        new ParamMapBuilder().add("param1", "testVal").add("param2", "testVal", "test").toMap();
    getRuleDataContainerForUrlParameters().add(paramMap);

    rule = createRule("testRule3");
    rule.setConditions(
        Collections.singletonList(
            createExpression(
                createOperand(BTGUrlParameterOperandModel.class, "test"),
                createOperator("notContains"),
                createKeyValuePairListOperand("keyValuePairs", "param3", "param4=test"))));
    modelService.save(rule);

    Assert.assertTrue(
        ruleEvaluator.evaluate(
            customerA,
            rule,
            new BTGEvaluationContext(
                BTGConditionEvaluationScope.ONLINE,
                BTGEvaluationMethod.OPTIMIZED,
                BTGResultScope.PERMANENT)));
  }