"""细胞产品来源链质检 — 节点展平与编排""" import unittest from unittest.mock import MagicMock, patch from app.crud.cell_product import _flatten_lineage_nodes, get_product_lineage_qc class TestFlattenLineageNodes(unittest.TestCase): def test_current_only_when_no_ancestors(self): chain = { "current": { "id": "cp-cur", "productCode": "C-CUR", "productName": "当前", "nodeType": "cell_product", "passage": "P2", "isCurrent": True, }, "ancestors": [], } nodes = _flatten_lineage_nodes(chain) self.assertEqual(len(nodes), 1) self.assertEqual(nodes[0]["id"], "cp-cur") self.assertTrue(nodes[0]["isCurrent"]) def test_sample_then_parent_then_current_order(self): sample = { "id": "s1", "nodeType": "sample", "sampleCode": "YB001", "receptionSource": "cell_storage", "receptionSourceLabel": "细胞存储", } parent = { "id": "cp-p1", "productCode": "C-P1", "productName": "父代", "nodeType": "cell_product", "passage": "P1", "isCurrent": False, } current = { "id": "cp-cur", "productCode": "C-CUR", "productName": "当前", "nodeType": "cell_product", "passage": "P2", "isCurrent": True, } chain = { "current": current, "ancestors": [ { "node": parent, "edge": {}, "parent": {"node": sample, "edge": {}, "parent": None}, } ], } nodes = _flatten_lineage_nodes(chain) self.assertEqual([n["id"] for n in nodes], ["s1", "cp-p1", "cp-cur"]) self.assertEqual(nodes[0]["nodeType"], "sample") self.assertTrue(nodes[-1]["isCurrent"]) def test_dedupe_same_node_type_and_id(self): parent = { "id": "cp-p1", "nodeType": "cell_product", "productCode": "C-P1", "productName": "父", "passage": "P1", "isCurrent": False, } current = { "id": "cp-cur", "nodeType": "cell_product", "productCode": "C-CUR", "productName": "当前", "passage": "P2", "isCurrent": True, } chain = { "current": current, "ancestors": [ {"node": parent, "edge": {}, "parent": None}, {"node": dict(parent), "edge": {}, "parent": None}, ], } nodes = _flatten_lineage_nodes(chain) ids = [n["id"] for n in nodes] self.assertEqual(ids.count("cp-p1"), 1) self.assertEqual(ids[-1], "cp-cur") def test_parent_array_multi_input(self): s1 = {"id": "s1", "nodeType": "sample", "sampleCode": "A", "receptionSource": "cell_storage"} s2 = {"id": "s2", "nodeType": "sample", "sampleCode": "B", "receptionSource": "cell_storage"} parent = { "id": "cp-p1", "nodeType": "cell_product", "productCode": "P1", "productName": "父", "passage": "P1", "isCurrent": False, } current = { "id": "cp-cur", "nodeType": "cell_product", "productCode": "CUR", "productName": "当前", "passage": "P2", "isCurrent": True, } chain = { "current": current, "ancestors": [ { "node": parent, "edge": {}, "parent": [ {"node": s1, "edge": {}, "parent": None}, {"node": s2, "edge": {}, "parent": None}, ], } ], } nodes = _flatten_lineage_nodes(chain) ids = [n["id"] for n in nodes] self.assertIn("s1", ids) self.assertIn("s2", ids) self.assertEqual(ids[-1], "cp-cur") class TestGetProductLineageQc(unittest.TestCase): @patch("app.crud.cell_product.get_product_chain") @patch("app.crud.cell_product._load_lineage_qc_for_nodes") def test_missing_product_returns_none(self, _load, get_chain): get_chain.return_value = None db = MagicMock() self.assertIsNone(get_product_lineage_qc(db, "missing", "zkxw")) _load.assert_not_called() @patch("app.crud.cell_product.get_product_chain") @patch("app.crud.cell_product._load_lineage_qc_for_nodes") def test_returns_product_header_and_nodes(self, load_nodes, get_chain): get_chain.return_value = { "current": { "id": "cp1", "productCode": "C1", "productName": "产品1", "nodeType": "cell_product", "passage": "P1", "isCurrent": True, }, "ancestors": [], } load_nodes.return_value = [ { "nodeType": "cell_product", "id": "cp1", "label": "C1", "productName": "产品1", "passage": "P1", "receptionSource": None, "isCurrent": True, "workOrders": [ { "id": "wo1", "workOrderNo": "WO1", "workOrderType": "temporary", "workOrderStatus": "ywc", "workOrderStatusLabel": "已完成", "tasks": [ { "id": "t1", "taskNo": "T1", "itemName": "无菌", "results": [{"paramName": "结果", "paramValue": "阴性"}], "attachmentFiles": [], "remark": "", "conclusion": "tg", } ], } ], } ] db = MagicMock() out = get_product_lineage_qc(db, "cp1", "zkxw") self.assertEqual(out["productId"], "cp1") self.assertEqual(out["productCode"], "C1") self.assertEqual(len(out["nodes"]), 1) self.assertEqual( out["nodes"][0]["workOrders"][0]["tasks"][0]["results"][0]["paramValue"], "阴性", ) if __name__ == "__main__": unittest.main()