Browse Source

Test suite improvements, targeted to support the HTML suite:

domunit.pp:
+ Added AssertEqualsNoCase() method.
* TDOMTestBase.Load chaned doc argument to untyped, because some tests use TDOMNode instead of a
  TDOMDocument.
* Completed the URIEquals() method; changed parameter types to PChar in order to be able to
  distinguish nil from empty string.
* Modified GetResourceURI method so it is capable to handle the directory structure of CVS
  snapshot (level2/html using data files from level1/html).

testgen.pp:
* Counterparts to changes in domunit.pp
+ Support for renaming APIs (e.g. 'type'->'htmlType')
+ Support for enforcing the correct type of function arguments (emits 'as' operator).

api.xml:
+ Added data for DOM Level3 XPath and Level2 HTML suites.

git-svn-id: trunk@13055 -
sergei 16 years ago
parent
commit
efcccbf895
3 changed files with 547 additions and 48 deletions
  1. 437 2
      packages/fcl-xml/tests/api.xml
  2. 53 12
      packages/fcl-xml/tests/domunit.pp
  3. 57 34
      packages/fcl-xml/tests/testgen.pp

+ 437 - 2
packages/fcl-xml/tests/api.xml

@@ -14,7 +14,10 @@
   type (func|prop|method) "func"
   result CDATA #IMPLIED
   objtype CDATA #IMPLIED
+  rename CDATA #IMPLIED
   gc (yes|no) #IMPLIED>
+<!ATTLIST arg
+  type CDATA #IMPLIED>
 ]>
 <api>
 <item id="createDocumentFragment"/>
@@ -74,6 +77,11 @@
 <item id="publicId" type="prop"/> <!-- settable for DOM lvl 3 LSInput -->
 <item id="systemId" type="prop"/>
 <item id="notationName"/>
+<!-- Handled separately because our DOM has it as a default property, not a function
+<item id="item" result="Node">
+  <arg>index</arg>
+</item>
+-->
 <item id="getNamedItem" result="Node">
   <arg>name</arg>
 </item>
@@ -230,7 +238,7 @@
 
 <!-- Level 3 -->
 <item id="textContent" type="prop"/>
-<!-- item id="isElementContentWhitespace"/ --><!-- not there yet -->
+<item id="isElementContentWhitespace"/>
 <!--
 <item id="domConfig"/>
 <item id="schemaTypeInfo"/>
@@ -249,7 +257,9 @@
 <item id="setUserData"/>
 <item id="isEqualNode"/>
 <item id="isSameNode"/>
-<item id="lookupNamespaceURI"/>
+<item id="lookupNamespaceURI">
+  <arg>prefix</arg>
+</item>
 <item id="lookupPrefix"/>
 <item id="isDefaultNamespace"/>
 <item id="adoptNode"/>
@@ -257,4 +267,429 @@
 <item id="replaceWholeText"/>
 <item id="wholeText"/>
 -->
