TDDBC仙台で作成したコード

TDDBC仙台で我々JavaのBチームが作成したコードです。
まだ未完成ですし、誤字脱字などもありますが、あえてそのまま晒します。
個人的には、近いうちに最後まで実装したいと思います。

  • LRUCacheTest
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;

import java.util.Arrays;
import java.util.Collections;

import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;

public class LRUCacheTest {

    private LRUCache lru;

    @Before
    public void 前準備() {
    }

    @Test
    public void なにも足さずにgetするとnullガかえる() {
        lru = new LRUCache();
        assertThat(lru.get("_"), nullValue());
        assertThat(lru.get("a"), nullValue());
    }

    @Test
    public void 文字列をputしてgetすると値が取得できる() {
        lru = new LRUCache();
        lru.put("a", "dataA");
        assertThat(lru.get("a"), is("dataA"));
    }

    @Test
    public void 文字列_をputしてgetすると値が取得できる() {
        lru = new LRUCache();
        lru.put("_", "data_");
        assertThat(lru.get("_"), is("data_"));
    }

    @Test
    public void 文字列aをputしてbでgetするとmullが取得できる() {
        lru = new LRUCache();
        lru.put("a", "dataA");
        assertThat(lru.get("b"), nullValue());
    }

    @Test
    public void 何も要素を足さずにsizeを取得すると0が返される() {
        lru = new LRUCache();
        assertThat(lru.size(), is(0));
    }

    @Test
    public void まず1つ要素を足すとsizeに1が返る() {
        lru = new LRUCache();
        lru.put("a", "dataA");
        assertThat(lru.size(), is(1));
    }

    @Test
    public void 要素を3つ足して最初のを取得するとnullが返る() {
        lru = new LRUCache();
        lru.put("a", "dataA");
        lru.put("b", "dataB");
        lru.put("c", "dataC");
        assertThat(lru.get("a"), nullValue());
    }

    @Test
    public void デフォルトコンストラクタで生成するとキャッシュサイズ2が返る() {
        lru = new LRUCache();
        assertThat(lru.cacheSize(), is(2));
    }

    @Test
    public void コンストラクタ指定したサイズ3がキャッシュサイズが返る() {
        lru = new LRUCache(3);
        assertThat(lru.cacheSize(), is(3));
    }

    @Test
    public void 要素を3つ足しても要素数がキャッシュサイズを越えない() {
        lru = new LRUCache();
        lru.put("a", "dataA");
        lru.put("b", "dataB");
        lru.put("c", "dataC");
        assertThat(lru.size(), is(2));
    }

    // 防御的プログラミング
    @Test(expected = IllegalArgumentException.class)
    public void キャッシュサイズに0を渡すと例外が発生する() {
        lru = new LRUCache(0);
    }

    @Test
    public void 文字列を2回putしてgetすると後から追加した値が取得できる() {
        lru = new LRUCache();
        lru.put("a", "dataA");
        lru.put("a", "dataA2");
        assertThat(lru.get("a"), is("dataA2"));
    }

    @Test
    public void 最初にキーリストを取得すると空のリストが返る() {
        lru = new LRUCache();
        assertThat(lru.getKeyList(), notNullValue());
        assertThat(lru.getKeyList().size(), is(0));
    }

    @Test
    public void 要素を1つ足すとキーリストに値が追加される() {
        lru = new LRUCache();
        lru.put("a", "dataA");
        assertThat(lru.getKeyList(), notNullValue());
        assertThat(lru.getKeyList().size(), is(1));
        assertThat(lru.getKeyList().get(0), is("a"));
    }

    @Test
    public void 要素を2つ足すとキーリストに2つ値が追加される() {
        lru = new LRUCache();
        lru.put("a", "dataA");
        lru.put("b", "dataB");

        assertThat(lru.getKeyList(), notNullValue());
        assertThat(lru.getKeyList().size(), is(2));
        assertThat(lru.getKeyList().get(0), is("a"));
        assertThat(lru.getKeyList().get(1), is("b"));

    }

