"""Unit/security checks for QR primitives and contracts."""
from __future__ import annotations
import logging, unittest
from apps.qr_service import APP_MANIFEST
from apps.qr_service.service import PUBLIC_ERROR, QRServiceError, _clean_metadata, _policy, token_hash, token_pair

class QRPrimitiveChecks(unittest.TestCase):
    def test_manifest_and_mutation_idempotency_contracts(self):
        self.assertEqual([],APP_MANIFEST.validate())
        for name in ("create_qr_v1","revoke_qr_v1","regenerate_qr_v1","consume_resolution_v1"):
            self.assertTrue(APP_MANIFEST.actions[name].idempotency_key_required)

    def test_tokens_are_opaque_high_entropy_and_only_hash_is_stable(self):
        first,digest,prefix=token_pair();second,other,_=token_pair()
        self.assertNotEqual(first,second);self.assertGreaterEqual(len(first),40);self.assertEqual(digest,token_hash(first));self.assertNotEqual(digest,other);self.assertEqual(prefix,first[:8])
        self.assertNotIn("tenant",first);self.assertNotIn("resource",first)

    def test_policy_presets_and_bounds(self):
        self.assertEqual(1,_policy({"kind":"single_use"})["max_successful_uses"])
        with self.assertRaises(QRServiceError):_policy({"kind":"limited_use"})
        with self.assertRaises(QRServiceError):_policy({"kind":"unknown"})
        self.assertEqual(900,_policy({"kind":"permanent_revocable","resolution_ttl_seconds":9999})["resolution_ttl_seconds"])

    def test_metadata_rejects_nested_or_oversized_content(self):
        self.assertEqual({"label":"safe"},_clean_metadata({"label":"safe"}))
        with self.assertRaises(QRServiceError):_clean_metadata({"payload":{"private":"data"}})
        with self.assertRaises(QRServiceError):_clean_metadata({"label":"x"*257})

    def test_public_error_is_state_agnostic_and_tokens_are_not_logged(self):
        token,_,_=token_pair(); records=[]
        class Handler(logging.Handler):
            def emit(self,record):records.append(record.getMessage())
        logger=logging.getLogger("qr-test");handler=Handler();logger.addHandler(handler);logger.info("%s",PUBLIC_ERROR);logger.removeHandler(handler)
        self.assertNotIn(token," ".join(records));self.assertNotIn("revoked",PUBLIC_ERROR.lower())

if __name__=="__main__":unittest.main()