+<!-- XPath -->
+
+<item id="createNSResolver">
+  <arg>nodeResolver</arg>
+</item>
+
+<item id="XPathEvaluator.evaluate">
+  <arg>expression</arg>
+  <arg>contextNode</arg>
+  <arg>resolver</arg>
+  <arg>type</arg>
+  <arg>result</arg>
+</item>
+<item id="XPathExpression.evaluate">
+  <arg>contextNode</arg>
+  <arg>type</arg>
+  <arg>result</arg>
+</item>
+<item id="createExpression">
+  <arg>expression</arg>
+  <arg>resolver</arg>
+</item>
+<item id="iterateNext"/>
+<item id="booleanValue"/>
+<item id="numberValue"/>
+<item id="singleNodeValue"/>
+<item id="stringValue"/>
+<item id="resultType"/>
+<item id="snapshotLength"/>
+<item id="snapshotItem">
+  <arg>index</arg>
+</item>
+<item id="invalidIteratorState"/>
+
+<!-- HTML level 2 -->
+
+<item id="id" objtype="HTMLElement" type="prop"/>          <!-- applies to all HTML*Element -->
+<item id="namedItem">                <!-- HTMLCollection -->
+  <arg>name</arg>
+</item>
+
+<item id="body" objtype="HTMLDocument" type="prop"/>
+
+<item id="HTMLAnchorElement.accessKey" type="prop"/>
+<item id="HTMLAnchorElement.charset" type="prop"/>
+<item id="HTMLAnchorElement.coords" type="prop"/>
+<item id="HTMLAnchorElement.href" type="prop"/>
+<item id="HTMLAnchorElement.hreflang" type="prop"/>
+<item id="HTMLAnchorElement.name" type="prop"/>
+<item id="HTMLAnchorElement.rev" type="prop"/>
+<item id="HTMLAnchorElement.rel" type="prop"/>
+<item id="HTMLAnchorElement.shape" type="prop"/>
+<item id="HTMLAnchorElement.tabIndex" type="prop"/>
+<item id="HTMLAnchorElement.type" type="prop" rename="htmlType"/>
+<item id="HTMLAnchorElement.blur" type="method"/>
+<item id="HTMLAnchorElement.focus" type="method"/>
+
+<item id="HTMLAppletElement.align" type="prop"/>
+<item id="HTMLAppletElement.alt" type="prop"/>
+<item id="HTMLAppletElement.archive" type="prop"/>
+<item id="HTMLAppletElement.code" type="prop"/>
+<item id="HTMLAppletElement.codeBase" type="prop"/>
+<item id="HTMLAppletElement.height" type="prop"/>
+<item id="HTMLAppletElement.hspace" type="prop"/>
+<item id="HTMLAppletElement.name" type="prop"/>
+<item id="HTMLAppletElement.vspace" type="prop"/>
+<item id="HTMLAppletElement.width" type="prop"/>
+<item id="HTMLAppletElement.object" type="prop" rename="appletObject"/>
+
+<item id="HTMLAreaElement.accessKey" type="prop"/>
+<item id="HTMLAreaElement.alt" type="prop"/>
+<item id="HTMLAreaElement.coords" type="prop"/>
+<item id="HTMLAreaElement.href" type="prop"/>
+<item id="HTMLAreaElement.noHref" type="prop"/>
+<item id="HTMLAreaElement.shape" type="prop"/>
+<item id="HTMLAreaElement.tabIndex" type="prop"/>
+<item id="HTMLAreaElement.target" type="prop"/>
+
+<item id="HTMLBaseElement.href" type="prop"/>
+<item id="HTMLBaseElement.target" type="prop"/>
+
+<item id="HTMLBaseFontElement.color" type="prop"/>
+<item id="HTMLBaseFontElement.face" type="prop"/>
+<item id="HTMLBaseFontElement.size" type="prop"/>
+
+<item id="HTMLBodyElement.aLink" type="prop"/>
+<item id="HTMLBodyElement.background" type="prop"/>
+<item id="HTMLBodyElement.bgColor" type="prop"/>
+<item id="HTMLBodyElement.link" type="prop"/>
+<item id="HTMLBodyElement.text" type="prop"/>
+<item id="HTMLBodyElement.vLink" type="prop"/>
+
+
+<item id="HTMLBRElement.clear" type="prop"/>
+
+<item id="HTMLButtonElement.form" type="prop"/>
+<item id="HTMLButtonElement.accessKey" type="prop"/>
+<item id="HTMLButtonElement.disabled" type="prop"/>
+<item id="HTMLButtonElement.tabIndex" type="prop"/>
+<item id="HTMLButtonElement.type" type="prop" rename="htmlType"/>
+
+<item id="HTMLDirectoryElement.compact" type="prop"/>
+
+<item id="HTMLDivElement.align" type="prop"/>
+
+<item id="HTMLDListElement.compact" type="prop"/>
+
+<item id="HTMLDocument.title" type="prop"/>
+<item id="HTMLDocument.referrer" type="prop"/>
+<item id="HTMLDocument.domain" type="prop"/>
+<item id="HTMLDocument.URL" type="prop"/>
+<item id="HTMLDocument.body" type="prop"/>
+<item id="HTMLDocument.images" type="prop"/>
+<item id="HTMLDocument.applets" type="prop"/>
+<item id="HTMLDocument.links" type="prop"/>
+<item id="HTMLDocument.forms" type="prop"/>
+<item id="HTMLDocument.anchors" type="prop"/>
+<item id="HTMLDocument.cookie" type="prop"/>
+<item id="HTMLDocument.getElementsByName">
+  <arg>elementName</arg>
+</item>
+<item id="HTMLDocument.open" type="method"/>  <!-- !! arg type not specified -->
+<item id="HTMLDocument.close" type="method"/>
+
+<item id="HTMLElement.id" type="prop"/>
+<item id="HTMLElement.title" type="prop"/>
+<item id="HTMLElement.lang" type="prop"/>
+<item id="HTMLElement.dir" type="prop"/>
+<item id="HTMLElement.className" type="prop"/>
+
+<item id="HTMLFieldSetElement.form" type="prop"/>
+
+<item id="HTMLFontElement.color" type="prop"/>
+<item id="HTMLFontElement.face" type="prop"/>
+<item id="HTMLFontElement.size" type="prop"/>
+
+<item id="HTMLFormElement.elements" type="prop"/>
+<item id="HTMLFormElement.acceptCharset" type="prop"/>
+<item id="HTMLFormElement.action" type="prop"/>
+<item id="HTMLFormElement.enctype" type="prop"/>
+<item id="HTMLFormElement.method" type="prop"/>
+<item id="HTMLFormElement.reset" type="method"/>
+<item id="HTMLFormElement.submit" type="method"/>
+
+<item id="HTMLFrameElement.frameBorder" type="prop"/>
+<item id="HTMLFrameElement.longDesc" type="prop"/>
+<item id="HTMLFrameElement.marginHeight" type="prop"/>
+<item id="HTMLFrameElement.marginWidth" type="prop"/>
+<item id="HTMLFrameElement.noResize" type="prop"/>
+<item id="HTMLFrameElement.scrolling" type="prop"/>
+<item id="HTMLFrameElement.src" type="prop"/>
+<item id="HTMLFrameElement.contentDocument" type="prop"/>   <!-- level 2 -->
+
+<item id="HTMLFrameSetElement.cols" type="prop"/>
+<item id="HTMLFrameSetElement.rows" type="prop"/>
+
+<item id="HTMLHeadElement.profile" type="prop"/>
+
+<item id="HTMLHeadingElement.align" type="prop"/>
+
+<item id="HTMLHRElement.align" type="prop"/>
+<item id="HTMLHRElement.noShade" type="prop"/>
+<item id="HTMLHRElement.size" type="prop"/>
+<item id="HTMLHRElement.width" type="prop"/>
+
+<item id="HTMLHtmlElement.version" type="prop"/>
+
+<item id="HTMLIFrameElement.align" type="prop"/>
+<item id="HTMLIFrameElement.frameBorder" type="prop"/>
+<item id="HTMLIFrameElement.height" type="prop"/>
+<item id="HTMLIFrameElement.longDesc" type="prop"/>
+<item id="HTMLIFrameElement.marginWidth" type="prop"/>
+<item id="HTMLIFrameElement.marginHeight" type="prop"/>
+<item id="HTMLIFrameElement.scrolling" type="prop"/>
+<item id="HTMLIFrameElement.src" type="prop"/>
+<item id="HTMLIFrameElement.width" type="prop"/>
+<item id="HTMLIFrameElement.contentDocument" type="prop"/>   <!-- level 2 -->
+
+<item id="HTMLImageElement.align" type="prop"/>
+<item id="HTMLImageElement.alt" type="prop"/>
+<item id="HTMLImageElement.border" type="prop"/>
+<item id="HTMLImageElement.height" type="prop"/>
+<item id="HTMLImageElement.hspace" type="prop"/>
+<item id="HTMLImageElement.isMap" type="prop"/>
+<item id="HTMLImageElement.longDesc" type="prop"/>
+<item id="HTMLImageElement.src" type="prop"/>
+<item id="HTMLImageElement.useMap" type="prop"/>
+<item id="HTMLImageElement.vspace" type="prop"/>
+<item id="HTMLImageElement.width" type="prop"/>
+<item id="HTMLImageElement.lowSrc" type="prop"/>
+
+<item id="HTMLInputElement.defaultValue" type="prop"/>
+<item id="HTMLInputElement.defaultChecked" type="prop"/>
+<item id="HTMLInputElement.form" type="prop"/>
+<item id="HTMLInputElement.accept" type="prop"/>
+<item id="HTMLInputElement.accessKey" type="prop"/>
+<item id="HTMLInputElement.align" type="prop"/>
+<item id="HTMLInputElement.alt" type="prop"/>
+<item id="HTMLInputElement.checked" type="prop"/>
+<item id="HTMLInputElement.disabled" type="prop"/>
+<item id="HTMLInputElement.maxLength" type="prop"/>
+<item id="HTMLInputElement.readOnly" type="prop"/>
+<item id="HTMLInputElement.size" type="prop"/>
+<item id="HTMLInputElement.src" type="prop"/>
+<item id="HTMLInputElement.tabIndex" type="prop"/>
+<item id="HTMLInputElement.type" type="prop" rename="htmlType"/>
+<item id="HTMLInputElement.useMap" type="prop"/>
+<item id="HTMLInputElement.blur" type="method"/>
+<item id="HTMLInputElement.focus" type="method"/>
+<item id="HTMLInputElement.click" type="method"/>
+<item id="HTMLInputElement.select" type="method"/>
+
+<item id="HTMLIsIndexElement.prompt" type="prop"/>
+<item id="HTMLIsIndexElement.form" type="prop"/>
+
+<item id="HTMLLabelElement.form" type="prop"/>
+<item id="HTMLLabelElement.accessKey" type="prop"/>
+<item id="HTMLLabelElement.htmlFor" type="prop"/>
+
+<item id="HTMLLegendElement.form" type="prop"/>
+<item id="HTMLLegendElement.accessKey" type="prop"/>
+<item id="HTMLLegendElement.align" type="prop"/>
+
+<item id="HTMLLIElement.type" type="prop" rename="htmlType"/>
+
+<item id="HTMLLinkElement.disabled" type="prop"/>
+<item id="HTMLLinkElement.charset" type="prop"/>
+<item id="HTMLLinkElement.href" type="prop"/>
+<item id="HTMLLinkElement.hreflang" type="prop"/>
+<item id="HTMLLinkElement.media" type="prop"/>
+<item id="HTMLLinkElement.rel" type="prop"/>
+<item id="HTMLLinkElement.rev" type="prop"/>
+<item id="HTMLLinkElement.type" type="prop" rename="htmlType"/>
+
+<item id="HTMLMapElement.areas" type="prop"/>
+<item id="HTMLMapElement.name" type="prop"/>
+
+<item id="HTMLMenuElement.compact" type="prop"/>
+
+<item id="HTMLMetaElement.content" type="prop"/>
+<item id="HTMLMetaElement.httpEquiv" type="prop"/>
+<item id="HTMLMetaElement.name" type="prop"/>
+<item id="HTMLMetaElement.scheme" type="prop"/>
+
+<item id="HTMLModElement.cite" type="prop"/>
+<item id="HTMLModElement.dateTime" type="prop"/>
+
+<item id="HTMLObjectElement.form" type="prop"/>
+<item id="HTMLObjectElement.code" type="prop"/>
+<item id="HTMLObjectElement.align" type="prop"/>
+<item id="HTMLObjectElement.archive" type="prop"/>
+<item id="HTMLObjectElement.border" type="prop"/>
+<item id="HTMLObjectElement.codeBase" type="prop"/>
+<item id="HTMLObjectElement.codeType" type="prop"/>
+<item id="HTMLObjectElement.data" type="prop"/>
+<item id="HTMLObjectElement.declare" type="prop"/>
+<item id="HTMLObjectElement.height" type="prop"/>
+<item id="HTMLObjectElement.hspace" type="prop"/>
+<item id="HTMLObjectElement.standby" type="prop"/>
+<item id="HTMLObjectElement.tabIndex" type="prop"/>
+<item id="HTMLObjectElement.type" type="prop" rename="htmlType"/>
+<item id="HTMLObjectElement.useMap" type="prop"/>
+<item id="HTMLObjectElement.vspace" type="prop"/>
+<item id="HTMLObjectElement.width" type="prop"/>
+<item id="HTMLObjectElement.name" type="prop"/>
+<item id="HTMLObjectElement.contentDocument" type="prop"/>   <!-- level 2 -->
+
+<item id="HTMLOListElement.compact" type="prop"/>
+<item id="HTMLOListElement.start" type="prop"/>
+<item id="HTMLOListElement.type" type="prop" rename="htmlType"/>
+
+<item id="HTMLOptGroupElement.disabled" type="prop"/>
+<item id="HTMLOptGroupElement.label" type="prop" rename="groupLabel"/>
+
+<item id="HTMLOptionElement.form" type="prop"/>
+<item id="HTMLOptionElement.defaultSelected" type="prop"/>
+<item id="HTMLOptionElement.text" type="prop"/>
+<item id="HTMLOptionElement.index" type="prop"/>
+<item id="HTMLOptionElement.disabled" type="prop"/>
+<item id="HTMLOptionElement.label" type="prop" rename="optionLabel"/>
+<item id="HTMLOptionElement.value" type="prop"/>
+
+<item id="HTMLParagraphElement.align" type="prop"/>
+
+<item id="HTMLParamElement.name" type="prop"/>
+<item id="HTMLParamElement.value" type="prop"/>
+<item id="HTMLParamElement.valueType" type="prop"/>
+<item id="HTMLParamElement.type" type="prop" rename="htmlType"/>
+
+<item id="HTMLPreElement.width" type="prop"/>
+
+<item id="HTMLQuoteElement.cite" type="prop"/>
+
+<item id="HTMLScriptElement.text" type="prop"/>
+<item id="HTMLScriptElement.charset" type="prop"/>
+<item id="HTMLScriptElement.defer" type="prop"/>
+<item id="HTMLScriptElement.src" type="prop"/>
+<item id="HTMLScriptElement.type" type="prop" rename="htmlType"/>
+<item id="HTMLScriptElement.htmlFor" type="prop"/>
+<item id="HTMLScriptElement.event" type="prop"/>
+
+<item id="HTMLSelectElement.type" type="prop" rename="htmlType"/>
+<item id="HTMLSelectElement.selectedIndex" type="prop"/>
+<item id="HTMLSelectElement.value" type="prop"/>
+<item id="HTMLSelectElement.length" type="prop"/>
+<item id="HTMLSelectElement.form" type="prop"/>
+<item id="HTMLSelectElement.options" type="prop"/>
+<item id="HTMLSelectElement.disabled" type="prop"/>
+<item id="HTMLSelectElement.multiple" type="prop"/>
+<item id="HTMLSelectElement.size" type="prop"/>
+<item id="HTMLSelectElement.tabIndex" type="prop"/>
+<item id="HTMLSelectElement.focus" type="method"/>
+<item id="HTMLSelectElement.blur" type="method"/>
+<item id="HTMLSelectElement.remove" type="method">
+  <arg>index</arg>
+</item>
+<item id="HTMLSelectElement.add" type="method">
+  <arg type="HTMLElement">element</arg>
+  <arg type="HTMLElement">before</arg>
+</item>
+
+<item id="HTMLStyleElement.disabled" type="prop"/>
+<item id="HTMLStyleElement.media" type="prop"/>
+<item id="HTMLStyleElement.type" type="prop" rename="htmlType"/>
+
+<item id="HTMLTableCaptionElement.align" type="prop"/>
+
+<item id="HTMLTableSectionElement.align" type="prop"/>
+<item id="HTMLTableSectionElement.ch" type="prop"/>
+<item id="HTMLTableSectionElement.chOff" type="prop"/>
+<item id="HTMLTableSectionElement.rows" type="prop"/>
+<item id="HTMLTableSectionElement.vAlign" type="prop"/>
+<item id="HTMLTableSectionElement.insertRow">
+  <arg>index</arg>
+</item>
+<item id="HTMLTableSectionElement.deleteRow" type="method">
+  <arg>index</arg>
+</item>
+
+
+<item id="HTMLTableCellElement.abbr" type="prop"/>
+<item id="HTMLTableCellElement.align" type="prop"/>
+<item id="HTMLTableCellElement.axis" type="prop"/>
+<item id="HTMLTableCellElement.bgColor" type="prop"/>
+<item id="HTMLTableCellElement.cellIndex" type="prop"/>
+<item id="HTMLTableCellElement.ch" type="prop"/>
+<item id="HTMLTableCellElement.chOff" type="prop"/>
+<item id="HTMLTableCellElement.headers" type="prop"/>
+<item id="HTMLTableCellElement.height" type="prop"/>
+<item id="HTMLTableCellElement.noWrap" type="prop"/>
+<item id="HTMLTableCellElement.rowSpan" type="prop"/>
+<item id="HTMLTableCellElement.colSpan" type="prop"/>
+<item id="HTMLTableCellElement.scope" type="prop"/>
+<item id="HTMLTableCellElement.vAlign" type="prop"/>
+<item id="HTMLTableCellElement.width" type="prop"/>
+
+<item id="HTMLTableElement.align" type="prop"/>
+<item id="HTMLTableElement.border" type="prop"/>
+<item id="HTMLTableElement.bgColor" type="prop"/>
+<item id="HTMLTableElement.caption" type="prop"/>
+<item id="HTMLTableElement.frame" type="prop"/>
+<item id="HTMLTableElement.cellPadding" type="prop"/>
+<item id="HTMLTableElement.cellSpacing" type="prop"/>
+<item id="HTMLTableElement.summary" type="prop"/>
+<item id="HTMLTableElement.rules" type="prop"/>
+<item id="HTMLTableElement.width" type="prop"/>
+<item id="HTMLTableElement.rows" type="prop"/>
+<item id="HTMLTableElement.tHead" type="prop"/>
+<item id="HTMLTableElement.tFoot" type="prop"/>
+<item id="HTMLTableElement.tBodies" type="prop"/>
+<item id="HTMLTableElement.insertRow">
+  <arg>index</arg>
+</item>
+<item id="HTMLTableElement.deleteRow" type="method">
+  <arg>index</arg>
+</item>
+<item id="HTMLTableElement.createTHead"/>
+<item id="HTMLTableElement.createTFoot"/>
+<item id="HTMLTableElement.createCaption"/>
+<item id="HTMLTableElement.deleteTHead" type="method"/>
+<item id="HTMLTableElement.deleteTFoot" type="method"/>
+<item id="HTMLTableElement.deleteCaption" type="method"/>
+
+<item id="HTMLTableRowElement.align" type="prop"/>
+<item id="HTMLTableRowElement.bgColor" type="prop"/>
+<item id="HTMLTableRowElement.vAlign" type="prop"/>
+<item id="HTMLTableRowElement.ch" type="prop"/>
+<item id="HTMLTableRowElement.chOff" type="prop"/>
+<item id="HTMLTableRowElement.rowIndex" type="prop"/>
+<item id="HTMLTableRowElement.sectionRowIndex" type="prop"/>
+<item id="HTMLTableRowElement.cells" type="prop"/>
+<item id="HTMLTableRowElement.insertCell">
+  <arg>index</arg>
+</item>
+<item id="HTMLTableRowElement.deleteCell" type="method">
+  <arg>index</arg>
+</item>
+
+<item id="HTMLTableColElement.align" type="prop"/>
+<item id="HTMLTableColElement.ch" type="prop"/>
+<item id="HTMLTableColElement.chOff" type="prop"/>
+<item id="HTMLTableColElement.span" type="prop"/>
+<item id="HTMLTableColElement.vAlign" type="prop"/>
+<item id="HTMLTableColElement.width" type="prop"/>
+
+<item id="HTMLTextAreaElement.defaultValue" type="prop"/>
+<item id="HTMLTextAreaElement.form" type="prop"/>
+<item id="HTMLTextAreaElement.accessKey" type="prop"/>
+<item id="HTMLTextAreaElement.cols" type="prop"/>
+<item id="HTMLTextAreaElement.disabled" type="prop"/>
+<item id="HTMLTextAreaElement.readOnly" type="prop"/>
+<item id="HTMLTextAreaElement.rows" type="prop"/>
+<item id="HTMLTextAreaElement.tabIndex" type="prop"/>
+<item id="HTMLTextAreaElement.type" type="prop" rename="htmlType"/>
+<item id="HTMLTextAreaElement.value" type="prop"/>
+<item id="HTMLTextAreaElement.blur" type="method"/>
+<item id="HTMLTextAreaElement.focus" type="method"/>
+<item id="HTMLTextAreaElement.select" type="method"/>
+
+<item id="HTMLUListElement.compact" type="prop"/>
+<item id="HTMLUListElement.type" type="prop" rename="htmlType"/>
+
+<item id="HTMLTitleElement.text" type="prop"/>
+
+
 </api>

