package test.mockobjects;

import com.mockobjects.ExpectationValue;
import com.mockobjects.MockObject;
import com.mockobjects.util.TestCaseMo;
import junit.framework.AssertionFailedError;
import junit.framework.Test;
import junit.framework.TestSuite;

public class TestVerifier extends TestCaseMo {
    private static final Class THIS = TestVerifier.class;

    class OneVerifiable extends MockObject {
        private ExpectationValue myValue = new ExpectationValue("should fail");
        private int unusedField;

        public OneVerifiable() {
            myValue.setFailOnVerify();
            myValue.setExpected("good");
        }

        public void setValue(String aValue) {
            myValue.setActual(aValue);
        }
    }

    class InheritVerifiable extends OneVerifiable {
    }

    class LoopingVerifiable extends MockObject {
        LoopingVerifiable myRef = this;
        boolean inVerify = false;

        LoopingVerifiable() {
            super();
        }

        public void setRef(LoopingVerifiable aRef) {
            myRef = aRef;
        }

        public void verify() {
            assertTrue("Looping verification detected", !inVerify);
            inVerify = true;
            super.verify();
            inVerify = false;
        }
    }

    public TestVerifier(String name) {
        super(name);
    }


    public static void main(String[] args) {
        start(new String[]{THIS.getName()});
    }


    public static Test suite() {
        return new TestSuite(THIS);
    }


    public void testInheritVerifiableFails() {
        InheritVerifiable inheritVerifiable = new InheritVerifiable();
        inheritVerifiable.setValue("bad");

        boolean hasThrownException = false;
        try {
            inheritVerifiable.verify();
        } catch (AssertionFailedError ex) {
            hasThrownException = true;
        }
        assertTrue("Should have thrown exception", hasThrownException);
    }


    public void testInheritVerifiablePasses() {
        InheritVerifiable inheritVerifiable = new InheritVerifiable();
        inheritVerifiable.setValue("good");

        inheritVerifiable.verify();
    }


    public void testNoVerifiables() {
        class NoVerifiables extends MockObject {
        }

        new NoVerifiables().verify();
    }


    public void testOneVerifiableFails() {
        OneVerifiable oneVerifiable = new OneVerifiable();
        oneVerifiable.setValue("bad");

        boolean hasThrownException = false;
        try {
            oneVerifiable.verify();
        } catch (AssertionFailedError ex) {
            hasThrownException = true;
        }
        assertTrue("Should have thrown exception", hasThrownException);
    }


    public void testOneVerifiablePasses() {
        OneVerifiable oneVerifiable = new OneVerifiable();
        oneVerifiable.setValue("good");

        oneVerifiable.verify();
    }

    public void testNoLoopVerifySingleLevel() {
        new LoopingVerifiable().verify();
    }

    public void testNoLoopVerifyMultiLevel() {
        LoopingVerifiable a = new LoopingVerifiable();
        LoopingVerifiable b = new LoopingVerifiable();

        a.setRef(b);
        b.setRef(a);
        a.verify();
    }
}
