101 lines
3.3 KiB
Dart
101 lines
3.3 KiB
Dart
import 'package:flutter_test/flutter_test.dart';
|
||
import 'package:new_budget/src/core/database/converters/enum_converters.dart';
|
||
import 'package:new_budget/src/features/notification_parsing/data/parser/regex_parser.dart';
|
||
import 'package:new_budget/src/features/notification_parsing/domain/entities/raw_message.dart';
|
||
import 'package:new_budget/src/features/notification_parsing/domain/enums.dart';
|
||
|
||
RawMessage _msg(String body, {String pkg = 'ru.sberbankmobile'}) {
|
||
final now = DateTime(2026, 5, 29, 14, 5);
|
||
return RawMessage(
|
||
id: 'm1',
|
||
userId: 'u1',
|
||
packageName: pkg,
|
||
body: body,
|
||
receivedAt: now,
|
||
dedupHash: 'h',
|
||
status: RawMessageStatus.pending,
|
||
createdAt: now,
|
||
);
|
||
}
|
||
|
||
void main() {
|
||
const parser = RegexParser();
|
||
|
||
group('parseAmountMinor', () {
|
||
test('plain integer → minor units', () {
|
||
expect(parseAmountMinor('1240'), 124000);
|
||
});
|
||
|
||
test('RU thousands separator + decimal comma', () {
|
||
expect(parseAmountMinor('1 240,50'), 124050);
|
||
});
|
||
|
||
test('dot decimal', () {
|
||
expect(parseAmountMinor('99.90'), 9990);
|
||
});
|
||
|
||
test('trailing dot in 3-digit group is NOT a decimal', () {
|
||
// «1.240» — точка как разделитель тысяч (3 цифры после) → 124000.
|
||
expect(parseAmountMinor('1.240'), 124000);
|
||
});
|
||
|
||
test('empty / garbage → null', () {
|
||
expect(parseAmountMinor(''), isNull);
|
||
expect(parseAmountMinor(' '), isNull);
|
||
});
|
||
});
|
||
|
||
group('RegexParser.parse', () {
|
||
test('purchase amount→card→merchant (Сбер-подобный)', () {
|
||
final d = parser.parse(
|
||
_msg('Покупка 1240р Карта *3456 PYATEROCHKA 14:05 Баланс: 5000р'),
|
||
);
|
||
expect(d, isNotNull);
|
||
expect(d!.type, TransactionType.expense);
|
||
expect(d.amount, 124000);
|
||
expect(d.cardLast4, '3456');
|
||
expect(d.merchantRaw, 'PYATEROCHKA');
|
||
expect(d.source, ParseSource.regex);
|
||
expect(d.kind, TxKind.purchase);
|
||
});
|
||
|
||
test('purchase card→amount→merchant (Тинькофф-подобный)', () {
|
||
final d = parser.parse(
|
||
_msg('Покупка. Карта *3456. 1 240 ₽. Пятёрочка. Доступно 5 000 ₽'),
|
||
);
|
||
expect(d, isNotNull);
|
||
expect(d!.type, TransactionType.expense);
|
||
expect(d.amount, 124000);
|
||
expect(d.cardLast4, '3456');
|
||
expect(d.merchantRaw, 'Пятёрочка');
|
||
});
|
||
|
||
test('income (зачисление)', () {
|
||
final d = parser.parse(_msg('Зачисление 5000 ₽ Карта *3456 Зарплата'));
|
||
expect(d, isNotNull);
|
||
expect(d!.type, TransactionType.income);
|
||
expect(d.amount, 500000);
|
||
expect(d.cardLast4, '3456');
|
||
});
|
||
|
||
test('SBP transfer by phone', () {
|
||
final d = parser.parse(_msg('Перевод 1000 ₽ на +79991234567 успешно'));
|
||
expect(d, isNotNull);
|
||
expect(d!.amount, 100000);
|
||
expect(d.counterpartyPhone, '+79991234567');
|
||
});
|
||
|
||
test('refund → income', () {
|
||
final d = parser.parse(_msg('Возврат 1240 ₽ Карта *3456'));
|
||
expect(d, isNotNull);
|
||
expect(d!.type, TransactionType.income);
|
||
expect(d.amount, 124000);
|
||
});
|
||
|
||
test('non-matching body → null', () {
|
||
expect(parser.parse(_msg('Ваш баланс по карте *3456 составляет 5000 ₽')),
|
||
isNull);
|
||
});
|
||
});
|
||
}
|