# tests/unit/modules/loyalty/test_loyalty_features.py """ Unit tests for the loyalty feature provider. Tests cover: - Feature category - Feature declarations (count, codes, types, scopes) - Usage methods return empty lists - Protocol compliance """ import pytest from app.modules.contracts.features import ( FeatureProviderProtocol, FeatureScope, FeatureType, ) from app.modules.loyalty.definition import loyalty_module from app.modules.loyalty.services.loyalty_features import ( LoyaltyFeatureProvider, loyalty_feature_provider, ) @pytest.mark.unit class TestLoyaltyFeatureProvider: """Tests for LoyaltyFeatureProvider.""" def test_feature_category(self): """Feature category should be 'loyalty'.""" assert loyalty_feature_provider.feature_category == "loyalty" def test_get_feature_declarations_count(self): """Should return exactly 11 feature declarations.""" declarations = loyalty_feature_provider.get_feature_declarations() assert len(declarations) == 11 def test_feature_codes_match_module_definition(self): """All declared feature codes should match loyalty_module.features.""" declarations = loyalty_feature_provider.get_feature_declarations() declared_codes = {d.code for d in declarations} module_features = set(loyalty_module.features) assert declared_codes == module_features def test_all_features_are_binary(self): """All loyalty features should be BINARY type.""" declarations = loyalty_feature_provider.get_feature_declarations() for decl in declarations: assert decl.feature_type == FeatureType.BINARY, ( f"Feature {decl.code} should be BINARY, got {decl.feature_type}" ) def test_all_features_are_merchant_scoped(self): """All loyalty features should be MERCHANT scoped.""" declarations = loyalty_feature_provider.get_feature_declarations() for decl in declarations: assert decl.scope == FeatureScope.MERCHANT, ( f"Feature {decl.code} should be MERCHANT scoped, got {decl.scope}" ) def test_all_features_have_name_key(self): """All features should have a non-empty name_key.""" declarations = loyalty_feature_provider.get_feature_declarations() for decl in declarations: assert decl.name_key, f"Feature {decl.code} missing name_key" def test_all_features_have_description_key(self): """All features should have a non-empty description_key.""" declarations = loyalty_feature_provider.get_feature_declarations() for decl in declarations: assert decl.description_key, f"Feature {decl.code} missing description_key" def test_get_store_usage_returns_empty(self): """get_store_usage should return an empty list.""" result = loyalty_feature_provider.get_store_usage(db=None, store_id=1) assert result == [] def test_get_merchant_usage_returns_empty(self): """get_merchant_usage should return an empty list.""" result = loyalty_feature_provider.get_merchant_usage( db=None, merchant_id=1, platform_id=1 ) assert result == [] def test_satisfies_feature_provider_protocol(self): """Provider should satisfy FeatureProviderProtocol.""" assert isinstance(loyalty_feature_provider, FeatureProviderProtocol) def test_singleton_is_correct_type(self): """Singleton instance should be a LoyaltyFeatureProvider.""" assert isinstance(loyalty_feature_provider, LoyaltyFeatureProvider)