package ua.yandex.shad.tries;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static ua.yandex.shad.tries.RWayTrie.Node;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;

import org.mockito.runners.MockitoJUnitRunner;
import ua.yandex.shad.collections.Iterables;

@RunWith(MockitoJUnitRunner.class)
public class RWayTrieTest {

    @Mock private Tuple oneMock;
    @Mock private Tuple appleMock;
    @Mock private Tuple oneDriveMock;
    @Mock private Tuple oneAppleMock;

    private final RWayTrie trie = new RWayTrie();
    private final Node root = trie.getRoot();

    @Before
    public void setup() {
        when(oneMock.getTerm()).thenReturn("one");
        when(oneMock.getWeight()).thenReturn(3);
        when(appleMock.getTerm()).thenReturn("apple");
        when(appleMock.getWeight()).thenReturn(5);
        when(oneDriveMock.getTerm()).thenReturn("onedrive");
        when(oneDriveMock.getWeight()).thenReturn(8);
        when(oneAppleMock.getTerm()).thenReturn("oneapple");
        when(oneAppleMock.getWeight()).thenReturn(8);

        root.setNext('o', new Node());
        get("o").setNext('n', new Node());
        get("on").setNext('e', new Node());
        get("one").setValue(3);
        get("one").setNext('a', new Node());
        get("onea").setNext('p', new Node());
        get("oneap").setNext('p', new Node());
        get("oneapp").setNext('l', new Node());
        get("oneappl").setNext('e', new Node());
        get("oneapple").setValue(5);
        trie.setSize(2);
    }

    @Test
    public void testAdd_result() {
        int expectedValue = 5;

        trie.add(appleMock);
        int actualValue = get("apple").getValue();

        assertEquals(expectedValue, actualValue);
    }

    @Test
    public void testContains_hitWord_positiveResult() {
        String word = "one";

        assertTrue(trie.contains(word));
    }

    @Test
    public void testContains_missWord_negativeResult() {
        String word = "two";

        assertFalse(trie.contains(word));
    }

    @Test
    public void testDelete_hitWord_positiveResult() {
        String word = "oneapple";

        assertTrue(trie.delete(word));
    }

    @Test
    public void testDelete_missWord_negativeResult() {
        String word = "oneapp";

        assertFalse(trie.delete(word));
    }

    @Test
    public void testDelete_hitWord_deletedRedundantNodes() {
        String word = "oneapple";

        trie.delete(word);

        assertNull(get("onea"));
    }

    @Test
    public void testDelete_hitWord_nodesDoNotChanged() {
        String word = "one";

        trie.delete(word);

        assertNotNull(get("oneapple"));
    }

    @Test
    public void testDelete_emptyString_nodesDoNotChanged() {
        String word = "";

        trie.delete(word);

        assertNotNull(get("oneapple"));
    }

    @Test
    public void testWords_result() {
        String expectedResult = "one oneapple";

        String actualResult = new Iterables<String>().toString(trie.words());

        assertEquals(expectedResult, actualResult);
    }

    @Test
    public void testWordsWithPrefix_hitsSeveralWords_result() {
        String pref = "one";
        String expectedResult = "one oneapple";

        String actualResult = new Iterables<String>().toString(trie.wordsWithPrefix(pref));

        assertEquals(expectedResult, actualResult);
    }

    @Test
    public void testWordsWithPrefix_hitsOneWord_result() {
        String pref = "oneapp";
        String expectedResult = "oneapple";

        String actualResult = new Iterables<String>().toString(trie.wordsWithPrefix(pref));

        assertEquals(expectedResult, actualResult);
    }

    @Test
    public void testWordsWithPrefix_doNotHitAnyWord_negativeResultIteratorHasNext() {
        String pref = "two";

        assertFalse(trie.wordsWithPrefix(pref).iterator().hasNext());
    }

    @Test
    public void testSize_result() {
        int expectedSize = 2;

        int actualSize = trie.size();

        assertEquals(expectedSize, actualSize);
    }

    private Node get(String key) {
        Node current = root;
        for (char c : key.toCharArray()) {
            if (current == null) {
                break;
            }
            current = current.getNext(c);
        }
        return current;
    }
}
@@ -1190,28 +1190,89 @@
 .set
-Next('n', new Node()
+Value(1);%0A        get(%22o%22).setNext('n', new Node());%0A        get(%22on%22).setValue(2
 );%0A 
@@ -1639,17 +1639,17 @@
 setSize(
-2
+4
 );%0A    %7D
@@ -1857,32 +1857,252 @@
 lValue);%0A    %7D%0A%0A
+    @Test%0A    public void testAdd_existingWord_sizeDoNotChanged() %7B%0A        int expectedSize = 4;%0A%0A        trie.add(oneMock);%0A        int actualSize = trie.size();%0A%0A        assertEquals(expectedSize, actualSize);%0A    %7D%0A%0A
     @Test%0A    pu
@@ -3256,32 +3256,37 @@
 pectedResult = %22
+o on 
 one oneapple%22;%0A%0A
@@ -4301,17 +4301,17 @@
 dSize = 
-2
+4
 ;%0A%0A     

Modify tests for delete to test clear.