blob: e7ac82d8cf78bd28a783371f84ddd4ac12918e8e [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* In the real (non-test) code, this data comes from the C++ handler.
* Only used for tests.
* @typedef {{defaults: !Object<settings.ContentSettingsTypes,
* !DefaultContentSetting>,
* exceptions: !Object<settings.ContentSettingsTypes,
* !Array<!RawSiteException>>,
* chooserExceptions: !Object<settings.ContentSettingsTypes,
* !Array<!RawChooserException>>}}
*/
let SiteSettingsPref;
/**
* A test version of SiteSettingsPrefsBrowserProxy. Provides helper methods
* for allowing tests to know when a method was called, as well as
* specifying mock responses.
*
* @implements {settings.SiteSettingsPrefsBrowserProxy}
*/
class TestSiteSettingsPrefsBrowserProxy extends TestBrowserProxy {
constructor() {
super([
'clearFlashPref',
'fetchBlockAutoplayStatus',
'fetchUsbDevices',
'fetchZoomLevels',
'getAllSites',
'getChooserExceptionList',
'getDefaultValueForContentType',
'getFormattedBytes',
'getExceptionList',
'getOriginPermissions',
'isOriginValid',
'isPatternValidForType',
'observeProtocolHandlers',
'observeProtocolHandlersEnabledState',
'removeIgnoredHandler',
'removeProtocolHandler',
'removeUsbDevice',
'removeZoomLevel',
'resetCategoryPermissionForPattern',
'resetChooserExceptionForSite',
'setCategoryPermissionForPattern',
'setDefaultValueForContentType',
'setOriginPermissions',
'setProtocolDefault',
'updateIncognitoStatus',
]);
/** @private {boolean} */
this.hasIncognito_ = false;
/** @private {!SiteSettingsPref} */
this.prefs_ = test_util.createSiteSettingsPrefs([], [], []);
/** @private {!Array<ZoomLevelEntry>} */
this.zoomList_ = [];
/** @private {!Array<!UsbDeviceEntry>} */
this.usbDevices_ = [];
/** @private {!Array<!ProtocolEntry>} */
this.protocolHandlers_ = [];
/** @private {!Array<!HandlerEntry>} */
this.ignoredProtocols_ = [];
/** @private {boolean} */
this.isOriginValid_ = true;
/** @private {boolean} */
this.isPatternValidForType_ = true;
}
/**
* Pretends an incognito session started or ended.
* @param {boolean} hasIncognito True for session started.
*/
setIncognito(hasIncognito) {
this.hasIncognito_ = hasIncognito;
cr.webUIListenerCallback('onIncognitoStatusChanged', hasIncognito);
}
/**
* Sets the prefs to use when testing.
* @param {!SiteSettingsPref} prefs The prefs to set.
*/
setPrefs(prefs) {
this.prefs_ = prefs;
// Notify all listeners that their data may be out of date.
for (const type in prefs.defaults) {
cr.webUIListenerCallback('contentSettingCategoryChanged', type);
}
for (const type in this.prefs_.exceptions) {
let exceptionList = this.prefs_.exceptions[type];
for (let i = 0; i < exceptionList.length; ++i) {
cr.webUIListenerCallback(
'contentSettingSitePermissionChanged', type,
exceptionList[i].origin, '');
}
}
}
/**
* Sets one exception for a given category, replacing any existing exceptions
* for the same origin. Note this ignores embedding origins.
* @param {!settings.ContentSettingsTypes} category The category the new
* exception belongs to.
* @param {!RawSiteException} newException The new preference to add/replace.
*/
setSingleException(category, newException) {
// Remove entries from the current prefs which have the same origin.
const newPrefs = /** @type {!Array<RawSiteException>} */
(this.prefs_.exceptions[category].filter((categoryException) => {
if (categoryException.origin != newException.origin) {
return true;
}
}));
newPrefs.push(newException);
this.prefs_.exceptions[category] = newPrefs;
cr.webUIListenerCallback(
'contentSettingSitePermissionChanged', category, newException.origin);
}
/**
* Sets the prefs to use when testing.
* @param {!Array<ZoomLevelEntry>} list The zoom list to set.
*/
setZoomList(list) {
this.zoomList_ = list;
}
/**
* Sets the prefs to use when testing.
* @param {!Array<UsbDeviceEntry>} list The usb device entry list to set.
*/
setUsbDevices(list) {
// Shallow copy of the passed-in array so mutation won't impact the source
this.usbDevices_ = list.slice();
}
/**
* Sets the prefs to use when testing.
* @param {!Array<ProtocolEntry>} list The protocol handlers list to set.
*/
setProtocolHandlers(list) {
// Shallow copy of the passed-in array so mutation won't impact the source
this.protocolHandlers_ = list.slice();
}
/**
* Sets the prefs to use when testing.
* @param {!Array<!HandlerEntry>}
*/
setIgnoredProtocols(list) {
// Shallow copy of the passed-in array so mutation won't impact the source
this.ignoredProtocols_ = list.slice();
}
/** @override */
setDefaultValueForContentType(contentType, defaultValue) {
this.methodCalled(
'setDefaultValueForContentType', [contentType, defaultValue]);
}
/** @override */
setOriginPermissions(origin, contentTypes, blanketSetting) {
for (let i = 0; i < contentTypes.length; ++i) {
let type = contentTypes[i];
let exceptionList = this.prefs_.exceptions[type];
for (let j = 0; j < exceptionList.length; ++j) {
let effectiveSetting = blanketSetting;
if (blanketSetting == settings.ContentSetting.DEFAULT) {
effectiveSetting = this.prefs_.defaults[type].setting;
exceptionList[j].source = settings.SiteSettingSource.DEFAULT;
}
exceptionList[j].setting = effectiveSetting;
}
}
this.setPrefs(this.prefs_);
this.methodCalled(
'setOriginPermissions', [origin, contentTypes, blanketSetting]);
}
/** @override */
clearFlashPref(origin) {
this.methodCalled('clearFlashPref', origin);
}
/** @override */
getAllSites(contentTypes) {
this.methodCalled('getAllSites', contentTypes);
const origins_set = new Set();
contentTypes.forEach((contentType) => {
this.prefs_.exceptions[contentType].forEach((exception) => {
if (exception.origin.includes('*')) {
return;
}
origins_set.add(exception.origin);
});
});
const origins_array = [...origins_set];
let result = [];
origins_array.forEach((origin, index) => {
// Functionality to get the eTLD+1 from an origin exists only on the
// C++ side, so just do an (incorrect) approximate extraction here.
const host = new URL(origin).host;
let urlParts = host.split('.');
urlParts = urlParts.slice(Math.max(urlParts.length - 2, 0));
const etldPlus1Name = urlParts.join('.');
let existing = result.find(siteGroup => {
return siteGroup.etldPlus1 == etldPlus1Name;
});
if (existing) {
existing.origins.push(test_util.createOriginInfo(origin));
} else {
const entry = test_util.createSiteGroup(etldPlus1Name, [origin]);
result.push(entry);
}
});
return Promise.resolve(result);
}
/** @override */
getFormattedBytes(numBytes) {
this.methodCalled('getFormattedBytes', numBytes);
return Promise.resolve(`${numBytes} B`);
}
/** @override */
getDefaultValueForContentType(contentType) {
this.methodCalled('getDefaultValueForContentType', contentType);
let pref = this.prefs_.defaults[contentType];
assert(pref != undefined, 'Pref is missing for ' + contentType);
return Promise.resolve(pref);
}
/** @override */
getExceptionList(contentType) {
// Defer |methodCalled| call so that |then| callback for the promise
// returned from this method runs before the one for the promise returned
// from |whenCalled| calls in tests.
window.setTimeout(
() => this.methodCalled('getExceptionList', contentType), 0);
let pref = this.prefs_.exceptions[contentType];
assert(pref != undefined, 'Pref is missing for ' + contentType);
if (this.hasIncognito_) {
const incognitoElements = [];
for (let i = 0; i < pref.length; ++i) {
// Copy |pref[i]| to avoid changing the original |pref[i]|.
const incognitoPref = Object.assign({}, pref[i]);
incognitoElements.push(Object.assign(incognitoPref, {incognito: true}));
}
pref = pref.concat(incognitoElements);
}
return Promise.resolve(pref);
}
/** @override */
getChooserExceptionList(chooserType) {
let pref = this.prefs_.chooserExceptions[chooserType];
assert(pref != undefined, 'Pref is missing for ' + chooserType);
if (this.hasIncognito_) {
const incognitoElements = [];
for (let i = 0; i < pref.length; ++i) {
// Copy |pref[i]| to avoid changing the original |pref[i]|.
incognitoElements.push(Object.assign({}, pref[i], {incognito: true}));
}
pref.push(...incognitoElements);
}
this.methodCalled('getChooserExceptionList', chooserType);
return Promise.resolve(pref);
}
/** @override */
isOriginValid(origin) {
this.methodCalled('isOriginValid', origin);
return Promise.resolve(this.isOriginValid_);
}
/**
* Specify whether isOriginValid should succeed or fail.
*/
setIsOriginValid(isValid) {
this.isOriginValid_ = isValid;
}
/** @override */
isPatternValidForType(pattern, category) {
this.methodCalled('isPatternValidForType', pattern, category);
return Promise.resolve({
isValid: this.isPatternValidForType_,
reason: this.isPatternValidForType_ ? '' : 'pattern is invalid',
});
}
/**
* Specify whether isPatternValidForType should succeed or fail.
*/
setIsPatternValidForType(isValid) {
this.isPatternValidForType_ = isValid;
}
/** @override */
resetCategoryPermissionForPattern(
primaryPattern, secondaryPattern, contentType, incognito) {
this.methodCalled(
'resetCategoryPermissionForPattern',
[primaryPattern, secondaryPattern, contentType, incognito]);
return Promise.resolve();
}
/** @override */
resetChooserExceptionForSite(
chooserType, origin, embeddingOrigin, exception) {
this.methodCalled(
'resetChooserExceptionForSite',
[chooserType, origin, embeddingOrigin, exception]);
return Promise.resolve();
}
/** @override */
getOriginPermissions(origin, contentTypes) {
this.methodCalled('getOriginPermissions', [origin, contentTypes]);
const exceptionList = [];
contentTypes.forEach(function(contentType) {
let setting;
let source;
this.prefs_.exceptions[contentType].some((originPrefs) => {
if (originPrefs.origin == origin) {
setting = originPrefs.setting;
source = originPrefs.source;
return true;
}
});
assert(
setting != undefined,
'There was no exception set for origin: ' + origin +
' and contentType: ' + contentType);
exceptionList.push({
embeddingOrigin: '',
incognito: false,
origin: origin,
displayName: '',
setting: setting,
source: source,
});
}, this);
return Promise.resolve(exceptionList);
}
/** @override */
setCategoryPermissionForPattern(
primaryPattern, secondaryPattern, contentType, value, incognito) {
this.methodCalled(
'setCategoryPermissionForPattern',
[primaryPattern, secondaryPattern, contentType, value, incognito]);
return Promise.resolve();
}
/** @override */
fetchZoomLevels() {
cr.webUIListenerCallback('onZoomLevelsChanged', this.zoomList_);
this.methodCalled('fetchZoomLevels');
}
/** @override */
removeZoomLevel(host) {
this.methodCalled('removeZoomLevel', [host]);
}
/** @override */
fetchUsbDevices() {
this.methodCalled('fetchUsbDevices');
return Promise.resolve(this.usbDevices_);
}
/** @override */
removeUsbDevice() {
this.methodCalled('removeUsbDevice', arguments);
}
/** @override */
observeProtocolHandlers() {
cr.webUIListenerCallback('setHandlersEnabled', true);
cr.webUIListenerCallback('setProtocolHandlers', this.protocolHandlers_);
cr.webUIListenerCallback(
'setIgnoredProtocolHandlers', this.ignoredProtocols_);
this.methodCalled('observeProtocolHandlers');
}
/** @override */
observeProtocolHandlersEnabledState() {
cr.webUIListenerCallback('setHandlersEnabled', true);
this.methodCalled('observeProtocolHandlersEnabledState');
}
/** @override */
setProtocolDefault() {
this.methodCalled('setProtocolDefault', arguments);
}
/** @override */
removeProtocolHandler() {
this.methodCalled('removeProtocolHandler', arguments);
}
/** @override */
updateIncognitoStatus() {
this.methodCalled('updateIncognitoStatus', arguments);
}
/** @override */
fetchBlockAutoplayStatus() {
this.methodCalled('fetchBlockAutoplayStatus');
}
}