#include "pca9956b_fault_monitor.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
static unsigned count,fail_at;static uint8_t before,after,flags[6];
static const uint8_t registers[8]={1,0x41,0x42,0x43,0x44,0x45,0x46,1};
static bool rd(void *ctx,uint8_t addr,uint8_t reg,uint8_t *out) {
 assert(ctx==&count && addr==0x20 && reg==registers[count%8u]);
 unsigned step=count++%8u;if(count==fail_at)return false;
 *out=step==0?before:step==7?after:flags[step-1];return true;
}
static pca_fault_snapshot run(unsigned ch,unsigned code,unsigned mode,uint32_t eligible,uint32_t start) {
 count=0;fail_at=99;before=after=(uint8_t)mode;memset(flags,0,sizeof flags);
 if(code)flags[ch/4]=(uint8_t)(code<<(2*(ch%4)));
 pca_fault_monitor m;assert(pca_fault_init(&m,&count,rd,0x20,0xffffff,eligible,start));
 pca_fault_snapshot s={0};
 for(unsigned i=0;i<8;i++){
  pca_fault_poll(&m,start+i);
  if(i<7)assert(!pca_fault_get(&m,start+i,&s));
 }
 assert(pca_fault_get(&m,start+7,&s) && count==8 && s.sequence==1);
 assert(s.first_read_ms==start && s.completed_ms==start+7);
 assert(s.coverage_complete==(eligible==0xffffff));
 pca_fault_snapshot old=s;
 assert(!pca_fault_get(&m,start+21,&s) && memcmp(&old,&s,sizeof s)==0);
 return s;
}
int main(void) {
 unsigned cases=0;
 for(unsigned ch=0;ch<24;ch++)for(unsigned code=0;code<4;code++)
 for(unsigned mode=0;mode<256;mode++) {
  pca_fault_snapshot s=run(ch,code,mode,(mode&1)?0xffffff:0,UINT32_MAX-3);
  assert(s.short_mask==(code==1?(1u<<ch):0));
  assert(s.open_mask==(code==2?(1u<<ch):0));
  assert(s.invalid_code_mask==(code==3?(1u<<ch):0));
  assert(s.overtemperature==((mode&128)!=0) && s.global_error==((mode&64)!=0));
  assert(s.summary_mismatch==(((mode&64)!=0)!=(code!=0)));cases++;
 }
 for(unsigned failure=1;failure<=8;failure++){
  count=0;fail_at=failure;before=after=0;memset(flags,0,sizeof flags);
  pca_fault_monitor m;assert(pca_fault_init(&m,&count,rd,0x20,1,0,0));
  for(unsigned i=0;i<10;i++)pca_fault_poll(&m,i);
  assert(m.failed && count==failure);pca_fault_snapshot s;assert(!pca_fault_get(&m,10,&s));
 }
 count=0;fail_at=99;before=0;after=128;memset(flags,0,sizeof flags);
 pca_fault_monitor m;assert(pca_fault_init(&m,&count,rd,0x20,1,0,0));
 for(unsigned i=0;i<8;i++)pca_fault_poll(&m,i);assert(m.failed && !m.valid);
 assert(pca_fault_init(&m,&count,rd,0x20,1,0,100));pca_fault_poll(&m,99);assert(m.failed);
 assert(pca_fault_init(&m,&count,rd,0x20,1,0,0));pca_fault_poll(&m,6);assert(m.failed);
 for(unsigned addr=0;addr<256;addr++) if(addr<8 || addr>0x77)assert(!pca_fault_init(&m,&count,rd,(uint8_t)addr,1,0,0));
 assert(!pca_fault_init(&m,&count,rd,0x20,0x1000000,0,0));
 assert(!pca_fault_init(&m,&count,rd,0x20,1,2,0));
 assert(!pca_fault_init(&m,&count,NULL,0x20,1,0,0));
 assert(!pca_fault_init(NULL,&count,rd,0x20,1,0,0));
 /* Each new collection invalidates prior data; no old clear snapshot survives. */
 count=0;fail_at=99;before=after=0;memset(flags,0,sizeof flags);
 assert(pca_fault_init(&m,&count,rd,0x20,1,0,0));
 for(unsigned i=0;i<8;i++)pca_fault_poll(&m,i);
 pca_fault_snapshot cached;assert(pca_fault_get(&m,7,&cached));
 pca_fault_poll(&m,8);assert(!pca_fault_get(&m,8,&cached));
 /* Individually timely reads can still exceed total collection freshness. */
 count=0;assert(pca_fault_init(&m,&count,rd,0x20,1,0,0));
 for(unsigned i=0;i<8;i++)pca_fault_poll(&m,i*3u);
 assert(m.failed && !m.valid);
 /* All-zero disabled outputs have no diagnostic coverage and no health grant. */
 pca_fault_snapshot s=run(0,0,0,0,0);assert(!s.coverage_complete && !s.global_error);
 printf("PASS: %u mode/channel/code read sequences, all8 callback failures, status changes, missing coverage, invalid inputs, stale/gap/backward time and wrap. Mock register transactions only.\n",cases);
}