    @Test
    public void 要素を3つ足すとキーリストにキーリストから最後の二つが返される() {
        lru = new LRUCache();
        lru.put("a", "dataA");
        lru.put("b", "dataB");
        lru.put("c", "dataC");
        assertThat(lru.getKeyList(), is(Arrays.asList("b", "c")));
    }

    @Test
    public void 最初に値をgetしてもキーリストは空のまま() {
        lru = new LRUCache();
        lru.get("a");
        assertThat(lru.getKeyList(), is(Collections.<String> emptyList()));
    }

    @Test
    public void 要素を2つ追加して最初の値をgetするとキーリストの順番が変わる() {
        lru = new LRUCache();
        lru.put("a", "dataA");
        lru.put("b", "dataB");
        lru.get("a");
        assertThat(lru.getKeyList(), is(Arrays.asList("b", "a")));
    }

    @Test
    public void 要素を2つ追加して最初の値をgetしてさらに要素を追加したらキーリストの順番が変わる() {
        lru = new LRUCache();
        lru.put("a", "dataA");
        lru.put("b", "dataB");
        lru.get("a");
        lru.put("c", "dataC");
        assertThat(lru.getKeyList(), is(Arrays.asList("a", "c")));
    }

    @Test
    public void 同じキーを複数回putしてもキーリストのサイズは1() {
        lru = new LRUCache();
        lru.put("a", "dataA");
        lru.put("a", "dataA");
        lru.put("a", "dataA");
        assertThat(lru.getKeyList(), is(Arrays.asList("a")));

    }

    @Test
    public void キーをputした順番でキーリストに入る() {
        lru = new LRUCache();
        lru.put("a", "dataA");
        lru.put("b", "dataB");
        lru.put("a", "dataA");
        assertThat(lru.getKeyList(), is(Arrays.asList("b", "a")));

    }

    @Test
    public void キャッシュサイズを越えたときキーをputした順番でキーリストに入る() {
        lru = new LRUCache();
        lru.put("a", "dataA");
        lru.put("b", "dataB");
        lru.put("b", "dataBB");
        assertThat(lru.getKeyList(), is(Arrays.asList("a", "b")));
    }

    @Test
    public void 要素を3つ足した後最初に追加したキーでgetするとnullになるはず() {
        lru = new LRUCache();
        lru.put("a", "dataA");
        lru.put("b", "dataB");
        lru.put("c", "dataC");
        assertThat(lru.get("a"), nullValue());
    }

    // TODO キーリストと値のマップの同期が取れていない
    @Ignore
    @Test
    public void 要素を3つ足した後最初に追加したキーでgetしてその後キーリストを取得する() {
        lru = new LRUCache();
        lru.put("a", "dataA");
        lru.put("b", "dataB");
        lru.put("c", "dataC");
        lru.get("a");
        assertThat(lru.getKeyList(), is(Arrays.asList("b", "c")));
    }

}
  • LRUCache
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class LRUCache {
    private int cacheSize;
    private Map<String, String> map = new HashMap<String, String>();
    private List<String> keyList = new ArrayList<String>();

    public LRUCache(int cachesize) {
        if (cachesize <= 0) {
            throw new IllegalArgumentException();
        }
        this.cacheSize = cachesize;
    }

    public LRUCache() {
        this.cacheSize = 2;
    }

    public String get(String key) {
        boolean containsKey = false;
        if (keyList.contains(key)) {
            keyList.remove(key);
            containsKey = true;
        }
        if (map.containsKey(key)) {
            keyList.add(key);
        }

        if (containsKey) {
            return map.get(key);
        } else {
            return null;
        }
    }

    public void put(String key, String value) {

        if (keyList.size() < this.cacheSize) {
            if (keyList.contains(key)) {
                keyList.remove(key);
            }
            keyList.add(key);
        } else {
            if (keyList.contains(key)) {
                keyList.remove(key);
            } else {
                keyList.remove(0);
            }
            keyList.add(key);
        }
        map.put(key, value);
    }

    public int size() {
        return Math.min(map.size(), this.cacheSize);
    }

    public int cacheSize() {
        return this.cacheSize;
    }

    public List<String> getKeyList() {
        return keyList;
    }

}