Files
shaka-player/test/cast/cast_utils_unit.js
T
Jacob Trimble adb8da4764 Disallow unknown properties (1/5).
This is part of adding a new conformance rule to add additional type
safety.  This will disallow using properties of unknown types or using
unknown properties.

The first parts will be fixing errors caused by the new rule.  These
are backwards compatible, so can be applied before the rule is enabled.
Once all the errors and bugs are fixed, the rule will be enabled.

Change-Id: Iefde089b2f62ddfdf43944cda5badab438577561
2017-06-27 19:43:00 +00:00

272 lines
9.1 KiB
JavaScript

/**
* @license
* Copyright 2016 Google Inc.
*
* Licensed 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.
*/
describe('CastUtils', function() {
/** @const */
var CastUtils = shaka.cast.CastUtils;
/** @const */
var FakeEvent = shaka.util.FakeEvent;
it('includes every Player member', function() {
var ignoredMembers = [
'constructor', // JavaScript added field
'getNetworkingEngine', // Handled specially
'setMaxHardwareResolution',
'destroy', // Should use CastProxy.destroy instead
// Test helper methods (not @export'd)
'createDrmEngine',
'createNetworkingEngine',
'createPlayhead',
'createMediaSource',
'createMediaSourceEngine',
'createStreamingEngine'
];
var castMembers = shaka.cast.CastUtils.PlayerVoidMethods
.concat(shaka.cast.CastUtils.PlayerGetterMethods)
.concat(shaka.cast.CastUtils.PlayerPromiseMethods);
var playerMembers = Object.keys(shaka.Player.prototype).filter(
function(name) {
// Private members end with _.
return ignoredMembers.indexOf(name) < 0 &&
name.substr(name.length - 1) != '_';
});
// To make debugging easier, don't check that they are equal; instead check
// that neither has any extra entries.
var extraCastMembers = castMembers.filter(function(name) {
return playerMembers.indexOf(name) < 0;
});
var extraPlayerMembers = castMembers.filter(function(name) {
return castMembers.indexOf(name) < 0;
});
expect(extraCastMembers).toEqual([]);
expect(extraPlayerMembers).toEqual([]);
});
describe('serialize/deserialize', function() {
it('transfers infinite values and NaN', function() {
var orig = {
'nan': NaN,
'positive_infinity': Infinity,
'negative_infinity': -Infinity,
'null': null,
'true': true,
'false': false,
'one': 1,
'string': 'a string'
};
var serialized = CastUtils.serialize(orig);
// The object is turned into a string.
expect(typeof serialized).toBe('string');
// The deserialized object matches the original.
var deserialized = CastUtils.deserialize(serialized);
for (var k in orig) {
expect(deserialized[k]).toEqual(orig[k]);
}
});
it('transfers real Events', function() {
// new Event() is not usable on IE11:
var event =
/** @type {!CustomEvent} */ (document.createEvent('CustomEvent'));
event.initCustomEvent('myEventType', false, false, null);
// Properties that can definitely be transferred.
var nativeProperties = [
'bubbles',
'type',
'cancelable',
'defaultPrevented'
];
var extraProperties = {
'key': 'value',
'true': true,
'one': 1
};
for (var k in extraProperties) {
event[k] = extraProperties[k];
}
// The event is turned into a string.
var serialized = CastUtils.serialize(event);
expect(typeof serialized).toBe('string');
// The string is turned back into an object.
var deserialized = CastUtils.deserialize(serialized);
expect(typeof deserialized).toBe('object');
// The object can be used to construct a FakeEvent.
var fakeEvent = new FakeEvent(deserialized['type'], deserialized);
// The fake event has the same type and properties as the original.
nativeProperties.forEach(function(k) {
expect(fakeEvent[k]).toEqual(event[k]);
});
for (var k in extraProperties) {
expect(fakeEvent[k]).toEqual(event[k]);
}
});
it('transfers dispatched FakeEvents', function(done) {
var event = new FakeEvent('custom');
// Properties that can definitely be transferred.
var nativeProperties = [
'bubbles',
'type',
'cancelable',
'defaultPrevented'
];
var extraProperties = {
'key': 'value',
'true': true,
'one': 1
};
for (var k in extraProperties) {
event[k] = extraProperties[k];
}
var target = new shaka.util.FakeEventTarget();
target.addEventListener(event.type, function() {
try {
// The event is turned into a string.
var serialized = CastUtils.serialize(event);
expect(typeof serialized).toBe('string');
// The string is turned back into an object.
var deserialized = CastUtils.deserialize(serialized);
expect(typeof deserialized).toBe('object');
// The deserialized event has the same type and properties as the
// original.
nativeProperties.forEach(function(k) {
expect(deserialized[k]).toEqual(event[k]);
});
for (var k in extraProperties) {
expect(deserialized[k]).toEqual(event[k]);
}
} catch (exception) {
fail(exception);
}
done();
});
target.dispatchEvent(event);
});
describe('TimeRanges', function() {
/** @type {!HTMLVideoElement} */
var video;
/** @type {!shaka.util.EventManager} */
var eventManager;
/** @type {!shaka.media.MediaSourceEngine} */
var mediaSourceEngine;
beforeAll(function() {
video =
/** @type {!HTMLVideoElement} */ (document.createElement('video'));
document.body.appendChild(video);
});
beforeEach(function(done) {
// The TimeRanges constructor cannot be used directly, so we load a clip
// to get ranges to use.
var mediaSource = new MediaSource();
var mimeType = 'video/mp4; codecs="avc1.42c01e"';
var initSegmentUrl = '/base/test/test/assets/sintel-video-init.mp4';
var videoSegmentUrl = '/base/test/test/assets/sintel-video-segment.mp4';
// Wait for the media source to be open.
eventManager = new shaka.util.EventManager();
video.src = window.URL.createObjectURL(mediaSource);
eventManager.listen(video, 'error', onError);
eventManager.listen(mediaSource, 'sourceopen', onSourceOpen);
function onError() {
fail('Error code ' + (video.error ? video.error.code : 0));
}
function onSourceOpen() {
var ContentType = shaka.util.ManifestParserUtils.ContentType;
eventManager.unlisten(mediaSource, 'sourceopen');
mediaSourceEngine = new shaka.media.MediaSourceEngine(
video, mediaSource, /* TextTrack */ null);
// Create empty object first and initialize the fields through
// [] to allow field names to be expressions.
var initObject = {};
initObject[ContentType.VIDEO] = mimeType;
mediaSourceEngine.init(initObject);
shaka.test.Util.fetch(initSegmentUrl).then(function(data) {
return mediaSourceEngine.appendBuffer(ContentType.VIDEO, data,
null, null);
}).then(function() {
return shaka.test.Util.fetch(videoSegmentUrl);
}).then(function(data) {
return mediaSourceEngine.appendBuffer(ContentType.VIDEO, data,
null, null);
}).catch(fail).then(done);
}
});
afterEach(function(done) {
eventManager.destroy().then(function() {
if (mediaSourceEngine) {
return mediaSourceEngine.destroy();
}
}).then(function() {
video.removeAttribute('src');
video.load();
done();
});
});
afterAll(function() {
document.body.removeChild(video);
});
it('deserialize into equivalent objects', function() {
var buffered = video.buffered;
// The test is less interesting if the ranges are empty.
expect(buffered.length).toBeGreaterThan(0);
// The TimeRanges object is turned into a string.
var serialized = CastUtils.serialize(buffered);
expect(typeof serialized).toBe('string');
// Expect the deserialized version to look like the original.
var deserialized = CastUtils.deserialize(serialized);
expect(deserialized.length).toEqual(buffered.length);
expect(deserialized.start).toEqual(jasmine.any(Function));
expect(deserialized.end).toEqual(jasmine.any(Function));
for (var i = 0; i < deserialized.length; ++i) {
// Not exact because of the possibility of rounding errors.
expect(deserialized.start(i)).toBeCloseTo(buffered.start(i));
expect(deserialized.end(i)).toBeCloseTo(buffered.end(i));
}
});
});
});
});