33import unittest
44from pathlib import Path
55
6- from crypto_strategies import get_strategy_definitions
6+ from crypto_strategies import (
7+ get_strategy_definition ,
8+ get_strategy_definitions ,
9+ get_strategy_entrypoint ,
10+ get_strategy_index_rows ,
11+ get_strategy_metadata ,
12+ )
13+ from crypto_strategies .manifests import get_strategy_manifest
714from crypto_strategies .runtime_adapters import (
815 BINANCE_PLATFORM ,
916 CRYPTO_CANONICAL_REQUIRED_INPUTS ,
@@ -44,7 +51,9 @@ def test_every_compatible_platform_has_runtime_adapter_coverage(self) -> None:
4451 with self .subTest (profile = profile , platform_id = platform_id ):
4552 adapter = get_platform_runtime_adapter (profile , platform_id = platform_id )
4653 self .assertLessEqual (definition .required_inputs , adapter .available_inputs )
47- if definition .target_mode != PLATFORM_NATIVE_TARGET_MODES [platform_id ]:
54+ if "portfolio_snapshot" in definition .required_inputs :
55+ self .assertEqual (adapter .portfolio_input_name , "portfolio_snapshot" )
56+ elif definition .target_mode != PLATFORM_NATIVE_TARGET_MODES [platform_id ]:
4857 self .assertTrue (adapter .portfolio_input_name )
4958
5059 def test_runtime_adapter_map_matches_catalog_compatibility (self ) -> None :
@@ -59,6 +68,43 @@ def test_runtime_adapter_map_matches_catalog_compatibility(self) -> None:
5968 with self .subTest (platform_id = platform_id ):
6069 self .assertEqual (frozenset (adapters ), supported_profiles )
6170
71+ def test_manifest_matches_catalog_definition_and_metadata (self ) -> None :
72+ for profile in get_strategy_definitions ():
73+ definition = get_strategy_definition (profile )
74+ metadata = get_strategy_metadata (profile )
75+ manifest = get_strategy_manifest (profile )
76+ with self .subTest (profile = profile ):
77+ self .assertEqual (manifest .profile , definition .profile )
78+ self .assertEqual (manifest .domain , definition .domain )
79+ self .assertEqual (manifest .display_name , metadata .display_name )
80+ self .assertEqual (manifest .required_inputs , definition .required_inputs )
81+ self .assertEqual (dict (manifest .default_config ), dict (definition .default_config ))
82+
83+ def test_entrypoint_manifest_matches_catalog_when_importable (self ) -> None :
84+ for profile in get_strategy_definitions ():
85+ try :
86+ entrypoint = get_strategy_entrypoint (profile )
87+ except ModuleNotFoundError as exc :
88+ if exc .name == "pandas" :
89+ self .skipTest ("pandas is not installed" )
90+ raise
91+ definition = get_strategy_definition (profile )
92+ metadata = get_strategy_metadata (profile )
93+ with self .subTest (profile = profile ):
94+ self .assertEqual (entrypoint .manifest .profile , definition .profile )
95+ self .assertEqual (entrypoint .manifest .domain , definition .domain )
96+ self .assertEqual (entrypoint .manifest .display_name , metadata .display_name )
97+ self .assertEqual (entrypoint .manifest .required_inputs , definition .required_inputs )
98+
99+ def test_strategy_index_rows_expose_expected_contract_fields (self ) -> None :
100+ rows = {row ["canonical_profile" ]: row for row in get_strategy_index_rows ()}
101+ for profile , definition in get_strategy_definitions ().items ():
102+ row = rows [profile ]
103+ with self .subTest (profile = profile ):
104+ self .assertEqual (row ["required_inputs" ], definition .required_inputs )
105+ self .assertEqual (row ["target_mode" ], definition .target_mode )
106+ self .assertEqual (row ["compatible_platforms" ], definition .supported_platforms )
107+
62108 def test_strategy_and_entrypoint_sources_do_not_branch_on_platform_or_env (self ) -> None :
63109 for root in GOVERNED_SOURCE_ROOTS :
64110 for path in sorted (root .rglob ("*.py" )):
0 commit comments