<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=588683
-->
<head>
  <title>Test for form attributes 1</title>
  <script src="/tests/SimpleTest/SimpleTest.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=588683">Mozilla Bug 588683</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">

/** Test for form attributes 1 **/

/**
 * All functions take an array of forms in first argument and an array of
 * elements in second argument.
 * Then, it returns an array containing an array of form and an array of array
 * of elements. The array represent the form association with elements like this:
 * [ [ form1, form2 ], [ [ elmt1ofForm1, elmt2ofForm2 ], [ elmtofForm2 ] ] ]
 */

/**
 * test0a and test0b are testing the regular behavior of form ownership.
 */
function test0a(aForms, aElements)
{
  // <form><element></form>
  // <form><element></form>
  aForms[0].appendChild(aElements[0]);
  aForms[1].appendChild(aElements[1]);

  return [[aForms[0],aForms[1]],[[aElements[0]],[aElements[1]]]];
}

function test0b(aForms, aElements)
{
  // <form><element><form><element></form></form>
  aForms[0].appendChild(aElements[0]);
  aForms[0].appendChild(aForms[1]);
  aForms[1].appendChild(aElements[1]);

  return [[aForms[0],aForms[1]],[[aElements[0]],[aElements[1]]]];
}

/**
 * This function test that, when an element is not a descendant of a form
 * element and has @form set to a valid form id, it's form owner is the form
 * which has the id.
 */
function test1(aForms, aElements)
{
  // <form id='f'></form><element id='f'>
  aForms[0].id = 'f';
  aElements[0].setAttribute('form', 'f');

  return [[aForms[0]], [[aElements[0]]]];
}

/**
 * This function test that, when an element is a descendant of a form
 * element and has @form set to a valid form id (not it's descendant), it's form
 * owner is the form which has the id.
 */
function test2(aForms, aElements)
{
  // <form id='f'></form><form><element form='f'></form>
  aForms[0].id = 'f';
  aForms[1].appendChild(aElements[0]);
  aElements[0].setAttribute('form', 'f');

  return [[aForms[0], aForms[1]], [[aElements[0]],[]]];
}

/**
 * This function test that, when an element is a descendant of a form
 * element and has @form set to a valid form id (not it's descendant), then the
 * form attribute is removed, it does not have a form owner.
 */
function test3(aForms, aElements)
{
  // <form id='f'></form><form><element form='f'></form>
  aForms[0].id = 'f';
  aForms[1].appendChild(aElements[0]);
  aElements[0].setAttribute('form', 'f');
  aElements[0].removeAttribute('form');

  return [[aForms[0], aForms[1]], [[],[aElements[0]]]];
}

/**
 * This function test that, when an element is a descendant of a form
 * element and has @form set to a valid form id (not it's descendant), then the
 * form's id attribute is removed, it does not have a form owner.
 */
function test4(aForms, aElements)
{
  // <form id='f'></form><form><element form='f'></form>
  aForms[0].id = 'f';
  aForms[1].appendChild(aElements[0]);
  aElements[0].setAttribute('form', 'f');
  aForms[0].removeAttribute('id');

  return [[aForms[0], aForms[1]], [[],[]]];
}

/**
 * This function test that, when an element is a descendant of a form
 * element and has @form set to an invalid form id, then it does not have a form
 * owner.
 */
function test5(aForms, aElements)
{
  // <form id='f'></form><form><element form='foo'></form>
  aForms[0].id = 'f';
  aForms[1].appendChild(aElements[0]);
  aElements[0].setAttribute('form', 'foo');

  return [[aForms[0], aForms[1]], [[],[]]];
}

/**
 * This function test that, when an element is a descendant of a form
 * element and has @form set to a valid form id (not it's descendant), then the
 * form id attribute is changed to an invalid id, it does not have a form owner.
 */
function test6(aForms, aElements)
{
  // <form id='f'></form><form><element form='f'></form>
  aForms[0].id = 'f';
  aForms[1].appendChild(aElements[0]);
  aElements[0].setAttribute('form', 'f');
  aElements[0].setAttribute('form', 'foo');

  return [[aForms[0], aForms[1]], [[],[]]];
}

/**
 * This function test that, when an element is a descendant of a form
 * element and has @form set to an invalid form id, then the form id attribute
 * is changed to a valid form id, it's form owner is the form which has this id.
 */
function test7(aForms, aElements)
{
  // <form id='f'></form><form><element form='foo'></form>
  aForms[0].id = 'f';
  aForms[1].appendChild(aElements[0]);
  aElements[0].setAttribute('form', 'foo');
  aElements[0].setAttribute('form', 'f');

  return [[aForms[0], aForms[1]], [[aElements[0]],[]]];
}

