package com.example.wordbook.common;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.database.sqlite.SQLiteDatabase;
import android.preference.PreferenceManager;
import android.test.AndroidTestCase;
import android.test.RenamingDelegatingContext;

import com.example.wordbook.R;
import com.example.wordbook.provider.WBData;
import com.example.wordbook.provider.WBHelper;

/**
 * DB利用クラステストクラス
 */
public class DBAccessTest extends AndroidTestCase {

	/** テスト項目数 i */
	private static final int DATA_NUM_I = 8; // >=7
	/** テスト項目数 j */
	private static final int DATA_NUM_J = 16; // >=7

	/** テスト用接頭辞 */
	private static final String TEST_PREFIX = "test_";

	/** WBHelper */
	private WBHelper mHelper;

	/** RenamingDelegatingContext */
	private RenamingDelegatingContext mRDContext;

	/*
	 * (非 Javadoc)
	 * 
	 * @see android.test.AndroidTestCase#setUp()
	 */
	@Override
	protected void setUp() throws Exception {
		super.setUp();

		mRDContext = new RenamingDelegatingContext(getContext(), TEST_PREFIX);
		mHelper = WBHelper.getInstance(mRDContext);

		// クリア
		SQLiteDatabase db = mHelper.getWritableDatabase();
		db.delete(WBData.TABLE_NAME_INFO, null, null);

		// FILE=1はLEVELとFLAGの組み合わせ
		for (int i = 0; i < DATA_NUM_I; i++) {
			for (int j = 0; j < DATA_NUM_J; j++) {
				ContentValues values = new ContentValues();
				values.put(WBData.InfoColumns.INFO_FILE, 1);
				values.put(WBData.InfoColumns.INFO_NUM, i * DATA_NUM_J + j + 1);
				values.put(WBData.InfoColumns.INFO_STAT, 0);
				values.put(WBData.InfoColumns.INFO_LEVEL, i);
				values.put(WBData.InfoColumns.INFO_FLAG, j);
				values.put(WBData.InfoColumns.INFO_OK, 0);
				values.put(WBData.InfoColumns.INFO_NG, 0);
				values.put(WBData.InfoColumns.INFO_QUESTION, "[Q-" + i + "-"
						+ j + "]");
				values.put(WBData.InfoColumns.INFO_ANSWER, "[A-" + i + "-" + j
						+ "]");
				values.put(WBData.InfoColumns.INFO_DATA1, "[D1-" + i + "-" + j
						+ "]");
				values.put(WBData.InfoColumns.INFO_DATA2, "[D2-" + i + "-" + j
						+ "]");
				db.insert(WBData.TABLE_NAME_INFO, null, values);
			}
		}
		// FILE=2はOKとNGの組み合わせ
		for (int i = 0; i < DATA_NUM_I; i++) {
			for (int j = 0; j < DATA_NUM_J; j++) {
				ContentValues values = new ContentValues();
				values.put(WBData.InfoColumns.INFO_FILE, 2);
				values.put(WBData.InfoColumns.INFO_NUM, i * DATA_NUM_J + j + 1);
				values.put(WBData.InfoColumns.INFO_STAT, 0);
				values.put(WBData.InfoColumns.INFO_LEVEL, 0);
				values.put(WBData.InfoColumns.INFO_FLAG, 0);
				values.put(WBData.InfoColumns.INFO_OK, i);
				values.put(WBData.InfoColumns.INFO_NG, j);
				values.put(WBData.InfoColumns.INFO_QUESTION, "[W-" + i + "-"
						+ j + "]");
				values.put(WBData.InfoColumns.INFO_ANSWER, "[S-" + i + "-" + j
						+ "]");
				values.put(WBData.InfoColumns.INFO_DATA1, "[F1-" + i + "-" + j
						+ "]");
				values.put(WBData.InfoColumns.INFO_DATA2, "[F2-" + i + "-" + j
						+ "]");
				db.insert(WBData.TABLE_NAME_INFO, null, values);
			}
		}

		db.close();
	}

	/*
	 * (非 Javadoc)
	 * 
	 * @see android.test.AndroidTestCase#tearDown()
	 */
	@Override
	protected void tearDown() throws Exception {
		super.tearDown();

		if (mHelper != null) {
			mHelper.close();
		}
		mHelper = null;
	}

	/**
	 * testGetDBSearchResultList()
	 */
	public void testGetDBSearchResultList() {
		List<Data> list = null;

		// タイトル用設定
		String title1 = "FILE_1";
		String title2 = "FILE_2";
		Common.modWordbookPref(mRDContext, 1, title1, new int[] {
				DATA_NUM_I * DATA_NUM_J, DATA_NUM_I * DATA_NUM_J, 0, 0 }, 0);
		Common.modWordbookPref(mRDContext, 2, title2, new int[] {
				DATA_NUM_I * DATA_NUM_J, DATA_NUM_I * DATA_NUM_J, 0, 0 }, 0);

		// データ＋タイトル
		list = DBAccess.getDBSearchResultList(mRDContext, "", "");
		assertEquals((DATA_NUM_I * DATA_NUM_J + 1) * 2, list.size());
		assertEquals(0, list.get(0).num);
		assertTrue(title1.equals(list.get(0).question));
		assertEquals(0, list.get(DATA_NUM_I * DATA_NUM_J + 1).num);
		assertTrue(title2
				.equals(list.get(DATA_NUM_I * DATA_NUM_J + 1).question));

		// ACTION_SEARCH
		// 質問検索
		list = DBAccess.getDBSearchResultList(mRDContext, "q-1-", "");
		assertEquals(DATA_NUM_J + 1, list.size());
		list = DBAccess.getDBSearchResultList(mRDContext, "w-", "");
		assertEquals(DATA_NUM_I * DATA_NUM_J + 1, list.size());
		// 解答検索
		list = DBAccess.getDBSearchResultList(mRDContext, "a-1-", "");
		assertEquals(DATA_NUM_J + 1, list.size());
		list = DBAccess.getDBSearchResultList(mRDContext, "s-", "");
		assertEquals(DATA_NUM_I * DATA_NUM_J + 1, list.size());
		// 両方検索
		list = DBAccess.getDBSearchResultList(mRDContext, "[", "");
		assertEquals((DATA_NUM_I * DATA_NUM_J + 1) * 2, list.size());
		list = DBAccess.getDBSearchResultList(mRDContext, "-1]", "");
		assertEquals((DATA_NUM_I + 1) * 2, list.size());

		// ACTION_VIEW
		// 質問検索
		list = DBAccess.getDBSearchResultList(mRDContext, "[Q-1-1]", "[A-1-1]");
		assertEquals(1 + 1, list.size());
		list = DBAccess.getDBSearchResultList(mRDContext, "[Q-1-1]", "]");
		assertEquals(1 + 1, list.size());
		list = DBAccess.getDBSearchResultList(mRDContext, "[", "[A-1-1]");
		assertEquals(1 + 1, list.size());
		list = DBAccess.getDBSearchResultList(mRDContext, "[A-1-1]", "[Q-1-1]");
		assertEquals(0, list.size());
		list = DBAccess.getDBSearchResultList(mRDContext, "[Q-1-1]", "[A-2-1]");
		assertEquals(2 + 1, list.size());
		list = DBAccess.getDBSearchResultList(mRDContext, "[W-1-1]", "[S-1-1]");
		assertEquals(1 + 1, list.size());
		list = DBAccess.getDBSearchResultList(mRDContext, "[W-1-1]", "]");
		assertEquals(1 + 1, list.size());
		list = DBAccess.getDBSearchResultList(mRDContext, "[", "[S-1-1]");
		assertEquals(1 + 1, list.size());
		list = DBAccess.getDBSearchResultList(mRDContext, "[S-1-1]", "[W-1-1]");
		assertEquals(0, list.size());
		list = DBAccess.getDBSearchResultList(mRDContext, "[W-1-1]", "[S-2-1]");
		assertEquals(2 + 1, list.size());
		list = DBAccess.getDBSearchResultList(mRDContext, "[Q-1-1]", "[S-1-1]");
		assertEquals(2 + 2, list.size());
		list = DBAccess.getDBSearchResultList(mRDContext, "[W-1-1]", "[A-1-1]");
		assertEquals(2 + 2, list.size());
	}

	/**
	 * testGetDBCount()
	 */
	public void testGetDBCount() {

		// FILE=0は設定していない
		assertEquals(0, DBAccess.getDBCount(mRDContext, 0));
		// FILE=1は設定している
		assertEquals(DATA_NUM_I * DATA_NUM_J,
				DBAccess.getDBCount(mRDContext, 1));
		// FILE=2は設定している
		assertEquals(DATA_NUM_I * DATA_NUM_J,
				DBAccess.getDBCount(mRDContext, 2));
		// FILE=3は設定していない
		assertEquals(0, DBAccess.getDBCount(mRDContext, 3));
	}

	/**
	 * testGetDBInfo()
	 */
	public void testGetDBInfo() {
		int ok = 0;
		int ng = 0;
		for (int i = 0; i < DATA_NUM_I; i++) {
			for (int j = 0; j < DATA_NUM_J; j++) {
				ok += i;
				ng += j;
			}
		}

		// FILE=0は設定していない
		int[] res0 = DBAccess.getDBInfo(mRDContext, 0);
		assertEquals(4, res0.length);
		assertEquals(0, res0[0]);
		assertEquals(0, res0[1]);
		assertEquals(0, res0[2]);
		assertEquals(0, res0[3]);
		// FILE=1は設定している
		int[] res1 = DBAccess.getDBInfo(mRDContext, 1);
		assertEquals(4, res1.length);
		assertEquals(DATA_NUM_I * DATA_NUM_J, res1[0]); // count
		assertEquals(DATA_NUM_I * DATA_NUM_J, res1[1]); // zero
		assertEquals(0, res1[2]); // ok
		assertEquals(0, res1[3]); // ng
		// FILE=2は設定している
		int[] res2 = DBAccess.getDBInfo(mRDContext, 2);
		assertEquals(4, res2.length);
		assertEquals(DATA_NUM_I * DATA_NUM_J, res2[0]); // count
		assertEquals(1, res2[1]); // zero
		assertEquals(ok, res2[2]); // ok
		assertEquals(ng, res2[3]); // ng
		// FILE=3は設定していない
		int[] res3 = DBAccess.getDBInfo(mRDContext, 3);
		assertEquals(4, res3.length);
		assertEquals(0, res3[0]);
		assertEquals(0, res3[1]);
		assertEquals(0, res3[2]);
		assertEquals(0, res3[3]);
	}

