"""Tests for the incrementables parser service.""" import pytest from app.services.parser import IncrementablesParser, ParsingError, parse_incrementables # Sample text fixtures SAMPLE_TEXT_COMPLETE = """ CARTA INSTRUCTIVO DE EMBARQUE No. 228718 AJUSTE DE INCREMENTABLES EN: Fletes: $1,591.20 USD Seguros: $250.50 USD Almacenaje/Consolidación: $100.00 USD Regalías: $75.00 USD Total: $2,016.70 USD """ SAMPLE_TEXT_EMPTY_FIELDS = """ AJUSTE DE INCREMENTABLES EN: Fletes: $1,591.20 USD Seguros: USD Almacenaje/Consolidación: $0.00 USD Regalías: USD Observaciones: Los seguros y regalías están vacíos """ SAMPLE_TEXT_NO_ANCHOR = """ Este es un documento sin la sección de incrementables. Solo tiene texto normal sin el ancla esperada. """ SAMPLE_TEXT_VARIATIONS = """ INCREMENTABLES EN: Fletes: $2,500.00 USD Seguros: USD Almacenaje Consolidacion: $150.75 USD Regalias: $300.00 USD """ class TestIncrementablesParser: """Test cases for IncrementablesParser class.""" def test_parse_complete_data(self): """Test parsing with all fields present.""" parser = IncrementablesParser(SAMPLE_TEXT_COMPLETE) result = parser.parse() assert result["currency"] == "USD" assert result["fletes"] == 1591.20 assert result["seguros"] == 250.50 assert result["almacenaje_consolidacion"] == 100.00 assert result["regalias"] == 75.00 assert len(result["anchors_found"]) > 0 def test_parse_empty_fields(self): """Test parsing with empty seguros and regalias.""" parser = IncrementablesParser(SAMPLE_TEXT_EMPTY_FIELDS) result = parser.parse() assert result["currency"] == "USD" assert result["fletes"] == 1591.20 assert result["seguros"] is None assert result["almacenaje_consolidacion"] == 0.00 assert result["regalias"] is None def test_parse_no_anchor(self): """Test parsing fails when anchor not found.""" parser = IncrementablesParser(SAMPLE_TEXT_NO_ANCHOR) with pytest.raises(ParsingError) as exc_info: parser.parse() assert "not found" in str(exc_info.value).lower() def test_parse_variations(self): """Test parsing with text variations.""" parser = IncrementablesParser(SAMPLE_TEXT_VARIATIONS) result = parser.parse() assert result["currency"] == "USD" assert result["fletes"] == 2500.00 assert result["seguros"] is None assert result["almacenaje_consolidacion"] == 150.75 assert result["regalias"] == 300.00 def test_parse_amount_with_commas(self): """Test amount parsing with comma separators.""" parser = IncrementablesParser(SAMPLE_TEXT_COMPLETE) amount = parser._parse_amount("1,591.20") assert amount == 1591.20 def test_parse_amount_with_dollar(self): """Test amount parsing with dollar sign.""" parser = IncrementablesParser(SAMPLE_TEXT_COMPLETE) amount = parser._parse_amount("$1,591.20") assert amount == 1591.20 def test_parse_amount_empty(self): """Test amount parsing with empty string.""" parser = IncrementablesParser(SAMPLE_TEXT_COMPLETE) amount = parser._parse_amount("") assert amount is None def test_parse_amount_none(self): """Test amount parsing with None.""" parser = IncrementablesParser(SAMPLE_TEXT_COMPLETE) amount = parser._parse_amount(None) assert amount is None def test_extract_currency_default(self): """Test currency extraction defaults to USD.""" parser = IncrementablesParser("Text without currency") currency = parser._extract_currency("No currency here") assert currency == "USD" assert len(parser.warnings) > 0 assert "currency" in parser.warnings[0].lower() def test_find_incrementables_section(self): """Test finding incrementables section.""" parser = IncrementablesParser(SAMPLE_TEXT_COMPLETE) section = parser._find_incrementables_section() assert section is not None assert "Fletes" in section assert len(parser.anchors_found) > 0 def test_parse_incrementables_function(): """Test the main parse_incrementables function.""" result = parse_incrementables(SAMPLE_TEXT_COMPLETE) assert result["currency"] == "USD" assert result["fletes"] == 1591.20 assert "anchors_found" in result assert "warnings" in result def test_parse_incrementables_raises_error(): """Test parse_incrementables raises error on invalid input.""" with pytest.raises(ParsingError): parse_incrementables(SAMPLE_TEXT_NO_ANCHOR) class TestParserEdgeCases: """Test edge cases and error conditions.""" def test_missing_fletes(self): """Test that missing fletes raises error.""" text = """ AJUSTE DE INCREMENTABLES EN: Seguros: $100.00 USD Almacenaje: $50.00 USD """ parser = IncrementablesParser(text) with pytest.raises(ParsingError) as exc_info: parser.parse() assert "fletes" in str(exc_info.value).lower() def test_missing_almacenaje(self): """Test that missing almacenaje raises error.""" text = """ AJUSTE DE INCREMENTABLES EN: Fletes: $1000.00 USD Seguros: $100.00 USD """ parser = IncrementablesParser(text) with pytest.raises(ParsingError) as exc_info: parser.parse() assert "almacenaje" in str(exc_info.value).lower() def test_case_insensitive_anchor(self): """Test anchor detection is case insensitive.""" text_lower = "ajuste de incrementables en:\nFletes: $100.00 USD\nAlmacenaje: $50.00 USD" parser = IncrementablesParser(text_lower) section = parser._find_incrementables_section() assert section is not None def test_accent_variations_regalias(self): """Test that both 'regalías' and 'regalias' work.""" text_with_accent = """ AJUSTE DE INCREMENTABLES EN: Fletes: $100.00 USD Almacenaje: $50.00 USD Regalías: $25.00 USD """ parser = IncrementablesParser(text_with_accent) result = parser.parse() assert result["regalias"] == 25.00