303 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			303 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
// @flow
 | 
						|
import {
 | 
						|
  serialize,
 | 
						|
  deserialize,
 | 
						|
  registerSerializableClass,
 | 
						|
  unregisterSerializableClass,
 | 
						|
} from '../src/serializer';
 | 
						|
import assert from 'assert';
 | 
						|
import sinon from 'sinon';
 | 
						|
 | 
						|
describe('serializer', () => {
 | 
						|
  it('should serialize a basic object', () => {
 | 
						|
    let serialized = serialize({foo: 2, bar: 3});
 | 
						|
    assert(Buffer.isBuffer(serialized));
 | 
						|
    let deserialized = deserialize(serialized);
 | 
						|
    assert.equal(typeof deserialized, 'object');
 | 
						|
    assert.deepEqual(deserialized, {foo: 2, bar: 3});
 | 
						|
  });
 | 
						|
 | 
						|
  it('should serialize an object with multiple references', () => {
 | 
						|
    let a = {foo: 2};
 | 
						|
    let b = {bar: a, baz: a};
 | 
						|
    let res = deserialize(serialize(b));
 | 
						|
    assert.deepEqual(res, b);
 | 
						|
    assert.equal(res.bar, res.baz);
 | 
						|
  });
 | 
						|
 | 
						|
  it('should serialize a cyclic object', () => {
 | 
						|
    let a = {foo: 2, bar: {}};
 | 
						|
    a.bar = a;
 | 
						|
    let res = deserialize(serialize(a));
 | 
						|
    assert.deepEqual(res, a);
 | 
						|
    assert.equal(res.bar, res);
 | 
						|
    assert.equal(a.bar, a);
 | 
						|
  });
 | 
						|
 | 
						|
  it('should serialize a Map', () => {
 | 
						|
    let a = new Map([[2, 3]]);
 | 
						|
    let res = deserialize(serialize(a));
 | 
						|
    assert(res instanceof Map);
 | 
						|
    assert.equal(res.get(2), 3);
 | 
						|
  });
 | 
						|
 | 
						|
  it('should serialize a Set', () => {
 | 
						|
    let a = new Set([2, 3]);
 | 
						|
    let res = deserialize(serialize(a));
 | 
						|
    assert(res instanceof Set);
 | 
						|
    assert(res.has(2));
 | 
						|
    assert(res.has(3));
 | 
						|
  });
 | 
						|
 | 
						|
  it('should serialize a class', () => {
 | 
						|
    class Test {
 | 
						|
      x: number;
 | 
						|
      constructor(x: number) {
 | 
						|
        this.x = x;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    registerSerializableClass('Test', Test);
 | 
						|
 | 
						|
    let x = new Test(2);
 | 
						|
    let res = deserialize(serialize(x));
 | 
						|
    assert(res instanceof Test);
 | 
						|
    assert.equal(res.x, x.x);
 | 
						|
 | 
						|
    unregisterSerializableClass('Test', Test);
 | 
						|
  });
 | 
						|
 | 
						|
  it('should serialize a class with a custom serialize method', () => {
 | 
						|
    class Test {
 | 
						|
      x: number;
 | 
						|
      constructor(x: number) {
 | 
						|
        this.x = x;
 | 
						|
      }
 | 
						|
 | 
						|
      serialize() {
 | 
						|
        return {
 | 
						|
          x: this.x,
 | 
						|
          serialized: true,
 | 
						|
        };
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    registerSerializableClass('Test', Test);
 | 
						|
 | 
						|
    let x = new Test(2);
 | 
						|
    let res = deserialize(serialize(x));
 | 
						|
    assert(res instanceof Test);
 | 
						|
    assert.equal(res.x, x.x);
 | 
						|
    assert.equal(res.serialized, true);
 | 
						|
 | 
						|
    unregisterSerializableClass('Test', Test);
 | 
						|
  });
 | 
						|
 | 
						|
  it('should serialize a class with a custom deserialize method', () => {
 | 
						|
    class Test {
 | 
						|
      x: number;
 | 
						|
      constructor(x: number) {
 | 
						|
        this.x = x;
 | 
						|
      }
 | 
						|
 | 
						|
      static deserialize(x: any) {
 | 
						|
        return {
 | 
						|
          deserialized: true,
 | 
						|
          value: x,
 | 
						|
        };
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    registerSerializableClass('Test', Test);
 | 
						|
 | 
						|
    let x = new Test(2);
 | 
						|
    let res = deserialize(serialize(x));
 | 
						|
    assert(!(res instanceof Test));
 | 
						|
    assert.equal(res.value.x, x.x);
 | 
						|
    assert.equal(res.deserialized, true);
 | 
						|
 | 
						|
    unregisterSerializableClass('Test', Test);
 | 
						|
  });
 | 
						|
 | 
						|
  it('should serialize a class recursively', () => {
 | 
						|
    class Foo {
 | 
						|
      x: number;
 | 
						|
      constructor(x: number) {
 | 
						|
        this.x = x;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    class Bar {
 | 
						|
      foo: Foo;
 | 
						|
      constructor(foo: Foo) {
 | 
						|
        this.foo = foo;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    registerSerializableClass('Foo', Foo);
 | 
						|
    registerSerializableClass('Bar', Bar);
 | 
						|
 | 
						|
    let x = new Bar(new Foo(2));
 | 
						|
    let res = deserialize(serialize(x));
 | 
						|
    assert(res instanceof Bar);
 | 
						|
    assert(res.foo instanceof Foo);
 | 
						|
    assert.equal(res.foo.x, 2);
 | 
						|
 | 
						|
    unregisterSerializableClass('Foo', Foo);
 | 
						|
    unregisterSerializableClass('Bar', Bar);
 | 
						|
  });
 | 
						|
 | 
						|
  it('should serialize a cyclic class', () => {
 | 
						|
    class Foo {
 | 
						|
      x: ?Foo;
 | 
						|
      constructor(x: ?Foo) {
 | 
						|
        this.x = x;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    registerSerializableClass('Foo', Foo);
 | 
						|
 | 
						|
    let x = new Foo();
 | 
						|
    x.x = x;
 | 
						|
 | 
						|
    let res = deserialize(serialize(x));
 | 
						|
    assert(res instanceof Foo);
 | 
						|
    assert(res.x instanceof Foo);
 | 
						|
    assert.equal(res.x, res);
 | 
						|
 | 
						|
    assert.equal(x.x, x);
 | 
						|
 | 
						|
    unregisterSerializableClass('Foo', Foo);
 | 
						|
  });
 | 
						|
 | 
						|
  it('should copy on write', () => {
 | 
						|
    class Foo {
 | 
						|
      x: number;
 | 
						|
      constructor(x: number) {
 | 
						|
        this.x = x;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    registerSerializableClass('Foo', Foo);
 | 
						|
 | 
						|
    let x = {y: {foo: new Foo(2)}};
 | 
						|
 | 
						|
    let res = deserialize(serialize(x));
 | 
						|
    assert(res.y.foo instanceof Foo);
 | 
						|
    assert(x.y.foo instanceof Foo);
 | 
						|
 | 
						|
    unregisterSerializableClass('Foo', Foo);
 | 
						|
  });
 | 
						|
 | 
						|
  it('should serialize a cyclic class and copy on write', () => {
 | 
						|
    class Foo {
 | 
						|
      x: ?Foo;
 | 
						|
      constructor(x: ?Foo) {
 | 
						|
        this.x = x;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    registerSerializableClass('Foo', Foo);
 | 
						|
 | 
						|
    let x = new Foo();
 | 
						|
    x.x = x;
 | 
						|
    let y = {x: {y: x}};
 | 
						|
 | 
						|
    let res = deserialize(serialize(y));
 | 
						|
    assert(res.x.y instanceof Foo);
 | 
						|
    assert(res.x.y.x instanceof Foo);
 | 
						|
    assert(y.x.y instanceof Foo);
 | 
						|
    assert(y.x.y.x instanceof Foo);
 | 
						|
    assert.equal(res.x.y.x, res.x.y);
 | 
						|
 | 
						|
    assert.equal(x.x, x);
 | 
						|
 | 
						|
    unregisterSerializableClass('Foo', Foo);
 | 
						|
  });
 | 
						|
 | 
						|
  it('should serialize a class inside a Map', () => {
 | 
						|
    class Test {
 | 
						|
      x: number;
 | 
						|
      constructor(x: number) {
 | 
						|
        this.x = x;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    registerSerializableClass('Test', Test);
 | 
						|
 | 
						|
    let x = new Map([[2, new Test(2)]]);
 | 
						|
    let res = deserialize(serialize(x));
 | 
						|
    assert(res instanceof Map);
 | 
						|
    assert(res.get(2) instanceof Test);
 | 
						|
 | 
						|
    unregisterSerializableClass('Test', Test);
 | 
						|
  });
 | 
						|
 | 
						|
  it('should serialize a class inside a Set', () => {
 | 
						|
    class Test {
 | 
						|
      x: number;
 | 
						|
      constructor(x: number) {
 | 
						|
        this.x = x;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    registerSerializableClass('Test', Test);
 | 
						|
 | 
						|
    let x = new Set([new Test(2)]);
 | 
						|
    let res = deserialize(serialize(x));
 | 
						|
    assert(res instanceof Set);
 | 
						|
    assert(res.values().next().value instanceof Test);
 | 
						|
 | 
						|
    unregisterSerializableClass('Test', Test);
 | 
						|
  });
 | 
						|
 | 
						|
  describe('raw values', () => {
 | 
						|
    class Outer {
 | 
						|
      inner: Inner;
 | 
						|
 | 
						|
      constructor(inner) {
 | 
						|
        this.inner = inner;
 | 
						|
      }
 | 
						|
 | 
						|
      serialize() {
 | 
						|
        return {
 | 
						|
          $$raw: true,
 | 
						|
          inner: this.inner,
 | 
						|
        };
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    class Inner {
 | 
						|
      x: number;
 | 
						|
 | 
						|
      constructor(x) {
 | 
						|
        this.x = x;
 | 
						|
      }
 | 
						|
 | 
						|
      static deserialize = sinon.spy();
 | 
						|
    }
 | 
						|
 | 
						|
    beforeEach(() => {
 | 
						|
      registerSerializableClass('Outer', Outer);
 | 
						|
      registerSerializableClass('Inner', Inner);
 | 
						|
    });
 | 
						|
 | 
						|
    afterEach(() => {
 | 
						|
      unregisterSerializableClass('Outer', Outer);
 | 
						|
      unregisterSerializableClass('Inner', Inner);
 | 
						|
    });
 | 
						|
 | 
						|
    it('should not recursively serialize raw values', () => {
 | 
						|
      let res = deserialize(serialize(new Outer(new Inner(42))));
 | 
						|
      assert(res instanceof Outer);
 | 
						|
      assert(!(res.inner instanceof Inner));
 | 
						|
      assert.equal(res.inner.x, 42);
 | 
						|
    });
 | 
						|
 | 
						|
    it('should not recursively deserialize raw values', () => {
 | 
						|
      deserialize(serialize(new Outer(new Inner(42))));
 | 
						|
      assert(Inner.deserialize.notCalled);
 | 
						|
    });
 | 
						|
  });
 | 
						|
});
 |