OCR_Vehicle_01 / tests /test_layout.py
Esketch's picture
v28: Add PP-Structure layout analysis engine for form-aware OCR
a6c2f2d
Raw
History Blame Contribute Delete
5.98 kB
# -*- coding: utf-8 -*-
"""Tests for layout_engine.py and form_parser.py"""
import unittest
import sys
sys.stdout.reconfigure(encoding='utf-8')
class TestFormParser(unittest.TestCase):
"""Test FormParser with mock layout analysis results."""
def setUp(self):
from src.parser.form_parser import FormParser
self.parser = FormParser()
def _make_table(self, html, bbox=(0, 0, 800, 600)):
"""Helper to create a table result dict."""
return {'bbox': bbox, 'html': html, 'cells': []}
def test_extract_vehicle_no_from_table(self):
html = '<table><tr><td>자동차등록번호</td><td>서울 12가 3456</td></tr></table>'
layout = {'tables': [self._make_table(html)], 'text_regions': []}
fields = self.parser.parse_layout(layout)
self.assertIn('vehicle_no', fields)
self.assertIn('서울 12가 3456', fields['vehicle_no']['value'])
def test_extract_vin_from_table(self):
html = '<table><tr><td>차대번호</td><td>KMHD341DBNU123456</td></tr></table>'
layout = {'tables': [self._make_table(html)], 'text_regions': []}
fields = self.parser.parse_layout(layout)
self.assertIn('vin', fields)
self.assertEqual(fields['vin']['value'], 'KMHD341DBNU123456')
def test_extract_dimensions_from_table(self):
html = (
'<table>'
'<tr><td>길이</td><td>4,880</td><td>너비</td><td>1,860</td></tr>'
'<tr><td>높이</td><td>1,475</td><td>총중량</td><td>1,990</td></tr>'
'</table>'
)
layout = {'tables': [self._make_table(html)], 'text_regions': []}
fields = self.parser.parse_layout(layout)
self.assertEqual(fields['length_mm']['value'], '4880')
self.assertEqual(fields['width_mm']['value'], '1860')
self.assertEqual(fields['height_mm']['value'], '1475')
self.assertEqual(fields['total_weight_kg']['value'], '1990')
def test_extract_owner_name_from_table(self):
html = '<table><tr><td>성명(명칭)</td><td>홍길동</td></tr></table>'
layout = {'tables': [self._make_table(html)], 'text_regions': []}
fields = self.parser.parse_layout(layout)
self.assertIn('owner_name', fields)
self.assertEqual(fields['owner_name']['value'], '홍길동')
def test_extract_from_text_regions(self):
regions = [
{'bbox': (100, 100, 200, 130), 'text': '차명', 'confidence': 0.95, 'region_type': 'text'},
{'bbox': (220, 100, 400, 130), 'text': '쏘나타', 'confidence': 0.92, 'region_type': 'text'},
]
layout = {'tables': [], 'text_regions': regions}
fields = self.parser.parse_layout(layout, img_height=800, img_width=600)
self.assertIn('model_name', fields)
self.assertEqual(fields['model_name']['value'], '쏘나타')
def test_circled_number_labels_matched(self):
html = '<table><tr><td>②차종</td><td>승용차</td></tr></table>'
layout = {'tables': [self._make_table(html)], 'text_regions': []}
fields = self.parser.parse_layout(layout)
self.assertIn('vehicle_type', fields)
self.assertEqual(fields['vehicle_type']['value'], '승용차')
def test_empty_layout_returns_empty(self):
layout = {'tables': [], 'text_regions': []}
fields = self.parser.parse_layout(layout)
self.assertEqual(fields, {})
def test_registration_date_cleaned(self):
html = '<table><tr><td>최초등록일</td><td>2020년 01월 15일</td></tr></table>'
layout = {'tables': [self._make_table(html)], 'text_regions': []}
fields = self.parser.parse_layout(layout)
self.assertIn('registration_date', fields)
self.assertIn('2020', fields['registration_date']['value'])
def test_model_year_extracted(self):
html = '<table><tr><td>연식</td><td>2023</td></tr></table>'
layout = {'tables': [self._make_table(html)], 'text_regions': []}
fields = self.parser.parse_layout(layout)
self.assertEqual(fields['model_year']['value'], '2023')
def test_passenger_capacity_digits_only(self):
html = '<table><tr><td>승차정원</td><td>5명</td></tr></table>'
layout = {'tables': [self._make_table(html)], 'text_regions': []}
fields = self.parser.parse_layout(layout)
self.assertEqual(fields['passenger_capacity']['value'], '5')
def test_label_not_used_as_value(self):
"""Label cell followed by another label should not produce a field."""
html = '<table><tr><td>차종</td><td>차명</td></tr></table>'
layout = {'tables': [self._make_table(html)], 'text_regions': []}
fields = self.parser.parse_layout(layout)
# 차명 is also a label, so 차종 should not get 차명 as its value
if 'vehicle_type' in fields:
self.assertNotEqual(fields['vehicle_type']['value'], '차명')
class TestLayoutEngine(unittest.TestCase):
"""Test LayoutEngine initialization and graceful degradation."""
def test_parse_table_html(self):
from src.ocr.layout_engine import LayoutEngine
cells = LayoutEngine._parse_table_html(
'<table><tr><td>A</td><td>B</td></tr><tr><td>C</td><td>D</td></tr></table>'
)
self.assertEqual(len(cells), 4)
self.assertEqual(cells[0], {'row': 0, 'col': 0, 'text': 'A'})
self.assertEqual(cells[3], {'row': 1, 'col': 1, 'text': 'D'})
def test_parse_empty_html(self):
from src.ocr.layout_engine import LayoutEngine
cells = LayoutEngine._parse_table_html('')
self.assertEqual(cells, [])
def test_parse_nested_tags_stripped(self):
from src.ocr.layout_engine import LayoutEngine
cells = LayoutEngine._parse_table_html(
'<table><tr><td><b>Bold</b> text</td></tr></table>'
)
self.assertEqual(cells[0]['text'], 'Bold text')
if __name__ == '__main__':
unittest.main()