"""Tests for the ST25TN512 / ST25TN01K (ST NFC Forum Type 2) models.""" import asyncio import pytest from pm3py.sim.frame import RFFrame from pm3py.transponders.hf.iso14443a.base import _compute_bcc from pm3py.transponders.hf.iso14443a.st.st25tn import ST25TN512, ST25TN01K UID = b"\x02\x11\x22\x33\x44\x55\x66" def run(coro): return asyncio.new_event_loop().run_until_complete(coro) def select(tag): run(tag.handle_frame(RFFrame.from_hex("26"))) uid = tag._uid ct = b"\x88" + uid[0:3] run(tag.handle_frame(RFFrame.from_bytes(b"\x93\x70" + ct + bytes([_compute_bcc(ct)])))) run(tag.handle_frame(RFFrame.from_bytes(b"\x95\x70" + uid[3:7] + bytes([_compute_bcc(uid[3:7])])))) assert tag.state == "ACTIVE" def activate(cls, **kw): tag = cls(uid=UID, **kw) run(tag.power_on()) select(tag) return tag class TestIdentity: def test_st_uid_prefix_autogen(self): assert ST25TN512()._uid[0] == 0x02 # ST manufacturer code def test_atqa_sak(self): tag = ST25TN512(uid=UID) run(tag.power_on()) assert run(tag.handle_frame(RFFrame.from_hex("26"))).data == b"\x44\x00" select(tag) # reaches ACTIVE with SAK 0x00 def test_cc_defaults(self): assert ST25TN512(uid=UID)._get_page(3) == b"\xE1\x10\x08\x00" assert ST25TN01K(uid=UID)._get_page(3) == b"\xE1\x10\x14\x00" def test_read_returns_uid(self): tag = activate(ST25TN512) resp = run(tag.handle_frame(RFFrame.from_bytes(b"\x30\x00"))) assert resp.data[0:3] == UID[0:3] def test_product_id_block(self): tag = activate(ST25TN512) assert run(tag.handle_frame(RFFrame.from_bytes(b"\x30\x2D"))).data[0:4] == b"\x91\x90\x13\x05" tag = activate(ST25TN01K) assert run(tag.handle_frame(RFFrame.from_bytes(b"\x30\x2D"))).data[0:4] == b"\x90\x90\x13\x05" class TestCommands: def test_no_fast_read_version_pwd(self): tag = activate(ST25TN512) assert run(tag.handle_frame(RFFrame.from_bytes(b"\x3A\x00\x03"))) is None assert run(tag.handle_frame(RFFrame.from_bytes(b"\x60"))) is None assert run(tag.handle_frame(RFFrame.from_bytes(b"\x1B\x00\x00\x00\x00"))) is None def test_write_readback(self): tag = activate(ST25TN512) assert run(tag.handle_frame(RFFrame.from_bytes(b"\xA2\x05\xDE\xAD\xBE\xEF"))).data == b"\x0A" assert run(tag.handle_frame(RFFrame.from_bytes(b"\x30\x05"))).data[0:4] == b"\xDE\xAD\xBE\xEF" def test_product_id_read_only(self): tag = activate(ST25TN512) assert run(tag.handle_frame(RFFrame.from_bytes(b"\xA2\x2D\x01\x02\x03\x04"))).data == b"\x00" def test_kill_pwd_reads_zero(self): tag = activate(ST25TN512) assert run(tag.handle_frame(RFFrame.from_bytes(b"\x30\x2F"))).data[0:4] == bytes(4) class TestKill: def test_kill_with_correct_password(self): tag = activate(ST25TN512, kill_password=b"\x11\x22\x33\x44") # wrong password → NAK assert run(tag.handle_frame(RFFrame.from_bytes(b"\xA2\x30\x00\x00\x00\x00"))).data == b"\x00" # correct → ACK, killed on next boot assert run(tag.handle_frame(RFFrame.from_bytes(b"\xA2\x30\x11\x22\x33\x44"))).data == b"\x0A" run(tag.power_on()) assert tag.killed assert run(tag.handle_frame(RFFrame.from_hex("26"))) is None def test_kill_disabled(self): tag = activate(ST25TN512, kill_password=b"\x00\x00\x00\x00", kill_enabled=False) assert run(tag.handle_frame(RFFrame.from_bytes(b"\xA2\x30\x00\x00\x00\x00"))).data == b"\x00"