Skip to content

Commit

Permalink
fix(validation) Serializing a not finite Double throws a validation e…
Browse files Browse the repository at this point in the history
…rror #158

Signed-off-by: Jerome Simeon <[email protected]>
  • Loading branch information
jeromesimeon committed Dec 19, 2019
1 parent e3b1083 commit 4e0a6cb
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 7 deletions.
12 changes: 10 additions & 2 deletions packages/concerto-core/lib/serializer/resourcevalidator.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,12 +299,16 @@ class ResourceValidator {
invalid = true;
}
break;
case 'Double':
case 'Long':
case 'Integer':
case 'Double': {
if(dataType !== 'number') {
invalid = true;
}
if (!isFinite(obj)) {
invalid = true;
}
}
break;
case 'Boolean':
if(dataType !== 'boolean') {
Expand Down Expand Up @@ -421,7 +425,11 @@ class ResourceValidator {
else {
if(value) {
try {
value = JSON.stringify(value);
if (typeof value === 'number' && !isFinite(value)) {
value = value.toString();
} else {
value = JSON.stringify(value);
}
}
catch(err) {
value = value.toString();
Expand Down
50 changes: 46 additions & 4 deletions packages/concerto-core/test/serializer.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ describe('Serializer', () => {
o String assetId
--> SampleParticipant owner
o String stringValue
o Double doubleValue
}
participant SampleParticipant identified by participantId {
Expand All @@ -61,6 +62,7 @@ describe('Serializer', () => {
concept Address {
o String city
o String country
o Double elevation
}
event SampleEvent{
Expand Down Expand Up @@ -113,17 +115,49 @@ describe('Serializer', () => {
let resource = factory.newResource('org.acme.sample', 'SampleAsset', '1');
resource.owner = factory.newRelationship('org.acme.sample', 'SampleParticipant', '[email protected]');
resource.stringValue = 'the value';
resource.doubleValue = 3.14;
let json = serializer.toJSON(resource, {
validate: true
});
json.should.deep.equal({
$class: 'org.acme.sample.SampleAsset',
assetId: '1',
owner: 'resource:org.acme.sample.SampleParticipant#[email protected]',
stringValue: 'the value'
stringValue: 'the value',
doubleValue: 3.14
});
});

it('should throw validation errors during JSON object generation if Double is NaN', () => {
let resource = factory.newResource('org.acme.sample', 'SampleAsset', '1');
resource.owner = factory.newRelationship('org.acme.sample', 'SampleParticipant', '[email protected]');
resource.stringValue = 'the value';
resource.doubleValue = NaN;
(() => {
serializer.toJSON(resource);
}).should.throw(/Model violation in instance org.acme.sample.SampleAsset#1 field doubleValue has value NaN/);
});

it('should throw validation errors during JSON object generation if Double is Infinity', () => {
let resource = factory.newResource('org.acme.sample', 'SampleAsset', '1');
resource.owner = factory.newRelationship('org.acme.sample', 'SampleParticipant', '[email protected]');
resource.stringValue = 'the value';
resource.doubleValue = Infinity;
(() => {
serializer.toJSON(resource);
}).should.throw(/Model violation in instance org.acme.sample.SampleAsset#1 field doubleValue has value Infinity/);
});

it('should throw validation errors during JSON object generation if Double is -Infinity', () => {
let resource = factory.newResource('org.acme.sample', 'SampleAsset', '1');
resource.owner = factory.newRelationship('org.acme.sample', 'SampleParticipant', '[email protected]');
resource.stringValue = 'the value';
resource.doubleValue = -Infinity;
(() => {
serializer.toJSON(resource);
}).should.throw(/Model violation in instance org.acme.sample.SampleAsset#1 field doubleValue has value -Infinity/);
});

it('should throw validation errors during JSON object generation if the validate flag is not specified and errors are present', () => {
let resource = factory.newResource('org.acme.sample', 'SampleAsset', '1');
(() => {
Expand Down Expand Up @@ -175,10 +209,12 @@ describe('Serializer', () => {
let address = factory.newConcept('org.acme.sample', 'Address');
address.city = 'Winchester';
address.country = 'UK';
address.elevation = 3.14;
const json = serializer.toJSON(address);
json.should.deep.equal({
$class: 'org.acme.sample.Address',
country: 'UK',
elevation: 3.14,
city: 'Winchester'
});
});
Expand All @@ -187,14 +223,16 @@ describe('Serializer', () => {
let resource = factory.newResource('org.acme.sample', 'SampleAsset', '1');
resource.owner = factory.newRelationship('org.acme.sample', 'SampleParticipant', '[email protected]');
resource.stringValue = '';
resource.doubleValue = 3.14;
let json = serializer.toJSON(resource, {
validate: true
});
json.should.deep.equal({
$class: 'org.acme.sample.SampleAsset',
assetId: '1',
owner: 'resource:org.acme.sample.SampleParticipant#[email protected]',
stringValue: ''
stringValue: '',
doubleValue: 3.14
});
});
});
Expand Down Expand Up @@ -222,13 +260,15 @@ describe('Serializer', () => {
$class: 'org.acme.sample.SampleAsset',
assetId: '1',
owner: 'resource:org.acme.sample.SampleParticipant#[email protected]',
stringValue: 'the value'
stringValue: 'the value',
doubleValue: 3.14
};
let resource = serializer.fromJSON(json);
resource.should.be.an.instanceOf(Resource);
resource.assetId.should.equal('1');
resource.owner.should.be.an.instanceOf(Relationship);
resource.stringValue.should.equal('the value');
resource.doubleValue.should.equal(3.14);
});

it('should deserialize a valid transaction', () => {
Expand Down Expand Up @@ -263,12 +303,14 @@ describe('Serializer', () => {
let json = {
$class: 'org.acme.sample.Address',
city: 'Winchester',
country: 'UK'
country: 'UK',
elevation: 3.14
};
let resource = serializer.fromJSON(json);
resource.should.be.an.instanceOf(Concept);
resource.city.should.equal('Winchester');
resource.country.should.equal('UK');
resource.elevation.should.equal(3.14);
});

it('should throw validation errors if the validate flag is not specified', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/concerto-core/test/serializer/jsongenerator.js
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ describe('JSONGenerator', () => {
ergoJsonGenerator.convertToJSON({ getType: () => { return 'Integer'; } }, 123456).nat.should.equal(123456);
});

it('should pass through a double object', () => {
it('should pass through a finite double object', () => {
jsonGenerator.convertToJSON({ getType: () => { return 'Double'; } }, 3.142).should.equal(3.142);
});

Expand Down
17 changes: 17 additions & 0 deletions packages/concerto-core/test/serializer/resourcevalidator.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ describe('ResourceValidator', function () {
import org.acme.l1.Person
asset Vehicle extends Base {
o Integer numberOfWheels
o Double milage
}
participant PrivateOwner identified by employeeId extends Person {
o String employeeId
Expand Down Expand Up @@ -414,6 +415,7 @@ describe('ResourceValidator', function () {
vehicle.$identifier = ''; // empty the identifier
vehicle.model = 'Ford';
vehicle.numberOfWheels = 4;
vehicle.milage = 3.14;
const typedStack = new TypedStack(vehicle);
const assetDeclaration = modelManager.getType('org.acme.l3.Car');
const parameters = { stack : typedStack, 'modelManager' : modelManager, rootResourceIdentifier : 'ABC' };
Expand All @@ -423,6 +425,21 @@ describe('ResourceValidator', function () {
}).should.throw(/has an empty identifier/);
});

it('should reject a Double which is not finite', function () {
const vehicle = factory.newResource('org.acme.l3', 'Car', 'foo');
vehicle.$identifier = '42';
vehicle.model = 'Ford';
vehicle.numberOfWheels = 4;
vehicle.milage = NaN; // NaN
const typedStack = new TypedStack(vehicle);
const assetDeclaration = modelManager.getType('org.acme.l3.Car');
const parameters = { stack : typedStack, 'modelManager' : modelManager, rootResourceIdentifier : 'ABC' };

(() => {
assetDeclaration.accept(resourceValidator,parameters);
}).should.throw(/Model violation in instance org.acme.l3.Car#42 field milage has value NaN/);
});

it('should report undeclared field if not identifiable', () => {
const data = factory.newConcept('org.acme.l1', 'Data');
data.name = 'name';
Expand Down

0 comments on commit 4e0a6cb

Please sign in to comment.