UNPKG

jsmf-core

Version:

Javascript Modelling Framework

436 lines (380 loc) 18.5 kB
'use strict' const should = require('should') , JSMF = require('../src/index') , Class = JSMF.Class describe('Class', function() { describe('Class construction', function() { it('should have the given name', function(done) { var Instance = new Class('Instance') Instance.__name.should.equal('Instance') done() }) it('should ConformsTo Class', function(done) { var Instance = new Class('Instance') Instance.conformsTo().should.equal(Class) done() }) it('is a JSMF element', function(done) { var Instance = new Class('Instance') JSMF.isJSMFElement(Instance).should.be.true() done() }) it('has an UUID', function(done) { var s = new Class('S') should(JSMF.jsmfId(s)).not.equal(undefined) done() }) it('can be built with newInstance', function(done) { var Instance = Class.newInstance('Instance') Instance.__name.should.equal('Instance') done() }) }) describe('Class inheritance', function() { it('should work with assigniation of superClasses', function(done) { var Instance = new Class('Instance') var SuperInstance = new Class('SuperInstance') var NonRelatedInstance = new Class('NonRelatedInstance') Instance.superClasses = [SuperInstance] Instance.superClasses.should.containEql(SuperInstance) done() }), it('should work with push of new superClass', function(done) { var Instance = new Class('Instance') var SuperInstance = new Class('SuperInstance') var NonRelatedInstance = new Class('NonRelatedInstance') Instance.superClasses.push(SuperInstance) Instance.superClasses.should.containEql(SuperInstance) done() }), it('should work at class initialization', function(done) { var SuperInstance = new Class('SuperInstance') var Instance = new Class('Instance', SuperInstance) var NonRelatedInstance = new Class('NonRelatedInstance') Instance.superClasses = [SuperInstance] Instance.superClasses.should.containEql(SuperInstance) done() }), it('can be done in cascade', function(done) { var Instance = new Class('Instance') var SuperInstance = new Class('SuperInstance') var SuperSuperInstance = new Class('SuperSuperInstance') Instance.superClasses = [SuperInstance] SuperInstance.superClasses = [SuperSuperInstance] Instance.superClasses.should.containEql(SuperInstance) Instance.superClasses.should.not.containEql(SuperSuperInstance) SuperInstance.superClasses.should.containEql(SuperSuperInstance) SuperInstance.superClasses.should.not.containEql(SuperInstance) done() }), it('should support multi-inheritance', function(done) { var SuperInstance = new Class('SuperInstance') var OtherSuperInstance = new Class('OtherSuperInstance') var Instance = new Class('Instance', [SuperInstance, OtherSuperInstance]) Instance.superClasses.should.have.length(2) Instance.superClasses.should.containEql(SuperInstance) Instance.superClasses.should.containEql(OtherSuperInstance) done() }) }) describe('Class attributes', function() { it('allows jsmf primitive types', function(done) { var State = new Class('State') State.attributes.should.be.empty State.setAttribute('name', JSMF.String) State.attributes.should.have.property('name') State.attributes.name.should.have.property('type', JSMF.String) State.attributes.name.should.have.property('mandatory', false) done() }) it('allows normalize built-in primitive types', function(done) { var State = new Class('State') State.attributes.should.be.empty() State.setAttribute('name', String) State.attributes.should.have.property('name') State.attributes.name.should.have.property('type', JSMF.String) State.attributes.name.should.have.property('mandatory', false) done() }) it('allows mandatory attributes', function(done) { var State = new Class('State') State.attributes.should.be.empty() State.setAttribute('name', String, true) State.attributes.should.have.property('name') State.attributes.name.should.have.property('type', JSMF.String) State.attributes.name.should.have.property('mandatory', true) done() }) it('has addAttribute is a synonym to setAttribute', function(done) { var State = new Class('State') State.attributes.should.be.empty() State.addAttribute('name', JSMF.String) State.attributes.should.have.property('name') State.attributes.name.should.have.property('type', JSMF.String) State.attributes.name.should.have.property('mandatory', false) done() }) it('accept bulk setting', function(done) { var State = new Class('State') State.attributes.should.be.empty State.addAttributes({name: {type: JSMF.String, mandatory: true}, age: Number}) State.attributes.should.have.property('name') State.attributes.name.should.have.property('type', JSMF.String) State.attributes.name.should.have.property('mandatory', true) State.attributes.should.have.property('age') State.attributes.age.should.have.property('type', JSMF.Number) State.attributes.age.should.have.property('mandatory', false) done() }) it('can be modified', function(done) { var State = new Class('State') State.attributes.should.be.empty State.addAttributes({name: JSMF.Number}) State.addAttributes({name: JSMF.String}) State.attributes.should.have.property('name') State.attributes.name.should.have.property('type', JSMF.String) State.attributes.name.should.have.property('mandatory', false) done() }) it('can be set at initialization', function(done) { var State = new Class('State', [], {name: JSMF.String, age: Number}) State.attributes.should.have.property('name') State.attributes.name.should.have.property('type', JSMF.String) State.attributes.name.should.have.property('mandatory', false) State.attributes.should.have.property('age') State.attributes.age.should.have.property('type', JSMF.Number) State.attributes.age.should.have.property('mandatory', false) done() }) it ('can be removed', function(done) { var State = new Class('State', [], {name: JSMF.String, age: Number}) State.removeAttribute('name') State.attributes.should.not.have.property('name') State.attributes.should.have.property('age') State.attributes.age.should.have.property('type', JSMF.Number) State.attributes.age.should.have.property('mandatory', false) done() }) }) describe('Class references', function() { it('can be assign', function(done) { var Hero = new Class('Hero') var SuperPower = new Class('SuperPower') Hero.setReference('has', SuperPower, JSMF.Cardinality.one) Hero.references.should.have.property('has') Hero.references.has.should.have.property('type', SuperPower) Hero.references.has.should.have.property('cardinality') Hero.references.has.cardinality.should.have.property('min' , 1) Hero.references.has.cardinality.should.have.property('max' , 1) done() }) it('has a default cardinality of {0,n}', function(done) { var Hero = new Class('Hero') var SuperPower = new Class('SuperPower') Hero.setReference('has', SuperPower) Hero.references.should.have.property('has') Hero.references.has.should.have.property('cardinality') Hero.references.has.cardinality.should.have.property('min', 0) Hero.references.has.cardinality.should.have.property('max', undefined) done() }) it('accepts only the max cardinality', function(done) { var Hero = new Class('Hero') var SuperPower = new Class('SuperPower') Hero.setReference('has', SuperPower, 2) Hero.references.should.have.property('has') Hero.references.has.should.have.property('cardinality') Hero.references.has.cardinality.should.have.property('max', 2) done() }) it('has unlimited max cardinality on negative number', function(done) { var Hero = new Class('Hero') var SuperPower = new Class('SuperPower') Hero.setReference('has', SuperPower, -1) Hero.references.should.have.property('has') Hero.references.has.should.have.property('cardinality') Hero.references.has.cardinality.should.have.property('max', undefined) done() }) it('push opposite reference in the target class', function(done) { var Hero = new Class('Hero') var SuperPower = new Class('SuperPower') Hero.setReference('has', SuperPower, JSMF.Cardinality.any, 'owners') SuperPower.references.should.have.property('owners') Hero.references.has.should.have.property('opposite', 'owners') done() }) it('keep the cardinality of the opposite ref if it exists', function(done) { const Hero = new Class('Hero') const SuperPower = new Class('SuperPower') SuperPower.setReference('owners', Hero, JSMF.Cardinality.one) Hero.setReference('has', SuperPower, JSMF.Cardinality.any, 'owners') SuperPower.references.should.have.property('owners') SuperPower.references.owners.cardinality.should.have.properties({min: 1, max: 1}) SuperPower.references.owners.should.have.property('opposite', 'has') done() }) it('support bulk definition', function(done) { var Hero = new Class('Hero') var SuperPower = new Class('SuperPower') Hero.setReferences({has: {target: SuperPower}, weakness: {target: SuperPower}}) Hero.references.should.have.property('has') Hero.references.should.have.property('weakness') done() }) it('can be set at initialization', function(done) { var SuperPower = new Class('SuperPower') var Hero = new Class('Hero', [], {}, {has: {target: SuperPower}, weakness: {target: SuperPower}}) Hero.references.should.have.property('has') Hero.references.should.have.property('weakness') done() }) it('has addReference as a synonym', function(done) { var Hero = new Class('Hero') var SuperPower = new Class('SuperPower') Hero.addReference('has', SuperPower, JSMF.Cardinality.one) Hero.references.should.have.property('has') Hero.references.has.should.have.property('type', SuperPower) Hero.references.has.should.have.property('cardinality') Hero.references.has.cardinality.should.have.property('min' , 1) Hero.references.has.cardinality.should.have.property('max' , 1) done() }) it ('can be removed', function(done) { var SuperPower = new Class('SuperPower') var Hero = new Class('Hero', [], {}, {has: {target: SuperPower}, weakness: {target: SuperPower}}) Hero.removeReference('has') Hero.references.should.not.have.property('has') Hero.references.should.have.property('weakness') done() }) it('remove a removed reference from its opposite', function(done) { var Hero = new Class('Hero') var SuperPower = new Class('SuperPower') Hero.setReference('has', SuperPower, JSMF.Cardinality.any, 'owners') Hero.removeReference('has') SuperPower.references.owners.should.not.have.property('opposite') done() }) it('can removed a reference and its opposite simulteneaously', function(done) { var Hero = new Class('Hero') var SuperPower = new Class('SuperPower') Hero.setReference('has', SuperPower, JSMF.Cardinality.any, 'owners') Hero.removeReference('has', true) SuperPower.references.should.not.have.property('owners') done() }) }) describe('Class getInheritanceChain', function() { it('returns the class alone if no superClasses', function(done) { var Hero = new Class('Hero') Hero.getInheritanceChain().should.be.eql([Hero]) done() }) it('returns the class and it\'s parent for simple inheritance', function(done) { var Hero = new Class('Hero') var SuperHero = new Class('SuperHero', [Hero]) SuperHero.getInheritanceChain().should.be.eql([Hero, SuperHero]) done() }) it('returns the class and it\'s parent for multiple inheritance', function(done) { var A = new Class('A') var B = new Class('B', [A]) var C = new Class('C', [A]) var D = new Class('D', [B,C]) D.getInheritanceChain().should.be.eql([A, B, A, C, D]) done() }) }) describe('Class getAllAttributes', function() { it('returns the attributes of the class if no inheritance', function(done) { var State = new Class('State') State.attributes.should.be.empty State.addAttributes({name: JSMF.String, age: Number}) const res = State.getAllAttributes() res.should.have.property('name') res.name.should.have.property('type', JSMF.String) res.name.should.have.property('mandatory', false) res.should.have.property('age') res.age.should.have.property('type', JSMF.Number) res.age.should.have.property('mandatory', false) done() }) it('get parents attributes, override them if necessary', function(done) { const State = new Class('State') const TargetState = new Class('TargetState', State) State.attributes.should.be.empty() State.addAttributes({name: JSMF.String, age: Number}) function positive(x) {return x > 0;} TargetState.addAttributes({age: positive, value: JSMF.Any}) const res = TargetState.getAllAttributes() res.should.have.property('name') res.name.should.have.property('type', JSMF.String) res.name.should.have.property('mandatory', false) res.should.have.property('age') res.age.should.have.property('type', positive) res.age.should.have.property('mandatory', false) res.should.have.property('value') res.value.should.have.property('type', JSMF.Any) res.value.should.have.property('mandatory', false) done() }) it ('kept the attributes of the last inherited class', function(done) { var A = new Class('A', [], {foo: JSMF.Number}) var B = new Class('B', [], {foo: JSMF.String}) var C = new Class('C', [A, B]) const res = C.getAllAttributes() res.should.have.property('foo') res.foo.should.have.property('type', JSMF.String) res.foo.should.have.property('mandatory', false) done() }) }) describe('Class getAllReferences', function() { it('returns the references of the class if no inheritance', done => { var State = new Class('State') State.attributes.should.be.empty State.addReference('next', State) State.getAllReferences().should.have.property('next') done() }) it('get parents references, override them if necessary', done => { var State = new Class('State') var TargetState = new Class('TargetState', State) State.attributes.should.be.empty() State.addAttributes({name: JSMF.String, age: Number}) State.addReference('next', State) TargetState.addReference('next', TargetState) var references = TargetState.getAllReferences() references.should.have.property('next') references.next.type.should.eql(TargetState) done() }) it ('kept the references of the last inherited class', done => { const A = new Class('A') A.addReference('foo', A) const B = new Class('B') B.addReference('foo', B) const C = new Class('C', [A, B]) const references = C.getAllReferences() references.should.have.property('foo') references.foo.type.should.eql(B) done() }) }) describe('Class semanticReference', function() { it('create the semantic references (URI) building the Class', done => { var Bus = new Class('Bus',[],[],[],false,'https://schema.org/BusOrCoach') Bus.__semanticReference.should.equal('https://schema.org/BusOrCoach') Bus.getSemanticReference().should.equal('https://schema.org/BusOrCoach') done() }) it('set the semantic reference (URI) by setSemanticReference function and retrives it', done => { var Bus = new Class('Bus') Bus.getSemanticReference.should.be.empty Bus.setSemanticReference('https://schema.org/BusOrCoach') Bus.getSemanticReference().should.equal('https://schema.org/BusOrCoach') done() }) }) })