utdirwatch.pas 7.4 KB

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