package cpsc2150.MyDeque;

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

public class TestListDeque {

    // Wrapper function to return a ListDeque
    private IDeque<Integer> MakeADeque() {

        return new ListDeque<Integer>();

    }

    // Distinct test case: Enqueue a value when the deque is empty, where only value
    // becomes value being enqueued and length becomes 1
    // Distinct because: Enqueue could only be working for an empty deque
    @Test
    public void testEnqueue_empty_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<4>";

        // Enqueue a value (deque is empty at this point)
        testDeque.enqueue(4);

        // Check that the length of the deque is 1
        assertEquals(testDeque.length(), 1);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: Enqueue a value when the deque already has some values (not almost full), where
    // deque becomes #deque + values being enqueued and length becomes #deque length + 1
    // Distinct because: Enqueue could fail when values already exist if it's accidentally adding to a fixed position
    @Test
    public void testEnqueue_partially_filled_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<";
        // Add expected values to expected string from 1 to 55
        for (int i = 1; i <= 55; i++) {

            // If not the last value to be added, add a comma and space
            if (i != 55) {

                expected += i + ", ";

                // If last value to be added, don't add comma and space
                // Instead, add closing bracket
            } else {

                expected += i + ">";

            }

        }

        // Enqueue values 1 through 54 to the deque
        for (int i = 1; i <= 54; i++) {

            testDeque.enqueue(i);

        }

        // Get length of deque before enqueuing another value
        int originalLength = testDeque.length();

        // Enqueue another value
        testDeque.enqueue(55);

        // Check that the length of the deque is original length + 1
        assertEquals(testDeque.length(), originalLength + 1);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: Enqueue a value when the deque is almost full, where deque becomes #deque + value
    // being enqueued and length of deque becomes length of #deque + 1
    // Distinct because: Enqueue could be mistakenly guarding against filling the deque
    @Test
    public void testEnqueue_almost_full_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<";
        // Add expected values to expected string from 1 to 100
        for (int i = 1; i <= testDeque.MAX_LENGTH; i++) {

            // If not the last value to be added, add a comma and space
            if (i != testDeque.MAX_LENGTH) {

                expected += i + ", ";

                // If last value to be added, don't add comma and space
                // Instead, add closing bracket
            } else {

                expected += i + ">";

            }

        }

        // Enqueue values 1 through 99 to the deque
        for (int i = 1; i < testDeque.MAX_LENGTH; i++) {

            testDeque.enqueue(i);

        }

        // Get length of deque before enqueuing another value
        int originalLength = testDeque.length();

        // Enqueue one more value, so that the deque is now full and
        // has values 1 through 100
        testDeque.enqueue(100);

        // Check that the length of the deque is original length + 1
        assertEquals(testDeque.length(), originalLength + 1);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: Deque when the deque only has one value, where deque becomes
    // empty and length of deque becomes 0
    // Distinct because: Dequeue could only work when the deque has one value
    @Test
    public void testDequeue_empty_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<>";

        // Enqueue a value
        testDeque.enqueue(5);

        // Get length of deque before dequeue
        int originalLength = testDeque.length();

        // Immediately dequeue the value
        int dequeuedValue = testDeque.dequeue();

