chromium/third_party/blink/web_tests/svg/animations/resources/SVGAnimationTestCase.js

// Inspired by Layoutests/animations/animation-test-helpers.js

function isCloseEnough(actual, desired, tolerance) {
    var diff = Math.abs(actual - desired);
    return diff <= tolerance;
}

function shouldBeCloseEnough(_a, _b, tolerance) {
    if (typeof tolerance != "number")
      tolerance = 0.1 // Default
    if (typeof _a != "string" || typeof _b != "string")
        debug("WARN: shouldBeCloseEnough() expects two string and one number arguments");
    var exception;
    var _av;
    try {
        _av = eval(_a);
    } catch (e) {
        exception = e;
    }
    var _bv = eval(_b);
    
    if (exception)
        testFailed(_a + " should be " + _bv + ". Threw exception " + exception);
    else if (isCloseEnough(_av, _bv, tolerance))
        testPassed(_a + " is " + _b);
    else if (typeof(_av) == typeof(_bv))
        testFailed(_a + " should be close to " + _bv + ". Was " + stringify(_av) + ".");
    else
        testFailed(_a + " should be close to " + _bv + " (of type " + typeof _bv + "). Was " + _av + " (of type " + typeof _av + ").");
}

function expectMatrix(actualMatrix, expectedA, expectedB, expectedC, expectedD, expectedE, expectedF, tolerance) {
    shouldBeCloseEnough(actualMatrix + ".a", expectedA, tolerance);
    shouldBeCloseEnough(actualMatrix + ".b", expectedB, tolerance);
    shouldBeCloseEnough(actualMatrix + ".c", expectedC, tolerance);
    shouldBeCloseEnough(actualMatrix + ".d", expectedD, tolerance);
    shouldBeCloseEnough(actualMatrix + ".e", expectedE, tolerance);
    shouldBeCloseEnough(actualMatrix + ".f", expectedF, tolerance);
}

function expectTranslationMatrix(actualMatrix, expectedE, expectedF, tolerance) {
    shouldBeCloseEnough(actualMatrix + ".e", expectedE, tolerance);
    shouldBeCloseEnough(actualMatrix + ".f", expectedF, tolerance);
}

function getTransformToElement(rootElement, element) {
    return element.getCTM().inverse().multiply(rootElement.getCTM());
}

function expectColor(element, red, green, blue, property) {
    if (typeof property != "string")
        color = getComputedStyle(element).getPropertyValue("color");
    else
        color = getComputedStyle(element).getPropertyValue(property);

    var re = new RegExp("rgba?\\(([^, ]*), ([^, ]*), ([^, ]*)(?:, )?([^, ]*)\\)");
    colorComponents = re.exec(color);

    // Allow a tolerance of 1 for color values, as they are integers.
    shouldBeCloseEnough("colorComponents[1]", "" + red, 1);
    shouldBeCloseEnough("colorComponents[2]", "" + green, 1);
    shouldBeCloseEnough("colorComponents[3]", "" + blue, 1);
}

function expectFillColor(element, red, green, blue) {
    expectColor(element, red, green, blue, "fill");
}

function moveAnimationTimelineAndSample(index) {
    var animationId = expectedResults[index][0];
    var time = expectedResults[index][1];
    var sampleCallback = expectedResults[index][2];
    var animation = rootSVGElement.ownerDocument.getElementById(animationId);

    // If we want to sample the animation end, add a small delta, to reliable point past the end of the animation.
    newTime = time;

    try {
        newTime += animation.getStartTime();
    } catch(e) {
        // No current interval.
    }

    // The sample time is relative to the start time of the animation, take that into account.
    rootSVGElement.setCurrentTime(newTime);
    sampleCallback();
}

var currentTest = 0;
var expectedResults;

function sampleAnimation() {
    if (currentTest == expectedResults.length) {
        completeTest();
        return;
    }

    moveAnimationTimelineAndSample(currentTest);
    ++currentTest;

    setTimeout(sampleAnimation, 0);
}

function runSMILTest() {
    // Pause animations, we'll drive them manually.
    // This also ensures that the timeline is paused before it starts. This should make the instance time of the below
    // 'click' (for instance) 0, and hence minimize rounding errors for the addition in moveAnimationTimelineAndSample.
    rootSVGElement.pauseAnimations();

    // If eg. an animation is running with begin="0s", and we want to sample the first time, before the animation
    // starts, then we can't delay the testing by using an onclick event, as the animation would be past start time.
    if (window.animationStartsImmediately) {
        executeTest();
        return;
    }

    var useX = 50;
    var useY = 50;
    if (window.clickX)
        useX = window.clickX;
    if (window.clickY)
        useY = window.clickY;
    setTimeout("clickAt(" + useX + "," + useY + ")", 0);
}

function runAnimationTest(expected) {
    if (!expected)
        throw("Expected results are missing!");
    if (currentTest > 0)
        throw("Not allowed to call runAnimationTest() twice");

    if (window.testRunner)
        testRunner.waitUntilDone();

    expectedResults = expected;
    testCount = expectedResults.length;
    currentTest = 0;

    // Immediately sample, if the first time is zero.
    if (expectedResults[0][1] == 0) {
        expectedResults[0][2]();
        ++currentTest;
    }

    if (window.testRunner)
        setTimeout(sampleAnimation, 0);
    else
        setTimeout(sampleAnimation, 50);
}