+ 53 - 12
packages/fcl-xml/tests/domunit.pp

@@ -40,7 +40,7 @@ type
     procedure SetUp; override;
     procedure TearDown; override;
     procedure GC(obj: TObject);
-    procedure Load(out doc: TDOMDocument; const uri: string);
+    procedure Load(out doc; const uri: string);
     function getResourceURI(const res: WideString): WideString;
     function ContentTypeIs(const t: string): Boolean;
     function GetImplementation: TDOMImplementation;
@@ -49,12 +49,13 @@ type
     procedure assertEquals(const id: string; exp, act: TObject); overload;
     procedure assertEqualsList(const id: string; const exp: array of DOMString; const act: _list);
     procedure assertEqualsCollection(const id: string; const exp: array of DOMString; const act: _collection);
+    procedure assertEqualsNoCase(const id: string; const exp, act: DOMString);
     procedure assertSame(const id: string; exp, act: TDOMNode);
     procedure assertSize(const id: string; size: Integer; obj: TDOMNodeList);
     procedure assertSize(const id: string; size: Integer; obj: TDOMNamedNodeMap);
     procedure assertInstanceOf(const id: string; obj: TObject; const typename: string);
     procedure assertURIEquals(const id: string;
-      const scheme, path, host, file_, name, query, fragment: DOMString;
+      scheme, path, host, file_, name, query, fragment: PChar;
       IsAbsolute: Boolean; const Actual: DOMString);
     function bad_condition(const TagName: WideString): Boolean;
     property implementationAttribute[const name: string]: Boolean read getImplAttr write setImplAttr;
