Adds shared util for isPlainObject and tests for kafka serializer.

This commit is contained in:
Michael Kaufman
2019-08-22 20:28:08 -04:00
parent dcbeb59596
commit be239b598b
4 changed files with 212 additions and 5 deletions

View File

@@ -8,8 +8,13 @@ import {
validatePath,
isNil,
isEmpty,
isPlainObject
} from '../../utils/shared.utils';
function Foo(a) {
this.a = 1;
}
describe('Shared utils', () => {
describe('isUndefined', () => {
it('should returns true when obj is undefined', () => {
@@ -38,6 +43,24 @@ describe('Shared utils', () => {
expect(isObject(undefined)).to.be.false;
});
});
describe('isPlainObject', () => {
it('should returns true when obj is plain object', () => {
expect(isPlainObject({})).to.be.true;
expect(isPlainObject({prop: true})).to.be.true;
expect(isPlainObject({
constructor: Foo
})).to.be.true;
expect(isPlainObject(Object.create(null))).to.be.true;
});
it('should returns false when object is not object', () => {
expect(isPlainObject(3)).to.be.false;
expect(isPlainObject(null)).to.be.false;
expect(isPlainObject(undefined)).to.be.false;
expect(isPlainObject([1, 2, 3])).to.be.false;
expect(isPlainObject(new Date())).to.be.false;
expect(isPlainObject(new Foo(1))).to.be.false;
});
});
describe('isString', () => {
it('should returns true when obj is string', () => {
expect(isString('true')).to.be.true;

View File

@@ -2,6 +2,21 @@ export const isUndefined = (obj: any): obj is undefined =>
typeof obj === 'undefined';
export const isObject = (fn: any): fn is object =>
!isNil(fn) && typeof fn === 'object';
export const isPlainObject = (fn: any): fn is object => {
if (!isObject(fn)) {
return false;
}
const proto = Object.getPrototypeOf(fn);
if (proto === null) {
return true;
}
const Ctor = Object.prototype.hasOwnProperty.call(proto, 'constructor') && proto.constructor;
return typeof Ctor === 'function' && Ctor instanceof Ctor && Function.prototype.toString.call(Ctor) === Function.prototype.toString.call(Object);
};
export const validatePath = (path?: string): string =>
path ? (path.charAt(0) !== '/' ? '/' + path : path) : '';
export const isFunction = (fn: any): boolean => typeof fn === 'function';

View File

@@ -1,4 +1,4 @@
import { isUndefined, isNil, isObject, isString, isFunction } from '@nestjs/common/utils/shared.utils';
import { isUndefined, isNil, isObject, isString, isFunction, isPlainObject } from '@nestjs/common/utils/shared.utils';
export class KafkaSerializer {
public static deserialize<T>(data: any): T {
@@ -57,13 +57,13 @@ export class KafkaSerializer {
public static encode(value: any): Buffer | string | null {
if (!isNil(value) && !isString(value) && !Buffer.isBuffer(value)) {
if (isObject(value) || Array.isArray(value)) {
if (isPlainObject(value) || Array.isArray(value)) {
// convert to stringified object
return JSON.stringify(value);
} else if (isFunction(value.toString)) {
// convert to string
return value.toString();
}
// convert to string
return value.toString();
} else if (isUndefined(value)) {
return null;
}

View File

@@ -0,0 +1,169 @@
import { expect } from 'chai';
import { KafkaSerializer } from '../../helpers/kafka-serializer';
import { KafkaHeaders } from '../../enums/kafka-headers.enum';
describe('kafka serializer', () => {
describe('serialize types', () => {
it('undefined', () => {
expect(KafkaSerializer.serialize(undefined)).to.deep.eq({
headers: {},
value: null
});
});
it('null', () => {
expect(KafkaSerializer.serialize(null)).to.deep.eq({
headers: {},
value: null
});
});
it('string', () => {
expect(KafkaSerializer.serialize('string')).to.deep.eq({
headers: {},
value: 'string'
});
});
it('number', () => {
expect(KafkaSerializer.serialize(12345)).to.deep.eq({
headers: {},
value: '12345'
});
});
it('buffer', () => {
expect(KafkaSerializer.serialize(Buffer.from('buffer'))).to.deep.eq({
headers: {},
value: Buffer.from('buffer')
});
});
it('array', () => {
expect(KafkaSerializer.serialize([1, 2, 3, 4, 5])).to.deep.eq({
headers: {},
value: '[1,2,3,4,5]'
});
});
it('object', () => {
expect(KafkaSerializer.serialize({
prop: 'value'
})).to.deep.eq({
headers: {},
value: '{"prop":"value"}'
});
});
it('complex object with .toString()', () => {
class Complex {
private name = 'complex';
public toString(): string {
return this.name;
}
}
expect(KafkaSerializer.serialize(new Complex())).to.deep.eq({
headers: {},
value: 'complex'
});
});
it('complex object without .toString()', () => {
class ComplexWithOutToString {
private name = 'complex';
}
expect(KafkaSerializer.serialize(new ComplexWithOutToString())).to.deep.eq({
headers: {},
value: '[object Object]'
});
});
});
describe('serialize kafka message', () => {
it('kafka message without key', () => {
expect(KafkaSerializer.serialize({
value: 'string'
})).to.deep.eq({
headers: {},
value: 'string'
});
});
it('kafka message with key', () => {
expect(KafkaSerializer.serialize({
key: '1',
value: 'string'
})).to.deep.eq({
headers: {},
key: '1',
value: 'string'
});
});
it('kafka message with headers', () => {
expect(KafkaSerializer.serialize({
key: '1',
value: 'string',
headers: {
[KafkaHeaders.CORRELATION_ID]: '1234'
}
})).to.deep.eq({
headers: {
[KafkaHeaders.CORRELATION_ID]: '1234'
},
key: '1',
value: 'string'
});
});
});
describe('deserialize', () => {
it('undefined', () => {
expect(KafkaSerializer.deserialize({
value: undefined
})).to.deep.eq({
value: null
});
});
it('null', () => {
expect(KafkaSerializer.deserialize({
value: null
})).to.deep.eq({
value: null
});
});
it('buffer string', () => {
expect(KafkaSerializer.deserialize({
value: Buffer.from('string')
})).to.deep.eq({
value: 'string'
});
});
it('buffer json', () => {
expect(KafkaSerializer.deserialize({
value: Buffer.from(JSON.stringify({prop: 'value'}))
})).to.deep.eq({
value: {
prop: 'value'
}
});
});
it('buffer json with key', () => {
expect(KafkaSerializer.deserialize({
value: Buffer.from(JSON.stringify({prop: 'value'})),
key: Buffer.from('1')
})).to.deep.eq({
key: 1,
value: {
prop: 'value'
}
});
});
});
});