from dataclasses import dataclass
import math,unittest,json,hashlib,io
@dataclass(frozen=True)
class Voorstel:
    id: str
    tijd_s: float
    modus: str
    vermogen_W: float
    ttl_s: float=60.
class Supervisor:
    # Contractvoorbeeld voor de e39-stationsheater, geen pinbesturing.
    def __init__(self): self.gezien=set()
    def beoordeel(self,p,nu,modus):
        if not isinstance(p,Voorstel): return False,"schema"
        if not isinstance(p.id,str) or not p.id: return False,"id"
        if not all(not isinstance(v,bool) and isinstance(v,(int,float)) and math.isfinite(v)
                   for v in (p.tijd_s,p.vermogen_W,p.ttl_s,nu)): return False,"niet-eindig"
        if not 0<p.ttl_s<=60: return False,"ttl"
        if not 0<=nu-p.tijd_s<=p.ttl_s: return False,"tijd"
        if p.modus not in ("DAG","NACHT") or p.modus!=modus: return False,"modus"
        if not 0<=p.vermogen_W<=2000: return False,"bereik"
        if p.id in self.gezien: return False,"dubbel"
        self.gezien.add(p.id)
        return True,"voorstel-goedgekeurd"
class Eisen(unittest.TestCase):
    def test_RF02_grenzen(self):
        for w,ok in [(-1,False),(0,True),(2000,True),(2001,False)]:
            self.assertEqual(Supervisor().beoordeel(Voorstel("a",10,"DAG",w),10,"DAG")[0],ok)
    def test_RN03_tijd(self):
        for tijd,ok in [(9,False),(10,True),(70,True),(70.001,False)]:
            self.assertEqual(Supervisor().beoordeel(Voorstel("a",10,"DAG",500),tijd,"DAG")[0],ok)
    def test_RF03_replay(self):
        s=Supervisor(); p=Voorstel("a",10,"DAG",500)
        self.assertTrue(s.beoordeel(p,11,"DAG")[0])
        self.assertEqual(s.beoordeel(p,12,"DAG"),(False,"dubbel"))
    def test_RF04_modus(self):
        self.assertEqual(Supervisor().beoordeel(Voorstel("a",10,"NACHT",500),11,"DAG"),(False,"modus"))
    def test_RF02_niet_eindig(self):
        for v in (float("nan"),float("inf")):
            self.assertFalse(Supervisor().beoordeel(Voorstel("a",10,"DAG",v),11,"DAG")[0])
res=unittest.TextTestRunner(stream=io.StringIO()).run(unittest.defaultTestLoader.loadTestsFromTestCase(Eisen))
print("contracttests",res.testsRun,"fouten",len(res.errors)+len(res.failures))
config={"telemetrie_s":60,"leeftijd_s":90,"voorstel_ttl_s":60,"eigenaar":"lokale-regelaar"}
canon=json.dumps(config,sort_keys=True,separators=(",",":"))
print("config",canon)
print("configsha256",hashlib.sha256(canon.encode()).hexdigest())
assert res.wasSuccessful()
