main
  1import unittest
  2import json
  3import io
  4from check_bounding_boxes import get_bounding_box_messages
  5
  6
  7# Currently this is not run automatically in CI; it's just for documentation and manual checking.
  8class TestGetBoundingBoxMessages(unittest.TestCase):
  9    
 10    def create_json_stream(self, data):
 11        """Helper to create a JSON stream from data"""
 12        return io.StringIO(json.dumps(data))
 13    
 14    def test_no_intersections(self):
 15        """Test case with no bounding box intersections"""
 16        data = {
 17            "form_fields": [
 18                {
 19                    "description": "Name",
 20                    "page_number": 1,
 21                    "label_bounding_box": [10, 10, 50, 30],
 22                    "entry_bounding_box": [60, 10, 150, 30]
 23                },
 24                {
 25                    "description": "Email",
 26                    "page_number": 1,
 27                    "label_bounding_box": [10, 40, 50, 60],
 28                    "entry_bounding_box": [60, 40, 150, 60]
 29                }
 30            ]
 31        }
 32        
 33        stream = self.create_json_stream(data)
 34        messages = get_bounding_box_messages(stream)
 35        self.assertTrue(any("SUCCESS" in msg for msg in messages))
 36        self.assertFalse(any("FAILURE" in msg for msg in messages))
 37    
 38    def test_label_entry_intersection_same_field(self):
 39        """Test intersection between label and entry of the same field"""
 40        data = {
 41            "form_fields": [
 42                {
 43                    "description": "Name",
 44                    "page_number": 1,
 45                    "label_bounding_box": [10, 10, 60, 30],
 46                    "entry_bounding_box": [50, 10, 150, 30]  # Overlaps with label
 47                }
 48            ]
 49        }
 50        
 51        stream = self.create_json_stream(data)
 52        messages = get_bounding_box_messages(stream)
 53        self.assertTrue(any("FAILURE" in msg and "intersection" in msg for msg in messages))
 54        self.assertFalse(any("SUCCESS" in msg for msg in messages))
 55    
 56    def test_intersection_between_different_fields(self):
 57        """Test intersection between bounding boxes of different fields"""
 58        data = {
 59            "form_fields": [
 60                {
 61                    "description": "Name",
 62                    "page_number": 1,
 63                    "label_bounding_box": [10, 10, 50, 30],
 64                    "entry_bounding_box": [60, 10, 150, 30]
 65                },
 66                {
 67                    "description": "Email",
 68                    "page_number": 1,
 69                    "label_bounding_box": [40, 20, 80, 40],  # Overlaps with Name's boxes
 70                    "entry_bounding_box": [160, 10, 250, 30]
 71                }
 72            ]
 73        }
 74        
 75        stream = self.create_json_stream(data)
 76        messages = get_bounding_box_messages(stream)
 77        self.assertTrue(any("FAILURE" in msg and "intersection" in msg for msg in messages))
 78        self.assertFalse(any("SUCCESS" in msg for msg in messages))
 79    
 80    def test_different_pages_no_intersection(self):
 81        """Test that boxes on different pages don't count as intersecting"""
 82        data = {
 83            "form_fields": [
 84                {
 85                    "description": "Name",
 86                    "page_number": 1,
 87                    "label_bounding_box": [10, 10, 50, 30],
 88                    "entry_bounding_box": [60, 10, 150, 30]
 89                },
 90                {
 91                    "description": "Email",
 92                    "page_number": 2,
 93                    "label_bounding_box": [10, 10, 50, 30],  # Same coordinates but different page
 94                    "entry_bounding_box": [60, 10, 150, 30]
 95                }
 96            ]
 97        }
 98        
 99        stream = self.create_json_stream(data)
