tcsdfdata.pp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. unit tcsdfdata;
  2. // Tests specific functionality of SdfDataSet (multiline etc)
  3. // and FixedFormatDataSet
  4. {$mode objfpc}{$H+}
  5. interface
  6. uses
  7. Classes, SysUtils, Fpcunit, TestRegistry,
  8. dateutils,sdfdata,ToolsUnit;
  9. type
  10. { TTestSdfSpecific }
  11. TTestSdfSpecific = class(TTestCase)
  12. private
  13. TestDataset: TSdfDataset;
  14. function TestFileName(const FileName: string=''): string;
  15. protected
  16. procedure Setup; override;
  17. procedure Teardown; override;
  18. published
  19. procedure TestEmptyFileHeader;
  20. procedure TestEmptyFileNoHeader;
  21. procedure TestSingleLineHeader;
  22. procedure TestSingleLineNoHeader;
  23. procedure TestOutput;
  24. procedure TestDelimitedTextOutput;
  25. procedure TestEmptyFieldHeader;
  26. Procedure TestEmptyFieldNoHeader;
  27. procedure TestEmptyFieldContents;
  28. Procedure TestEmptyFieldHeaderStripTrailingDelimiters;
  29. Procedure TestStripTrailingDelimiters;
  30. end;
  31. { TTestFixedFormatSpecific }
  32. TTestFixedFormatSpecific = class(TTestCase)
  33. private
  34. TestDataset: TFixedFormatDataset;
  35. function TestFileName(const FileName: string=''): string;
  36. procedure CreateTestFile;
  37. protected
  38. procedure Setup; override;
  39. procedure Teardown; override;
  40. published
  41. procedure TestTrimSpace;
  42. procedure TestNoTrimSpace;
  43. end;
  44. implementation
  45. function Ttestsdfspecific.TestFileName(const FileName: string): string;
  46. const
  47. DefaultTestFileName = 'test.csv';
  48. begin
  49. if FileName = '' then
  50. Result := DefaultTestFileName
  51. else
  52. Result := FileName;
  53. if dbname <> '' then
  54. begin
  55. ForceDirectories(dbname);
  56. Result := IncludeTrailingPathDelimiter(dbname) + Result;
  57. end;
  58. if FileExists(Result) then DeleteFile(Result);
  59. end;
  60. procedure Ttestsdfspecific.TestEmptyFileHeader;
  61. // An empty file should return 0 records even if it has a header
  62. begin
  63. // with Schema, with Header line
  64. TestDataset.FirstLineAsSchema := True;
  65. TestDataset.FileName := TestFileName('empty.csv');
  66. TestDataset.Open;
  67. TestDataset.Last;
  68. TestDataset.First;
  69. AssertEquals('Number of records in test dataset', 0, TestDataset.RecordCount);
  70. TestDataset.Close;
  71. end;
  72. procedure Ttestsdfspecific.TestEmptyFileNoHeader;
  73. // An empty file should return 0 records even if it has a header
  74. begin
  75. // with Schema, without Header line
  76. TestDataset.FirstLineAsSchema := False;
  77. TestDataset.FileName := TestFileName('empty.csv');
  78. TestDataset.Open;
  79. TestDataset.Last;
  80. TestDataset.First;
  81. AssertEquals('Number of records in test dataset', 0, TestDataset.RecordCount);
  82. TestDataset.Close;
  83. end;
  84. procedure Ttestsdfspecific.TestSingleLineHeader;
  85. // A file with a single data line and header should return 1 records
  86. var
  87. FileStrings: TStringList;
  88. begin
  89. // with Schema, with Header line, which differs from Schema
  90. TestDataset.FirstLineAsSchema := True;
  91. TestDataset.FileName := TestFileName('singleh.csv');
  92. FileStrings:=TStringList.Create;
  93. try
  94. FileStrings.Add('ID,NAME,BIRTHDAY,GENDER'); // 4 fields override 3 fields in Schema
  95. FileStrings.Add('1,SimpleName,31-12-1976,M');
  96. FileStrings.SaveToFile(TestDataset.FileName);
  97. finally
  98. FileStrings.Free;
  99. end;
  100. TestDataset.Open;
  101. AssertEquals('FieldDefs.Count', 4, TestDataset.FieldDefs.Count);
  102. AssertEquals('1', TestDataset.Fields[0].AsString); // just after Open
  103. TestDataset.Last;
  104. TestDataset.First;
  105. AssertEquals('RecNo', 1, TestDataset.RecNo);
  106. AssertEquals('RecordCount', 1, TestDataset.RecordCount);
  107. TestDataset.Close;
  108. AssertEquals('RecordCount after Close', 0, TestDataset.RecordCount);
  109. end;
  110. procedure Ttestsdfspecific.TestSingleLineNoHeader;
  111. // A file with a single data line, no header should return 1 records
  112. var
  113. FileStrings: TStringList;
  114. begin
  115. // with Schema, without Header line
  116. TestDataset.FirstLineAsSchema := False;
  117. TestDataset.FileName := TestFileName('singleh.csv');
  118. FileStrings:=TStringList.Create;
  119. try
  120. FileStrings.Add('1,SimpleName,31-12-1976');
  121. FileStrings.SaveToFile(TestDataset.FileName);
  122. finally
  123. FileStrings.Free;
  124. end;
  125. TestDataset.Open;
  126. AssertEquals('FieldDefs.Count', 3, TestDataset.FieldDefs.Count);
  127. AssertEquals('1', TestDataset.Fields[0].AsString);
  128. TestDataset.Last;
  129. TestDataset.First;
  130. AssertEquals('RecNo', 1, TestDataset.RecNo);
  131. AssertEquals('RecordCount', 1, TestDataset.RecordCount);
  132. TestDataset.Close;
  133. AssertEquals('RecordCount after Close', 0, TestDataset.RecordCount);
  134. end;
  135. procedure Ttestsdfspecific.TestOutput;
  136. // Basic assignment test: assign some difficult data to records and
  137. // see if the RecordCount is correct.
  138. const
  139. NAME: array[1..4] of string = (
  140. 'J"T"', // Data with quotes
  141. 'Hello, goodbye', // Data with delimiter
  142. ' Just a line with spaces ', // Regular data
  143. 'Delimiter,"and";quote' // Data with delimiter and quote
  144. );
  145. var
  146. i: integer;
  147. begin
  148. // with Schema, with Header line
  149. TestDataset.Schema[1] := 'NAME=30';
  150. TestDataset.FileName := TestFileName('output.csv');
  151. TestDataset.Open;
  152. // Fill test data
  153. TestDataset.Append;
  154. TestDataset.FieldByName('ID').AsInteger := 1;
  155. TestDataset.FieldByName('NAME').AsString := NAME[1];
  156. TestDataset.FieldByName('BIRTHDAY').AsDateTime := ScanDateTime('yyyymmdd', '19761231', 1);
  157. TestDataset.Post;
  158. TestDataset.Append;
  159. TestDataset.FieldByName('ID').AsInteger := 2;
  160. TestDataset.FieldByName('NAME').AsString := NAME[2];
  161. TestDataset.FieldByName('BIRTHDAY').AsDateTime := ScanDateTime('yyyymmdd', '19761231', 1);
  162. TestDataset.Post;
  163. TestDataset.Append;
  164. TestDataset.FieldByName('ID').AsInteger := 4;
  165. TestDataset.FieldByName('NAME').AsString := NAME[4];
  166. TestDataset.FieldByName('BIRTHDAY').AsDateTime := ScanDateTime('yyyymmdd', '19761231', 1);
  167. TestDataset.Post;
  168. TestDataset.Insert;
  169. TestDataset.FieldByName('ID').AsInteger := 3;
  170. TestDataset.FieldByName('NAME').AsString := NAME[3];
  171. TestDataset.FieldByName('BIRTHDAY').AsDateTime := ScanDateTime('yyyymmdd', '19761231', 1);
  172. TestDataset.Post;
  173. // test sequential order of records
  174. TestDataset.First;
  175. for i:=1 to 4 do begin
  176. AssertEquals('RecNo', i, TestDataset.RecNo);
  177. AssertEquals(i, TestDataset.FieldByName('ID').AsInteger);
  178. TestDataset.Next;
  179. end;
  180. // set/test RecNo
  181. for i:=1 to 4 do begin
  182. TestDataset.RecNo := i;
  183. AssertEquals('RecNo', i, TestDataset.RecNo);
  184. AssertEquals(i, TestDataset.FieldByName('ID').AsInteger);
  185. end;
  186. AssertEquals('RecordCount', 4, TestDataset.RecordCount);
  187. TestDataset.Close;
  188. AssertEquals('RecordCount after Close', 0, TestDataset.RecordCount);
  189. // reopen, retest
  190. TestDataset.Open;
  191. for i:=1 to 4 do begin
  192. AssertEquals(NAME[i], TestDataset.FieldByName('NAME').AsString);
  193. TestDataset.Next;
  194. end;
  195. AssertTrue('Eof', TestDataset.Eof);
  196. end;
  197. procedure Ttestsdfspecific.TestDelimitedTextOutput;
  198. // Test if saving and loading data keeps the original values.
  199. // Mainly check if writing & reading quotes works.
  200. // to do: more fully test RFC4180
  201. const
  202. Value1='Delimiter,"and";quote';
  203. Value2='J"T"';
  204. Value3='Just a long line';
  205. Value4='Just a quoted long line';
  206. Value5='multi'+#13+#10+'line';
  207. Value6='Delimiter,and;done';
  208. Value7='Some "random" quotes';
  209. Var
  210. F : Text;
  211. begin
  212. // with Schema, with Header line
  213. TestDataset.Close;
  214. TestDataset.AllowMultiLine := True;
  215. TestDataset.FirstLineAsSchema := True;
  216. TestDataset.FileName := TestFileName('delim.csv');
  217. Assign(F, TestDataset.FileName);
  218. Rewrite(F);
  219. Writeln(F,'Field1,Field2,Field3,Field4,Field5,Field6,Field7');
  220. Writeln(F,'"Delimiter,""and"";quote","J""T""",Just a long line,"Just a quoted long line","multi');
  221. Writeln(F,'line","Delimiter,and;done","Some ""random"" quotes"');
  222. Close(F);
  223. // Load our dataset
  224. TestDataset.Open;
  225. // AssertEquals('Field count',7,TestDataset.FieldDefs.Count);
  226. // AssertEquals('Record count',1,TestDataset.RecordCount);
  227. TestDataset.First;
  228. AssertEquals('Field1', Value1, TestDataSet.Fields[0].AsString);
  229. AssertEquals('Field2', Value2, TestDataSet.Fields[1].AsString);
  230. AssertEquals('Field3', Value3, TestDataSet.Fields[2].AsString);
  231. AssertEquals('Field4', Value4, TestDataSet.Fields[3].AsString);
  232. AssertEquals('Field5', Value5, TestDataSet.Fields[4].AsString);
  233. AssertEquals('Field6', Value6, TestDataSet.Fields[5].AsString);
  234. AssertEquals('Field7' ,Value7, TestDataSet.Fields[6].AsString);
  235. end;
  236. procedure Ttestsdfspecific.TestEmptyFieldContents;
  237. Var
  238. F : Text;
  239. begin
  240. // with empty Field name in Header line
  241. TestDataset.FirstLineAsSchema := True;
  242. TestDataset.Delimiter := ';';
  243. TestDataset.FileName := TestFileName();
  244. Assign(F, TestDataset.FileName);
  245. Rewrite(F);
  246. Writeln(F,'1;2;3;;5');
  247. Writeln(F,'11;12;13;;15');
  248. Close(F);
  249. TestDataset.Open;
  250. AssertEquals('FieldDefs.Count',5,TestDataset.FieldDefs.Count);
  251. AssertEquals('RecordCount',1,TestDataset.RecordCount);
  252. end;
  253. procedure Ttestsdfspecific.TestEmptyFieldHeader;
  254. Var
  255. F : Text;
  256. begin
  257. // with empty Field name in Header line
  258. TestDataset.Delimiter := ';';
  259. TestDataset.FirstLineAsSchema := True;
  260. TestDataset.FileName := TestFileName();
  261. Assign(F, TestDataset.FileName);
  262. Rewrite(F);
  263. Writeln(F,'1;2;3;;5');
  264. Close(F);
  265. TestDataset.Open;
  266. AssertEquals('FieldDefs.Count',5,TestDataset.FieldDefs.Count);
  267. AssertEquals('RecordCount', 0, TestDataset.RecordCount);
  268. end;
  269. procedure Ttestsdfspecific.TestEmptyFieldNoHeader;
  270. Var
  271. F : Text;
  272. S1,S2 : String;
  273. begin
  274. // without Schema, without Header line
  275. TestDataset.Schema.Clear;
  276. TestDataset.FirstLineAsSchema := False;
  277. TestDataset.Delimiter := ';';
  278. TestDataset.FileName := TestFileName();
  279. Assign(F, TestDataset.FileName);
  280. Rewrite(F);
  281. Writeln(F,'value1;value2;;;');
  282. Close(F);
  283. with TestDataset do begin
  284. Open;
  285. AssertEquals('FieldDefs.Count', 5, FieldDefs.Count);
  286. AssertEquals('RecordCount', 1, RecordCount);
  287. // #1 record
  288. Edit;
  289. Fields[0].AsString := 'Value1';
  290. Post;
  291. AssertEquals('Fields[4]', '', Fields[4].AsString);
  292. // #2 record
  293. Append;
  294. Fields[1].AsString := 'Value2';
  295. Fields[2].AsString := 'Value"'; // embedded double quote
  296. Post;
  297. Close;
  298. end;
  299. Assign(F, TestDataset.FileName);
  300. Reset(F);
  301. ReadLn(F,S1);
  302. ReadLn(F,S2);
  303. Close(F);
  304. AssertEquals('Value1;value2;;;',S1);
  305. AssertEquals(';Value2;"Value""";;',S2);
  306. end;
  307. procedure Ttestsdfspecific.TestEmptyFieldHeaderStripTrailingDelimiters;
  308. Var
  309. F : Text;
  310. S : String;
  311. begin
  312. // without Schema, without Header line
  313. TestDataset.Schema.Clear;
  314. TestDataset.FirstLineAsSchema := False;
  315. TestDataset.Delimiter := ';';
  316. TestDataset.StripTrailingDelimiters := True;
  317. TestDataset.FileName := TestFileName();
  318. Assign(F, TestDataset.FileName);
  319. Rewrite(F);
  320. Writeln(F,'value1;value2;;;');
  321. Close(F);
  322. TestDataset.Open;
  323. AssertEquals('FieldDefs.Count',2,TestDataset.FieldDefs.Count);
  324. TestDataset.Edit;
  325. TestDataset.Fields[0].AsString:='Value1';
  326. TestDataset.Post;
  327. TestDataset.Close;
  328. Assign(F, TestDataset.FileName);
  329. Reset(F);
  330. ReadLn(F,S);
  331. Close(F);
  332. AssertEquals('No data lost','Value1;value2',S);
  333. end;
  334. procedure Ttestsdfspecific.TestStripTrailingDelimiters;
  335. Var
  336. F : Text;
  337. S1,S2 : String;
  338. begin
  339. // without Schema, with Header line
  340. TestDataset.Schema.Clear;
  341. TestDataset.FirstLineAsSchema := True;
  342. TestDataset.Delimiter := ';';
  343. TestDataset.StripTrailingDelimiters := True;
  344. TestDataset.FileName := TestFileName();;
  345. Assign(F, TestDataset.FileName);
  346. Rewrite(F);
  347. Writeln(F,'value1;value2;;;');
  348. Writeln(F,'value1;value2;;;');
  349. Close(F);
  350. TestDataset.Open;
  351. AssertEquals('FieldDefs.Count',2,TestDataset.FieldDefs.Count);
  352. TestDataset.Edit;
  353. TestDataset.Fields[0].AsString:='Value1';
  354. TestDataset.Post;
  355. TestDataset.Close;
  356. Assign(F, TestDataset.FileName);
  357. Reset(F);
  358. ReadLn(F,S1);
  359. ReadLn(F,S2);
  360. Close(F);
  361. AssertEquals('Headers lost','value1;value2;;;',S1); // should striping affect also header line ?
  362. AssertEquals('Data lost','Value1;value2',S2);
  363. end;
  364. procedure Ttestsdfspecific.Setup;
  365. begin
  366. TestDataset := TSDFDataset.Create(nil);
  367. TestDataset.Delimiter := ',';
  368. TestDataset.FileMustExist := False;
  369. TestDataset.FirstLineAsSchema := True;
  370. TestDataset.TrimSpace := False;
  371. TestDataset.AllowMultiLine := False;
  372. TestDataset.Schema.Add('ID');
  373. TestDataset.Schema.Add('NAME');
  374. TestDataset.Schema.Add('BIRTHDAY');
  375. end;
  376. procedure Ttestsdfspecific.Teardown;
  377. begin
  378. try
  379. TestDataset.Close;
  380. except
  381. //swallow
  382. end;
  383. TestDataset.Free;
  384. try
  385. //DeleteFile(FCSVFileName);
  386. except
  387. //swallow
  388. end;
  389. end;
  390. { TTestFixedFormatSpecific }
  391. procedure TTestFixedFormatSpecific.Setup;
  392. begin
  393. TestDataset := TFixedFormatDataset.Create(nil);
  394. TestDataset.FileMustExist := False;
  395. TestDataset.Schema.Add('ID=1');
  396. TestDataset.Schema.Add('NAME=10');
  397. TestDataset.Schema.Add('BIRTHDAY=10');
  398. end;
  399. procedure TTestFixedFormatSpecific.Teardown;
  400. begin
  401. TestDataSet.Close;
  402. TestDataSet.Free;
  403. end;
  404. function TTestFixedFormatSpecific.TestFileName(const FileName: string): string;
  405. const
  406. DefaultTestFileName = 'test.sdf';
  407. begin
  408. if FileName = '' then
  409. Result := DefaultTestFileName
  410. else
  411. Result := FileName;
  412. if dbname <> '' then
  413. begin
  414. ForceDirectories(dbname);
  415. Result := IncludeTrailingPathDelimiter(dbname) + Result;
  416. end;
  417. if FileExists(Result) then DeleteFile(Result);
  418. end;
  419. procedure TTestFixedFormatSpecific.CreateTestFile;
  420. var
  421. FileStrings: TStringList;
  422. begin
  423. FileStrings:=TStringList.Create;
  424. try
  425. FileStrings.Add('1John 2000-01-01');
  426. FileStrings.Add('2Christiana2001-02-02');
  427. FileStrings.SaveToFile(TestDataset.FileName);
  428. finally
  429. FileStrings.Free;
  430. end;
  431. end;
  432. procedure TTestFixedFormatSpecific.TestTrimSpace;
  433. begin
  434. TestDataset.FileName := TestFileName();
  435. CreateTestFile;
  436. with TestDataset do begin
  437. Open;
  438. AssertEquals('FieldDefs.Count', 3, FieldDefs.Count);
  439. AssertEquals('1', Fields[0].AsString); // just after Open
  440. Last;
  441. First;
  442. AssertEquals('RecNo', 1, RecNo);
  443. AssertEquals('RecordCount', 2, RecordCount);
  444. AssertEquals('1', Fields[0].AsString);
  445. AssertEquals('John', Fields[1].AsString);
  446. Next;
  447. AssertEquals('2', Fields[0].AsString);
  448. AssertEquals('Christiana', Fields[1].AsString);
  449. Edit;
  450. Fields[1].AsString := 'Chris';
  451. Post;
  452. AssertEquals('Chris', Fields[1].AsString);
  453. Close; // save changes
  454. AssertEquals('RecordCount after Close', 0, RecordCount);
  455. Open;
  456. Next;
  457. AssertEquals('Chris', Fields[1].AsString);
  458. end;
  459. end;
  460. procedure TTestFixedFormatSpecific.TestNoTrimSpace;
  461. begin
  462. TestDataset.FileName := TestFileName();
  463. CreateTestFile;
  464. with TestDataset do begin
  465. TrimSpace := False;
  466. Open;
  467. AssertEquals('1', Fields[0].AsString);
  468. AssertEquals('John ', Fields[1].AsString);
  469. Next;
  470. AssertEquals('2', Fields[0].AsString);
  471. AssertEquals('Christiana', Fields[1].AsString);
  472. Edit;
  473. Fields[1].AsString := 'Chris';
  474. Post;
  475. AssertEquals('Chris ', Fields[1].AsString);
  476. Close; // save changes
  477. Open;
  478. Next;
  479. AssertEquals('Chris ', Fields[1].AsString);
  480. end;
  481. end;
  482. initialization
  483. // Only run these tests if we are running
  484. // sdf tests. After all, running these when testing
  485. // e.g. SQL RDBMS doesn't make sense.
  486. if uppercase(dbconnectorname)='SDFDS' then
  487. begin
  488. RegisterTest(TTestSdfSpecific);
  489. RegisterTest(TTestFixedFormatSpecific);
  490. end;
  491. end.