2
0

tcsdfdata.pp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  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 embedded quotes and CRLF works.
  200. const
  201. Value1='Delimiter,"and";quote';
  202. Value2='J"T"';
  203. Value3='Just a long line';
  204. Value4='Just a quoted long line';
  205. Value5='multi'+#13+#10+'line';
  206. Value6='Delimiter,and;done';
  207. Value7='Some "random" quotes';
  208. Var
  209. F : Text;
  210. i : integer;
  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. for i:=1 to 3 do
  221. begin
  222. Writeln(F,'"Delimiter,""and"";quote","J""T""",Just a long line,"Just a quoted long line","multi');
  223. Writeln(F,'line","Delimiter,and;done","Some ""random"" quotes"');
  224. end;
  225. Close(F);
  226. // Load our dataset
  227. TestDataset.Open;
  228. AssertEquals('FieldDefs.Count', 7, TestDataset.FieldDefs.Count);
  229. AssertEquals('RecordCount', 3, TestDataset.RecordCount);
  230. TestDataset.First;
  231. for i:=1 to 3 do
  232. begin
  233. AssertEquals('Field1', Value1, TestDataSet.Fields[0].AsString);
  234. AssertEquals('Field2', Value2, TestDataSet.Fields[1].AsString);
  235. AssertEquals('Field3', Value3, TestDataSet.Fields[2].AsString);
  236. AssertEquals('Field4', Value4, TestDataSet.Fields[3].AsString);
  237. AssertEquals('Field5', Value5, TestDataSet.Fields[4].AsString);
  238. AssertEquals('Field6', Value6, TestDataSet.Fields[5].AsString);
  239. AssertEquals('Field7' ,Value7, TestDataSet.Fields[6].AsString);
  240. TestDataSet.Next;
  241. end;
  242. end;
  243. procedure Ttestsdfspecific.TestEmptyFieldContents;
  244. Var
  245. F : Text;
  246. begin
  247. // with empty Field name in Header line
  248. TestDataset.FirstLineAsSchema := True;
  249. TestDataset.Delimiter := ';';
  250. TestDataset.FileName := TestFileName();
  251. Assign(F, TestDataset.FileName);
  252. Rewrite(F);
  253. Writeln(F,'1;2;3;;5');
  254. Writeln(F,'11;12;13;;15');
  255. Close(F);
  256. TestDataset.Open;
  257. AssertEquals('FieldDefs.Count',5,TestDataset.FieldDefs.Count);
  258. AssertEquals('RecordCount',1,TestDataset.RecordCount);
  259. end;
  260. procedure Ttestsdfspecific.TestEmptyFieldHeader;
  261. Var
  262. F : Text;
  263. begin
  264. // with empty Field name in Header line
  265. TestDataset.Delimiter := ';';
  266. TestDataset.FirstLineAsSchema := True;
  267. TestDataset.FileName := TestFileName();
  268. Assign(F, TestDataset.FileName);
  269. Rewrite(F);
  270. Writeln(F,'1;2;3;;5');
  271. Close(F);
  272. TestDataset.Open;
  273. AssertEquals('FieldDefs.Count',5,TestDataset.FieldDefs.Count);
  274. AssertEquals('RecordCount', 0, TestDataset.RecordCount);
  275. end;
  276. procedure Ttestsdfspecific.TestEmptyFieldNoHeader;
  277. Var
  278. F : Text;
  279. S1,S2 : String;
  280. begin
  281. // without Schema, without Header line
  282. TestDataset.Schema.Clear;
  283. TestDataset.FirstLineAsSchema := False;
  284. TestDataset.Delimiter := ';';
  285. TestDataset.FileName := TestFileName();
  286. Assign(F, TestDataset.FileName);
  287. Rewrite(F);
  288. Writeln(F,'value1;value2;;;');
  289. Close(F);
  290. with TestDataset do begin
  291. Open;
  292. AssertEquals('FieldDefs.Count', 5, FieldDefs.Count);
  293. AssertEquals('RecordCount', 1, RecordCount);
  294. // #1 record
  295. Edit;
  296. Fields[0].AsString := 'Value1';
  297. Post;
  298. AssertEquals('Fields[4]', '', Fields[4].AsString);
  299. // #2 record
  300. Append;
  301. Fields[1].AsString := 'Value2';
  302. Fields[2].AsString := 'Value"'; // embedded double quote
  303. Post;
  304. Close;
  305. end;
  306. Assign(F, TestDataset.FileName);
  307. Reset(F);
  308. ReadLn(F,S1);
  309. ReadLn(F,S2);
  310. Close(F);
  311. AssertEquals('Value1;value2;;;',S1);
  312. AssertEquals(';Value2;"Value""";;',S2);
  313. end;
  314. procedure Ttestsdfspecific.TestEmptyFieldHeaderStripTrailingDelimiters;
  315. Var
  316. F : Text;
  317. S : String;
  318. begin
  319. // without Schema, without Header line
  320. TestDataset.Schema.Clear;
  321. TestDataset.FirstLineAsSchema := False;
  322. TestDataset.Delimiter := ';';
  323. TestDataset.StripTrailingDelimiters := True;
  324. TestDataset.FileName := TestFileName();
  325. Assign(F, TestDataset.FileName);
  326. Rewrite(F);
  327. Writeln(F,'value1;value2;;;');
  328. Close(F);
  329. TestDataset.Open;
  330. AssertEquals('FieldDefs.Count',2,TestDataset.FieldDefs.Count);
  331. TestDataset.Edit;
  332. TestDataset.Fields[0].AsString:='Value1';
  333. TestDataset.Post;
  334. TestDataset.Close;
  335. Assign(F, TestDataset.FileName);
  336. Reset(F);
  337. ReadLn(F,S);
  338. Close(F);
  339. AssertEquals('No data lost','Value1;value2',S);
  340. end;
  341. procedure Ttestsdfspecific.TestStripTrailingDelimiters;
  342. Var
  343. F : Text;
  344. S1,S2 : String;
  345. begin
  346. // without Schema, with Header line
  347. TestDataset.Schema.Clear;
  348. TestDataset.FirstLineAsSchema := True;
  349. TestDataset.Delimiter := ';';
  350. TestDataset.StripTrailingDelimiters := True;
  351. TestDataset.FileName := TestFileName();;
  352. Assign(F, TestDataset.FileName);
  353. Rewrite(F);
  354. Writeln(F,'value1;value2;;;');
  355. Writeln(F,'value1;value2;;;');
  356. Close(F);
  357. TestDataset.Open;
  358. AssertEquals('FieldDefs.Count',2,TestDataset.FieldDefs.Count);
  359. TestDataset.Edit;
  360. TestDataset.Fields[0].AsString:='Value1';
  361. TestDataset.Post;
  362. TestDataset.Close;
  363. Assign(F, TestDataset.FileName);
  364. Reset(F);
  365. ReadLn(F,S1);
  366. ReadLn(F,S2);
  367. Close(F);
  368. AssertEquals('Headers lost','value1;value2;;;',S1); // should striping affect also header line ?
  369. AssertEquals('Data lost','Value1;value2',S2);
  370. end;
  371. procedure Ttestsdfspecific.Setup;
  372. begin
  373. TestDataset := TSDFDataset.Create(nil);
  374. TestDataset.Delimiter := ',';
  375. TestDataset.FileMustExist := False;
  376. TestDataset.FirstLineAsSchema := True;
  377. TestDataset.TrimSpace := False;
  378. TestDataset.AllowMultiLine := False;
  379. TestDataset.Schema.Add('ID');
  380. TestDataset.Schema.Add('NAME');
  381. TestDataset.Schema.Add('BIRTHDAY');
  382. end;
  383. procedure Ttestsdfspecific.Teardown;
  384. begin
  385. try
  386. TestDataset.Close;
  387. except
  388. //swallow
  389. end;
  390. TestDataset.Free;
  391. try
  392. //DeleteFile(FCSVFileName);
  393. except
  394. //swallow
  395. end;
  396. end;
  397. { TTestFixedFormatSpecific }
  398. procedure TTestFixedFormatSpecific.Setup;
  399. begin
  400. TestDataset := TFixedFormatDataset.Create(nil);
  401. TestDataset.FileMustExist := False;
  402. TestDataset.Schema.Add('ID=1');
  403. TestDataset.Schema.Add('NAME=10');
  404. TestDataset.Schema.Add('BIRTHDAY=10');
  405. end;
  406. procedure TTestFixedFormatSpecific.Teardown;
  407. begin
  408. TestDataSet.Close;
  409. TestDataSet.Free;
  410. end;
  411. function TTestFixedFormatSpecific.TestFileName(const FileName: string): string;
  412. const
  413. DefaultTestFileName = 'test.sdf';
  414. begin
  415. if FileName = '' then
  416. Result := DefaultTestFileName
  417. else
  418. Result := FileName;
  419. if dbname <> '' then
  420. begin
  421. ForceDirectories(dbname);
  422. Result := IncludeTrailingPathDelimiter(dbname) + Result;
  423. end;
  424. if FileExists(Result) then DeleteFile(Result);
  425. end;
  426. procedure TTestFixedFormatSpecific.CreateTestFile;
  427. var
  428. FileStrings: TStringList;
  429. begin
  430. FileStrings:=TStringList.Create;
  431. try
  432. FileStrings.Add('1John 2000-01-01');
  433. FileStrings.Add('2Christiana2001-02-02');
  434. FileStrings.SaveToFile(TestDataset.FileName);
  435. finally
  436. FileStrings.Free;
  437. end;
  438. end;
  439. procedure TTestFixedFormatSpecific.TestTrimSpace;
  440. begin
  441. TestDataset.FileName := TestFileName();
  442. CreateTestFile;
  443. with TestDataset do begin
  444. Open;
  445. AssertEquals('FieldDefs.Count', 3, FieldDefs.Count);
  446. AssertEquals('1', Fields[0].AsString); // just after Open
  447. Last;
  448. First;
  449. AssertEquals('RecNo', 1, RecNo);
  450. AssertEquals('RecordCount', 2, RecordCount);
  451. AssertEquals('1', Fields[0].AsString);
  452. AssertEquals('John', Fields[1].AsString);
  453. Next;
  454. AssertEquals('2', Fields[0].AsString);
  455. AssertEquals('Christiana', Fields[1].AsString);
  456. Edit;
  457. Fields[1].AsString := 'Chris';
  458. Post;
  459. AssertEquals('Chris', Fields[1].AsString);
  460. Close; // save changes
  461. AssertEquals('RecordCount after Close', 0, RecordCount);
  462. Open;
  463. Next;
  464. AssertEquals('Chris', Fields[1].AsString);
  465. end;
  466. end;
  467. procedure TTestFixedFormatSpecific.TestNoTrimSpace;
  468. begin
  469. TestDataset.FileName := TestFileName();
  470. CreateTestFile;
  471. with TestDataset do begin
  472. TrimSpace := False;
  473. Open;
  474. AssertEquals('1', Fields[0].AsString);
  475. AssertEquals('John ', Fields[1].AsString);
  476. Next;
  477. AssertEquals('2', Fields[0].AsString);
  478. AssertEquals('Christiana', Fields[1].AsString);
  479. Edit;
  480. Fields[1].AsString := 'Chris';
  481. Post;
  482. AssertEquals('Chris ', Fields[1].AsString);
  483. Close; // save changes
  484. Open;
  485. Next;
  486. AssertEquals('Chris ', Fields[1].AsString);
  487. end;
  488. end;
  489. initialization
  490. // Only run these tests if we are running
  491. // sdf tests. After all, running these when testing
  492. // e.g. SQL RDBMS doesn't make sense.
  493. if uppercase(dbconnectorname)='SDFDS' then
  494. begin
  495. RegisterTest(TTestSdfSpecific);
  496. RegisterTest(TTestFixedFormatSpecific);
  497. end;
  498. end.