Home Reference Source Test

test/specs/generic/consensus/base/account/BasicAccount.spec.js

describe('BasicAccount', () => {
    const pubKey = PublicKey.unserialize(BufferUtils.fromBase64(Dummy.publicKey1));
    const recipient = Address.unserialize(BufferUtils.fromBase64(Dummy.address1));

    it('can serialize and unserialize itself', () => {
        const account = new BasicAccount(100);
        const account2 = Account.unserialize(account.serialize());

        expect(account.type).toEqual(account2.type);
        expect(account.balance).toEqual(account2.balance);
    });

    it('is self plain', () => {
        const account1 = new BasicAccount(100);
        const account2 = Account.fromPlain(account1);
        expect(account1.equals(account2)).toBeTruthy();
    });

    it('can be converted to plain and back', () => {
        const account1 = new BasicAccount(100);
        const plain = JSON.stringify(account1.toPlain());
        const account2 = Account.fromPlain(JSON.parse(plain));
        expect(account1.equals(account2)).toBeTruthy();
    });

    it('can handle balance changes', () => {
        const account = new BasicAccount(0);

        expect(account.balance).toBe(0);
        expect(account.withBalance(10).balance).toBe(10);
        expect(account.withBalance(Number.MAX_SAFE_INTEGER).balance).toBe(Number.MAX_SAFE_INTEGER);
        expect(account.withBalance(Number.MAX_SAFE_INTEGER).withBalance(0).balance).toBe(0);

        expect(() => account.withBalance(-1)).toThrowError('Malformed balance');
        expect(() => account.withBalance(NaN)).toThrowError('Malformed balance');
    });

    it('can accept incoming transactions', (done) => {
        (async () => {
            let transaction = new BasicTransaction(pubKey, recipient, 100, 0, 0);
            expect(await BasicAccount.verifyIncomingTransaction(transaction)).toBeTruthy();

            transaction = new ExtendedTransaction(recipient, Account.Type.BASIC, recipient, Account.Type.BASIC, 100, 0, 0, Transaction.Flag.NONE, new Uint8Array(60));
            expect(await BasicAccount.verifyIncomingTransaction(transaction)).toBeTruthy();
        })().then(done, done.fail);
    });

    it('can deny incoming transactions', (done) => {
        (async () => {
            let transaction = new ExtendedTransaction(recipient, Account.Type.BASIC, recipient, Account.Type.BASIC, 100, 0, 0, Transaction.Flag.NONE, new Uint8Array(65));
            expect(await BasicAccount.verifyIncomingTransaction(transaction)).toBeFalsy();

            transaction = new ExtendedTransaction(recipient, Account.Type.BASIC, recipient, Account.Type.BASIC, 100, 0, 0, Transaction.Flag.NONE, new Uint8Array(1000));
            expect(await BasicAccount.verifyIncomingTransaction(transaction)).toBeFalsy();
        })().then(done, done.fail);
    });

    it('can apply incoming transactions', () => {
        let account = new BasicAccount(0);

        expect(account.balance).toBe(0);

        let transaction = new BasicTransaction(pubKey, recipient, 100, 0, 0);
        account = account.withIncomingTransaction(transaction, 1);

        expect(account.balance).toBe(100);

        transaction = new BasicTransaction(pubKey, recipient, 1, 0, 0);
        account = account.withIncomingTransaction(transaction, 2);

        expect(account.balance).toBe(101);
    });

    it('can revert incoming transaction', () => {
        let account = new BasicAccount(0);
        const transaction = new BasicTransaction(pubKey, recipient, 100, 0, 0);

        expect(account.balance).toBe(0);

        account = account.withIncomingTransaction(transaction, 1);

        expect(account.balance).toBe(100);

        account = account.withIncomingTransaction(transaction, 1, true);

        expect(account.balance).toBe(0);
    });

    it('can falsify invalid outgoing transaction', (done) => {
        (async () => {
            const signature = Signature.unserialize(BufferUtils.fromBase64(Dummy.signature1));

            const transaction = new BasicTransaction(pubKey, recipient, 100, 0, 0, signature);

            expect(await BasicAccount.verifyOutgoingTransaction(transaction)).toBeFalsy();
        })().then(done, done.fail);
    });

    it('can verify valid outgoing transaction', (done) => {
        (async () => {
            const keyPair = KeyPair.generate();

            const transaction = new BasicTransaction(keyPair.publicKey, recipient, 100, 0, 0);
            transaction.signature = Signature.create(keyPair.privateKey, keyPair.publicKey, transaction.serializeContent());

            expect(await BasicAccount.verifyOutgoingTransaction(transaction)).toBeTruthy();
        })().then(done, done.fail);
    });

    it('can apply outgoing transaction', () => {
        let account = new BasicAccount(100);

        expect(account.balance).toBe(100);

        const cache = new TransactionCache();
        let transaction = new BasicTransaction(pubKey, recipient, 1, 0, 0);
        account = account.withOutgoingTransaction(transaction, 1, cache);

        expect(account.balance).toBe(99);

        transaction = new BasicTransaction(pubKey, recipient, 50, 0, 1);
        account = account.withOutgoingTransaction(transaction, 2, cache);

        expect(account.balance).toBe(49);
    });

    it('refuses to apply invalid outgoing transaction', () => {
        const account = new BasicAccount(100);

        const cache = new TransactionCache();
        let transaction = new BasicTransaction(pubKey, recipient, 1, 0, 4);
        expect(() => account.withOutgoingTransaction(transaction, 1, cache)).toThrowError('Validity Error!');

        transaction = new BasicTransaction(pubKey, recipient, 101, 0, 0);
        expect(() => account.withOutgoingTransaction(transaction, 1, cache)).toThrowError('Balance Error!');

        transaction = new BasicTransaction(pubKey, recipient, 1, 0, 0);
        cache.transactions.add(transaction.hash());
        expect(() => account.withOutgoingTransaction(transaction, 1, cache)).toThrowError('Double Transaction Error!');
    });

    it('can revert outgoing transaction', () => {
        let account = new BasicAccount(100);

        expect(account.balance).toBe(100);

        const cache = new TransactionCache();
        const transaction = new BasicTransaction(pubKey, recipient, 1, 0, 0);
        account = account.withOutgoingTransaction(transaction, 1, cache);

        expect(account.balance).toBe(99);
        cache.transactions.add(transaction.hash());

        account = account.withOutgoingTransaction(transaction, 1, cache, true);

        expect(account.balance).toBe(100);
    });

    it('has toString method', (done) => {
        (async function () {
            const account = new BasicAccount(100);
            expect(() => account.toString()).not.toThrow();
        })().then(done, done.fail);
    });
});