package de.renew.engine.searchqueue;

import java.util.NoSuchElementException;

import org.junit.jupiter.api.Test;

import de.renew.engine.searcher.Searchable;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;

/**
 * Test class for the {@link DSQEnumeration}.
 */
public class DSQEnumerationTest {
    private final Searchable _searchable1 = new EmptySearchable();
    private final Searchable _searchable2 = new EmptySearchable();
    private final Searchable _searchable3 = new EmptySearchable();
    private final DSQListNode _node1 = new DSQListNode(_searchable1);
    private final DSQListNode _node2 = new DSQListNode(_searchable2);
    private final DSQListNode _node3 = new DSQListNode(_searchable3);
    {
        // set node1 → node2 → node3
        _node1.setPrevious(null);
        _node1.setNext(_node2);
        _node2.setPrevious(_node1);
        _node2.setNext(_node3);
        _node3.setPrevious(_node2);
        _node3.setNext(null);
    }

    /**
     * Test method for {@link DSQEnumeration#nextElement}.
     */
    @Test
    public void testNextElement() {
        //given
        DSQEnumeration enumeration = new DSQEnumeration(_node1);

        //when/then
        assertEquals(_searchable1, enumeration.nextElement());
        assertEquals(_searchable2, enumeration.nextElement());
        assertEquals(_searchable3, enumeration.nextElement());
        assertFalse(enumeration.hasMoreElements());
    }

    /**
     * Test method for {@link DSQEnumeration#nextElement}. Tests that an instance
     * of a {@link NoSuchElementException} is thrown if the method is called
     * when the enumeration doesn't have more elements.
     */
    @Test
    public void testNextElementThrowsNoSuchElementException() {
        //given
        DSQEnumeration enumeration = new DSQEnumeration(null);

        //when/then
        assertThrows(NoSuchElementException.class, enumeration::nextElement);
    }

    /**
     * Test method for {@link DSQEnumeration#nextElement}. Tests that a loop
     * in the nodes back to the start node is detected and the enumeration doesn't
     * loop.
     */
    @Test
    public void testNextElementWithLoop() {
        //given
        _node3.setNext(_node1); //set node3 → back to node1 to create loop
        DSQEnumeration enumeration = new DSQEnumeration(_node1);

        //when/then
        assertEquals(_searchable1, enumeration.nextElement());
        assertEquals(_searchable2, enumeration.nextElement());
        assertEquals(_searchable3, enumeration.nextElement());
        assertFalse(enumeration.hasMoreElements());
    }
}
