UNPKG

serialijse

Version:

serialize and deserialize your javascript objects, preserve your object model

570 lines (402 loc) 19.2 kB
/*global describe, it*/ var should; if (typeof require !== "undefined") { should = require("should"); var serialijse = require("../"); } var serialize = serialijse.serialize; var deserialize = serialijse.deserialize; var declarePersistable = serialijse.declarePersistable; var serializeZ = serialijse.serializeZ; var deserializeZ = serialijse.deserializeZ; (function () { "use strict"; function Color(colorName) { this.name = colorName; } function Vehicule() { this.brand = "Fiat"; this.price = 10000.05; this.color = new Color("blue"); this.created_on = new Date("04 May 1956 GMT"); this.second_hand = false } declarePersistable(Vehicule); declarePersistable(Color); describe("persistence ", function () { it("should serialize true", function () { var bool = true; var serializationString = serialize(bool); var reconstructedObject = deserialize(serializationString); reconstructedObject.should.eql(true); }); it("should serialize false", function () { var serializationString = serialize(false); var reconstructedObject = deserialize(serializationString); reconstructedObject.should.eql(false); }); it("should serialize string", function () { var str = "Vehicule"; var serializationString = serialize(str); var reconstructedObject = deserialize(serializationString); reconstructedObject.should.eql(str); }); it("should serialize number", function () { var pi = Math.PI var serializationString = serialize(pi); var reconstructedObject = deserialize(serializationString); reconstructedObject.should.eql(pi); }); it("should serialize null", function () { var serializationString = serialize(null); var reconstructedObject = deserialize(serializationString); should.equal(reconstructedObject, null); }); it("should fail to serialize undefined", function () { should.throws(function() {serialize(undefined)}); }); it("should persist a simple javascript object (pojo)", function () { var vehicule = { name: "GM" }; var serializationString = serialize(vehicule); //xx console.log(serializationString); var reconstructedObject = deserialize(serializationString); reconstructedObject.should.eql(vehicule); }); it("should persist a javascript class instance", function () { var vehicule = new Vehicule(); vehicule.brand = "Renault"; vehicule.price = 95000; vehicule.created_on = new Date("04 May 1949 22:00:00 GMT"); vehicule.should.be.instanceOf(Vehicule); var serializationString = serialize(vehicule); //xx console.log(serializationString); var reconstructedObject = deserialize(serializationString); reconstructedObject.should.eql(vehicule); reconstructedObject.should.be.instanceOf(Vehicule); }); it("should persist a simple object containing an array", function () { var vehicule = new Vehicule(); vehicule.passengers = ["Joe", "Jack"]; var serializationString = serialize(vehicule); //xx console.log(serializationString); var reconstructedObject = deserialize(serializationString); reconstructedObject.should.eql(vehicule); }); it("should persist a array of persistable objects", function () { var vehicules = [new Vehicule(), new Vehicule()]; vehicules[0].brand = "Renault"; vehicules[0].price = 95000; vehicules[0].created_on = new Date("Wed, 04 May 1949 22:00:00 GMT"); var serializationString = serialize(vehicules); //xx console.log(serializationString); var reconstructedObject = deserialize(serializationString); reconstructedObject.should.eql(vehicules); }); it("should persist a array containing two elements pointing to the same object ", function () { var the_vehicule = new Vehicule(); the_vehicule.brand = "Citroen"; the_vehicule.price = 95000; the_vehicule.created_on = new Date("Wed, 04 May 1949 22:00:00 GMT"); var vehicules = [the_vehicule, the_vehicule]; vehicules[0].should.equal(vehicules[1]); var serializationString = serialize(vehicules); should(the_vehicule.____index).eql(undefined); var expected = `[[{"c":"Vehicule","d":{"brand":"Citroen","price":95000,"color":{"o":1},"created_on":{"d":-651981600000},"second_hand":false}},{"c":"Color","d":{"name":"blue"}}],{"a":[{"o":0},{"o":0}]}]`; serializationString.should.eql(expected); //xx console.log(serializationString); var reconstructedObject = deserialize(serializationString); reconstructedObject.length.should.eql(2); reconstructedObject[0].should.equal(reconstructedObject[1]); reconstructedObject.should.eql(vehicules); }); it("should not persist property defined in class prototype", function () { function Rectangle() { this.width = 10; this.height = 20; Object.defineProperty(this, "area", { get: function () { return this.width * this.height; } }); } Rectangle.prototype.__defineGetter__("perimeter", function () { return (this.width + this.height) * 2.0; }); declarePersistable(Rectangle); var rect1 = new Rectangle(); rect1.width = 100; rect1.height = 2; rect1.area.should.equal(200); rect1.perimeter.should.equal(204); var serializationString = serialize(rect1); //xx console.log(serializationString); var rect2 = deserialize(serializationString); rect2.area.should.equal(200); rect2.perimeter.should.equal(204); }); it("testing compression impact ", function (done) { var vehicules = [new Vehicule(), new Vehicule(), new Vehicule()]; var uncompressed_serializationString = serialize(vehicules); serializeZ(vehicules, function (err, buffer) { //xx var serializationString = buffer.toString("base64"); var compression_ratio = Math.round(100.0 - 100.0 * (buffer.length / uncompressed_serializationString.length)); // console.log(" = ", uncompressed_serializationString.length, "compressed =", buffer.length, " ratio ", compression_ratio, "%"); deserializeZ(buffer, function (err, reconstructedObject) { done(err); reconstructedObject.should.eql(vehicules); }); }); }); it("should persist object with boolean", function (done) { var vehicule = new Vehicule(); vehicule.requireServicing = true; var serializationString = serialize(vehicule); //xx console.log(serializationString); var reconstructedObject = deserialize(serializationString); reconstructedObject.should.eql(vehicule); vehicule.requireServicing.should.equal(true); done(); }); it("should persist an object with an undefined property", function (done) { var vehicule = new Vehicule(); vehicule.serviceDate = [null, new Date("2013/01/02")]; // try to mess with the serialisation algo by adding a fake null property vehicule.toto = null; var serializationString = serialize(vehicule); var reconstructedObject = deserialize(serializationString); reconstructedObject.should.eql(vehicule); done(); }); it("should deserialize an already parsed JSON string", function (done) { var vehicule = new Vehicule(); var serializationString = serialize(vehicule); var json_obj = JSON.parse(serializationString); var reconstructedObject = deserialize(json_obj); reconstructedObject.should.eql(vehicule); done(); }); it("unlike JSON.stringify/parse, it should serialize a standard object and preserve date", function () { var some_object = { the_date: new Date() }; some_object.the_date.should.be.instanceOf(Date); var serializationString = serialize(some_object); var reconstructedObject = deserialize(serializationString); reconstructedObject.the_date.should.be.instanceOf(Date); reconstructedObject.the_date.should.eql(some_object.the_date); reconstructedObject.should.eql(some_object); reconstructedObject.should.eql(some_object); }); it("unlike JSON.stringify/parse, it should persist object that contains cyclic object value", function () { function Person(name) { this.name = name; this.parent = null; this.children = []; } declarePersistable(Person); Person.prototype.addChild = function (name) { var child = new Person(name); child.parent = this; this.children.push(child); return child; }; var mark = new Person("mark"), valery = mark.addChild("valery"), edgar = mark.addChild("edgar"); valery.parent.should.equal(mark); edgar.parent.should.equal(mark); should(function () { JSON.stringify(mark); }).throwError(); // Circular var serializationString = serialize(mark); //xx console.log(serializationString); var mark_reloaded = deserialize(serializationString); mark_reloaded.name.should.eql("mark"); mark_reloaded.children.length.should.eql(2); mark_reloaded.should.be.instanceOf(Person); mark_reloaded.children[0].should.be.instanceOf(Person); mark_reloaded.children[1].should.be.instanceOf(Person); mark_reloaded.children[0].parent.should.equal(mark_reloaded); mark_reloaded.children[1].parent.should.equal(mark_reloaded); mark_reloaded.children[0].name.should.eql("valery"); mark_reloaded.children[1].name.should.eql("edgar"); }); function MyClassWithUnpersistableMembers() { this.name = "unset"; this._cache = []; this.$someOtherStuff = 0; } MyClassWithUnpersistableMembers.serialijseOptions = { ignored: [ "_cache", /$.*/ ] }; declarePersistable(MyClassWithUnpersistableMembers); it("should not persist un-persistable members", function () { var obj = new MyClassWithUnpersistableMembers(); obj._cache = [1, 2, 3]; obj.$someOtherStuff = 35; obj.name = "Hello"; obj.$$key = "24"; var serializationString = serialize(obj); var json_obj = JSON.parse(serializationString); var reconstructedObject = deserialize(json_obj); should.exist(reconstructedObject.name); should.exist(reconstructedObject._cache); should.exist(reconstructedObject.$someOtherStuff); should.not.exist(reconstructedObject.$$key); reconstructedObject._cache.should.eql([]); reconstructedObject.$someOtherStuff.should.eql(0); }); function MyClassWithPostDeserializeAction() { this.name = "unset"; this._cache = []; } MyClassWithPostDeserializeAction.prototype.reconstructCache = function () { this._cache.push("reconstructCache has been called"); }; MyClassWithPostDeserializeAction.serialijseOptions = { ignored: [ "_cache" ], onPostDeserialize: function (o) { o.reconstructCache(); } }; declarePersistable(MyClassWithPostDeserializeAction); it("should run onPostDeserialize during deserialization", function () { var obj = new MyClassWithPostDeserializeAction(); obj._cache.push(36); var serializationString = serialize(obj); var reconstructedObject = deserialize(serializationString); reconstructedObject._cache.should.eql(["reconstructCache has been called"]); }); it("should persist typed array such as Float32Array", function () { var obj = { float32: new Float32Array([1, 2, 3, 5, 6, 10, 100]), uint32: new Int32Array([1, 2, 3, 5, 6, 10, 100]) }; obj.float32[5].should.eql(10.0); obj.float32[6].should.eql(100); obj.uint32[5].should.eql(10.0); obj.uint32[6].should.eql(100); var serializationString = serialize(obj); //xx console.log("serializationString", serializationString); var reconstructedObject = deserialize(serializationString); reconstructedObject.float32.should.be.instanceOf(Float32Array); reconstructedObject.uint32.should.be.instanceOf(Int32Array); reconstructedObject.float32.length.should.eql(obj.float32.length); reconstructedObject.uint32.length.should.eql(obj.uint32.length); reconstructedObject.float32[5].should.eql(10.0); reconstructedObject.float32[6].should.eql(100); reconstructedObject.uint32[5].should.eql(10.0); reconstructedObject.uint32[6].should.eql(100); }); it("should be possible to filter out member we don't want to serialize at any level (such as $$ angular extra prop)", function () { var obj = { name: "foo", $$key: 1, address: { city: "Paris", $$key: 2, } }; var data = serialize(obj, { ignored: [/^\$\$.*/] }); var obj2 = deserialize(data); obj2.should.have.property("name"); obj2.should.have.property("address"); obj2.address.should.have.property("city"); obj2.should.not.have.property("$$key"); obj2.address.should.not.have.property("$$key"); }); it("should persist a Map", () => { const obj = { map: new Map() }; obj.map.set("A", 1); obj.map.set("B", { c: "d" }); obj.map.set("C", obj.map); /// << Circumar const serializationString = serialize(obj); const reconstructedObject = deserialize(serializationString); reconstructedObject.map.should.be.instanceOf(Map); reconstructedObject.map.get("A").should.eql(1); reconstructedObject.map.get("B").should.eql({c:"d"}); reconstructedObject.map.get("C").should.eql(reconstructedObject.map); }) it("should persist a Set", () => { const obj = { c: { c: "d"}, set: new Set() }; obj.d = { d: obj.set }; obj.set.add("A"); obj.set.add(obj.c); obj.set.add(obj.d); const serializationString = serialize(obj); const reconstructedObject = deserialize(serializationString); // xx console.log(serializationString); // xx console.log(reconstructedObject); reconstructedObject.set.has("A").should.eql(true); reconstructedObject.set.has(reconstructedObject.c).should.eql(true); }); it("should persist a Uint8Array", ()=>{ const obj = new Uint8Array([1,2,3,4]); const serializationString = serialize(obj); const reconstructedObject = deserialize(serializationString); reconstructedObject.should.be.instanceof(Uint8Array); obj.toString().should.eql(reconstructedObject.toString()); }); it("should persist a Uint16Array", ()=>{ const obj = new Uint16Array([1,2,3,4]); const serializationString = serialize(obj); const reconstructedObject = deserialize(serializationString); reconstructedObject.should.be.instanceof(Uint16Array); obj.toString().should.eql(reconstructedObject.toString()); }) it("should persist a Uint32Array", ()=>{ const obj = new Uint32Array([1,2,3,4]); const serializationString = serialize(obj); const reconstructedObject = deserialize(serializationString); reconstructedObject.should.be.instanceof(Uint32Array); obj.toString().should.eql(reconstructedObject.toString()); }) it("should persist a Float32Array", ()=>{ const obj = new Float32Array([1,2,3,4]); const serializationString = serialize(obj); const reconstructedObject = deserialize(serializationString); reconstructedObject.should.be.instanceof(Float32Array); obj.toString().should.eql(reconstructedObject.toString()); }) it("should persist a Float64Array", ()=>{ const obj = new Float64Array([1,2,3,4]); const serializationString = serialize(obj); const reconstructedObject = deserialize(serializationString); reconstructedObject.should.be.instanceof(Float64Array); obj.toString().should.eql(reconstructedObject.toString()); }); it("onDeserialize options", ()=>{ function SomeClassXYZ() { this.name = "unset"; this._cache = []; this.$someOtherStuff = 0; } SomeClassXYZ.serialijseOptions = { ignored: [ "_cache", /$.*/ ], onDeserialize: (o) =>{ o._wasHere =true; } }; declarePersistable(SomeClassXYZ); const rect1 = new SomeClassXYZ(); rect1.name = "100"; const serializationString = serialize(rect1); const rect2 = deserialize(serializationString); rect2._wasHere.should.eql(true); }) }); }());