package org.reasm.m68k.source; import static ca.fragag.testhelpers.HasType.hasType; import static org.hamcrest.Matchers.both; import static org.hamcrest.Matchers.hasProperty; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.startsWith; import static org.junit.Assert.assertThat; import static org.reasm.m68k.source.BlockParserTestsCommon.COMPLETE_BLOCK; import static org.reasm.m68k.source.BlockParserTestsCommon.INCOMPLETE_BLOCK; import java.util.List; import javax.annotation.Nonnull; import org.hamcrest.Matcher; import org.junit.Test; import org.reasm.commons.parseerrors.ElseOrElseIfAfterElseParseError; import org.reasm.source.CompositeSourceNode; import org.reasm.source.SimpleCompositeSourceNode; import org.reasm.source.SourceNode; import ca.fragag.text.Document; /** * Test class for {@link M68KIfBlockParser}. * * @author Francis Gagné */ public class M68KIfBlockParserTest { private static void parseIfBlock(@Nonnull String code, @Nonnull Matcher<Object> blockParseErrorMatcher, int numberOfChildNodes) { SourceNode node = M68KParser.INSTANCE.parse(new Document(code)); assertThat(node.getParseError(), is(nullValue())); List<SourceNode> childNodes = ((CompositeSourceNode) node).getChildNodes(); assertThat(childNodes.size(), is(1)); node = childNodes.get(0); assertThat(node.getParseError(), blockParseErrorMatcher); assertThat(node, hasType(IfBlock.class)); childNodes = ((CompositeSourceNode) node).getChildNodes(); assertThat(childNodes.size(), is(numberOfChildNodes)); for (int i = 0; i < childNodes.size(); i++) { final SourceNode childNode = childNodes.get(i); assertThat(childNode.getParseError(), is(nullValue())); assertThat(childNode, hasType((i & 1) == 0 ? M68KBlockDirectiveLine.class : SimpleCompositeSourceNode.class)); } } /** * Asserts that {@link M68KIfBlockParser} correctly parses a complete <code>IF</code> block that ends with an <code>ENDC</code> * directive. */ @Test public void parseCompleteIfBlockEndc() { parseIfBlock(" IF\n NOP\n ENDC", COMPLETE_BLOCK, 3); } /** * Asserts that {@link M68KIfBlockParser} correctly parses a complete <code>IF</code> block that ends with an <code>ENDIF</code> * directive. */ @Test public void parseCompleteIfBlockEndif() { parseIfBlock(" IF\n NOP\n ENDIF", COMPLETE_BLOCK, 3); } /** * Asserts that {@link M68KIfBlockParser} correctly parses a complete <code>IF</code> block with an <code>ELSE</code> clause. */ @Test public void parseCompleteIfBlockWithElseClause() { parseIfBlock(" IF\n NOP\n ELSE\n RTS\n ENDIF", COMPLETE_BLOCK, 5); } /** * Asserts that {@link M68KIfBlockParser} correctly parses a complete <code>IF</code> block with two <code>ELSE</code> clauses. */ @Test public void parseCompleteIfBlockWithElseClauseAfterElseClause() { final Matcher<Object> blockParseErrorMatcher = both(hasType(ElseOrElseIfAfterElseParseError.class)).and( hasProperty("text", startsWith("ELSE "))); parseIfBlock(" IF\n NOP\n ELSE\n RTS\n ELSE\n RTS\n ENDIF", blockParseErrorMatcher, 7); } /** * Asserts that {@link M68KIfBlockParser} correctly parses a complete <code>IF</code> block with an <code>ELSEIF</code> clause * followed by an <code>ELSE</code> clause. */ @Test public void parseCompleteIfBlockWithElseifAndElseClause() { parseIfBlock(" IF\n NOP\n ELSEIF\n RTE\n ELSE\n RTS\n ENDIF", COMPLETE_BLOCK, 7); } /** * Asserts that {@link M68KIfBlockParser} correctly parses a complete <code>IF</code> block with an <code>ELSEIF</code> clause. */ @Test public void parseCompleteIfBlockWithElseifClause() { parseIfBlock(" IF\n NOP\n ELSEIF\n RTE\n ENDIF", COMPLETE_BLOCK, 5); } /** * Asserts that {@link M68KIfBlockParser} correctly parses a complete <code>IF</code> block with an <code>ELSE</code> clause * followed by an <code>ELSEIF</code> clause. */ @Test public void parseCompleteIfBlockWithElseifClauseAfterElseClause() { final Matcher<Object> blockParseErrorMatcher = both(hasType(ElseOrElseIfAfterElseParseError.class)).and( hasProperty("text", startsWith("ELSEIF "))); parseIfBlock(" IF\n NOP\n ELSE\n RTS\n ELSEIF\n RTE\n ENDIF", blockParseErrorMatcher, 7); } /** * Asserts that {@link M68KIfBlockParser} correctly parses a complete <code>IF</code> block with an <code>ELSE</code> clause * followed by two <code>ELSEIF</code> clauses. */ @Test public void parseCompleteIfBlockWithTwoElseifClausesAfterElseClause() { final Matcher<Object> blockParseErrorMatcher = both(hasType(ElseOrElseIfAfterElseParseError.class)).and( hasProperty("text", startsWith("ELSEIF "))); parseIfBlock(" IF\n NOP\n ELSE\n RTS\n ELSEIF\n RTE\n ELSEIF\n RTE\n ENDIF", blockParseErrorMatcher, 9); } /** * Asserts that {@link M68KIfBlockParser} correctly parses a complete <code>IF</code> block. */ @Test public void parseIfBlockLineWithNoMnemonic() { parseIfBlock(" IF\nfoo:\n ENDIF", COMPLETE_BLOCK, 3); } /** * Asserts that {@link M68KIfBlockParser} correctly parses an incomplete <code>IF</code> block. */ @Test public void parseIncompleteIfBlock() { parseIfBlock(" IF\n NOP", INCOMPLETE_BLOCK, 2); } /** * Asserts that {@link M68KIfBlockParser} correctly parses an incomplete <code>IF</code> block with an <code>ELSE</code> clause. */ @Test public void parseIncompleteIfBlockWithElseClause() { parseIfBlock(" IF\n NOP\n ELSE\n RTS", INCOMPLETE_BLOCK, 4); } }