/**
 * Copyright 2008 Matthew Hillsdon
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.hillsdon.reviki.wiki.renderer.creole;

import java.io.IOException;
import java.io.PrintStream;
import java.io.StringReader;
import java.net.URL;
import java.util.List;
import java.util.Map;

import junit.framework.TestCase;
import net.hillsdon.reviki.wiki.renderer.result.TagResultNode;
import net.hillsdon.xhtmlvalidator.XHTMLValidator;

import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.JavaTypeMapper;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public abstract class JsonDrivenRenderingTest extends TestCase {

  private static final String XHTML_PREFIX = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"
                                           + "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title>XHTML prefix</title></head><body>";
  private static final String XHTML_SUFFIX = "</body></html>";
  private final XHTMLValidator _validator = new XHTMLValidator();
  private final List<Map<String, String>> _tests;

  @SuppressWarnings("unchecked")
  public JsonDrivenRenderingTest(final URL url) throws JsonParseException, IOException {
    JsonFactory jf = new JsonFactory();
    _tests = (List<Map<String, String>>) new JavaTypeMapper().read(jf.createJsonParser(url));
  }
  
  public void test() throws Exception {
    final PrintStream err = System.err;
    int errors = 0;
    for (Map<String, String> test : _tests) {
      final String caseName = test.get("name");
      final String bugExplanation = test.get("bug");
      final String expected = test.get("output");
      final String input = test.get("input");
      final String actual = render(input);
      validate(caseName, actual);
      final boolean match = matches(expected, actual);
      if (bugExplanation != null) {
        assertFalse("You fixed " + caseName, match);
        continue;
      }
      if (!match) {
        errors++;
        err.println("Creole case: " + caseName);
        err.println("Input:\n" + input);
        err.println("Expected:\n" + expected);
        err.println("Actual:\n" + actual);
        err.println();
      }
    }
    if (errors > 0) {
      fail("Rendering errors, please see stderr.");
    }
  }

  private boolean matches(final String expected, String actual) {
    // We ignore the CSS class we add to save cluttering the expectations.
    actual = actual.replaceAll(" " + TagResultNode.CSS_CLASS_ATTR, "");
    return expected.equals(actual);
  }

  private void validate(final String caseName, final String actual) {
    // Put the content in a <body> tag first.
    final String content = XHTML_PREFIX + actual + XHTML_SUFFIX;
    try {
      _validator.validate(new InputSource(new StringReader(content)));
    }
    catch (SAXException e) {
      fail(caseName + ": " + e.getMessage());
    }
    catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  protected abstract String render(String input) throws Exception;
  
}

@@ -2400,49 +2400,224 @@
     
-final boolean match = matches(expected, a
+%0A      // We ignore the CSS class we add to save cluttering the expectations.%0A      String tidiedActual = actual.replaceAll(%22 %22 + TagResultNode.CSS_CLASS_ATTR, %22%22);%0A      final boolean match = expected.equals(tidiedA
 ctua
@@ -2941,16 +2941,31 @@
 tual
-:%5Cn%22 + a
+ (tidied):%5Cn%22 + tidiedA
 ctua
@@ -3075,24 +3075,24 @@
  stderr.%22);%0A
+
     %7D%0A  %7D%0A%0A 
@@ -3094,262 +3094,8 @@
  %7D%0A%0A
-  private boolean matches(final String expected, String actual) %7B%0A    // We ignore the CSS class we add to save cluttering the expectations.%0A    actual = actual.replaceAll(%22 %22 + TagResultNode.CSS_CLASS_ATTR, %22%22);%0A    return expected.equals(actual);%0A  %7D%0A%0A
   pr

Improve test output when diff fails - show what we actually compared.