@@ -51,61 +51,71 @@ const ourFields = FIELD_SIZES.slice(1).map(([name, bytes]) => [name, bytes] as [
5151
5252const describeIf = ( path : string ) => ( existsSync ( path ) ? describe : describe . skip ) ;
5353
54- describeIf ( IDL_PATH ) ( 'PetAccount layout vs the Anchor IDL' , ( ) => {
54+ // Read inside the tests, never in a describe body: vitest evaluates the body of a
55+ // skipped describe, so a top-level readFileSync throws where the file is absent
56+ // and the skip never gets a chance to apply.
57+ const readIdl = ( ) => {
5558 const idl = JSON . parse ( readFileSync ( IDL_PATH , 'utf8' ) ) as {
5659 accounts ?: { name : string ; discriminator : number [ ] } [ ] ;
5760 types ?: { name : string ; type : { fields : { name : string ; type : IdlType } [ ] } } [ ] ;
5861 } ;
5962 const fields = idl . types ?. find ( ( t ) => t . name === 'PetAccount' ) ?. type . fields ?? [ ] ;
60- const idlLayout = fields . map ( ( f ) => [ f . name , widthOf ( f . type ) ] as [ string , number ] ) ;
63+ return { idl, layout : fields . map ( ( f ) => [ f . name , widthOf ( f . type ) ] as [ string , number ] ) } ;
64+ } ;
65+
66+ describeIf ( IDL_PATH ) ( 'PetAccount layout vs the Anchor IDL' , ( ) => {
6167
6268 // Guards the guard: an empty layout would agree with anything.
6369 it ( 'found the account in the IDL' , ( ) => {
64- expect ( idlLayout . length ) . toBeGreaterThan ( 20 ) ;
70+ expect ( readIdl ( ) . layout . length ) . toBeGreaterThan ( 20 ) ;
6571 } ) ;
6672
6773 it ( 'has the same fields, in the same order, at the same widths' , ( ) => {
68- expect ( ourFields ) . toEqual ( idlLayout ) ;
74+ expect ( ourFields ) . toEqual ( readIdl ( ) . layout ) ;
6975 } ) ;
7076
7177 it ( 'totals the same account size once the discriminator is added' , ( ) => {
72- const total = idlLayout . reduce ( ( sum , [ , bytes ] ) => sum + bytes , 0 ) ;
78+ const total = readIdl ( ) . layout . reduce ( ( sum , [ , bytes ] ) => sum + bytes , 0 ) ;
7379 expect ( PET_ACCOUNT_SPACE ) . toBe ( total + 8 ) ;
7480 } ) ;
7581
7682 // Computed as sha256("account:PetAccount")[0..8] rather than read from
7783 // anywhere. If that convention were wrong, every real account would fail the
7884 // discriminator check and Solana would never serve a single pet.
7985 it ( 'computes the discriminator Anchor generated' , ( ) => {
80- const expected = idl . accounts ?. find ( ( a ) => a . name === 'PetAccount' ) ?. discriminator ;
86+ const expected = readIdl ( ) . idl . accounts ?. find ( ( a ) => a . name === 'PetAccount' ) ?. discriminator ;
8187 expect ( expected ) . toBeDefined ( ) ;
8288 expect ( [ ...petAccountDiscriminator ( ) ] ) . toEqual ( expected ) ;
8389 } ) ;
8490} ) ;
8591
86- describeIf ( PET_RS ) ( 'PetAccount layout vs pet.rs' , ( ) => {
92+ /** Same reason as readIdl: never read at describe level. */
93+ const readRustLayout = ( ) : [ string , number ] [ ] => {
8794 const toCamel = ( name : string ) : string =>
8895 name . replace ( / ^ _ + / , '' ) . replace ( / _ ( [ a - z ] ) / g, ( _full , c : string ) => c . toUpperCase ( ) ) ;
8996
9097 const source = readFileSync ( PET_RS , 'utf8' ) ;
9198 const body = source . slice ( source . indexOf ( 'pub struct PetAccount {' ) , source . indexOf ( 'impl PetAccount' ) ) ;
9299
93- const rustLayout : [ string , number ] [ ] = [ ] ;
100+ const layout : [ string , number ] [ ] = [ ] ;
94101 for ( const line of body . split ( '\n' ) ) {
95102 const match = / ^ \s * p u b \s + ( \w + ) : \s * ( [ ^ , ] + ) , / . exec ( line ) ;
96103 if ( ! match ) continue ;
97104 const type = match [ 2 ] ! . trim ( ) . replace ( 'PetAccount::MAX_NAME_LEN' , '32' ) ;
98105 const array = / ^ \[ u 8 ; \s * ( \d + ) \] $ / . exec ( type ) ;
99- rustLayout . push ( [ toCamel ( match [ 1 ] ! ) , array ? Number ( array [ 1 ] ) : widthOf ( type ) ] ) ;
106+ layout . push ( [ toCamel ( match [ 1 ] ! ) , array ? Number ( array [ 1 ] ) : widthOf ( type ) ] ) ;
100107 }
108+ return layout ;
109+ } ;
101110
111+ describeIf ( PET_RS ) ( 'PetAccount layout vs pet.rs' , ( ) => {
102112 it ( 'found the struct in the source' , ( ) => {
103- expect ( rustLayout . length ) . toBeGreaterThan ( 20 ) ;
113+ expect ( readRustLayout ( ) . length ) . toBeGreaterThan ( 20 ) ;
104114 } ) ;
105115
106116 // Disagreement here means the checked-in IDL no longer matches the program
107117 // source, so this service would decode for a program that is not deployed.
108118 it ( 'matches the current Rust struct too, so the IDL is not stale' , ( ) => {
109- expect ( ourFields ) . toEqual ( rustLayout ) ;
119+ expect ( ourFields ) . toEqual ( readRustLayout ( ) ) ;
110120 } ) ;
111121} ) ;
0 commit comments