	/**
	 * testGetDBStat()
	 */
	public void testGetDBStat() {
		int ok = 0;
		int ng = 0;
		int[] stat = new int[6];
		for (int i = 0; i < DATA_NUM_I; i++) {
			for (int j = 0; j < DATA_NUM_J; j++) {
				ok += i;
				ng += j;
				if (i == 0 && j == 0) {
					stat[0]++;
				}
				if (i + j > 0 && i * 4 <= j) {
					stat[1]++;
				}
				if (i * 4 > j && i * 3 <= j * 2) {
					stat[2]++;
				}
				if (i * 3 > j * 2 && i * 2 <= j * 3) {
					stat[3]++;
				}
				if (i * 2 > j * 3 && i <= j * 4) {
					stat[4]++;
				}
				if (i > j * 4 && i + j > 0) {
					stat[5]++;
				}
			}
		}
		int total = 0;
		for (int i = 0; i < stat.length; i++) {
			total += stat[i];
		}
		assertEquals(DATA_NUM_I * DATA_NUM_J, total);

		// FILE=0は設定していない
		Integer[] res0 = DBAccess.getDBStat(mRDContext, 0);
		assertEquals(24, res0.length);
		for (int i = 0; i < res0.length; i++) {
			assertEquals(0, res0[i].intValue());
		}
		// FILE=1は設定している
		Integer[] res1 = DBAccess.getDBStat(mRDContext, 1);
		assertEquals(24, res1.length);
		assertEquals(DATA_NUM_J, res1[0].intValue());
		assertEquals(DATA_NUM_J, res1[1].intValue());
		assertEquals(DATA_NUM_J, res1[2].intValue());
		assertEquals(DATA_NUM_J, res1[3].intValue());
		assertEquals(DATA_NUM_J, res1[4].intValue());
		assertEquals(DATA_NUM_J, res1[5].intValue());
		assertEquals(DATA_NUM_J, res1[6].intValue());
		assertEquals(DATA_NUM_J, res1[7].intValue());
		assertEquals(DATA_NUM_I, res1[8].intValue());
		assertEquals(DATA_NUM_I, res1[9].intValue());
		assertEquals(DATA_NUM_I, res1[10].intValue());
		assertEquals(DATA_NUM_I, res1[11].intValue());
		assertEquals(DATA_NUM_I, res1[12].intValue());
		assertEquals(DATA_NUM_I, res1[13].intValue());
		assertEquals(DATA_NUM_I, res1[14].intValue());
		assertEquals(DATA_NUM_I, res1[15].intValue());
		assertEquals(DATA_NUM_I * DATA_NUM_J, res1[16].intValue()); // undefined
		assertEquals(0, res1[17].intValue()); // 20%
		assertEquals(0, res1[18].intValue()); // 40%
		assertEquals(0, res1[19].intValue()); // 60%
		assertEquals(0, res1[20].intValue()); // 80%
		assertEquals(0, res1[21].intValue()); // 100%
		assertEquals(0, res1[22].intValue()); // ok
		assertEquals(0, res1[23].intValue()); // ng
		// FILE=2は設定している
		Integer[] res2 = DBAccess.getDBStat(mRDContext, 2);
		assertEquals(24, res2.length);
		assertEquals(DATA_NUM_I * DATA_NUM_J, res2[0].intValue());
		assertEquals(0, res2[1].intValue());
		assertEquals(0, res2[2].intValue());
		assertEquals(0, res2[3].intValue());
		assertEquals(0, res2[4].intValue());
		assertEquals(0, res2[5].intValue());
		assertEquals(0, res2[6].intValue());
		assertEquals(0, res2[7].intValue());
		assertEquals(DATA_NUM_I * DATA_NUM_J, res2[8].intValue());
		assertEquals(0, res2[9].intValue());
		assertEquals(0, res2[10].intValue());
		assertEquals(0, res2[11].intValue());
		assertEquals(0, res2[12].intValue());
		assertEquals(0, res2[13].intValue());
		assertEquals(0, res2[14].intValue());
		assertEquals(0, res2[15].intValue());
		assertEquals(stat[0], res2[16].intValue()); // undefined
		assertEquals(stat[1], res2[17].intValue()); // 20%
		assertEquals(stat[2], res2[18].intValue()); // 40%
		assertEquals(stat[3], res2[19].intValue()); // 60%
		assertEquals(stat[4], res2[20].intValue()); // 80%
		assertEquals(stat[5], res2[21].intValue()); // 100%
		assertEquals(ok, res2[22].intValue()); // ok
		assertEquals(ng, res2[23].intValue()); // ng
		// FILE=3は設定していない
		Integer[] res3 = DBAccess.getDBStat(mRDContext, 3);
		assertEquals(24, res3.length);
		for (int i = 0; i < res3.length; i++) {
			assertEquals(0, res3[i].intValue());
		}
	}

	/**
	 * testGetDBData()
	 */
	public void testGetDBData() {
		Data d = null;

		// FILE=0は設定していない
		d = DBAccess.getDBData(mRDContext, 0, 0);
		assertNull(d);
		// FILE=1は設定している
		for (int i = 0; i < DATA_NUM_I; i++) {
			for (int j = 0; j < DATA_NUM_J; j++) {
				d = DBAccess.getDBData(mRDContext, 1, i * DATA_NUM_J + j + 1);
				assertEquals(i * DATA_NUM_J + j + 1, d.num);
				assertEquals(0, d.stat);
				assertEquals(i, d.level);
				assertEquals(j, d.flag);
				assertEquals(0, d.ok);
				assertEquals(0, d.ng);
				assertEquals("[Q-" + i + "-" + j + "]", d.question);
				assertEquals("[A-" + i + "-" + j + "]", d.answer);
				assertEquals("[D1-" + i + "-" + j + "]", d.data1);
				assertEquals("[D2-" + i + "-" + j + "]", d.data2);
			}
		}
		// FILE=2は設定している
		for (int i = 0; i < DATA_NUM_I; i++) {
			for (int j = 0; j < DATA_NUM_J; j++) {
				d = DBAccess.getDBData(mRDContext, 2, i * DATA_NUM_J + j + 1);
				assertEquals(i * DATA_NUM_J + j + 1, d.num);
				assertEquals(0, d.stat);
				assertEquals(0, d.level);
				assertEquals(0, d.flag);
				assertEquals(i, d.ok);
				assertEquals(j, d.ng);
				assertEquals("[W-" + i + "-" + j + "]", d.question);
				assertEquals("[S-" + i + "-" + j + "]", d.answer);
				assertEquals("[F1-" + i + "-" + j + "]", d.data1);
				assertEquals("[F2-" + i + "-" + j + "]", d.data2);
			}
		}
		// FILE=3は設定していない
		d = DBAccess.getDBData(mRDContext, 3, 0);
		assertNull(d);
	}

	/**
	 * testGetDBDataList()
	 */
	public void testGetDBDataList() {
		List<Data> list = null;
		// フィルタ制限無し
		boolean[] r = new boolean[6];
		boolean[] f = new boolean[8];
		boolean[] l = new boolean[8];
		Arrays.fill(r, true);
		Arrays.fill(f, true);
		Arrays.fill(l, true);
		setFilter(mRDContext, r, f, l);

		// FILE=0は設定していない
		list = DBAccess.getDBDataList(mRDContext, 0, 0,
				DATA_NUM_I * DATA_NUM_J, 7, null);
		assertEquals(0, list.size());
		// FILE=1は設定している
		list = DBAccess.getDBDataList(mRDContext, 1, 0,
				DATA_NUM_I * DATA_NUM_J, 7, null);
		assertEquals(DATA_NUM_I * DATA_NUM_J, list.size());
		for (int i = 0; i < DATA_NUM_I; i++) {
			for (int j = 0; j < DATA_NUM_J; j++) {
				Data d = list.get(i * DATA_NUM_J + j);
				assertEquals(i * DATA_NUM_J + j + 1, d.num);
				assertEquals(0, d.stat);
				assertEquals(i, d.level);
				assertEquals(j, d.flag);
				assertEquals(0, d.ok);
				assertEquals(0, d.ng);
				assertEquals("[Q-" + i + "-" + j + "]", d.question);
				assertEquals("[A-" + i + "-" + j + "]", d.answer);
				assertEquals("[D1-" + i + "-" + j + "]", d.data1);
				assertEquals("[D2-" + i + "-" + j + "]", d.data2);
			}
		}
		// FILE=2は設定している
		list = DBAccess.getDBDataList(mRDContext, 2, 0,
				DATA_NUM_I * DATA_NUM_J, 7, null);
		assertEquals(DATA_NUM_I * DATA_NUM_J, list.size());
		for (int i = 0; i < DATA_NUM_I; i++) {
			for (int j = 0; j < DATA_NUM_J; j++) {
				Data d = list.get(i * DATA_NUM_J + j);
				assertEquals(i * DATA_NUM_J + j + 1, d.num);
				assertEquals(0, d.stat);
				assertEquals(0, d.level);
				assertEquals(0, d.flag);
				assertEquals(i, d.ok);
				assertEquals(j, d.ng);
				assertEquals("[W-" + i + "-" + j + "]", d.question);
				assertEquals("[S-" + i + "-" + j + "]", d.answer);
				assertEquals("[F1-" + i + "-" + j + "]", d.data1);
				assertEquals("[F2-" + i + "-" + j + "]", d.data2);
			}
		}
		// FILE=3は設定していない
		list = DBAccess.getDBDataList(mRDContext, 3, 0,
				DATA_NUM_I * DATA_NUM_J, 7, null);
		assertEquals(0, list.size());
	}

	/**
	 * testModDBData()
	 * 
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 * @throws IllegalAccessException
	 */
	public void testModDBData() throws InvocationTargetException,
			NoSuchMethodException, IllegalAccessException {

		// リフレクション
		Class<DBAccess> c = DBAccess.class;
		Class<?>[] args = { Context.class, int.class, Data.class };
		Method m = c.getDeclaredMethod("modDBData", args);
		m.setAccessible(true);

		// 操作対象のNUMが存在／NUM以外は不一致
		Data d = new Data(1, 111, 222, 333, 444, 555, "Q", "A", "D1", "D2");
		Data res = null;

		// FILE=0は設定していない
		m.invoke(null, mRDContext, 0, d);
		res = DBAccess.getDBData(mRDContext, 0, d.num);
		assertNull(res);
		// FILE=1は設定している
		m.invoke(null, mRDContext, 1, d);
		res = DBAccess.getDBData(mRDContext, 1, d.num);
		assertNotNull(res);
		assertEquals(d.num, res.num);
		// 更新対象
		assertEquals(d.stat, res.stat);
		assertEquals(d.flag, res.flag);
		assertEquals(d.ok, res.ok);
		assertEquals(d.ng, res.ng);
		assertEquals(d.data2, res.data2);
		// 非更新対象
		assertFalse(d.level == res.level);
		assertFalse(d.question.equals(res.question));
		assertFalse(d.answer.equals(res.answer));
		assertFalse(d.data1.equals(res.data1));
		// FILE=2は設定している
		m.invoke(null, mRDContext, 2, d);
		res = DBAccess.getDBData(mRDContext, 2, d.num);
		assertNotNull(res);
		assertEquals(d.num, res.num);
		// 更新対象
		assertEquals(d.stat, res.stat);
		assertEquals(d.flag, res.flag);
		assertEquals(d.ok, res.ok);
		assertEquals(d.ng, res.ng);
		assertEquals(d.data2, res.data2);
		// 非更新対象
		assertFalse(d.level == res.level);
		assertFalse(d.question.equals(res.question));
		assertFalse(d.answer.equals(res.answer));
		assertFalse(d.data1.equals(res.data1));
		// FILE=3は設定していない
		m.invoke(null, mRDContext, 3, d);
		res = DBAccess.getDBData(mRDContext, 3, d.num);
		assertNull(res);
	}

