@@ -177,24 +177,47 @@ test('generateFromTextSpec remains deterministic under overlapping seeded invoca
177177
178178test ( 'generateFromTextSpec supports pairwise generation for enum rules' , ( ) => {
179179 const result = generateFromTextSpec ( {
180- textSpec : 'Browser\nChrome,Firefox,Safari\nTheme\nLight,Dark' ,
180+ textSpec : 'Browser\nChrome,Firefox,Safari\nTheme\nLight,Dark\nRegion\nUS,EU ' ,
181181 rowCount : 100 ,
182182 outputFormat : 'json' ,
183183 pairwise : true ,
184184 } ) ;
185185
186186 expect ( result . ok ) . toBe ( true ) ;
187- expect ( result . headers ) . toEqual ( [ 'Browser' , 'Theme' ] ) ;
188- expect ( result . rows ) . toEqual ( [
189- [ 'Chrome' , 'Light' ] ,
190- [ 'Chrome' , 'Dark' ] ,
191- [ 'Firefox' , 'Light' ] ,
192- [ 'Firefox' , 'Dark' ] ,
193- [ 'Safari' , 'Light' ] ,
194- [ 'Safari' , 'Dark' ] ,
195- ] ) ;
187+ expect ( result . headers ) . toEqual ( [ 'Browser' , 'Theme' , 'Region' ] ) ;
188+ expect ( result . rows . length ) . toBeLessThan ( 3 * 2 * 2 ) ;
189+
190+ const valuesByHeader = {
191+ Browser : [ 'Chrome' , 'Firefox' , 'Safari' ] ,
192+ Theme : [ 'Light' , 'Dark' ] ,
193+ Region : [ 'US' , 'EU' ] ,
194+ } ;
195+ const getValue = ( row , header ) => row [ result . headers . indexOf ( header ) ] ;
196+
197+ const coveredPairs = new Set ( ) ;
198+ for ( const row of result . rows ) {
199+ coveredPairs . add ( `Browser:${ getValue ( row , 'Browser' ) } |Theme:${ getValue ( row , 'Theme' ) } ` ) ;
200+ coveredPairs . add ( `Browser:${ getValue ( row , 'Browser' ) } |Region:${ getValue ( row , 'Region' ) } ` ) ;
201+ coveredPairs . add ( `Theme:${ getValue ( row , 'Theme' ) } |Region:${ getValue ( row , 'Region' ) } ` ) ;
202+ }
203+
204+ for ( const browser of valuesByHeader . Browser ) {
205+ for ( const theme of valuesByHeader . Theme ) {
206+ expect ( coveredPairs . has ( `Browser:${ browser } |Theme:${ theme } ` ) ) . toBe ( true ) ;
207+ }
208+ for ( const region of valuesByHeader . Region ) {
209+ expect ( coveredPairs . has ( `Browser:${ browser } |Region:${ region } ` ) ) . toBe ( true ) ;
210+ }
211+ }
212+ for ( const theme of valuesByHeader . Theme ) {
213+ for ( const region of valuesByHeader . Region ) {
214+ expect ( coveredPairs . has ( `Theme:${ theme } |Region:${ region } ` ) ) . toBe ( true ) ;
215+ }
216+ }
217+
196218 expect ( result . diagnostics . pairwise ) . toBe ( true ) ;
197- expect ( result . diagnostics . rowCount ) . toBe ( 6 ) ;
219+ expect ( result . diagnostics . rowCount ) . toBe ( result . rows . length ) ;
220+ expect ( result . diagnostics . warnings ) . toContain ( 'rowCount is ignored when pairwise generation is enabled.' ) ;
198221} ) ;
199222
200223test ( 'generateFromTextSpec rejects pairwise mode with fewer than 2 enum rules' , ( ) => {
@@ -208,3 +231,23 @@ test('generateFromTextSpec rejects pairwise mode with fewer than 2 enum rules',
208231 expect ( result . ok ) . toBe ( false ) ;
209232 expect ( result . errors [ 0 ] ) . toMatch ( / r e q u i r e s a t l e a s t 2 E N U M p a r a m e t e r s / i) ;
210233} ) ;
234+
235+ test ( 'generateFromTextSpec pairwise preserves original interleaved column order' , ( ) => {
236+ const result = generateFromTextSpec ( {
237+ textSpec : 'Name\nBob\nBrowser\nChrome,Firefox,Safari\nAge\n30\nTheme\nLight,Dark' ,
238+ rowCount : 100 ,
239+ outputFormat : 'json' ,
240+ pairwise : true ,
241+ } ) ;
242+
243+ expect ( result . ok ) . toBe ( true ) ;
244+ expect ( result . headers ) . toEqual ( [ 'Name' , 'Browser' , 'Age' , 'Theme' ] ) ;
245+ expect ( result . rows ) . toEqual ( [
246+ [ 'Bob' , 'Chrome' , '30' , 'Light' ] ,
247+ [ 'Bob' , 'Chrome' , '30' , 'Dark' ] ,
248+ [ 'Bob' , 'Firefox' , '30' , 'Light' ] ,
249+ [ 'Bob' , 'Firefox' , '30' , 'Dark' ] ,
250+ [ 'Bob' , 'Safari' , '30' , 'Light' ] ,
251+ [ 'Bob' , 'Safari' , '30' , 'Dark' ] ,
252+ ] ) ;
253+ } ) ;
0 commit comments