/**
 * This function test that, when an element is a descendant of a form
 * element and has @form set to a list of ids containing one valid form, then
 * it does not have a form owner.
 */
function test8(aForms, aElements)
{
  // <form id='f'></form><form><element form='f foo'></form>
  aForms[0].id = 'f';
  aForms[1].appendChild(aElements[0]);
  aElements[0].setAttribute('form', 'f foo');

  return [[aForms[0], aForms[1]], [[],[]]];
}

/**
 * This function test that, when an element is a descendant of a form
 * element and has @form set to a form id which is valid in a case insensitive
 * way, then it does not have a form owner.
 */
function test9(aForms, aElements)
{
  // <form id='f'></form><form><element form='F'></form>
  aForms[0].id = 'f';
  aForms[1].appendChild(aElements[0]);
  aElements[0].setAttribute('form', 'F');

  return [[aForms[0], aForms[1]], [[],[]]];
}

/**
 * This function test that, when an element is a descendant of a form
 * element and has @form set to a form id which is not a valid id, then it's
 * form owner is it does not have a form owner.
 */
function test10(aForms, aElements)
{
  // <form id='F'></form><form><element form='f'></form>
  aForms[0].id = 'F';
  aForms[1].appendChild(aElements[0]);
  aElements[0].setAttribute('form', 'f');

  return [[aForms[0], aForms[1]], [[],[]]];
}

/**
 * This function test that, when an element is a descendant of a form
 * element and has @form set to a form id which is not a valid id, then it's
 * form owner is it does not have a form owner.
 */
function test11(aForms, aElements)
{
  // <form id='foo bar'></form><form><element form='foo bar'></form>
  aForms[0].id = 'foo bar';
  aForms[1].appendChild(aElements[0]);
  aElements[0].setAttribute('form', 'foo bar');

  return [[aForms[0], aForms[1]], [[aElements[0]],[]]];
}

/**
 * This function test that, when an element is a descendant of a form
 * element and has @form set to a valid form id and the form id change, then
 * it does not have a form owner.
 */
function test12(aForms, aElements)
{
  // <form id='f'></form><form><element form='f'></form>
  aForms[0].id = 'f';
  aForms[1].appendChild(aElements[0]);
  aElements[0].setAttribute('form', 'f');
  aForms[0].id = 'foo';

  return [[aForms[0], aForms[1]], [[],[]]];
}

/**
 * This function test that, when an element is a descendant of a form
 * element and has @form set to an invalid form id and the form id change to a
 * valid one, then it's form owner is the form which has the id.
 */
function test13(aForms, aElements)
{
  // <form id='foo'></form><form><element form='f'></form>
  aForms[0].id = 'foo';
  aForms[1].appendChild(aElements[0]);
  aElements[0].setAttribute('form', 'f');
  aForms[0].id = 'f';

  return [[aForms[0], aForms[1]], [[aElements[0]],[]]];
}

/**
 * This function test that, when an element is a descendant of a form
 * element and has @form set to a valid form id and a form with the same id is
 * inserted before in the tree, then it's form owner is the form which has the
 * id.
 */
function test14(aForms, aElements)
{
  // <form id='f'></form><form><element form='f'></form>
  aForms[0].id = 'f';
  aForms[1].appendChild(aElements[0]);
  aElements[0].setAttribute('form', 'f');
  aForms[2].id = 'f';

  document.getElementById('content').insertBefore(aForms[2], aForms[0]);

  return [[aForms[0], aForms[1], aForms[2]], [[],[],[aElements[0]]]];
}

/**
 * This function test that, when an element is a descendant of a form
 * element and has @form set to a valid form id and an element with the same id is
 * inserted before in the tree, then it does not have a form owner.
 */
function test15(aForms, aElements)
{
  // <form id='f'></form><form><element form='f'></form>
  aForms[0].id = 'f';
  aForms[1].appendChild(aElements[0]);
  aElements[0].setAttribute('form', 'f');
  aElements[1].id = 'f';

  document.getElementById('content').insertBefore(aElements[1], aForms[0]);

  return [[aForms[0], aForms[1]], [[],[]]];
}

/**
 * This function test that, when an element is a descendant of a form
 * element and has @form set to a valid form id and the form is removed from
 * the tree, then it does not have a form owner.
 */
function test16(aForms, aElements)
{
  // <form id='f'></form><form><element form='f'></form>
  aForms[0].id = 'f';
  aForms[1].appendChild(aElements[0]);
  aElements[0].setAttribute('form', 'f');
  aElements[1].id = 'f';

  document.getElementById('content').removeChild(aForms[0]);

  return [[aForms[0], aForms[1]], [[],[]]];
}

