1/**2 * Copyright (c) 2009-2011, The HATS Consortium. All rights reserved. 3 * This file is licensed under the terms of the Modified BSD License.4 */5package abs.backend.tests;6import static abs.backend.tests.ReflectionUtils.getField;7import static abs.backend.tests.ReflectionUtils.setField;8import static org.hamcrest.CoreMatchers.equalTo;9import static org.hamcrest.CoreMatchers.notNullValue;10import static org.hamcrest.CoreMatchers.nullValue;11import static org.junit.Assert.assertEquals;12import static org.junit.Assert.assertFalse;13import static org.junit.Assert.assertSame;14import static org.junit.Assert.assertThat;15import static org.junit.Assert.assertTrue;16import static org.junit.Assert.fail;17import static org.hamcrest.CoreMatchers.both;18import static org.hamcrest.CoreMatchers.everyItem;19import static org.hamcrest.CoreMatchers.hasItem;20import java.io.ByteArrayOutputStream;21import java.io.PrintStream;22import java.util.Collections;23import java.util.Iterator;24import java.util.List;25import java.util.Map;26import java.util.Map.Entry;27import java.util.Set;28import org.hamcrest.BaseMatcher;29import org.hamcrest.Description;30import org.hamcrest.Matcher;31import org.junit.Test;32import abs.frontend.analyser.SemanticCondition;33import abs.frontend.analyser.SemanticConditionList;34import abs.frontend.ast.ClassDecl;35import abs.frontend.ast.InterfaceDecl;36import abs.frontend.ast.Model;37import abs.frontend.ast.ModuleDecl;38import abs.frontend.parser.Main;39import abs.frontend.parser.ParserError;40/**41 * Unit tests for {@link ASTBasedABSTestRunnerGenerator}42 * @author woner43 *44 */45public class ASTBasedABSTestRunnerGeneratorTest {46 private final static String ABS_UNIT =47 "module AbsUnit; export *;" +48 "[TypeAnnotation] data DataPoint = DataPoint; " +49 "[TypeAnnotation] data Ignored = Ignored;" +50 "[TypeAnnotation] data Test = Test; " +51 "[TypeAnnotation] data Suite = Suite; " +52 "[TypeAnnotation] data Fixture = Fixture; ";53 private final static String TEST_CODE =54 "module Test; export *; import * from AbsUnit;" +55 "[Fixture] interface T { [Test] Unit t(); }" +56 "[Suite] class TI implements T { Unit t() { } }";57 58 private final static Iterable<Entry<InterfaceDecl, Set<ClassDecl>>> EMPTY_MAP = 59 Collections.<InterfaceDecl, Set<ClassDecl>>emptyMap().entrySet();60 61 private static class SizeMatcher 62 extends BaseMatcher<Iterable<Entry<InterfaceDecl, Set<ClassDecl>>>> {63 64 private final int size;65 66 public SizeMatcher(int size) {67 this.size = size;68 }69 70 public boolean matches(Object arg0) {71 if (arg0 instanceof Iterable) {72 Iterable<?> it = (Iterable<?>) arg0;73 Iterator<?> tr = it.iterator();74 75 int count = 0;76 while (count < size) {77 if (! tr.hasNext()) {78 return false;79 }80 tr.next();81 count++;82 }83 return ! tr.hasNext();84 }85 return false;86 }87 88 @SuppressWarnings("unused")89 public void describeTo(Description arg0) {90 // TODO Auto-generated method stub91 92 }93 94 }95 /**96 * @see ASTBasedABSTestRunnerGeneratorTest.ModuleMatcher below for note about generics!97 */98 private static class TestClassMatcher<I,C>99 extends BaseMatcher<Entry<I, Set<C>>> {100 101 public boolean matches(Object arg0) {102 if (!(arg0 instanceof Entry)) {103 return false;104 }105 106 final Entry<?, ?> entry = (Entry<?, ?>) arg0;107 if (!(entry.getKey() instanceof InterfaceDecl)) {108 return false;109 }110 111 if (!(entry.getValue() instanceof Set)) {112 return false;113 }114 115 final Set<?> set = (Set<?>) entry.getValue();116 if (set.size() != 1) {117 return false;118 }119 120 final Object ele = set.iterator().next();121 if (!(ele instanceof ClassDecl)) {122 return false;123 }124 125 final InterfaceDecl intf = (InterfaceDecl) entry.getKey();126 final ClassDecl clazz = (ClassDecl) ele;127 128 return intf.getName().equals("T") &&129 clazz.getName().equals("TI");130 }131 132 @SuppressWarnings("unused")133 public void describeTo(Description arg0) {134 }135 136 }137 138 /**139 * NB: type patched to be generic instead of the more specific ModuleDecl because140 * javac is too picky about hamcrests' generics!141 */142 private static class ModuleMatcher<T> 143 extends BaseMatcher<T> {144 public boolean matches(Object arg0) {145 if (arg0 instanceof ModuleDecl) {146 ModuleDecl module = (ModuleDecl) arg0;147 if (module.getName().equals(ASTBasedABSTestRunnerGenerator.RUNNER_MAIN)) {148 return module.hasBlock();149 }150 }151 return false;152 }153 @SuppressWarnings("unused")154 public void describeTo(Description arg0) {155 // TODO Auto-generated method stub156 157 }158 }159 @SuppressWarnings("unchecked")160 private static void assertMatches(161 Model model,162 Matcher<Object> testType, 163 Matcher<Object> dataPointType,164 Matcher<Object> fixtureType,165 Matcher<Object> suiteType,166 Matcher<Iterable<Entry<InterfaceDecl, Set<ClassDecl>>>> tests,167 Boolean isEmpty,168 ABSTestRunnerGenerator aut) {169 170 assertSame(model,getField(aut, AbstractABSTestRunnerGenerator.class, "model"));171 assertThat(getField(aut, AbstractABSTestRunnerGenerator.class, "testType"),testType);172 assertThat(getField(aut, AbstractABSTestRunnerGenerator.class, "dataPointType"),dataPointType);173 assertThat(getField(aut, AbstractABSTestRunnerGenerator.class, "fixtureType"),fixtureType);174 assertThat(getField(aut, AbstractABSTestRunnerGenerator.class, "suiteType"),suiteType);175 176 Map<InterfaceDecl, Set<ClassDecl>> actual = 177 (Map<InterfaceDecl, Set<ClassDecl>>) getField(aut, AbstractABSTestRunnerGenerator.class, "tests");178 assertThat(actual.entrySet(),tests);179 assertEquals(isEmpty,getField(aut, AbstractABSTestRunnerGenerator.class, "isEmpty"));180 }181 @SuppressWarnings("unused")182 @Test(expected=IllegalArgumentException.class)183 public final void testABSTestRunnerGeneratorNull() {184 new ASTBasedABSTestRunnerGenerator(null);185 }186 187 @Test188 public final void testABSTestRunnerGenerator() {189 Model model = new Model();190 ABSTestRunnerGenerator generator = 191 new ASTBasedABSTestRunnerGenerator(model);192 193 assertMatches(model, 194 nullValue(), nullValue(), nullValue(), nullValue(), 195 equalTo(EMPTY_MAP), Boolean.TRUE,196 generator);197 198 try {199 model = Main.parseString(ABS_UNIT, true);200 generator = new ASTBasedABSTestRunnerGenerator(model);201 202 assertMatches(model, 203 notNullValue(), notNullValue(), notNullValue(), notNullValue(), 204 equalTo(EMPTY_MAP), Boolean.TRUE,205 generator);206 207 model = Main.parseString(ABS_UNIT + TEST_CODE, true);208 generator = new ASTBasedABSTestRunnerGenerator(model);209 210 assertMatches(model, 211 notNullValue(), notNullValue(), notNullValue(), notNullValue(), 212 both(everyItem(new TestClassMatcher())).213 and(new SizeMatcher(1)), Boolean.FALSE,214 generator);215 216 } catch (Exception e) {217 throw new IllegalStateException("Cannot parse test code",e);218 }219 }220 221 @Test222 public final void testHasUnitTest() {223 Model model = new Model();224 ABSTestRunnerGenerator generator = 225 new ASTBasedABSTestRunnerGenerator(model);226 227 generator = setField(generator, AbstractABSTestRunnerGenerator.class, "isEmpty", Boolean.TRUE);228 assertFalse(generator.hasUnitTest());229 generator = setField(generator, AbstractABSTestRunnerGenerator.class, "isEmpty", Boolean.FALSE);230 assertTrue(generator.hasUnitTest());231 }232 233 @Test234 public final void testGenerateTestRunner() {235 final Model model;236 try {237 model = Main.parseString(ABS_UNIT + TEST_CODE, true);238 } catch (Exception e) {239 throw new IllegalStateException("Cannot parse test code",e);240 }241 242 ABSTestRunnerGenerator generator = new ASTBasedABSTestRunnerGenerator(model);243 ByteArrayOutputStream stream = new ByteArrayOutputStream();244 PrintStream print = new PrintStream(stream); 245 generator.generateTestRunner(print);246 String runner = stream.toString();247 248 try {249 Model result = Main.parseString(ABS_UNIT + TEST_CODE + runner, true);250 251 StringBuilder parseErrors = new StringBuilder();252 if (result.hasParserErrors()) {253 parseErrors.append("Syntactic errors: ");254 List<ParserError> es = result.getParserErrors();255 parseErrors.append(es.size());256 parseErrors.append("\n");257 for (ParserError e : es) {258 parseErrors.append(e.getHelpMessage());259 parseErrors.append("\n");260 }261 }262 263 assertFalse("Generated code must not have parse error: "+parseErrors,result.hasParserErrors());264 265 StringBuilder errors = new StringBuilder();266 if (result.hasErrors()) {267 SemanticConditionList el = result.getErrors();268 errors.append("Semantic errors: ");269 errors.append(el.getErrorCount());270 errors.append("\n");271 for (SemanticCondition error : el) {272 errors.append(error.getHelpMessage());273 errors.append("\n");274 }275 }276 277 assertFalse("Generated code must not have semantic error: "+errors,result.hasErrors());278 result.typeCheck();279 assertFalse("Generated code must not have type error",result.hasTypeErrors());280 281 assertThat("Has one module that has the name 'AbsUnit.TestRunner' and a main block",282 result.getModuleDecls(),hasItem(new ModuleMatcher()));283 284 } catch (Exception e) {285 fail("Cannot throw an exception ");286 }287 288 }289 290}...