Commit b608bcb0 authored by Nicolas Biri's avatar Nicolas Biri

Externalize ConformanceCheck

parent 0d6d6b1a
Pipeline #749 passed with stage
in 54 seconds
{
"name": "jsmf-core",
"version": "0.8.0",
"version": "0.9.0",
"description": "Javascript Modelling Framework",
"main": "src/index.js",
"directories": {
......@@ -26,8 +26,7 @@
"license": "MIT",
"dependencies": {
"lodash": "^4.1.0",
"uuid": "^2.0.1",
"jsmf-check": "git+ssh://git@git.list.lu:jsmf/jsmf-check.git#0.4.2"
"uuid": "^2.0.1"
},
"devDependencies": {
"should": "^7.1.1",
......
/**
* @license
* ©2015-2016 Luxembourg Institute of Science and Technology All Rights Reserved
* JavaScript Modelling Framework (JSMF)
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @author J.S. Sottet
* @author N. Biri
* @author A. Vagner
*/
'use strict'
const _ = require('lodash')
const check = require('jsmf-check')
, hasClass = require('./Class').hasClass
, Model = require('./Model').Model
let isJSMFElement, conformsTo
(function() {const Common = require('./Common')
isJSMFElement = Common.isJSMFElement
conformsTo = Common.conformsTo
}).call()
const attributesTypeRule = new check.Rule(
[ check.all(check.Reference('elements'))
, check.all(check.ContextualReference(function () {
return _.map(conformsTo(this[0]).getAllAttributes(), (desc, name) => {return {name, desc}})
}))
],
(e, a) => {
const value = e[a.name]
return a.desc.type(value) || (!a.desc.mandatory && (_.isNull(value) || _.isUndefined(value)))
}
)
const referenceMinCardinalityRule = new check.Rule(
[ check.all(check.Reference('elements'))
, check.all(check.ContextualReference(function () {
return _.map(conformsTo(this[0]).getAllReferences(), (props, name) => {return {name, cardinality: props.cardinality}})
}))
],
(e, r) => e[r.name].length >= r.cardinality.min
)
const referenceMaxCardinalityRule = new check.Rule(
[ check.all(check.Reference('elements'))
, check.all(check.ContextualReference(function () {
return _.map(conformsTo(this[0]).getAllReferences(), (props, name) => {return {name, cardinality: props.cardinality}})
}))
],
(e, r) => e[r.name].length <= r.cardinality.max
)
const referencesTypeRule = new check.Rule(
[ check.all(check.Reference('elements'))
, check.all(check.ContextualReference(function () {
return _.map(conformsTo(this[0]).getAllReferences(), (props, name) => {return {name, type: props.type}})
}))
, check.all(check.ContextualReference(function () {
return this[0][this[1].name]
}))
],
(e, r, v) => {try { return hasClass(v, r.type) } catch (err) { return false }}
)
const associatedTypeRule = new check.Rule(
[ check.all(check.Reference('elements'))
, check.all(check.ContextualReference(function () {
return _.map(this[0].getAssociated(), (value, key) => {return {key, value}})
}))
, check.all(check.ContextualReference(function () { return this[1].value }))
],
(e, as, v) => {
const refs = conformsTo(e).getAllReferences()
const refType = refs[as.key].associated
try { return hasClass(v.associated, refType) } catch (err) { return false }
}
)
const nonExtraProperties = new check.Rule(
[ check.all(check.Reference('elements'))
, check.all(check.ContextualReference(function () {
return _.map(this[0], (value, name) => name)
}))
, check.raw(check.ContextualReference(function () {
const attrs = _.map(conformsTo(this[0]).getAllAttributes(), (type, name) => name)
const refs = _.map(conformsTo(this[0]).getAllReferences(), (type, name) => name)
return attrs.concat(refs)
}))
],
(e, elemA, classAs) => _.includes(classAs, elemA)
)
const conformance = new check.Checker()
conformance.rules =
{ attributesTypeRule
, referenceMinCardinalityRule
, referenceMaxCardinalityRule
, referencesTypeRule
, associatedTypeRule
, nonExtraProperties
}
conformance.helpers.elements = e => {
if (e instanceof Model) {
return e.elements()
}
if (isJSMFElement(e)) {
return (new Model('tmp', {}, e, true)).elements()
}
throw new TypeError(`Invalid argument for conformance: ${e}`)
}
module.exports = _.assign(conformance.rules, { conformance })
......@@ -30,7 +30,6 @@ const Class = require('./Class')
const Enum = require('./Enum')
const Cardinality = require('./Cardinality')
const Type = require('./Type')
const Conformance = require('./ConformanceCheck')
module.exports = _.assign(Common, Model, Class, Enum, Cardinality, Type, Conformance)
module.exports = _.assign(Common, Model, Class, Enum, Cardinality, Type)
'use strict'
const should = require('should')
const C = require('../src/Class')
const Co = require('../src/ConformanceCheck')
const Ca = require('../src/Cardinality')
const Sample = new C.Class('Sample', [], {name: {type: String, mandatory: true}, foo: Number})
Sample.addReference('test', Sample, Ca.Cardinality.one, undefined, undefined, Sample)
const WrongType = new C.Class('WrongType', [], {name: String, foo: Number})
describe('referenceMinCardinality rule', function () {
it ('is verified if Min cardinality is verified', function (done) {
const x = new Sample({name: 'x', foo: 42})
x.test = x
const result = Co.referenceMinCardinalityRule.run(undefined, {elements: [x]})
result.succeed.should.be.true()
done()
})
it ('fails if Min cardinality is not verified', function (done) {
const x = new Sample({name: 'x', foo: 42})
const result = Co.referenceMinCardinalityRule.run(undefined, {elements: [x]})
result.succeed.should.be.false()
done()
})
})
describe('referenceMaxCardinality rule', function () {
it ('is verified if Max cardinality is verified', function (done) {
const x = new Sample({name: 'x', foo: 42})
x.test = x
const result = Co.referenceMaxCardinalityRule.run(undefined, {elements: [x]})
result.succeed.should.be.true()
done()
})
it ('fails if Max cardinality is not verified', function (done) {
const x = new Sample({name: 'x', foo: 42})
const y = new Sample({name: 'y', foo: 42})
x.test = [x,y]
const result = Co.referenceMaxCardinalityRule.run(undefined, {elements: [x]})
result.succeed.should.be.false()
done()
})
})
describe('referenceType rule', function () {
it ('is verified if references type are correct', function (done) {
const x = new Sample({name: 'x', foo: 42})
x.test = x
const result = Co.referencesTypeRule.run(undefined, {elements: [x]})
result.succeed.should.be.true()
done()
})
it ('fails if types are not correct', function (done) {
const x = new Sample({name: 'x', foo: 42})
const y = new WrongType({name: 'y', foo: 42})
x.__jsmf__.references.test = [y]
const result = Co.referencesTypeRule.run(undefined, {elements: [x]})
result.succeed.should.be.false()
done()
})
})
describe('attributeType rule', function () {
it ('is verified if attributes type are correct', function (done) {
const x = new Sample({name: 'x', foo: 42})
x.test = x
const result = Co.attributesTypeRule.run(undefined, {elements: [x]})
result.succeed.should.be.true()
done()
})
it ('fails if types are not correct', function (done) {
const x = new Sample({name: 'x', foo: 42})
x.__jsmf__.attributes.foo = "wroooooong"
const result = Co.attributesTypeRule.run(undefined, {elements: [x]})
result.succeed.should.be.false()
done()
})
it ('fails if values are not defined for a mandatory attribute', function (done) {
const x = new Sample({foo: 42})
const result = Co.attributesTypeRule.run(undefined, {elements: [x]})
result.succeed.should.be.false()
done()
})
it ('passes if values are not defined for a non-mandatory attribute', function (done) {
const x = new Sample({name: 'x'})
const result = Co.attributesTypeRule.run(undefined, {elements: [x]})
result.succeed.should.be.true()
done()
})
})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment