/**
 * LOGICAL-PARADOX.ORG b-tree library
 * Copyright (C)2004 satoshi akabane(akabane@logical-paradox.org)
 *
 * Release 1.0
 * ・初期パージョン
 */
package org.logical_paradox.common.btree;

import junit.framework.TestCase;

/**
 * BtreePageの単体テストユニット<br>
 * @author satoshi akabane
 * @version 1.0
 */
public class BtreePageTest extends TestCase {
	private BtreeFactory _factory = null;

	public BtreePageTest( String name ) {
		super(name);
	}

	/**
	 * コンストラクタ(1)のテスト
	 */
	public void testBtreePage_Constructor1() throws Exception {
		BtreePage bp = null;

		/*
		 * 正常系
		 */
		_factory.getProperty().setProperty(BtreeFile.ORDER, "64");
		bp = new BtreePage(_factory,1);
		assertTrue("正常系の次数がおかしい", bp.order() == 64);
		assertTrue("正常系のページ番号がおかしい", bp.getPageNo() == 1);
		assertTrue("正常系の子ノード数がおかしい", bp.children() == 65);

		/*
	 	 * 次数を0以下にした場合
	 	 */
		try {
			_factory.getProperty().setProperty(BtreeFile.ORDER, "0");
			bp = new BtreePage(_factory,0);
			fail("次数0で作成されてしまった");
		} catch( BtreeException be1 ) {
		}
		try {
			_factory.getProperty().setProperty(BtreeFile.ORDER, "-1");
			bp = new BtreePage(_factory,0);
			fail("次数-1で作成されてしまった");
		} catch( BtreeException be2 ) {
		}

		/*
		 * ページ番号を0未満にした場合
		 */
		try {
			_factory.getProperty().setProperty(BtreeFile.ORDER, "1");
			bp = new BtreePage(_factory,-1);
			fail("ページ番号-1で作成されてしまった");
		} catch( BtreeException be3 ) {
		}

		// 最後にページ番号0でテスト - 値としては問題ない
		_factory.getProperty().setProperty(BtreeFile.ORDER, "1");
		bp = new BtreePage(_factory,0);
	}
	/**
	 * コンストラクタ(2)のテスト
	 */
	public void testBtreePage_Constructor2() {
	}
	/**
	 * キー挿入のテスト
	 * 許容されるキーは格納されるし，昇進が発生するケースにおいては格納されない
	 */
	public void testInsert() throws Exception {
		_factory.getProperty().setProperty(BtreeFile.ORDER, "3");
		BtreePage bp = new BtreePage(_factory, 0);
		BtreeKey[] keys = new BtreeKey[4];
		keys[0] = new BtreeKeyTestImpl("キー1");
		keys[1] = new BtreeKeyTestImpl("キー2");
		keys[2] = new BtreeKeyTestImpl("キー3");
		keys[3] = new BtreeKeyTestImpl("キー4");

		for(int i = 0; i < 4; i++) {
			BtreePage.PromoResult pr = bp.insert(keys[i], -1);
			assertTrue("なぜか昇進が発生した: i=" + i, pr == null || i == 3);
			assertTrue("キーの総数がおかしい: k="+ bp.keyCount(), (bp.keyCount() == i+1 && i < 3 || bp.keyCount() == 2 && i == 3));
			assertTrue("挿入したはずなのにページに格納されていない", (bp.isContained(keys[i]) == true && i < 3) || (bp.isContained(keys[i]) == false && i == 3));
			if(i == 3) {
				assertTrue("昇進が発生しなかった", pr != null && pr._promoKey != null);
				assertTrue("分割が発生したなかった", pr != null && pr._page != null);
			}
		}
	}
	/**
	 * 昇進処理のテスト
	 */
	public void testPromotion() throws Exception {
		_factory.getProperty().setProperty(BtreeFile.ORDER, "3");
		BtreePage bp = new BtreePage(_factory, 0);
		BtreePage.PromoResult pr = null;

		BtreeKey key1 = new BtreeKeyTestImpl("A");
		pr = bp.insert(key1,-1);
		assertTrue("なぜか昇進が発生した - A", pr == null);

		BtreeKey key2 = new BtreeKeyTestImpl("G");
		pr = bp.insert(key2,1);
		assertTrue("なぜか昇進が発生した - G", pr == null);

		BtreeKey key3 = new BtreeKeyTestImpl("M");
		pr = bp.insert(key3,3);
		assertTrue("なぜか昇進が発生した - M", pr == null);

		BtreeKey key4 = new BtreeKeyTestImpl("Q");
		pr = bp.insert(key4,-1);

		assertTrue("昇進が発生しなかった - Q", pr != null);
		assertTrue("昇進が発生したのがMでなかった", pr._promoKey.equals(new BtreeKeyTestImpl("M")) );
		assertTrue("昇進が発生したのがGだった", !pr._promoKey.equals(new BtreeKeyTestImpl("G")) );
		assertTrue("昇進が発生したのがQだった", !pr._promoKey.equals(new BtreeKeyTestImpl("Q")) );
		assertTrue("昇進が発生したのがAだった", !pr._promoKey.equals(new BtreeKeyTestImpl("A")) );

		assertTrue("分割によって発生したページに格納されているキーの数が1でない:"+pr._page.keyCount(), pr._page.keyCount() == 1);
		assertTrue("分割によって発生したページにAが含まれていた", !pr._page.isContained(key1));
		assertTrue("分割によって発生したページにGが含まれていた", !pr._page.isContained(key2));
		assertTrue("分割によって発生したページにMが含まれていた", !pr._page.isContained(key3));
		assertTrue("分割によって発生したページにQが含まれていなかった", pr._page.isContained(key4));

		assertTrue("Aの左の子が-1でなかった", bp.leftChildOf(key1) == -1);
		assertTrue("Aの右の子が-1でなかった", bp.rightChildOf(key1) == -1);
		assertTrue("Gの左の子が-1でなかった", bp.leftChildOf(key2) == -1);
		assertTrue("Gの右の子が1でなかった", bp.rightChildOf(key2) == 1);
		assertTrue("Qの左の子が3でなかった", pr._page.leftChildOf(key4) == 3);
		assertTrue("Qの右の子が-1でなかった", pr._page.rightChildOf(key4) == -1);
	}
	/**
	 * キー検索のテスト
	 */
	public void testFind() throws Exception {
		_factory.getProperty().setProperty(BtreeFile.ORDER, "5");
		BtreePage bp = new BtreePage(_factory, 0);
		BtreeKeyTestImpl key = new BtreeKeyTestImpl("テストキー");
		BtreePage.PromoResult pr = bp.insert(key, -1);

		assertTrue("ページから見つけられなかった", bp.find(key.toString()) != null);
	}
	/**
	 * 指定キーがページに含まれるべきかどうかの検査テスト
	 */
	public void testShouldBeContained() throws Exception {
		_factory.getProperty().setProperty(BtreeFile.ORDER, "7");
		BtreePage bp = new BtreePage(_factory, 0);
		BtreeKeyTestImpl key1 = new BtreeKeyTestImpl("A");
		BtreeKeyTestImpl key2 = new BtreeKeyTestImpl("D");
		BtreeKeyTestImpl key3 = new BtreeKeyTestImpl("B");
		BtreePage.PromoResult pr = null;
		pr = bp.insert(key1, -1);
		pr = bp.insert(key2, -1);

		assertTrue("含まれるべきはずなのに含まれないとでた", bp.shouldBeContained(key3) == true);

		pr = bp.insert(key3, 0);		// Bを右の子指定で挿入． Cは挿入できないはず
		BtreeKeyTestImpl key4 = new BtreeKeyTestImpl("C");
//		try {
//			bp.insert(key4,5);
//			fail("挿入できないはずが，挿入できてしまった");
//		} catch(BtreeManipulationException be) {
//			// 挿入できないはずなので，ここに処理が通れば正常系
//		}

		// 一番左に格納するテスト
		BtreeKeyTestImpl key5 = new BtreeKeyTestImpl("0");
		bp.insert(key5, 1);

		// 一番右に格納するテスト
		BtreeKeyTestImpl key6 = new BtreeKeyTestImpl("Q");
		bp.insert(key6,-1);
	}
	/**
	 * キーがページに格納されているかどうかの判定テスト
	 */
	public void testIsContained() throws Exception {
		BtreeKeyTestImpl key2 = new BtreeKeyTestImpl("こんにちは");
		BtreeKeyTestImpl key1 = new BtreeKeyTestImpl("abc");
		_factory.getProperty().setProperty(BtreeFile.ORDER, "16");
		BtreePage bp = new BtreePage(_factory, 0);
		bp.insert(key2, -1);
		bp.insert(key1, -1);
		assertNotNull(bp.find("abc"));
		assertNotNull(bp.find("こんにちは"));
	}
	/**
	 * ページ全体をバイトストリームに変換するテスト
	 * @throws Exception
	 */
	public void testToByteStream() throws Exception {
		BtreeFile file = _factory.getFileHandle("aa");
		// 次数の設定を元に戻す
		_factory.getProperty().setProperty(BtreeFile.ORDER, "64");
		BtreePage btp = file.newPage();

		int keyByteSize = 128;
		int _order = 64;
		int pageStreamSize = keyByteSize * _order + 8 * (_order+1) +4;

		assertEquals(64,Integer.parseInt(_factory.getProperty().getProperty(BtreeFile.ORDER)));
		assertEquals(keyByteSize, _factory.keyByteSize());
		assertEquals(_order, btp.order());
		assertEquals(pageStreamSize, btp.getByteStream().length);
	}
	/**
	 * バイトストリームからページ全体を復元するテスト
	 * @throws Exception
	 */
	public void testFromByteStream() throws Exception {
		BtreeFile file = _factory.getFileHandle("aa");
		// 次数の設定を元に戻す
		_factory.getProperty().setProperty(BtreeFile.ORDER, "64");
		BtreePage btp1 = file.newPage();
		btp1.insert(_factory.newKey("あああ"), 1024);
		BtreePage btp2 = new BtreePage(_factory, 100, btp1.getByteStream());
		
		assertEquals(btp1.order(), btp2.order());
		assertEquals(btp1.keyCount(), btp2.keyCount());
		assertNotNull(btp1.find("あああ"));
		assertNotNull(btp2.find("あああ"));
		assertEquals(btp1.find("あああ"), btp2.find("あああ"));

		assertEquals(btp1.rightChildOf(btp1.find("あああ")), btp2.rightChildOf(btp2.find("あああ")));
		assertEquals(btp1.leftChildOf(btp1.find("あああ")), btp2.leftChildOf(btp2.find("あああ")));
	}
	/**
	 * キー削除のテスト
	 */
	public void testDelete() {
	}
	
	/**
	 * テストの初期化
	 */
	public void setUp() throws Exception {
		_factory = BtreeFactory.getInstance("org.logical_paradox.common.btree.BtreeFactoryTestImpl");
	}
}

// end of BtreePageTest.java
