Browse Source

fcl-db: sdfdataset: simplify tests, add comments

git-svn-id: trunk@30567 -
lacak 10 years ago
parent
commit
1a5126081f
2 changed files with 142 additions and 151 deletions
  1. 31 23
      packages/fcl-db/src/sdf/sdfdata.pp
  2. 111 128
      packages/fcl-db/tests/tcsdfdata.pp

+ 31 - 23
packages/fcl-db/src/sdf/sdfdata.pp

@@ -259,7 +259,7 @@ type
     FFirstLineAsSchema : Boolean;
     FFMultiLine        : Boolean;
     FStripTrailingDelimiters : Boolean;
-    procedure DoStripTrailingDelimiters(var S: String; All : Boolean);
+    procedure DoStripTrailingDelimiters(var S: String);
     procedure SetMultiLine(const Value: Boolean);
     procedure SetFirstLineAsSchema(Value : Boolean);
     procedure SetDelimiter(Value : Char);
@@ -864,7 +864,7 @@ end;
 procedure TSdfDataSet.InternalInitFieldDefs;
 var
   pStart, pEnd, len : Integer;
-  SL,Fn : String;
+  SchemaLine, FN : String;
 
 begin
   if not IsCursorOpen then
@@ -881,45 +881,53 @@ begin
   else if (Schema.Count = 0) or FirstLineAsSchema then
   begin
     Schema.Clear;
-    SL:=FData[0];
+    SchemaLine:=FData[0];
     if StripTrailingDelimiters then
-      DoStripTrailingDelimiters(SL,True);
-    len := Length(SL);
+      DoStripTrailingDelimiters(SchemaLine);
+    len := Length(SchemaLine);
     pEnd := 1;
     repeat
