| <!DOCTYPE html> |
| <title>CSS Values and Units Test: random() in @function</title> |
| <link rel="help" href="https://drafts.csswg.org/css-values-5/#random"> |
| <script src="/resources/testharness.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="../support/computed-testcommon.js"></script> |
| <div id=container> |
| <div id=target></div> |
| </div> |
| <style> |
| @property --number { |
| syntax: "<number>"; |
| inherits: true; |
| initial-value: 0; |
| } |
| @property --number-2 { |
| syntax: "<number>"; |
| inherits: true; |
| initial-value: 0; |
| } |
| @property --numbers { |
| syntax: "<number>+"; |
| inherits: true; |
| initial-value: 0; |
| } |
| </style> |
| <style id="function-holder"></style> |
| <script> |
| // Since actual and expected values are generated randomly, `assert_equals()` |
| // does not generate deterministic test failure output. Chrome relies on test |
| // failure output to be deterministic and stable for failing test expectations. |
| function test_random_equals(v1, v2, message = "Random values should be equal") { |
| assert_true(v1 == v2, message); |
| } |
| function test_random_not_equals(v1, v2, message = "Random values should not be equal") { |
| assert_false(v1 == v2, message); |
| } |
| function test_value_in_range(value, min=1, max=1e9) { |
| assert_false(Number.isNaN(Number(value)), "Value should be a number."); |
| assert_true(value >= min); |
| assert_true(value <= max); |
| } |
| |
| |
| // Let each set of tests set up unique functions, |
| // without having to manually uniquify the names. |
| function setup_functions(s) { |
| document.querySelector("#function-holder").textContent = s; |
| } |
| |
| // Helper functions to obtain random values in various combinations. |
| |
| // Diff element, same property, same index |
| function diff_elements(v1, v2) { |
| const holder = document.createElement('div'); |
| document.body.appendChild(holder); |
| let el1ComputedValue, el2ComputedValue; |
| try { |
| const el1 = document.createElement('div'); |
| el1.style.setProperty('--number', v1.trim()); |
| holder.appendChild(el1); |
| |
| const el2 = document.createElement('div'); |
| el2.style.setProperty('--number', v2.trim()); |
| holder.appendChild(el2); |
| |
| el1ComputedValue = getComputedStyle(el1).getPropertyValue('--number'); |
| el2ComputedValue = getComputedStyle(el2).getPropertyValue('--number'); |
| |
| test_value_in_range(el1ComputedValue); |
| test_value_in_range(el2ComputedValue); |
| } finally { |
| document.body.removeChild(holder); |
| } |
| return [el1ComputedValue, el2ComputedValue]; |
| } |
| |
| // Same element, diff property, same index |
| function diff_properties(v1, v2) { |
| const holder = document.createElement('div'); |
| document.body.appendChild(holder); |
| let elComputedValue1, elComputedValue2; |
| try { |
| const el1 = document.createElement('div'); |
| el1.style.setProperty('--number', v1.trim()); |
| el1.style.setProperty('--number-2', v2.trim()); |
| holder.appendChild(el1); |
| |
| elComputedValue1 = getComputedStyle(el1).getPropertyValue('--number'); |
| elComputedValue2 = getComputedStyle(el1).getPropertyValue('--number-2'); |
| |
| test_value_in_range(elComputedValue1); |
| test_value_in_range(elComputedValue2); |
| } finally { |
| document.body.removeChild(holder); |
| } |
| return [elComputedValue1, elComputedValue2]; |
| } |
| |
| // Same element, same property, diff index |
| function diff_indexes(v1, v2) { |
| const holder = document.createElement('div'); |
| document.body.appendChild(holder); |
| let elComputedValue1, elComputedValue2; |
| try { |
| const el1 = document.createElement('div'); |
| el1.style.setProperty('--numbers', v1.trim() + " " + v2.trim()); |
| holder.appendChild(el1); |
| [elComputedValue1, elComputedValue2] = getComputedStyle(el1).getPropertyValue('--numbers').split(' '); |
| test_value_in_range(elComputedValue1); |
| test_value_in_range(elComputedValue2); |
| } finally { |
| document.body.removeChild(holder); |
| } |
| return [elComputedValue1, elComputedValue2]; |
| } |
| |
| // Same as diff_indexes except both numbers come from a single value |
| function multi_values(v1) { |
| const holder = document.createElement('div'); |
| document.body.appendChild(holder); |
| let elComputedValue1, elComputedValue2; |
| try { |
| const el1 = document.createElement('div'); |
| el1.style.setProperty('--numbers', v1.trim()); |
| holder.appendChild(el1); |
| [elComputedValue1, elComputedValue2] = getComputedStyle(el1).getPropertyValue('--numbers').split(' '); |
| test_value_in_range(elComputedValue1); |
| test_value_in_range(elComputedValue2); |
| } finally { |
| document.body.removeChild(holder); |
| } |
| return [elComputedValue1, elComputedValue2]; |
| } |
| |
| |
| |
| |
| // Untyped 'result' leaves random() unparsed. |
| // It'll assign its ua-random-ident post-substitution |
| setup_functions(` |
| @function --f() { |
| result: random(property-index-scoped, 1, 1e9); |
| } |
| @function --g() { |
| result: random(property-index-scoped, 1, 1e9); |
| } |
| `); |
| test(() => { |
| const [v1, v2] = diff_elements("--f()", "--f()"); |
| test_random_equals(v1, v2); |
| }, `random(p-i-s) in untyped result, same function on different elements`); |
| test(() => { |
| const [v1, v2] = diff_properties("--f()", "--f()"); |
| test_random_not_equals(v1, v2); |
| }, `random(p-i-s) in untyped result, same function in different properties`); |
| test(() => { |
| const [v1, v2] = diff_indexes("--f()", "--f()"); |
| test_random_not_equals(v1, v2); |
| }, `random(p-i-s) in untyped result, same function at different indexes`); |
| test(() => { |
| const [v1, v2] = diff_elements("--f()", "--g()"); |
| test_random_equals(v1, v2); |
| }, `random(p-i-s) in untyped result, different functions on different elements`); |
| test(() => { |
| const [v1, v2] = diff_properties("--f()", "--g()"); |
| test_random_not_equals(v1, v2); |
| }, `random(p-i-s) in untyped result, different functions in different properties`); |
| test(() => { |
| const [v1, v2] = diff_indexes("--f()", "--g()"); |
| test_random_not_equals(v1, v2); |
| }, `random(p-i-s) in untyped result, different functions at different indexes`); |
| |
| |
| |
| |
| // Typed result will parse the random() inside the function. |
| // ua-random-ident will use function name and 'result' |
| setup_functions(` |
| @function --f() returns <number> { |
| result: random(property-index-scoped, 1, 1e9); |
| } |
| @function --g() returns <number> { |
| result: random(property-index-scoped, 1, 1e9); |
| } |
| `); |
| test(() => { |
| const [v1, v2] = diff_elements("--f()", "--f()"); |
| test_random_equals(v1, v2); |
| }, `random(p-i-s) in typed result, same function on different elements`); |
| test(() => { |
| const [v1, v2] = diff_properties("--f()", "--f()"); |
| test_random_equals(v1, v2); |
| }, `random(p-i-s) in typed result, same function in different properties`); |
| test(() => { |
| const [v1, v2] = diff_indexes("--f()", "--f()"); |
| test_random_equals(v1, v2); |
| }, `random(p-i-s) in typed result, same function at different indexes`); |
| test(() => { |
| const [v1, v2] = diff_elements("--f()", "--g()"); |
| test_random_not_equals(v1, v2); |
| }, `random(p-i-s) in typed result, different function on different elements`); |
| test(() => { |
| const [v1, v2] = diff_properties("--f()", "--g()"); |
| test_random_not_equals(v1, v2); |
| }, `random(p-i-s) in typed result, different function in different properties`); |
| test(() => { |
| const [v1, v2] = diff_indexes("--f()", "--g()"); |
| test_random_not_equals(v1, v2); |
| }, `random(p-i-s) in typed result, different function at different indexes`); |
| |
| |
| |
| |
| // Untyped element-scoped will escape the function before resolving. |
| // Will vary based on element it's applied to, only |
| setup_functions(` |
| @function --f() { |
| result: random(element-scoped, 1, 1e9); |
| } |
| @function --g() { |
| result: random(element-scoped, 1, 1e9); |
| } |
| `); |
| test(() => { |
| const [v1, v2] = diff_elements("--f()", "--f()"); |
| test_random_not_equals(v1, v2); |
| }, `random(e-s) in untyped result, same function on different elements`); |
| test(() => { |
| const [v1, v2] = diff_properties("--f()", "--f()"); |
| test_random_equals(v1, v2); |
| }, `random(e-s) in untyped result, same function in different properties`); |
| test(() => { |
| const [v1, v2] = diff_indexes("--f()", "--f()"); |
| test_random_equals(v1, v2); |
| }, `random(e-s) in untyped result, same function at different indexes`); |
| test(() => { |
| const [v1, v2] = diff_elements("--f()", "--g()"); |
| test_random_not_equals(v1, v2); |
| }, `random(e-s) in untyped result, different functions on different elements`); |
| test(() => { |
| const [v1, v2] = diff_properties("--f()", "--g()"); |
| test_random_equals(v1, v2); |
| }, `random(e-s) in untyped result, different functions in different properties`); |
| test(() => { |
| const [v1, v2] = diff_indexes("--f()", "--g()"); |
| test_random_equals(v1, v2); |
| }, `random(e-s) in untyped result, different functions at different indexes`); |
| |
| |
| |
| |
| // element-scoped inside of function refers to the hypothetical element |
| // each invocation is thus distinct automatically |
| setup_functions(` |
| @function --f() returns <number> { |
| result: random(element-scoped, 1, 1e9); |
| } |
| @function --g() returns <number> { |
| result: random(element-scoped, 1, 1e9); |
| } |
| `); |
| test(() => { |
| const [v1, v2] = diff_elements("--f()", "--f()"); |
| test_random_not_equals(v1, v2); |
| }, `random(e-s) in typed result, same function on different elements`); |
| test(() => { |
| const [v1, v2] = diff_properties("--f()", "--f()"); |
| test_random_not_equals(v1, v2); |
| }, `random(e-s) in typed result, same function in different properties`); |
| test(() => { |
| const [v1, v2] = diff_indexes("--f()", "--f()"); |
| test_random_not_equals(v1, v2); |
| }, `random(e-s) in typed result, same function at different indexes`); |
| test(() => { |
| const [v1, v2] = diff_elements("--f()", "--g()"); |
| test_random_not_equals(v1, v2); |
| }, `random(e-s) in typed result, different functions on different elements`); |
| test(() => { |
| const [v1, v2] = diff_properties("--f()", "--g()"); |
| test_random_not_equals(v1, v2); |
| }, `random(e-s) in typed result, different functions in different properties`); |
| test(() => { |
| const [v1, v2] = diff_indexes("--f()", "--g()"); |
| test_random_not_equals(v1, v2); |
| }, `random(e-s) in typed result, different functions at different indexes`); |
| |
| |
| |
| // Untyped local is same as untyped result |
| setup_functions(` |
| @function --f() { |
| --x: random(property-index-scoped, 1, 1e9); |
| result: var(--x); |
| } |
| @function --g() { |
| --x: random(property-index-scoped, 1, 1e9); |
| result: var(--x); |
| } |
| `); |
| test(() => { |
| const [v1, v2] = diff_elements("--f()", "--f()"); |
| test_random_equals(v1, v2); |
| }, `random(p-i-s) in untyped local, same function on different elements`); |
| test(() => { |
| const [v1, v2] = diff_properties("--f()", "--f()"); |
| test_random_not_equals(v1, v2); |
| }, `random(p-i-s) in untyped local, same function in different properties`); |
| test(() => { |
| const [v1, v2] = diff_indexes("--f()", "--f()"); |
| test_random_not_equals(v1, v2); |
| }, `random(p-i-s) in untyped local, same function at different indexes`); |
| test(() => { |
| const [v1, v2] = diff_elements("--f()", "--g()"); |
| test_random_equals(v1, v2); |
| }, `random(p-i-s) in untyped local, different functions on different elements`); |
| test(() => { |
| const [v1, v2] = diff_properties("--f()", "--g()"); |
| test_random_not_equals(v1, v2); |
| }, `random(p-i-s) in untyped local, different functions in different properties`); |
| test(() => { |
| const [v1, v2] = diff_indexes("--f()", "--g()"); |
| test_random_not_equals(v1, v2); |
| }, `random(p-i-s) in untyped local, different functions at different indexes`); |
| |
| |
| |
| // Random set on untyped local, but substituted into typed result. |
| // Same as setting directly in typed result. |
| setup_functions(` |
| @function --f() returns <number> { |
| --x: random(property-index-scoped, 1, 1e9); |
| result: var(--x); |
| } |
| @function --g() returns <number> { |
| --x: random(property-index-scoped, 1, 1e9); |
| result: var(--x); |
| } |
| `); |
| test(() => { |
| const [v1, v2] = diff_elements("--f()", "--f()"); |
| test_random_equals(v1, v2); |
| }, `random(p-i-s) substituted into typed result, same function on different elements`); |
| test(() => { |
| const [v1, v2] = diff_properties("--f()", "--f()"); |
| test_random_equals(v1, v2); |
| }, `random(p-i-s) substituted into typed result, same function in different properties`); |
| test(() => { |
| const [v1, v2] = diff_indexes("--f()", "--f()"); |
| test_random_equals(v1, v2); |
| }, `random(p-i-s) substituted into typed result, same function at different indexes`); |
| test(() => { |
| const [v1, v2] = diff_elements("--f()", "--g()"); |
| test_random_not_equals(v1, v2); |
| }, `random(p-i-s) substituted into typed result, different function on different elements`); |
| test(() => { |
| const [v1, v2] = diff_properties("--f()", "--g()"); |
| test_random_not_equals(v1, v2); |
| }, `random(p-i-s) substituted into typed result, different function in different properties`); |
| test(() => { |
| const [v1, v2] = diff_indexes("--f()", "--g()"); |
| test_random_not_equals(v1, v2); |
| }, `random(p-i-s) substituted into typed result, different function at different indexes`); |
| |
| |
| |
| // Randoms set in multiple untyped locals, substituted into an untyped result |
| // Don't evaluate until they hit the actual element |
| setup_functions(` |
| @function --f() { |
| --x: random(property-index-scoped, 1, 1e9); |
| --y: random(property-index-scoped, 1, 1e9); |
| result: var(--x) var(--y); |
| } |
| `); |
| test(() => { |
| const [v1, v2] = multi_values("--f()"); |
| test_random_not_equals(v1, v2); |
| }, `random(p-i-s) in multiple untyped locals, substituted into untyped result`); |
| |
| |
| |
| // Randoms set in multiple untyped locals, substituted into an untyped result |
| // Don't evaluate until they hit the actual element |
| setup_functions(` |
| @function --f() { |
| --x: random(property-scoped, 1, 1e9); |
| --y: random(property-scoped, 1, 1e9); |
| result: var(--x) var(--y); |
| } |
| `); |
| test(() => { |
| const [v1, v2] = multi_values("--f()"); |
| test_random_equals(v1, v2); |
| }, `random(p-s) in multiple untyped locals, substituted into untyped result`); |
| |
| |
| |
| // Random set in untyped local, substituted into typed result |
| // Evaluate against function name and 'result' |
| setup_functions(` |
| @function --f() returns <number>+ { |
| --x: random(property-index-scoped, 1, 1e9); |
| result: var(--x) var(--x); |
| } |
| `); |
| test(() => { |
| const [v1, v2] = multi_values("--f()"); |
| test_random_not_equals(v1, v2); |
| }, `random(p-i-s) in untyped local, substituted multiple times into typed result`); |
| |
| |
| |
| // Random set in untyped local, substituted into typed result |
| // Evaluate against function name and 'result' |
| setup_functions(` |
| @function --f() returns <number>+ { |
| --x: random(property-scoped, 1, 1e9); |
| result: var(--x) var(--x); |
| } |
| `); |
| test(() => { |
| const [v1, v2] = multi_values("--f()"); |
| test_random_equals(v1, v2); |
| }, `random(p-s) in untyped local, substituted multiple times into typed result`); |
| |
| |
| |
| // Random in typed argument default |
| // Evaluate against function name + arg name |
| // Essentially same as typed result. |
| setup_functions(` |
| @function --f(--x <number>: random(property-index-scoped, 1, 1e9)) { |
| result: var(--x); |
| } |
| @function --g(--y <number>: random(property-index-scoped, 1, 1e9)) { |
| result: var(--y); |
| } |
| `); |
| test(() => { |
| const [v1, v2] = diff_elements("--f()", "--f()"); |
| test_random_equals(v1, v2); |
| }, `random(p-i-s) in typed arg default, same function on different elements`); |
| test(() => { |
| const [v1, v2] = diff_properties("--f()", "--f()"); |
| test_random_equals(v1, v2); |
| }, `random(p-i-s) in typed arg default, same function in different properties`); |
| test(() => { |
| const [v1, v2] = diff_indexes("--f()", "--f()"); |
| test_random_equals(v1, v2); |
| }, `random(p-i-s) in typed arg default, same function at different indexes`); |
| test(() => { |
| const [v1, v2] = diff_elements("--f()", "--g()"); |
| test_random_not_equals(v1, v2); |
| }, `random(p-i-s) in typed arg default, different function on different elements`); |
| test(() => { |
| const [v1, v2] = diff_properties("--f()", "--g()"); |
| test_random_not_equals(v1, v2); |
| }, `random(p-i-s) in typed arg default, different function in different properties`); |
| test(() => { |
| const [v1, v2] = diff_indexes("--f()", "--g()"); |
| test_random_not_equals(v1, v2); |
| }, `random(p-i-s) in typed arg default, different function at different indexes`); |
| |
| |
| |
| // Random set in several typed argument defaults, substituted into untyped result |
| // Evaluate against function name and each arg name |
| setup_functions(` |
| @function --f( |
| --x <number>: random(property-scoped, 1, 1e9), |
| --y <number>: random(property-scoped, 1, 1e9) |
| ) { |
| result: var(--x) var(--y); |
| } |
| `); |
| test(() => { |
| const [v1, v2] = multi_values("--f()"); |
| test_random_not_equals(v1, v2); |
| }, `random(p-s) in typed arg defaults, substituted into untyped result`); |
| |
| |
| |
| // Random set in several untyped argument defaults, substituted into typed result |
| // Evaluate against function name and each arg name |
| setup_functions(` |
| @function --f( |
| --x: random(property-scoped, 1, 1e9), |
| --y: random(property-scoped, 1, 1e9) |
| ) returns <number>+ { |
| result: var(--x) var(--y); |
| } |
| `); |
| test(() => { |
| const [v1, v2] = multi_values("--f()"); |
| test_random_equals(v1, v2); |
| }, `random(p-s) in untyped arg defaults, substituted into typed result`); |
| |
| |
| |
| // Element-scoped set in typed arg, substituted into untyped result |
| // Different per invocation |
| setup_functions(` |
| @function --f(--x <number>: random(element-scoped, 1, 1e9)) { |
| result: var(--x); |
| } |
| `); |
| test(() => { |
| const [v1, v2] = diff_elements("--f()", "--f()"); |
| test_random_not_equals(v1, v2); |
| }, `random(e-s) in typed arg defaults, same function on different elements`); |
| test(() => { |
| const [v1, v2] = diff_properties("--f()", "--f()"); |
| test_random_not_equals(v1, v2); |
| }, `random(e-s) in typed arg defaults, same function in different properties`); |
| test(() => { |
| const [v1, v2] = diff_indexes("--f()", "--f()"); |
| test_random_not_equals(v1, v2); |
| }, `random(e-s) in typed arg defaults, same function at different indexes`); |
| |
| |
| |
| // Element-scoped set in untyped arg, substituted into untyped result |
| // Doesn't resolve until it hits the element's styles |
| setup_functions(` |
| @function --f(--x: random(element-scoped, 1, 1e9)) { |
| result: var(--x); |
| } |
| `); |
| test(() => { |
| const [v1, v2] = diff_elements("--f()", "--f()"); |
| test_random_not_equals(v1, v2); |
| }, `random(e-s) in untyped arg defaults, same function on different elements`); |
| test(() => { |
| const [v1, v2] = diff_properties("--f()", "--f()"); |
| test_random_equals(v1, v2); |
| }, `random(e-s) in untyped arg defaults, same function in different properties`); |
| test(() => { |
| const [v1, v2] = diff_indexes("--f()", "--f()"); |
| test_random_equals(v1, v2); |
| }, `random(e-s) in untyped arg defaults, same function at different indexes`); |
| |
| |
| |
| // Typed arg, random set in the body. |
| // Should be identical to setting in the typed arg defaults. |
| setup_functions(` |
| @function --f(--x <number>) { |
| --x: random(property-index-scoped, 1, 1e9); |
| result: var(--x); |
| } |
| @function --g(--x <number>) { |
| --x: random(property-index-scoped, 1, 1e9); |
| result: var(--x); |
| } |
| `); |
| test(() => { |
| const [v1, v2] = diff_elements("--f(0)", "--f(0)"); |
| test_random_equals(v1, v2); |
| }, `random(p-i-s) in typed arg and set in body, same function on different elements`); |
| test(() => { |
| const [v1, v2] = diff_properties("--f(0)", "--f(0)"); |
| test_random_equals(v1, v2); |
| }, `random(p-i-s) in typed arg and set in body, same function in different properties`); |
| test(() => { |
| const [v1, v2] = diff_indexes("--f(0)", "--f(0)"); |
| test_random_equals(v1, v2); |
| }, `random(p-i-s) in typed arg and set in body, same function at different indexes`); |
| test(() => { |
| const [v1, v2] = diff_elements("--f(0)", "--g(0)"); |
| test_random_not_equals(v1, v2); |
| }, `random(p-i-s) in typed arg and set in body, different function on different elements`); |
| test(() => { |
| const [v1, v2] = diff_properties("--f(0)", "--g(0)"); |
| test_random_not_equals(v1, v2); |
| }, `random(p-i-s) in typed arg and set in body, different function in different properties`); |
| test(() => { |
| const [v1, v2] = diff_indexes("--f(0)", "--g(0)"); |
| test_random_not_equals(v1, v2); |
| }, `random(p-i-s) in typed arg and set in body, different function at different indexes`); |
| |
| |
| |
| // Typed arg, element-scoped random set in the body. |
| // Again, should be identical to setting in the typed arg defaults. |
| setup_functions(` |
| @function --f(--x <number>) { |
| --x: random(element-scoped, 1, 1e9); |
| result: var(--x); |
| } |
| `); |
| test(() => { |
| const [v1, v2] = diff_elements("--f(0)", "--f(0)"); |
| test_random_not_equals(v1, v2); |
| }, `random(e-s) in typed arg and set in body, same function on different elements`); |
| test(() => { |
| const [v1, v2] = diff_properties("--f(0)", "--f(0)"); |
| test_random_not_equals(v1, v2); |
| }, `random(e-s) in typed arg and set in body, same function in different properties`); |
| test(() => { |
| const [v1, v2] = diff_indexes("--f(0)", "--f(0)"); |
| test_random_not_equals(v1, v2); |
| }, `random(e-s) in typed arg and set in body, same function at different indexes`); |
| </script> |