package recognizer;

import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;

import tokenizer.Token;
import tokenizer.TokenType;
import tokenizer.Tokenizer;

/**
 * @author David Matuszek
 * @version Jan 30, 2004.
 */
public class RecognizerTest {

    Recognizer r0, r1, r2, r3, r4, r5, r6, r7, r8, r9;

    @Test
    public void testExpression() {
        r1 = new Recognizer("250");
        assertTrue(r1.expression());

        r2 = new Recognizer("hello");
        assertTrue(r2.expression());
        
        r3 = new Recognizer("(xyz + 3)");
        assertTrue(r3.expression());

        r4 = new Recognizer("12 * 5 - 3 * 4 / 6 + 8");
        assertTrue(r4.expression());
        
        r5 = new Recognizer("12 * ((5 - 3) * 4) / 6 + (8)");
        assertTrue(r5.expression());

        r0 = new Recognizer("");
        assertFalse(r0.expression());

        r8 = new Recognizer("#");
        assertFalse(r8.expression());
        
        r9 = new Recognizer("-25");
        assertTrue(r9.expression());    
        
        r9 = new Recognizer("(-5+10)");
        assertTrue(r9.expression());      
    }
    
    @Test(expected=RuntimeException.class)
    public void testBadExpression1() {
        r6 = new Recognizer("17 +");
        r6.expression();
    }
    
    @Test(expected=RuntimeException.class)
    public void testBadExpression2() {
        r7 = new Recognizer("22 *");
        r7.expression();
    }

    @Test
    public void testTerm() {
        r0 = new Recognizer("");
        assertFalse(r0.term());

        r1 = new Recognizer("250");
        assertTrue(r1.term());

        r2 = new Recognizer("hello");
        assertTrue(r2.term());

        r3 = new Recognizer("(xyz + 3)");
        assertTrue(r3.term());
        matchEverythingThatsLeft(r3, "");

        r4 = new Recognizer("12 * 5 - 3 * 4 / 6 + 8");
        assertTrue(r4.term());                                           // 12 * 5
        assertEquals(new Token(TokenType.OPERATOR, "-"), nextToken(r4)); // -
        assertTrue(r4.term());                                           // 3 * 4 / 6
        matchEverythingThatsLeft(r4, "+ 8");

        r5 = new Recognizer("12 * ((5 - 3) * 4) / 6 + (8)");
        assertTrue(r5.term());                                           // 12 * ((5 - 3) * 4) / 6
        assertEquals(new Token(TokenType.OPERATOR, "+"), nextToken(r5)); // +
        assertTrue(r5.term());                                           // (8)
        matchEverythingThatsLeft(r5, "");
    }

    @Test
    public void testFactor() {
        r0 = new Recognizer("");
        assertFalse(r0.factor());
        
        r1 = new Recognizer("250");
        assertTrue(r1.factor());
        
        r2 = new Recognizer("hello");
        assertTrue(r2.factor());
        
        r3 = new Recognizer("(xyz + 3)");
        assertTrue(r3.factor());
        
        r4 = new Recognizer("12 * 5 - 3 * 4 / 6 + 8");
        assertTrue(r4.factor());
        matchEverythingThatsLeft(r4, "* 5 - 3 * 4 / 6 + 8");
        
        r5 = new Recognizer("12 * ((5 - 3) * 4) / 6 + (8)");
        assertTrue(r5.factor());
        matchEverythingThatsLeft(r5, "* ((5");
        
        r6 = new Recognizer("17 +");
        assertTrue(r6.factor());
        matchEverythingThatsLeft(r6, "+");
        
        r7 = new Recognizer("22 *");
        assertTrue(r7.factor());
        matchEverythingThatsLeft(r7, "*");

        r8 = new Recognizer("#");
        assertFalse(r8.factor());
        matchEverythingThatsLeft(r8, "#");
    }

    @Test
    public void testAdd_operator() {
        Recognizer r = new Recognizer("+ - $");
        assertTrue(r.addOperator());
        assertTrue(r.addOperator());
        assertFalse(r.addOperator());
        matchEverythingThatsLeft(r, "$");
    }

    @Test
    public void testMultiply_operator() {
        Recognizer r = new Recognizer("* / $");
        assertTrue(r.multiplyOperator());
        assertTrue(r.multiplyOperator());
        assertFalse(r.multiplyOperator());
        matchEverythingThatsLeft(r, "$");
    }

//  ----- "Helper" methods

    private void matchEverythingThatsLeft(Recognizer recognizer, String rest) {
        Tokenizer actual = recognizer.tokenizer;
        Tokenizer expected = new Tokenizer(rest);
        while (expected.hasNext()) {
            Token actualToken = actual.next();
            Token expectedToken = expected.next();
            assertEquals(expectedToken, actualToken);
        }
    }

    private Token nextToken(Recognizer r) {
        return r.tokenizer.next();
    }
}