@@ -160,6 +161,12 @@ begin
   end;
 end;
 
+procedure TDOMTestBase.assertEqualsNoCase(const id: string; const exp, act: DOMString);
+begin
+// TODO: could write custom comparison because range is limited to ASCII
+  AssertTrue(id + ComparisonMsg(exp, act), WideSameText(exp, act));
+end;
+
 procedure TDOMTestBase.assertSize(const id: string; size: Integer; obj: TDOMNodeList);
 begin
   AssertNotNull(id, obj);
@@ -174,10 +181,28 @@ end;
 
 function TDOMTestBase.getResourceURI(const res: WideString): WideString;
 var
-  Base, Level: WideString;
+  Base, Base2: WideString;
+
+function CheckFile(const uri: WideString; out name: WideString): Boolean;
+var
+  filename: string;
+begin
+  Result := ResolveRelativeURI(uri + 'files/', res + '.xml', name) and
+    URIToFilename(name, filename) and
+    FileExists(filename);
+end;
+
 begin
-  Base := GetTestFilesURI + 'files/';
-  if not ResolveRelativeURI(Base, res+'.xml', Result) then
+  Base := GetTestFilesURI;
+  if Pos(WideString('level2/html'), Base) <> 0 then
+  begin
+    // This is needed to run HTML testsuite off the CVS snapshot.
+    // Web version simply uses all level1 files copied to level2.
+    if ResolveRelativeURI(Base, '../../level1/html/', Base2) and
+      CheckFile(Base2, Result) then
+        Exit;
+  end;
+  if not CheckFile(Base, Result) then
     Result := '';
 end;
 
