Skip to content

Commit

Permalink
* improved test classes
Browse files Browse the repository at this point in the history
* renamed getProperty --> property
* renamed replaceProperty --> replaceValueOf
* renamed andDo --> withCloneAndDo
  • Loading branch information
Maier, Martin committed Jul 2, 2018
1 parent 0f07699 commit 11b74bd
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 126 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "typescript-immutable-helper",
"version": "0.5.0",
"version": "0.6.0",
"description": "Helpers for handling immutable objects with typescript",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
28 changes: 14 additions & 14 deletions src/replicator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as _ from 'lodash'
import {deepFreeze, isDeepFrozen} from './deepFreeze'

/**
* Class that helps to replicate a new object by encapsulating a deep copy of the source object
* Class that helps to replaceValueOf a new object by encapsulating a deep copy of the source object
* If input object is frozen by (@link Object.freeze()} or {@link deepFreeze} then the replica will be produced frozen
* freeze in --> deep freeze out
* Warns if source object is just frozen, not deep frozen
Expand All @@ -29,30 +29,30 @@ export class ReplicationBuilder<T> {

/**
* @deprecated since 0.4.1
* use getProperty instead
* use property instead
*/
public getChild<K extends keyof T>(childNode: K): ReplicaChildOperator<T, T[K]> {
return this.getProperty(childNode);
return this.property(childNode);
}

