"""Business boundaries for extracted pure rules; no model service is contacted.""" from datetime import datetime from pathlib import Path import subprocess import sys import tempfile import unittest from unittest.mock import patch from logistics_chat import knowledge, pricing, tracking class RuleTests(unittest.TestCase): def test_specific_knowledge_wins_and_unknown_questions_have_no_match(self): for question in ('英国空运价格','英国空运多久','英国空运多少钱'): self.assertIn('22KG+', knowledge.search_knowledge(question)) self.assertIn('21KG+', knowledge.search_knowledge('欧洲空运价格')) self.assertIsNone(knowledge.search_knowledge('没有相关关键词的测试')) def test_sea_tier_boundary_and_minimum(self): self.assertEqual(pricing.calc_freight(100, 'sea')['price'], 12.3) self.assertEqual(pricing.calc_freight(101, 'sea')['price'], 10.3) self.assertEqual(pricing.calc_freight(1, 'sea')['total'], 258.3) self.assertEqual(pricing.calc_freight(1, 'air_uk')['charge'], 22) def test_large_air_shipments_use_the_highest_applicable_tier(self): self.assertEqual(pricing.calc_freight(2000, 'air')['total'], 72000) self.assertEqual(pricing.calc_freight(2000, 'air_uk')['total'], 84000) def test_volume_weight_and_unit_conversion(self): for dims, unit in (([100, 100, 100], 'cm'), ([1, 1, 1], 'm'), ([1000]*3, 'mm')): with self.subTest(unit=unit): result = pricing.calc_freight(20, 'sea', dims, unit) self.assertEqual(result['vol'], 166.67) self.assertEqual(result['charge'], 166.67) def test_shipping_intent_keeps_dimensions_separate_from_weight(self): intent = pricing.parse_shipping_intent('100x80x60 200kg 海运') self.assertEqual(intent['dims'], [100, 80, 60]) self.assertEqual(intent['weight'], 200) self.assertEqual(intent['channel'], 'sea') self.assertEqual(pricing.parse_shipping_intent('1吨铁路')['weight'], 1000) self.assertEqual(pricing.parse_shipping_intent('100 lbs air')['weight'], 45.36) self.assertEqual(pricing.parse_shipping_intent('1.2 x 0.8 x 0.6 m 30kg海运')['dims'],[1.2,0.8,0.6]) self.assertEqual(pricing.parse_shipping_intent('长10.5宽20.5高30.5')['dims'],[10.5,20.5,30.5]) def test_shipping_regions_distinguish_country_codes_from_english_pronouns(self): self.assertEqual(pricing.shipping_region('Give us a quote for 30kg to Germany'),'eu') self.assertEqual(pricing.shipping_region('30kg air to US'),'unsupported') self.assertEqual(pricing.shipping_region('30kg air to us'),'unsupported') self.assertEqual(pricing.shipping_region('30kg to UK'),'uk') self.assertEqual(pricing.shipping_region('30kg发UK海运'),'uk') self.assertEqual(pricing.shipping_region('30kg发US仓海运'),'unsupported') self.assertIsNone(pricing.shipping_region('talk about us and our work')) self.assertIsNone(pricing.shipping_region('30kg for UKEURO warehouse')) self.assertIsNone(pricing.shipping_region('2GB附件,30kg海运报价')) self.assertTrue(pricing.is_shipping_destination_reply('英国的FBA仓')) self.assertTrue(pricing.is_shipping_destination_reply('目的地是UK仓')) self.assertFalse(pricing.is_shipping_destination_reply('英国VAT费用是什么')) self.assertFalse(pricing.is_shipping_destination_reply('Give us a quote for 30kg to Germany')) def test_warehouse_country_and_surcharge(self): result = pricing.calc_warehouse_card(2, '海运', country='DE') self.assertIn('-DE', result['warehouse']) self.assertEqual(result['total'], 3472) product, fee = pricing.detect_surcharge('寄手机到德国') self.assertIn('手机', product) self.assertEqual(fee, '5/KG') self.assertIn('500', pricing.surcharge_reply(product, fee, 100)) self.assertEqual(pricing.check_island('07000')[1], 'IT') self.assertIsNone(pricing.check_island('not a postcode')) self.assertIsNone(pricing.calc_warehouse_card(2, '海运', country='GB')) self.assertIsNone(pricing.calc_warehouse_card(2, '海运', warehouse_key='unknown')) def test_tracking_recognition_and_card_context(self): self.assertEqual(tracking.extract_tracking_no('查询15252125'), '15252125') self.assertFalse(tracking.is_tracking_no('2026-10-28')) self.assertFalse(tracking.is_tracking_no('i want to go 1t how money')) with patch.object(tracking, 'datetime') as clock: clock.now.return_value = datetime(2026, 10, 28, 12) card = tracking.build_track('15252125') self.assertEqual(card, tracking.build_track('15252125')) self.assertEqual(card['status'], '派送中') self.assertEqual(len(card['nodes']), 6) self.assertIn('15252125', tracking.card_to_text('__CARD__{"no":"15252125","status":"派送中"}')) def test_pure_modules_import_without_site_packages_or_runtime_files(self): root = str(Path(__file__).resolve().parents[1]) code = ('import sys; sys.dont_write_bytecode=True; sys.path.insert(0, sys.argv[1]); ' 'import logistics_chat.knowledge, logistics_chat.pricing, logistics_chat.tracking; ' 'import logistics_chat.config, logistics_chat.db, logistics_chat.file_service; ' 'assert "flask" not in sys.modules; assert "requests" not in sys.modules') with tempfile.TemporaryDirectory() as directory: result = subprocess.run([sys.executable, '-S', '-c', code, root], cwd=directory, capture_output=True, text=True, timeout=15) self.assertEqual(result.returncode, 0, result.stderr) self.assertEqual(list(Path(directory).iterdir()), []) if __name__ == '__main__': unittest.main()