"""Тестовые рецепты LAB — полная матрица и «в нормах».""" from __future__ import annotations import unittest from app import create_app, db from app.lab.commands.seed_lab_math_ration import ( RECIPE_IN_NORMS, RECIPE_MATRIX, seed_lab_math_ration, ) from app.lab.commands.seed_math_test_profiles import seed_math_test_profiles from app.lab.loaders.ration_loader import load_ration from app.lab.nutrient_schema import read_from_mapping from app.models import Recipe from app.services.setup_state import mark_setup_complete from tests.helpers.zootech_test_helpers import ZootechTestConfig class LabMathRationSeedTests(unittest.TestCase): @classmethod def setUpClass(cls) -> None: cls.app = create_app(ZootechTestConfig) cls.ctx = cls.app.app_context() cls.ctx.push() db.create_all() mark_setup_complete(cls.app) @classmethod def tearDownClass(cls) -> None: db.session.remove() db.drop_all() cls.ctx.pop() def test_read_mapping_ca_not_dcab(self) -> None: data = {"Ca": 3.5, "DCAB Форм": 120.0} self.assertEqual(read_from_mapping(data, ("DCAB Форм", "DCAB")), 120.0) self.assertEqual(read_from_mapping(data, ("Ca",)), 3.5) def _snap(self, name: str): recipe = Recipe.query.filter_by(name=name, is_deleted=False).first() self.assertIsNotNone(recipe) return load_ration(recipe.id) def test_seed_matrix_recipe(self) -> None: seed_math_test_profiles() stats = seed_lab_math_ration(force=True) self.assertFalse(stats.errors, stats.errors) snap = self._snap(RECIPE_MATRIX) self.assertIn("rnb", snap.norms) labels = {i["label"] for i in (snap.ration_results.get("indicators") or [])} self.assertIn("RNB", labels) self.assertIn("Fe", labels) dm = next(i for i in snap.ration_results["indicators"] if i.get("key") == "dry_matter") self.assertGreater(dm["content"], 10000) cp = next(i for i in snap.ration_results["indicators"] if i.get("key") == "crude_protein") usp = next(i for i in snap.ration_results["indicators"] if i.get("key") == "usp") rnb = next(i for i in snap.ration_results["indicators"] if i.get("key") == "rnb") expected_rnb = (cp["content"] - usp["content"]) / 6.25 self.assertAlmostEqual(rnb["content"], expected_rnb, places=1) self.assertAlmostEqual(rnb["content"], 71.68, places=1) def test_seed_in_norms_mostly_green(self) -> None: seed_math_test_profiles() seed_lab_math_ration(force=True) snap = self._snap(RECIPE_IN_NORMS) indicators = snap.ration_results.get("indicators") or [] with_norm = [i for i in indicators if i.get("min") is not None or i.get("max") is not None] greens = [i for i in with_norm if abs(i.get("diff") or 0) < 0.01] reds = [i for i in with_norm if abs(i.get("diff") or 0) >= 0.01] self.assertGreaterEqual(len(greens), len(reds), f"reds: {[r['key'] for r in reds]}") dm = next(i for i in indicators if i.get("key") == "dry_matter") self.assertLess(dm["content"], 6500) sf = next(i for i in indicators if i.get("key") == "structural_fiber") self.assertGreaterEqual(sf["content"], sf["min"]) fat_pct = next(i for i in indicators if i.get("key") == "fat_pct_per_kg_dm") nfc_pct = next(i for i in indicators if i.get("key") == "nfc_pct_dm") cp_kg = next(i for i in indicators if i.get("key") == "cp_per_kg_dm") usp = next(i for i in indicators if i.get("key") == "usp") usp_kg = next(i for i in indicators if i.get("key") == "usp_per_kg_dm") self.assertAlmostEqual(fat_pct["content"], 3.5, delta=0.5) self.assertAlmostEqual(nfc_pct["content"], 23.0, delta=2.0) self.assertAlmostEqual(cp_kg["content"], 109.0, delta=15.0) dom = next(i for i in indicators if i.get("key") == "digestible_organic_matter") dig_nfe = next(i for i in indicators if i.get("key") == "digestible_nfe") self.assertGreater(usp_kg["content"], 0) self.assertAlmostEqual(usp_kg["content"], usp["content"] / (dm["content"] / 1000), delta=2.0) self.assertGreater(dom["content"], 0) self.assertGreater(dig_nfe["content"], 0)