[@property] Set status to 'test' and move tests to WPT

Bug: 973830
Change-Id: I5d950496834ab17dc8615335c9c4ae25f2a4179b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2157528
Commit-Queue: Anders Hartvoll Ruud <andruud@chromium.org>
Reviewed-by: Ian Kilpatrick <ikilpatrick@chromium.org>
Cr-Commit-Position: refs/heads/master@{#761157}
diff --git a/css/css-properties-values-api/at-property-cssom.html b/css/css-properties-values-api/at-property-cssom.html
new file mode 100644
index 0000000..5a0ef9f
--- /dev/null
+++ b/css/css-properties-values-api/at-property-cssom.html
@@ -0,0 +1,187 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1/#cssom">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<style>
+  @property --valid {
+    syntax: "<color> | none";
+    inherits: false;
+    initial-value: red;
+  }
+  @property --valid-reverse {
+    initial-value: 0px;
+    inherits: true;
+    syntax: "<length>";
+  }
+  @property --valid-universal {
+    syntax: "*";
+    inherits: false;
+  }
+  @property --valid-whitespace {
+    syntax: " <color>+ ";
+    inherits: false;
+    initial-value: red, blue;
+  }
+  @property --vALId {
+    syntax: "<color> | none";
+    inherits: false;
+    initial-value: red;
+  }
+  @property --no-descriptors {
+
+  }
+  @property --no-syntax {
+    inherits: false;
+    initial-value: red;
+  }
+  @property --no-inherits {
+    syntax: "<color> | none";
+    initial-value: red;
+  }
+  @property --no-initial-value {
+    syntax: "<color> | none";
+    inherits: false;
+  }
+  @property --syntax-only {
+    syntax: "<color> | none";
+  }
+  @property --inherits-only {
+    inherits: true;
+  }
+  @property --initial-value-only {
+    initial-value: red;
+  }
+</style>
+<script>
+
+function find_at_property_rule(name) {
+  for (let rule of  document.styleSheets[0].cssRules) {
+    if (rule.type != CSSRule.PROPERTY_RULE)
+      continue;
+    if (rule.name == name)
+      return rule;
+  }
+  return null;
+}
+
+function test_css_text(name, expected) {
+  test(() => {
+    let rule = find_at_property_rule(name);
+    assert_true(!!rule);
+    assert_equals(rule.cssText, expected);
+  }, `Rule for ${name} has expected cssText`);
+}
+
+function test_name(name) {
+  test(() => {
+    let rule = find_at_property_rule(name);
+    assert_true(!!rule);
+    assert_equals(rule.name, name);
+  }, `Rule for ${name} returns expected value for CSSPropertyRule.name`);
+}
+
+function test_syntax(name, expected) {
+  test(() => {
+    let rule = find_at_property_rule(name);
+    assert_true(!!rule);
+    assert_equals(rule.syntax, expected);
+  }, `Rule for ${name} returns expected value for CSSPropertyRule.syntax`);
+}
+
+function test_inherits(name, expected) {
+  test(() => {
+    let rule = find_at_property_rule(name);
+    assert_true(!!rule);
+    assert_equals(rule.inherits, expected);
+  }, `Rule for ${name} returns expected value for CSSPropertyRule.inherits`);
+}
+
+function test_initial_value(name, expected) {
+  test(() => {
+    let rule = find_at_property_rule(name);
+    assert_true(!!rule);
+    assert_equals(rule.initialValue, expected);
+  }, `Rule for ${name} returns expected value for CSSPropertyRule.initialValue`);
+}
+
+// CSSPropertyRule.cssText
+
+test_css_text('--valid', '@property --valid { syntax: "<color> | none"; inherits: false; initial-value: red; }');
+test_css_text('--valid-reverse', '@property --valid-reverse { syntax: "<length>"; inherits: true; initial-value: 0px; }');
+test_css_text('--valid-universal', '@property --valid-universal { syntax: "*"; inherits: false; }');
+test_css_text('--valid-whitespace', '@property --valid-whitespace { syntax: " <color>+ "; inherits: false; initial-value: red, blue; }');
+test_css_text('--vALId', '@property --vALId { syntax: "<color> | none"; inherits: false; initial-value: red; }');
+
+test_css_text('--no-descriptors', '@property --no-descriptors { }');
+test_css_text('--no-syntax', '@property --no-syntax { inherits: false; initial-value: red; }');
+test_css_text('--no-inherits', '@property --no-inherits { syntax: "<color> | none"; initial-value: red; }');
+test_css_text('--no-initial-value', '@property --no-initial-value { syntax: "<color> | none"; inherits: false; }');
+test_css_text('--syntax-only', '@property --syntax-only { syntax: "<color> | none"; }');
+test_css_text('--inherits-only', '@property --inherits-only { inherits: true; }');
+test_css_text('--initial-value-only', '@property --initial-value-only { initial-value: red; }');
+
+// CSSPropertyRule.name
+
+test_name('--valid');
+test_name('--valid-reverse');
+test_name('--valid-universal');
+test_name('--valid-whitespace');
+test_name('--vALId');
+
+test_name('--no-descriptors');
+test_name('--no-syntax');
+test_name('--no-inherits');
+test_name('--no-initial-value');
+test_name('--syntax-only');
+test_name('--inherits-only');
+test_name('--initial-value-only');
+
+// CSSPropertyRule.syntax
+
+test_syntax('--valid', '<color> | none');
+test_syntax('--valid-reverse', '<length>');
+test_syntax('--valid-universal', '*');
+test_syntax('--valid-whitespace', ' <color>+ ');
+test_syntax('--vALId', '<color> | none');
+
+test_syntax('--no-descriptors', '');
+test_syntax('--no-syntax', '');
+test_syntax('--no-inherits', '<color> | none');
+test_syntax('--no-initial-value', '<color> | none');
+test_syntax('--syntax-only', '<color> | none');
+test_syntax('--inherits-only', '');
+test_syntax('--initial-value-only', '');
+
+// CSSPropertyRule.inherits
+
+test_inherits('--valid', false);
+test_inherits('--valid-reverse', true);
+test_inherits('--valid-universal', false);
+test_inherits('--valid-whitespace', false);
+test_inherits('--vALId', false);
+
+test_inherits('--no-descriptors', false);
+test_inherits('--no-syntax', false);
+test_inherits('--no-inherits', false);
+test_inherits('--no-initial-value', false);
+test_inherits('--syntax-only', false);
+test_inherits('--inherits-only', true);
+test_inherits('--initial-value-only', false);
+
+// CSSPropertyRule.initialValue
+
+test_initial_value('--valid', ' red');
+test_initial_value('--valid-reverse', ' 0px');
+test_initial_value('--valid-universal', null);
+test_initial_value('--valid-whitespace', ' red, blue');
+test_initial_value('--vALId', ' red');
+
+test_initial_value('--no-descriptors', null);
+test_initial_value('--no-syntax', ' red');
+test_initial_value('--no-inherits', ' red');
+test_initial_value('--no-initial-value', null);
+test_initial_value('--syntax-only', null);
+test_initial_value('--inherits-only', null);
+test_initial_value('--initial-value-only', ' red');
+
+</script>
diff --git a/css/css-properties-values-api/at-property.html b/css/css-properties-values-api/at-property.html
new file mode 100644
index 0000000..cf4cee0
--- /dev/null
+++ b/css/css-properties-values-api/at-property.html
@@ -0,0 +1,232 @@
+<!DOCTYPE html>
+<link rel="help" href="https://drafts.css-houdini.org/css-properties-values-api-1/#at-property-rule">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="outer">
+  <div id="target"></div>
+</div>
+<script>
+
+let g_id = 0;
+
+function generate_name() {
+  g_id++;
+  return `--property-${g_id}`;
+}
+
+function with_style_node(text, fn) {
+  let node = document.createElement('style');
+  node.textContent = text;
+  try {
+    document.body.append(node);
+    fn(node);
+  } finally {
+    node.remove();
+  }
+}
+
+function with_at_rule(desc, fn) {
+  let name = typeof(desc.name) === 'undefined' ? generate_name() : desc.name;
+  let text = `@property ${name} {`;
+  if (typeof(desc.syntax) !== 'undefined')
+    text += `syntax:${desc.syntax};`;
+  if (typeof(desc.initialValue) !== 'undefined')
+    text += `initial-value:${desc.initialValue};`;
+  if (typeof(desc.inherits) !== 'undefined')
+    text += `inherits:${desc.inherits};`;
+  text += '}';
+  with_style_node(text, (node) => fn(name, node.sheet.rules[0]));
+}
+
+function test_with_at_rule(desc, fn, description) {
+  test(() => with_at_rule(desc, fn), description);
+}
+
+function test_with_style_node(text, fn, description) {
+  test(() => with_style_node(text, fn), description);
+}
+
+// Parsing:
+
+let uppercase_first = (x) => x.charAt(0).toUpperCase() + x.slice(1);
+let to_camel_case = (x) => x.split('-')[0] + x.split('-').slice(1).map(uppercase_first).join('');
+
+function get_cssom_descriptor_value(rule, descriptor) {
+  switch (descriptor) {
+    case 'syntax':
+      return rule.syntax;
+    case 'inherits':
+      return rule.inherits;
+    case 'initial-value':
+      return rule.initialValue;
+    default:
+      assert_true(false, 'Should not reach here');
+      return null;
+  }
+}
+
+// Test that for the given descriptor (e.g. 'syntax'), the specified value
+// will yield the expected_value when observed using CSSOM. If the expected_value
+// is omitted, it is the same as the specified value.
+function test_descriptor(descriptor, specified_value, expected_value) {
+  let camel = to_camel_case(descriptor);
+  if (typeof(expected_value) === 'undefined')
+    expected_value = specified_value;
+  test_with_at_rule({ [camel]: specified_value }, (name, rule) => {
+    assert_equals(get_cssom_descriptor_value(rule, descriptor), expected_value);
+  }, `Attribute '${descriptor}' returns expected value for [${specified_value}]`);
+}
+
+// syntax
+test_descriptor('syntax', '"<color>"', '<color>');
+test_descriptor('syntax', '"<color> | none"', '<color> | none');
+test_descriptor('syntax', '"<color># | <image> | none"', '<color># | <image> | none');
+test_descriptor('syntax', '"foo | bar | baz"', 'foo | bar | baz');
+test_descriptor('syntax', '"*"', '*');
+test_descriptor('syntax', '"notasyntax"', 'notasyntax');
+
+test_descriptor('syntax', 'red', '');
+test_descriptor('syntax', 'rgb(255, 0, 0)', '');
+test_descriptor('syntax', '<color>', '');
+test_descriptor('syntax', 'foo | bar', '');
+
+// initial-value
+test_descriptor('initial-value', '10px');
+test_descriptor('initial-value', 'rgb(1, 2, 3)');
+test_descriptor('initial-value', 'red');
+test_descriptor('initial-value', 'foo');
+test_descriptor('initial-value', 'if(){}');
+test_descriptor('initial-value', 'var(--x)');
+
+// inherits
+test_descriptor('inherits', 'true', true);
+test_descriptor('inherits', 'false', false);
+
+test_descriptor('inherits', 'none', false);
+test_descriptor('inherits', '0', false);
+test_descriptor('inherits', '1', false);
+test_descriptor('inherits', '"true"', false);
+test_descriptor('inherits', '"false"', false);
+test_descriptor('inherits', 'calc(0)', false);
+
+test_with_style_node('@property foo { }', (node) => {
+  assert_equals(node.sheet.rules.length, 0);
+}, 'Invalid property name does not parse [foo]');
+
+test_with_style_node('@property -foo { }', (node) => {
+  assert_equals(node.sheet.rules.length, 0);
+}, 'Invalid property name does not parse [-foo]');
+
+// Applying @property rules
+
+function test_applied(syntax, initial, inherits, expected) {
+  test_with_at_rule({
+    syntax: `"${syntax}"`,
+    initialValue: initial,
+    inherits: inherits
+  }, (name, rule) => {
+    let actual = getComputedStyle(target).getPropertyValue(name);
+    assert_equals(actual, expected);
+  }, `Rule applied [${syntax}, ${initial}, ${inherits}]`);
+}
+
+function test_not_applied(syntax, initial, inherits) {
+  test_with_at_rule({
+    syntax: `"${syntax}"`,
+    initialValue: initial,
+    inherits: inherits
+  }, (name, rule) => {
+    let actual = getComputedStyle(target).getPropertyValue(name);
+    assert_equals(actual, '');
+  }, `Rule not applied [${syntax}, ${initial}, ${inherits}]`);
+}
+
+// syntax, initialValue, inherits, expected
+test_applied('*', 'if(){}', false, 'if(){}');
+test_applied('<angle>', '42deg', false, '42deg');
+test_applied('<angle>', '1turn', false, '360deg');
+test_applied('<color>', 'green', false, 'rgb(0, 128, 0)');
+test_applied('<color>', 'rgb(1, 2, 3)', false, 'rgb(1, 2, 3)');
+test_applied('<image>', 'url("http://a/")', false, 'url("http://a/")');
+test_applied('<integer>', '5', false, '5');
+test_applied('<length-percentage>', '10px', false, '10px');
+test_applied('<length-percentage>', '10%', false, '10%');
+test_applied('<length-percentage>', 'calc(10% + 10px)', false, 'calc(10% + 10px)');
+test_applied('<length>', '10px', false, '10px');
+test_applied('<number>', '2.5', false, '2.5');
+test_applied('<percentage>', '10%', false, '10%');
+test_applied('<resolution>', '50dppx', false, '50dppx');
+test_applied('<resolution>', '96dpi', false, '1dppx');
+test_applied('<time>', '10s', false, '10s');
+test_applied('<time>', '1000ms', false, '1s');
+test_applied('<transform-function>', 'rotateX(0deg)', false, 'rotateX(0deg)');
+test_applied('<transform-list>', 'rotateX(0deg)', false, 'rotateX(0deg)');
+test_applied('<transform-list>', 'rotateX(0deg) translateX(10px)', false, 'rotateX(0deg) translateX(10px)');
+test_applied('<url>', 'url("http://a/")', false, 'url("http://a/")');
+
+// inherits: true/false
+test_applied('<color>', 'tomato', false, 'rgb(255, 99, 71)');
+test_applied('<color>', 'tomato', true, 'rgb(255, 99, 71)');
+
+test_with_at_rule({ syntax: '"*"', inherits: true }, (name, rule) => {
+  try {
+    outer.style.setProperty(name, 'foo');
+    let actual = getComputedStyle(target).getPropertyValue(name);
+    assert_equals(actual, 'foo');
+  } finally {
+    outer.style = '';
+  }
+}, 'Rule applied for "*", even with no initial value');
+
+test_not_applied(undefined, 'green', false);
+test_not_applied('<color>', undefined, false);
+test_not_applied('<color>', 'green', undefined);
+test_not_applied('<gandalf>', 'grey', false);
+test_not_applied('gandalf', 'grey', false);
+test_not_applied('<color>', 'notacolor', false);
+test_not_applied('<length>', '10em', false);
+
+// Inheritance
+
+test_with_at_rule({
+  syntax: '"<length>"',
+  inherits: false,
+  initialValue: '0px'
+}, (name, rule) => {
+  try {
+    outer.style = `${name}: 40px`;
+    assert_equals(getComputedStyle(outer).getPropertyValue(name), '40px');
+    assert_equals(getComputedStyle(target).getPropertyValue(name), '0px');
+  } finally {
+    outer.style = '';
+  }
+}, 'Non-inherited properties do not inherit');
+
+test_with_at_rule({
+  syntax: '"<length>"',
+  inherits: true,
+  initialValue: '0px'
+}, (name, rule) => {
+  try {
+    outer.style = `${name}: 40px`;
+    assert_equals(getComputedStyle(outer).getPropertyValue(name), '40px');
+    assert_equals(getComputedStyle(target).getPropertyValue(name), '40px');
+  } finally {
+    outer.style = '';
+  }
+}, 'Inherited properties inherit');
+
+test_with_at_rule({
+  syntax: '"<color>"',
+  inherits: true,
+  initialValue: 'green'
+}, (name, rule) => {
+  try {
+    target.style = `--x:var(${name})`;
+    assert_equals(getComputedStyle(target).getPropertyValue(name), 'rgb(0, 128, 0)');
+  } finally {
+    target.style = '';
+  }
+}, 'Initial values substituted as computed value');
+
+</script>