utcdirwatch.pp 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. unit utcdirwatch;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, punit, testutils, testregistry, dirwatch;
  6. procedure RegisterTests;
  7. implementation
  8. uses typinfo, inifiles;
  9. type
  10. TChangedEntry = record
  11. Dir : TWatchDirectoryEntry;
  12. Events : TWatchFileEvents;
  13. FN : String;
  14. end;
  15. TChangedEntryArray = Array of TChangedEntry;
  16. { TEventObject }
  17. TEventObject = class
  18. procedure DoChange(Sender: TObject; const aEvent: TFileChangeEvent);
  19. private
  20. procedure DoCheck(sender: TObject; var aContinue: Boolean);
  21. procedure HandleCreateFile(Sender: TObject);
  22. end;
  23. var
  24. FDirWatch: TDirwatch;
  25. FTestDir: string;
  26. FChanged: TChangedEntryArray;
  27. FCheckCount : Integer;
  28. FMaxLoopCount : Integer;
  29. FDoCheckOne : TNotifyEvent;
  30. BaseDir : String;
  31. Events : TEventObject;
  32. // Helper functions from the original test case
  33. procedure CleanDirs(aDir: String);
  34. Var
  35. Info : TSearchRec;
  36. lDir,lFull : String;
  37. begin
  38. lDir:=IncludeTrailingPathDelimiter(aDir);
  39. If FindFirst(lDir+AllFilesMask,sysutils.faDirectory,Info)=0 then
  40. try
  41. Repeat
  42. lFull:=lDir+Info.Name;
  43. if (Info.Attr and faDirectory)<>0 then
  44. begin
  45. if not ((Info.Name='.') or (Info.Name='..')) then
  46. begin
  47. CleanDirs(lFull);
  48. if not RemoveDir(lFull) then
  49. Fail('Failed to remove directory '+lFull)
  50. end;
  51. end
  52. else if not DeleteFile(lFull) then
  53. Fail('Failed to remove file '+lFull)
  54. until FindNext(Info)<>0;
  55. finally
  56. FindClose(Info);
  57. end;
  58. end;
  59. procedure TEventObject.DoChange(Sender: TObject; const aEvent: TFileChangeEvent);
  60. var
  61. Len : Integer;
  62. begin
  63. len:=Length(FChanged);
  64. SetLength(FChanged,Len+1);
  65. FChanged[Len].Dir:=aEvent.Entry;
  66. FChanged[Len].Events:=aEvent.Events;
  67. FChanged[Len].FN:=aEvent.FileName;
  68. end;
  69. procedure TEventObject.DoCheck(sender: TObject; var aContinue: Boolean);
  70. begin
  71. aContinue:=FCheckCount<FMaxLoopCount;
  72. if (FCheckCount=0) then
  73. if Assigned(FDoCheckOne) then
  74. FDoCheckOne(nil);
  75. inc(FCheckCount);
  76. end;
  77. procedure DoAppendFile(const aName : string);
  78. var
  79. FD : THandle;
  80. begin
  81. FD:=FileOpen(FTestDir+aName,fmOpenWrite);
  82. try
  83. FileSeek(FD,0,fsFromEnd);
  84. if FileWrite(FD,aName[1],Length(aName))=-1 then
  85. Writeln(GetLastOSError);
  86. finally
  87. FileClose(FD);
  88. end;
  89. end;
  90. procedure DoCreateFile(const aName : string);
  91. var
  92. L: TStrings;
  93. begin
  94. L:=TStringList.Create;
  95. try
  96. L.Add(aName);
  97. L.SaveToFile(FTestDir+aName);
  98. finally
  99. L.Free;
  100. end;
  101. end;
  102. procedure DoDeleteFile(const aName: string);
  103. begin
  104. If not DeleteFile(FTestDir+aName) then
  105. Fail('Failed to delete file '+FTestDir+aName);
  106. end;
  107. procedure TEventObject.HandleCreateFile(Sender: TObject);
  108. begin
  109. DoCreateFile('name.txt');
  110. end;
  111. procedure AssertEventsEquals(const Msg: String; aExpected, aActual: TWatchFileEvents);
  112. begin
  113. AssertEquals(Msg,SetToString(PTypeInfo(TypeInfo(TWatchFileEvents)),Longint(aExpected),False),
  114. SetToString(PTypeInfo(TypeInfo(TWatchFileEvents)),Longint(aActual),False));
  115. end;
  116. procedure AssertChange(const Msg: String; aIndex: Integer; aEntry: TWatchDirectoryEntry; aEvents: TWatchFileEvents; const aFileName: string = '');
  117. var
  118. M : String;
  119. begin
  120. M:=Msg+Format(' [%d]: ',[aIndex]);
  121. AssertTrue(M+'correct index',aIndex<Length(FChanged));
  122. AssertSame(M+'correct dir entry',aEntry,FChanged[aIndex].Dir);
  123. AssertEventsEquals(M+'correct changes',aEvents,FChanged[aIndex].Events);
  124. if aFileName<>'' then
  125. AssertEquals(M+'correct fileName',aFileName,FChanged[aIndex].FN);
  126. end;
  127. // Per-test setup and teardown
  128. procedure TestSetup;
  129. begin
  130. FDirWatch:=TDirwatch.Create(Nil);
  131. FTestDir:=IncludeTrailingPathDelimiter(BaseDir);
  132. ForceDirectories(FTestDir);
  133. FDirWatch.OnChange:[email protected];
  134. FMaxLoopCount:=0;
  135. FCheckCount:=0;
  136. FDoCheckOne:=Nil;
  137. SetLength(FChanged, 0);
  138. end;
  139. procedure TestTearDown;
  140. begin
  141. FDirWatch.Free;
  142. CleanDirs(FTestDir);
  143. end;
  144. // Flattened Tests
  145. function TestDirWatch_TestHookUp: TTestString;
  146. begin
  147. Result := '';
  148. TestSetup;
  149. try
  150. AssertNotNull('Have watch',FDirWatch);
  151. AssertEquals('No watches',0,FDirWatch.Watches.Count);
  152. AssertTrue('Have test dir',FTestDir<>'');
  153. AssertTrue('test dir exists',DirectoryExists(FTestDir));
  154. AssertEquals('No max check count',0,FMaxLoopCount);
  155. AssertEquals('No check count',0,FCheckCount);
  156. AssertTrue('No docheckone',FDoCheckOne=nil);
  157. finally
  158. TestTearDown;
  159. end;
  160. end;
  161. function TestDirWatch_TestAddFile: TTestString;
  162. begin
  163. Result := '';
  164. TestSetup;
  165. try
  166. FDirwatch.AddWatch(FTestDir,[feCreate]);
  167. FDirWatch.InitWatch;
  168. DoCreateFile('name.txt');
  169. AssertEquals('Change detected', 1, FDirWatch.Check);
  170. AssertChange('Create',0,FDirWatch.Watches[0],[feCreate],'name.txt');
  171. finally
  172. TestTearDown;
  173. end;
  174. end;
  175. function TestDirWatch_TestAppendFile: TTestString;
  176. begin
  177. Result := '';
  178. TestSetup;
  179. try
  180. FDirwatch.AddWatch(FTestDir,[feModify]);
  181. DoCreateFile('name.txt');
  182. FDirWatch.InitWatch;
  183. DoAppendFile('name.txt');
  184. AssertEquals('Change detected',1,FDirWatch.Check);
  185. AssertChange('Change detected',0,FDirWatch.Watches[0],[feModify],'name.txt');
  186. finally
  187. TestTearDown;
  188. end;
  189. end;
  190. function TestDirWatch_TestDeleteFile: TTestString;
  191. begin
  192. Result := '';
  193. TestSetup;
  194. try
  195. FDirwatch.AddWatch(FTestDir,[feDelete]);
  196. DoCreateFile('name.txt');
  197. FDirWatch.InitWatch;
  198. DoDeleteFile('name.txt');
  199. AssertEquals('Change detected',1,FDirWatch.Check);
  200. AssertChange('Change detected',0,FDirWatch.Watches[0],[feDelete],'name.txt');
  201. finally
  202. TestTearDown;
  203. end;
  204. end;
  205. function TestDirWatch_TestLoopNoThread: TTestString;
  206. begin
  207. Result := '';
  208. TestSetup;
  209. try
  210. FDirwatch.AddWatch(FTestDir,[feCreate]);
  211. FDirwatch.OnCheck:[email protected];
  212. FDoCheckOne:[email protected];
  213. FMaxLoopCount:=2;
  214. FDirWatch.StartLoop;
  215. AssertChange('Change detected',0,FDirWatch.Watches[0],[feCreate],'name.txt');
  216. finally
  217. TestTearDown;
  218. end;
  219. end;
  220. function TestDirWatch_TestLoopThread: TTestString;
  221. var
  222. I : Integer;
  223. begin
  224. Result := '';
  225. TestSetup;
  226. try
  227. FDirwatch.AddWatch(FTestDir,[feCreate]);
  228. FDirwatch.Threaded:=True;
  229. FDirWatch.StartLoop;
  230. Sleep(50);
  231. DoCreateFile('name.txt');
  232. I:=0;
  233. Repeat
  234. Sleep(10);
  235. CheckSynchronize;
  236. inc(i);
  237. until (I>=50) or (length(FChanged)>0);
  238. AssertChange('Change detected',0,FDirWatch.Watches[0],[feCreate],'name.txt');
  239. finally
  240. TestTearDown;
  241. end;
  242. end;
  243. function TestDirWatch_TestAddFileBaseDir: TTestString;
  244. begin
  245. Result := '';
  246. TestSetup;
  247. try
  248. FDirwatch.BaseDir:=FTestDir;
  249. AssertTrue('Create Subdir ',ForceDirectories(FTestDir+'sub'));
  250. FDirwatch.AddWatch('',[feCreate]);
  251. FDirWatch.InitWatch;
  252. DoCreateFile('sub/name.txt');
  253. AssertEquals('Subdirs not watched',0,FDirWatch.Check);
  254. finally
  255. TestTearDown;
  256. end;
  257. end;
  258. // Suite setup and registration
  259. procedure GetBaseDir;
  260. var
  261. FN : string;
  262. begin
  263. BaseDir:=IncludeTrailingPathDelimiter(GetTempDir)+'Dirwatch'+PathDelim;
  264. FN:=ExtractFilePath(ParamStr(0))+'config.ini';
  265. If FileExists(FN) then
  266. With TMemIniFile.Create(FN) do
  267. try
  268. BaseDir:=ReadString('dirwatch','basedir',BaseDir);
  269. finally
  270. Free;
  271. end;
  272. end;
  273. function SuiteSetup: string;
  274. begin
  275. Result := '';
  276. GetBaseDir;
  277. end;
  278. procedure RegisterTests;
  279. var
  280. lSuite : PSuite;
  281. begin
  282. lSuite:=AddSuite('TDirWatchTests', @SuiteSetup, nil, nil, true);
  283. AddTest('TestHookUp', @TestDirWatch_TestHookUp, lSuite);
  284. AddTest('TestAddFile', @TestDirWatch_TestAddFile, lSuite);
  285. AddTest('TestAppendFile', @TestDirWatch_TestAppendFile, lSuite);
  286. AddTest('TestDeleteFile', @TestDirWatch_TestDeleteFile, lSuite);
  287. AddTest('TestLoopNoThread', @TestDirWatch_TestLoopNoThread, lSuite);
  288. AddTest('TestLoopThread', @TestDirWatch_TestLoopThread, lSuite);
  289. AddTest('TestAddFileBaseDir', @TestDirWatch_TestAddFileBaseDir, lSuite);
  290. end;
  291. end.