Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

<!DOCTYPE html>
<title>CSS Values and Units Test: random() in @function</title>
<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>