/**
 * This function test that, when an element is a descendant of a form element
 * and has @form set to the empty string, it does not have a form owner.
 */
function test17(aForms, aElements)
{
  // <form><element form=''></form>
  aForms[0].appendChild(aElements[0]);
  aElements[0].setAttribute('form', '');

  return [[aForms[0]], [[]]];
}

/**
 * This function test that, when an element is a descendant of a form element
 * and has @form set to the empty string, it does not have a form owner even if
 * it's parent has its id equals to the empty string.
 */
function test18(aForms, aElements)
{
  // <form id=''><element form=''></form>
  aForms[0].id = '';
  aForms[0].appendChild(aElements[0]);
  aElements[0].setAttribute('form', '');

  return [[aForms[0]], [[]]];
}

/**
 * This function test that, when an element is a descendant of a form element
 * and has @form set to a valid form id and the element is being moving inside
 * it's parent, it's form owner will remain the form with the id.
 */
function test19(aForms, aElements)
{
  // <form id='f'></form><form><element form='f'><element></form>
  aForms[0].id = 'f';
  aForms[1].appendChild(aElements[0]);
  aForms[1].appendChild(aElements[1]);
  aElements[0].setAttribute('form', 'f');
  aForms[1].appendChild(aElements[0]);

  return [[aForms[0],aForms[1]],[[aElements[0]],[aElements[1]]]];
}

/**
 * This function test that, when an element is a descendant of a form element
 * and has @form set to a valid form id and the element is being moving inside
 * another form, it's form owner will remain the form with the id.
 */
function test20(aForms, aElements)
{
  // <form id='f'></form><form><element form='f'><element></form>
  aForms[0].id = 'f';
  aForms[1].appendChild(aElements[0]);
  aForms[1].appendChild(aElements[1]);
  aElements[0].setAttribute('form', 'f');
  aForms[2].appendChild(aElements[0]);

  return [[aForms[0],aForms[1],aForms[2]],[[aElements[0]],[aElements[1]],[]]];
}

/**
 * This function test that when removing a form, the elements with a @form set
 * will be correctly removed from there form owner.
 */
function test21(aForms, aElements)
{
  // <form id='f'><form><form><element form='f'></form>
  aForms[0].id = 'f';
  aForms[1].appendChild(aElements[0]);
  aElements[0].setAttribute('form', 'f');
  document.getElementById('content').removeChild(aForms[1]);

  return [[aForms[0]],[[]]];
}

var functions = [
  test0a, test0b,
  test1, test2, test3, test4, test5, test6, test7, test8, test9,
  test10, test11, test12, test13, test14, test15, test16, test17, test18, test19,
  test20, test21,
];

// Global variable to have an easy access to <div id='content'>.
var content = document.getElementById('content');

// Initializing the needed elements.
var forms = [
  document.createElement('form'),
  document.createElement('form'),
  document.createElement('form'),
];

var elementNames = [
  'button', 'fieldset', 'input', 'label', 'object', 'output', 'select',
  'textarea'
];

var todoElements = [
  ['keygen', 'Keygen'],
];

for (var e of todoElements) {
  var node = document.createElement(e[0]);
  var nodeString = HTMLElement.prototype.toString.apply(node);
  nodeString = nodeString.replace(/Element[\] ].*/, "Element");
  todo_is(nodeString, "[object HTML" + e[1] + "Element",
          e[0] + " should not be implemented");
}

for (var name of elementNames) {
  var elements = [
    document.createElement(name),
    document.createElement(name),
  ];

  for (var func of functions) {
    // Clean-up.
    while (content.firstChild) {
      content.firstChild.remove();
    }
    for (form of forms) {
      content.appendChild(form);
      form.removeAttribute('id');
    }
    for (e of elements) {
      content.appendChild(e);
      e.removeAttribute('form');
      is(e.form, null, "The element should not have a form owner");
    }

    // Calling the test.
    var results = func(forms, elements);

    // Checking the results.
    var formsList = results[0];
    for (var i=0; i<formsList.length; ++i) {
      var elementsList = results[1][i];
      if (name != 'label' && name != 'meter' && name != 'progress') {
        is(formsList[i].elements.length, elementsList.length,
           "The form should contain " + elementsList.length + " elements");
      }
      for (var j=0; j<elementsList.length; ++j) {
        if (name != 'label' && name != 'meter' && name != 'progress') {
          is(formsList[i].elements[j], elementsList[j],
             "The form should contain " + elementsList[j]);
        }
        if (name != 'label') {
          is(elementsList[j].form, formsList[i],
             "The form owner should be the form associated to the list");
        }
      }
    }
  }

  // Cleaning-up.
  for (e of elements) {
    e.remove();
    e = null;
  }
}

</script>
</pre>
</body>
</html>
