tcsdfdata.pp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. unit tcsdfdata;
  2. // Tests specific functionality of sdfdataset (multiline etc)
  3. {$mode objfpc}{$H+}
  4. interface
  5. uses
  6. Classes, SysUtils, Fpcunit, Testutils, Testregistry, testdecorator,
  7. dateutils,sdfdata,ToolsUnit;
  8. type
  9. { Ttestsdfspecific }
  10. Ttestsdfspecific = class(Ttestcase)
  11. protected
  12. TestDataset: TSDFDataset;
  13. procedure Setup; override;
  14. procedure Teardown; override;
  15. published
  16. procedure TestEmptyFileHeader;
  17. procedure TestEmptyFileNoHeader;
  18. procedure TestSingleLineHeader;
  19. procedure TestSingleLineNoHeader;
  20. procedure TestOutput;
  21. procedure TestInputOurFormat;
  22. procedure TestDelimitedTextOutput;
  23. end;
  24. implementation
  25. procedure Ttestsdfspecific.TestEmptyFileHeader;
  26. // An empty file should return 0 records even if it has a header
  27. const
  28. InputFilename='empty.csv';
  29. begin
  30. TestDataSet.Close;
  31. if FileExists(InputFilename) then DeleteFile(InputFilename);
  32. TestDataset.FileMustExist:=false;
  33. TestDataset.FirstLineAsSchema := True;
  34. TestDataset.FileName:=InputFilename;
  35. TestDataset.Open;
  36. TestDataset.Last;
  37. TestDataset.First;
  38. AssertEquals('Number of records in test dataset', 0, TestDataset.RecordCount);
  39. TestDataset.Close;
  40. end;
  41. procedure Ttestsdfspecific.TestEmptyFileNoHeader;
  42. // An empty file should return 0 records even if it has a header
  43. const
  44. InputFilename='empty.csv';
  45. begin
  46. TestDataSet.Close;
  47. if FileExists(InputFilename) then DeleteFile(InputFilename);
  48. TestDataset.FileMustExist:=false;
  49. TestDataset.FirstLineAsSchema := false;
  50. TestDataset.FileName:=InputFilename;
  51. TestDataset.Open;
  52. TestDataset.Last;
  53. TestDataset.First;
  54. AssertEquals('Number of records in test dataset', 0, TestDataset.RecordCount);
  55. TestDataset.Close;
  56. end;
  57. procedure Ttestsdfspecific.TestSingleLineHeader;
  58. // A file with a single data line and header should return 1 records
  59. const
  60. InputFilename='singleh.csv';
  61. var
  62. FileStrings: TStringList;
  63. begin
  64. TestDataSet.Close;
  65. if FileExists(InputFilename) then DeleteFile(InputFilename);
  66. FileStrings:=TStringList.Create;
  67. try
  68. FileStrings.Add('ID,NAME,BIRTHDAY');
  69. FileStrings.Add('1,SimpleName,31-12-1976');
  70. FileStrings.SaveToFile(InputFileName);
  71. finally
  72. FileStrings.Free;
  73. end;
  74. TestDataset.FileMustExist:=false;
  75. TestDataset.FirstLineAsSchema := true;
  76. TestDataset.FileName:=InputFilename;
  77. TestDataset.Open;
  78. TestDataset.Last;
  79. TestDataset.First;
  80. AssertEquals('Number of records in test dataset', 1, TestDataset.RecordCount);
  81. TestDataset.Close;
  82. end;
  83. procedure Ttestsdfspecific.TestSingleLineNoHeader;
  84. // A file with a single data line, no header should return 1 records
  85. const
  86. InputFilename='single.csv';
  87. var
  88. FileStrings: TStringList;
  89. begin
  90. TestDataSet.Close;
  91. if FileExists(InputFilename) then DeleteFile(InputFilename);
  92. FileStrings:=TStringList.Create;
  93. try
  94. FileStrings.Add('1,SimpleName,31-12-1976');
  95. FileStrings.SaveToFile(InputFileName);
  96. finally
  97. FileStrings.Free;
  98. end;
  99. TestDataset.FileMustExist:=false;
  100. TestDataset.FirstLineAsSchema := false;
  101. TestDataset.FileName:=InputFilename;
  102. TestDataset.Open;
  103. TestDataset.Last;
  104. TestDataset.First;
  105. AssertEquals('Number of records in test dataset', 1, TestDataset.RecordCount);
  106. TestDataset.Close;
  107. end;
  108. procedure Ttestsdfspecific.TestOutput;
  109. const
  110. OutputFilename='output.csv';
  111. begin
  112. TestDataSet.Close;
  113. if FileExists(OutputFilename) then DeleteFile(OutputFileName);
  114. TestDataset.FileName:=OutputFileName;
  115. TestDataset.Open;
  116. // Fill test data
  117. TestDataset.Append;
  118. TestDataset.FieldByName('ID').AsInteger := 1;
  119. // Data with quotes
  120. TestDataset.FieldByName('NAME').AsString := 'J"T"';
  121. TestDataset.FieldByName('BIRTHDAY').AsDateTime := ScanDateTime('yyyymmdd', '19761231', 1);
  122. TestDataset.Post;
  123. TestDataset.Append;
  124. TestDataset.FieldByName('ID').AsInteger := 2;
  125. // Data with delimiter
  126. TestDataset.FieldByName('NAME').AsString := 'Hello'+TestDataset.Delimiter+' goodbye';
  127. TestDataset.FieldByName('BIRTHDAY').AsDateTime := ScanDateTime('yyyymmdd', '19761231', 1);
  128. TestDataset.Post;
  129. TestDataset.Append;
  130. TestDataset.FieldByName('ID').AsInteger := 3;
  131. //Data with delimiter and quote (to test 19376)
  132. TestDataset.FieldByName('NAME').AsString := 'Delimiter,"and";quote';
  133. TestDataset.FieldByName('BIRTHDAY').AsDateTime := ScanDateTime('yyyymmdd', '19761231', 1);
  134. TestDataset.Post;
  135. TestDataset.Append;
  136. TestDataset.FieldByName('ID').AsInteger := 4;
  137. // Regular data
  138. TestDataset.FieldByName('NAME').AsString := 'Just a long line of text without anything special';
  139. TestDataset.FieldByName('BIRTHDAY').AsDateTime := ScanDateTime('yyyymmdd', '19761231', 1);
  140. TestDataset.Post;
  141. TestDataset.Last;
  142. TestDataset.First;
  143. // This fails - seems it sees the header as a record, too?
  144. AssertEquals('Number of records in test dataset', 4, TestDataset.RecordCount);
  145. TestDataset.Close;
  146. end;
  147. procedure Ttestsdfspecific.TestInputOurFormat;
  148. // Test if input works with our format
  149. // Mainly check if reading quotes is according to Delphi sdf specs and works.
  150. // See test results from bug 19610 for evidence that the strings below should work.
  151. // If this works, we can switch to this and be RFC 4180 compliant and Delphi compliant.
  152. const
  153. OutputFileName='input.csv';
  154. //Value1 is the on disk format; it should translate to Expected1
  155. Value1='"Delimiter,""and"";quote"';
  156. Expected1='Delimiter,"and";quote';
  157. Value2='"J""T"""';
  158. Expected2='J"T"';
  159. Value3='Just a long line';
  160. Expected3='Just a long line';
  161. //Note: Delphi can read this, see evidence in bug 19610 (the "quoted and space" value)
  162. Value4='"Just a quoted long line"';
  163. Expected4='Just a quoted long line';
  164. // Delphi can read multiline, see evidence in bug 19610 (the multiline entry)
  165. Value5='"quoted_multi'+#13+#10+'line"';
  166. Expected5='quoted_multi'+#13+#10+'line';
  167. Value6='"Delimiter,and;quoted"';
  168. Expected6='Delimiter,and;quoted';
  169. Value7='"A random""quote"';
  170. Expected7='A random"quote';
  171. var
  172. FileStrings: TStringList;
  173. begin
  174. TestDataset.Close;
  175. TestDataset.AllowMultiLine:=true;
  176. if FileExists(OutputFilename) then DeleteFile(OutputFileName);
  177. FileStrings:=TStringList.Create;
  178. try
  179. FileStrings.Add('ID,NAME,BIRTHDAY');
  180. FileStrings.Add('1,'+Value1+',31-12-1976');
  181. FileStrings.Add('2,'+Value2+',31-12-1976');
  182. FileStrings.Add('3,'+Value3+',31-12-1976');
  183. FileStrings.Add('4,'+Value4+',31-12-1976');
  184. FileStrings.Add('5,'+Value5+',31-12-1976');
  185. FileStrings.Add('6,'+Value6+',31-12-1976');
  186. FileStrings.Add('7,'+Value7+',31-12-1976');
  187. FileStrings.SaveToFile(OutputFileName);
  188. finally
  189. FileStrings.Free;
  190. end;
  191. // Load our dataset
  192. TestDataset.FileName:=OutputFileName;
  193. TestDataset.Open;
  194. TestDataset.First;
  195. AssertEquals(Expected1, TestDataSet.FieldByName('NAME').AsString);
  196. TestDataSet.Next;
  197. AssertEquals(Expected2, TestDataSet.FieldByName('NAME').AsString);
  198. TestDataSet.Next;
  199. AssertEquals(Expected3, TestDataSet.FieldByName('NAME').AsString);
  200. TestDataSet.Next;
  201. AssertEquals(Expected4, TestDataSet.FieldByName('NAME').AsString);
  202. TestDataSet.Next;
  203. AssertEquals(Expected5, TestDataSet.FieldByName('NAME').AsString);
  204. TestDataSet.Next;
  205. AssertEquals(Expected6, TestDataSet.FieldByName('NAME').AsString);
  206. TestDataSet.Next;
  207. AssertEquals(Expected7, TestDataSet.FieldByName('NAME').AsString);
  208. end;
  209. procedure Ttestsdfspecific.TestDelimitedTextOutput;
  210. // Test if input works with our format
  211. // Mainly check if reading quotes is according to Delphi sdf specs and works.
  212. // See test results from bug 19610 for evidence that the strings below should work.
  213. // If this works, we can switch to this and be RFC 4180 compliant and Delphi compliant.
  214. const
  215. OutputFileName='delim.csv';
  216. //Value1 is the on disk format; it should translate to Expected1
  217. Value1='Delimiter,"and";quote';
  218. Value2='J"T"';
  219. Value3='Just a long line';
  220. Value4='Just a quoted long line';
  221. Value5='multi'+#13+#10+'line';
  222. Value6='Delimiter,and;done';
  223. Value7='Some "random" quotes';
  224. var
  225. FileStrings: TStringList;
  226. OneRecord: TStringList;
  227. begin
  228. TestDataset.Close;
  229. TestDataset.AllowMultiLine:=true;
  230. if FileExists(OutputFileName) then DeleteFile(OutputFileName);
  231. FileStrings:=TStringList.Create;
  232. OneRecord:=TStringList.Create;
  233. try
  234. FileStrings.Add('Field1,Field2,Field3,Field4,Field5,Field6,Field7');
  235. OneRecord.Add(Value1);
  236. OneRecord.Add(Value2);
  237. OneRecord.Add(Value3);
  238. OneRecord.Add(Value4);
  239. OneRecord.Add(Value5);
  240. OneRecord.Add(Value6);
  241. OneRecord.Add(Value7);
  242. OneRecord.Delimiter:=',';
  243. OneRecord.QuoteChar:='"';
  244. OneRecord.StrictDelimiter:=true;
  245. FileStrings.Add(OneRecord.DelimitedText);
  246. FileStrings.SaveToFile(OutputFileName);
  247. finally
  248. FileStrings.Free;
  249. OneRecord.Free;
  250. end;
  251. // Load our dataset
  252. TestDataset.FileName:=OutputFileName;
  253. TestDataset.Open;
  254. TestDataset.First;
  255. AssertEquals(Value1, TestDataSet.Fields[0].AsString);
  256. AssertEquals(Value2, TestDataSet.Fields[1].AsString);
  257. AssertEquals(Value3, TestDataSet.Fields[2].AsString);
  258. AssertEquals(Value4, TestDataSet.Fields[3].AsString);
  259. AssertEquals(Value5, TestDataSet.Fields[4].AsString);
  260. AssertEquals(Value6, TestDataSet.Fields[5].AsString);
  261. AssertEquals(Value7, TestDataSet.Fields[6].AsString);
  262. end;
  263. procedure Ttestsdfspecific.Setup;
  264. begin
  265. TestDataset := TSDFDataset.Create(nil);
  266. TestDataset.Delimiter := ',';
  267. TestDataset.FileMustExist:=false;
  268. TestDataset.FirstLineAsSchema := True;
  269. TestDataset.Schema.Add('ID');
  270. TestDataset.Schema.Add('NAME');
  271. TestDataset.Schema.Add('BIRTHDAY');
  272. end;
  273. procedure Ttestsdfspecific.Teardown;
  274. begin
  275. try
  276. TestDataset.Close;
  277. except
  278. //swallow
  279. end;
  280. TestDataset.Free;
  281. try
  282. //DeleteFile(FCSVFileName);
  283. except
  284. //swallow
  285. end;
  286. end;
  287. initialization
  288. // Only run these tests if we are running
  289. // sdf tests. After all, running these when testing
  290. // e.g. SQL RDBMS doesn't make sense.
  291. if uppercase(dbconnectorname)='SDFDS' then
  292. begin
  293. Registertest(Ttestsdfspecific);
  294. end;
  295. end.