@Test
  public void addAndGetMacroInvocations() {
    MacroInvocation invocation =
        htmlSerializerContext.addMacroInvocation("foo", "params"); // $NON-NLS-1$ //$NON-NLS-2$
    assertEquals("foo", invocation.getMacroName()); // $NON-NLS-1$
    assertEquals("params", invocation.getParameters()); // $NON-NLS-1$

    List<MacroInvocation> invocations = htmlSerializerContext.getMacroInvocations();
    assertEquals(1, invocations.size());
    invocation = invocations.get(0);
    assertEquals("foo", invocation.getMacroName()); // $NON-NLS-1$
    assertEquals("params", invocation.getParameters()); // $NON-NLS-1$
  }
  private String markdownToHtml(
      RootNode rootNode,
      String projectName,
      String branchName,
      String path,
      Authentication authentication,
      Locale locale,
      boolean nonCacheableMacros,
      String contextPath) {

    HtmlSerializerContext context =
        new HtmlSerializerContext(
            projectName,
            branchName,
            path,
            this,
            authentication,
            locale,
            pageStore,
            systemSettingsStore,
            contextPath);
    HtmlSerializer serializer = new HtmlSerializer(context);
    String html = serializer.toHtml(rootNode);

    List<MacroInvocation> macroInvocations = Lists.newArrayList(context.getMacroInvocations());
    // reverse order so that inner invocations will be processed before outer
    Collections.reverse(macroInvocations);
    int nonCacheableMacroIdx = 1;
    for (MacroInvocation invocation : macroInvocations) {
      IMacro macro = macroFactory.get(invocation.getMacroName());
      if (macro == null) {
        macro = new UnknownMacroMacro();
      }
      IMacroDescriptor macroDescriptor = macro.getDescriptor();
      String startMarker = invocation.getStartMarker();
      String endMarker = invocation.getEndMarker();
      String body = StringUtils.substringBetween(html, startMarker, endMarker);
      if (macroDescriptor.isCacheable()) {
        MacroContext macroContext =
            MacroContext.create(
                invocation.getMacroName(),
                invocation.getParameters(),
                body,
                context,
                locale,
                beanFactory);
        IMacroRunnable macroRunnable = macro.createRunnable();
        String macroHtml = StringUtils.defaultString(macroRunnable.getHtml(macroContext));
        html = StringUtils.replace(html, startMarker + body + endMarker, macroHtml);
      } else if (nonCacheableMacros) {
        String macroName = invocation.getMacroName();
        String params = invocation.getParameters();
        String idx = String.valueOf(nonCacheableMacroIdx++);
        html =
            StringUtils.replace(
                html,
                startMarker + body + endMarker,
                "__"
                    + NON_CACHEABLE_MACRO_MARKER
                    + "_"
                    + idx
                    + "__"
                    + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
                    macroName
                    + " "
                    + StringUtils.defaultString(params)
                    + //$NON-NLS-1$
                    "__"
                    + NON_CACHEABLE_MACRO_BODY_MARKER
                    + "__"
                    + //$NON-NLS-1$ //$NON-NLS-2$
                    body
                    + "__/"
                    + NON_CACHEABLE_MACRO_MARKER
                    + "_"
                    + idx
                    + "__"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
      } else {
        html = StringUtils.replace(html, startMarker + body + endMarker, StringUtils.EMPTY);
      }
    }
    html = cleanupHtml(html, macroInvocations, true);
    return html;
  }