Fix spec test runner

This commit is contained in:
Adam Gent
2023-11-17 17:38:49 -05:00
parent 196a471fa8
commit a45d9dde4b
3 changed files with 97 additions and 143 deletions
@@ -1,33 +0,0 @@
//
// JMustache - A Java implementation of the Mustache templating language
// http://github.com/samskivert/jmustache/blob/master/LICENSE
package com.samskivert.mustache.specs;
import java.lang.reflect.Method;
import org.junit.runners.model.FrameworkMethod;
/**
* @author Yoryos Valotasios
*/
public class SpecFrameworkMethod extends FrameworkMethod
{
private final String group;
private final Spec spec;
public SpecFrameworkMethod (Method method, String group, Spec spec) {
super(method);
this.group = group;
this.spec = spec;
}
@Override
public Object invokeExplosively (Object target, Object... params) throws Throwable {
return super.invokeExplosively(target, spec);
}
@Override
public String getName () {
return group + ": " + spec.getName();
}
}
@@ -1,95 +0,0 @@
//
// JMustache - A Java implementation of the Mustache templating language
// http://github.com/samskivert/jmustache/blob/master/LICENSE
package com.samskivert.mustache.specs;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.junit.After;
import org.junit.Before;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.error.YAMLException;
/**
* @author Yoryos Valotasios
*/
public class SpecRunner extends BlockJUnit4ClassRunner
{
private final Yaml yaml = new Yaml();
private final List<FrameworkMethod> tests;
public SpecRunner (Class<?> klass) throws InitializationError {
super(klass);
if (klass != SpecTest.class) throw new IllegalArgumentException(
SpecRunner.class.getSimpleName() + " should only be used with classes of type " +
SpecTest.class.getName());
this.tests = computeTests();
}
@Override
protected List<FrameworkMethod> computeTestMethods () {
return tests;
}
@Override
protected void validateInstanceMethods (List<Throwable> errors) {
validatePublicVoidNoArgMethods(After.class, false, errors);
validatePublicVoidNoArgMethods(Before.class, false, errors);
validateTestMethods(errors);
}
private List<FrameworkMethod> computeTests () throws InitializationError {
String[] groups = new String[] {
"comments",
"delimiters",
"interpolation",
"inverted",
"sections",
"partials"
};
Method m = getTestClassMethod("test", Spec.class);
List<FrameworkMethod> tests = new ArrayList<FrameworkMethod>();
for (String name : groups) {
for (Map<String, Object> test: getTestsForGroup(name)) {
tests.add(new SpecFrameworkMethod(m, name, new Spec(test)));
}
}
return tests;
}
private Method getTestClassMethod (String name, Class<?>... paramTypes)
throws InitializationError {
try {
return getTestClass().getJavaClass().getDeclaredMethod(name, paramTypes);
} catch (NoSuchMethodException ex) {
throw new InitializationError("Could not find " + name + " " +
getTestClass().getJavaClass());
} catch (SecurityException ex) {
throw new InitializationError("Could not find " + name + " " +
getTestClass().getJavaClass());
}
}
private Iterable<Map<String, Object>> getTestsForGroup (String name) {
String ymlPath = "/specs/specs/" + name + ".yml";
try {
@SuppressWarnings("unchecked") Map<String, Object> map =
(Map<String, Object>)yaml.load(getClass().getResourceAsStream(ymlPath));
@SuppressWarnings("unchecked") List<Map<String, Object>> tests =
(List<Map<String, Object>>)map.get("tests");
return tests;
} catch (YAMLException err) {
System.err.println("*** Error loading: " + ymlPath);
System.err.println("*** You probably need to 'git submodule update'.");
throw err;
}
}
}
@@ -1,22 +1,37 @@
//
// JMustache - A Java implementation of the Mustache templating language
// http://github.com/samskivert/jmustache/blob/master/LICENSE
package com.samskivert.mustache.specs; package com.samskivert.mustache.specs;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.junit.Assert; import org.junit.Assert;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.error.YAMLException;
import com.samskivert.mustache.Mustache; import com.samskivert.mustache.Mustache;
import com.samskivert.mustache.Template; import com.samskivert.mustache.Template;
/** @RunWith(Parameterized.class)
* @author Yoryos Valotasios public class SpecTest {
*/
@RunWith(SpecRunner.class) private static final Yaml yaml = new Yaml();
public class SpecTest
{ private final Spec spec;
private final String name;
public SpecTest(Spec spec, String name) {
super();
this.spec = spec;
this.name = name;
}
private static Mustache.Compiler compiler; private static Mustache.Compiler compiler;
private static SpecAwareTemplateLoader loader; private static SpecAwareTemplateLoader loader;
@@ -25,8 +40,10 @@ public class SpecTest
loader = new SpecAwareTemplateLoader(); loader = new SpecAwareTemplateLoader();
compiler = Mustache.compiler().defaultValue("").withLoader(loader); compiler = Mustache.compiler().defaultValue("").withLoader(loader);
} }
public void test (Spec spec) { @Test
public void test() throws Exception {
//System.out.println("Testing: " + name);
loader.setSpec(spec); loader.setSpec(spec);
String tmpl = spec.getTemplate(); String tmpl = spec.getTemplate();
String desc = String.format("Template: '''%s'''\nData: '%s'\n", String desc = String.format("Template: '''%s'''\nData: '%s'\n",
@@ -34,17 +51,82 @@ public class SpecTest
try { try {
Template t = compiler.compile(spec.getTemplate()); Template t = compiler.compile(spec.getTemplate());
String out = t.execute(spec.getData()); String out = t.execute(spec.getData());
Assert.assertEquals(desc, uncrlf(spec.getExpectedOutput()), uncrlf(out)); if (! Objects.equals(uncrlf(spec.getExpectedOutput()), uncrlf(out))) {
System.out.println("");
System.out.println("----------------------------------------");
System.out.println("");
System.out.println("Failed: " + name);
System.out.println(spec);
System.out.println("Expected : \"" + showWhitespace(spec.getExpectedOutput()) + "\"");
System.out.println("Result : \"" + showWhitespace(out) + "\"");
System.out.println("----------------------------------------");
System.out.println("");
}
Assert.assertEquals(desc, showWhitespace(spec.getExpectedOutput()), showWhitespace(out));
} catch (Exception e) { } catch (Exception e) {
// the specs tests assume that the engine silently ignores invalid delimiter // the specs tests assume that the engine silently ignores invalid delimiter
// specifications, but we throw an exception (and rightfully so IMO; this is not a // specifications, but we throw an exception (and rightfully so IMO; this is not a
// place where silent failure is helpful), so just ignore those test failures // place where silent failure is helpful), so just ignore those test failures
if (!e.getMessage().contains("Invalid delimiter")) Assert.fail( if (!e.getMessage().contains("Invalid delimiter")) {
Assert.fail(
desc + "\nExpected: " + uncrlf(spec.getExpectedOutput()) + "\nError: " + e); desc + "\nExpected: " + uncrlf(spec.getExpectedOutput()) + "\nError: " + e);
}
} }
} }
private static String showWhitespace(String s) {
s = s.replace("\r\n", "\u240D");
s = s.replace('\t', '\u21E5');
s = s.replace("\n", "\u21B5\n");
s = s.replace("\u240D", "\u240D\n");
return s;
}
private static String uncrlf (String text) { private static String uncrlf (String text) {
return (text == null) ? null : text.replace("\r", "\\r").replace("\n", "\\n"); return (text == null) ? null : text.replace("\r", "\\r").replace("\n", "\\n");
} }
}
@Parameters(name = "{1}")
public static Collection<Object[]> data() {
String[] groups = new String[] { //
"comments", //
"delimiters", //
"interpolation", //
"inverted", //
"sections", //
"partials"
};
List<Object[]> tuples = new ArrayList<>();
int i = 0;
for (String g : groups) {
Iterable<Spec> specs = getTestsForGroup(g);
for (Spec s : specs) {
Object[] tuple = new Object[] {s, g + "-" + s.getName() + "-" + i++};
tuples.add(tuple);
}
}
return tuples;
}
private static Iterable<Spec> getTestsForGroup(String name) {
String ymlPath = "/specs/specs/" + name + ".yml";
try {
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) yaml.load(SpecTest.class.getResourceAsStream(ymlPath));
@SuppressWarnings("unchecked")
List<Map<String, Object>> tests = (List<Map<String, Object>>) map.get("tests");
List<Spec> specs = new ArrayList<>();
for (Map<String,Object> t : tests) {
specs.add(new Spec(t));
}
return specs;
} catch (YAMLException err) {
System.err.println("*** Error loading: " + ymlPath);
System.err.println("*** You probably need to 'git submodule update'.");
throw err;
}
}
}