        // Check that the returned value is the same as the expected value
        assertEquals(dequeuedValue, 5);
        // Check that the length of the deque is original length - 1
        assertEquals(testDeque.length(), originalLength - 1);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: Dequeue when the deque has more than one value (but is
    // not full), leaving all values but the first where deque becomes #deque - value dequeued and
    // length of deque becomes length of #deque - 1
    // Distinct because: Dequeue could be accidentally removing from a position other than 1
    @Test
    public void testDequeue_partially_filled_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<2, 97>";

        // Enqueue some values
        testDeque.enqueue(55);
        testDeque.enqueue(2);
        testDeque.enqueue(97);

        // Get length of deque before dequeue
        int originalLength = testDeque.length();

        // Dequeue from the deque
        int dequeuedValue = testDeque.dequeue();

        // Check that the returned value is the same as the expected value
        assertEquals(dequeuedValue, 55);
        // Check that the length of the deque is original length - 1
        assertEquals(testDeque.length(), originalLength - 1);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: Deque when deque is full, leaving all but the first values and a length of MAX_LENGTH - 1
    // Distinct because: Dequeue could be mistakenly guarding against removing from a full deque
    @Test
    public void testDequeue_full_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<";
        // Add expected values to expected string from 2 to 100
        for (int i = 2; i <= testDeque.MAX_LENGTH; i++) {

            // If not the last value to be added, add a comma and space
            if (i != testDeque.MAX_LENGTH) {

                expected += i + ", ";

                // If last value to be added, don't add comma and space
                // Instead, add closing bracket
            } else {

                expected += i + ">";

            }

        }

        // Enqueue values 1 through 100 to the deque
        for (int i = 1; i <= testDeque.MAX_LENGTH; i++) {

            testDeque.enqueue(i);

        }

        // Get length of deque before deque
        int originalLength = testDeque.length();

        // Dequeue from the deque
        int dequeuedValue = testDeque.dequeue();

        // Check that the returned value is the same as the expected value
        assertEquals(dequeuedValue, 1);
        // Check that the length of the deque is original length - 1
        assertEquals(testDeque.length(), originalLength - 1);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: Inject when deque is empty, where only value
    // becomes value being injected and length becomes 1
    // Distinct because: Inject could only be working when deque is empty
    @Test
    public void testInject_empty_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<11>";

        // Get length of deque before injecting another value
        int originalLength = testDeque.length();

        // Inject a value
        testDeque.inject(11);

        // Check that the length of the deque is original length + 1
        assertEquals(testDeque.length(), originalLength + 1);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: Inject a value when the deque already has some values (not almost full), where
    // deque becomes #deque + values being injected and length becomes #deque length + 1
    // Distinct because: Inject could be accidentally adding to a position other than 1
    @Test
    public void testInject_partially_filled_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<";
        // Add expected values to expected string from 1 to 55
        for (int i = 1; i <= 55; i++) {

            // If not the last value to be added, add a comma and space
            if (i != 55) {

                expected += i + ", ";

                // If last value to be added, don't add comma and space
                // Instead, add closing bracket
            } else {

                expected += i + ">";

            }

        }

        // Inject values 2 through 55 to the deque
        for (int i = 55; i >= 2; i--) {

            testDeque.inject(i);

        }

        // Get length of deque before injecting another value
        int originalLength = testDeque.length();

        // Enqueue another value
        testDeque.inject(1);

        // Check that the length of the deque is original length + 1
        assertEquals(testDeque.length(), originalLength + 1);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: Inject a value when the deque is almost full, where deque becomes #deque + value
    // being injected and length of deque becomes length of #deque + 1
    // Distinct because: Inject could be mistakenly guarding against adding if the deque would be full
    @Test
    public void testInject_almost_full_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<";
        // Add expected values to expected string from 1 to 100
        for (int i = 1; i <= testDeque.MAX_LENGTH; i++) {

            // If not the last value to be added, add a comma and space
            if (i != testDeque.MAX_LENGTH) {

                expected += i + ", ";

                // If last value to be added, don't add comma and space
                // Instead, add closing bracket
            } else {

                expected += i + ">";

            }

        }

        // Inject values 2 through 100 to the deque
        for (int i = testDeque.MAX_LENGTH; i >= 2; i--) {

            testDeque.inject(i);

        }

        // Get length of deque before injecting another value
        int originalLength = testDeque.length();

        // Inject one more value, so that the deque is now full and
        // has values 1 through 100
        testDeque.inject(1);

        // Check that the length of the deque is original length + 1
        assertEquals(testDeque.length(), originalLength + 1);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: removeLast when the deque only has one value, where deque becomes
    // empty and length of deque becomes 0
    // Distinct because: removeLast could only be working if the deque is empty
    @Test
    public void testRemoveLast_empty_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<>";

        // Enqueue a value
        testDeque.enqueue(5);

        // Get length of deque before removing last
        int originalLength = testDeque.length();

        // Immediately remove the last value
        int removedValue = testDeque.removeLast();

        // Check that the returned value is the same as the expected value
        assertEquals(removedValue, 5);
        // Check that the length of the deque is original length - 1
        assertEquals(testDeque.length(), originalLength - 1);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: removeLast when the deque has more than one value (but is
    // not full), leaving all values but the first where deque becomes #deque - value removed and
    // length of deque becomes length of #deque - 1
    // Distinct because: removeLast could be accidentally removing from a set position instead of the end
    @Test
    public void testRemoveLast_partially_filled_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<55, 2>";

        // Enqueue some values
        testDeque.enqueue(55);
        testDeque.enqueue(2);
        testDeque.enqueue(97);

        // Get length of deque before removing last
        int originalLength = testDeque.length();

        // Remove the last value
        int removedValue = testDeque.removeLast();

        // Check that the returned value is the same as the expected value
        assertEquals(removedValue, 97);
        // Check that the length of the deque is original length - 1
        assertEquals(testDeque.length(), originalLength - 1);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: removeLast when deque is full, leaving all but the first values and a
    // length of MAX_LENGTH - 1
    // Distinct because: removeLast could be mistakenly guarding against removing from a full deque
    @Test
    public void testRemoveLast_full_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<";
        // Add expected values to expected string from 1 to 99
        for (int i = 1; i <= (testDeque.MAX_LENGTH - 1); i++) {

            // If not the last value to be added, add a comma and space
            if (i != (testDeque.MAX_LENGTH - 1)) {

                expected += i + ", ";

                // If last value to be added, don't add comma and space
                // Instead, add closing bracket
            } else {

                expected += i + ">";

            }

        }

        // Enqueue values 1 through 100 to the deque
        for (int i = 1; i <= testDeque.MAX_LENGTH; i++) {

            testDeque.enqueue(i);

        }

        // Get length of deque before removingLast
        int originalLength = testDeque.length();

        // Remove last from deque
        int removedValue = testDeque.removeLast();

        // Check that the returned value is the same as the expected value
        assertEquals(removedValue, 100);
        // Check that the length of the deque is original length - 1
        assertEquals(testDeque.length(), originalLength - 1);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: Clear an empty deque, where length becomes 0
    // Distinct because: Clear should remove at least one value
    @Test
    public void testClear_empty_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<>";

        // Clear the deque
        testDeque.clear();

        // Check that the length of the deque is 0
        assertEquals(testDeque.length(), 0);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: Clear a deque that has more than one value (but is
    // not full), where the length becomes 0
    // Distinct because: Clear may be only working when deque is empty
    @Test
    public void testClear_partially_filled_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<>";

        // Enqueue some values
        testDeque.enqueue(1);
        testDeque.enqueue(2);
        testDeque.enqueue(3);

        // Clear the deque
        testDeque.clear();

        // Check that the length of the deque is 0
        assertEquals(testDeque.length(), 0);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: Clear a deque that is full, where the length becomes 0
    // Distinct because: Clear could be mistakenly guarding against clearing a full deque
    @Test
    public void testClear_full_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<>";

        // Enqueue values 1 through 100 to the deque
        for (int i = 1; i <= testDeque.MAX_LENGTH; i++) {

            testDeque.enqueue(i);

        }

        // Clear the deque
        testDeque.clear();

        // Check that the length of the deque is 0
        assertEquals(testDeque.length(), 0);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: Peek from a deque that has only one value, where deque remains
    // unmodified and length remains the same as before
    // Distinct because: Peek could be getting a value other than position 1
    @Test
    public void testPeek_single_value_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<1>";

        // Enqueue a single value
        testDeque.enqueue(1);

        // Get length of deque before peeking
        int originalLength = testDeque.length();

        // Peek from the deque
        int peekedValue = testDeque.peek();

        // Check that the returned value is the same as the expected value
        assertEquals(peekedValue, 1);
        // Check that the length of the deque is original length
        assertEquals(testDeque.length(), originalLength);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: Peek from a deque that has more than one value (but is
    // not full), where deque remains unmodified and length remains the same as before
    // Distinct because: Peek could be accidentally removing a value
    @Test
    public void testPeek_partially_filled_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<1, 2, 3, 4, 5, 6, 7, 8, 9, 10>";

        // Enqueue values 1 through 10
        for (int i = 1; i <= 10; i++) {

            testDeque.enqueue(i);

        }

        // Get length of deque before peeking
        int originalLength = testDeque.length();

        // Peek from the deque
        int peekedValue = testDeque.peek();

        // Check that the returned value is the same as the expected value
        assertEquals(peekedValue, 1);
        // Check that the length of the deque is original length
        assertEquals(testDeque.length(), originalLength);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: Peek from a deque that is full, where deque remains
    // unmodified and length remains the same as before
    // Distinct because: Peek could be accidentally guarding against peeking from a full deque
    @Test
    public void testPeek_full_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<";
        // Add expected values to expected string from 1 to 100
        for (int i = 1; i <= testDeque.MAX_LENGTH; i++) {

            // If not the last value to be added, add a comma and space
            if (i != testDeque.MAX_LENGTH) {

                expected += i + ", ";

                // If last value to be added, don't add comma and space
                // Instead, add closing bracket
            } else {

                expected += i + ">";

            }

        }

        // Enqueue values 1 through 100 to the deque
        for (int i = 1; i <= testDeque.MAX_LENGTH; i++) {

            testDeque.enqueue(i);

        }

        // Get length of deque before peeking
        int originalLength = testDeque.length();

        // Peek from the deque
        int peekedValue = testDeque.peek();

        // Check that the returned value is the same as the expected value
        assertEquals(peekedValue, 1);
        // Check that the length of the deque is original length
        assertEquals(testDeque.length(), originalLength);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: endOfDeque from a deque that has only one value, where deque remains
    // unmodified and length remains the same as before
    // Distinct because: endOfDeque could be accidentally removing a value
    @Test
    public void testEndOfDeque_single_value_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<1>";

        // Enqueue a single value
        testDeque.enqueue(1);

        // Get length of deque before getting end of deque
        int originalLength = testDeque.length();

        // Get end value from deque
        int endValue = testDeque.endOfDeque();

        // Check that the returned value is the same as the expected value
        assertEquals(endValue, 1);
        // Check that the length of the deque is original length
        assertEquals(testDeque.length(), originalLength);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: endOfDeque from a deque that has more than one value (but is
    // not full), where deque remains unmodified and length remains the same as before
    // Distinct because: endOfDeque could be accidentally getting a value other than the last
    @Test
    public void testEndOfDeque_partially_filled_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<1, 2, 3, 4, 5, 6, 7, 8, 9, 10>";

        // Enqueue values 1 through 10
        for (int i = 1; i <= 10; i++) {

            testDeque.enqueue(i);

        }

        // Get length of deque before getting end of deque
        int originalLength = testDeque.length();

        // Get end value from deque
        int endValue = testDeque.endOfDeque();

        // Check that the returned value is the same as the expected value
        assertEquals(endValue, 10);
        // Check that the length of the deque is original length
        assertEquals(testDeque.length(), originalLength);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: endOfDeque from a deque that is full, where deque remains
    // unmodified and length remains the same as before
    // Distinct because: endOfDeque could be accidentally guarding against getting a value from a full deque
    @Test
    public void testEndOfDeque_full_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<";
        // Add expected values to expected string from 1 to 100
        for (int i = 1; i <= testDeque.MAX_LENGTH; i++) {

            // If not the last value to be added, add a comma and space
            if (i != testDeque.MAX_LENGTH) {

                expected += i + ", ";

                // If last value to be added, don't add comma and space
                // Instead, add closing bracket
            } else {

                expected += i + ">";

            }

        }

        // Enqueue values 1 through 100 to the deque
        for (int i = 1; i <= testDeque.MAX_LENGTH; i++) {

            testDeque.enqueue(i);

        }

        // Get length of deque before getting end of deque
        int originalLength = testDeque.length();

        // Get end value from deque
        int endValue = testDeque.endOfDeque();

        // Check that the returned value is the same as the expected value
        assertEquals(endValue, 100);
        // Check that the length of the deque is original length
        assertEquals(testDeque.length(), originalLength);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: Insert a value at position 1 when the deque is empty, where only value
    // becomes value being insert and length becomes 1
    // Distinct because: Insert could only be working for position 1
    @Test
    public void testInsert_empty_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<4>";

        // Insert a value (deque is empty at this point)
        testDeque.insert(4, 1);

        // Check that the length of the deque is 1
        assertEquals(testDeque.length(), 1);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: Insert a value when the deque already has some values (not almost full), where
    // deque becomes #deque + values being inserted and length becomes #deque length + 1
    // Distinct because: Insert could be adding values at the wrong indexes
    @Test
    public void testInsert_partially_filled_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<";
        // Add expected values to expected string from 1 to 70
        for (int i = 1; i <= 70; i++) {

            // If not the last value to be added, add a comma and space
            if (i != 70) {

                expected += i + ", ";

                // If last value to be added, don't add comma and space
                // Instead, add closing bracket
            } else {

                expected += i + ">";

            }

        }

        // Enqueue values 1 through 54 to the deque
        for (int i = 1; i <= 54; i++) {

            testDeque.enqueue(i);

        }
        // Enqueue values 56 through 70 to the deque
        for (int i = 56; i <= 70; i++) {

            testDeque.enqueue(i);

        }

        // Get length of deque before inserting another value
        int originalLength = testDeque.length();

        // Insert a value at position 55
        testDeque.insert(55, 55);

        // Check that the length of the deque is original length + 1
        assertEquals(testDeque.length(), originalLength + 1);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: Insert a value when the deque is almost full, where deque becomes #deque + value
    // being enqueued and length of deque becomes length of #deque + 1
    // Distinct because: Insert could be mistakenly guarding against adding to a full queue
    @Test
    public void testInsert_almost_full_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<";
        // Add expected values to expected string from 1 to 100
        for (int i = 1; i <= testDeque.MAX_LENGTH; i++) {

            // If not the last value to be added, add a comma and space
            if (i != testDeque.MAX_LENGTH) {

                expected += i + ", ";

                // If last value to be added, don't add comma and space
                // Instead, add closing bracket
            } else {

                expected += i + ">";

            }

        }

        // Enqueue values 1 through 54 to the deque
        for (int i = 1; i <= 54; i++) {

            testDeque.enqueue(i);

        }
        // Enqueue values 56 through 100 to the deque
        for (int i = 56; i <= 100; i++) {

            testDeque.enqueue(i);

        }

        // Get length of deque before inserting another value
        int originalLength = testDeque.length();

        // Insert a value at position 55
        testDeque.insert(55, 55);

        // Check that the length of the deque is original length + 1
        assertEquals(testDeque.length(), originalLength + 1);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: Remove a value at position 1 when the deque has only one value, where deque becomes
    // empty and length becomes 0
    // Distinct because: Remove could only work when the deque has one value
    @Test
    public void testRemove_single_value_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<>";

        // Enqueue a value
        testDeque.enqueue(44);

        // Remove value at position 1
        int removedValue = testDeque.remove(1);

        // Check that the returned value is the same as the expected value
        assertEquals(removedValue, 44);
        // Check that the length of the deque is 0
        assertEquals(testDeque.length(), 0);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: Remove a value when the deque already has some values (not almost full), where
    // deque becomes #deque - value being removed and length becomes #deque length - 1
    // Distinct because: Remove could be removing from the wrong index
    @Test
    public void testRemove_partially_filled_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<";
        // Add expected values to expected string from 1 to 70
        for (int i = 1; i <= 70; i++) {

            // If i is 50, skip adding to deque
            if (i == 50) {

                continue;

            }

            // If not the last value to be added, add a comma and space
            if (i != 70) {

                expected += i + ", ";

                // If last value to be added, don't add comma and space
                // Instead, add closing bracket
            } else {

                expected += i + ">";

            }

        }

        // Enqueue values 1 through 70 to the deque
        for (int i = 1; i <= 70; i++) {

            testDeque.enqueue(i);

        }

        // Get length of deque before removing a value
        int originalLength = testDeque.length();

        // Remove the value at position 50
        int removedValue = testDeque.remove(50);

        // Check that the returned value is the same as the expected value
        assertEquals(removedValue, 50);
        // Check that the length of the deque is original length - 1
        assertEquals(testDeque.length(), originalLength - 1);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: Remove a value when the deque is full, where deque becomes #deque - value
    // being removed and length of deque becomes length of #deque - 1
    // Distinct because: Remove could be mistakenly guarding against removing from a full deque
    @Test
    public void testRemove_full_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<";
        // Add expected values to expected string from 1 to 100
        for (int i = 1; i <= testDeque.MAX_LENGTH; i++) {

            // If i is 50, skip adding to deque
            if (i == 50) {

                continue;

            }

            // If not the last value to be added, add a comma and space
            if (i != testDeque.MAX_LENGTH) {

                expected += i + ", ";

                // If last value to be added, don't add comma and space
                // Instead, add closing bracket
            } else {

                expected += i + ">";

            }

        }

        // Enqueue values 1 through 100 to the deque
        for (int i = 1; i <= testDeque.MAX_LENGTH; i++) {

            testDeque.enqueue(i);

        }

        // Get length of deque before inserting another value
        int originalLength = testDeque.length();

        // Remove the value at position 50
        int removedValue = testDeque.remove(50);

        // Check that the returned value is the same as the expected value
        assertEquals(removedValue, 50);
        // Check that the length of the deque is original length - 1
        assertEquals(testDeque.length(), originalLength - 1);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: Get value from a deque that has only one value, where deque remains
    // unmodified and length remains the same as before
    // Distinct because: Get could only be working for position 1
    @Test
    public void testGet_single_value_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<1>";

        // Enqueue a single value
        testDeque.enqueue(1);

        // Get length of deque before peeking
        int originalLength = testDeque.length();

        // Get value from the deque at position 1
        int value = testDeque.get(1);

        // Check that the returned value is the same as the expected value
        assertEquals(value, 1);
        // Check that the length of the deque is original length
        assertEquals(testDeque.length(), originalLength);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: Get value from a deque that has more than one value (but is
    // not full), where deque remains unmodified and length remains the same as before
    // Distinct because: Get could be getting values at the wrong index
    @Test
    public void testGet_partially_filled_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<1, 2, 3, 4, 5, 6, 7, 8, 9, 10>";

        // Enqueue values 1 through 10
        for (int i = 1; i <= 10; i++) {

            testDeque.enqueue(i);

        }

        // Get length of deque before peeking
        int originalLength = testDeque.length();

        // Get from the deque at position 5
        int value = testDeque.get(5);

        // Check that the returned value is the same as the expected value
        assertEquals(value, 5);
        // Check that the length of the deque is original length
        assertEquals(testDeque.length(), originalLength);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

    // Distinct test case: Get value from a deque that is full, where deque remains
    // unmodified and length remains the same as before
    // Distinct because: Get could be mistakenly guarding against getting a value from a full deque
    @Test
    public void testGet_full_deque() {

        // Create a deque for testing
        IDeque<Integer> testDeque = MakeADeque();

        // Created string of expected output after operations
        String expected = "<";
        // Add expected values to expected string from 1 to 100
        for (int i = 1; i <= testDeque.MAX_LENGTH; i++) {

            // If not the last value to be added, add a comma and space
            if (i != testDeque.MAX_LENGTH) {

                expected += i + ", ";

                // If last value to be added, don't add comma and space
                // Instead, add closing bracket
            } else {

                expected += i + ">";

            }

        }

        // Enqueue values 1 through 100 to the deque
        for (int i = 1; i <= testDeque.MAX_LENGTH; i++) {

            testDeque.enqueue(i);

        }

        // Get length of deque before peeking
        int originalLength = testDeque.length();

        // Get from the deque at position 100
        int value = testDeque.get(100);

        // Check that the returned value is the same as the expected value
        assertEquals(value, 100);
        // Check that the length of the deque is original length
        assertEquals(testDeque.length(), originalLength);
        // Check that deque output is equal to expected output
        assertEquals(testDeque.toString(), expected);

    }

}