1616package org .labkey .test .util ;
1717
1818import org .apache .commons .csv .CSVFormat ;
19- import org .apache .commons .io .FileUtils ;
2019import org .apache .commons .lang3 .StringUtils ;
2120import org .apache .commons .lang3 .time .DateUtils ;
22- import org .apache .poi .xssf .streaming .SXSSFRow ;
23- import org .apache .poi .xssf .streaming .SXSSFWorkbook ;
2421import org .jetbrains .annotations .NotNull ;
2522import org .jetbrains .annotations .Nullable ;
2623import org .junit .Assert ;
3734import org .labkey .remoteapi .query .SelectRowsResponse ;
3835import org .labkey .remoteapi .query .Sort ;
3936import org .labkey .serverapi .reader .TabLoader ;
40- import org .labkey .test .TestFileUtils ;
4137import org .labkey .test .WebTestHelper ;
4238import org .labkey .test .params .FieldDefinition ;
4339import org .labkey .test .util .data .ColumnNameMapper ;
4440import org .labkey .test .util .data .TestDataUtils ;
4541import org .labkey .test .util .query .QueryApiHelper ;
4642
4743import java .io .File ;
48- import java .io .FileOutputStream ;
4944import java .io .IOException ;
5045import java .text .SimpleDateFormat ;
5146import java .util .ArrayList ;
5449import java .util .Collections ;
5550import java .util .Date ;
5651import java .util .HashMap ;
52+ import java .util .Iterator ;
5753import java .util .List ;
5854import java .util .Map ;
55+ import java .util .NoSuchElementException ;
56+ import java .util .Objects ;
5957import java .util .Set ;
6058import java .util .concurrent .ThreadLocalRandom ;
6159import java .util .function .Supplier ;
@@ -313,7 +311,7 @@ public TestDataGenerator withGeneratedRows(int desiredRowCount)
313311
314312 public TestDataGenerator addDataSupplier (String columnName , Supplier <Object > supplier )
315313 {
316- _dataSuppliers .put (columnName , ()-> supplier . get () );
314+ _dataSuppliers .put (columnName , supplier );
317315 return this ;
318316 }
319317
@@ -400,7 +398,7 @@ public List<PropertyDescriptor> getColumns()
400398
401399 public void generateRows (int numberOfRowsToGenerate )
402400 {
403- if (_columns .keySet (). size () == 0 )
401+ if (_columns .isEmpty () )
404402 throw new IllegalStateException ("can't generate row data without column definitions" );
405403
406404 for (int i = 0 ; i < numberOfRowsToGenerate ; i ++)
@@ -444,7 +442,7 @@ private Supplier<Object> getDefaultDataSupplier(String columnType)
444442 case "double" :
445443 return ()-> randomDouble (0 , 20 );
446444 case "boolean" :
447- return ()-> randomBoolean () ;
445+ return this :: randomBoolean ;
448446 case "date" :
449447 case "datetime" :
450448 return ()-> randomDateString (DateUtils .addWeeks (new Date (), -39 ), new Date ());
@@ -670,40 +668,6 @@ public String getDataAsTsv()
670668 return TestDataUtils .stringFromRowMaps (_rows , getFieldsForFile (), true , CSVFormat .TDF );
671669 }
672670
673- public File writeGeneratedDataToExcel (String sheetName , String fileName ) throws IOException
674- {
675- File file = new File (TestFileUtils .getTestTempDir (), fileName );
676- FileUtils .forceMkdirParent (file );
677-
678- try (SXSSFWorkbook workbook = new SXSSFWorkbook (1000 ); // only holds 1000 rows in memory
679- FileOutputStream out = new FileOutputStream (file ))
680- {
681- var sheet = workbook .createSheet (sheetName );
682-
683- // write headers as row 0
684- List <String > columnNames = getFieldsForFile ();
685- var headerRow = sheet .createRow (0 );
686- for (int i = 0 ; i < columnNames .size (); i ++)
687- {
688- headerRow .createCell (i ).setCellValue (columnNames .get (i ));
689- }
690-
691- // write content
692- for (int i = 0 ; i < _rows .size (); i ++)
693- {
694- Map <String , Object > row = _rows .get (i );
695- SXSSFRow currentRow = sheet .createRow (i + 1 );
696- for (int j = 0 ; j < columnNames .size (); j ++)
697- {
698- currentRow .createCell (j ).setCellValue (row .getOrDefault (columnNames .get (j ), "" ).toString ());
699- }
700- }
701- workbook .write (out );
702- }
703-
704- return file ;
705- }
706-
707671 /**
708672 * Creates a file containing the contents of the current rows, formatted in TSV, CSV, or xlsx.
709673 * The file is written to the test temp dir
@@ -712,33 +676,43 @@ public File writeGeneratedDataToExcel(String sheetName, String fileName) throws
712676 */
713677 public File writeData (String fileName )
714678 {
715- String fileExtension = fileName .toLowerCase ().substring (fileName .lastIndexOf ('.' ) + 1 );
716- switch (fileExtension )
717- {
718- case "xlsx" :
719- case "xls" :
720- try
721- {
722- return writeGeneratedDataToExcel ("sheet1" , fileName );
723- }
724- catch (IOException e )
725- {
726- throw new RuntimeException (e );
727- }
728- case "csv" :
729- return writeData (fileName , CSVFormat .DEFAULT );
730- case "tsv" :
731- return writeData (fileName , CSVFormat .TDF );
732- default :
733- throw new IllegalArgumentException ("Unsupported file extension: " + fileExtension );
734- }
679+ return writeData (fileName , new FileRowIterator (getFieldsForFile (), _rows ));
735680 }
736681
737- public File writeData (String fileName , CSVFormat format )
682+ /**
683+ * Generate rows and write to file without saving in data generator
684+ * @param fileName the name of the file, e.g. 'testDataFileForMyTest.tsv'
685+ * @param numRows the number of rows to generate
686+ * @return object pointing at created file
687+ */
688+ public File writeData (String fileName , int numRows )
689+ {
690+ return writeData (fileName , new FileRowIterator (getFieldsForFile (), this ::generateRow , numRows ));
691+ }
692+
693+ /**
694+ * Creates a file containing the contents of the current rows, formatted in TSV, CSV, or xlsx.
695+ * The file is written to the test temp dir
696+ * @param fileName the name of the file, e.g. 'testDataFileForMyTest.tsv'
697+ * @return File object pointing at created file
698+ */
699+ public File writeData (String fileName , Iterator <List <Object >> rowIterator )
738700 {
739701 try
740702 {
741- return TestDataUtils .writeRowsToFile (fileName , TestDataUtils .rowListsFromMaps (_rows , getFieldsForFile ()), format );
703+ String fileExtension = fileName .toLowerCase ().substring (fileName .lastIndexOf ('.' ) + 1 );
704+ switch (fileExtension )
705+ {
706+ case "xlsx" :
707+ case "xls" :
708+ return TestDataUtils .writeRowsToExcel (fileName , rowIterator );
709+ case "csv" :
710+ return TestDataUtils .writeRowsToFile (fileName , rowIterator , CSVFormat .DEFAULT );
711+ case "tsv" :
712+ return TestDataUtils .writeRowsToFile (fileName , rowIterator , CSVFormat .TDF );
713+ default :
714+ throw new IllegalArgumentException ("Unsupported file extension: " + fileExtension );
715+ }
742716 }
743717 catch (IOException e )
744718 {
@@ -915,3 +889,71 @@ public static boolean doesDomainExists(final String containerPath, final String
915889 }
916890
917891}
892+
893+ class FileRowIterator implements Iterator <List <Object >>
894+ {
895+ private final List <String > headers ;
896+ private final Iterator <Map <String , Object >> rows ;
897+
898+ private boolean firstRow = true ;
899+
900+ public FileRowIterator (@ NotNull List <String > headers , @ NotNull Iterator <Map <String , Object >> rows )
901+ {
902+ this .headers = Objects .requireNonNull (headers );
903+ this .rows = Objects .requireNonNull (rows );
904+ }
905+
906+ public FileRowIterator (@ NotNull List <String > headers , @ NotNull Supplier <Map <String , Object >> rowSupplier , final int rowCount )
907+ {
908+ this (headers , new Iterator <>()
909+ {
910+ int count = 0 ;
911+
912+ @ Override
913+ public boolean hasNext ()
914+ {
915+ return count < rowCount ;
916+ }
917+
918+ @ Override
919+ public Map <String , Object > next ()
920+ {
921+ count ++;
922+ return rowSupplier .get ();
923+ }
924+ });
925+ }
926+
927+ public FileRowIterator (@ NotNull List <String > headers , @ NotNull List <Map <String , Object >> rows )
928+ {
929+ this (headers , rows .iterator ());
930+ }
931+
932+ @ Override
933+ public boolean hasNext ()
934+ {
935+ return firstRow || rows .hasNext ();
936+ }
937+
938+ @ Override
939+ public List <Object > next ()
940+ {
941+ if (!hasNext ())
942+ throw new NoSuchElementException ();
943+
944+ if (firstRow )
945+ {
946+ firstRow = false ;
947+ return Collections .unmodifiableList (headers );
948+ }
949+ else
950+ {
951+ return rowMapToList (rows .next ());
952+ }
953+ }
954+
955+ private List <Object > rowMapToList (Map <String , Object > row )
956+ {
957+ return headers .stream ().map (h -> row .getOrDefault (h , "" )).toList ();
958+ }
959+ }
0 commit comments