	/**
	 * testModDBDataList()
	 * 
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 * @throws IllegalAccessException
	 */
	public void testModDBDataList() throws InvocationTargetException,
			NoSuchMethodException, IllegalAccessException {
		// フィルタ制限無し
		boolean[] r = new boolean[6];
		boolean[] f = new boolean[8];
		boolean[] l = new boolean[8];
		Arrays.fill(r, true);
		Arrays.fill(f, true);
		Arrays.fill(l, true);
		setFilter(mRDContext, r, f, l);

		// リフレクション
		Class<DBAccess> c = DBAccess.class;
		Class<?>[] args = { Context.class, int.class, List.class };
		Method m = c.getDeclaredMethod("modDBDataList", args);
		m.setAccessible(true);

		// 操作対象のNUMが存在／NUM以外は不一致
		List<Data> list = new ArrayList<Data>();
		for (int i = 0; i < DATA_NUM_I; i++) {
			for (int j = 0; j < DATA_NUM_J; j++) {
				Data d = new Data(DATA_NUM_J * i + j + 1, 111, 222, 333, 444,
						555, "Q-" + i + "-" + j, "A-" + i + "-" + j, "D1-" + i
								+ "-" + j, "D2-" + i + "-" + j);
				list.add(d);
			}
		}
		List<Data> res = null;

		// FILE=0は設定していない
		m.invoke(null, mRDContext, 0, list);
		res = DBAccess.getDBDataList(mRDContext, 0, 0, DATA_NUM_I * DATA_NUM_J,
				7, null);
		assertEquals(0, res.size());
		// FILE=1は設定している
		m.invoke(null, mRDContext, 1, list);
		res = DBAccess.getDBDataList(mRDContext, 1, 0, DATA_NUM_I * DATA_NUM_J,
				7, null);
		assertEquals(DATA_NUM_I * DATA_NUM_J, res.size());
		for (int i = 0; i < res.size(); i++) {
			assertEquals(list.get(i).num, res.get(i).num);
			// 更新対象
			assertEquals(list.get(i).stat, res.get(i).stat);
			assertEquals(list.get(i).flag, res.get(i).flag);
			assertEquals(list.get(i).ok, res.get(i).ok);
			assertEquals(list.get(i).ng, res.get(i).ng);
			assertEquals(list.get(i).data2, res.get(i).data2);
			// 非更新対象
			assertFalse(list.get(i).level == res.get(i).level);
			assertFalse(list.get(i).question.equals(res.get(i).question));
			assertFalse(list.get(i).answer.equals(res.get(i).answer));
			assertFalse(list.get(i).data1.equals(res.get(i).data1));
		}
		// FILE=2は設定している
		m.invoke(null, mRDContext, 2, list);
		res = DBAccess.getDBDataList(mRDContext, 2, 0, DATA_NUM_I * DATA_NUM_J,
				7, null);
		assertEquals(DATA_NUM_I * DATA_NUM_J, res.size());
		for (int i = 0; i < res.size(); i++) {
			assertEquals(list.get(i).num, res.get(i).num);
			// 更新対象
			assertEquals(list.get(i).stat, res.get(i).stat);
			assertEquals(list.get(i).flag, res.get(i).flag);
			assertEquals(list.get(i).ok, res.get(i).ok);
			assertEquals(list.get(i).ng, res.get(i).ng);
			assertEquals(list.get(i).data2, res.get(i).data2);
			// 非更新対象
			assertFalse(list.get(i).level == res.get(i).level);
			assertFalse(list.get(i).question.equals(res.get(i).question));
			assertFalse(list.get(i).answer.equals(res.get(i).answer));
			assertFalse(list.get(i).data1.equals(res.get(i).data1));
		}
		// FILE=3は設定していない
		m.invoke(null, mRDContext, 3, list);
		res = DBAccess.getDBDataList(mRDContext, 3, 0, DATA_NUM_I * DATA_NUM_J,
				7, null);
		assertEquals(0, res.size());
	}

	/**
	 * testGetDBDataListRange()
	 */
	public void testGetDBDataListRange() {
		List<Data> list = null;
		// フィルタ制限無し
		boolean[] r = new boolean[6];
		boolean[] f = new boolean[8];
		boolean[] l = new boolean[8];
		Arrays.fill(r, true);
		Arrays.fill(f, true);
		Arrays.fill(l, true);
		setFilter(mRDContext, r, f, l);

		// FILE=0は設定していない
		list = DBAccess.getDBDataList(mRDContext, 0, 0,
				DATA_NUM_I * DATA_NUM_J, 7, null);
		assertEquals(0, list.size());
		// FILE=1は設定している
		// 0からJ-1まで
		list = DBAccess.getDBDataList(mRDContext, 1, 0, DATA_NUM_J, 7, null);
		assertEquals(DATA_NUM_J, list.size());
		for (int i = 0; i < DATA_NUM_J; i++) {
			assertEquals(i + 1, list.get(i).num);
		}
		// Jから最後まで
		list = DBAccess.getDBDataList(mRDContext, 1, DATA_NUM_J, DATA_NUM_I
				* DATA_NUM_J, 7, null);
		assertEquals(DATA_NUM_I * DATA_NUM_J - DATA_NUM_J, list.size());
		for (int i = 0; i < DATA_NUM_I * DATA_NUM_J - DATA_NUM_J; i++) {
			assertEquals(DATA_NUM_J + i + 1, list.get(i).num);
		}
		// FILE=2は設定している
		// 0からJ-1まで
		list = DBAccess.getDBDataList(mRDContext, 2, 0, DATA_NUM_J, 7, null);
		assertEquals(DATA_NUM_J, list.size());
		for (int i = 0; i < DATA_NUM_J; i++) {
			assertEquals(i + 1, list.get(i).num);
		}
		// Jから最後まで
		list = DBAccess.getDBDataList(mRDContext, 2, DATA_NUM_J, DATA_NUM_I
				* DATA_NUM_J, 7, null);
		assertEquals(DATA_NUM_I * DATA_NUM_J - DATA_NUM_J, list.size());
		for (int i = 0; i < DATA_NUM_I * DATA_NUM_J - DATA_NUM_J; i++) {
			assertEquals(DATA_NUM_J + i + 1, list.get(i).num);
		}
		// FILE=3は設定していない
		list = DBAccess.getDBDataList(mRDContext, 3, 0,
				DATA_NUM_I * DATA_NUM_J, 7, null);
		assertEquals(0, list.size());
	}