/** switch to child node
* @param {K} childNode of the root node
* @returns {ReplicaChildOperator<T, T[K]>} operator of child node
**/
public getProperty<K extends keyof T>(childNode: K): ReplicaChildOperator<T, T[K]> {
public property<K extends keyof T>(childNode: K): ReplicaChildOperator<T, T[K]> {
let node = this.replica[childNode];
return new ReplicaChildOperator((() => this.build()), this.replica, node, childNode)
}

/**
* @deprecated since 0.4.1
* use replaceProperty instead
* use replaceValueOf instead
*/
public modify<K extends keyof T>(childNode: K): PropertyModifier<ReplicationBuilder<T>, T[K]> {
return this.replaceProperty(childNode);
return this.replaceValueOf(childNode);
}

public replaceProperty<K extends keyof T>(childNode: K): PropertyModifier<ReplicationBuilder<T>, T[K]> {
public replaceValueOf<K extends keyof T>(childNode: K): PropertyModifier<ReplicationBuilder<T>, T[K]> {
return new PropertyModifier<ReplicationBuilder<T>, T[K]>(this, childNode, this.replica)
}

Expand Down Expand Up @@ -103,31 +103,31 @@ export class ReplicaChildOperator<RT, T> {

/**
* @deprecated since 0.4.1
* use getProperty instead
* use property instead
*/
getChild<K extends keyof T>(childNode: K): ReplicaChildOperator<RT, T[K]> {
return this.getProperty(childNode);
return this.property(childNode);
}


/** switch to child node
* @param {K} childNode of this node
* @returns {ReplicaChildOperator<RT, N[K]>} traversable child node
**/
getProperty<K extends keyof T>(childNode: K): ReplicaChildOperator<RT, T[K]> {
property<K extends keyof T>(childNode: K): ReplicaChildOperator<RT, T[K]> {
let branch = this.node[childNode];
return new ReplicaChildOperator(this.buildFunction, this.replica, branch, this.relativePath + '.' + childNode)
}

/**
* @deprecated since 0.4.1
* use replaceProperty instead
* use replaceValueOf instead
*/
modify<K extends keyof T>(childNode: K): PropertyModifier<ReplicaChildOperator<RT, T>, T[K]> {
return this.replaceProperty(childNode);
return this.replaceValueOf(childNode);
}

replaceProperty<K extends keyof T>(childNode: K): PropertyModifier<ReplicaChildOperator<RT, T>, T[K]> {
replaceValueOf<K extends keyof T>(childNode: K): PropertyModifier<ReplicaChildOperator<RT, T>, T[K]> {
return new PropertyModifier<ReplicaChildOperator<RT, T>, T[K]>(this, this.relativePath + '.' + childNode, this.replica)
}

Expand Down Expand Up @@ -201,7 +201,7 @@ export class PropertyModifier<PT, VT> {
* @param {(VT) => void} executeOnCloneFunction function that is executed
* @returns {PT}
*/
andDo(executeOnCloneFunction: (VT) => void): PT {
withCloneAndDo(executeOnCloneFunction: (VT) => void): PT {
let currentvalue = _.get(this.replica, this.relativePathToRoot);
executeOnCloneFunction(currentvalue);
return this.parent;
Expand Down
64 changes: 32 additions & 32 deletions src/tests/replicator.deprecated.spec.ts
Original file line number Diff line number Diff line change
@@ -1,76 +1,76 @@
import {expect} from 'chai'
import {ClassorientedTeststate, SimpleTeststate, SubTypeA} from './testobjects'
import {Concert, Rockband, SimpleBand} from './testobjects'
import {ReplicationBuilder} from '../replicator'
import {deepFreeze, isDeepFrozen} from '../deepFreeze'

describe('Deprecated API of ReplicationBuilder', () => {

it('Inputstate must not be modified, output must be modified', () => {
let rootState = new ClassorientedTeststate();
let manipulatedRoot = ReplicationBuilder.forObject(rootState).getChild('subTypeA').getChild('subTypeB').modify('subTypeBAttribute').to('Test').build();
let rootState = new Concert();
let manipulatedRoot = ReplicationBuilder.forObject(rootState).getChild('band').getChild('homeland').modify('name').to('Test').build();

expect(rootState.subTypeA.subTypeB.subTypeBAttribute).to.null;
expect(manipulatedRoot.subTypeA.subTypeB.subTypeBAttribute).to.equal('Test')
expect(rootState.band.homeland.name).to.null;
expect(manipulatedRoot.band.homeland.name).to.equal('Test')
});

it('Inputstate must not be modified, output must be modified', () => {
let rootState = new ClassorientedTeststate();
let manipulatedRoot = ReplicationBuilder.forObject(rootState).getChild('subTypeA').getChild('subTypeB').modify('subTypeBAttribute').to('Test').build();
let rootState = new Concert();
let manipulatedRoot = ReplicationBuilder.forObject(rootState).getChild('band').getChild('homeland').modify('name').to('Test').build();

expect(rootState.subTypeA.subTypeB.subTypeBAttribute).to.null;
expect(manipulatedRoot.subTypeA.subTypeB.subTypeBAttribute).to.equal('Test')
expect(rootState.band.homeland.name).to.null;
expect(manipulatedRoot.band.homeland.name).to.equal('Test')
});

it('Inputstate must not be modified, output node must be deleted', () => {
let rootState = new ClassorientedTeststate();
let manipulatedRoot = ReplicationBuilder.forObject(rootState).delete('subTypeA').build();
let rootState = new Concert();
let manipulatedRoot = ReplicationBuilder.forObject(rootState).delete('band').build();

expect(rootState.subTypeA).to.exist;
expect(manipulatedRoot.subTypeA).to.not.exist
expect(rootState.band).to.exist;
expect(manipulatedRoot.band).to.not.exist
});

it('Inputstate must not be modified, output child node must be deleted', () => {
let rootState = new ClassorientedTeststate();
let manipulatedRoot = ReplicationBuilder.forObject(rootState).getChild('subTypeA').delete('subTypeB').build();
let rootState = new Concert();
let manipulatedRoot = ReplicationBuilder.forObject(rootState).getChild('band').delete('homeland').build();

expect(rootState.subTypeA.subTypeB).to.exist;
expect(manipulatedRoot.subTypeA.subTypeB).to.not.exist
expect(rootState.band.homeland).to.exist;
expect(manipulatedRoot.band.homeland).to.not.exist
});

it('to untyped structure: Inputstate must not be modified, output must be modified', () => {
let rootState = SimpleTeststate;
let manipulatedRoot = ReplicationBuilder.forObject(rootState).getChild('subTypeB').modify('subtypeBAttribute').to('Test').build();
let rootState = SimpleBand;
let manipulatedRoot = ReplicationBuilder.forObject(rootState).getChild('genre').modify('name').to('Test').build();

expect(rootState.subTypeB.subtypeBAttribute).to.equal('initial');
expect(manipulatedRoot.subTypeB.subtypeBAttribute).to.equal('Test')
expect(rootState.genre.name).to.equal('initial');
expect(manipulatedRoot.genre.name).to.equal('Test')
});

it('if input state is deep frozen --> output state must be deep frozen', () => {
let rootState = new ClassorientedTeststate();
let rootState = new Concert();
deepFreeze(rootState);
let manipulatedRoot = ReplicationBuilder.forObject(rootState).getChild('subTypeA').getChild('subTypeB').modify('subTypeBAttribute').to('Test').build();
let manipulatedRoot = ReplicationBuilder.forObject(rootState).getChild('band').getChild('homeland').modify('name').to('Test').build();

expect(rootState.subTypeA.subTypeB.subTypeBAttribute).to.null;
expect(manipulatedRoot.subTypeA.subTypeB.subTypeBAttribute).to.equal('Test');
expect(rootState.band.homeland.name).to.null;
expect(manipulatedRoot.band.homeland.name).to.equal('Test');
expect(isDeepFrozen(manipulatedRoot)).true
});

it('redux like root state --> if input state is deep frozen --> output state must be deep frozen', () => {
let rootState = {
subTypeA: new SubTypeA()
band: new Rockband()
};
deepFreeze(rootState);
let manipulatedRoot = ReplicationBuilder.forObject(rootState).getChild('subTypeA').getChild('subTypeB').modify('subTypeBArray')
.by((oldArray) => [...oldArray, 'Test']).build();
let manipulatedRoot = ReplicationBuilder.forObject(rootState).getChild('band').modify('members')
.by((oldMembers) => [...oldMembers, 'Test']).build();

expect(rootState.subTypeA.subTypeB.subTypeBArray.length).to.equal(0);
expect(manipulatedRoot.subTypeA.subTypeB.subTypeBArray[0]).to.equal('Test');
expect(rootState.band.members.length).to.equal(0);
expect(manipulatedRoot.band.members[0]).to.equal('Test');
expect(isDeepFrozen(manipulatedRoot)).true
});

it('if input state is NOT frozen --> output state must NOT be frozen', () => {
let rootState = new ClassorientedTeststate();
let manipulatedRoot = ReplicationBuilder.forObject(rootState).getChild('subTypeA').getChild('subTypeB').modify('subTypeBAttribute').to('Test').build();
let rootState = new Concert();
let manipulatedRoot = ReplicationBuilder.forObject(rootState).getChild('band').getChild('homeland').modify('name').to('Test').build();

expect(Object.isFrozen(manipulatedRoot)).false
});
Expand Down
83 changes: 41 additions & 42 deletions src/tests/replicator.spec.ts
Original file line number Diff line number Diff line change
@@ -1,86 +1,85 @@
import {expect} from 'chai'
import {ClassorientedTeststate, ObjectArray, SimpleTeststate, SubTypeA} from './testobjects'
import {Concert, ObjectArray, Rockband, SimpleBand} from './testobjects'
import {ReplicationBuilder} from '../replicator'
import {deepFreeze, isDeepFrozen} from '../deepFreeze'

describe('ReplicationBuilder', () => {

it('should clone a property and execute function on the clone ', function () {
let rootState = new ClassorientedTeststate();
let someNewValue = 'someNewValue';
let manipulatedRoot = ReplicationBuilder.forObject(rootState).replaceProperty('subTypeA').andDo((clonedSubTypeA) => {
clonedSubTypeA.setSubTypeAAttribute(someNewValue)
let concert = new Concert();
let newBandName = 'someNewName';
let manipulatedRoot = ReplicationBuilder.forObject(concert).replaceValueOf('band').withCloneAndDo((band) => {
band.changeNameTo(newBandName)
}).build();
expect(manipulatedRoot.subTypeA.subTypeAAttribute).to.equal(someNewValue);
expect(manipulatedRoot.band.name).to.equal(newBandName);
});

it('Inputstate must not be modified, output must be modified', () => {
let rootState = new ClassorientedTeststate();
let manipulatedRoot = ReplicationBuilder.forObject(rootState).getProperty('subTypeA').getProperty('subTypeB').replaceProperty('subTypeBAttribute').with('Test').build();
let concert = new Concert();
let manipulatedRoot = ReplicationBuilder.forObject(concert).property('band').property('homeland').replaceValueOf('name').with('Spain').build();

expect(rootState.subTypeA.subTypeB.subTypeBAttribute).to.null;
expect(manipulatedRoot.subTypeA.subTypeB.subTypeBAttribute).to.equal('Test')
expect(concert.band.homeland.name).to.null;
expect(manipulatedRoot.band.homeland.name).to.equal('Spain')
});

it('Inputstate must not be modified, output must be modified', () => {
let rootState = new ClassorientedTeststate();
let manipulatedRoot = ReplicationBuilder.forObject(rootState).getProperty('subTypeA').getProperty('subTypeB').replaceProperty('subTypeBAttribute').with('Test').build();
let rootState = new Concert();
let manipulatedRoot = ReplicationBuilder.forObject(rootState).property('band').property('homeland').replaceValueOf('name').with('Russia').build();

expect(rootState.subTypeA.subTypeB.subTypeBAttribute).to.null;
expect(manipulatedRoot.subTypeA.subTypeB.subTypeBAttribute).to.equal('Test')
expect(rootState.band.homeland.name).to.null;
expect(manipulatedRoot.band.homeland.name).to.equal('Russia')
});

it('Inputstate must not be modified, output node must be deleted', () => {
let rootState = new ClassorientedTeststate();
let manipulatedRoot = ReplicationBuilder.forObject(rootState).removeProperty('subTypeA').build();
let rootState = new Concert();
let manipulatedRoot = ReplicationBuilder.forObject(rootState).removeProperty('band').build();

expect(rootState.subTypeA).to.exist;
expect(manipulatedRoot.subTypeA).to.not.exist
expect(rootState.band).to.exist;
expect(manipulatedRoot.band).to.not.exist
});

it('Inputstate must not be modified, output child node must be deleted', () => {
let rootState = new ClassorientedTeststate();
let manipulatedRoot = ReplicationBuilder.forObject(rootState).getProperty('subTypeA').removeProperty('subTypeB').build();
let rootState = new Concert();
let manipulatedRoot = ReplicationBuilder.forObject(rootState).property('band').removeProperty('homeland').build();

expect(rootState.subTypeA.subTypeB).to.exist;
expect(manipulatedRoot.subTypeA.subTypeB).to.not.exist
expect(rootState.band.homeland).to.exist;
expect(manipulatedRoot.band.homeland).to.not.exist
});

it('with untyped structure: Inputstate must not be modified, output must be modified', () => {
let rootState = SimpleTeststate;
let manipulatedRoot = ReplicationBuilder.forObject(rootState).getProperty('subTypeB').replaceProperty('subtypeBAttribute').with('Test').build();
let simpleBand = SimpleBand;
let manipulatedRoot = ReplicationBuilder.forObject(simpleBand).property('genre').replaceValueOf('name').with('Test').build();

expect(rootState.subTypeB.subtypeBAttribute).to.equal('initial');
expect(manipulatedRoot.subTypeB.subtypeBAttribute).to.equal('Test')
expect(simpleBand.genre.name).to.equal('initial');
expect(manipulatedRoot.genre.name).to.equal('Test')
});

it('if input state is deep frozen --> output state must be deep frozen', () => {
let rootState = new ClassorientedTeststate();
deepFreeze(rootState);
let manipulatedRoot = ReplicationBuilder.forObject(rootState).getProperty('subTypeA').getProperty('subTypeB').replaceProperty('subTypeBAttribute').with('Test').build();
let concert = new Concert();
deepFreeze(concert);
let manipulatedRoot = ReplicationBuilder.forObject(concert).property('band').property('homeland').replaceValueOf('name').with('Test').build();

expect(rootState.subTypeA.subTypeB.subTypeBAttribute).to.null;
expect(manipulatedRoot.subTypeA.subTypeB.subTypeBAttribute).to.equal('Test');
expect(concert.band.homeland.name).to.null;
expect(manipulatedRoot.band.homeland.name).to.equal('Test');
expect(isDeepFrozen(manipulatedRoot)).true
});

it('redux like root state --> if input state is deep frozen --> output state must be deep frozen', () => {
let rootState = {
subTypeA: new SubTypeA()
let festival = {
band: new Rockband()
};
deepFreeze(rootState);
let manipulatedRoot = ReplicationBuilder.forObject(rootState).getProperty('subTypeA').getProperty('subTypeB').replaceProperty('subTypeBArray')
.by((oldArray) => [...oldArray, 'Test']).build();
deepFreeze(festival);
let newFestival = ReplicationBuilder.forObject(festival).property('band').replaceValueOf('members')
.by((oldMembers) => [...oldMembers, 'NewRocker']).build();

expect(rootState.subTypeA.subTypeB.subTypeBArray.length).to.equal(0);
expect(manipulatedRoot.subTypeA.subTypeB.subTypeBArray[0]).to.equal('Test');
expect(isDeepFrozen(manipulatedRoot)).true
expect(festival.band.members.length).to.equal(0);
expect(newFestival.band.members[0]).to.equal('NewRocker');
expect(isDeepFrozen(newFestival)).true
});

it('if input state is NOT frozen --> output state must NOT be frozen', () => {
let rootState = new ClassorientedTeststate();
let manipulatedRoot = ReplicationBuilder.forObject(rootState).getProperty('subTypeA').getProperty('subTypeB').replaceProperty('subTypeBAttribute').with('Test').build();

let concert = new Concert();
let manipulatedRoot = ReplicationBuilder.forObject(concert).property('band').property('homeland').replaceValueOf('name').with('USA').build();
expect(Object.isFrozen(manipulatedRoot)).false
});

Expand Down
Loading

0 comments on commit 11b74bd

Please sign in to comment.