package com.rox.emu.env;

import com.pholser.junit.quickcheck.Property;
import com.pholser.junit.quickcheck.When;
import com.pholser.junit.quickcheck.generator.InRange;
import com.pholser.junit.quickcheck.runner.JUnitQuickcheck;
import com.rox.emu.InvalidDataTypeException;
import org.junit.Test;
import org.junit.runner.RunWith;
import spock.lang.Specification;

import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertNotNull;
import static org.junit.Assert.*;

@RunWith(JUnitQuickcheck.class)
public class RoxByteTest extends Specification{
    @Test
    public void testEmptyByteCreation(){
        final RoxByte myByte = RoxByte.ZERO;
        assertNotNull(myByte);
        assertEquals(0, myByte.getAsInt());
    }

    @Test
    public void testSignedFromInteger() throws InvalidDataTypeException {
        final RoxByte myByte = RoxByte.signedFrom(1);
        assertNotNull(myByte);
        assertEquals(RoxByte.ByteFormat.SIGNED_TWOS_COMPLIMENT, myByte.getFormat());
        assertEquals(0b00000001, myByte.getRawValue());
    }

    @Test
    public void testLiteralFromInteger() throws InvalidDataTypeException {
        final RoxByte myByte = RoxByte.literalFrom(1);
        assertNotNull(myByte);
        assertEquals(RoxByte.ByteFormat.SIGNED_TWOS_COMPLIMENT, myByte.getFormat());
        assertEquals(0b00000001, myByte.getRawValue());
    }

    @Test
    public void testByteFromRaw() throws InvalidDataTypeException {
        final RoxByte myByte = RoxByte.literalFrom(0b11111111);
        assertNotNull(myByte);
        assertEquals(RoxByte.ByteFormat.SIGNED_TWOS_COMPLIMENT, myByte.getFormat());
        assertEquals(0b11111111, myByte.getRawValue());
    }

    @Property(trials = 30)
    public void testSignedFromWithInvalid(@When(satisfies = "#_ < -128 || #_ > 127") int byteValue){
        try {
            RoxByte.signedFrom(byteValue);
            fail(byteValue + " was expected to be too low to convert to unsigned byte");
        }catch(InvalidDataTypeException e) {
            assertNotNull(e);
        }
    }

    @Property(trials = 10)
    public void testSignedFromWithTooHigh(@InRange(min = "128", max = "300") int byteValue){
        try {
            RoxByte.signedFrom(byteValue);
            fail(byteValue + " was expected to be too high to convert to unsigned byte");
        }catch(InvalidDataTypeException e) {
            assertNotNull(e);
        }
    }

    @Test
    public void testSetBit(){
        final RoxByte myByte = RoxByte.ZERO;

        assertEquals(1, myByte.withBit(0).getAsInt());
        assertEquals(2, myByte.withBit(1).getAsInt());
        assertEquals(4, myByte.withBit(2).getAsInt());
        assertEquals(8, myByte.withBit(3).getAsInt());
        assertEquals(16, myByte.withBit(4).getAsInt());
        assertEquals(32, myByte.withBit(5).getAsInt());
        assertEquals(64, myByte.withBit(6).getAsInt());
        assertEquals(-128, myByte.withBit(7).getAsInt());
    }

    @Test
    public void testWithoutBit(){
        final RoxByte myByte = RoxByte.literalFrom(0b11111111);

        assertEquals(0b11111110, myByte.withoutBit(0).getRawValue());
        assertEquals(0b11111101, myByte.withoutBit(1).getRawValue());
        assertEquals(0b11111011, myByte.withoutBit(2).getRawValue());
        assertEquals(0b11110111, myByte.withoutBit(3).getRawValue());
        assertEquals(0b11101111, myByte.withoutBit(4).getRawValue());
        assertEquals(0b11011111, myByte.withoutBit(5).getRawValue());
        assertEquals(0b10111111, myByte.withoutBit(6).getRawValue());
        assertEquals(0b01111111, myByte.withoutBit(7).getRawValue());
    }

    @Property(trials = 5)
    public void testWithBitInvalidChoice(@When(satisfies = "#_ < 0 || #_ > 7") int bit){
        final RoxByte myByte = RoxByte.ZERO;

        try {
            myByte.withBit(bit);
            fail("There is no bit " + bit + ", this should throw an error");
        }catch(ArrayIndexOutOfBoundsException e){
            assertNotNull(e);
        }
    }

    @Property(trials = 5)
    public void testWithoutBitInvalidChoice(@When(satisfies = "#_ < 0 || #_ > 7") int bit){
        final RoxByte myByte = RoxByte.ZERO;

        try {
            myByte.withoutBit(bit);
            fail("There is no bit " + bit + ", this should throw an error");
        }catch(ArrayIndexOutOfBoundsException e){
            assertNotNull(e);
        }
    }

    @Test
    public void testIsBitSet(){
        final RoxByte loadedByte = RoxByte.signedFrom(-1);
        final RoxByte emptyByte = RoxByte.ZERO;

        for (int i=0; i<8; i++){
            assertTrue(loadedByte.isBitSet(i));
            assertFalse(emptyByte.isBitSet(i));
        }
    }

    @Property(trials = 5)
    public void testIsBitSetInvalidChoice(@When(satisfies = "#_ < 0 || #_ > 7") int bit){
        final RoxByte myByte = RoxByte.ZERO;

        try {
            myByte.isBitSet(bit);
            fail("There is no bit " + bit + ", this should throw an error");
        }catch(ArrayIndexOutOfBoundsException e){
            assertNotNull(e);
        }
    }
}

@@ -4712,32 +4712,609 @@
        %7D%0A    %7D%0A%0A
+    @Property(trials = 10)%0A    public void testEquals(@When(satisfies = %22#_ %3C 255 %7C%7C #_ %3E 0%22) int byteValue)%7B%0A        final RoxByte valA = RoxByte.literalFrom(byteValue);%0A        final RoxByte valB = RoxByte.literalFrom(byteValue);%0A%0A        assertTrue(valA.equals(valB));%0A    %7D%0A%0A    @Property(trials = 10)%0A    public void testHashcode(@When(satisfies = %22#_ %3C 255 %7C%7C #_ %3E 0%22) int byteValue)%7B%0A        final RoxByte valA = RoxByte.literalFrom(byteValue);%0A        final RoxByte valB = RoxByte.literalFrom(byteValue);%0A%0A        assertTrue(valA.hashCode() == valB.hashCode());%0A    %7D%0A%0A
     @Property(tr

test equals and hascode to fix test coverage