/* Assertions for the HTMLDocument legacy alias installed by generics.js.
 *
 * Concatenated after generics.js by run-jstests.sh, so `NetSurf` is in scope
 * and ceInstall() can be driven with stand-in prototypes.
 *
 * The bug this pins down: HTMLDocument was simply absent, and a bundle that
 * touches the name dies on a ReferenceError before anything else in the file
 * runs -- one missing global taking a whole theme's scripts with it. The spec
 * makes Window.HTMLDocument a legacy *alias* of Document: the same interface
 * object, not a second one, so patches applied through either name land on the
 * prototype real documents carry.
 */

var fail = 0;

function check(what, got, want)
{
	var ok = got === want;
	if (!ok)
		fail++;
	print((ok ? "  ok   " : "  FAIL ") + what +
	      ": got " + got + (ok ? "" : ", want " + want));
}

print("HTMLDocument alias:");

/* The prototypes nsgenbind would hand over. Document inherits from Node the
 * way the bound ones do, so the interface-object chain is exercised too. */
var nodeProto = {};
var documentProto = Object.create(nodeProto);
var doc = Object.create(documentProto);   /* stands in for `document` */

NetSurf.ceInstall({ Node: nodeProto, Document: documentProto }, null);

check("HTMLDocument is defined",
      typeof globalThis.HTMLDocument !== 'undefined', true);
check("HTMLDocument is a function", typeof HTMLDocument, "function");

/* An alias, not a copy: === is the whole point. A separate constructor with
 * the same prototype would pass an instanceof test and still break
 * `HTMLDocument === Document` feature detection and identity maps. */
check("HTMLDocument is Document itself", HTMLDocument === Document, true);
check("shares Document.prototype",
      HTMLDocument.prototype === Document.prototype, true);
check("prototype is the bound one", HTMLDocument.prototype === documentProto,
      true);

check("a document is instanceof HTMLDocument", doc instanceof HTMLDocument,
      true);
check("a document is instanceof Document", doc instanceof Document, true);
check("a document is instanceof Node", doc instanceof Node, true);

/* What the failing bundle actually does: patch through the legacy name and
 * expect real documents to see it. */
HTMLDocument.prototype.__patched = 42;
check("patch through HTMLDocument reaches documents", doc.__patched, 42);
delete HTMLDocument.prototype.__patched;

/* Not enumerable, like every other interface object on Window: a page that
 * walks `for (k in window)` must not start seeing it. */
check("not enumerable on the global",
      Object.getOwnPropertyDescriptor(globalThis, 'HTMLDocument').enumerable,
      false);
check("configurable", Object.getOwnPropertyDescriptor(
      globalThis, 'HTMLDocument').configurable, true);

/* Calling an interface object is a TypeError, and the alias must behave the
 * same way -- it is the same object. */
var threw = false;
try {
	HTMLDocument();
} catch (e) {
	threw = (e instanceof TypeError);
}
check("HTMLDocument() throws TypeError", threw, true);

threw = false;
try {
	new HTMLDocument();
} catch (e) {
	threw = (e instanceof TypeError);
}
check("new HTMLDocument() throws TypeError", threw, true);

/* A second ceInstall() -- reruns happen per document -- must not clobber the
 * alias with anything different. */
NetSurf.ceInstall({ Node: nodeProto, Document: documentProto }, null);
check("survives a second install", HTMLDocument === Document, true);

/* A page that defines its own HTMLDocument keeps it: the alias only fills a
 * hole. (Checked by hand rather than through ceInstall, which is what the
 * "already claimed" guard in the installer is written against.) */
print("");
print("HTMLDocument alias: " + (fail === 0 ? "all ok" : fail + " failure(s)"));
if (fail !== 0)
	throw new Error(fail + " HTMLDocument alias test(s) failed");
