<commit_before>/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 */

/* global cordova, Windows, Media, MediaError, LocalFileSystem, halfSpeedBtn */

// increased timeout for actual playback to give device chance to download and play mp3 file
// some emulators can be REALLY slow at this, so two minutes
var ACTUAL_PLAYBACK_TEST_TIMEOUT = 2 * 60 * 1000;

var WEB_MP3_FILE = 'https://cordova.apache.org/static/downloads/BlueZedEx.mp3';
var WEB_MP3_STREAM = 'https://cordova.apache.org/static/downloads/BlueZedEx.mp3';

var isWindows = cordova.platformId === 'windows';
var isBrowser = cordova.platformId === 'browser';
// Detect whether audio hardware is available and enabled. For iOS playing audio is
// not supported on emulators w/out sound device connected to host PC but (which is
// the case for Sauce Labs emulators - see CB-11430)
var isAudioSupported = isWindows
    ? !!Windows.Media.Devices.MediaDevice.getDefaultAudioRenderId(Windows.Media.Devices.AudioDeviceRole.default)
    : cordova.platformId === 'ios'
        ? !window.SAUCELABS_ENV
        : true;

// Detect OS version when running on Android
var androidVersion = null;
if (cordova.platformId === 'android') {
    var ua = navigator.userAgent;
    var androidStart = ua.indexOf('Android ');
    var versionString = ua.substring(androidStart + 8, ua.indexOf(';', androidStart));
    androidVersion = versionString.split('.').map(function (x) { return x / 1; });
}

