Bug 906139 - Preserve unknown fields found in downloads.json. r=paolo

This commit is contained in:
Neil Deakin 2013-09-13 11:10:24 +02:00
parent 23ce61e5d5
commit 6fed774f8a
2 changed files with 140 additions and 8 deletions

View File

@ -92,6 +92,36 @@ function isString(aValue) {
(typeof aValue == "object" && "charAt" in aValue);
}
/**
* Serialize the unknown properties of aObject into aSerializable.
*/
function serializeUnknownProperties(aObject, aSerializable)
{
if (aObject._unknownProperties) {
for (let property in aObject._unknownProperties) {
aSerializable[property] = aObject._unknownProperties[property];
}
}
}
/**
* Check for any unknown properties in aSerializable and preserve those in the
* _unknownProperties field of aObject. aFilterFn is called for each property
* name of aObject and should return true only for unknown properties.
*/
function deserializeUnknownProperties(aObject, aSerializable, aFilterFn)
{
for (let property in aSerializable) {
if (aFilterFn(property)) {
if (!aObject._unknownProperties) {
aObject._unknownProperties = { };
}
aObject._unknownProperties[property] = aSerializable[property];
}
}
}
/**
* This determines the minimum time interval between updates to the number of
* bytes transferred, and is a limiting factor to the sequence of readings used
@ -838,11 +868,13 @@ Download.prototype = {
// These are serialized unless they are false, null, or empty strings.
for (let property of kSerializableDownloadProperties) {
if (property != "error" && this[property]) {
if (property != "error" && property != "startTime" && this[property]) {
serializable[property] = this[property];
}
}
serializeUnknownProperties(this, serializable);
return serializable;
},
@ -933,6 +965,13 @@ Download.fromSerializable = function (aSerializable) {
}
}
deserializeUnknownProperties(download, aSerializable, property =>
kSerializableDownloadProperties.indexOf(property) == -1 &&
property != "startTime" &&
property != "source" &&
property != "target" &&
property != "saver");
return download;
};
@ -971,7 +1010,7 @@ DownloadSource.prototype = {
toSerializable: function ()
{
// Simplify the representation if we don't have other details.
if (!this.isPrivate && !this.referrer) {
if (!this.isPrivate && !this.referrer && !this._unknownProperties) {
return this.url;
}
@ -982,6 +1021,8 @@ DownloadSource.prototype = {
if (this.referrer) {
serializable.referrer = this.referrer;
}
serializeUnknownProperties(this, serializable);
return serializable;
},
};
@ -1020,7 +1061,11 @@ DownloadSource.fromSerializable = function (aSerializable) {
if ("referrer" in aSerializable) {
source.referrer = aSerializable.referrer;
}
deserializeUnknownProperties(source, aSerializable, property =>
property != "url" && property != "isPrivate" && property != "referrer");
}
return source;
};
@ -1054,12 +1099,14 @@ DownloadTarget.prototype = {
toSerializable: function ()
{
// Simplify the representation if we don't have other details.
if (!this.partFilePath) {
if (!this.partFilePath && !this._unknownProperties) {
return this.path;
}
return { path: this.path,
partFilePath: this.partFilePath };
let serializable = { path: this.path,
partFilePath: this.partFilePath };
serializeUnknownProperties(this, serializable);
return serializable;
},
};
@ -1072,6 +1119,7 @@ DownloadTarget.prototype = {
* object with the following properties:
* {
* path: String containing the path of the target file.
* partFilePath: optional string containing the part file path.
* }
*
* @return The newly created DownloadTarget object.
@ -1091,6 +1139,9 @@ DownloadTarget.fromSerializable = function (aSerializable) {
if ("partFilePath" in aSerializable) {
target.partFilePath = aSerializable.partFilePath;
}
deserializeUnknownProperties(target, aSerializable, property =>
property != "path" && property != "partFilePath");
}
return target;
};
@ -1598,12 +1649,14 @@ DownloadCopySaver.prototype = {
toSerializable: function ()
{
// Simplify the representation if we don't have other details.
if (!this.entityID) {
if (!this.entityID && !this._unknownProperties) {
return "copy";
}
return { type: "copy",
entityID: this.entityID };
let serializable = { type: "copy",
entityID: this.entityID };
serializeUnknownProperties(this, serializable);
return serializable;
},
};
@ -1621,6 +1674,10 @@ DownloadCopySaver.fromSerializable = function (aSerializable) {
if ("entityID" in aSerializable) {
saver.entityID = aSerializable.entityID;
}
deserializeUnknownProperties(saver, aSerializable, property =>
property != "entityID" && property != "type");
return saver;
};

View File

@ -215,3 +215,78 @@ add_task(function test_load_string_malformed()
do_check_eq(items.length, 0);
});
/**
* Saves downloads with unknown properties to a file and then reloads
* them to ensure that these properties are preserved.
*/
add_task(function test_save_reload_unknownProperties()
{
let [listForSave, storeForSave] = yield promiseNewListAndStore();
let [listForLoad, storeForLoad] = yield promiseNewListAndStore(
storeForSave.path);
let download1 = yield promiseNewDownload(httpUrl("source.txt"));
// startTime should be ignored as it is a known property, and error
// is ignored by serialization
download1._unknownProperties = { peanut: "butter",
orange: "marmalade",
startTime: 77,
error: { message: "Passed" } };
listForSave.add(download1);
let download2 = yield promiseStartLegacyDownload();
yield download2.cancel();
download2._unknownProperties = { number: 5, object: { test: "string" } };
listForSave.add(download2);
let download3 = yield Downloads.createDownload({
source: { url: httpUrl("empty.txt"),
referrer: TEST_REFERRER_URL,
source1: "download3source1",
source2: "download3source2" },
target: { path: getTempFile(TEST_TARGET_FILE_NAME).path,
target1: "download3target1",
target2: "download3target2" },
saver : { type: "copy",
saver1: "download3saver1",
saver2: "download3saver2" },
});
listForSave.add(download3);
yield storeForSave.save();
yield storeForLoad.load();
let itemsForSave = yield listForSave.getAll();
let itemsForLoad = yield listForLoad.getAll();
do_check_eq(itemsForSave.length, itemsForLoad.length);
do_check_eq(Object.keys(itemsForLoad[0]._unknownProperties).length, 2);
do_check_eq(itemsForLoad[0]._unknownProperties.peanut, "butter");
do_check_eq(itemsForLoad[0]._unknownProperties.orange, "marmalade");
do_check_false("startTime" in itemsForLoad[0]._unknownProperties);
do_check_false("error" in itemsForLoad[0]._unknownProperties);
do_check_eq(Object.keys(itemsForLoad[1]._unknownProperties).length, 2);
do_check_eq(itemsForLoad[1]._unknownProperties.number, 5);
do_check_eq(itemsForLoad[1]._unknownProperties.object.test, "string");
do_check_eq(Object.keys(itemsForLoad[2].source._unknownProperties).length, 2);
do_check_eq(itemsForLoad[2].source._unknownProperties.source1,
"download3source1");
do_check_eq(itemsForLoad[2].source._unknownProperties.source2,
"download3source2");
do_check_eq(Object.keys(itemsForLoad[2].target._unknownProperties).length, 2);
do_check_eq(itemsForLoad[2].target._unknownProperties.target1,
"download3target1");
do_check_eq(itemsForLoad[2].target._unknownProperties.target2,
"download3target2");
do_check_eq(Object.keys(itemsForLoad[2].saver._unknownProperties).length, 2);
do_check_eq(itemsForLoad[2].saver._unknownProperties.saver1,
"download3saver1");
do_check_eq(itemsForLoad[2].saver._unknownProperties.saver2,
"download3saver2");
});