package scotch.compiler.syntax.type; import static java.util.Arrays.asList; import static java.util.stream.Collectors.toList; import static java.util.stream.Collectors.toSet; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static scotch.compiler.syntax.type.Unification.circular; import static scotch.compiler.syntax.type.Unification.contextMismatch; import static scotch.compiler.syntax.type.Unification.mismatch; import static scotch.compiler.syntax.type.Unification.unified; import java.util.List; import org.junit.Before; import scotch.symbol.Symbol; import scotch.compiler.syntax.util.DefaultSymbolGenerator; import scotch.symbol.SymbolResolver; public class UnificationTest { protected TypeScope scope; @Before public void initialize() { scope = createTypeScope(); setUp(); } protected TypeScope createTypeScope() { return new DefaultTypeScope(new DefaultSymbolGenerator(), mock(SymbolResolver.class)); } protected void setUp() { // extension point } private List<Symbol> symbolize(List<String> list) { return list.stream().map(Symbol::symbol).collect(toList()); } protected void addContext(Type type, String... context) { scope.extendContext(type, asList(context).stream().map(Symbol::symbol).collect(toSet())); } protected Type argumentOf(Type type) { if (type instanceof FunctionType) { return ((FunctionType) type).getArgument(); } else { throw new UnsupportedOperationException("Can't get argument from " + type.getClass().getSimpleName()); } } protected void shouldBeBound(Type variable, Type target) { assertThat(scope.generate(variable), is(target)); } protected void shouldBeCircular(Unification result, Type target, Type variable) { assertFalse(result.isUnified()); assertThat(result, is(circular(target, variable))); } protected void shouldBeContextMismatch(Unification unification, Type expected, Type actual, List<String> expectedContext, List<String> actualContext) { assertFalse(unification.isUnified()); assertThat(unification, is(contextMismatch(expected, actual, symbolize(expectedContext), symbolize(actualContext)))); } protected void shouldBeMismatch(Unification result, Type target, Type actual) { assertFalse(result.isUnified()); assertThat(result, is(mismatch(target, actual))); } protected void shouldBeReplaced(Type query, Type result) { assertThat(scope.generate(query), is(result)); } protected void shouldBeUnified(Unification result, Type target) { assertTrue(result.isUnified()); assertThat(result, is(unified(target))); } protected Unification unify(Type target, Type query) { return target.unify(query, scope); } }