program testcsvdoc; {$mode objfpc}{$H+} uses SysUtils, Classes, CsvDocument, DateUtils; function ReadStringFromFile(AFileName: string): string; var FileStream: TFileStream; Size: Integer; begin Result := ''; if not FileExists(AFileName) then Exit; FileStream := TFileStream.Create(AFileName, fmOpenRead); Size := FileStream.Size; if Size > 0 then begin SetLength(Result, Size); FileStream.ReadBuffer(Result[1], Size); end; FreeAndNil(FileStream); end; procedure FindTestFiles(AFileList: TStringList; const ASpec: string); var SearchRec: TSearchRec; TestFilesPath: String; begin AFileList.Clear; TestFilesPath := IncludeTrailingPathDelimiter(GetCurrentDir) + 'tests' + DirectorySeparator + ASpec + DirectorySeparator; if FindFirst(TestFilesPath + '*.csv', faAnyFile, SearchRec) = 0 then repeat AFileList.Add(TestFilesPath + SearchRec.Name); until FindNext(SearchRec) <> 0; FindClose(SearchRec); end; function TestCsvString(ADocument: TCSVDocument; const AnInput: String; out AParseTime, ABuildTime: Int64): String; var Start: TDateTime; begin ADocument.Clear; Start := Now; ADocument.CSVText := AnInput; AParseTime := MilliSecondsBetween(Start, Now); Start := Now; Result := ADocument.CSVText; ABuildTime := MilliSecondsBetween(Start, Now); end; procedure TestCsvFile(ADocument: TCSVDocument; const AnInputFilename, ASampleOutputFilename: String); var InBuffer, OutBuffer: String; SampleBuffer: String; ParseTime: Int64; BuildTime: Int64; begin InBuffer := ReadStringFromFile(AnInputFilename); SampleBuffer := ReadStringFromFile(ASampleOutputFilename); if SampleBuffer = '' then SampleBuffer := InBuffer; OutBuffer := TestCsvString(ADocument, InBuffer, ParseTime, BuildTime); Write(ExtractFileName(AnInputFilename)); if OutBuffer = SampleBuffer then begin Write(': ok'); WriteLn(' (parsed in ', BuildTime, ' ms)'); end else begin WriteLn(': FAILED'); WriteLn('--- Expected: ---'); SampleBuffer := StringReplace(SampleBuffer, #13, '', [rfReplaceAll]); SampleBuffer := StringReplace(SampleBuffer, #10, '', [rfReplaceAll]); WriteLn(SampleBuffer); WriteLn('--- Got: --------'); OutBuffer := StringReplace(OutBuffer, #13, '', [rfReplaceAll]); OutBuffer := StringReplace(OutBuffer, #10, '', [rfReplaceAll]); WriteLn(OutBuffer); WriteLn('-----------------'); end; end; procedure ExecTests(ADocument: TCSVDocument; const ASpec: String); var I: Integer; TestFiles: TStringList; CurrentTestFile: String; begin WriteLn('== Format: ', ASpec, ' =='); TestFiles := TStringList.Create; FindTestFiles(TestFiles, ASpec); for I := 0 to TestFiles.Count - 1 do begin CurrentTestFile := TestFiles[I]; TestCsvFile(ADocument, CurrentTestFile, ChangeFileExt(CurrentTestFile, '.sample')); end; FreeAndNil(TestFiles); WriteLn(); end; procedure ExecPerformanceTest(ADocument: TCSVDocument; const AMinSizeKB: Integer); var I, MaxRows: Integer; Seq: String; SeqLen: Integer; RealSize: Integer; InBuffer: String; ParseTime: Int64; BuildTime: Int64; begin WriteLn('== Performance test: =='); WriteLn('Preparing the test...'); Seq := '"abcd efg";"hij""k;l;m;n";opqrstuvw; xyz12 ;"3456'#13#10'7890'#13#10; SeqLen := Length(Seq); MaxRows := ((AMinSizeKB * 1024) div SeqLen) + 1; InBuffer := ''; RealSize := 0; for I := 0 to MaxRows do begin InBuffer := InBuffer + Seq; Inc(RealSize, SeqLen); end; WriteLn('Testing with ', RealSize div 1024, ' KB of CSV data...'); TestCsvString(ADocument, InBuffer, ParseTime, BuildTime); WriteLn('Parsed in ', ParseTime, ' ms'); WriteLn('Built in ', BuildTime, ' ms'); end; procedure SetupUnofficialCsvHandler(AHandler: TCSVHandler); begin AHandler.Delimiter := ','; AHandler.QuoteChar := '"'; AHandler.LineEnding := #13#10; AHandler.IgnoreOuterWhitespace := True; AHandler.QuoteOuterWhitespace := True; AHandler.EqualColCountPerRow := False; end; var CsvDoc: TCSVDocument; Param1: String; begin Param1 := ParamStr(1); WriteLn('Testing CSVDocument'); WriteLn('-------------------'); CsvDoc := TCSVDocument.Create; if Pos(Param1, 'performance') = 1 then begin CsvDoc.Delimiter := ';'; CsvDoc.QuoteChar := '"'; CsvDoc.LineEnding := #13#10; CsvDoc.EqualColCountPerRow := False; CsvDoc.IgnoreOuterWhitespace := False; CsvDoc.QuoteOuterWhitespace := True; ExecPerformanceTest(CsvDoc, StrToIntDef(ParamStr(2), 1)); end else begin // no setup needed, rfc4180 supported out-of-the-box ExecTests(CsvDoc, 'rfc4180'); // setup for unofficial Creativyst spec SetupUnofficialCsvHandler(CsvDoc); ExecTests(CsvDoc, 'unofficial'); // setup for MS Excel files // (todo) ExecTests(CsvDoc, 'msexcel'); // setup for OOo Calc files // (todo) ExecTests(CsvDoc, 'oocalc'); end; FreeAndNil(CsvDoc); WriteLn('------------------'); WriteLn('All tests complete'); end.