You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: diemdb_test.rs
    path of file: ./repos/diem/storage/diemdb/src
    
    the code of the file until where you have to start completion: // Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use super::*;
#[allow(unused_imports)]
use crate::{
    schema::jellyfish_merkle_node::JellyfishMerkleNodeSchema,
    test_helper::{arb_blocks_to_commit, arb_mock_genesis},
};
use diem_crypto::hash::CryptoHash;
#[allow(unused_imports)]
use diem_jellyfish_merkle::node_type::{Node, NodeKey};
use diem_temppath::TempPath;
use diem_types::transaction::Transaction;
#[allow(unused_imports)]
use diem_types::{
    account_address::{AccountAddress, HashAccountAddress},
    account_config::AccountResource,
    contract_event::ContractEvent,
    ledger_info::LedgerInfo,
    proof::SparseMerkleLeafNode,
    vm_status::{KeptVMStatus, StatusCode},
};
use proptest::prelude::*;
use std::collections::HashMap;

fn verify_epochs(db: &DiemDB, ledger_infos_with_sigs: &[LedgerInfoWithSignatures]) {
    const LIMIT: usize = 2;
    let mut actual_epoch_change_lis = Vec::new();
    let latest_epoch = ledger_infos_with_sigs
        .last()
        .unwrap()
        .ledger_info()
        .next_block_epoch();

    let mut cursor = 0;
    loop {
        let (chunk, more) = db
            .get_epoch_ending_ledger_infos_impl(cursor, latest_epoch, LIMIT)
            .unwrap();
        actual_epoch_change_lis.extend(chunk);
        if more {
            cursor = actual_epoch_change_lis
                .last()
                .unwrap()
                .ledger_info()
                .next_block_epoch();
        } else {
            break;
        }
    
pub fn test_save_blocks_impl(input: Vec<(Vec<TransactionToCommit>, LedgerInfoWithSignatures)>) {
    let tmp_dir = TempPath::new();
    let db = DiemDB::new_for_test(&tmp_dir);

    let num_batches = input.len();
    let mut cur_ver = 0;
    let mut all_committed_txns = vec![];
    for (batch_idx, (txns_to_commit, ledger_info_with_sigs)) in input.iter().enumerate() {
        db.save_transactions(
            txns_to_commit,
            cur_ver, /* first_version */
            Some(ledger_info_with_sigs),
        )
        .unwrap();

        assert_eq!(
            db.ledger_store.get_latest_ledger_info().unwrap(),
            *ledger_info_with_sigs
        );
        verify_committed_transactions(
            &db,
            txns_to_commit,
            cur_ver,
            ledger_info_with_sigs,
            batch_idx + 1 == num_batches, /* is_latest */
        );

        // check getting all events by version for all committed transactions
        // up to this point using the current ledger info
        all_committed_txns.extend_from_slice(txns_to_commit);
        verify_get_event_by_version(
            &db,
            &all_committed_txns,
            ledger_info_with_sigs.ledger_info(),
        );

        cur_ver += txns_to_commit.len() as u64;
    }

    let first_batch = input.first().unwrap().0.clone();
    let first_batch_ledger_info = input.first().unwrap().1.clone();
    let latest_ledger_info = input.last().unwrap().1.clone();
    // Verify an old batch with the latest LedgerInfo.
    verify_committed_transactions(
        &db,
        &first_batch,
        0,
        &latest_ledger_info,
        false, /* is_latest */
    );
    // Verify an old batch with an old LedgerInfo.
    verify_committed_transactions(
        &db,
        &first_batch,
        0,
        &first_batch_ledger_info,
        true, /* is_latest */
    );
    let (_, ledger_infos_with_sigs): (Vec<_>, Vec<_>) = input.iter().cloned().unzip();
    verify_epochs(&db, &ledger_infos_with_sigs);
}