exports.defineAutoTests = function () {
    var failed = function (done, msg, context) {
        if (context && context.done) return;
        context.done = true;
        var info = typeof msg === 'undefined' ? 'Unexpected error callback' : msg;
        expect(true).toFailWithMessage(info);
        done();
    };

    var succeed = function (done, msg, context) {
        if (context && context.done) return;
        context.done = true;
        var info = typeof msg === 'undefined' ? 'Unexpected success callback' : msg;
        expect(true).toFailWithMessage(info);
        done();
    };

    describe('Media', function () {
        beforeEach(function () {
            // Custom Matcher
            jasmine.Expectation.addMatchers({
                toFailWithMessage: function () {
                    return {
                        compare: function (_, message) {
                            var pass = false;
                            return {
                                pass: pass,
                                message: message
                            };
                        }
                    };
                }
            });
        });

        it('media.spec.1 should exist', function () {
            expect(Media).toBeDefined();
            expect(typeof Media).toBe('function');
        });

        it('media.spec.2 should have the following properties', function () {
            var media1 = new Media('dummy');
            expect(media1.id).toBeDefined();
            expect(media1.src).toBeDefined();
            expect(media1._duration).toBeDefined();
            expect(media1._position).toBeDefined();
            media1.release();
        });

        it('media.spec.3 should define constants for Media status', function () {
            expect(Media).toBeDefined();
            expect(Media.MEDIA_NONE).toBe(0);
            expect(Media.MEDIA_STARTING).toBe(1);
            expect(Media.MEDIA_RUNNING).toBe(2);
            expect(Media.MEDIA_PAUSED).toBe(3);
            expect(Media.MEDIA_STOPPED).toBe(4);
        });

        it('media.spec.4 should define constants for Media errors', function () {
            expect(MediaError).toBeDefined();
            expect(MediaError.MEDIA_ERR_NONE_ACTIVE).toBe(0);
            expect(MediaError.MEDIA_ERR_ABORTED).toBe(1);
            expect(MediaError.MEDIA_ERR_NETWORK).toBe(2);
            expect(MediaError.MEDIA_ERR_DECODE).toBe(3);
            expect(MediaError.MEDIA_ERR_NONE_SUPPORTED).toBe(4);
        });

        it('media.spec.5 should contain a play function', function () {
            var media1 = new Media('dummy');
            expect(media1.play).toBeDefined();
            expect(typeof media1.play).toBe('function');
            media1.release();
        });

        it('media.spec.6 should contain a stop function', function () {
            var media1 = new Media('dummy');
            expect(media1.stop).toBeDefined();
            expect(typeof media1.stop).toBe('function');
            media1.release();
        });

        it('media.spec.7 should contain a seekTo function', function () {
            var media1 = new Media('dummy');
            expect(media1.seekTo).toBeDefined();
            expect(typeof media1.seekTo).toBe('function');
            media1.release();
        });

        it('media.spec.8 should contain a pause function', function () {
            var media1 = new Media('dummy');
            expect(media1.pause).toBeDefined();
            expect(typeof media1.pause).toBe('function');
            media1.release();
        });

        it('media.spec.9 should contain a getDuration function', function () {
            var media1 = new Media('dummy');
            expect(media1.getDuration).toBeDefined();
            expect(typeof media1.getDuration).toBe('function');
            media1.release();
        });

        it('media.spec.10 should contain a getCurrentPosition function', function () {
            var media1 = new Media('dummy');
            expect(media1.getCurrentPosition).toBeDefined();
            expect(typeof media1.getCurrentPosition).toBe('function');
            media1.release();
        });

        it('media.spec.11 should contain a startRecord function', function () {
            var media1 = new Media('dummy');
            expect(media1.startRecord).toBeDefined();
            expect(typeof media1.startRecord).toBe('function');
            media1.release();
        });

        it('media.spec.12 should contain a stopRecord function', function () {
            var media1 = new Media('dummy');
            expect(media1.stopRecord).toBeDefined();
            expect(typeof media1.stopRecord).toBe('function');
            media1.release();
        });

        it('media.spec.13 should contain a release function', function () {
            var media1 = new Media('dummy');
            expect(media1.release).toBeDefined();
            expect(typeof media1.release).toBe('function');
            media1.release();
        });

        it('media.spec.14 should contain a setVolume function', function () {
            var media1 = new Media('dummy');
            expect(media1.setVolume).toBeDefined();
            expect(typeof media1.setVolume).toBe('function');
            media1.release();
        });

        it('media.spec.15 should contain a getCurrentAmplitude function', function () {
            var media1 = new Media('dummy');
            expect(media1.getCurrentAmplitude).toBeDefined();
            expect(typeof media1.getCurrentAmplitude).toBe('function');
            media1.release();
        });

        it('media.spec.16 should contain a pauseRecord function', function () {
            var media1 = new Media('dummy');
            expect(media1.pauseRecord).toBeDefined();
            expect(typeof media1.pauseRecord).toBe('function');
            media1.release();
        });

        it('media.spec.17 should contain a resumeRecord function', function () {
            var media1 = new Media('dummy');
            expect(media1.resumeRecord).toBeDefined();
            expect(typeof media1.resumeRecord).toBe('function');
            media1.release();
        });

        it('media.spec.18 should return MediaError for bad filename', function (done) {
            var context = this;
            var fileName = 'invalid.file.name';
            var badMedia = new Media(
                fileName,
                succeed.bind(
                    null,
                    done,
                    ' badMedia = new Media , Unexpected succees callback, it should not create Media object with invalid file name'
                ),
                function (result) {
                    if (context.done) return;
                    context.done = true;

                    expect(result).toBeDefined();
                    expect(result.code).toBe(MediaError.MEDIA_ERR_ABORTED);
                    if (badMedia) {
                        badMedia.release();
                    }
                    done();
                }
            );
            badMedia.play();
        });

        describe('actual playback', function () {
            var checkInterval, media;

            afterEach(function () {
                clearInterval(checkInterval);
                if (media) {
                    media.stop();
                    media.release();
                    media = null;
                }
            });

            it(
                'media.spec.19 position should be set properly',
                function (done) {
                    // no audio hardware available
                    if (!isAudioSupported || isBrowser) {
                        pending();
                    }

                    // context variable used as an extra security statement to ensure that the callback is processed only once,
                    // in case the statusChange callback is reached more than one time with the same status code.
                    // Some information about this kind of behaviour can be found at JIRA: CB-7099.
                    var context = this;
                    var mediaFile = WEB_MP3_FILE;
                    var successCallback = function () {};
                    var statusChange = function (statusCode) {
                        if (!context.done && statusCode === Media.MEDIA_RUNNING) {
                            checkInterval = setInterval(function () {
                                if (context.done) return;
                                media.getCurrentPosition(function successCallback (position) {
                                    if (position > 0.0) {
                                        context.done = true;
                                        expect(true).toBe(true);
                                        done();
                                    }
                                }, failed.bind(null, done, 'media1.getCurrentPosition - Error getting media current position', context));
                            }, 1000);
                        }
                    };
                    media = new Media(
                        mediaFile,
                        successCallback,
                        failed.bind(null, done, 'media1 = new Media - Error creating Media object. Media file: ' + mediaFile, context),
                        statusChange
                    );
                    media.play();
                },
                ACTUAL_PLAYBACK_TEST_TIMEOUT
            );

            it(
                'media.spec.20 duration should be set properly',
                function (done) {
                    if (!isAudioSupported || isBrowser) {
                        pending();
                    }

                    // context variable used as an extra security statement to ensure that the callback is processed only once,
                    // in case the statusChange callback is reached more than one time with the same status code.
                    // Some information about this kind of behaviour can be found at JIRA: CB-7099.
                    var context = this;
                    var mediaFile = WEB_MP3_FILE;
                    var successCallback = function () {};
                    var statusChange = function (statusCode) {
                        if (!context.done && statusCode === Media.MEDIA_RUNNING) {
                            checkInterval = setInterval(function () {
                                if (context.done) return;
                                media.getCurrentPosition(function (position) {
                                    if (position > 0.0) {
                                        context.done = true;
                                        expect(media.getDuration()).toBeGreaterThan(0.0);
                                        done();
                                    }
                                }, failed.bind(null, done, 'media1.getCurrentPosition - Error getting media current position', context));
                            }, 1000);
                        }
                    };
                    media = new Media(
                        mediaFile,
                        successCallback,
                        failed.bind(null, done, 'media1 = new Media - Error creating Media object. Media file: ' + mediaFile, context),
                        statusChange
                    );
                    media.play();
                },
                ACTUAL_PLAYBACK_TEST_TIMEOUT
            );

            it(
                'media.spec.21 should be able to resume playback after pause',
                function (done) {
                    if (!isAudioSupported || isBrowser) {
                        /**
                         * Browser Error:
                         * Uncaught (in promise) DOMException: play() failed because the user didn't interact with
                         * the document first. https://goo.gl/xX8pDD
                         *
                         * The Autoplay Policy launched in Chrome 66 for audio and video elements and is effectively
                         * blocking roughly half of unwanted media autoplays in Chrome. For the Web Audio API, the
                         * autoplay policy launched in Chrome 71. This affects web games, some WebRTC applications,
                         * and other web pages using audio features. More details can be found in the Web Audio API
                         * section below.
                         *
                         * Due to the Chrome Policies, this test is disabled because it can not be run without user
                         * interations.
                         */
                        pending();
                    }

                    // context variable used as an extra security statement to ensure that the callback is processed only once,
                    // in case the statusChange callback is reached more than one time with the same status code.
                    // Some information about this kind of behaviour can be found at JIRA: CB-7099.
                    var context = this;
                    var resumed = false;
                    var mediaFile = WEB_MP3_FILE;
                    var successCallback = function () {};
                    var statusChange = function (statusCode) {
                        if (context.done) return;

                        if (statusCode === Media.MEDIA_RUNNING) {
                            if (!resumed) {
                                media.seekTo(20000);
                                media.pause();
                                return;
                            }

                            media.getCurrentPosition(function (position) {
                                expect(position).toBeGreaterThan(19);
                                expect(position).toBeLessThan(21);
                                context.done = true;
                                done();
                            }, failed.bind(null, done, 'media1.getCurrentPosition - Error getting media current position', context));
                        }

                        if (statusCode === Media.MEDIA_PAUSED) {
                            resumed = true;
                            media.play();
                        }
                    };
                    media = new Media(
                        mediaFile,
                        successCallback,
                        failed.bind(null, done, 'media1 = new Media - Error creating Media object. Media file: ' + mediaFile, context),
                        statusChange
                    );

                    // CB-10535: Play after a few secs, to give allow enough buffering of media file before seeking
                    setTimeout(function () {
                        media.play();
                    }, 4000);
                },
                ACTUAL_PLAYBACK_TEST_TIMEOUT
            );

            it(
                'media.spec.22 should be able to seek through file',
                function (done) {
                    if (!isAudioSupported || isBrowser) {
                        /**
                         * Browser Error:
                         * Uncaught (in promise) DOMException: play() failed because the user didn't interact with
                         * the document first. https://goo.gl/xX8pDD
                         *
                         * The Autoplay Policy launched in Chrome 66 for audio and video elements and is effectively
                         * blocking roughly half of unwanted media autoplays in Chrome. For the Web Audio API, the
                         * autoplay policy launched in Chrome 71. This affects web games, some WebRTC applications,
                         * and other web pages using audio features. More details can be found in the Web Audio API
                         * section below.
                         *
                         * Due to the Chrome Policies, this test is disabled because it can not be run without user
                         * interations.
                         */
                        pending();
                    }

                    // context variable used as an extra security statement to ensure that the callback is processed only once,
                    // in case the statusChange callback is reached more than one time with the same status code.
                    // Some information about this kind of behaviour can be found at JIRA: CB-7099.
                    var context = this;
                    var mediaFile = WEB_MP3_FILE;
                    var successCallback = function () {};
                    var statusChange = function (statusCode) {
                        if (!context.done && statusCode === Media.MEDIA_RUNNING) {
                            checkInterval = setInterval(function () {
                                if (context.done) return;<commit_msg>test(spec.timeout): try to improve against timeout failures (#356)<commit_after>/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 */

/* global cordova, Windows, Media, MediaError, LocalFileSystem, halfSpeedBtn */

// increased timeout for actual playback to give device chance to download and play mp3 file
// some emulators can be REALLY slow at this, so two minutes
var ACTUAL_PLAYBACK_TEST_TIMEOUT = 2 * 60 * 1000;
jasmine.DEFAULT_TIMEOUT_INTERVAL = ACTUAL_PLAYBACK_TEST_TIMEOUT;

var WEB_MP3_FILE = 'https://cordova.apache.org/static/downloads/BlueZedEx.mp3';
var WEB_MP3_STREAM = 'https://cordova.apache.org/static/downloads/BlueZedEx.mp3';

var isWindows = cordova.platformId === 'windows';
var isBrowser = cordova.platformId === 'browser';
// Detect whether audio hardware is available and enabled. For iOS playing audio is
// not supported on emulators w/out sound device connected to host PC but (which is
// the case for Sauce Labs emulators - see CB-11430)
var isAudioSupported = isWindows
    ? !!Windows.Media.Devices.MediaDevice.getDefaultAudioRenderId(Windows.Media.Devices.AudioDeviceRole.default)
    : cordova.platformId === 'ios'
        ? !window.SAUCELABS_ENV
        : true;

// Detect OS version when running on Android
var androidVersion = null;
if (cordova.platformId === 'android') {
    var ua = navigator.userAgent;
    var androidStart = ua.indexOf('Android ');
    var versionString = ua.substring(androidStart + 8, ua.indexOf(';', androidStart));
    androidVersion = versionString.split('.').map(function (x) { return x / 1; });
}

exports.defineAutoTests = function () {
    var failed = function (done, msg, context) {
        if (context && context.done) return;
        context.done = true;
        var info = typeof msg === 'undefined' ? 'Unexpected error callback' : msg;
        expect(true).toFailWithMessage(info);
        done();
    };

    var succeed = function (done, msg, context) {
        if (context && context.done) return;
        context.done = true;
        var info = typeof msg === 'undefined' ? 'Unexpected success callback' : msg;
        expect(true).toFailWithMessage(info);
        done();
    };

    describe('Media', function () {
        beforeEach(function () {
            // Custom Matcher
            jasmine.Expectation.addMatchers({
                toFailWithMessage: function () {
                    return {
                        compare: function (_, message) {
                            var pass = false;
                            return {
                                pass: pass,
                                message: message
                            };
                        }
                    };
                }
            });
        });

        it('media.spec.1 should exist', function () {
            expect(Media).toBeDefined();
            expect(typeof Media).toBe('function');
        });

        it('media.spec.2 should have the following properties', function () {
            var media1 = new Media('dummy');
            expect(media1.id).toBeDefined();
            expect(media1.src).toBeDefined();
            expect(media1._duration).toBeDefined();
            expect(media1._position).toBeDefined();
            media1.release();
        });

        it('media.spec.3 should define constants for Media status', function () {
            expect(Media).toBeDefined();
            expect(Media.MEDIA_NONE).toBe(0);
            expect(Media.MEDIA_STARTING).toBe(1);
            expect(Media.MEDIA_RUNNING).toBe(2);
            expect(Media.MEDIA_PAUSED).toBe(3);
            expect(Media.MEDIA_STOPPED).toBe(4);
        });

        it('media.spec.4 should define constants for Media errors', function () {
            expect(MediaError).toBeDefined();
            expect(MediaError.MEDIA_ERR_NONE_ACTIVE).toBe(0);
            expect(MediaError.MEDIA_ERR_ABORTED).toBe(1);
            expect(MediaError.MEDIA_ERR_NETWORK).toBe(2);
            expect(MediaError.MEDIA_ERR_DECODE).toBe(3);
            expect(MediaError.MEDIA_ERR_NONE_SUPPORTED).toBe(4);
        });

        it('media.spec.5 should contain a play function', function () {
            var media1 = new Media('dummy');
            expect(media1.play).toBeDefined();
            expect(typeof media1.play).toBe('function');
            media1.release();
        });

        it('media.spec.6 should contain a stop function', function () {
            var media1 = new Media('dummy');
            expect(media1.stop).toBeDefined();
            expect(typeof media1.stop).toBe('function');
            media1.release();
        });

        it('media.spec.7 should contain a seekTo function', function () {
            var media1 = new Media('dummy');
            expect(media1.seekTo).toBeDefined();
            expect(typeof media1.seekTo).toBe('function');
            media1.release();
        });

        it('media.spec.8 should contain a pause function', function () {
            var media1 = new Media('dummy');
            expect(media1.pause).toBeDefined();
            expect(typeof media1.pause).toBe('function');
            media1.release();
        });

        it('media.spec.9 should contain a getDuration function', function () {
            var media1 = new Media('dummy');
            expect(media1.getDuration).toBeDefined();
            expect(typeof media1.getDuration).toBe('function');
            media1.release();
        });

        it('media.spec.10 should contain a getCurrentPosition function', function () {
            var media1 = new Media('dummy');
            expect(media1.getCurrentPosition).toBeDefined();
            expect(typeof media1.getCurrentPosition).toBe('function');
            media1.release();
        });

        it('media.spec.11 should contain a startRecord function', function () {
            var media1 = new Media('dummy');
            expect(media1.startRecord).toBeDefined();
            expect(typeof media1.startRecord).toBe('function');
            media1.release();
        });

        it('media.spec.12 should contain a stopRecord function', function () {
            var media1 = new Media('dummy');
            expect(media1.stopRecord).toBeDefined();
            expect(typeof media1.stopRecord).toBe('function');
            media1.release();
        });

        it('media.spec.13 should contain a release function', function () {
            var media1 = new Media('dummy');
            expect(media1.release).toBeDefined();
            expect(typeof media1.release).toBe('function');
            media1.release();
        });

        it('media.spec.14 should contain a setVolume function', function () {
            var media1 = new Media('dummy');
            expect(media1.setVolume).toBeDefined();
            expect(typeof media1.setVolume).toBe('function');
            media1.release();
        });

        it('media.spec.15 should contain a getCurrentAmplitude function', function () {
            var media1 = new Media('dummy');
            expect(media1.getCurrentAmplitude).toBeDefined();
            expect(typeof media1.getCurrentAmplitude).toBe('function');
            media1.release();
        });

        it('media.spec.16 should contain a pauseRecord function', function () {
            var media1 = new Media('dummy');
            expect(media1.pauseRecord).toBeDefined();
            expect(typeof media1.pauseRecord).toBe('function');
            media1.release();
        });

        it('media.spec.17 should contain a resumeRecord function', function () {
            var media1 = new Media('dummy');
            expect(media1.resumeRecord).toBeDefined();
            expect(typeof media1.resumeRecord).toBe('function');
            media1.release();
        });

        it('media.spec.18 should return MediaError for bad filename', function (done) {
            var context = this;
            var fileName = 'invalid.file.name';
            var badMedia = new Media(
                fileName,
                succeed.bind(
                    null,
                    done,
                    ' badMedia = new Media , Unexpected succees callback, it should not create Media object with invalid file name'
                ),
                function (result) {
                    if (context.done) return;
                    context.done = true;

                    expect(result).toBeDefined();
                    expect(result.code).toBe(MediaError.MEDIA_ERR_ABORTED);
                    if (badMedia) {
                        badMedia.release();
                    }
                    done();
                }
            );
            badMedia.play();
        });

        describe('actual playback', function () {
            var checkInterval, media;

            // Ensure interval and media is cleared out before and after each test
            var safeDone = function () {
                if (checkInterval) {
                    clearInterval(checkInterval);
                    checkInterval = null;
                }

                if (media) {
                    media.stop();
                    media.release();
                    media = null;
                }
            };

            afterEach(function () { safeDone(); });
            beforeEach(function () { safeDone(); });

            it(
                'media.spec.19 position should be set properly',
                function (done) {
                    // no audio hardware available
                    if (!isAudioSupported || isBrowser) {
                        pending();
                    }

                    // context variable used as an extra security statement to ensure that the callback is processed only once,
                    // in case the statusChange callback is reached more than one time with the same status code.
                    // Some information about this kind of behaviour can be found at JIRA: CB-7099.
                    var context = this;
                    var mediaFile = WEB_MP3_FILE;
                    var successCallback = function () {
                        done();
                    };
                    var statusChange = function (statusCode) {
                        if (!context.done && statusCode === Media.MEDIA_RUNNING) {
                            checkInterval = setInterval(function () {
                                if (context.done) return;
                                media.getCurrentPosition(function successCallback (position) {
                                    if (position > 0.0) {
                                        context.done = true;
                                        expect(true).toBe(true);
                                        done();
                                    }
                                }, failed.bind(null, done, 'media1.getCurrentPosition - Error getting media current position', context));
                            }, 1000);
                        }
                    };
                    media = new Media(
                        mediaFile,
                        successCallback,
                        failed.bind(null, done, 'media1 = new Media - Error creating Media object. Media file: ' + mediaFile, context),
                        statusChange
                    );
                    media.play();
                },
                ACTUAL_PLAYBACK_TEST_TIMEOUT
            );

            it(
                'media.spec.20 duration should be set properly',
                function (done) {
                    if (!isAudioSupported || isBrowser) {
                        pending();
                    }

                    // context variable used as an extra security statement to ensure that the callback is processed only once,
                    // in case the statusChange callback is reached more than one time with the same status code.
                    // Some information about this kind of behaviour can be found at JIRA: CB-7099.
                    var context = this;
                    var mediaFile = WEB_MP3_FILE;
                    var successCallback = function () {
                        done();
                    };
                    var statusChange = function (statusCode) {
                        if (!context.done && statusCode === Media.MEDIA_RUNNING) {
                            checkInterval = setInterval(function () {
                                if (context.done) return;
                                media.getCurrentPosition(function (position) {
                                    if (position > 0.0) {
                                        context.done = true;
                                        expect(media.getDuration()).toBeGreaterThan(0.0);
                                        done();
                                    }
                                }, failed.bind(null, done, 'media1.getCurrentPosition - Error getting media current position', context));
                            }, 1000);
                        }
                    };
                    media = new Media(
                        mediaFile,
                        successCallback,
                        failed.bind(null, done, 'media1 = new Media - Error creating Media object. Media file: ' + mediaFile, context),
                        statusChange
                    );
                    media.play();
                },
                ACTUAL_PLAYBACK_TEST_TIMEOUT
            );

            it(
                'media.spec.21 should be able to resume playback after pause',
                function (done) {
                    if (!isAudioSupported || isBrowser) {
                        /**
                         * Browser Error:
                         * Uncaught (in promise) DOMException: play() failed because the user didn't interact with
                         * the document first. https://goo.gl/xX8pDD
                         *
                         * The Autoplay Policy launched in Chrome 66 for audio and video elements and is effectively
                         * blocking roughly half of unwanted media autoplays in Chrome. For the Web Audio API, the
                         * autoplay policy launched in Chrome 71. This affects web games, some WebRTC applications,
                         * and other web pages using audio features. More details can be found in the Web Audio API
                         * section below.
                         *
                         * Due to the Chrome Policies, this test is disabled because it can not be run without user
                         * interations.
                         */
                        pending();
                    }

                    // context variable used as an extra security statement to ensure that the callback is processed only once,
                    // in case the statusChange callback is reached more than one time with the same status code.
                    // Some information about this kind of behaviour can be found at JIRA: CB-7099.
                    var context = this;
                    var resumed = false;
                    var mediaFile = WEB_MP3_FILE;
                    var successCallback = function () {
                        done();
                    };
                    var statusChange = function (statusCode) {
                        if (context.done) return;

                        if (statusCode === Media.MEDIA_RUNNING) {
                            if (!resumed) {
                                media.seekTo(20000);
                                media.pause();
                                return;
                            }

                            media.getCurrentPosition(function (position) {
                                expect(position).toBeGreaterThan(19);
                                expect(position).toBeLessThan(21);
                                context.done = true;
                                done();
                            }, failed.bind(null, done, 'media1.getCurrentPosition - Error getting media current position', context));
                        }

                        if (statusCode === Media.MEDIA_PAUSED) {
                            resumed = true;
                            media.play();
                        }
                    };
                    media = new Media(
                        mediaFile,
                        successCallback,
                        failed.bind(null, done, 'media1 = new Media - Error creating Media object. Media file: ' + mediaFile, context),
                        statusChange
                    );

                    // CB-10535: Play after a few secs, to give allow enough buffering of media file before seeking
                    setTimeout(function () {
                        media.play();
                    }, 4000);
                },
                ACTUAL_PLAYBACK_TEST_TIMEOUT
            );

            it(
                'media.spec.22 should be able to seek through file',
                function (done) {
                    if (!isAudioSupported || isBrowser) {
                        /**
                         * Browser Error:
                         * Uncaught (in promise) DOMException: play() failed because the user didn't interact with
                         * the document first. https://goo.gl/xX8pDD
                         *
                         * The Autoplay Policy launched in Chrome 66 for audio and video elements and is effectively
                         * blocking roughly half of unwanted media autoplays in Chrome. For the Web Audio API, the
                         * autoplay policy launched in Chrome 71. This affects web games, some WebRTC applications,
                         * and other web pages using audio features. More details can be found in the Web Audio API
                         * section below.
                         *
                         * Due to the Chrome Policies, this test is disabled because it can not be run without user
                         * interations.
                         */
                        pending();
                    }

                    // context variable used as an extra security statement to ensure that the callback is processed only once,
                    // in case the statusChange callback is reached more than one time with the same status code.
                    // Some information about this kind of behaviour can be found at JIRA: CB-7099.
                    var context = this;
                    var mediaFile = WEB_MP3_FILE;
                    var successCallback = function () {
                        done();
                    };
                    var statusChange = function (statusCode) {
                        if (!context.done && statusCode === Media.MEDIA_RUNNING) {
                            checkInterval = setInterval(function () {
                                if (context.done) return;
{'fraction_non_alphanumeric': 0.088512144450999, 'fraction_numerical': 0.010028469568339788, 'mean_word_length': 1.3812141199462562, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 8, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 42, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6836717', 'n_tokens_mistral': 8993, 'n_tokens_neox': 8452, 'n_words': 2626}