MO-Fuel-Tax-Back/test/vin_parser_test.dart

106 lines
3.9 KiB
Dart

import 'package:flutter_test/flutter_test.dart';
import 'package:fuel_tax_tracker/services/vin_parser.dart';
void main() {
group('VinParser', () {
test('parses a bare 17-character VIN', () {
const text = '''
VEHICLE IDENTIFICATION NUMBER
1HGCM82633A004352
MFD BY HONDA MFG CO
''';
expect(VinParser.parse(text), '1HGCM82633A004352');
});
test('prefers a "VIN:" labeled match over another candidate elsewhere', () {
const text = '''
PART NO 4F2CZ58899BA12345
VIN: 1HGCM82633A004352
''';
expect(VinParser.parse(text), '1HGCM82633A004352');
});
test('normalizes to uppercase', () {
expect(VinParser.parse('vin: 1hgcm82633a004352'), '1HGCM82633A004352');
});
test('normalizes an O to 0 — real VINs never contain one, so it reads as a misread zero', () {
// Real OCR output from a Kia/Hyundai data plate photo: "0" (zero)
// came back as "O" (letter) — this is exactly why I/O/Q are excluded
// from real VINs in the first place (too easily confused with
// 1/0/9), which cuts both ways for OCR reading one back off a plate.
expect(VinParser.parse('V.I.N 5XYZKDAG2BGO50982 TYPE:MPY'), '5XYZKDAG2BG050982');
});
test('normalizes an I to 1 the same way', () {
expect(VinParser.parse('VIN: 1HGCM82633AI04352'), '1HGCM82633A104352');
});
test('does not match a run containing Q — unlike I/O, not a plausible misread digit', () {
expect(VinParser.parse('1HGCM82633AQ04352'), isNull);
});
test('retries with whitespace stripped when OCR splits the VIN across a stray space', () {
// Real OCR output from an etched-glass VIN photo: a space landed
// mid-VIN (likely two separate detected text regions on the curved
// surface), so no single unbroken 17-character run exists until the
// whitespace is collapsed.
expect(VinParser.parse('5XYZKD AG2BG050982'), '5XYZKDAG2BG050982');
});
test('a whitespace-stripped retry is only a last resort, after a normal match is preferred',
() {
const text = '''
PART NO 4F2CZ 58899BA12345
VIN: 1HGCM82633A004352
''';
// The "VIN:"-labeled match (unaffected by the space in the unrelated
// part number above it) should win over anything the fallback might
// have found in the stripped text.
expect(VinParser.parse(text), '1HGCM82633A004352');
});
test('does not match a 16-character (too short) run', () {
expect(VinParser.parse('1HGCM82633A00435'), isNull);
});
test('does not match an 18-character (too long) run', () {
expect(VinParser.parse('1HGCM82633A0043521'), isNull);
});
test('returns null when nothing matches', () {
expect(VinParser.parse('THANK YOU FOR YOUR PURCHASE'), isNull);
});
test('matches a "V.I.N" label (period between each letter) — common on compliance/data plates',
() {
// Real text from a Kia/Hyundai-built data plate: "V.I.N" rather than
// "VIN:" — a manufacturer plate styling the labeled pattern didn't
// originally account for, so this fell through to relying on OCR
// reading the bare 17-char run cleanly.
const text = '''
THIS VEHICLE CONFORMS TO ALL APPLICABLE U.S.A. FEDERAL
MOTOR VEHICLE SAFETY AND THEFT PREVENTION STANDARDS
IN EFFECT ON THE DATE OF MANUFACTURE SHOWN ABOVE
V.I.N 5XYZKDAG2BG050982 TYPE:MPV
''';
expect(VinParser.parse(text), '5XYZKDAG2BG050982');
});
test('matches "V.I.N." with a trailing period too', () {
expect(VinParser.parse('V.I.N. 5XYZKDAG2BG050982'), '5XYZKDAG2BG050982');
});
test('a "V.I.N" labeled match is still preferred over another candidate elsewhere', () {
const text = '''
PART NO 4F2CZ58899BA12345
V.I.N 5XYZKDAG2BG050982
''';
expect(VinParser.parse(text), '5XYZKDAG2BG050982');
});
});
}