domunit.pp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. {**********************************************************************
  2. This file is part of the Free Component Library (FCL)
  3. fpcunit extensions required to run w3.org DOM test suites
  4. Copyright (c) 2008 by Sergei Gorelkin, [email protected]
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit domunit;
  12. {$mode objfpc}{$H+}
  13. interface
  14. uses
  15. Classes, SysUtils, DOM, XMLRead, contnrs, fpcunit;
  16. type
  17. { these two types are separated for the purpose of readability }
  18. _collection = array of DOMString; // unordered
  19. _list = _collection; // ordered
  20. TDOMTestBase = class(TTestCase)
  21. private
  22. procedure setImplAttr(const name: string; value: Boolean);
  23. function getImplAttr(const name: string): Boolean;
  24. protected
  25. // override for this one is generated by testgen for each descendant
  26. function GetTestFilesURI: string; virtual;
  27. protected
  28. FParser: TDOMParser;
  29. FAutoFree: TObjectList;
  30. procedure SetUp; override;
  31. procedure TearDown; override;
  32. procedure GC(obj: TObject);
  33. procedure Load(out doc; const uri: string);
  34. procedure LoadStringData(out Doc; const data: string);
  35. function getResourceURI(const res: WideString): WideString;
  36. function ContentTypeIs(const t: string): Boolean;
  37. function GetImplementation: TDOMImplementation;
  38. procedure CheckFeature(const name: string);
  39. procedure assertNull(const id: string; const ws: DOMString); overload;
  40. procedure assertEquals(const id: string; exp, act: TObject); overload;
  41. procedure assertEqualsList(const id: string; const exp: array of DOMString; const act: _list);
  42. procedure assertEqualsCollection(const id: string; const exp: array of DOMString; const act: _collection);
  43. procedure assertEqualsNoCase(const id: string; const exp, act: DOMString);
  44. procedure assertSame(const id: string; exp, act: TDOMNode);
  45. procedure assertSize(const id: string; size: Integer; obj: TDOMNodeList);
  46. procedure assertSize(const id: string; size: Integer; obj: TDOMNamedNodeMap);
  47. procedure assertInstanceOf(const id: string; obj: TObject; const typename: string);
  48. procedure assertURIEquals(const id: string;
  49. scheme, path, host, file_, name, query, fragment: PChar;
  50. IsAbsolute: Boolean; const Actual: DOMString);
  51. function bad_condition(const TagName: WideString): Boolean;
  52. property implementationAttribute[const name: string]: Boolean read getImplAttr write setImplAttr;
  53. end;
  54. procedure _append(var coll: _collection; const Value: DOMString);
  55. procedure _assign(out rslt: _collection; const value: array of DOMString);
  56. function IsSame(exp, act: TDOMNode): Boolean;
  57. implementation
  58. uses
  59. URIParser;
  60. procedure _append(var coll: _collection; const Value: DOMString);
  61. var
  62. L: Integer;
  63. begin
  64. L := Length(coll);
  65. SetLength(coll, L+1);
  66. coll[L] := Value;
  67. end;
  68. procedure _assign(out rslt: _collection; const value: array of DOMString);
  69. var
  70. I: Integer;
  71. begin
  72. SetLength(rslt, Length(value));
  73. for I := 0 to High(value) do
  74. rslt[I] := value[I];
  75. end;
  76. function IsSame(exp, act: TDOMNode): Boolean;
  77. begin
  78. Result := exp = act;
  79. end;
  80. procedure TDOMTestBase.SetUp;
  81. begin
  82. FParser := TDOMParser.Create;
  83. FParser.Options.PreserveWhitespace := True;
  84. //FParser.Options.ExpandEntities := True;
  85. FAutoFree := TObjectList.Create(True);
  86. end;
  87. procedure TDOMTestBase.TearDown;
  88. begin
  89. FreeAndNil(FAutoFree);
  90. FreeAndNil(FParser);
  91. end;
  92. procedure TDOMTestBase.GC(obj: TObject);
  93. begin
  94. FAutoFree.Add(obj);
  95. end;
  96. procedure TDOMTestBase.assertSame(const id: string; exp, act: TDOMNode);
  97. begin
  98. if exp <> act then
  99. begin
  100. assertNotNull(id, exp);
  101. assertNotNull(id, act);
  102. assertEquals(id, exp.nodeType, act.nodeType);
  103. assertEquals(id, exp.nodeValue, act.nodeValue);
  104. end;
  105. end;
  106. procedure TDOMTestBase.assertNull(const id: string; const ws: DOMString);
  107. begin
  108. if ws <> '' then
  109. Fail(id);
  110. end;
  111. procedure TDOMTestBase.assertEquals(const id: string; exp, act: TObject);
  112. begin
  113. inherited assertSame(id, exp, act);
  114. end;
  115. procedure TDOMTestBase.assertEqualsList(const id: string;
  116. const exp: array of DOMString; const act: _list);
  117. var
  118. I: Integer;
  119. begin
  120. AssertEquals(id, Length(exp), Length(act));
  121. // compare ordered
  122. for I := 0 to High(exp) do
  123. AssertEquals(id, exp[I], act[I]);
  124. end;
  125. procedure TDOMTestBase.assertEqualsCollection(const id: string; const exp: array of DOMString; const act: _collection);
  126. var
  127. I, J, matches: Integer;
  128. begin
  129. AssertEquals(id, Length(exp), Length(act));
  130. // compare unordered
  131. for I := 0 to High(exp) do
  132. begin
  133. matches := 0;
  134. for J := 0 to High(act) do
  135. if act[J] = exp[I] then
  136. Inc(matches);
  137. AssertTrue(id+': no match found for <'+exp[I]+'>', matches <> 0);
  138. AssertTrue(id+': multiple matches for <'+exp[I]+'>', matches = 1);
  139. end;
  140. end;
  141. procedure TDOMTestBase.assertEqualsNoCase(const id: string; const exp, act: DOMString);
  142. begin
  143. // TODO: could write custom comparison because range is limited to ASCII
  144. AssertTrue(id + ComparisonMsg(exp, act), WideSameText(exp, act));
  145. end;
  146. procedure TDOMTestBase.assertSize(const id: string; size: Integer; obj: TDOMNodeList);
  147. begin
  148. AssertNotNull(id, obj);
  149. AssertEquals(id, size, obj.Length);
  150. end;
  151. procedure TDOMTestBase.assertSize(const id: string; size: Integer; obj: TDOMNamedNodeMap);
  152. begin
  153. AssertNotNull(id, obj);
  154. AssertEquals(id, size, obj.Length);
  155. end;
  156. function TDOMTestBase.getResourceURI(const res: WideString): WideString;
  157. var
  158. Base, Base2: WideString;
  159. function CheckFile(const uri: WideString; out name: WideString): Boolean;
  160. var
  161. filename: string;
  162. begin
  163. Result := ResolveRelativeURI(uri + 'files/', res + '.xml', name) and
  164. URIToFilename(name, filename) and
  165. FileExists(filename);
  166. end;
  167. begin
  168. Base := GetTestFilesURI;
  169. if Pos(WideString('level2/html'), Base) <> 0 then
  170. begin
  171. // This is needed to run HTML testsuite off the CVS snapshot.
  172. // Web version simply uses all level1 files copied to level2.
  173. if ResolveRelativeURI(Base, '../../level1/html/', Base2) and
  174. CheckFile(Base2, Result) then
  175. Exit;
  176. end;
  177. CheckFile(Base, Result);
  178. end;
  179. function TDOMTestBase.getImplAttr(const name: string): Boolean;
  180. begin
  181. if name = 'expandEntityReferences' then
  182. result := FParser.Options.ExpandEntities
  183. else if name = 'validating' then
  184. result := FParser.Options.Validate
  185. else if name = 'namespaceAware' then
  186. result := FParser.Options.Namespaces
  187. else if name = 'ignoringElementContentWhitespace' then
  188. result := not FParser.Options.PreserveWhitespace
  189. else
  190. begin
  191. Fail('Unknown implementation attribute: ''' + name + '''');
  192. result := False;
  193. end;
  194. end;
  195. procedure TDOMTestBase.setImplAttr(const name: string; value: Boolean);
  196. begin
  197. if name = 'validating' then
  198. FParser.Options.Validate := value
  199. else if name = 'expandEntityReferences' then
  200. FParser.Options.ExpandEntities := value
  201. else if name = 'coalescing' then
  202. // TODO: action unknown yet
  203. else if (name = 'signed') and value then
  204. Ignore('Setting implementation attribute ''signed'' to ''true'' is not supported')
  205. else if name = 'hasNullString' then
  206. // TODO: probably we cannot support this
  207. else if name = 'namespaceAware' then
  208. FParser.Options.Namespaces := value
  209. else if name = 'ignoringElementContentWhitespace' then
  210. FParser.Options.PreserveWhitespace := not value
  211. else
  212. Fail('Unknown implementation attribute: ''' + name + '''');
  213. end;
  214. procedure TDOMTestBase.Load(out doc; const uri: string);
  215. var
  216. t: TXMLDocument;
  217. begin
  218. TObject(doc) := nil;
  219. FParser.ParseURI(getResourceURI(uri), t);
  220. TObject(doc) := t;
  221. GC(t);
  222. end;
  223. procedure TDOMTestBase.assertInstanceOf(const id: string; obj: TObject; const typename: string);
  224. begin
  225. AssertTrue(id, obj.ClassNameIs(typename));
  226. end;
  227. { expected args already UTF-8 encoded }
  228. procedure TDOMTestBase.assertURIEquals(const id: string; scheme, path,
  229. host, file_, name, query, fragment: PChar; IsAbsolute: Boolean;
  230. const Actual: DOMString);
  231. var
  232. URI: TURI;
  233. begin
  234. AssertTrue(id, Actual <> '');
  235. URI := ParseURI(utf8Encode(Actual));
  236. if fragment <> nil then
  237. AssertEquals(id, string(fragment), URI.Bookmark);
  238. if query <> nil then
  239. AssertEquals(id, string(query), URI.Params);
  240. if scheme <> nil then
  241. AssertEquals(id, string(scheme), URI.Protocol);
  242. if host <> nil then
  243. begin
  244. AssertTrue(id, URI.HasAuthority);
  245. AssertEquals(id, string(host), URI.Host);
  246. end;
  247. if path <> nil then
  248. AssertEquals(id, string(path), '//' + Uri.Host + URI.Path + URI.Document);
  249. if file_ <> nil then
  250. AssertEquals(id, string(file_), URI.Document);
  251. if name <> nil then
  252. AssertEquals(id, string(name), ChangeFileExt(URI.Document, ''));
  253. end;
  254. function TDOMTestBase.bad_condition(const TagName: WideString): Boolean;
  255. begin
  256. Fail('Unsupported condition: '+ TagName);
  257. Result := False;
  258. end;
  259. function TDOMTestBase.ContentTypeIs(const t: string): Boolean;
  260. begin
  261. { For now, claim only xml as handled content.
  262. This may be extended with html and svg.
  263. }
  264. result := (t = 'text/xml');
  265. end;
  266. function TDOMTestBase.GetImplementation: TDOMImplementation;
  267. begin
  268. result := nil;
  269. end;
  270. procedure TDOMTestBase.CheckFeature(const name: string);
  271. begin
  272. // purpose/action is currently unknown
  273. end;
  274. function TDOMTestBase.GetTestFilesURI: string;
  275. begin
  276. result := '';
  277. end;
  278. procedure TDOMTestBase.LoadStringData(out Doc; const data: string);
  279. var
  280. src: TXMLInputSource;
  281. begin
  282. src := TXMLInputSource.Create(data);
  283. try
  284. FParser.Parse(src, TXMLDocument(Doc));
  285. GC(TObject(Doc));
  286. finally
  287. src.Free;
  288. end;
  289. end;
  290. end.