| Index: chrome/test/data/webui/settings/prefs_tests.js
|
| diff --git a/chrome/test/data/webui/settings/prefs_tests.js b/chrome/test/data/webui/settings/prefs_tests.js
|
| index 95e8f487c94b30d9c6c726e009466fd1ee62cd3c..12c8deecfd3e16bbe6a7ee52978ee3321068a9f5 100644
|
| --- a/chrome/test/data/webui/settings/prefs_tests.js
|
| +++ b/chrome/test/data/webui/settings/prefs_tests.js
|
| @@ -5,6 +5,15 @@
|
| /** @fileoverview Suite of tests for cr-settings-prefs. */
|
| cr.define('cr_settings_prefs', function() {
|
| /**
|
| + * Creates a deep copy of the object.
|
| + * @param {!Object} obj
|
| + * @return {!Object}
|
| + */
|
| + function deepCopy(obj) {
|
| + return JSON.parse(JSON.stringify(obj));
|
| + }
|
| +
|
| + /**
|
| * Mock of chrome.settingsPrivate API.
|
| * @constructor
|
| * @extends {chrome.settingsPrivate}
|
| @@ -12,6 +21,7 @@ cr.define('cr_settings_prefs', function() {
|
| function MockSettingsApi() {
|
| this.prefs = {};
|
| this.listener_ = null;
|
| + this.rand_ = getPseudoRand();
|
|
|
| // Hack alert: bind this instance's onPrefsChanged members to this.
|
| this.onPrefsChanged = {
|
| @@ -24,6 +34,8 @@ cr.define('cr_settings_prefs', function() {
|
| this.addBooleanPref_('browser.enable_html5', true);
|
| this.addNumberPref_('device.overclock', .6);
|
| this.addStringPref_('homepage', 'example.com');
|
| + this.addListPref_('languages', generateList(10, String, this.rand_));
|
| + this.addListPref_('content.sites', generateList(2, Object, this.rand_));
|
| }
|
|
|
| MockSettingsApi.prototype = {
|
| @@ -43,7 +55,7 @@ cr.define('cr_settings_prefs', function() {
|
| // Send a copy of prefs to keep our internal state private.
|
| var prefs = [];
|
| for (var key in this.prefs)
|
| - prefs.push(this.createCopy_(this.prefs[key]));
|
| + prefs.push(deepCopy(this.prefs[key]));
|
|
|
| setTimeout(callback.bind(null, prefs));
|
| },
|
| @@ -59,32 +71,43 @@ cr.define('cr_settings_prefs', function() {
|
| this.failNextSetPref_ = false;
|
| return;
|
| }
|
| + assertNotEquals(true, this.disallowSetPref_);
|
|
|
| - // TODO(michaelpg): support list and dict prefs.
|
| - var changed = this.prefs[key].value != value;
|
| - this.prefs[key].value = value;
|
| - setTimeout(function() {
|
| - callback(true);
|
| + var changed = JSON.stringify(pref.value) != JSON.stringify(value);
|
| + pref.value = JSON.parse(JSON.stringify(value));
|
| + setTimeout(callback.bind(null,true));
|
| + if (changed) {
|
| + setTimeout(function() {
|
| // Like chrome.settingsPrivate, send a notification when prefs change.
|
| - if (changed)
|
| - this.sendPrefChanges([key], [value]);
|
| - }.bind(this));
|
| + this.sendPrefChanges([key], [deepCopy(value)]);
|
| + }.bind(this));
|
| + }
|
| },
|
|
|
| getPref: function(key, callback) {
|
| var pref = this.prefs[key];
|
| assertNotEquals(undefined, pref);
|
|
|
| - setTimeout(callback.bind(null, this.createCopy_(pref)));
|
| + var copy = deepCopy(pref);
|
| + setTimeout(callback.bind(null, copy));
|
| },
|
|
|
| // Functions used by tests.
|
|
|
| - /** Instructs the API to fail when setPref is next called. */
|
| + /** Instructs the API to return a failure when setPref is next called. */
|
| failNextSetPref: function() {
|
| this.failNextSetPref_ = true;
|
| },
|
|
|
| + /** Instructs the API to assert (fail the test) if setPref is called. */
|
| + disallowSetPref: function() {
|
| + this.disallowSetPref_ = true;
|
| + },
|
| +
|
| + allowSetPref: function() {
|
| + this.disallowSetPref_ = false;
|
| + },
|
| +
|
| /**
|
| * Notifies the listener of pref changes.
|
| * @param {!Array<string>} keys
|
| @@ -97,11 +120,13 @@ cr.define('cr_settings_prefs', function() {
|
| for (var i = 0; i < keys.length; i++) {
|
| var key = keys[i];
|
| var pref = this.prefs[key];
|
| + assertNotEquals(undefined, pref);
|
| pref.value = values[i];
|
| - prefs.push(this.createCopy_(pref));
|
| + prefs.push(deepCopy(pref));
|
| }
|
|
|
| - setTimeout(this.listener_.bind(null, prefs));
|
| + this.listener_(prefs);
|
| +// setTimeout(this.listener_.bind(null, prefs));
|
| },
|
|
|
| // Private methods for use by the mock API.
|
| @@ -144,12 +169,11 @@ cr.define('cr_settings_prefs', function() {
|
| },
|
|
|
| /**
|
| - * Creates a deep copy of the preference.
|
| - * @param {chrome.settingsPrivate.PrefObject} pref
|
| - * @return {chrome.settingsPrivate.PrefObject}
|
| + * @param {string} key
|
| + * @param {!Array} value
|
| */
|
| - createCopy_: function(pref) {
|
| - return JSON.parse(JSON.stringify(pref));
|
| + addListPref_: function(key, value) {
|
| + this.addPref_(chrome.settingsPrivate.PrefType.LIST, key, value);
|
| },
|
| };
|
|
|
| @@ -170,6 +194,79 @@ cr.define('cr_settings_prefs', function() {
|
| });
|
| }
|
|
|
| + // Pseudo-random number generator using Fibonacci LFSR.
|
| + function getPseudoRand() {
|
| + // Start with any integer in [1, 65535].
|
| + var lfsr = 3465; // Chromium's melting point (F).
|
| + var bit;
|
| + return function() {
|
| + bit = ((lfsr >> 0) ^ (lfsr >> 2) ^ (lfsr >> 3) ^ (lfsr >> 5) ) & 1;
|
| + lfsr = (lfsr >> 1) | (bit << 15);
|
| + return lfsr;
|
| + };
|
| + }
|
| +
|
| + function generateList(length, valueType, rand) {
|
| + var list = [];
|
| + for (var i = 0; i < length; i++) {
|
| + if (valueType == Boolean) {
|
| + list.push(Boolean(rand() % 2));
|
| + } else if (valueType == Number) {
|
| + list.push(rand());
|
| + } else if (valueType == String) {
|
| + // Allow empty strings.
|
| + list.push(generateString(rand() % 20, rand));
|
| + } else if (valueType == Object) {
|
| + // Don't allow empty objects.
|
| + list.push(generateObject(rand() % 2 + 1, rand));
|
| + }
|
| + }
|
| +
|
| + return list;
|
| + };
|
| +
|
| + function generateString(length, rand) {
|
| + var s = '';
|
| + for (var i = 0; i < length; i++)
|
| + s += String.fromCharCode(65 + rand() % 26);
|
| + return s;
|
| + }
|
| +
|
| + function generateObject(numProps, rand) {
|
| + var obj = {};
|
| + var types = [Boolean, Number, String, Array];
|
| + var typesIndex = 0;
|
| + for (var i = 0; i < numProps; i++) {
|
| + var prop;
|
| + do {
|
| + prop = generateString(rand() % 20 + 1, rand);
|
| + } while (obj[prop] != undefined);
|
| + switch(types[typesIndex++ % types.length]) {
|
| + case Boolean:
|
| + obj[prop] = Boolean(rand() % 2);
|
| + break;
|
| + case Number:
|
| + obj[prop] = rand();
|
| + break;
|
| + case String:
|
| + obj[prop] = generateString(rand() % 20, rand);
|
| + break;
|
| + case Array:
|
| + // Generate a list of booleans, numbers or strings.
|
| + obj[prop] = generateList(rand() % 10, types[rand() % 3], rand);
|
| + break;
|
| + }
|
| + }
|
| + return obj;
|
| + }
|
| +/*
|
| + var pref = {
|
| + type: 'LIST',
|
| + key: key,
|
| + value: list
|
| + };
|
| + */
|
| +
|
| function registerTests() {
|
| suite('CrSettingsPrefs', function() {
|
| /**
|
| @@ -229,7 +326,7 @@ cr.define('cr_settings_prefs', function() {
|
|
|
| expectEquals(expectedPref.key, actualPref.key);
|
| expectEquals(expectedPref.type, actualPref.type);
|
| - if (expectedPref.type != chrome.settingsPrivate.LIST) {
|
| + if (expectedPref.type != chrome.settingsPrivate.PrefType.LIST) {
|
| expectEquals(expectedPref.value, actualPref.value);
|
| } else {
|
| expectEquals(JSON.stringify(expectedPref.value),
|
| @@ -238,7 +335,10 @@ cr.define('cr_settings_prefs', function() {
|
| }
|
| });
|
|
|
| - test('forwards pref changes to API', function() {
|
| + test('forwards pref changes to API', function(done) {
|
| + var rand = getPseudoRand();
|
| + rand();rand();
|
| +
|
| // Test that cr-settings-prefs uses the setPref API.
|
| prefs.set('prefs.browser.enable_flash.value', true);
|
| expectTrue(mockApi.prefs['browser.enable_flash'].value);
|
| @@ -246,17 +346,39 @@ cr.define('cr_settings_prefs', function() {
|
| expectEquals(1.2, mockApi.prefs['device.overclock'].value);
|
| prefs.set('prefs.homepage.value', 'chromium.org');
|
| expectEquals('chromium.org', mockApi.prefs['homepage'].value);
|
| -
|
| - // Test that when setPref fails, the pref is reverted locally.
|
| - mockApi.failNextSetPref();
|
| - prefs.set('prefs.browser.enable_flash.value', false);
|
| - mockApi.failNextSetPref();
|
| - prefs.set('prefs.device.overclock.value', 2.0);
|
| - mockApi.failNextSetPref();
|
| - prefs.set('prefs.homepage.value', 'invalid-url');
|
| + var list = generateList(10, String, rand);
|
| + prefs.set('prefs.languages.value', deepCopy(list));
|
| + expectEquals(JSON.stringify(list),
|
| + JSON.stringify(mockApi.prefs['languages'].value));
|
| + var newList = deepCopy(mockApi.prefs['content.sites'].value);
|
| + var dict = newList[1];
|
| + var prop = Object.keys(dict)[0];
|
| + // Set a property (and append _ to ensure the value is different)
|
| + dict[prop] = generateString(10, rand) + '_';
|
| +// var listOfDicts = generateList(3, Object, rand);
|
| + prefs.set('prefs.content.sites.value', deepCopy(newList));
|
| + expectEquals(JSON.stringify(newList),
|
| + JSON.stringify(mockApi.prefs['content.sites'].value));
|
| + PolymerTest.async(function() {
|
| + mockApi.disallowSetPref();
|
| + prefs.set('prefs.content.sites.value', deepCopy(newList));
|
| + mockApi.allowSetPref();
|
| +
|
| + // Test that when setPref fails, the pref is reverted locally.
|
| + mockApi.failNextSetPref();
|
| + prefs.set('prefs.browser.enable_flash.value', false);
|
| + mockApi.failNextSetPref();
|
| + prefs.set('prefs.device.overclock.value', 2.0);
|
| + mockApi.failNextSetPref();
|
| + prefs.set('prefs.homepage.value', 'invalid-url');
|
| + mockApi.failNextSetPref();
|
| + prefs.set('prefs.languages.value', generateList(10, String, rand));
|
| + mockApi.failNextSetPref();
|
| + prefs.set('prefs.content.sites.value', generateList(3, Object, rand));
|
| + }).async(function() {
|
|
|
| // Multiple asynchronous round trips need to happen.
|
| - return Promise.all([
|
| + Promise.all([
|
| waitUntilTrue(function() {
|
| return prefs.prefs.browser.enable_flash.value;
|
| }),
|
| @@ -266,19 +388,101 @@ cr.define('cr_settings_prefs', function() {
|
| waitUntilTrue(function() {
|
| return prefs.prefs.homepage.value == 'chromium.org';
|
| }),
|
| - ]);
|
| + waitUntilTrue(function() {
|
| + return JSON.stringify(prefs.prefs.languages.value) ==
|
| + JSON.stringify(list);
|
| + }),
|
| + waitUntilTrue(function() {
|
| + return JSON.stringify(prefs.prefs.content.sites.value) ==
|
| + JSON.stringify(newList);
|
| + }),
|
| + ]).then(function() {
|
| + done();
|
| + });
|
| + });
|
| });
|
|
|
| test('responds to API changes', function(done) {
|
| - mockApi.sendPrefChanges(['top_level_pref'], [false]);
|
| - PolymerTest.async(function() {
|
| - expectEquals(false, prefs.prefs.top_level_pref.value);
|
| + var rand = getPseudoRand();
|
|
|
| - mockApi.sendPrefChanges(['top_level_pref'], [true]);
|
| + var topLevelPref = false;
|
| + var contentSites = generateList(2, Object, rand);
|
| + contentSites = [{E: 'e', F: 'ff'}, {G: true, H: false}];
|
| +
|
| + mockApi.disallowSetPref();
|
| + PolymerTest.async(function() {
|
| + mockApi.sendPrefChanges(['top_level_pref', 'content.sites'],
|
| + [topLevelPref, deepCopy(contentSites)]);
|
| }).async(function() {
|
| - expectEquals(true, prefs.prefs.top_level_pref.value);
|
| - done();
|
| - });
|
| + expectEquals(topLevelPref, prefs.prefs.top_level_pref.value);
|
| + expectEquals(JSON.stringify(contentSites),
|
| + JSON.stringify(prefs.prefs.content.sites.value));
|
| +
|
| + topLevelPref = true;
|
| + var oldContentSites = contentSites;
|
| + contentSites = deepCopy(contentSites);
|
| + var dict = contentSites[1];
|
| + var prop = Object.keys(contentSites[1])[0];
|
| + // Set a property (and append _ to ensure the value is different)
|
| + dict[prop] = generateString(10, rand) + '_';
|
| + mockApi.sendPrefChanges(['top_level_pref', 'content.sites'],
|
| + [topLevelPref, deepCopy(contentSites)]);
|
| + }).async(function() {
|
| + expectEquals(topLevelPref, prefs.prefs.top_level_pref.value);
|
| + expectEquals(JSON.stringify(contentSites),
|
| + JSON.stringify(prefs.prefs.content.sites.value));
|
| + }).async(function() {
|
| + // Shouldn't respond to non-changes.
|
| + mockApi.disallowSetPref();
|
| + mockApi.sendPrefChanges(['top_level_pref', 'content.sites'],
|
| + [topLevelPref, deepCopy(contentSites)]);
|
| + }).async(function() {}
|
| + ).async(done);
|
| + });
|
| + });
|
| +
|
| + suite('pseudo-random number generator', function() {
|
| + test('generates pseudo-random numbers', function() {
|
| + var numbers = {};
|
| + var rand1 = getPseudoRand();
|
| + var rand2 = getPseudoRand();
|
| + for (var i = 0; i < 1000; i++) {
|
| + var num1 = rand1();
|
| + var num2 = rand2();
|
| + // Generators should have the same seed and algorithm.
|
| + expectEquals(num1, num2);
|
| + // Generator shouldn't cycle in the first few numbers.
|
| + expectEquals(undefined, numbers[num1]);
|
| + numbers[num1] = true;
|
| + }
|
| + });
|
| + });
|
| +
|
| + suite('list generator', function() {
|
| + var rand;
|
| +
|
| + function checkList(length, type) {
|
| + var list = generateList(length, type, rand);
|
| + expectEquals(length, list.length);
|
| + for (var i = 0; i < length; i++)
|
| + expectEquals(typeof list[i], type.name.toLowerCase());
|
| + return list;
|
| + }
|
| +
|
| + setup(function() {
|
| + rand = getPseudoRand();
|
| + });
|
| +
|
| + test('flat lists', function() {
|
| + checkList(10, Boolean);
|
| + checkList(20, Number);
|
| + checkList(5, String);
|
| + });
|
| +
|
| + test('object lists', function() {
|
| + var list = checkList(40, Object);
|
| + for (var i = 0; i < 40; i++)
|
| + expectGT(Object.keys(list[i]).length, 0);
|
| });
|
| });
|
| }
|
|
|