package editor.wordcount;

import static org.junit.Assert.*;

import java.util.ArrayList;

import org.junit.Test;

abstract public class WordCounterTest {
	abstract public WordCounter create();
	
	WordCounter wc = create();
	ArrayList<WordCounterEntry> targets = new ArrayList<WordCounterEntry>();
	
	public void checkBump(String word) {
		WordCounter old = wc.makeCopy();
		wc.bump(word);
		assertEquals(old.get(word) + 1, wc.get(word));
		assertTrue(wc.isConsistent());
	}
	
	public void checkDock(String word) {
		WordCounter old = wc.makeCopy();
		wc.dock(word);
		assertEquals(Math.max(0, old.get(word) - 1), wc.get(word));
		assertTrue(wc.isConsistent());
	}
	
	public void checkIterator() {
		for (WordCounterEntry entry: wc) {
			assertTrue(targets.contains(entry));
		}
	}
	
	@Test
	public void test1() {
		checkBump("hello");
		checkBump("hello");
		checkBump("hello");
		checkDock("hello");
		checkBump("goodbye");
		
		targets.add(new WordCounterEntry("hello", 2));
		targets.add(new WordCounterEntry("goodbye", 1));
		checkIterator();
	}
	
	@Test
	public void test2() {
		test1();
		checkDock("goodbye");
		checkDock("goodbye");
		
		checkDock("bye");
	}
	
	@Test
	public void test3() {
		for (char c = 'A'; c <= 'z'; c++) {
			checkBump(Character.toString(c));
			targets.add(new WordCounterEntry(Character.toString(c), 1));
		}
		
		checkIterator();
	}
	
	@Test
	public void test4() {
		test3();
		for (WordCounterEntry target: targets) {
			checkDock(target.getWord());
		}
	}
	
	@Test
	public void test5() {
		test3();
		checkDock("A");
		checkDock("a");
		checkDock("z");
		for (int i = 0; i < 100; i++) {
			checkBump(Integer.toString(i));
		}
	}
	
	@Test
	public void test6() {
		for (char c = 'z'; c >= 'A'; c--) {
			checkBump(Character.toString(c));
			targets.add(new WordCounterEntry(Character.toString(c), 1));
		}
		
		checkIterator();
	}
}
