package com.hubspot.jinjava.lib.fn.eager;

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

import com.hubspot.jinjava.BaseInterpretingTest;
import com.hubspot.jinjava.interpret.DeferredValue;
import com.hubspot.jinjava.lib.fn.MacroFunction;
import org.junit.Test;

public class EagerMacroFunctionTest extends BaseInterpretingTest {

  @Test
  public void itReconstructsImage() {
    String name = "foo";
    String code = "{% macro foo(bar) %}It's: {{ bar }}{% endmacro %}";
    MacroFunction macroFunction = makeMacroFunction(name, code);
    EagerMacroFunction eagerMacroFunction = new EagerMacroFunction(
      name,
      macroFunction,
      interpreter
    );
    assertThat(eagerMacroFunction.reconstructImage()).isEqualTo(code);
  }

  @Test
  public void itResolvesFromContext() {
    context.put("foobar", "resolved");
    String name = "foo";
    String code = "{% macro foo(bar) %}{{ foobar }} and {{ bar }}{% endmacro %}";
    MacroFunction macroFunction = makeMacroFunction(name, code);
    EagerMacroFunction eagerMacroFunction = new EagerMacroFunction(
      name,
      macroFunction,
      interpreter
    );
    assertThat(eagerMacroFunction.reconstructImage())
      .isEqualTo("{% macro foo(bar) %}resolved and {{ bar }}{% endmacro %}");
  }

  @Test
  public void itReconstructsForAliasedName() {
    String name = "foo";
    String fullName = "local." + name;
    String codeFormat = "{%% macro %s(bar) %%}It's: {{ bar }}{%% endmacro %%}";
    MacroFunction macroFunction = makeMacroFunction(
      name,
      String.format(codeFormat, name)
    );
    EagerMacroFunction eagerMacroFunction = new EagerMacroFunction(
      fullName,
      macroFunction,
      interpreter
    );
    assertThat(eagerMacroFunction.reconstructImage())
      .isEqualTo(String.format(codeFormat, fullName));
  }

  @Test
  public void itReconstructsImageWithNamedParams() {
    String name = "foo";
    String code = "{% macro foo(bar, baz=0) %}It's: {{ bar }}, {{ baz }}{% endmacro %}";
    MacroFunction macroFunction = makeMacroFunction(name, code);
    EagerMacroFunction eagerMacroFunction = new EagerMacroFunction(
      name,
      macroFunction,
      interpreter
    );
    assertThat(eagerMacroFunction.reconstructImage()).isEqualTo(code);
  }

  private MacroFunction makeMacroFunction(String name, String code) {
    interpreter.render(code);
    return context.getGlobalMacro(name);
  }
}

@@ -93,16 +93,82 @@
 ertThat;
+%0Aimport static org.assertj.core.api.Assertions.assertThatThrownBy;
 %0A%0Aimport
@@ -251,21 +251,159 @@
 ret.
-DeferredValue
+Context.PartialMacroEvaluationClosable;%0Aimport com.hubspot.jinjava.interpret.DeferredValue;%0Aimport com.hubspot.jinjava.interpret.DeferredValueException
 ;%0Aim
@@ -2467,16 +2467,646 @@
 );%0A  %7D%0A%0A
+  @Test%0A  public void itPartiallyEvaluatesMacroFunction() %7B%0A    // Put this test here because it's only used in eager execution%0A    context.put(%22deferred%22, DeferredValue.instance());%0A    MacroFunction macroFunction = makeMacroFunction(%0A      %22foo%22,%0A      %22%7B%25 macro foo(bar) %25%7DIt's: %7B%7B bar %7D%7D, %7B%7B deferred %7D%7D%7B%25 endmacro %25%7D%22%0A    );%0A    assertThatThrownBy(() -%3E macroFunction.evaluate(%22Bar%22))%0A      .isInstanceOf(DeferredValueException.class);%0A    try (PartialMacroEvaluationClosable ignored = context.withPartialMacroEvaluation()) %7B%0A      assertThat(macroFunction.evaluate(%22Bar%22)).isEqualTo(%22It's: Bar, %7B%7B deferred %7D%7D%22);%0A    %7D%0A  %7D%0A%0A
   privat

Add explicit test for partial macro evaluation