100        messages = get_bounding_box_messages(stream)
101        self.assertTrue(any("SUCCESS" in msg for msg in messages))
102        self.assertFalse(any("FAILURE" in msg for msg in messages))
103    
104    def test_entry_height_too_small(self):
105        """Test that entry box height is checked against font size"""
106        data = {
107            "form_fields": [
108                {
109                    "description": "Name",
110                    "page_number": 1,
111                    "label_bounding_box": [10, 10, 50, 30],
112                    "entry_bounding_box": [60, 10, 150, 20],  # Height is 10
113                    "entry_text": {
114                        "font_size": 14  # Font size larger than height
115                    }
116                }
117            ]
118        }
119        
120        stream = self.create_json_stream(data)
121        messages = get_bounding_box_messages(stream)
122        self.assertTrue(any("FAILURE" in msg and "height" in msg for msg in messages))
123        self.assertFalse(any("SUCCESS" in msg for msg in messages))
124    
125    def test_entry_height_adequate(self):
126        """Test that adequate entry box height passes"""
127        data = {
128            "form_fields": [
129                {
130                    "description": "Name",
131                    "page_number": 1,
132                    "label_bounding_box": [10, 10, 50, 30],
133                    "entry_bounding_box": [60, 10, 150, 30],  # Height is 20
134                    "entry_text": {
135                        "font_size": 14  # Font size smaller than height
136                    }
137                }
138            ]
139        }
140        
141        stream = self.create_json_stream(data)
142        messages = get_bounding_box_messages(stream)
143        self.assertTrue(any("SUCCESS" in msg for msg in messages))
144        self.assertFalse(any("FAILURE" in msg for msg in messages))
145    
146    def test_default_font_size(self):
147        """Test that default font size is used when not specified"""
148        data = {
149            "form_fields": [
150                {
151                    "description": "Name",
152                    "page_number": 1,
153                    "label_bounding_box": [10, 10, 50, 30],
154                    "entry_bounding_box": [60, 10, 150, 20],  # Height is 10
155                    "entry_text": {}  # No font_size specified, should use default 14
156                }
157            ]
158        }
159        
160        stream = self.create_json_stream(data)
161        messages = get_bounding_box_messages(stream)
162        self.assertTrue(any("FAILURE" in msg and "height" in msg for msg in messages))
163        self.assertFalse(any("SUCCESS" in msg for msg in messages))
164    
165    def test_no_entry_text(self):
166        """Test that missing entry_text doesn't cause height check"""
167        data = {
168            "form_fields": [
169                {
170                    "description": "Name",
171                    "page_number": 1,
172                    "label_bounding_box": [10, 10, 50, 30],
173                    "entry_bounding_box": [60, 10, 150, 20]  # Small height but no entry_text
174                }
175            ]
176        }
177        
178        stream = self.create_json_stream(data)
179        messages = get_bounding_box_messages(stream)
180        self.assertTrue(any("SUCCESS" in msg for msg in messages))
181        self.assertFalse(any("FAILURE" in msg for msg in messages))
182    
183    def test_multiple_errors_limit(self):
184        """Test that error messages are limited to prevent excessive output"""
185        fields = []
186        # Create many overlapping fields
187        for i in range(25):
188            fields.append({
189                "description": f"Field{i}",
190                "page_number": 1,
191                "label_bounding_box": [10, 10, 50, 30],  # All overlap
192                "entry_bounding_box": [20, 15, 60, 35]   # All overlap
193            })
194        
195        data = {"form_fields": fields}
196        
197        stream = self.create_json_stream(data)
198        messages = get_bounding_box_messages(stream)
199        # Should abort after ~20 messages
200        self.assertTrue(any("Aborting" in msg for msg in messages))
201        # Should have some FAILURE messages but not hundreds
202        failure_count = sum(1 for msg in messages if "FAILURE" in msg)
203        self.assertGreater(failure_count, 0)
204        self.assertLess(len(messages), 30)  # Should be limited
205    
206    def test_edge_touching_boxes(self):
207        """Test that boxes touching at edges don't count as intersecting"""
208        data = {
209            "form_fields": [
210                {
211                    "description": "Name",
212                    "page_number": 1,
213                    "label_bounding_box": [10, 10, 50, 30],
214                    "entry_bounding_box": [50, 10, 150, 30]  # Touches at x=50
215                }
216            ]
217        }
218        
219        stream = self.create_json_stream(data)
220        messages = get_bounding_box_messages(stream)
221        self.assertTrue(any("SUCCESS" in msg for msg in messages))
222        self.assertFalse(any("FAILURE" in msg for msg in messages))
223    
224
225if __name__ == '__main__':
226    unittest.main()