diff --git a/packages/concerto-core/src/introspect/classdeclaration.ts b/packages/concerto-core/src/introspect/classdeclaration.ts index e86fba57a9..d925a54a32 100644 --- a/packages/concerto-core/src/introspect/classdeclaration.ts +++ b/packages/concerto-core/src/introspect/classdeclaration.ts @@ -249,6 +249,10 @@ class ClassDeclaration extends Declaration { throw new IllegalModelException('Identifying fields cannot be optional.', this.modelFile, this.ast.location); } + if (idField.isArray()) { + throw new IllegalModelException('Identifying fields cannot be arrays.', this.modelFile, this.ast.location); + } + if(this.superType) { const superType = this.getModelFile().getType(this.superType); if (superType && superType.isIdentified() ) { diff --git a/packages/concerto-core/test/data/parser/assetdeclaration.arrayid.cto b/packages/concerto-core/test/data/parser/assetdeclaration.arrayid.cto new file mode 100644 index 0000000000..fcbb9495cd --- /dev/null +++ b/packages/concerto-core/test/data/parser/assetdeclaration.arrayid.cto @@ -0,0 +1,21 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace com.hyperledger.testing@1.0.0 + +import com.hyperledger.elsewhere@1.0.0.BaseAsset + +asset TestAsset identified by assetId { + o String[] assetId +} diff --git a/packages/concerto-core/test/introspect/assetdeclaration.js b/packages/concerto-core/test/introspect/assetdeclaration.js index 226d9ab6bf..c5dcbb85a5 100644 --- a/packages/concerto-core/test/introspect/assetdeclaration.js +++ b/packages/concerto-core/test/introspect/assetdeclaration.js @@ -98,6 +98,13 @@ describe('AssetDeclaration', () => { }).should.throw(/Identifying fields cannot be optional/); }); + it('should throw when identifying field is an array', () => { + let asset = loadAssetDeclaration('test/data/parser/assetdeclaration.arrayid.cto'); + (() => { + asset.validate(); + }).should.throw(/Identifying fields cannot be arrays/); + }); + it('should throw when field has been duplicated in the same class', () => { let asset = loadAssetDeclaration('test/data/parser/assetdeclaration.dupesimp.cto'); diff --git a/packages/concerto-core/test/introspect/classdeclaration.js b/packages/concerto-core/test/introspect/classdeclaration.js index 009cd4b841..2c549a435a 100644 --- a/packages/concerto-core/test/introspect/classdeclaration.js +++ b/packages/concerto-core/test/introspect/classdeclaration.js @@ -97,6 +97,73 @@ describe('ClassDeclaration', () => { const clazz = introspectUtils.loadLastDeclaration('test/data/parser/classdeclaration.scalararray.cto', ConceptDeclaration); clazz.validate(); }); + + it('should throw when a string array is used as an identifier', () => { + const mm = new ModelManager(); + (() => { + mm.addCTOModel(` +namespace com.testing@1.0.0 +asset Person identified by names { + o String[] names +} + `); + }).should.throw(/Identifying fields cannot be arrays/); + }); + + it('should throw when a scalar string array is used as an identifier', () => { + const mm = new ModelManager(); + (() => { + mm.addCTOModel(` +namespace com.testing@1.0.0 +scalar SSN extends String default="000-00-0000" regex=/\\d{3}-\\d{2}-\\d{4}/ +concept Person identified by ssnArray { + o SSN[] ssnArray +} + `); + }).should.throw(/Identifying fields cannot be arrays/); + }); + + it('should throw when an inherited string array is used as an identifier', () => { + const mm = new ModelManager(); + (() => { + mm.addCTOModel(` +namespace com.testing@1.0.0 +abstract asset Base { + o String[] ids +} +asset Child identified by ids extends Base { +} + `); + }).should.throw(/Identifying fields cannot be arrays/); + }); + + it('should throw when a participant is identified by an array', () => { + const mm = new ModelManager(); + (() => { + mm.addCTOModel(` +namespace com.testing@1.0.0 +participant Member identified by memberIds { + o String[] memberIds +} + `); + }).should.throw(/Identifying fields cannot be arrays/); + }); + + it('should throw when a 3rd-level subclass is identified by an array defined in a root class', () => { + const mm = new ModelManager(); + (() => { + mm.addCTOModel(` +namespace com.testing@1.0.0 +abstract concept Root { + o String[] codes +} +abstract concept Middle extends Root { +} +asset Leaf identified by codes extends Middle { +} + `); + }).should.throw(/Identifying fields cannot be arrays/); + }); }); describe('#accept', () => {