func TestSimpleJSONDB_InitializesDataFile(t *testing.T) {
	firstDataBlock := make([]byte, 10)
	blocksBitMapBlock := make([]byte, dbio.DATABLOCK_SIZE)
	bTreeRootBlock := make([]byte, 2)
	fakeDataFile := utils.NewFakeDataFileWithBlocks([][]byte{
		firstDataBlock,
		blocksBitMapBlock,
		nil,
		nil,
		bTreeRootBlock,
	})

	jsondb.NewWithDataFile(fakeDataFile)

	if !utils.SlicesEqual(firstDataBlock[0:2], []byte{0x00, 0x03}) {
		t.Error("Did not set the next available data block pointer to 3")
	}

	if !utils.SlicesEqual(firstDataBlock[2:4], []byte{0x00, 0x03}) {
		t.Error("Did not set the first record block pointer to 3")
	}

	blocksBitMap := dbio.NewBitMapFromBytes(blocksBitMapBlock)
	for i := 0; i < 4; i++ {
		val, err := blocksBitMap.Get(i)
		if err != nil {
			t.Fatal(err)
		}

		if !val {
			t.Errorf("Expected block %d to be flagged as used", i)
		}
	}
}
func TestSet(t *testing.T) {
	b := dbio.NewBitMap(16)
	b.Set(2)
	b.Set(15)

	if !utils.SlicesEqual(b.Bytes(), []byte{0x02, 0x40}) {
		t.Errorf("bytes do not match '%X'", b.Bytes())
	}
}
func TestFetchesBlockFromDataFile(t *testing.T) {
	fakeDataBlock := []byte{0x10, 0xF0}
	fakeDataFile := utils.NewFakeDataFileWithBlocks([][]byte{nil, fakeDataBlock})

	dataBlock, err := dbio.NewDataBuffer(fakeDataFile, 1).FetchBlock(1)
	if err != nil {
		t.Fatal("Unexpected error", err)
	}
	if dataBlock.ID != 1 {
		t.Errorf("ID doesn't match (expected %d got %d)", 1, dataBlock.ID)
	}
	if !utils.SlicesEqual(dataBlock.Data[0:2], fakeDataBlock) {
		t.Errorf("Data blocks do not match (expected %x got %x)", fakeDataBlock, dataBlock.Data[0:2])
	}
}
func TestControlBlock_IndexRootBlockID(t *testing.T) {
	block := &dbio.DataBlock{Data: []byte{0, 0, 0, 0, 0, 0x09}}
	cb := &controlBlock{block}

	if blockID := cb.IndexRootBlockID(); blockID != 9 {
		t.Errorf("Root BTree datablock pointer was not read, got %d and expected %d", blockID, 9)
	}

	cb.SetIndexRootBlockID(901)
	if id := cb.IndexRootBlockID(); id != 901 {
		t.Errorf("Next id was not read, got %d and expected %d", id, 901)
	}

	if !utils.SlicesEqual(block.Data, []byte{0, 0, 0, 0, 0x03, 0x85}) {
		fmt.Printf("% x\n", block.Data)
		t.Errorf("Invalid data written to block (% x)", block.Data)
	}
}
func TestControlBlock_NextAvailableRecordsDataBlock(t *testing.T) {
	block := &dbio.DataBlock{Data: []byte{0x10, 0x01}}
	cb := &controlBlock{block}

	if id := cb.NextAvailableRecordsDataBlockID(); id != 4097 {
		t.Errorf("Next id was not read, got %d and expected %d", id, 16)
	}

	cb.SetNextAvailableRecordsDataBlockID(900)
	if id := cb.NextAvailableRecordsDataBlockID(); id != 900 {
		t.Errorf("Next id was not read, got %d and expected %d", id, 900)
	}

	if !utils.SlicesEqual(block.Data, []byte{0x03, 0x84}) {
		fmt.Printf("% x\n", block.Data)
		t.Errorf("Invalid data written to block (% x)", block.Data)
	}
}
func TestSavesDirtyFramesWhenEvicting(t *testing.T) {
	fakeDataBlock := []byte{0x00, 0x01, 0x02}
	fakeDataFile := utils.NewFakeDataFileWithBlocks([][]byte{
		fakeDataBlock, []byte{}, []byte{}, []byte{},
	})

	blockThatWasWritten := uint16(999)
	bytesWritten := []byte{}
	fakeDataFile.WriteBlockFunc = func(id uint16, data []byte) error {
		blockThatWasWritten = id
		bytesWritten = data
		return nil
	}

	buffer := dbio.NewDataBuffer(fakeDataFile, 2)

	// Read the first 2 blocks and flag the first one as dirty
	buffer.FetchBlock(0)
	buffer.FetchBlock(1)
	buffer.MarkAsDirty(0)

	// Evict the frame 1 by loading a third frame
	buffer.FetchBlock(2)

	// Evict the frame 0 by loading a fourth frame
	buffer.FetchBlock(3)

	if blockThatWasWritten == 999 {
		t.Fatalf("Block was not saved to disk (%d)", blockThatWasWritten)
	}
	if blockThatWasWritten != 0 {
		t.Errorf("Unknown block saved to disk (%d)", blockThatWasWritten)
	}
	if !utils.SlicesEqual(bytesWritten[0:3], fakeDataBlock) {
		t.Errorf("Invalid data saved to disk %x", bytesWritten[0:3])
	}
}