-      while (pEnd<=len) and (SL[pEnd] in [#1..' ']) do
+      // skip leading white-spaces
+      while (pEnd<=len) and (SchemaLine[pEnd] in [#1..' ']) do
         Inc(pEnd);
+
       if (pEnd > len) then
         break;
+
       pStart := pEnd;
-      if (SL[pStart] = '"') then
+      if (SchemaLine[pStart] = '"') then
+        // quoted field name
         begin
         repeat
           Inc(pEnd);
-        until (pEnd > len)  or (SL[pEnd] = '"');
-        if (SL[pEnd] = '"') then
+        until (pEnd > len)  or (SchemaLine[pEnd] = '"');
+        if (SchemaLine[pEnd] = '"') then
           Inc(pStart);
         end
       else
-        while (pEnd<=len) and (SL[pEnd]<>Delimiter) do
+        // unquoted field name
+        while (pEnd<=len) and (SchemaLine[pEnd]<>Delimiter) do
           Inc(pEnd);
-      if (FirstLineAsSchema) then
-        FN:=Copy(SL,pStart,pEnd - pStart)
+
+      if FirstLineAsSchema then
+        FN:=Copy(SchemaLine, pStart, pEnd - pStart)
       else
         FN:='';
-      if (FN='') then // Pend-PStart=0 is possible: a,b,,c
+      if FN='' then // pEnd-pStart=0 is possible: a,b,,c
         FN:=Format('Field%d', [Schema.Count + 1]);
       Schema.Add(FN);
-      if (Pend<=Len) and (SL[pEnd] = '"') then
-        while (pEnd <= len) and (SL[pEnd] <> Delimiter) do
+
+      // skip all after trailing quote until next Delimiter
+      if (pEnd<=Len) and (SchemaLine[pEnd] = '"') then
+        while (pEnd <= len) and (SchemaLine[pEnd] <> Delimiter) do
           Inc(pEnd);
-//      if (SL[pEnd]=Delimiter) then
-        Inc(pEnd);
+
+      Inc(pEnd);
     until (pEnd > len);
+
     // Special case: f1,f2, is 3 fields, last unnamed.
-    if (Len>0) and (SL[Len]=Delimiter) then
+    if (Len>0) and (SchemaLine[Len]=Delimiter) then
       Schema.Add(Format('Field%d', [Schema.Count + 1]));
-
   end;
   inherited;
 end;
@@ -1077,10 +1085,10 @@ begin
       end;
     Result := Result + Str + FDelimiter;
   end;
-  DoStripTrailingDelimiters(Result,StripTrailingDelimiters)
+  DoStripTrailingDelimiters(Result)
 end;
 
-procedure TSdfDataSet.DoStripTrailingDelimiters(var S: String; All: Boolean);
+procedure TSdfDataSet.DoStripTrailingDelimiters(var S: String);
 
 var
   L,P : integer;
@@ -1088,8 +1096,8 @@ begin
 //  Write('S "',S,'" -> "');
   L:=Length(S);
   P:=L;
-  while (p>0) and (S[p]=FDelimiter) and (All or (P=L)) do
-    Dec(p);
+  while (P>0) and (S[P]=FDelimiter) and ((P=L) or StripTrailingDelimiters) do
+    Dec(P);
   if P<L then
     S:=Copy(S,1,P);
 //  Writeln(s,'"');

+ 111 - 128
packages/fcl-db/tests/tcsdfdata.pp

@@ -6,7 +6,7 @@ unit tcsdfdata;
 interface
 
 uses
-  Classes, SysUtils, Fpcunit, Testutils, Testregistry, testdecorator,
+  Classes, SysUtils, Fpcunit, TestRegistry,
   dateutils,sdfdata,ToolsUnit;
 
 type
@@ -15,7 +15,7 @@ type
 
   Ttestsdfspecific = class(Ttestcase)
   private
-    procedure TestEmptyFieldContents;
+    function TestFileName(const FileName: string=''): string;
   protected
     TestDataset: TSDFDataset;
     procedure Setup; override;
@@ -33,25 +33,39 @@ type
     procedure TestInputOurFormat;
     }
     procedure TestDelimitedTextOutput;
-    procedure TestEmptyHeader;
-    Procedure TestEmptyHeader2;
-    Procedure TestEmptyHeaderStripTrailingDelimiters;
+    procedure TestEmptyFieldHeader;
+    Procedure TestEmptyFieldNoHeader;
+    procedure TestEmptyFieldContents;
+    Procedure TestEmptyFieldHeaderStripTrailingDelimiters;
     Procedure TestStripTrailingDelimiters;
   end;
 
 implementation
 
-procedure Ttestsdfspecific.TestEmptyFileHeader;
-// An empty file should return 0 records even if it has a header
+function Ttestsdfspecific.TestFileName(const FileName: string): string;
 const
-  InputFilename='empty.csv';
+  DefaultTestFileName = 'test.csv';
 begin
-  TestDataSet.Close;
+  if FileName = '' then
+    Result := DefaultTestFileName
+  else
+    Result := FileName;
+
+  if dbname <> '' then
+    begin
+    ForceDirectories(dbname);
+    Result := IncludeTrailingPathDelimiter(dbname) + Result;
+    end;
 
-  if FileExists(InputFilename) then DeleteFile(InputFilename);
-  TestDataset.FileMustExist:=false;
-  TestDataset.FirstLineAsSchema := True;  
-  TestDataset.FileName:=InputFilename;
+  if FileExists(Result) then DeleteFile(Result);
+end;
+
+procedure Ttestsdfspecific.TestEmptyFileHeader;
+// An empty file should return 0 records even if it has a header
+begin
+  // with Schema, with Header line
+  TestDataset.FirstLineAsSchema := True;
+  TestDataset.FileName := TestFileName('empty.csv');
   TestDataset.Open;
 
   TestDataset.Last;
@@ -62,15 +76,10 @@ end;
 
 procedure Ttestsdfspecific.TestEmptyFileNoHeader;
 // An empty file should return 0 records even if it has a header
-const
-  InputFilename='empty.csv';
 begin
-  TestDataSet.Close;
-
-  if FileExists(InputFilename) then DeleteFile(InputFilename);
-  TestDataset.FileMustExist:=false;
-  TestDataset.FirstLineAsSchema := false;  
-  TestDataset.FileName:=InputFilename;
+  // with Schema, without Header line
+  TestDataset.FirstLineAsSchema := False;
+  TestDataset.FileName := TestFileName('empty.csv');
   TestDataset.Open;
 
   TestDataset.Last;
@@ -81,26 +90,22 @@ end;
 
 procedure Ttestsdfspecific.TestSingleLineHeader;
 // A file with a single data line and header should return 1 records
-const
-  InputFilename='singleh.csv';
 var
   FileStrings: TStringList;
 begin
-  TestDataSet.Close;
+  // with Schema, with Header line
+  TestDataset.FirstLineAsSchema := True;
+  TestDataset.FileName := TestFileName('singleh.csv');
 
-  if FileExists(InputFilename) then DeleteFile(InputFilename);
   FileStrings:=TStringList.Create;
   try
     FileStrings.Add('ID,NAME,BIRTHDAY');
     FileStrings.Add('1,SimpleName,31-12-1976');
-    FileStrings.SaveToFile(InputFileName);
+    FileStrings.SaveToFile(TestDataset.FileName);
   finally
     FileStrings.Free;
   end;
 
-  TestDataset.FileMustExist:=false;
-  TestDataset.FirstLineAsSchema := True;
-  TestDataset.FileName:=InputFilename;
   TestDataset.Open;
   AssertEquals('1', TestDataset.Fields[0].AsString); // just after Open
 
@@ -114,25 +119,21 @@ end;
 
 procedure Ttestsdfspecific.TestSingleLineNoHeader;
 // A file with a single data line, no header should return 1 records
-const
-  InputFilename='single.csv';
 var
   FileStrings: TStringList;
 begin
-  TestDataSet.Close;
+  // with Schema, without Header line
+  TestDataset.FirstLineAsSchema := False;
+  TestDataset.FileName := TestFileName('singleh.csv');
 
-  if FileExists(InputFilename) then DeleteFile(InputFilename);
   FileStrings:=TStringList.Create;
   try
     FileStrings.Add('1,SimpleName,31-12-1976');
-    FileStrings.SaveToFile(InputFileName);
+    FileStrings.SaveToFile(TestDataset.FileName);
   finally
     FileStrings.Free;
   end;
 
-  TestDataset.FileMustExist:=false;
-  TestDataset.FirstLineAsSchema := False;
-  TestDataset.FileName:=InputFilename;
   TestDataset.Open;
   AssertEquals('1', TestDataset.Fields[0].AsString);
 
@@ -147,15 +148,11 @@ end;
 procedure Ttestsdfspecific.TestOutput;
 // Basic assignment test: assign some difficult data to records and
 // see if the RecordCount is correct.
-const
-  OutputFilename='output.csv';
 var
   i: integer;
 begin
-  TestDataSet.Close;
-
-  if FileExists(OutputFilename) then DeleteFile(OutputFileName);
-  TestDataset.FileName:=OutputFileName;
+  // with Schema, with Header line
+  TestDataset.FileName := TestFileName('output.csv');
   TestDataset.Open;
   // Fill test data
   TestDataset.Append;
@@ -276,7 +273,6 @@ procedure Ttestsdfspecific.TestDelimitedTextOutput;
 // Mainly check if writing & reading quotes works.
 // to do: more fully test RFC4180
 const
-  OutputFileName='delim.csv';
   Value1='Delimiter,"and";quote';
   Value2='J"T"';
   Value3='Just a long line';
@@ -287,18 +283,18 @@ const
 Var
   F : Text;
 begin
+  // with Schema, with Header line
   TestDataset.Close;
-  TestDataset.AllowMultiLine:=true;
-  TestDataset.FirstLineAsSchema:=true;
-  if FileExists(OutputFileName) then DeleteFile(OutputFileName);
-  Assign(F,OutputFileName);
+  TestDataset.AllowMultiLine := True;
+  TestDataset.FirstLineAsSchema := True;
+  TestDataset.FileName := TestFileName('delim.csv');
+  Assign(F, TestDataset.FileName);
   Rewrite(F);
   Writeln(F,'Field1,Field2,Field3,Field4,Field5,Field6,Field7');
   Writeln(F,'"Delimiter,""and"";quote","J""T""",Just a long line,"Just a quoted long line","multi');
   Writeln(F,'line","Delimiter,and;done","Some ""random"" quotes"');
   Close(F);
   // Load our dataset
-  TestDataset.FileName:=OutputFileName;
   TestDataset.Open;
 //  AssertEquals('Field count',7,TEstDataset.Fielddefs.Count);
 //  AssertEquals('Record count',1,TEstDataset.RecordCount);
@@ -312,50 +308,63 @@ begin
   AssertEquals('Field7',Value7, TestDataSet.Fields[6].AsString);
 end;
 
-procedure Ttestsdfspecific.TestEmptyHeader;
+procedure Ttestsdfspecific.TestEmptyFieldContents;
+Var
+  F : Text;
+begin
+  // with empty Field name in Header line
+  TestDataset.FirstLineAsSchema := True;
+  TestDataset.Delimiter := ';';
+  TestDataset.FileName := TestFileName();
 
-const
-  OutputFileName='delim.csv';
+  Assign(F, TestDataset.FileName);
+  Rewrite(F);
+  Writeln(F,'1;2;3;;5');
+  Writeln(F,'11;12;13;;15');
+  Close(F);
 
+  TestDataset.Open;
+  AssertEquals('FieldDefs.Count',5,TestDataset.FieldDefs.Count);
+  AssertEquals('RecordCount',1,TestDataset.RecordCount);
+end;
+
+procedure Ttestsdfspecific.TestEmptyFieldHeader;
 Var
   F : Text;
 begin
-  TestDataset.Close;
-  TestDataset.AllowMultiLine:=False;
-  if FileExists(OutputFileName) then DeleteFile(OutputFileName);
-  Assign(F,OutputFileName);
+  // with empty Field name in Header line
+  TestDataset.Delimiter := ';';
+  TestDataset.FirstLineAsSchema := True;
+  TestDataset.FileName := TestFileName();
+
+  Assign(F, TestDataset.FileName);
   Rewrite(F);
   Writeln(F,'1;2;3;;5');
   Close(F);
-  TestDataset.FirstLineAsSchema:=True;
-  TestDataset.Delimiter := ';';
-  TestDataset.FileName:=OutputFileName;
+
   TestDataset.Open;
   AssertEquals('FieldDefs.Count',5,TestDataset.FieldDefs.Count);
   AssertEquals('RecordCount', 0, TestDataset.RecordCount);
 end;
 
-procedure Ttestsdfspecific.TestEmptyHeader2;
-
-const
-  OutputFileName='delim.csv';
+procedure Ttestsdfspecific.TestEmptyFieldNoHeader;
 
 Var
   F : Text;
   S : String;
 
 begin
-  TestDataset.Close;
-  TestDataset.AllowMultiLine:=False;
-  if FileExists(OutputFileName) then DeleteFile(OutputFileName);
-  Assign(F,OutputFileName);
+  // without Schema, without Header line
+  TestDataset.Schema.Clear;
+  TestDataset.FirstLineAsSchema := False;
+  TestDataset.Delimiter := ';';
+  TestDataset.FileName := TestFileName();
+
+  Assign(F, TestDataset.FileName);
   Rewrite(F);
   Writeln(F,'value1;value2;;;');
   Close(F);
-  TestDataset.FirstLineAsSchema:=False;
-  TestDataset.Delimiter := ';';
-  TestDataset.FileName:=OutputFileName;
-  TestDataset.Schema.Clear;
+
   TestDataset.Open;
   AssertEquals('FieldDefs.Count',5,TestDataset.FieldDefs.Count);
   AssertEquals('RecordCount', 1, TestDataset.RecordCount);
@@ -363,41 +372,40 @@ begin
   TestDataset.Fields[0].AsString:='Value1';
   TestDataset.Post;
   TestDataset.Close;
-  Assign(F,OutputFileName);
+
+  Assign(F, TestDataset.FileName);
   Reset(F);
   ReadLn(F,S);
   Close(F);
   AssertEquals('No data lost','Value1;value2;;;',S);
 end;
 
-procedure Ttestsdfspecific.TestEmptyHeaderStripTrailingDelimiters;
-const
-  OutputFileName='delim.csv';
-
+procedure Ttestsdfspecific.TestEmptyFieldHeaderStripTrailingDelimiters;
 Var
   F : Text;
   S : String;
 
 begin
-  TestDataset.Close;
-  TestDataset.AllowMultiLine:=False;
-  if FileExists(OutputFileName) then DeleteFile(OutputFileName);
-  Assign(F,OutputFileName);
+  // without Schema, without Header line
+  TestDataset.Schema.Clear;
+  TestDataset.FirstLineAsSchema := False;
+  TestDataset.Delimiter := ';';
+  TestDataset.StripTrailingDelimiters := True;
+  TestDataset.FileName := TestFileName();
+
+  Assign(F, TestDataset.FileName);
   Rewrite(F);
   Writeln(F,'value1;value2;;;');
   Close(F);
-  TestDataset.StripTrailingDelimiters:=True;
-  TestDataset.FirstLineAsSchema:=False;
-  TestDataset.Delimiter := ';';
-  TestDataset.FileName:=OutputFileName;
-  TestDataset.Schema.Clear;
+
   TestDataset.Open;
   AssertEquals('FieldDefs.Count',2,TestDataset.FieldDefs.Count);
   TestDataset.Edit;
   TestDataset.Fields[0].AsString:='Value1';
   TestDataset.Post;
   TestDataset.Close;
-  Assign(F,OutputFileName);
+
+  Assign(F, TestDataset.FileName);
   Reset(F);
   ReadLn(F,S);
   Close(F);
@@ -405,64 +413,38 @@ begin
 end;
 
 procedure Ttestsdfspecific.TestStripTrailingDelimiters;
-const
-  OutputFileName='delim.csv';
-
 Var
   F : Text;
-  S,S2 : String;
+  S1,S2 : String;
 
 begin
-  TestDataset.Close;
-  TestDataset.AllowMultiLine:=False;
-  if FileExists(OutputFileName) then DeleteFile(OutputFileName);
-  Assign(F,OutputFileName);
+  // without Schema, with Header line
+  TestDataset.Schema.Clear;
+  TestDataset.FirstLineAsSchema := True;
+  TestDataset.Delimiter := ';';
+  TestDataset.StripTrailingDelimiters := True;
+  TestDataset.FileName := TestFileName();;
+
+  Assign(F, TestDataset.FileName);
   Rewrite(F);
   Writeln(F,'value1;value2;;;');
   Writeln(F,'value1;value2;;;');
   Close(F);
-  TestDataset.StripTrailingDelimiters:=True;
-  TestDataset.FirstLineAsSchema:=False;
-  TestDataset.Delimiter := ';';
-  TestDataset.FileName:=OutputFileName;
-  TestDataset.Schema.Clear;
+
   TestDataset.Open;
   AssertEquals('FieldDefs.Count',2,TestDataset.FieldDefs.Count);
   TestDataset.Edit;
   TestDataset.Fields[0].AsString:='Value1';
   TestDataset.Post;
   TestDataset.Close;
-  Assign(F,OutputFileName);
+
+  Assign(F, TestDataset.FileName);
   Reset(F);
-  ReadLn(F,S);
+  ReadLn(F,S1);
   ReadLn(F,S2);
   Close(F);
-  AssertEquals('Headers lost','Value1;value2',S);
-  AssertEquals('Data lost','Value1;value2',S);
-end;
-
-procedure Ttestsdfspecific.TestEmptyFieldContents;
-
-const
-  OutputFileName='delim.csv';
-
-Var
-  F : Text;
-begin
-  TestDataset.Close;
-  TestDataset.AllowMultiLine:=False;
-  if FileExists(OutputFileName) then DeleteFile(OutputFileName);
-  Assign(F,OutputFileName);
-  Rewrite(F);
-  Writeln(F,'1;2;3;;5');
-  Writeln(F,'11;12;13;;15');
-  Close(F);
-  TestDataset.FirstLineAsSchema:=True;
-  TestDataset.Delimiter := ';';
-  TestDataset.FileName:=OutputFileName;
-  TestDataset.Open;
-  AssertEquals('FieldDefs.Count',5,TestDataset.FieldDefs.Count);
-  AssertEquals('RecordCount',1,TestDataset.RecordCount);
+  AssertEquals('Headers lost','value1;value2;;;',S1); // should striping affect also header line ?
+  AssertEquals('Data lost','Value1;value2',S2);
 end;
 
 
@@ -471,8 +453,9 @@ procedure Ttestsdfspecific.Setup;
 begin
   TestDataset := TSDFDataset.Create(nil);
   TestDataset.Delimiter := ',';
-  TestDataset.FileMustExist:=false;
+  TestDataset.FileMustExist := False;
   TestDataset.FirstLineAsSchema := True;
+  TestDataset.AllowMultiLine := False;
   TestDataset.Schema.Add('ID');
   TestDataset.Schema.Add('NAME');
   TestDataset.Schema.Add('BIRTHDAY');