@@ -218,13 +243,13 @@ begin
     Fail('Unknown implementation attribute: ''' + name + '''');
 end;
 
-procedure TDOMTestBase.Load(out doc: TDOMDocument; const uri: string);
+procedure TDOMTestBase.Load(out doc; const uri: string);
 var
   t: TXMLDocument;
 begin
-  doc := nil;
+  TObject(doc) := nil;
   FParser.ParseURI(getResourceURI(uri), t);
-  doc := t;
+  TObject(doc) := t;
   GC(t);
 end;
 
@@ -233,16 +258,32 @@ begin
   AssertTrue(id, obj.ClassNameIs(typename));
 end;
 
-// TODO: This is a very basic implementation, needs to be completed.
-procedure TDOMTestBase.assertURIEquals(const id: string; const scheme, path,
-  host, file_, name, query, fragment: DOMString; IsAbsolute: Boolean;
+{ expected args already UTF-8 encoded }
+procedure TDOMTestBase.assertURIEquals(const id: string; scheme, path,
+  host, file_, name, query, fragment: PChar; IsAbsolute: Boolean;
   const Actual: DOMString);
 var
   URI: TURI;
 begin
   AssertTrue(id, Actual <> '');
   URI := ParseURI(utf8Encode(Actual));
-  AssertEquals(id, URI.Document, utf8Encode(file_));
+  if fragment <> nil then
+    AssertEquals(id, string(fragment), URI.Bookmark);
+  if query <> nil then
+    AssertEquals(id, string(query), URI.Params);
+  if scheme <> nil then
+    AssertEquals(id, string(scheme), URI.Protocol);
+  if host <> nil then
+  begin
+    AssertTrue(id, URI.HasAuthority);
+    AssertEquals(id, string(host), URI.Host);
+  end;
+  if path <> nil then
+    AssertEquals(id, string(path), '//' + Uri.Host + URI.Path + URI.Document);
+  if file_ <> nil then
+    AssertEquals(id, string(file_), URI.Document);
+  if name <> nil then
+    AssertEquals(id, string(name), ChangeFileExt(URI.Document, ''));
 end;
 
 function TDOMTestBase.bad_condition(const TagName: WideString): Boolean;

+ 57 - 34
packages/fcl-xml/tests/testgen.pp

@@ -39,7 +39,8 @@ begin
     result := '_collection'
   else if s = 'List' then
     result := '_list'
-  else if (Pos(WideString('DOM'), s) = 1) or (Pos(WideString('XPath'), s) = 1) then
+  else if (Pos(WideString('DOM'), s) = 1) or (Pos(WideString('XPath'), s) = 1) or
+          (Pos(WideString('HTML'), s) = 1) then
     result := 'T' + s
   else
     result := 'TDOM'+s;
@@ -69,7 +70,7 @@ begin
   if n.HasAttribute(attName) then
     s := s + ReplaceQuotes(n[attName])
   else
-    s := s + '''''';
+    s := s + 'nil';
   s := s + ', ';
 end;
 
@@ -232,23 +233,56 @@ begin
   end;
 end;
 
+function fixname(e: TDOMElement): string;
+begin
+  if e.HasAttribute('_fixup_') then
+    result := e['_fixup_']
+  else  
+    result := e.TagName;
+end;
+
+function argstring(e: TDOMElement; args: TDOMNodeList): string;
+var
+  I: Integer;
+  argnode: TDOMElement;
+begin
+  Result := '';
+  for I := 0 to args.Length-1 do
+  begin
+    argnode := args[I] as TDOMElement;
+    Result := Result + ReplaceQuotes(e[argnode.TextContent]);
+    if argnode.HasAttribute('type') then
+      Result := Result + ' as ' + PascalType(argnode['type']);
+    if I <> args.Length-1 then
+      Result := Result + ', ';
+  end;
+end;
+
 function prop_call(e: TDOMElement): string;
 begin
   if e.HasAttribute('var') then
-    Result := e['var'] + ' := ' + getobj(e) + '.' + e.TagName + ';'
+    Result := e['var'] + ' := ' + getobj(e) + '.' + fixname(e) + ';'
   else
-    Result := getobj(e) + '.' + e.TagName + ' := ' + ReplaceQuotes(e['value']) + ';';
+    Result := getobj(e) + '.' + fixname(e) + ' := ' + ReplaceQuotes(e['value']) + ';';
 end;
 
-function func_call(e: TDOMElement; const args: array of DOMString; const rsltType: string=''): string;
-var
-  I: Integer;
+function func_call(e: TDOMElement; args: TDOMNodeList; const rsltType: string=''): string;
 begin
   if (rsltType <> '') and (TypeOfVar(e['var']) <> rsltType) then
     Result := rsltType + '(' + e['var'] + ')'
   else
     Result := e['var'];
-  Result := Result + ' := ' + getobj(e) + '.' + e.TagName;
+  Result := Result + ' := ' + getobj(e) + '.' + fixname(e);
+  if args.Length > 0 then
+    Result := Result + '(' + argstring(e, args) + ')';
+  Result := Result + ';';
+end;
+
+function func_call(e: TDOMElement; const args: array of DOMString): string;
+var
+  I: Integer;
+begin
+  Result := e['var'] + ' := ' + getobj(e) + '.' + e.TagName;
   if Length(args) > 0 then
   begin
     Result := Result + '(';
@@ -264,21 +298,10 @@ begin
 end;
 
 function method_call(e: TDOMElement; args: TDOMNodeList): string;
-var
-  I: Integer;
 begin
-  Result := getobj(e) + '.' + e.TagName;
+  Result := getobj(e) + '.' + fixname(e);
   if args.Length > 0 then
-  begin
-    Result := Result + '(';
-    for I := 0 to args.Length-1 do
-    begin
-      Result := Result + ReplaceQuotes(e[args[I].TextContent]);
-      if I <> args.Length-1 then
-        Result := Result + ', ';
-    end;
-    Result := Result + ')';
-  end;
+    Result := Result + '(' + argstring(e, args) + ')';
   Result := Result + ';';
 end;
 
@@ -301,8 +324,6 @@ var
   cond: string;
   apinode: TDOMElement;
   arglist: TDOMNodeList;
-  args: array of DOMString;
-  I: Integer;
 begin
   FixKeywords(node, 'var');
   FixKeywords(node, 'obj');
@@ -316,16 +337,19 @@ begin
   if assigned(apinode) then
   begin
     // handle most of DOM API in consistent way
+    
+    if apinode.HasAttribute('rename') then   // handles reserved words, e.g 'type' -> 'htmlType'
+      node['_fixup_'] := apinode['rename'];  // use this trick because DOM node cannot be renamed (yet)
+    
     arglist := apinode.GetElementsByTagName('arg');
-    SetLength(args, arglist.Length);
-    for I := 0 to arglist.Length-1 do
-      args[I] := arglist[I].TextContent;
+
+    if apinode.HasAttribute('objtype') then
+      CastTo(node, apinode['objtype']);
+      
     if apinode['type'] = 'prop' then
       rslt.Add(indent + prop_call(node))
     else if apinode['type'] = 'method' then
     begin
-      if apinode.HasAttribute('objtype') then
-        CastTo(node, apinode['objtype']);
       rslt.Add(indent + method_call(node, arglist));
     end
     else
@@ -334,9 +358,7 @@ begin
         cond := PascalType(apinode['result'])
       else
         cond := '';
-      if apinode.HasAttribute('objtype') then
-        CastTo(node, apinode['objtype']);
-      rslt.Add(indent + func_call(node, args, cond));
+      rslt.Add(indent + func_call(node, arglist, cond));
       if apinode['gc'] = 'yes' then
         rslt.Add(indent + 'GC(' + node['var'] + ');');
     end;
@@ -403,6 +425,8 @@ begin
       rslt.Add(indent + 'AssertEqualsCollection(''' + node['id'] + ''', ' + ReplaceQuotes(node['expected']) + ', ' + node['actual'] + ');')
     else if cond = '_list' then
       rslt.Add(indent + 'AssertEqualsList(''' + node['id'] + ''', ' + ReplaceQuotes(node['expected']) + ', ' + node['actual'] + ');')
+    else if node['ignoreCase'] = 'true' then
+      rslt.Add(indent + 'AssertEqualsNoCase(''' + node['id'] + ''', ' + ReplaceQuotes(node['expected']) + ', ' + node['actual'] + ');')
     else
       rslt.Add(indent + s + '(''' + node['id'] + ''', ' + ReplaceQuotes(node['expected']) + ', ' + node['actual'] + ');');
   end
@@ -599,7 +623,7 @@ begin
       // having loop var name globally unique isn't a must.
       cond := 'loop'+IntToStr(cntr);
       Inc(cntr);
-      rslt.Insert(2, '  ' + cond + ': Integer;');
+      rslt.Insert(rslt.IndexOf('var')+1, '  ' + cond + ': Integer;');
       IsColl := IsCollection(element);
       if IsColl then
         rslt.Add(indent+'for '+cond+' := 0 to ' + 'High(' + element['collection'] + ') do')
@@ -837,7 +861,6 @@ begin
   for I := 0 to testcount-1 do
   begin
     href := TDOMElement(testlist[I])['href'];
-    // simple concatenation should suffice, but be paranoid
     ResolveRelativeURI(BaseURI, href, testuri);
     Pars.ParseURI(testuri, testdoc);
     try
@@ -848,7 +871,7 @@ begin
         root['name'] := 'attr_name';
       sl.Add('procedure ' + class_name + '.' + root['name'] + ';');
       try
-      ConvertTest(root, sl);
+        ConvertTest(root, sl);
       except
         Writeln('An exception occured while converting '+root['name']);
         raise;