From 57afa8b0cbb8c7d863f24efdbaff28d8fb093a5e Mon Sep 17 00:00:00 2001 From: Stefan Blaginov Date: Fri, 1 Apr 2022 17:02:17 +0300 Subject: [PATCH] refactor(errors): improve error messages (#390) * refactor(errors): improve error messages Signed-off-by: Stefan Blaginov * test(concerto): fix 6 failing tests Signed-off-by: Stefan Blaginov Co-authored-by: Stefan Blaginov Co-authored-by: Matt Roberts <7544022+mttrbrts@users.noreply.github.com> --- packages/concerto-cli/test/cli.js | 8 +- packages/concerto-core/messages/en.json | 96 +++++++++---------- packages/concerto-core/test/1.0.0/validate.js | 6 +- packages/concerto-core/test/composer/i18n.js | 53 +++++----- packages/concerto-core/test/concerto.js | 16 ++-- packages/concerto-core/test/factory.js | 2 +- .../test/introspect/assetdeclaration.js | 2 +- .../test/introspect/identifieddeclaration.js | 30 +++--- .../concerto-core/test/model/relationship.js | 6 +- packages/concerto-core/test/models/model.js | 50 +++++----- packages/concerto-core/test/models/test.js | 24 ++--- packages/concerto-core/test/serializer.js | 22 ++--- .../test/serializer/instancegenerator.js | 2 +- .../test/serializer/objectvalidator.js | 24 ++--- .../test/serializer/resourcevalidator.js | 42 ++++---- 15 files changed, 194 insertions(+), 189 deletions(-) diff --git a/packages/concerto-cli/test/cli.js b/packages/concerto-cli/test/cli.js index f514b715ea..4e19dd5ca3 100644 --- a/packages/concerto-cli/test/cli.js +++ b/packages/concerto-cli/test/cli.js @@ -63,7 +63,7 @@ describe('cicero-cli', () => { const result = await Commands.validate(input2, models, {offline:false}); JSON.parse(result).should.deep.equal(JSON.parse(inputText2)); } catch (err) { - err.message.should.equal('Instance org.accordproject.money.MonetaryAmount invalid enum value true for field CurrencyCode'); + err.message.should.equal('Model violation in the "org.accordproject.money.MonetaryAmount" instance. Invalid enum value of "true" for the field "CurrencyCode".'); } }); @@ -77,7 +77,7 @@ describe('cicero-cli', () => { const result = await Commands.validate(input2, offlineModels, {offline:true}); JSON.parse(result).should.deep.equal(JSON.parse(inputText2)); } catch (err) { - err.message.should.equal('Instance org.accordproject.money.MonetaryAmount invalid enum value true for field CurrencyCode'); + err.message.should.equal('Model violation in the "org.accordproject.money.MonetaryAmount" instance. Invalid enum value of "true" for the field "CurrencyCode".'); } }); @@ -116,7 +116,7 @@ describe('cicero-cli', () => { try { await Commands.validate(input2, models, {offline:false, functional: true}); } catch (err) { - err.message.should.equal('Instance undefined invalid enum value true for field CurrencyCode'); + err.message.should.equal('Model violation in the "undefined" instance. Invalid enum value of "true" for the field "CurrencyCode".'); } }); }); @@ -258,4 +258,4 @@ describe('cicero-cli', () => { output.cleanup(); }); }); -}); \ No newline at end of file +}); diff --git a/packages/concerto-core/messages/en.json b/packages/concerto-core/messages/en.json index 3b7ebe5930..cd8a3750bb 100644 --- a/packages/concerto-core/messages/en.json +++ b/packages/concerto-core/messages/en.json @@ -13,68 +13,68 @@ "test-repeat-array": "{0} {0} {0}", "test-repeat-object": "{value} {value} {value}", - "classdeclaration-constructor-modelastreq": "ModelFile and AST are required to create a ClassDecl.", - "classdeclaration-process-unrecmodelelem": "Unrecognised model element {type}", - "classdeclaration-getfield-notfindsupertype": "Could not find super type {type}", - "classdeclaration-validate-identifiernotproperty": "Class {class} is identified by field ({idField}) but does not contain this property.", - "classdeclaration-validate-identifiernotstring": "Class {class} is identified by field ({idField}) but the type of the field is not String.", - "classdeclaration-validate-duplicatefieldname": "Class {class} has more than one field named ({fieldName}).", - "classdeclaration-validate-missingidentifier" : "Class {class} is not declared as abstract. It must define an identifying field.", + "classdeclaration-constructor-modelastreq": "\"ModelFile\" and \"AST\" are required to create a \"ClassDecl\".", + "classdeclaration-process-unrecmodelelem": "Unrecognised model element \"{type}\".", + "classdeclaration-getfield-notfindsupertype": "Could not find supertype \"{type}\".", + "classdeclaration-validate-identifiernotproperty": "Class \"{class}\" is identified by field \"{idField}\", but does not contain this property.", + "classdeclaration-validate-identifiernotstring": "Class \"{class}\" is identified by field \"{idField}\", but the type of the field is not \"String\".", + "classdeclaration-validate-duplicatefieldname": "Class \"{class}\" has more than one field named \"{fieldName}\".", + "classdeclaration-validate-missingidentifier" : "Class \"{class}\" is not declared as \"abstract\". It must define an identifying field.", - "modelfile-constructor-unrecmodelelem": "Unrecognised model element {type}", - "modelfile-resolvetype-undecltype": "Undeclared type {type} in {context}", - "modelfile-resolveimport-failfindimp": "Failed to find {type} in list of imports [{imports}] for namespace {namespace}", + "modelfile-constructor-unrecmodelelem": "Unrecognised model element \"{type}\".", + "modelfile-resolvetype-undecltype": "Undeclared type \"{type}\" in \"{context}\".", + "modelfile-resolveimport-failfindimp": "Failed to find \"{type}\" in list of imports \"[{imports}]\" for namespace \"{namespace}\".", "transactiondeclaration-getidentifierfieldname-noidentifyingfield": "Transactions do not have an identifying field.", - "composer-connect-noconopts": "connectOptions not specified", - "composer-connect-nokeyvalstore": "connectOptions.keyValStore not specified", - "composer-connect-nomembersrvcurl": "connectOptions.membershipServicesURL not specified", - "composer-connect-nopeerurl": "connectOptions.peerURL not specified", - "composer-connect-noeventhuburl": "connectOptions.eventHubURL not specified", - "composer-connect-notconnected": "Connection needs to be connected. Call connect(..)", - "composer-login-noenrollmentid": "enrollmentID not specified", - "composer-login-noenrollmentsecret": "enrollmentSecret not specified", - "composer-deploy-nosecuritycontext": "securityContext not specified", + "composer-connect-noconopts": "\"connectOptions\" not specified.", + "composer-connect-nokeyvalstore": "\"connectOptions.keyValStore\" not specified.", + "composer-connect-nomembersrvcurl": "\"connectOptions.membershipServicesURL\" not specified.", + "composer-connect-nopeerurl": "\"connectOptions.peerURL\" not specified.", + "composer-connect-noeventhuburl": "\"connectOptions.eventHubURL\" not specified.", + "composer-connect-notconnected": "Connection needs to be connected. Call \"connect(..)\".", + "composer-login-noenrollmentid": "\"enrollmentID\" not specified.", + "composer-login-noenrollmentsecret": "\"enrollmentSecret\" not specified.", + "composer-deploy-nosecuritycontext": "\"securityContext\" not specified.", - "factory-newinstance-missingidentifier": "Missing identifier for Type {type} in namespace {namespace}", - "factory-newinstance-invalididentifier": "Invalid or missing identifier for Type {type} in namespace {namespace}", - "factory-newinstance-abstracttype": "Cannot instantiate Abstract Type {type} in namespace {namespace}", - "factory-newrelationship-notregisteredwithmm" : "Cannot create relationship as namespace {namespace} is not known", - "factory-newinstance-typenotdeclaredinns" : "Cannot instantiate Type {type} in namespace {namespace}", + "factory-newinstance-missingidentifier": "Missing identifier for Type \"{type}\" in namespace \"{namespace}\".", + "factory-newinstance-invalididentifier": "Invalid or missing identifier for Type \"{type}\" in namespace \"{namespace}\".", + "factory-newinstance-abstracttype": "Cannot instantiate the abstract type \"{type}\" in the \"{namespace}\" namespace.", + "factory-newrelationship-notregisteredwithmm" : "Cannot create relationship as namespace \"{namespace}\" is not known.", + "factory-newinstance-typenotdeclaredinns" : "Cannot instantiate Type \"{type}\" in namespace \"{namespace}\".", - "instancegenerator-newinstance-noconcreteclass": "No concrete extending type for {type}", + "instancegenerator-newinstance-noconcreteclass": "No concrete extending type for \"{type}\".", - "modelmanager-resolvetype-nonsfortype": "No registered namespace for type {type} in {context}", - "modelmanager-resolvetype-notypeinnsforcontext": "No type {type} in namespace {namespace} for {context}", + "modelmanager-resolvetype-nonsfortype": "No registered namespace for type \"{type}\" in \"{context}\".", + "modelmanager-resolvetype-notypeinnsforcontext": "No type \"{type}\" in namespace \"{namespace}\" for \"{context}\".", - "modelmanager-gettype-noregisteredns": "Namespace is not defined for type {type}", - "modelmanager-gettype-notypeinns": "Type {type} is not defined in namespace {namespace}", + "modelmanager-gettype-noregisteredns": "Namespace is not defined for type \"{type}\".", + "modelmanager-gettype-notypeinns": "Type \"{type}\" is not defined in namespace \"{namespace}\".", - "serializer-constructor-factorynull": "Factory cannot be null", - "serializer-constructor-modelmanagernull": "ModelManager cannot be null", - "serializer-tojson-notcobject": "Serializer.toJSON only accepts Concept, Event, Asset, Participant or Transaction.", + "serializer-constructor-factorynull": "\"Factory\" cannot be \"null\".", + "serializer-constructor-modelmanagernull": "\"ModelManager\" cannot be \"null\".", + "serializer-tojson-notcobject": "\"Serializer.toJSON\" only accepts \"Concept\", \"Event\", \"Asset\", \"Participant\" or \"Transaction\".", - "util-securitycheck-novalidcontext": "A valid SecurityContext must be specified.", + "util-securitycheck-novalidcontext": "A valid \"SecurityContext\" must be specified.", "modelutil-getnamespace-nofnq": "FQN is invalid.", - "resourcevalidator-notresourceorconcept": "Model violation in instance {resourceId} class {classFQN} has value {invalidValue} expected a Resource or a Concept.", - "resourcevalidator-notrelationship": "Model violation in instance {resourceId} class {classFQN} has value {invalidValue} expected a Relationship.", - "resourcevalidator-fieldtypeviolation": "Model violation in instance {resourceId} field {propertyName} has value {value} ({typeOfValue}) expected type {fieldType}", - "resourcevalidator-missingrequiredproperty": "Instance {resourceId} missing required field {fieldName}", - "resourcevalidator-invalidenumvalue": "Instance {resourceId} invalid enum value {value} for field {fieldName}", - "resourcevalidator-abstractclass": "The class {className} is abstract. Should not have an instance!", - "resourcevalidator-undeclaredfield": "Instance {resourceId} has a property named {propertyName} which is not declared in {fullyQualifiedTypeName}", - "resourcevalidator-invalidfieldassignment": "Instance {resourceId} has property {propertyName} with type {objectType} that is not derived from {fieldType}", - "resourcevalidator-emptyidentifier": "Instance {resourceId} has an empty identifier.", + "resourcevalidator-notresourceorconcept": "Model violation in the \"{resourceId}\" instance. Class \"{classFQN}\" has the value of \"{invalidValue}\". Expected a \"Resource\" or a \"Concept\".", + "resourcevalidator-notrelationship": "Model violation in the \"{resourceId}\" instance. Class \"{classFQN}\" has a value of \"{invalidValue}\". Expected a \"Relationship\".", + "resourcevalidator-fieldtypeviolation": "Model violation in the \"{resourceId}\" instance. The field \"{propertyName}\" has a value of \"{value}\" (type of value: \"{typeOfValue}\"). Expected type of value: \"{fieldType}\".", + "resourcevalidator-missingrequiredproperty": "The instance \"{resourceId}\" is missing the required field \"{fieldName}\".", + "resourcevalidator-invalidenumvalue": "Model violation in the \"{resourceId}\" instance. Invalid enum value of \"{value}\" for the field \"{fieldName}\".", + "resourcevalidator-abstractclass": "The class \"{className}\" is abstract and should not contain an instance.", + "resourcevalidator-undeclaredfield": "Instance \"{resourceId}\" has a property named \"{propertyName}\", which is not declared in \"{fullyQualifiedTypeName}\".", + "resourcevalidator-invalidfieldassignment": "Instance \"{resourceId}\" has a property \"{propertyName}\" with type \"{objectType}\" that is not derived from \"{fieldType}\".", + "resourcevalidator-emptyidentifier": "Instance \"{resourceId}\" has an empty identifier.", - "typenotfounderror-defaultmessage": "Type not found: {typeName}", + "typenotfounderror-defaultmessage": "Type \"{typeName}\" not found.", - "whereastvalidator-propertytypeviolation": "Property {propertyName} cannot be compared with {value} ({typeOfValue}) expected type {fieldType}", - "whereastvalidator-enum-propertytypeviolation": "Enum property {propertyName} cannot be compared with {value} ({typeOfValue}) expected a String", - "whereastvalidator-relationship-propertytypeviolation": "Relationship {propertyName} cannot be compared with {value} ({typeOfValue}) expected type String", - "whereastvalidator-unsupportedtype": "Property {propertyName} of type {fieldType} cannot be compared with a literal value.", - "whereastvalidator-invalidoperator": "Property {propertyName} cannot be compared using the {operator} operator." + "whereastvalidator-propertytypeviolation": "Property \"{propertyName}\" cannot be compared with \"{value}\" (type of value: \"{typeOfValue}\"). Expected type: \"{fieldType}\".", + "whereastvalidator-enum-propertytypeviolation": "Enum property \"{propertyName}\" cannot be compared with \"{value}\" (type of value: \"{typeOfValue}\"). Expected type: \"String\".", + "whereastvalidator-relationship-propertytypeviolation": "Relationship \"{propertyName}\" cannot be compared with \"{value}\" (type of value: \"{typeOfValue}\"). Expected type: \"String\".", + "whereastvalidator-unsupportedtype": "Property \"{propertyName}\" of type \"{fieldType}\" cannot be compared with a literal value.", + "whereastvalidator-invalidoperator": "Property \"{propertyName}\" cannot be compared using the \"{operator}\" operator." } } diff --git a/packages/concerto-core/test/1.0.0/validate.js b/packages/concerto-core/test/1.0.0/validate.js index 1845f9d9e2..a352fa0064 100644 --- a/packages/concerto-core/test/1.0.0/validate.js +++ b/packages/concerto-core/test/1.0.0/validate.js @@ -129,13 +129,13 @@ const negative = [{ sample: './data/hierarchy2err.json', ctoFiles: ['./models/hierarchy2.cto'], error: 'Unexpected properties for type org.test.C: c, t', - errorFunctional: 'Instance undefined has a property named c which is not declared in org.test.C' + errorFunctional: 'Instance "undefined" has a property named "c", which is not declared in "org.test.C".' }, { name: 'user defined identifier', sample: './data/identifier1err.json', ctoFiles: ['./models/identifier1.cto'], - error: 'Invalid or missing identifier for Type A1 in namespace org.test', - errorFunctional: 'Instance org.test.A1#undefined has an empty identifier.', + error: 'Invalid or missing identifier for Type "A1" in namespace "org.test".', + errorFunctional: 'Instance "org.test.A1#undefined" has an empty identifier.', }]; describe('Validation (1.0.0)', () => { diff --git a/packages/concerto-core/test/composer/i18n.js b/packages/concerto-core/test/composer/i18n.js index dbc6278e95..fcd2204902 100644 --- a/packages/concerto-core/test/composer/i18n.js +++ b/packages/concerto-core/test/composer/i18n.js @@ -24,6 +24,7 @@ const Serializer = require('./../../lib/serializer'); const ModelManager = require('./../../lib/modelmanager'); const ModelUtil = require('./../../lib/modelutil'); const Util = require('../composer/composermodelutility'); +const ParserUtil = require('../introspect/parserutility'); const dayjs = require('dayjs'); const utc = require('dayjs/plugin/utc'); dayjs.extend(utc); @@ -93,14 +94,14 @@ describe('Globalization', function() { let formatter = Globalize('en').messageFormatter('classdeclaration-process-unrecmodelelem'); formatter({ 'type': 'Cow' - }).should.equal('Unrecognised model element Cow'); + }).should.equal('Unrecognised model element "Cow".'); }); it('check message in getFields()', function() { let formatter = Globalize('en').messageFormatter('classdeclaration-getfield-notfindsupertype'); formatter({ 'type': 'Bar' - }).should.equal('Could not find super type Bar'); + }).should.equal('Could not find supertype "Bar".'); // TODO (LG) functionally test this function }); @@ -111,7 +112,7 @@ describe('Globalization', function() { formatter({ 'class': 'Cow', 'idField': 'CowID' - }).should.equal('Class Cow is identified by field (CowID) but does not contain this property.'); + }).should.equal('Class "Cow" is identified by field "CowID", but does not contain this property.'); // create and polulate the modelManager with a model file const modelManager = new ModelManager(); @@ -120,10 +121,11 @@ describe('Globalization', function() { let fileName = './test/composer/models/classdeclaration/validate/foo-identifiernotproperty.cto'; let invalidFile = fs.readFileSync(fileName, 'utf8'); invalidFile.should.not.be.null; + let invalidModelFile = ParserUtil.newModelFile(modelManager, invalidFile); expect(function() { - modelManager.addCTOModel(invalidFile,fileName); - }).to.throw(IllegalModelException, 'Class foo is identified by field (fooID) but does not contain this property.'); + modelManager.addModelFile(invalidModelFile, fileName); + }).to.throw(IllegalModelException, 'Class "foo" is identified by field "fooID", but does not contain this property.'); }); it('where identifier is not a string', function() { @@ -131,7 +133,7 @@ describe('Globalization', function() { formatter({ 'class': 'Cow', 'idField': 'CowID' - }).should.equal('Class Cow is identified by field (CowID) but the type of the field is not String.'); + }).should.equal('Class "Cow" is identified by field "CowID", but the type of the field is not "String".'); // create and polulate the modelManager with a model file const modelManager = new ModelManager(); @@ -140,9 +142,11 @@ describe('Globalization', function() { let fileName = './test/composer/models/classdeclaration/validate/foo-identifiernotstring.cto'; let invalidFile = fs.readFileSync(fileName, 'utf8'); invalidFile.should.not.be.null; + let invalidModelFile = ParserUtil.newModelFile(modelManager, invalidFile); + expect(function() { - modelManager.addCTOModel(invalidFile,fileName); - }).to.throw(IllegalModelException, 'Class foo is identified by field (fooID) but the type of the field is not String.'); + modelManager.addModelFile(invalidModelFile, fileName); + }).to.throw(IllegalModelException, 'Class "foo" is identified by field "fooID", but the type of the field is not "String".'); }); }); }); @@ -152,17 +156,16 @@ describe('Globalization', function() { let formatter = Globalize.messageFormatter('modelfile-constructor-unrecmodelelem'); formatter({ 'type': 'Person', - }).should.equal('Unrecognised model element Person'); + }).should.equal('Unrecognised model element "Person".'); // TODO (LG) functionally test this function }); - it('check message in resolveType()', function() { let formatter = Globalize.messageFormatter('modelfile-resolvetype-undecltype'); formatter({ 'type': 'Person', 'context': 'Context' - }).should.equal('Undeclared type Person in Context'); + }).should.equal('Undeclared type "Person" in "Context".'); // create and polulate the modelManager with a model file const modelManager = new ModelManager(); @@ -171,9 +174,11 @@ describe('Globalization', function() { let fileName = './test/composer/models/modelfile/resolvetype/foo-undecltype.cto'; let invalidFile = fs.readFileSync(fileName, 'utf8'); invalidFile.should.not.be.null; + let invalidModelFile = ParserUtil.newModelFile(modelManager, invalidFile); + expect(function() { - modelManager.addCTOModel(invalidFile,fileName); - }).to.throw(IllegalModelException, 'Undeclared type Person in property Bar.foo.fooProperty'); + modelManager.addModelFile(invalidModelFile, fileName); + }).to.throw(IllegalModelException, 'Undeclared type "Person" in "property Bar.foo.fooProperty"'); }); it('check message in resolveImport()', function() { @@ -182,7 +187,7 @@ describe('Globalization', function() { 'type': 'Type', 'imports': 'Imports', 'namespace': 'Namespace' - }).should.equal('Failed to find Type in list of imports [Imports] for namespace Namespace'); + }).should.equal('Failed to find "Type" in list of imports "[Imports]" for namespace "Namespace".'); // TODO (LG) functionally test this function (will never be thrown) }); }); @@ -318,14 +323,14 @@ describe('Globalization', function() { formatter({ type: 'bar', context: 'foo' - }).should.equal('No registered namespace for type bar in foo'); + }).should.equal('No registered namespace for type "bar" in "foo".'); const modelManager = new ModelManager(); Util.addComposerModel(modelManager); expect(function() { modelManager.resolveType('foo', 'bar'); - }).to.throw(IllegalModelException, 'No registered namespace for type bar in foo'); + }).to.throw(IllegalModelException, 'No registered namespace for type "bar" in "foo".'); }); it('when a type doesn\'t exist in a namespace for a context', function() { @@ -334,7 +339,7 @@ describe('Globalization', function() { namespace: 'baz', type: 'bar', context: 'foo' - }).should.equal('No type bar in namespace baz for foo'); + }).should.equal('No type "bar" in namespace "baz" for "foo".'); // Cannot be tested - will throw error on line 85 modelmanager.js first }); @@ -345,13 +350,13 @@ describe('Globalization', function() { let formatter = Globalize.messageFormatter('modelmanager-gettype-noregisteredns'); formatter({ type: 'TYPE' - }).should.equal('Namespace is not defined for type TYPE'); + }).should.equal('Namespace is not defined for type "TYPE".'); const modelManager = new ModelManager(); expect(function() { modelManager.getType('NAMESPACE.TYPE'); - }).to.throw(Error, 'Namespace is not defined for type NAMESPACE.TYPE'); + }).to.throw(Error, 'Namespace is not defined for type "NAMESPACE.TYPE".'); }); it('check type exists in namespace', function() { @@ -359,7 +364,7 @@ describe('Globalization', function() { formatter({ type: 'TYPE', namespace: 'NAMESPACE' - }).should.equal('Type TYPE is not defined in namespace NAMESPACE'); + }).should.equal('Type "TYPE" is not defined in namespace "NAMESPACE".'); // Cannot be tested - will throw error on line 139 modelmanager.js first }); @@ -369,25 +374,25 @@ describe('Globalization', function() { describe('#check Serializer messages are correct', function() { it('check message in constructor()', function() { let formatter = Globalize.messageFormatter('serializer-constructor-factorynull'); - formatter().should.equal('Factory cannot be null'); + formatter().should.equal('"Factory" cannot be "null".'); const modelManager = new ModelManager(); Util.addComposerModel(modelManager); expect(function() { new Serializer(null, modelManager); - }).to.throw(Error, 'Factory cannot be null'); + }).to.throw(Error, '"Factory" cannot be "null".'); }); it('check message in toJSON()', function() { let formatter = Globalize.messageFormatter('serializer-tojson-notcobject'); - formatter().should.equal('Serializer.toJSON only accepts Concept, Event, Asset, Participant or Transaction.'); + formatter().should.equal('"Serializer.toJSON" only accepts "Concept", "Event", "Asset", "Participant" or "Transaction".'); const modelManager = new ModelManager(); Util.addComposerModel(modelManager); expect(function() { let serializer = new Serializer(true, modelManager); serializer.toJSON({}); - }).to.throw(Error, 'Serializer.toJSON only accepts Concept, Event, Asset, Participant or Transaction.'); + }).to.throw(Error, '"Serializer.toJSON" only accepts "Concept", "Event", "Asset", "Participant" or "Transaction".'); }); }); diff --git a/packages/concerto-core/test/concerto.js b/packages/concerto-core/test/concerto.js index 7e6519dd7c..9633d53f1b 100644 --- a/packages/concerto-core/test/concerto.js +++ b/packages/concerto-core/test/concerto.js @@ -181,7 +181,7 @@ describe('concerto', () => { (() => { concerto.getTypeDeclaration(obj); - }).should.throw(/Namespace is not defined for type Foo/); + }).should.throw(/Namespace is not defined for type "Foo"./); }); }); @@ -279,7 +279,7 @@ describe('concerto', () => { (() => { concerto.validate(obj); - }).should.throw(/Instance 123456789 has a property named name which is not declared in org.accordproject.test.Customer/); + }).should.throw(/Instance "123456789" has a property named "name", which is not declared in "org.accordproject.test.Customer"./); }); it('should fail with extra property (concept)', () => { @@ -292,7 +292,7 @@ describe('concerto', () => { (() => { concerto.validate(obj); - }).should.throw(/Instance undefined has a property named price which is not declared in org.accordproject.test.Product/); + }).should.throw(/Instance "undefined" has a property named "price", which is not declared in "org.accordproject.test.Product"./); }); it('should fail with invalid enum', () => { @@ -305,7 +305,7 @@ describe('concerto', () => { (() => { concerto.validate(obj); - }).should.throw(/Instance org.accordproject.test.Customer#123456789 invalid enum value FOO for field Department/); + }).should.throw(/Model violation in the "org.accordproject.test.Customer#123456789" instance. Invalid enum value of "FOO" for the field "Department"./); }); it('should fail with empty identifier', () => { @@ -318,7 +318,7 @@ describe('concerto', () => { (() => { concerto.validate(obj); - }).should.throw(/Instance org.accordproject.test.Customer# has an empty identifier./); + }).should.throw(/Instance "org.accordproject.test.Customer#" has an empty identifier./); }); it('should fail with missing required property', () => { @@ -330,7 +330,7 @@ describe('concerto', () => { (() => { concerto.validate(obj); - }).should.throw(/Instance org.accordproject.test.Customer#001 missing required field department/); + }).should.throw(/The instance "org.accordproject.test.Customer#001" is missing the required field "department"./); }); it('should fail with string used for string[]', () => { @@ -343,7 +343,7 @@ describe('concerto', () => { (() => { concerto.validate(obj); - }).should.throw(/Model violation in instance org.accordproject.test.Employee#001 field pets has value/); + }).should.throw(/Model violation in the "org.accordproject.test.Employee#001" instance. The field "pets" has a value of ""cat"" \(type of value: "string"\). Expected type of value: "String\[\]"./); }); it('should fail with abstract type', () => { @@ -355,7 +355,7 @@ describe('concerto', () => { (() => { concerto.validate(obj); - }).should.throw(/The class org.accordproject.test.Person is abstract. Should not have an instance!/); + }).should.throw(/The class "org.accordproject.test.Person" is abstract and should not contain an instance./); }); }); diff --git a/packages/concerto-core/test/factory.js b/packages/concerto-core/test/factory.js index 2c6fc463d4..e9a478518f 100644 --- a/packages/concerto-core/test/factory.js +++ b/packages/concerto-core/test/factory.js @@ -192,7 +192,7 @@ describe('Factory', function() { it('should throw if concept is abstract', () => { (() => { factory.newConcept(namespace, 'AbstractConcept'); - }).should.throw(/Cannot instantiate Abstract Type AbstractConcept in namespace org.acme.test/); + }).should.throw(/Cannot instantiate the abstract type "AbstractConcept" in the "org.acme.test" namespace./); }); it('should create a new concept', () => { diff --git a/packages/concerto-core/test/introspect/assetdeclaration.js b/packages/concerto-core/test/introspect/assetdeclaration.js index 10a4fd923c..97e42e6ce6 100644 --- a/packages/concerto-core/test/introspect/assetdeclaration.js +++ b/packages/concerto-core/test/introspect/assetdeclaration.js @@ -88,7 +88,7 @@ describe('AssetDeclaration', () => { let asset = loadAssetDeclaration('test/data/parser/assetdeclaration.numid.cto'); (() => { asset.validate(); - }).should.throw(/type of the field is not String/); + }).should.throw(/Class "TestAsset" is identified by field "assetId", but the type of the field is not "String". Line 19 column 1, to line 21 column 2. /); }); it('should throw when identifying field is optional', () => { diff --git a/packages/concerto-core/test/introspect/identifieddeclaration.js b/packages/concerto-core/test/introspect/identifieddeclaration.js index ac6dbaea13..806c2f83c4 100644 --- a/packages/concerto-core/test/introspect/identifieddeclaration.js +++ b/packages/concerto-core/test/introspect/identifieddeclaration.js @@ -104,15 +104,15 @@ asset Order identified by sku { (() => { mm.addCTOModel( ` namespace test - + asset Order identified by sku { o String sku o Double price } - + asset FancyOrder identified extends Order { } - + `, 'test.cto'); }).should.throw(/Super class test.Order has an explicit identifier sku that cannot be redeclared./); }); @@ -123,13 +123,13 @@ asset Order identified by sku { (() => { mm.addCTOModel( ` namespace test - + asset FancyOrder identified { o String sku } - + `, 'test.cto'); - }).should.throw(/Class FancyOrder has more than one field named \(\$identifier\)/); + }).should.throw(/Class "FancyOrder" has more than one field named "\$identifier". File 'test.cto': line 4 column 17, to line 6 column 18. /); }); it('should not allow overriding explicit identifier with a system identifier', () => { @@ -138,16 +138,16 @@ asset Order identified by sku { (() => { mm.addCTOModel( ` namespace test - + asset Order identified by sku { o Double price o String sku } - + asset FancyOrder identified extends Order { o String model } - + `, 'test.cto'); }).should.throw(/Super class test.Order has an explicit identifier sku that cannot be redeclared./); }); @@ -158,16 +158,16 @@ asset Order identified by sku { (() => { mm.addCTOModel( ` namespace test - + asset Order identified by sku { o Double price o String sku } - + asset FancyOrder identified by model extends Order { o String model } - + `, 'test.cto'); }).should.throw(/Super class test.Order has an explicit identifier sku that cannot be redeclared./); }); @@ -178,7 +178,7 @@ asset Order identified by sku { (() => { mm.addCTOModel( ` namespace test - + asset Order { o String $identifier }`, 'test.cto'); @@ -189,11 +189,11 @@ asset Order identified by sku { const mm = new ModelManager(); mm.addCTOModel( ` namespace test - + abstract asset Order { o Double price } - + asset FancyOrder identified by sku extends Order { o String sku } diff --git a/packages/concerto-core/test/model/relationship.js b/packages/concerto-core/test/model/relationship.js index 5f719fed0c..e6401cd89f 100644 --- a/packages/concerto-core/test/model/relationship.js +++ b/packages/concerto-core/test/model/relationship.js @@ -132,13 +132,13 @@ describe('Relationship', function () { it('check invalid name space gets error', function() { (function () { Relationship.fromURI(modelManager, '123', 'org.acme.empty', 'Person' ); - }).should.throw(/Namespace is not defined for type org.acme.empty/); + }).should.throw(/Namespace is not defined for type "org.acme.empty.Person"./); }); - it('check that relationships can be created from a URI', function() { + it('', function() { (function () { Relationship.fromURI(modelManager, 'resource:org.acme.l1.Unkown#123' ); - }).should.throw(/Type Unkown is not defined in namespace org.acme.l1/); + }).should.throw(/Type "Unkown" is not defined in namespace "org.acme.l1"./); }); it('should error on invalid URI scheme', function() { diff --git a/packages/concerto-core/test/models/model.js b/packages/concerto-core/test/models/model.js index ad09aef0ab..97ef24c3e0 100644 --- a/packages/concerto-core/test/models/model.js +++ b/packages/concerto-core/test/models/model.js @@ -71,7 +71,7 @@ describe('Model Tests', function(){ let factory = new Factory(modelManager); // attempt to create an abstract asset - assert.throws( function() {factory.newResource('org.acme.base', 'AbstractAsset', '123' );}, /.+Cannot instantiate Abstract Type AbstractAsset in namespace org.acme.base/, 'did not throw with expected message'); + assert.throws( function() {factory.newResource('org.acme.base', 'AbstractAsset', '123' );}, 'Error: Cannot instantiate Abstract Type "AbstractAsset" in namespace "org.acme.base".'); // create a new instance let resource = factory.newResource( @@ -83,75 +83,75 @@ describe('Model Tests', function(){ // o String stringProperty resource.setPropertyValue('stringProperty', 'string'); resource.stringProperty.should.equal('string'); - assert.throws( function() {resource.setPropertyValue('stringProperty', 1);}, /.+expected type String/, 'did not throw with expected message'); + assert.throws( function() {resource.setPropertyValue('stringProperty', 1);}, /ValidationException: Model violation in the "org.acme.base.BaseAsset#123" instance. The field "stringProperty" has a value of "1" \(type of value: "number"\). Expected type of value: "String"./); // o Integer integerProperty resource.setPropertyValue('integerProperty', 999); resource.integerProperty.should.equal(999); - assert.throws( function() {resource.setPropertyValue('integerProperty', 'Foo');}, /.+expected type Integer/, 'did not throw with expected message'); + assert.throws( function() {resource.setPropertyValue('integerProperty', 'Foo');}, /ValidationException: Model violation in the "org.acme.base.BaseAsset#123" instance. The field "integerProperty" has a value of ""Foo"" \(type of value: "string"\). Expected type of value: "Integer"./); // o Double doubleProperty resource.setPropertyValue('doubleProperty', 10.0); resource.doubleProperty.should.equal(10.0); - assert.throws( function() {resource.setPropertyValue('doubleProperty', 'Foo');}, /.+expected type Double/, 'did not throw with expected message'); + assert.throws( function() {resource.setPropertyValue('doubleProperty', 'Foo');}, /ValidationException: Model violation in the "org.acme.base.BaseAsset#123" instance. The field "doubleProperty" has a value of ""Foo"" \(type of value: "string"\). Expected type of value: "Double"./); // o Boolean booleanProperty resource.setPropertyValue('booleanProperty', true ); resource.booleanProperty.should.equal(true); - assert.throws( function() {resource.setPropertyValue('booleanProperty', 'Foo');}, /.+expected type Boolean/, 'did not throw with expected message'); + assert.throws( function() {resource.setPropertyValue('booleanProperty', 'Foo');}, /ValidationException: Model violation in the "org.acme.base.BaseAsset#123" instance. The field "booleanProperty" has a value of ""Foo"" \(type of value: "string"\). Expected type of value: "Boolean"./); // o DateTime dateTimeProperty const dateTime = dayjs.utc('2016-10-11T02:30:26.262Z'); resource.setPropertyValue('dateTimeProperty', dateTime ); resource.dateTimeProperty.should.equal(dateTime); - assert.throws( function() {resource.setPropertyValue('dateTimeProperty', 'Foo');}, /.+expected type DateTime/, 'did not throw with expected message'); + assert.throws( function() {resource.setPropertyValue('dateTimeProperty', 'Foo');}, /ValidationException: Model violation in the "org.acme.base.BaseAsset#123" instance. The field "dateTimeProperty" has a value of ""Foo"" \(type of value: "string"\). Expected type of value: "DateTime"./); // o Long longProperty resource.setPropertyValue('longProperty', 100 ); resource.longProperty.should.equal(100); - assert.throws( function() {resource.setPropertyValue('longProperty', 'Foo');}, /.+expected type Long/, 'did not throw with expected message'); + assert.throws( function() {resource.setPropertyValue('longProperty', 'Foo');}, /ValidationException: Model violation in the "org.acme.base.BaseAsset#123" instance. The field "longProperty" has a value of ""Foo"" \(type of value: "string"\). Expected type of value: "Long"./); // o State stateProperty resource.setPropertyValue('stateProperty', 'GOLD' ); resource.stateProperty.should.equal('GOLD'); - assert.throws( function() {resource.setPropertyValue('stateProperty', 'Foo');}, /.+for field State/, 'did not throw with expected message'); - assert.throws( function() {resource.setPropertyValue('stateProperty', 1);}, /.+for field State/, 'did not throw with expected message'); + assert.throws( function() {resource.setPropertyValue('stateProperty', 'Foo');}, /ValidationException: Model violation in the "org.acme.base.BaseAsset#123" instance. Invalid enum value of "Foo" for the field "State"./); + assert.throws( function() {resource.setPropertyValue('stateProperty', 1);}, /ValidationException: Model violation in the "org.acme.base.BaseAsset#123" instance. Invalid enum value of "1" for the field "State"./); // o String[] stringArrayProperty resource.setPropertyValue('stringArrayProperty', ['string'] ); resource.stringArrayProperty.should.contain('string'); - assert.throws( function() {resource.setPropertyValue('stringArrayProperty', 1);}, /.+expected type String\[\]/, 'did not throw with expected message'); + assert.throws( function() {resource.setPropertyValue('stringArrayProperty', 1);}, /ValidationException: Model violation in the "org.acme.base.BaseAsset#123" instance. The field "stringArrayProperty" has a value of "1" \(type of value: "number"\). Expected type of value: "String\[\]"./); // o Integer[] integerArrayProperty resource.setPropertyValue('integerArrayProperty', [999] ); resource.integerArrayProperty.should.contain(999); - assert.throws( function() {resource.setPropertyValue('integerArrayProperty', 'Foo');}, /.+expected type Integer\[\]/, 'did not throw with expected message'); + assert.throws( function() {resource.setPropertyValue('integerArrayProperty', 'Foo');}, /ValidationException: Model violation in the "org.acme.base.BaseAsset#123" instance. The field "integerArrayProperty" has a value of ""Foo"" \(type of value: "string"\). Expected type of value: "Integer\[\]"./); // o Double[] doubleArrayProperty resource.setPropertyValue('doubleArrayProperty', [999.0] ); resource.doubleArrayProperty.should.contain(999.0); - assert.throws( function() {resource.setPropertyValue('doubleArrayProperty', 'Foo');}, /.+expected type Double\[\]/, 'did not throw with expected message'); + assert.throws( function() {resource.setPropertyValue('doubleArrayProperty', 'Foo');}, /ValidationException: Model violation in the "org.acme.base.BaseAsset#123" instance. The field "doubleArrayProperty" has a value of ""Foo"" \(type of value: "string"\). Expected type of value: "Double\[\]"./); // o Boolean[] booleanArrayProperty resource.setPropertyValue('booleanArrayProperty', [true, false] ); resource.booleanArrayProperty.should.contain(true); - assert.throws( function() {resource.setPropertyValue('booleanArrayProperty', 'Foo');}, /.+expected type Boolean\[\]/, 'did not throw with expected message'); + assert.throws( function() {resource.setPropertyValue('booleanArrayProperty', 'Foo');}, /ValidationException: Model violation in the "org.acme.base.BaseAsset#123" instance. The field "booleanArrayProperty" has a value of ""Foo"" \(type of value: "string"\). Expected type of value: "Boolean\[\]"./); // o DateTime[] dateTimeArrayProperty resource.setPropertyValue('dateTimeArrayProperty', [dateTime] ); resource.dateTimeArrayProperty.should.contain(dateTime); - assert.throws( function() {resource.setPropertyValue('dateTimeArrayProperty', 'Foo');}, /.+expected type DateTime\[\]/, 'did not throw with expected message'); + assert.throws( function() {resource.setPropertyValue('dateTimeArrayProperty', 'Foo');}, /ValidationException: Model violation in the "org.acme.base.BaseAsset#123" instance. The field "dateTimeArrayProperty" has a value of ""Foo"" \(type of value: "string"\). Expected type of value: "DateTime\[\]"./); // o Long[] longArrayProperty resource.setPropertyValue('longArrayProperty', [1,2,3] ); resource.longArrayProperty.should.contain(3); - assert.throws( function() {resource.setPropertyValue('longArrayProperty', 'Foo');}, /.+expected type Long\[\]/, 'did not throw with expected message'); + assert.throws( function() {resource.setPropertyValue('longArrayProperty', 'Foo');}, /ValidationException: Model violation in the "org.acme.base.BaseAsset#123" instance. The field "longArrayProperty" has a value of ""Foo"" \(type of value: "string"\). Expected type of value: "Long\[\]"./); // o State[] stateArrayProperty resource.setPropertyValue('stateArrayProperty', ['GOLD', 'SILVER'] ); resource.stateArrayProperty.should.contain('SILVER'); - assert.throws( function() {resource.setPropertyValue('stateArrayProperty', ['GOLD', 'Foo']);}, /.+for field State/, 'did not throw with expected message'); - assert.throws( function() {resource.setPropertyValue('stateArrayProperty', 'GOLD');}, /.+expected type State\[\]/, 'did not throw with expected message'); + assert.throws( function() {resource.setPropertyValue('stateArrayProperty', ['GOLD', 'Foo']);}, 'ValidationException: Model violation in the "org.acme.base.BaseAsset#123" instance. Invalid enum value of "Foo" for the field "State".'); + assert.throws( function() {resource.setPropertyValue('stateArrayProperty', 'GOLD');}, /ValidationException: Model violation in the "org.acme.base.BaseAsset#123" instance. The field "stateArrayProperty" has a value of ""GOLD"" \(type of value: "string"\). Expected type of value: "State\[\]"./); // set the relationships const personRelationship = factory.newRelationship('org.acme.base', 'Person', 'DAN' ); @@ -160,7 +160,7 @@ describe('Model Tests', function(){ // set an invalid relationship const blokeRelationship = factory.newRelationship('org.acme.base', 'Bloke', 'DAN' ); - assert.throws( function() {resource.setPropertyValue('singlePerson', blokeRelationship );}, /.+not derived from org.acme.base.Person/, 'did not throw with expected message'); + assert.throws( function() {resource.setPropertyValue('singlePerson', blokeRelationship );}, /ValidationException: Instance "org.acme.base.BaseAsset#123" has a property "singlePerson" with type "org.acme.base.Bloke" that is not derived from "org.acme.base.Person"./); // create a Person const person = factory.newResource('org.acme.base', 'Person', 'P1' ); @@ -182,22 +182,22 @@ describe('Model Tests', function(){ resource.myPeople = [person,person]; - assert.throws( function() {resource.validate();}, /.+type org.acme.base.Bloke that is not derived from org.acme.base.Person/, 'did not throw with expected message'); + assert.throws( function() {resource.validate();}, /ValidationException: Instance "org.acme.base.BaseAsset#123" has a property "myPerson" with type "org.acme.base.Bloke" that is not derived from "org.acme.base.Person"./); resource.myPerson = person; // set an extra property resource.blotto = 'Yes!'; - assert.throws( function() {resource.validate();}, /.+blotto which is not declared in org.acme.base.BaseAsset/, 'did not throw with expected message'); + assert.throws( function() {resource.validate();}, /ValidationException: Instance "123" has a property named "blotto", which is not declared in "org.acme.base.BaseAsset"./); delete resource.blotto; // set a missing property - assert.throws( function() {resource.setPropertyValue('missing', 'Foo');}, /.+trying to set field missing which is not declared in the model./, 'did not throw with expected message'); + assert.throws( function() {resource.setPropertyValue('missing', 'Foo');}, '/.+trying to set field missing which is not declared in the model./'); // add a missing array value - assert.throws( function() {resource.addArrayValue('missing', 'Foo');}, /.+trying to set field missing which is not declared in the model./, 'did not throw with expected message'); + assert.throws( function() {resource.addArrayValue('missing', 'Foo');}, /.+trying to set field missing which is not declared in the model./); // not an array - assert.throws( function() {resource.addArrayValue('longProperty', '[1]');}, /.+longProperty which is not declared as an array in the model./, 'did not throw with expected message'); + assert.throws( function() {resource.addArrayValue('longProperty', '[1]');}, /.+longProperty which is not declared as an array in the model./); const serializer = new Serializer(factory, modelManager); let json = serializer.toJSON(resource, { utcOffset: 0 }); @@ -236,12 +236,12 @@ describe('Model Tests', function(){ tx.setPropertyValue('myAsset', resource ); tx.myAsset.should.equal(resource); - assert.throws( function() {tx.setPropertyValue('myAsset', ['GOLD', 'Foo']);}, /.+GOLD,Foo expected a Resource./, 'did not throw with expected message'); + assert.throws( function() {tx.setPropertyValue('myAsset', ['GOLD', 'Foo']);}, /ValidationException: Model violation in the "org.acme.base.MyTransaction#TX_123" instance. Class "org.acme.base.BaseAsset" has the value of "GOLD,Foo". Expected a "Resource" or a "Concept"./); json = serializer.toJSON(tx); txEx.setPropertyValue('myAsset', resource ); txEx.myAsset.should.equal(resource); - assert.throws( function() {txEx.setPropertyValue('myAsset', txEx);}, /.+type org.acme.base.MyTransactionEx that is not derived from org.acme.base.BaseAsset/, 'did not throw with expected message'); + assert.throws( function() {txEx.setPropertyValue('myAsset', txEx);}, /ValidationException: Instance "org.acme.base.MyTransactionEx#TX_456" has a property "myAsset" with type "org.acme.base.MyTransactionEx" that is not derived from "org.acme.base.BaseAsset"./); const derivedDerivedAsset = factory.newResource('org.acme.base', 'DerivedDerivedAsset', 'DERIVED_001' ); diff --git a/packages/concerto-core/test/models/test.js b/packages/concerto-core/test/models/test.js index 42e73c62f4..5a53de2840 100644 --- a/packages/concerto-core/test/models/test.js +++ b/packages/concerto-core/test/models/test.js @@ -61,10 +61,10 @@ describe('Test Model', function(){ cObject.model.should.equal('CAPRI'); // now try some invalid values - ( function() {cObject.setPropertyValue('model', 1);}).should.throw(/.+expected type String/); - ( function() {cObject.setPropertyValue('model', true);}).should.throw(/.+expected type String/); - ( function() {cObject.setPropertyValue('model', dayjs.utc());}).should.throw(/.+expected type String/); - ( function() {cObject.setPropertyValue('model', [1,2,3]);}).should.throw(/.+expected type String/); + ( function() {cObject.setPropertyValue('model', 1);}).should.throw('Model violation in the "org.acme.Vehicle#CAR_123" instance. The field "model" has a value of "1" (type of value: "number"). Expected type of value: "String".'); + ( function() {cObject.setPropertyValue('model', true);}).should.throw('Model violation in the "org.acme.Vehicle#CAR_123" instance. The field "model" has a value of "true" (type of value: "boolean"). Expected type of value: "String".'); + ( function() {cObject.setPropertyValue('model', dayjs.utc());}).should.throw(/.+Expected type of value: "String"./); + ( function() {cObject.setPropertyValue('model', [1,2,3]);}).should.throw('Model violation in the "org.acme.Vehicle#CAR_123" instance. The field "model" has a value of "[1,2,3]" (type of value: "object"). Expected type of value: "String".'); }); }); @@ -190,35 +190,35 @@ describe('Test Model', function(){ // model is defined as a string // set model to a number cObject.model = 1; - ( function() {serializer.toJSON(cObject);}).should.throw(/.+expected type String/); + ( function() {serializer.toJSON(cObject);}).should.throw('Model violation in the "org.acme.Vehicle#CAR_123" instance. The field "model" has a value of "1" (type of value: "number"). Expected type of value: "String".'); // set model to a double cObject.model = 42.05; - ( function() {serializer.toJSON(cObject);}).should.throw(/.+expected type String/); + ( function() {serializer.toJSON(cObject);}).should.throw('Model violation in the "org.acme.Vehicle#CAR_123" instance. The field "model" has a value of "42.05" (type of value: "number"). Expected type of value: "String".'); // set model to a Boolean cObject.model = true; - ( function() {serializer.toJSON(cObject);}).should.throw(/.+expected type String/); + ( function() {serializer.toJSON(cObject);}).should.throw('Model violation in the "org.acme.Vehicle#CAR_123" instance. The field "model" has a value of "true" (type of value: "boolean"). Expected type of value: "String".'); // set model to a DateTime cObject.model = dayjs.utc(); - ( function() {serializer.toJSON(cObject);}).should.throw(/.+expected type String/); + ( function() {serializer.toJSON(cObject);}).should.throw(/Expected type of value: "String"./); // set model to an object cObject.model = { 'foo' : 'bar' }; - ( function() {serializer.toJSON(cObject);}).should.throw(/.+expected type String/); + ( function() {serializer.toJSON(cObject);}).should.throw('Model violation in the "org.acme.Vehicle#CAR_123" instance. The field "model" has a value of "{"foo":"bar"}" (type of value: "object"). Expected type of value: "String".'); // set model to null cObject.model = null; - ( function() {serializer.toJSON(cObject);}).should.throw(/.+missing required field model/); + ( function() {serializer.toJSON(cObject);}).should.throw('The instance "org.acme.Vehicle#CAR_123" is missing the required field "model".'); // set model to an array cObject.model = ['1','2']; - ( function() {serializer.toJSON(cObject);}).should.throw(/.+expected type String/); + ( function() {serializer.toJSON(cObject);}).should.throw('Model violation in the "org.acme.Vehicle#CAR_123" instance. The field "model" has a value of "["1","2"]" (type of value: "object"). Expected type of value: "String".'); // set model to a function cObject.model = function() {throw new Error('OOps');}; - ( function() {serializer.toJSON(cObject);}).should.throw(/.+expected type String/); + ( function() {serializer.toJSON(cObject);}).should.throw('Model violation in the "org.acme.Vehicle#CAR_123" instance. The field "model" has a value of "undefined" (type of value: "function"). Expected type of value: "String".'); }); }); diff --git a/packages/concerto-core/test/serializer.js b/packages/concerto-core/test/serializer.js index bb5477e212..6b95b7e0b2 100644 --- a/packages/concerto-core/test/serializer.js +++ b/packages/concerto-core/test/serializer.js @@ -85,13 +85,13 @@ describe('Serializer', () => { it('should throw if factory not specified', () => { (() => { new Serializer(null, modelManager); - }).should.throw(/Factory cannot be null/); + }).should.throw(/"Factory" cannot be "null"./); }); it('should throw if modelManager not specified', () => { (() => { new Serializer(factory, null); - }).should.throw(/ModelManager cannot be null/); + }).should.throw(/"ModelManager" cannot be "null"./); }); }); @@ -137,7 +137,7 @@ describe('Serializer', () => { resource.doubleValue = NaN; (() => { serializer.toJSON(resource); - }).should.throw(/Model violation in instance org.acme.sample.SampleAsset#1 field doubleValue has value NaN/); + }).should.throw(/Model violation in the "org.acme.sample.SampleAsset#1" instance. The field "doubleValue" has a value of "NaN"./); }); it('should throw validation errors during JSON object generation if Double is Infinity', () => { @@ -147,7 +147,7 @@ describe('Serializer', () => { resource.doubleValue = Infinity; (() => { serializer.toJSON(resource); - }).should.throw(/Model violation in instance org.acme.sample.SampleAsset#1 field doubleValue has value Infinity/); + }).should.throw(/Model violation in the "org.acme.sample.SampleAsset#1" instance. The field "doubleValue" has a value of "Infinity"./); }); it('should throw validation errors during JSON object generation if Double is -Infinity', () => { @@ -157,14 +157,14 @@ describe('Serializer', () => { resource.doubleValue = -Infinity; (() => { serializer.toJSON(resource); - }).should.throw(/Model violation in instance org.acme.sample.SampleAsset#1 field doubleValue has value -Infinity/); + }).should.throw(/Model violation in the "org.acme.sample.SampleAsset#1" instance. The field "doubleValue" has a value of "-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'); (() => { serializer.toJSON(resource); - }).should.throw(/missing required field/); + }).should.throw('The instance "org.acme.sample.SampleAsset#1" is missing the required field "owner".'); }); it('should throw validation errors during JSON object generation if the validate flag is set to true and errors are present', () => { @@ -173,7 +173,7 @@ describe('Serializer', () => { serializer.toJSON(resource, { validate: true }); - }).should.throw(/missing required field/); + }).should.throw('The instance "org.acme.sample.SampleAsset#1" is missing the required field "owner".'); }); it('should generate a JSON object if errors are present but the validate flag is set to false', () => { @@ -206,7 +206,7 @@ describe('Serializer', () => { serializer.toJSON(resource, { validate: true }); - }).should.throw(/missing required field/); + }).should.throw('The instance "org.acme.sample.SampleAsset#1" is missing the required field "owner".'); }); it('should generate a concept', () => { @@ -329,7 +329,7 @@ describe('Serializer', () => { }; (() => { serializer.fromJSON(json); - }).should.throw(/missing required field/); + }).should.throw('The instance "org.acme.sample.SampleAsset#1" is missing the required field "stringValue".'); }); it('should throw validation errors if the validate flag is set to true', () => { @@ -340,7 +340,7 @@ describe('Serializer', () => { }; (() => { serializer.fromJSON(json, { validate: true }); - }).should.throw(/missing required field/); + }).should.throw('The instance "org.acme.sample.SampleAsset#1" is missing the required field "stringValue".'); }); it('should not validate if the validate flag is set to false', () => { @@ -381,7 +381,7 @@ describe('Serializer', () => { }; (() => { serializer.fromJSON(json, { validate: true }); - }).should.throw(/missing required field/); + }).should.throw('The instance "org.acme.sample.SampleAsset#1" is missing the required field "stringValue".'); }); it('should error on unexpected properties', () => { diff --git a/packages/concerto-core/test/serializer/instancegenerator.js b/packages/concerto-core/test/serializer/instancegenerator.js index 65127381cc..eda313f438 100644 --- a/packages/concerto-core/test/serializer/instancegenerator.js +++ b/packages/concerto-core/test/serializer/instancegenerator.js @@ -391,7 +391,7 @@ describe('InstanceGenerator', () => { o BaseConcept aConcept }`); } catch (error) { - error.should.match(/^Error: No concrete extending type for org.acme.test.BaseConcept$/); + error.should.match(/^Error: No concrete extending type for "org.acme.test.BaseConcept".$/); } }); diff --git a/packages/concerto-core/test/serializer/objectvalidator.js b/packages/concerto-core/test/serializer/objectvalidator.js index e16b3901ac..618dc608c1 100644 --- a/packages/concerto-core/test/serializer/objectvalidator.js +++ b/packages/concerto-core/test/serializer/objectvalidator.js @@ -92,7 +92,7 @@ describe('ObjectValidator', function () { (function () { objectValidator.visit(concerto.getTypeDeclaration(data), parameters); - }).should.throw(/expected type TestEnum\[\]/); + }).should.throw('Model violation in the "undefined" instance. The field "testEnums" has a value of ""ONE"" (type of value: "string"). Expected type of value: "TestEnum[]".'); }); it('should pass', () => { @@ -121,7 +121,7 @@ describe('ObjectValidator', function () { (function () { objectValidator.visit(concerto.getTypeDeclaration(data), parameters); - }).should.throw(/expected type Integer/); + }).should.throw('Model violation in the "undefined" instance. The field "integerProperty" has a value of ""bad"" (type of value: "string"). Expected type of value: "Integer".'); }); it('should fail if property not a string', () => { @@ -134,7 +134,7 @@ describe('ObjectValidator', function () { (function () { objectValidator.visit(concerto.getTypeDeclaration(data), parameters); - }).should.throw(/expected type String/); + }).should.throw('Model violation in the "undefined" instance. The field "stringProperty" has a value of "1" (type of value: "number"). Expected type of value: "String".'); }); it('should fail if property type is symbol', () => { @@ -147,7 +147,7 @@ describe('ObjectValidator', function () { (function () { objectValidator.visit(concerto.getTypeDeclaration(data), parameters); - }).should.throw(/expected type String/); + }).should.throw('Model violation in the "undefined" instance. The field "stringProperty" has a value of "undefined" (type of value: "symbol"). Expected type of value: "String".'); }); it('should fail if property not a boolean', () => { @@ -160,7 +160,7 @@ describe('ObjectValidator', function () { (function () { objectValidator.visit(concerto.getTypeDeclaration(data), parameters); - }).should.throw(/expected type Boolean/); + }).should.throw('Model violation in the "undefined" instance. The field "booleanProperty" has a value of ""false"" (type of value: "string"). Expected type of value: "Boolean".'); }); it('should fail if property not a DateTime', () => { @@ -173,7 +173,7 @@ describe('ObjectValidator', function () { (function () { objectValidator.visit(concerto.getTypeDeclaration(data), parameters); - }).should.throw(/expected type DateTime/); + }).should.throw('Model violation in the "undefined" instance. The field "dateTimeProperty" has a value of "true" (type of value: "boolean"). Expected type of value: "DateTime".'); }); it('should fail if property fails field validator', () => { @@ -202,7 +202,7 @@ describe('ObjectValidator', function () { (function () { objectValidator.visit(concerto.getTypeDeclaration(data), parameters); - }).should.throw(/test.Wheel that is not derived from test.Person/); + }).should.throw('Instance "undefined" has a property "owner" with type "test.Wheel" that is not derived from "test.Person".'); }); it('should fail complex property that references a missing type', () => { @@ -218,7 +218,7 @@ describe('ObjectValidator', function () { (function () { objectValidator.visit(concerto.getTypeDeclaration(data), parameters); - }).should.throw(/Type Missing is not defined in namespace test/); + }).should.throw('Type "Missing" is not defined in namespace "test".'); }); }); @@ -233,7 +233,7 @@ describe('ObjectValidator', function () { (function () { objectValidator.visit(concerto.getTypeDeclaration(data), parameters); - }).should.throw(/Instance undefined has property previousOwners with type undefined that is not derived from test.Person\[\]/); + }).should.throw('Instance "undefined" has a property "previousOwners" with type "undefined" that is not derived from "test.Person[]".'); }); }); @@ -264,7 +264,7 @@ describe('ObjectValidator', function () { parameters.stack = new TypedStack(data); (function () { objectValidator.visit(concerto.getTypeDeclaration(data), parameters); - }).should.throw(/expected a Relationship/); + }).should.throw('Model violation in the "undefined" instance. Class "test.Person" has a value of "[object Object]". Expected a "Relationship".'); }); it('should fail with non-identifiable instance if convertResourcesToRelationships is not set', () => { @@ -279,7 +279,7 @@ describe('ObjectValidator', function () { parameters.stack = new TypedStack(data); (function () { objectValidator.visit(concerto.getTypeDeclaration(data), parameters); - }).should.throw(/expected a Relationship/); + }).should.throw('Model violation in the "undefined" instance. Class "test.Person" has a value of "[object Object]". Expected a "Relationship".'); }); it('should fail with a relationship to a non identifiable type', () => { @@ -303,7 +303,7 @@ describe('ObjectValidator', function () { parameters.stack = new TypedStack(data); (function () { objectValidator.visit(concerto.getTypeDeclaration(data), parameters); - }).should.throw(/not derived from test.Person/); + }).should.throw('Instance "undefined" has a property "lastOwner" with type "undefined" that is not derived from "test.Person".'); }); diff --git a/packages/concerto-core/test/serializer/resourcevalidator.js b/packages/concerto-core/test/serializer/resourcevalidator.js index 5d83f4f77b..7e861b954e 100644 --- a/packages/concerto-core/test/serializer/resourcevalidator.js +++ b/packages/concerto-core/test/serializer/resourcevalidator.js @@ -160,7 +160,7 @@ describe('ResourceValidator', function () { const parameters = { stack : typedStack, 'modelManager' : modelManager, rootResourceIdentifier : 'TEST' }; (function () { field.accept(resourceValidator,parameters ); - }).should.throw(/.+expected a Relationship/); + }).should.throw('Model violation in the "TEST" instance. Class "org.acme.l1.Person" has a value of "Resource {id=org.acme.l1.Employee#DAN}". Expected a "Relationship".'); }); it('should allow assigning a relationship to a derived type', function () { const baseRel = factory.newRelationship('org.acme.l2', 'PrivateOwner', 'DAN'); @@ -188,7 +188,7 @@ describe('ResourceValidator', function () { const parameters = { stack : typedStack, 'modelManager' : modelManager, rootResourceIdentifier : 'TEST' }; (function () { vehicleDeclaration.accept(resourceValidator,parameters ); - }).should.throw(/has property owners with type/); + }).should.throw('Instance "org.acme.l3.Car#123" has a property "owners" with type "org.acme.l1.Person" that is not derived from "org.acme.l1.Person[]".'); }); }); @@ -211,7 +211,7 @@ describe('ResourceValidator', function () { const parameters = { stack : typedStack, 'modelManager' : modelManager, rootResourceIdentifier : 'TEST' }; (function () { field.accept(resourceValidator,parameters ); - }).should.throw(/Instance TEST has property containment with type org.acme.l1.Base that is not derived from org.acme.l1.Person/); + }).should.throw('Instance "TEST" has a property "containment" with type "org.acme.l1.Base" that is not derived from "org.acme.l1.Person[]".'); }); it('should allow assigning a derived type', function () { @@ -231,7 +231,7 @@ describe('ResourceValidator', function () { const parameters = { stack : typedStack, 'modelManager' : modelManager, rootResourceIdentifier : 'TEST' }; (function () { field.accept(resourceValidator,parameters ); - }).should.throw(/Instance TEST has property owner with type org.acme.l1.Base that is not derived from org.acme.l1.Person/); + }).should.throw('Instance "TEST" has a property "owner" with type "org.acme.l1.Base" that is not derived from "org.acme.l1.Person".'); }); it('should detect using a number type for a string field', function () { @@ -242,7 +242,7 @@ describe('ResourceValidator', function () { (function () { field.accept(resourceValidator,parameters ); - }).should.throw(/Model violation in instance TEST field model has value 123 \(number\) expected type String/); + }).should.throw(/Model violation in the "TEST" instance. The field "model" has a value of "123" \(type of value: "number"\). Expected type of value: "String"./); }); it('should detect using a date type for a string field', function () { @@ -253,7 +253,7 @@ describe('ResourceValidator', function () { (function () { field.accept(resourceValidator,parameters ); - }).should.throw(/Model violation in instance TEST field model has value "2016-10-13T14:49:47.971Z" \(object\) expected type String/); + }).should.throw('Model violation in the "TEST" instance. The field "model" has a value of ""2016-10-13T14:49:47.971Z"" (type of value: "object"). Expected type of value: "String".'); }); it('should detect using a boolean type for a string field', function () { @@ -264,7 +264,7 @@ describe('ResourceValidator', function () { (function () { field.accept(resourceValidator,parameters ); - }).should.throw(/Model violation in instance TEST field model has value false \(boolean\) expected type String/); + }).should.throw('Model violation in the "TEST" instance. The field "model" has a value of "false" (type of value: "boolean"). Expected type of value: "String".'); }); it('should detect using an array type for string field', function () { @@ -275,7 +275,7 @@ describe('ResourceValidator', function () { (function () { field.accept(resourceValidator,parameters ); - }).should.throw(/Model violation in instance TEST field model has value \["FOO"\] \(object\) expected type String/); + }).should.throw('Model violation in the "TEST" instance. The field "model" has a value of "["FOO"]" (type of value: "object"). Expected type of value: "String".'); }); it('should detect using an invalid array for string[] field', function () { @@ -286,7 +286,7 @@ describe('ResourceValidator', function () { (function () { field.accept(resourceValidator,parameters ); - }).should.throw(/Model violation in instance TEST field serviceHistory has value 1 \(number\) expected type String\[\]/); + }).should.throw('Model violation in the "TEST" instance. The field "serviceHistory" has a value of "1" (type of value: "number"). Expected type of value: "String[]".'); }); it('should detect using an invalid array for enum field', function () { @@ -297,7 +297,7 @@ describe('ResourceValidator', function () { (function () { field.accept(resourceValidator,parameters ); - }).should.throw(/Instance TEST invalid enum value 1 for field VehicleType/); + }).should.throw('Model violation in the "TEST" instance. Invalid enum value of "1" for the field "VehicleType".'); }); it('should allow using an valid array for enum field', function () { @@ -313,7 +313,7 @@ describe('ResourceValidator', function () { mockField.getName.returns('propName'); (() => { resourceValidator.visitField(mockField, {stack: {pop: () => {return undefined;}}}); - }).should.throw(/Model violation in instance undefined/); + }).should.throw('Model violation in the "undefined" instance. The field "propName" has a value of "undefined" (type of value: "undefined"). Expected type of value: "undefined".'); }); }); @@ -325,7 +325,7 @@ describe('ResourceValidator', function () { (function () { enumDeclaration.accept(resourceValidator,parameters ); - }).should.throw(/Instance TEST invalid enum value MISSING for field AnimalType/); + }).should.throw('Model violation in the "TEST" instance. Invalid enum value of "MISSING" for the field "AnimalType".'); }); it('should validate enum', function () { @@ -345,7 +345,7 @@ describe('ResourceValidator', function () { (function () { assetDeclaration.accept(resourceValidator,parameters ); - }).should.throw(/Model violation in instance ABC class org.acme.l2.Vehicle has value Invalid expected a Resource./); + }).should.throw('Model violation in the "ABC" instance. Class "org.acme.l2.Vehicle" has the value of "Invalid". Expected a "Resource" or a "Concept".'); }); it('should detect using a missing super type', function () { @@ -390,7 +390,7 @@ describe('ResourceValidator', function () { (function () { assetDeclaration.accept(resourceValidator,parameters ); - }).should.throw(/The class org.acme.l3.Car is abstract. Should not have an instance!/); + }).should.throw('The class "org.acme.l3.Car" is abstract and should not contain an instance.'); }); it('should detect additional field', function () { @@ -402,7 +402,7 @@ describe('ResourceValidator', function () { (function () { assetDeclaration.accept(resourceValidator,parameters ); - }).should.throw(/Instance ABC has a property named foo which is not declared in org.acme.l3.Car/); + }).should.throw('Instance "ABC" has a property named "foo", which is not declared in "org.acme.l3.Car".'); }); it('should detect an empty identifier', function () { @@ -432,7 +432,7 @@ describe('ResourceValidator', function () { (() => { assetDeclaration.accept(resourceValidator,parameters); - }).should.throw(/Model violation in instance org.acme.l3.Car#42 field milage has value NaN/); + }).should.throw('Model violation in the "org.acme.l3.Car#42" instance. The field "milage" has a value of "NaN" (type of value: "number"). Expected type of value: "Double".'); }); it('should report undeclared field if not identifiable', () => { @@ -445,7 +445,7 @@ describe('ResourceValidator', function () { (() => { resourceValidator.visitClassDeclaration(conceptDeclaration,parameters); - }).should.throw(/property named numberOfWipers which is not declared/); + }).should.throw('Instance "undefined" has a property named "numberOfWipers", which is not declared in "org.acme.l1.Data".'); }); }); @@ -462,7 +462,7 @@ describe('ResourceValidator', function () { mockIdentifiable.getFullyQualifiedIdentifier.returns('com.doge'); (() => { ResourceValidator.reportFieldTypeViolation('id', 'property', mockIdentifiable, mockField); - }).should.throw(/property has value com.doge \(doge\)/); + }).should.throw('Model violation in the "id" instance. The field "property" has a value of "com.doge" (type of value: "doge"). Expected type of value: "undefined".'); }); it('should not fail if strigify fails', () => { @@ -472,7 +472,7 @@ describe('ResourceValidator', function () { (() => { ResourceValidator.reportFieldTypeViolation('id', 'property', obj, mockField); - }).should.throw(/id field property has value/); + }).should.throw('Model violation in the "id" instance. The field "property" has a value of "[object Object]" (type of value: "object"). Expected type of value: "undefined".'); }); }); @@ -482,7 +482,7 @@ describe('ResourceValidator', function () { mockField.getName.returns('propName'); (() => { resourceValidator.checkItem(undefined, mockField, {rootResourceIdentifier: 'identifier'}); - }).should.throw(/Model violation in instance identifier field propName/); + }).should.throw('Model violation in the "identifier" instance. The field "propName" has a value of "undefined" (type of value: "undefined"). Expected type of value: "undefined".'); }); it('should throw if class declaration is not found', () => { @@ -499,7 +499,7 @@ describe('ResourceValidator', function () { (() => { resourceValidator.checkItem(mockIdentifiable, mockField, parameters); - }).should.throw(/Model violation in instance identifier field propName/); + }).should.throw('Model violation in the "identifier" instance. The field "propName" has a value of "undefined" (type of value: "undefined"). Expected type of value: "undefined".'); }); });