utcbufferedfilestream.pp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. unit utcBufferedFileStream;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, punit, bufstream;
  6. procedure RegisterTests;
  7. implementation
  8. const
  9. TEST_RANDOM_READS=10000;
  10. TEST_SEQUENTIAL_READS=1000000;
  11. TEST_FILENAME='testfile.bin';
  12. TEST_WRITEC_FILE='testwritecache.bin';
  13. TEST_WRITEF_FILE='testwritedirec.bin';
  14. function CompareStreams(const aStream1: TStream; const aStream2: TStream): Boolean;
  15. const
  16. BUFFER_SIZE=5213; // Odd number
  17. var
  18. b1: array [0..BUFFER_SIZE-1] of BYTE;
  19. b2: array [0..BUFFER_SIZE-1] of BYTE;
  20. lReadBytes: integer;
  21. lAvailable: integer;
  22. lEffectiveRead1: integer;
  23. lEffectiveRead2: integer;
  24. begin
  25. b1[0]:=0; // Avoid initalization hint
  26. b2[0]:=0; // Avoid initalization hint
  27. Result:=false;
  28. if aStream1.Size<>aStream2.Size then exit;
  29. aStream1.Position:=0;
  30. aStream2.Position:=0;
  31. while aStream1.Position<aStream1.Size do begin
  32. lAvailable:=aStream1.Size-aStream1.Position;
  33. if lAvailable>=BUFFER_SIZE then begin
  34. lReadBytes:=BUFFER_SIZE;
  35. end else begin
  36. lReadBytes:=aStream1.Size-aStream1.Position;
  37. end;
  38. lEffectiveRead1:=aStream1.Read(b1[0],lReadBytes);
  39. lEffectiveRead2:=aStream2.Read(b2[0],lReadBytes);
  40. if lEffectiveRead1<>lEffectiveRead2 then exit;
  41. if not CompareMem(@b1[0],@b2[0],lEffectiveRead1) then exit;
  42. end;
  43. Result:=true;
  44. end;
  45. function Setup: TTestString;
  46. var
  47. F: TFileStream;
  48. b: array [0..10000-1] of AnsiChar;
  49. j: integer;
  50. begin
  51. Result := '';
  52. for j := 0 to Pred(10000) do begin
  53. b[j]:=AnsiChar(ord('0')+j mod 10);
  54. end;
  55. try
  56. F:=TFileStream.Create(TEST_FILENAME,fmCreate);
  57. try
  58. for j := 0 to Pred(1000) do begin
  59. F.Write(b,sizeof(b));
  60. end;
  61. finally
  62. F.Free;
  63. end;
  64. except
  65. On E: Exception do
  66. Result := 'Setup failed: ' + E.Message;
  67. end;
  68. end;
  69. function TearDown: TTestString;
  70. begin
  71. Result := '';
  72. try
  73. DeleteFile(TEST_FILENAME);
  74. DeleteFile(TEST_WRITEC_FILE);
  75. DeleteFile(TEST_WRITEF_FILE);
  76. except
  77. On E: Exception do
  78. Result := 'TearDown failed: ' + E.Message;
  79. end;
  80. end;
  81. function TBufferedFileStream_TestCacheRead : TTestString;
  82. var
  83. lBufferedStream: TBufferedFileStream;
  84. lStream: TFileStream;
  85. b: array [0..10000-1] of AnsiChar;
  86. j,k: integer;
  87. lBytesToRead: integer;
  88. lEffectiveRead: integer;
  89. lReadPosition: int64;
  90. lCheckInitV: integer;
  91. begin
  92. Result := '';
  93. b[0]:=#0; // Avoid initalization hint
  94. lBufferedStream:=TBufferedFileStream.Create(TEST_FILENAME,fmOpenRead or fmShareDenyWrite);
  95. lStream:=TFileStream.Create(TEST_FILENAME,fmOpenRead or fmShareDenyWrite);
  96. try
  97. RandSeed:=1;
  98. Randomize;
  99. for j := 0 to Pred(TEST_RANDOM_READS) do begin
  100. lBytesToRead:=Random(10000);
  101. lReadPosition:=Random(lBufferedStream.Size);
  102. lBufferedStream.Position:=lReadPosition;
  103. lEffectiveRead:=lBufferedStream.Read(b,lBytesToRead);
  104. lCheckInitV:=lReadPosition mod 10;
  105. for k := 0 to Pred(lEffectiveRead) do begin
  106. if b[k]<>AnsiChar(ord('0')+lCheckInitV mod 10) then
  107. begin
  108. Result := 'Expected data error in random read test';
  109. Exit;
  110. end;
  111. inc(lCheckInitV);
  112. end;
  113. end;
  114. lBytesToRead:=1;
  115. lReadPosition:=0;
  116. lBufferedStream.Position:=lReadPosition;
  117. for j := 0 to Pred(TEST_SEQUENTIAL_READS) do begin
  118. lEffectiveRead:=lBufferedStream.Read(b,lBytesToRead);
  119. lCheckInitV:=lReadPosition mod 10;
  120. for k := 0 to Pred(lEffectiveRead) do begin
  121. if b[k]<>AnsiChar(ord('0')+lCheckInitV mod 10) then
  122. begin
  123. Result := 'Expected data error in sequential read test';
  124. Exit;
  125. end;
  126. inc(lCheckInitV);
  127. end;
  128. inc(lReadPosition,lBytesToRead);
  129. end;
  130. lBufferedStream.Position:=lBufferedStream.Size-1;
  131. lEffectiveRead:=lBufferedStream.Read(b,2);
  132. if lEffectiveRead<>1 then
  133. begin
  134. Result := 'Read beyond limits, returned bytes: '+inttostr(lEffectiveRead);
  135. Exit;
  136. end;
  137. finally
  138. lBufferedStream.Free;
  139. lStream.Free;
  140. end;
  141. end;
  142. function TBufferedFileStream_TestCacheWrite : TTestString;
  143. const
  144. EXPECTED_SIZE=10000000;
  145. TEST_ROUNDS=100000;
  146. var
  147. lBufferedStream: TBufferedFileStream;
  148. lStream: TFileStream;
  149. lVerifyStream1,lVerifyStream2: TFileStream;
  150. b: array [0..10000-1] of AnsiChar;
  151. j: integer;
  152. lBytesToWrite: integer;
  153. lWritePosition: int64;
  154. begin
  155. Result := '';
  156. RandSeed:=1;
  157. Randomize;
  158. for j := 0 to Pred(10000) do
  159. b[j]:='0';
  160. lBufferedStream:=TBufferedFileStream.Create(TEST_WRITEC_FILE,fmCreate);
  161. lStream:=TFileStream.Create(TEST_WRITEF_FILE,fmCreate);
  162. try
  163. for j := 0 to Pred(EXPECTED_SIZE div Sizeof(b)) do
  164. begin
  165. lBufferedStream.Write(b,sizeof(b));
  166. lStream.Write(b,sizeof(b));
  167. end;
  168. for j := 0 to Pred(Sizeof(b)) do
  169. b[j]:=AnsiChar(ord('0')+j mod 10);
  170. finally
  171. lBufferedStream.Free;
  172. lStream.Free;
  173. end;
  174. lBufferedStream:=TBufferedFileStream.Create(TEST_WRITEC_FILE,fmOpenReadWrite);
  175. lStream:=TFileStream.Create(TEST_WRITEF_FILE,fmOpenWrite);
  176. try
  177. for j := 0 to Pred(TEST_ROUNDS) do
  178. begin
  179. if lStream.Size<>lBufferedStream.Size then
  180. begin
  181. Result := 'Mismatched lengths during write';
  182. Exit;
  183. end;
  184. lWritePosition:=Random(EXPECTED_SIZE);
  185. lBytesToWrite:=Random(sizeof(b));
  186. lBufferedStream.Position:=lWritePosition;
  187. lStream.Position:=lWritePosition;
  188. lBufferedStream.Write(b,lBytesToWrite);
  189. lStream.Write(b,lBytesToWrite);
  190. end;
  191. if lStream.Size<>lBufferedStream.Size then
  192. begin
  193. Result := 'Mismatched lengths after write';
  194. Exit;
  195. end;
  196. finally
  197. lBufferedStream.Free;
  198. lStream.Free;
  199. end;
  200. lVerifyStream1:=TFileStream.Create(TEST_WRITEC_FILE,fmOpenRead or fmShareDenyWrite);
  201. lVerifyStream2:=TFileStream.Create(TEST_WRITEF_FILE,fmOpenRead or fmShareDenyWrite);
  202. try
  203. if not CompareStreams(lVerifyStream1,lVerifyStream2) then
  204. begin
  205. Result := 'Streams are different after write test!';
  206. Exit;
  207. end;
  208. finally
  209. lVerifyStream1.Free;
  210. lVerifyStream2.Free;
  211. end;
  212. end;
  213. function TBufferedFileStream_TestCacheSeek : TTestString;
  214. var
  215. lBufferedStream: TBufferedFileStream;
  216. lStream: TFileStream;
  217. bBuffered: array [0..10000] of BYTE;
  218. bStream: array [0..10000] of BYTE;
  219. bread : Integer;
  220. begin
  221. Result := '';
  222. bBuffered[0]:=0;
  223. bStream[0]:=0;
  224. lBufferedStream:=TBufferedFileStream.Create(TEST_FILENAME,fmOpenRead or fmShareDenyWrite);
  225. lStream:=TFileStream.Create(TEST_FILENAME,fmOpenRead or fmShareDenyWrite);
  226. try
  227. lStream.Position:=-1;
  228. lBufferedStream.Position:=-1;
  229. if lStream.Position<>lBufferedStream.Position then
  230. begin
  231. Result := 'Positions are not the same after setting to -1.';
  232. Exit;
  233. end;
  234. lStream.Read(bBuffered[0],10);
  235. lBufferedStream.Read(bStream[0],10);
  236. if (not CompareMem(@bBuffered[0],@bStream[0],10)) or (lStream.Position<>lBufferedStream.Position) then
  237. begin
  238. Result := 'Read data or positions are not the same after reading at -1.';
  239. Exit;
  240. end;
  241. lStream.Seek(-1,soBeginning);
  242. lBufferedStream.Seek(-1,soBeginning);
  243. lStream.Read(bBuffered[0],10);
  244. lBufferedStream.Read(bStream[0],10);
  245. if (not CompareMem(@bBuffered[0],@bStream[0],10)) or (lStream.Position<>lBufferedStream.Position) then
  246. begin
  247. Result := 'Read data or positions are not the same after seeking to -1.';
  248. Exit;
  249. end;
  250. lStream.Seek(lStream.Position*-2,soCurrent);
  251. lBufferedStream.Seek(lBufferedStream.Position*-2,soCurrent);
  252. lStream.Read(bBuffered[0],10);
  253. lBufferedStream.Read(bStream[0],10);
  254. if (not CompareMem(@bBuffered[0],@bStream[0],10)) or (lStream.Position<>lBufferedStream.Position) then
  255. begin
  256. Result := 'Read data or positions are not the same after seeking from current.';
  257. Exit;
  258. end;
  259. finally
  260. lBufferedStream.Free;
  261. lStream.Free;
  262. end;
  263. end;
  264. procedure RegisterTests;
  265. begin
  266. AddSuite('TBufferedFileStreamTests', @Setup, @TearDown);
  267. AddTest('TestCacheRead', @TBufferedFileStream_TestCacheRead, 'TBufferedFileStreamTests');
  268. AddTest('TestCacheWrite', @TBufferedFileStream_TestCacheWrite, 'TBufferedFileStreamTests');
  269. AddTest('TestCacheSeek', @TBufferedFileStream_TestCacheSeek, 'TBufferedFileStreamTests');
  270. end;
  271. end.