domunit.pp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339
  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, xmlutils, 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: XMLString): XMLString;
  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 assertEqualsW(const id: string; const exp, act: DOMString);
  44. procedure assertEqualsNoCase(const id: string; const exp, act: DOMString);
  45. procedure assertSame(const id: string; exp, act: TDOMNode);
  46. procedure assertSize(const id: string; size: Integer; obj: TDOMNodeList);
  47. procedure assertSize(const id: string; size: Integer; obj: TDOMNamedNodeMap);
  48. procedure assertInstanceOf(const id: string; obj: TObject; const typename: string);
  49. procedure assertURIEquals(const id: string;
  50. scheme, path, host, file_, name, query, fragment: PChar;
  51. IsAbsolute: Boolean; const Actual: DOMString);
  52. function bad_condition(const TagName: XMLString): Boolean;
  53. property implementationAttribute[const name: string]: Boolean read getImplAttr write setImplAttr;
  54. end;
  55. procedure _append(var coll: _collection; const Value: DOMString);
  56. procedure _assign(out rslt: _collection; const value: array of DOMString);
  57. function IsSame(exp, act: TDOMNode): Boolean;
  58. implementation
  59. uses
  60. URIParser;
  61. procedure _append(var coll: _collection; const Value: DOMString);
  62. var
  63. L: Integer;
  64. begin
  65. L := Length(coll);
  66. SetLength(coll, L+1);
  67. coll[L] := Value;
  68. end;
  69. procedure _assign(out rslt: _collection; const value: array of DOMString);
  70. var
  71. I: Integer;
  72. begin
  73. SetLength(rslt, Length(value));
  74. for I := 0 to High(value) do
  75. rslt[I] := value[I];
  76. end;
  77. function IsSame(exp, act: TDOMNode): Boolean;
  78. begin
  79. Result := exp = act;
  80. end;
  81. procedure TDOMTestBase.SetUp;
  82. begin
  83. FParser := TDOMParser.Create;
  84. FParser.Options.PreserveWhitespace := True;
  85. //FParser.Options.ExpandEntities := True;
  86. FAutoFree := TObjectList.Create(True);
  87. end;
  88. procedure TDOMTestBase.TearDown;
  89. begin
  90. FreeAndNil(FAutoFree);
  91. FreeAndNil(FParser);
  92. end;
  93. procedure TDOMTestBase.GC(obj: TObject);
  94. begin
  95. FAutoFree.Add(obj);
  96. end;
  97. procedure TDOMTestBase.assertSame(const id: string; exp, act: TDOMNode);
  98. begin
  99. if exp <> act then
  100. begin
  101. assertNotNull(id, exp);
  102. assertNotNull(id, act);
  103. assertEquals(id, exp.nodeType, act.nodeType);
  104. assertEqualsW(id, exp.nodeValue, act.nodeValue);
  105. end;
  106. end;
  107. procedure TDOMTestBase.assertNull(const id: string; const ws: DOMString);
  108. begin
  109. if ws <> '' then
  110. Fail(id);
  111. end;
  112. procedure TDOMTestBase.assertEquals(const id: string; exp, act: TObject);
  113. begin
  114. inherited assertSame(id, exp, act);
  115. end;
  116. procedure TDOMTestBase.assertEqualsList(const id: string;
  117. const exp: array of DOMString; const act: _list);
  118. var
  119. I: Integer;
  120. begin
  121. AssertEquals(id+'(length)', Length(exp), Length(act));
  122. // compare ordered
  123. for I := 0 to High(exp) do
  124. AssertEqualsW(id+'['+IntToStr(I)+']', exp[I], act[I]);
  125. end;
  126. procedure TDOMTestBase.assertEqualsCollection(const id: string; const exp: array of DOMString; const act: _collection);
  127. var
  128. I, J, matches: Integer;
  129. begin
  130. AssertEquals(id, Length(exp), Length(act));
  131. // compare unordered
  132. for I := 0 to High(exp) do
  133. begin
  134. matches := 0;
  135. for J := 0 to High(act) do
  136. if act[J] = exp[I] then
  137. Inc(matches);
  138. AssertTrue(id+': no match found for <'+exp[I]+'>', matches <> 0);
  139. AssertTrue(id+': multiple matches for <'+exp[I]+'>', matches = 1);
  140. end;
  141. end;
  142. procedure TDOMTestBase.assertEqualsW(const id: string; const exp, act: DOMString);
  143. begin
  144. AssertTrue(id + ComparisonMsg(exp, act), exp = act);
  145. end;
  146. procedure TDOMTestBase.assertEqualsNoCase(const id: string; const exp, act: DOMString);
  147. begin
  148. // TODO: could write custom comparison because range is limited to ASCII
  149. AssertTrue(id + ComparisonMsg(exp, act), WideSameText(exp, act));
  150. end;
  151. procedure TDOMTestBase.assertSize(const id: string; size: Integer; obj: TDOMNodeList);
  152. begin
  153. AssertNotNull(id, obj);
  154. AssertEquals(id, size, obj.Length);
  155. end;
  156. procedure TDOMTestBase.assertSize(const id: string; size: Integer; obj: TDOMNamedNodeMap);
  157. begin
  158. AssertNotNull(id, obj);
  159. AssertEquals(id, size, obj.Length);
  160. end;
  161. function TDOMTestBase.getResourceURI(const res: XMLString): XMLString;
  162. var
  163. Base, Base2: XMLString;
  164. function CheckFile(const uri: XMLString; out name: XMLString): Boolean;
  165. var
  166. filename: string;
  167. begin
  168. Result := ResolveRelativeURI(uri + 'files/', res + '.xml', name) and
  169. URIToFilename(name, filename) and
  170. FileExists(filename);
  171. end;
  172. begin
  173. Base := GetTestFilesURI;
  174. if Pos(XMLString('level2/html'), Base) <> 0 then
  175. begin
  176. // This is needed to run HTML testsuite off the CVS snapshot.
  177. // Web version simply uses all level1 files copied to level2.
  178. if ResolveRelativeURI(Base, '../../level1/html/', Base2) and
  179. CheckFile(Base2, Result) then
  180. Exit;
  181. end;
  182. CheckFile(Base, Result);
  183. end;
  184. function TDOMTestBase.getImplAttr(const name: string): Boolean;
  185. begin
  186. if name = 'expandEntityReferences' then
  187. result := FParser.Options.ExpandEntities
  188. else if name = 'validating' then
  189. result := FParser.Options.Validate
  190. else if name = 'namespaceAware' then
  191. result := FParser.Options.Namespaces
  192. else if name = 'ignoringElementContentWhitespace' then
  193. result := not FParser.Options.PreserveWhitespace
  194. else
  195. begin
  196. Fail('Unknown implementation attribute: ''' + name + '''');
  197. result := False;
  198. end;
  199. end;
  200. procedure TDOMTestBase.setImplAttr(const name: string; value: Boolean);
  201. begin
  202. if name = 'validating' then
  203. FParser.Options.Validate := value
  204. else if name = 'expandEntityReferences' then
  205. FParser.Options.ExpandEntities := value
  206. else if name = 'coalescing' then
  207. // TODO: action unknown yet
  208. else if (name = 'signed') and value then
  209. Ignore('Setting implementation attribute ''signed'' to ''true'' is not supported')
  210. else if name = 'hasNullString' then
  211. // TODO: probably we cannot support this
  212. else if name = 'namespaceAware' then
  213. FParser.Options.Namespaces := value
  214. else if name = 'ignoringElementContentWhitespace' then
  215. FParser.Options.PreserveWhitespace := not value
  216. else
  217. Fail('Unknown implementation attribute: ''' + name + '''');
  218. end;
  219. procedure TDOMTestBase.Load(out doc; const uri: string);
  220. var
  221. t: TXMLDocument;
  222. begin
  223. TObject(doc) := nil;
  224. FParser.ParseURI(getResourceURI(uri), t);
  225. TObject(doc) := t;
  226. GC(t);
  227. end;
  228. procedure TDOMTestBase.assertInstanceOf(const id: string; obj: TObject; const typename: string);
  229. begin
  230. AssertTrue(id, obj.ClassNameIs(typename));
  231. end;
  232. { expected args already UTF-8 encoded }
  233. procedure TDOMTestBase.assertURIEquals(const id: string; scheme, path,
  234. host, file_, name, query, fragment: PChar; IsAbsolute: Boolean;
  235. const Actual: DOMString);
  236. var
  237. URI: TURI;
  238. begin
  239. AssertTrue(id+'#0', Actual <> '');
  240. URI := ParseURI(utf8Encode(Actual));
  241. if fragment <> nil then
  242. AssertEquals(id+'#1', string(fragment), URI.Bookmark);
  243. if query <> nil then
  244. AssertEquals(id+'#2', string(query), URI.Params);
  245. if scheme <> nil then
  246. AssertEquals(id+'#3', string(scheme), URI.Protocol);
  247. if host <> nil then
  248. begin
  249. AssertTrue(id+'#4', URI.HasAuthority);
  250. AssertEquals(id+'#5', string(host), URI.Host);
  251. end;
  252. if path <> nil then
  253. AssertEquals(id+'#6', string(path), '//' + Uri.Host + URI.Path + URI.Document);
  254. if file_ <> nil then
  255. AssertEquals(id+'#7', string(file_), URI.Document);
  256. if name <> nil then
  257. AssertEquals(id+'#8', string(name), ChangeFileExt(URI.Document, ''));
  258. end;
  259. function TDOMTestBase.bad_condition(const TagName: XMLString): Boolean;
  260. begin
  261. Fail('Unsupported condition: '+ AnsiString(TagName));
  262. Result := False;
  263. end;
  264. function TDOMTestBase.ContentTypeIs(const t: string): Boolean;
  265. begin
  266. { For now, claim only xml as handled content.
  267. This may be extended with html and svg.
  268. }
  269. result := (t = 'text/xml');
  270. end;
  271. function TDOMTestBase.GetImplementation: TDOMImplementation;
  272. begin
  273. result := nil;
  274. end;
  275. procedure TDOMTestBase.CheckFeature(const name: string);
  276. begin
  277. // purpose/action is currently unknown
  278. end;
  279. function TDOMTestBase.GetTestFilesURI: string;
  280. begin
  281. result := '';
  282. end;
  283. procedure TDOMTestBase.LoadStringData(out Doc; const data: string);
  284. var
  285. src: TXMLInputSource;
  286. begin
  287. src := TXMLInputSource.Create(data);
  288. try
  289. FParser.Parse(src, TXMLDocument(Doc));
  290. GC(TObject(Doc));
  291. finally
  292. src.Free;
  293. end;
  294. end;
  295. end.