	/**
	 * testGetDBDataListIn()
	 */
	public void testGetDBDataListIn() {
		List<Data> list = null;
		// フィルタ制限無し
		boolean[] r = new boolean[6];
		boolean[] f = new boolean[8];
		boolean[] l = new boolean[8];
		Arrays.fill(r, true);
		Arrays.fill(f, true);
		Arrays.fill(l, true);
		setFilter(mRDContext, r, f, l);
		// 取得候補リスト
		List<Integer> in = Arrays.asList(4, 5, 6, 7);

		// FILE=0は設定していない
		list = DBAccess.getDBDataList(mRDContext, 0, 0,
				DATA_NUM_I * DATA_NUM_J, 7, in);
		assertEquals(0, list.size());
		// FILE=1は設定している
		// 候補のみ
		list = DBAccess.getDBDataList(mRDContext, 1, 0,
				DATA_NUM_I * DATA_NUM_J, 7, in);
		assertEquals(in.size(), list.size());
		for (int i = 0; i < in.size(); i++) {
			assertEquals(in.get(i).intValue(), list.get(i).num);
		}
		// FILE=2は設定している
		// 候補のみ
		list = DBAccess.getDBDataList(mRDContext, 2, 0,
				DATA_NUM_I * DATA_NUM_J, 7, in);
		assertEquals(in.size(), list.size());
		for (int i = 0; i < in.size(); i++) {
			assertEquals(in.get(i).intValue(), list.get(i).num);
		}
		// FILE=3は設定していない
		list = DBAccess.getDBDataList(mRDContext, 3, 0,
				DATA_NUM_I * DATA_NUM_J, 7, in);
		assertEquals(0, list.size());
	}

	/**
	 * testGetDBDataListSort1()
	 */
	public void testGetDBDataListSort1() {
		List<Data> list = null;
		int ok, prev_ok, ng, prev_ng, flag, prev_flag, level, prev_level, id, prev_id;
		// フィルタ制限無し
		boolean[] r = new boolean[6];
		boolean[] f = new boolean[8];
		boolean[] l = new boolean[8];
		Arrays.fill(r, true);
		Arrays.fill(f, true);
		Arrays.fill(l, true);
		setFilter(mRDContext, r, f, l);

		// FILE=1は設定している
		// ランダム
		// setSort(mRDContext, 0);
		list = DBAccess.getDBDataList(mRDContext, 1, 0,
				DATA_NUM_I * DATA_NUM_J, 0, null);
		assertEquals(DATA_NUM_I * DATA_NUM_J, list.size());
		// 正答率昇順
		// setSort(mRDContext, 1);
		list = DBAccess.getDBDataList(mRDContext, 1, 0,
				DATA_NUM_I * DATA_NUM_J, 1, null);
		prev_ok = DATA_NUM_I;
		prev_ng = DATA_NUM_J;
		for (int i = 0; i < list.size(); i++) {
			ok = list.get(i).ok;
			ng = list.get(i).ng;
			if (prev_ng == ng) {
				// 解答数
				assertTrue(prev_ok + prev_ng <= ok + ng);
			}
			// NG数
			assertTrue(ng <= prev_ng);
			prev_ok = ok;
			prev_ng = ng;
		}
		// 正答率降順
		// setSort(mRDContext, 2);
		list = DBAccess.getDBDataList(mRDContext, 1, 0,
				DATA_NUM_I * DATA_NUM_J, 2, null);
		prev_ok = DATA_NUM_I;
		prev_ng = DATA_NUM_J;
		for (int i = 0; i < list.size(); i++) {
			ok = list.get(i).ok;
			ng = list.get(i).ng;
			if (prev_ok == ok) {
				// 解答数
				assertTrue(prev_ok + prev_ng <= ok + ng);
			}
			// OK数
			assertTrue(ok <= prev_ok);
			prev_ok = ok;
			prev_ng = ng;
		}
		// フラグ昇順
		// setSort(mRDContext, 3);
		list = DBAccess.getDBDataList(mRDContext, 1, 0,
				DATA_NUM_I * DATA_NUM_J, 3, null);
		prev_flag = 0;
		for (int i = 0; i < list.size(); i++) {
			flag = list.get(i).flag;
			assertTrue(flag >= prev_flag);
			prev_flag = flag;
		}
		// フラグ降順
		// setSort(mRDContext, 4);
		list = DBAccess.getDBDataList(mRDContext, 1, 0,
				DATA_NUM_I * DATA_NUM_J, 4, null);
		prev_flag = DATA_NUM_J;
		for (int i = 0; i < list.size(); i++) {
			flag = list.get(i).flag;
			assertTrue(flag <= prev_flag);
			prev_flag = flag;
		}
		// レベル昇順
		// setSort(mRDContext, 5);
		list = DBAccess.getDBDataList(mRDContext, 1, 0,
				DATA_NUM_I * DATA_NUM_J, 5, null);
		prev_level = 0;
		for (int i = 0; i < list.size(); i++) {
			level = list.get(i).level;
			assertTrue(level >= prev_level);
			prev_level = level;
		}
		// レベル降順
		// setSort(mRDContext, 6);
		list = DBAccess.getDBDataList(mRDContext, 1, 0,
				DATA_NUM_I * DATA_NUM_J, 6, null);
		prev_level = DATA_NUM_I;
		for (int i = 0; i < list.size(); i++) {
			level = list.get(i).level;
			assertTrue(level <= prev_level);
			prev_level = level;
		}
		// 識別子昇順
		// setSort(mRDContext, 7);
		list = DBAccess.getDBDataList(mRDContext, 1, 0,
				DATA_NUM_I * DATA_NUM_J, 7, null);
		prev_id = 0;
		for (int i = 0; i < list.size(); i++) {
			id = list.get(i).num;
			assertTrue(id >= prev_id);
			prev_id = id;
		}
		// 識別子降順
		// setSort(mRDContext, 8);
		list = DBAccess.getDBDataList(mRDContext, 1, 0,
				DATA_NUM_I * DATA_NUM_J, 8, null);
		prev_id = DATA_NUM_I * DATA_NUM_J;
		for (int i = 0; i < list.size(); i++) {
			id = list.get(i).num;
			assertTrue(id <= prev_id);
			prev_id = id;
		}
	}

