mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-11-06 12:27:41 +00:00
352 lines
10 KiB
Dart
352 lines
10 KiB
Dart
import 'package:decimal/decimal.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:mockito/annotations.dart';
|
|
import 'package:mockito/mockito.dart';
|
|
import 'package:stackwallet/electrumx_rpc/electrumx.dart';
|
|
import 'package:stackwallet/models/balance.dart';
|
|
import 'package:stackwallet/models/isar/models/isar_models.dart';
|
|
import 'package:stackwallet/models/paymint/fee_object_model.dart';
|
|
import 'package:stackwallet/services/coins/coin_service.dart';
|
|
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
|
|
import 'package:stackwallet/services/coins/manager.dart';
|
|
import 'package:stackwallet/utilities/amount/amount.dart';
|
|
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
|
|
|
import 'manager_test.mocks.dart';
|
|
|
|
/// quick amount constructor wrapper. Using an int is bad practice but for
|
|
/// testing with small amounts this should be fine
|
|
Amount _a(int i) => Amount.fromDecimal(
|
|
Decimal.fromInt(i),
|
|
fractionDigits: 8,
|
|
);
|
|
|
|
@GenerateMocks([FiroWallet, ElectrumX])
|
|
void main() {
|
|
test("Manager should have a backgroundRefreshListener on initialization", () {
|
|
final manager = Manager(MockFiroWallet());
|
|
|
|
expect(manager.hasBackgroundRefreshListener, true);
|
|
});
|
|
|
|
test("get coin", () {
|
|
final CoinServiceAPI wallet = MockFiroWallet();
|
|
when(wallet.coin).thenAnswer((_) => Coin.firo);
|
|
final manager = Manager(wallet);
|
|
|
|
expect(manager.coin, Coin.firo);
|
|
});
|
|
|
|
test("fees", () async {
|
|
final CoinServiceAPI wallet = MockFiroWallet();
|
|
when(wallet.fees).thenAnswer((_) async => FeeObject(
|
|
fast: 10,
|
|
medium: 5,
|
|
slow: 1,
|
|
numberOfBlocksFast: 4,
|
|
numberOfBlocksSlow: 2,
|
|
numberOfBlocksAverage: 3));
|
|
|
|
final manager = Manager(wallet);
|
|
|
|
final feeObject = await manager.fees;
|
|
|
|
expect(feeObject.fast, 10);
|
|
expect(feeObject.medium, 5);
|
|
expect(feeObject.slow, 1);
|
|
expect(feeObject.numberOfBlocksFast, 4);
|
|
expect(feeObject.numberOfBlocksAverage, 3);
|
|
expect(feeObject.numberOfBlocksSlow, 2);
|
|
});
|
|
|
|
test("maxFee", () async {
|
|
final CoinServiceAPI wallet = MockFiroWallet();
|
|
when(wallet.maxFee).thenAnswer((_) async => 10);
|
|
|
|
final manager = Manager(wallet);
|
|
|
|
final fee = await manager.maxFee;
|
|
|
|
expect(fee, 10);
|
|
});
|
|
|
|
test("get currentReceivingAddress", () async {
|
|
final CoinServiceAPI wallet = MockFiroWallet();
|
|
when(wallet.currentReceivingAddress)
|
|
.thenAnswer((_) async => "Some address string");
|
|
|
|
final manager = Manager(wallet);
|
|
|
|
expect(await manager.currentReceivingAddress, "Some address string");
|
|
});
|
|
|
|
group("get balances", () {
|
|
test("balance", () async {
|
|
final CoinServiceAPI wallet = MockFiroWallet();
|
|
final balance = Balance(
|
|
total: _a(10),
|
|
spendable: _a(1),
|
|
blockedTotal: _a(0),
|
|
pendingSpendable: _a(9),
|
|
);
|
|
|
|
when(wallet.coin).thenAnswer((_) => Coin.firo);
|
|
when(wallet.balance).thenAnswer(
|
|
(_) => balance,
|
|
);
|
|
|
|
final manager = Manager(wallet);
|
|
|
|
expect(manager.balance, balance);
|
|
});
|
|
});
|
|
|
|
test("transactions", () async {
|
|
final CoinServiceAPI wallet = MockFiroWallet();
|
|
|
|
when(wallet.coin).thenAnswer((realInvocation) => Coin.firo);
|
|
|
|
final tx = Transaction(
|
|
walletId: "walletId",
|
|
txid: "txid",
|
|
timestamp: 6,
|
|
type: TransactionType.incoming,
|
|
subType: TransactionSubType.mint,
|
|
amount: 123,
|
|
amountString: Amount(
|
|
rawValue: BigInt.from(123),
|
|
fractionDigits: wallet.coin.decimals,
|
|
).toJsonString(),
|
|
fee: 3,
|
|
height: 123,
|
|
isCancelled: false,
|
|
isLelantus: true,
|
|
slateId: null,
|
|
otherData: null,
|
|
nonce: null,
|
|
inputs: [],
|
|
outputs: [],
|
|
numberOfMessages: null,
|
|
);
|
|
when(wallet.transactions).thenAnswer((_) async => [
|
|
tx,
|
|
]);
|
|
|
|
final manager = Manager(wallet);
|
|
|
|
final result = await manager.transactions;
|
|
|
|
expect(result.length, 1);
|
|
|
|
expect(result.first, tx);
|
|
});
|
|
|
|
test("refresh", () async {
|
|
final CoinServiceAPI wallet = MockFiroWallet();
|
|
when(wallet.refresh()).thenAnswer((_) => Future(() => {}));
|
|
|
|
final manager = Manager(wallet);
|
|
|
|
await manager.refresh();
|
|
|
|
verify(wallet.refresh()).called(1);
|
|
});
|
|
|
|
test("get walletName", () {
|
|
final CoinServiceAPI wallet = MockFiroWallet();
|
|
when(wallet.walletName).thenAnswer((_) => "Some wallet name");
|
|
final manager = Manager(wallet);
|
|
|
|
expect(manager.walletName, "Some wallet name");
|
|
});
|
|
|
|
test("get walletId", () {
|
|
final CoinServiceAPI wallet = MockFiroWallet();
|
|
when(wallet.walletId).thenAnswer((_) => "Some wallet ID");
|
|
|
|
final manager = Manager(wallet);
|
|
|
|
expect(manager.walletId, "Some wallet ID");
|
|
});
|
|
|
|
group("validateAddress", () {
|
|
test("some valid address", () {
|
|
final CoinServiceAPI wallet = MockFiroWallet();
|
|
when(wallet.validateAddress("a valid address")).thenAnswer((_) => true);
|
|
|
|
final manager = Manager(wallet);
|
|
|
|
expect(manager.validateAddress("a valid address"), true);
|
|
});
|
|
|
|
test("some invalid address", () {
|
|
final CoinServiceAPI wallet = MockFiroWallet();
|
|
when(wallet.validateAddress("an invalid address"))
|
|
.thenAnswer((_) => false);
|
|
|
|
final manager = Manager(wallet);
|
|
|
|
expect(manager.validateAddress("an invalid address"), false);
|
|
});
|
|
});
|
|
|
|
test("get mnemonic", () async {
|
|
final CoinServiceAPI wallet = MockFiroWallet();
|
|
when(wallet.mnemonic)
|
|
.thenAnswer((_) async => ["Some", "seed", "word", "list"]);
|
|
|
|
final manager = Manager(wallet);
|
|
|
|
expect(await manager.mnemonic, ["Some", "seed", "word", "list"]);
|
|
});
|
|
|
|
test("testNetworkConnection", () async {
|
|
final CoinServiceAPI wallet = MockFiroWallet();
|
|
when(wallet.testNetworkConnection()).thenAnswer((_) async => true);
|
|
|
|
final manager = Manager(wallet);
|
|
|
|
expect(await manager.testNetworkConnection(), true);
|
|
});
|
|
|
|
group("recoverFromMnemonic", () {
|
|
test("successfully recover", () async {
|
|
final CoinServiceAPI wallet = MockFiroWallet();
|
|
when(wallet.recoverFromMnemonic(
|
|
mnemonic: "Some valid mnemonic",
|
|
maxUnusedAddressGap: 20,
|
|
maxNumberOfIndexesToCheck: 1000,
|
|
height: 0))
|
|
.thenAnswer((realInvocation) => Future(() => {}));
|
|
|
|
final manager = Manager(wallet);
|
|
|
|
await manager.recoverFromMnemonic(
|
|
mnemonic: "Some valid mnemonic",
|
|
maxUnusedAddressGap: 20,
|
|
maxNumberOfIndexesToCheck: 1000,
|
|
height: 0);
|
|
|
|
verify(wallet.recoverFromMnemonic(
|
|
mnemonic: "Some valid mnemonic",
|
|
maxUnusedAddressGap: 20,
|
|
maxNumberOfIndexesToCheck: 1000,
|
|
height: 0))
|
|
.called(1);
|
|
});
|
|
|
|
test("failed recovery", () async {
|
|
final CoinServiceAPI wallet = MockFiroWallet();
|
|
when(wallet.recoverFromMnemonic(
|
|
mnemonic: "Some invalid mnemonic",
|
|
maxUnusedAddressGap: 20,
|
|
maxNumberOfIndexesToCheck: 1000,
|
|
height: 0))
|
|
.thenThrow(Exception("Invalid mnemonic"));
|
|
|
|
final manager = Manager(wallet);
|
|
|
|
expect(
|
|
() => manager.recoverFromMnemonic(
|
|
mnemonic: "Some invalid mnemonic",
|
|
maxUnusedAddressGap: 20,
|
|
maxNumberOfIndexesToCheck: 1000,
|
|
height: 0),
|
|
throwsA(isA<Exception>()));
|
|
|
|
verify(wallet.recoverFromMnemonic(
|
|
mnemonic: "Some invalid mnemonic",
|
|
maxUnusedAddressGap: 20,
|
|
maxNumberOfIndexesToCheck: 1000,
|
|
height: 0))
|
|
.called(1);
|
|
});
|
|
|
|
test("failed recovery due to some other error", () async {
|
|
final CoinServiceAPI wallet = MockFiroWallet();
|
|
when(wallet.recoverFromMnemonic(
|
|
mnemonic: "Some valid mnemonic",
|
|
maxUnusedAddressGap: 20,
|
|
maxNumberOfIndexesToCheck: 1000,
|
|
height: 0))
|
|
.thenThrow(Error());
|
|
|
|
final manager = Manager(wallet);
|
|
|
|
expect(
|
|
() => manager.recoverFromMnemonic(
|
|
mnemonic: "Some valid mnemonic",
|
|
maxUnusedAddressGap: 20,
|
|
maxNumberOfIndexesToCheck: 1000,
|
|
height: 0),
|
|
throwsA(isA<Error>()));
|
|
|
|
verify(wallet.recoverFromMnemonic(
|
|
mnemonic: "Some valid mnemonic",
|
|
maxUnusedAddressGap: 20,
|
|
maxNumberOfIndexesToCheck: 1000,
|
|
height: 0))
|
|
.called(1);
|
|
});
|
|
});
|
|
|
|
test("exitCurrentWallet", () async {
|
|
final CoinServiceAPI wallet = MockFiroWallet();
|
|
when(wallet.exit()).thenAnswer((realInvocation) => Future(() => {}));
|
|
when(wallet.walletId).thenAnswer((realInvocation) => "some id");
|
|
when(wallet.walletName).thenAnswer((realInvocation) => "some name");
|
|
|
|
final manager = Manager(wallet);
|
|
|
|
await manager.exitCurrentWallet();
|
|
|
|
verify(wallet.exit()).called(1);
|
|
verify(wallet.walletName).called(1);
|
|
verify(wallet.walletId).called(1);
|
|
|
|
expect(manager.hasBackgroundRefreshListener, false);
|
|
});
|
|
|
|
test("dispose", () async {
|
|
final CoinServiceAPI wallet = MockFiroWallet();
|
|
when(wallet.exit()).thenAnswer((realInvocation) => Future(() => {}));
|
|
when(wallet.walletId).thenAnswer((realInvocation) => "some id");
|
|
when(wallet.walletName).thenAnswer((realInvocation) => "some name");
|
|
|
|
final manager = Manager(wallet);
|
|
|
|
expect(() => manager.dispose(), returnsNormally);
|
|
});
|
|
|
|
test("fullRescan succeeds", () {
|
|
final CoinServiceAPI wallet = MockFiroWallet();
|
|
when(wallet.fullRescan(20, 1000)).thenAnswer((_) async {});
|
|
|
|
final manager = Manager(wallet);
|
|
|
|
expect(() => manager.fullRescan(20, 1000), returnsNormally);
|
|
});
|
|
|
|
test("fullRescan fails", () {
|
|
final CoinServiceAPI wallet = MockFiroWallet();
|
|
when(wallet.fullRescan(20, 1000)).thenThrow(Exception());
|
|
|
|
final manager = Manager(wallet);
|
|
|
|
expect(() => manager.fullRescan(20, 1000), throwsA(isA<Exception>()));
|
|
});
|
|
|
|
// test("act on event", () async {
|
|
// final CoinServiceAPI wallet = MockFiroWallet();
|
|
// when(wallet.exit()).thenAnswer((realInvocation) => Future(() => {}));
|
|
//
|
|
// final manager = Manager(wallet);
|
|
//
|
|
// expect(
|
|
// () => GlobalEventBus.instance.fire(UpdatedInBackgroundEvent(
|
|
// "act on event - test message", "wallet ID")),
|
|
// returnsNormally);
|
|
//
|
|
// expect(() => manager.dispose(), returnsNormally);
|
|
// });
|
|
}
|