package com.hubspot.jinjava.lib.expression;

import static org.assertj.core.api.Assertions.assertThat;

import com.hubspot.jinjava.JinjavaConfig;
import com.hubspot.jinjava.interpret.DeferredValue;
import com.hubspot.jinjava.interpret.JinjavaInterpreter;
import com.hubspot.jinjava.mode.EagerExecutionMode;
import com.hubspot.jinjava.objects.collections.PyList;
import com.hubspot.jinjava.tree.ExpressionNodeTest;
import java.util.ArrayList;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class EagerExpressionStrategyTest extends ExpressionNodeTest {

  @Before
  public void eagerSetup() {
    interpreter =
      new JinjavaInterpreter(
        jinjava,
        context,
        JinjavaConfig.newBuilder().withExecutionMode(new EagerExecutionMode()).build()
      );
    JinjavaInterpreter.pushCurrent(interpreter);
    context.put("deferred", DeferredValue.instance());
  }

  @After
  public void teardown() {
    JinjavaInterpreter.popCurrent();
  }

  @Test
  public void itPreservesRawTags() {
    interpreter =
      new JinjavaInterpreter(
        jinjava,
        context,
        JinjavaConfig
          .newBuilder()
          .withNestedInterpretationEnabled(false)
          .withExecutionMode(new EagerExecutionMode())
          .build()
      );
    JinjavaInterpreter.pushCurrent(interpreter);
    try {
      assertExpectedOutput(
        "{{ '{{ foo }}' }} {{ '{% something %}' }} {{ 'not needed' }}",
        "{% raw %}{{ foo }}{% endraw %} {% raw %}{% something %}{% endraw %} not needed"
      );
    } finally {
      JinjavaInterpreter.popCurrent();
    }
  }

  @Test
  public void itPreservesRawTagsNestedInterpretation() {
    assertExpectedOutput(
      "{{ '{{ 12345 }}' }} {{ '{% print 'bar' %}' }} {{ 'not needed' }}",
      "12345 bar not needed"
    );
  }

  @Test
  public void itPrependsMacro() {
    assertExpectedOutput(
      "{% macro foo(bar) %} {{ bar }} {% endmacro %}{{ foo(deferred) }}",
      "{% macro foo(bar) %} {{ bar }} {% endmacro %}{{ foo(deferred) }}"
    );
  }

  @Test
  public void itPrependsSet() {
    context.put("foo", new PyList(new ArrayList<>()));
    assertExpectedOutput(
      "{{ foo.append(deferred) }}",
      "{% set foo = [] %}{{ foo.append(deferred) }}"
    );
  }

  private void assertExpectedOutput(String inputTemplate, String expectedOutput) {
    assertThat(interpreter.render(inputTemplate)).isEqualTo(expectedOutput);
  }
}

@@ -721,16 +721,27 @@
 vaConfig
+%0A          
 .newBuil
@@ -745,16 +745,27 @@
 uilder()
+%0A          
 .withExe
@@ -767,36 +767,32 @@
 thExecutionMode(
-new 
 EagerExecutionMo
@@ -793,19 +793,39 @@
 tionMode
-())
+.instance())%0A          
 .build()
@@ -1273,20 +1273,16 @@
 ionMode(
-new 
 EagerExe
@@ -1291,16 +1291,25 @@
 tionMode
+.instance
 ())%0A    

Change to use execution mode singleton