	/**
	 * testGetDBDataListSort2()
	 */
	public void testGetDBDataListSort2() {
		List<Data> list = null;
		int ok, prev_ok, ng, prev_ng, flag, prev_flag, level, prev_level, id, prev_id;
		// フィルタ制限無し
		boolean[] r = new boolean[6];
		boolean[] f = new boolean[8];
		boolean[] l = new boolean[8];
		Arrays.fill(r, true);
		Arrays.fill(f, true);
		Arrays.fill(l, true);
		setFilter(mRDContext, r, f, l);

		// FILE=2は設定している
		// ランダム
		// setSort(mRDContext, 0);
		list = DBAccess.getDBDataList(mRDContext, 2, 0,
				DATA_NUM_I * DATA_NUM_J, 0, null);
		assertEquals(DATA_NUM_I * DATA_NUM_J, list.size());
		// 正答率昇順
		// setSort(mRDContext, 1);
		list = DBAccess.getDBDataList(mRDContext, 2, 0,
				DATA_NUM_I * DATA_NUM_J, 1, null);
		prev_ok = DATA_NUM_I;
		prev_ng = DATA_NUM_J;
		for (int i = 0; i < list.size(); i++) {
			ok = list.get(i).ok;
			ng = list.get(i).ng;
			if (prev_ng == ng) {
				// 解答数
				assertTrue(prev_ok + prev_ng <= ok + ng);
			}
			// NG数
			assertTrue(ng <= prev_ng);
			prev_ok = ok;
			prev_ng = ng;
		}
		// 正答率降順
		// setSort(mRDContext, 2);
		list = DBAccess.getDBDataList(mRDContext, 2, 0,
				DATA_NUM_I * DATA_NUM_J, 2, null);
		prev_ok = DATA_NUM_I;
		prev_ng = DATA_NUM_J;
		for (int i = 0; i < list.size(); i++) {
			ok = list.get(i).ok;
			ng = list.get(i).ng;
			if (prev_ok == ok) {
				// 解答数
				assertTrue(prev_ok + prev_ng <= ok + ng);
			}
			// OK数
			assertTrue(ok <= prev_ok);
			prev_ok = ok;
			prev_ng = ng;
		}
		// フラグ昇順
		// setSort(mRDContext, 3);
		list = DBAccess.getDBDataList(mRDContext, 2, 0,
				DATA_NUM_I * DATA_NUM_J, 3, null);
		prev_flag = 0;
		for (int i = 0; i < list.size(); i++) {
			flag = list.get(i).flag;
			assertTrue(flag >= prev_flag);
			prev_flag = flag;
		}
		// フラグ降順
		// setSort(mRDContext, 4);
		list = DBAccess.getDBDataList(mRDContext, 2, 0,
				DATA_NUM_I * DATA_NUM_J, 4, null);
		prev_flag = DATA_NUM_J;
		for (int i = 0; i < list.size(); i++) {
			flag = list.get(i).flag;
			assertTrue(flag <= prev_flag);
			prev_flag = flag;
		}
		// レベル昇順
		// setSort(mRDContext, 5);
		list = DBAccess.getDBDataList(mRDContext, 2, 0,
				DATA_NUM_I * DATA_NUM_J, 5, null);
		prev_level = 0;
		for (int i = 0; i < list.size(); i++) {
			level = list.get(i).level;
			assertTrue(level >= prev_level);
			prev_level = level;
		}
		// レベル降順
		// setSort(mRDContext, 6);
		list = DBAccess.getDBDataList(mRDContext, 2, 0,
				DATA_NUM_I * DATA_NUM_J, 6, null);
		prev_level = DATA_NUM_I;
		for (int i = 0; i < list.size(); i++) {
			level = list.get(i).level;
			assertTrue(level <= prev_level);
			prev_level = level;
		}
		// 識別子昇順
		// setSort(mRDContext, 7);
		list = DBAccess.getDBDataList(mRDContext, 2, 0,
				DATA_NUM_I * DATA_NUM_J, 7, null);
		prev_id = 0;
		for (int i = 0; i < list.size(); i++) {
			id = list.get(i).num;
			assertTrue(id >= prev_id);
			prev_id = id;
		}
		// 識別子降順
		// setSort(mRDContext, 8);
		list = DBAccess.getDBDataList(mRDContext, 2, 0,
				DATA_NUM_I * DATA_NUM_J, 8, null);
		prev_id = DATA_NUM_I * DATA_NUM_J;
		for (int i = 0; i < list.size(); i++) {
			id = list.get(i).num;
			assertTrue(id <= prev_id);
			prev_id = id;
		}
	}

