MarkdownProcessor { public String processNonCacheableMacros(String html, String projectName, String branchName, String path, Authentication authentication, Locale locale, String contextPath) { HtmlSerializerContext context = new HtmlSerializerContext(projectName, branchName, path, this, authentication, locale, pageStore, systemSettingsStore, contextPath); String startMarkerPrefix = "__" + NON_CACHEABLE_MACRO_MARKER + "_"; String endMarkerPrefix = "__/" + NON_CACHEABLE_MACRO_MARKER + "_"; String bodyMarker = "__" + NON_CACHEABLE_MACRO_BODY_MARKER + "__"; for (;;) { int start = html.indexOf(startMarkerPrefix); if (start < 0) { break; } start += startMarkerPrefix.length(); int end = html.indexOf('_', start); if (end < 0) { break; } String idx = html.substring(start, end); start = html.indexOf("__", start); if (start < 0) { break; } start += 2; end = html.indexOf(endMarkerPrefix + idx + "__", start); if (end < 0) { break; } String macroCallWithBody = html.substring(start, end); String macroCall = StringUtils.substringBefore(macroCallWithBody, bodyMarker); String body = StringUtils.substringAfter(macroCallWithBody, bodyMarker); String macroName = StringUtils.substringBefore(macroCall, " "); String params = StringUtils.substringAfter(macroCall, " "); IMacro macro = macroFactory.get(macroName); MacroContext macroContext = MacroContext.create(macroName, params, body, context, locale, beanFactory); IMacroRunnable macroRunnable = macro.createRunnable(); html = StringUtils.replace(html, startMarkerPrefix + idx + "__" + macroCallWithBody + endMarkerPrefix + idx + "__", StringUtils.defaultString(macroRunnable.getHtml(macroContext))); MacroInvocation invocation = new MacroInvocation(macroName, params); html = cleanupHtml(html, Collections.singletonList(invocation), false); } return html; }  String markdownToHtml(String markdown, String projectName, String branchName, String path,
			Authentication authentication, Locale locale, String contextPath); String markdownToHtml(String markdown, String projectName, String branchName, String path,
			Authentication authentication, Locale locale, boolean nonCacheableMacros, String contextPath); String headerMarkdownToHtml(String markdown, String projectName, String branchName, String path,
			Authentication authentication, Locale locale, String contextPath); String processNonCacheableMacros(String html, String projectName, String branchName, String path,
			Authentication authentication, Locale locale, String contextPath);  }
@Test public void processNonCacheableMacros() { when(descriptor.isCacheable()).thenReturn(false); when(macro.getDescriptor()).thenReturn(descriptor); when(macro.createRunnable()).thenReturn(runnable); String macroHtml = "<div>macroHtml</div>"; when(runnable.getHtml(any(IMacroContext.class))).thenReturn(macroHtml); String cleanedMacroHtml = "<div>cleanedMacroHtml</div>"; when(runnable.cleanupHtml(anyString())).thenAnswer(new Answer<String>() { @Override public String answer(InvocationOnMock invocation) { String html = (String) invocation.getArguments()[0]; return StringUtils.replace(html, "macroHtml", "cleanedMacroHtml"); } }); when(macroFactory.get(MACRO)).thenReturn(macro); String html = "<p>__" + MarkdownProcessor.NON_CACHEABLE_MACRO_MARKER + "_1__" + MACRO + " " + PARAMS + "__/" + MarkdownProcessor.NON_CACHEABLE_MACRO_MARKER + "_1__</p>"; String result = markdownProcessor.processNonCacheableMacros(html, "project", "branch", DocumentrConstants.HOME_PAGE_NAME + "/bar", authentication, Locale.US, CONTEXT); String expectedHtml = cleanedMacroHtml; assertEquals(expectedHtml, result); }