	/**
	 * testGetDBDataListFilter1()
	 */
	public void testGetDBDataListFilter1() {
		List<Data> list = null;
		double p;
		// フィルタ制限
		boolean[] r = new boolean[6];
		boolean[] f = new boolean[8];
		boolean[] l = new boolean[8];

		// 統計データ
		Integer[] res = DBAccess.getDBStat(mRDContext, 1);

		// FILE=1は設定している
		// record
		Arrays.fill(f, true);
		Arrays.fill(l, true);
		for (int i = 0; i < r.length; i++) {
			Arrays.fill(r, true);
			// 対象データを設定
			r[i] = false;
			setFilter(mRDContext, r, f, l);
			list = DBAccess.getDBDataList(mRDContext, 1, 0, DATA_NUM_I
					* DATA_NUM_J, 7, null);
			// 統計データと比較
			assertEquals(DATA_NUM_I * DATA_NUM_J - res[16 + i].intValue(),
					list.size());
			for (Data d : list) {
				if (i == 0) {
					// 対象データではないことを確認
					assertFalse(d.ok + d.ng == 0);
				} else {
					p = (d.ok + d.ng == 0 || d.ok == 0) ? 0.0 : d.ok * 100.0
							/ (d.ok + d.ng);
					// 対象データではないことを確認
					assertFalse(p > (i - 1) * 20.0 && p <= i * 20.0);
				}
			}
		}
		// flag
		Arrays.fill(r, true);
		Arrays.fill(l, true);
		for (int i = 0; i < f.length; i++) {
			Arrays.fill(f, true);
			// 対象データを設定
			f[i] = false;
			setFilter(mRDContext, r, f, l);
			list = DBAccess.getDBDataList(mRDContext, 1, 0, DATA_NUM_I
					* DATA_NUM_J, 7, null);
			// 統計データと比較
			assertEquals(DATA_NUM_I * DATA_NUM_J - res[8 + i].intValue(),
					list.size());
			for (Data d : list) {
				// 対象データではないことを確認
				assertFalse(d.flag == i);
			}
		}
		// level
		Arrays.fill(r, true);
		Arrays.fill(f, true);
		for (int i = 0; i < l.length; i++) {
			Arrays.fill(l, true);
			// 対象データを設定
			l[i] = false;
			setFilter(mRDContext, r, f, l);
			list = DBAccess.getDBDataList(mRDContext, 1, 0, DATA_NUM_I
					* DATA_NUM_J, 7, null);
			// 統計データと比較
			assertEquals(DATA_NUM_I * DATA_NUM_J - res[i].intValue(),
					list.size());
			for (Data d : list) {
				// 対象データではないことを確認
				assertFalse(d.level == i);
			}
		}
	}

	/**
	 * testGetDBDataListFilter2()
	 */
	public void testGetDBDataListFilter2() {
		List<Data> list = null;
		double p;
		// フィルタ制限
		boolean[] r = new boolean[6];
		boolean[] f = new boolean[8];
		boolean[] l = new boolean[8];

		// 統計データ
		Integer[] res = DBAccess.getDBStat(mRDContext, 2);

		// FILE=2は設定している
		// record
		Arrays.fill(f, true);
		Arrays.fill(l, true);
		for (int i = 0; i < r.length; i++) {
			Arrays.fill(r, true);
			// 対象データを設定
			r[i] = false;
			setFilter(mRDContext, r, f, l);
			list = DBAccess.getDBDataList(mRDContext, 2, 0, DATA_NUM_I
					* DATA_NUM_J, 7, null);
			// 統計データと比較
			assertEquals(DATA_NUM_I * DATA_NUM_J - res[16 + i].intValue(),
					list.size());
			for (Data d : list) {
				if (i == 0) {
					// 対象データではないことを確認
					assertFalse(d.ok + d.ng == 0);
				} else {
					p = (d.ok + d.ng == 0 || d.ok == 0) ? 0.0 : d.ok * 100.0
							/ (d.ok + d.ng);
					// 対象データではないことを確認
					assertFalse(p > (i - 1) * 20.0 && p <= i * 20.0);
				}
			}
		}
		// flag
		Arrays.fill(r, true);
		Arrays.fill(l, true);
		for (int i = 0; i < f.length; i++) {
			Arrays.fill(f, true);
			// 対象データを設定
			f[i] = false;
			setFilter(mRDContext, r, f, l);
			list = DBAccess.getDBDataList(mRDContext, 2, 0, DATA_NUM_I
					* DATA_NUM_J, 7, null);
			// 統計データと比較
			assertEquals(DATA_NUM_I * DATA_NUM_J - res[8 + i].intValue(),
					list.size());
			for (Data d : list) {
				// 対象データではないことを確認
				assertFalse(d.flag == i);
			}
		}
		// level
		Arrays.fill(r, true);
		Arrays.fill(f, true);
		for (int i = 0; i < l.length; i++) {
			Arrays.fill(l, true);
			// 対象データを設定
			l[i] = false;
			setFilter(mRDContext, r, f, l);
			list = DBAccess.getDBDataList(mRDContext, 2, 0, DATA_NUM_I
					* DATA_NUM_J, 7, null);
			// 統計データと比較
			assertEquals(DATA_NUM_I * DATA_NUM_J - res[i].intValue(),
					list.size());
			for (Data d : list) {
				// 対象データではないことを確認
				assertFalse(d.level == i);
			}
		}
	}

	/**
	 * 出題順序設定（テスト用）
	 * 
	 * @param context
	 *            コンテキスト
	 * @param sort
	 *            出題順序
	 * @return true:成功/false:失敗
	 */
	@SuppressWarnings("unused")
	private boolean setSort(Context context, int sort) {
		if (sort < 0 || sort > 8) {
			return false;
		}
		String[] sa = context.getResources().getStringArray(R.array.sort);
		if (sa.length != 9) {
			return false;
		}
		SharedPreferences pref = PreferenceManager
				.getDefaultSharedPreferences(context);
		Editor editor = pref.edit();

		String key = "pref_sort";
		editor.putString(key, sa[sort]);

		return editor.commit();
	}

	/**
	 * フィルタ設定（テスト用）
	 * 
	 * @param context
	 *            コンテキスト
	 * @param record
	 *            Recordリスト
	 * @param flag
	 *            Flagリスト
	 * @param level
	 *            Levelリスト
	 * @return true:成功/false:失敗
	 */
	private boolean setFilter(Context context, boolean[] record,
			boolean[] flag, boolean[] level) {
		if (record.length != 6 || flag.length != 8 || level.length != 8) {
			return false;
		}
		SharedPreferences pref = PreferenceManager
				.getDefaultSharedPreferences(context);
		Editor editor = pref.edit();

		for (int i = 0; i < record.length; i++) {
			String key = "pref_record0" + i;
			editor.putBoolean(key, record[i]);
		}
		for (int i = 0; i < flag.length; i++) {
			String key = "pref_flag0" + i;
			editor.putBoolean(key, flag[i]);
		}
		for (int i = 0; i < level.length; i++) {
			String key = "pref_level0" + i;
			editor.putBoolean(key, level[i]);
		}

		return editor.commit();
	}

}
