Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ontouml2alloy #106

Open
wants to merge 24 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
bc94668
Merge pull request #1 from OntoUML/development
fernandoam14 Mar 10, 2021
f2eb7fe
OntoUML 2.0 to Alloy Transformation
fernandoam14 May 13, 2021
41bf42b
Run result modified to three fields
fernandoam14 May 16, 2021
955086b
Added folder for ontouml2alloy tests
APantov Mar 23, 2023
2adee5a
Added helper class; added/fixed test cases
APantov Mar 24, 2023
868cfae
Added new test cases
APantov Mar 27, 2023
88eb8f5
More test cases added
APantov Mar 28, 2023
f8b1c47
class_functions fixing, added helper functions to helper.ts
APantov Apr 5, 2023
6161315
new helper function & class_functions adaptation
APantov Apr 5, 2023
8821619
empty name_normalization.test.ts,adapt other tests
APantov Apr 9, 2023
46be965
new test for name name_normalization, in dev
APantov Apr 13, 2023
ed8c011
normalize_name function & testing
APantov Apr 13, 2023
de8f43f
name_norm update & many other updates, fixes,TODOs
APantov Apr 27, 2023
66cf275
update generalization_set_functions
APantov Apr 27, 2023
065ac10
generalization & gen_set & helpers update
APantov May 3, 2023
c8d5a32
trim model implementation & testing
APantov May 8, 2023
00c411b
trim model implementation & testing
APantov May 8, 2023
0f81e3d
remove unnecessary checks
APantov May 9, 2023
ff309e4
a lot of minor updates
APantov May 17, 2023
85dafe6
relation test, fix minor things
APantov Jun 1, 2023
0b4ba79
update naming + tests
APantov Jun 18, 2023
b138ab3
property_functions test, relation_functions test
APantov Jul 5, 2023
7bc7ba7
minor fix,unsupp categorizer doesn't remove genSet
APantov Jul 5, 2023
1f1ea05
remove improper use of getAlias
APantov Jul 25, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 128 additions & 0 deletions __tests__/libs/ontouml2alloy/alloy_name_normalization.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import { Ontouml2Alloy } from '@libs/ontouml2alloy/index';
import { Class, OntoumlElement, Package, Project, Relation } from '@libs/ontouml';
import { getNormalizedName } from '@libs/ontouml2alloy/util';
import { generateAlloy, generateFact, generateWorldFieldForClass, generateWorldFact } from './helpers';
import { OntoumlType } from '@libs/ontouml';
import { reservedKeywords, forbiddenCharacters } from '@libs/ontouml2alloy/util';


describe('Name normalization' , () => {

let element: OntoumlElement;
let project: Project;
let model: Package;
let transformer: Ontouml2Alloy;

beforeEach(() => {
project = new Project();
model = project.createModel();
transformer = new Ontouml2Alloy(model);
element = new Class();
});

describe('Original name is kept when there are no issues' , () => {

it('Person -> Person', () => {
element.addName('Person');
const normalized = getNormalizedName(transformer, element);
expect(normalized).toBe('Person');
});

it('PERSON -> PERSON', () => {
element.addName('PERSON');
const normalized = getNormalizedName(transformer, element);
expect(normalized).toBe('PERSON');
});

it('person -> person', () => {
element.addName('person');
const normalized = getNormalizedName(transformer, element);
expect(normalized).toBe('person');
});

it('PeRsoN -> PeRsoN', () => {
element.addName('PeRsoN');
const normalized = getNormalizedName(transformer, element);
expect(normalized).toBe('PeRsoN');
});

})

describe("Inappropriate names are normalized properly", () => {

//normalization of reserved keywords: abstract -> abstract_OntoumlElementType
reservedKeywords.forEach(keyword => {
it(`should normalize the reserved keyword "${keyword}"`, () => {
element.addName(keyword);
const normalized = getNormalizedName(transformer, element);
expect(normalized).toBe(`${keyword}_${(element.type).toLowerCase()}`);
});
});

forbiddenCharacters.forEach(char => {
it(`should remove the forbidden character "${char}" from the name`, () => {
element.addName(`Happy${char}Person`);
const normalized = getNormalizedName(transformer, element);
expect(normalized).toBe('HappyPerson');
});
});

//normalization of empty name: '' -> Unnamed_OntoumlElementType;
it('should normalize a class with no name', () => {
element.addName('');
const normalized = getNormalizedName(transformer, element);
expect(normalized).toBe('class');
});

it('should normalize a relation with no name', () => {
element = new Relation();
element.addName('');
const normalized = getNormalizedName(transformer, element);
expect(normalized).toBe('relation');
});

it('should transform a relation between datatypes', () => {
const sourceClass = model.createDatatype('Date');
const targetClass = model.createDatatype('String');
const relation = model.createBinaryRelation(sourceClass, targetClass);

const result = generateAlloy(model);

expect(result).toContain('sig Date in Datatype {\n relation: String\n}');
});

it('should normalize two classes with no name/only forbidden characters', () => {
const element1 = model.createKind('');
const element2 = model.createKind('!!!');
const normalized1 = getNormalizedName(transformer, element1);
const normalized2 = getNormalizedName(transformer, element2);

expect(normalized1).toBe('class');
expect(normalized2).toBe('class1');
});

it('should normalize two classes with same name', () => {
model.createKind('Person');
model.createKind('Person');
const result = generateAlloy(model);

expect(result).toContain(generateFact('rigid',['rigidity[Person,Object,exists]']));
expect(result).toContain(generateFact('rigid',['rigidity[Person1,Object,exists]']));
expect(result).toContain(generateWorldFieldForClass('Person','Object'));
expect(result).toContain(generateWorldFieldForClass('Person1','Object'));
expect(result).toContain(generateWorldFact('Person+Person1','Object'));
})

it('should normalize a class starting with a number', () => {
element.addName('123Person');
const normalized = getNormalizedName(transformer, element);
expect(normalized).toBe('class_123Person');
});

});



})


221 changes: 221 additions & 0 deletions __tests__/libs/ontouml2alloy/class_functions.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
import { Ontouml2Alloy } from '@libs/ontouml2alloy/index';
import { generateAlloy, generateFact, generateWorldFieldForClass, generateWorldFact } from './helpers';
import { Class, ClassStereotype, Relation, Package, Project, Property, OntoumlType, AggregationKind, stereotypeUtils, OntologicalNature} from '@libs/ontouml';

describe('Class Functions', () => {

describe('transformClass function', () => {
let project: Project;
let model: Package;
let transformer: Ontouml2Alloy;

beforeEach(() => {
project = new Project();
model = project.createModel();
});

it('should ignore classes if they are an <<event>>', () => {
model.createEvent('Birthday');
expect(generateAlloy(model)).not.toContain('Birthday');
});

it('should ignore classes if they are a <<situation>>', () => {
model.createSituation('Hazard')
expect(generateAlloy(model)).not.toContain('Hazard');
});

it('should ignore classes if they are a <<type>>', () => {
model.createType('PaymentMethod')
expect(generateAlloy(model)).not.toContain('PaymentMethod');
})

it('should transform <<datatype>> class with attributes (complex datatype)', () => {
const _number = model.createDatatype('Number');
const complexDatatype = model.createDatatype('Date');
complexDatatype.createAttribute(_number, 'day');

const result = generateAlloy(model);
const factLines = ['Datatype = Number+Date','disjoint[Number,Date]'];

expect(result).toContain('sig Date in Datatype {\n day: set Number\n}');
expect(result).toContain(generateFact('additionalDatatypeFacts',factLines));
});

it('should transform <<datatype>> class without attributes (primitive datatype)', () => {
model.createDatatype('Date');
const result = generateAlloy(model);
expect(result).toContain('sig Date in Datatype {');
expect(result).toContain(generateFact('additionalDatatypeFacts',['Datatype = Date']))
});

it('should transform <<enumeration>> class with attributes', () => {
const status = model.createEnumeration('Status');
status.createLiteral('Active');
status.createLiteral('Inactive');

const result = generateAlloy(model)
expect(result).toContain('enum Status {\n Active, Inactive}')
});

it('should transform <<kind>> class', () => {
const person = model.createKind('Person');
const result = generateAlloy(model);
expect(result).toContain(generateFact('rigid',['rigidity[Person,Object,exists]']));
expect(result).toContain(generateWorldFieldForClass('Person','Object'));
expect(result).toContain(generateWorldFact('Person','Object'));
});

it('should transform <<collective>> class', () => {
model.createCollective('Group', false);
const result = generateAlloy(model);
expect(result).toContain(generateWorldFieldForClass('Group','Object'))
expect(result).toContain(generateWorldFact('Group','Object'));
expect(result).toContain(generateFact('rigid',['rigidity[Group,Object,exists]']));
});

//change member -> same thing -> isExtensional - false

// it('should generate fact to handle {isExtensional = True} for transforming <<collective>> class', () => {
// model.createCollective('FixedGroup', true);
// const result = generateAlloy(model);

// }); //TODO


// it('should generate fact to handle {isExtensional = False} for transforming <<collective>> class', () => {
// model.createCollective('FixedGroup', true);
// const result = generateAlloy(model);

// });

it('should transform «quantity» class', () => {
model.createQuantity('Wine');
const result = generateAlloy(model);

expect(result).toContain(generateFact('rigid',['rigidity[Wine,Object,exists]']));
expect(result).toContain(generateWorldFieldForClass('Wine','Object'));
expect(result).toContain(generateWorldFact('Wine','Object'));
});

it('should transform <<quality>> class', () => {
model.createQuality('Strong');
const result = generateAlloy(model);

expect(result).toContain(generateFact('rigid',['rigidity[Strong,Aspect,exists]']));
expect(result).toContain(generateWorldFieldForClass('Strong','Aspect'));
expect(result).toContain(generateWorldFact('Strong','Aspect'));

});

it('should transform «relator» class', () => {
model.createRelator('Marriage');
const result = generateAlloy(model);

expect(result).toContain(generateFact('rigid',['rigidity[Marriage,Aspect,exists]']));
expect(result).toContain(generateWorldFieldForClass('Marriage','Aspect'));
expect(result).toContain(generateWorldFact('Marriage','Aspect'));
});

it('should transform «role» class', () => {
model.createRole('Student');
const result = generateAlloy(model);

expect(result).toContain(generateFact('antirigid',['antirigidity[Student,Object,exists]']));
expect(result).toContain(generateWorldFieldForClass('Student','Object'));
expect(result).toContain(generateWorldFact('Student','Object'));
});

it('should transform «phase» class', () => {
model.createPhase('Child');
const result = generateAlloy(model);

expect(result).toContain(generateFact('antirigid',['antirigidity[Child,Object,exists]']));
expect(result).toContain(generateWorldFieldForClass('Child','Object'));
expect(result).toContain(generateWorldFact('Child','Object'));
});

it('should transform «abstract» class', () => {
let temp = model.createAbstract('Goal');
const _number = model.createDatatype('Date');
temp.createAttribute(_number, 'until');

const result = generateAlloy(model);

const factLines = ['Datatype = Goal+Date','disjoint[Goal,Date]'];
expect(result).toContain('sig Goal in Datatype {\n until: set Date\n}');
expect(result).toContain(generateFact('additionalDatatypeFacts',factLines));
});

it('should transform «mode» class { allowed=[intrinsic-mode] }', () => {
model.createIntrinsicMode('Skill');
const result = generateAlloy(model);

expect(result).toContain(generateFact('rigid',['rigidity[Skill,Aspect,exists]']));
expect(result).toContain(generateWorldFieldForClass('Skill','Aspect'));
expect(result).toContain(generateWorldFact('Skill','Aspect'));
});

it('should transform «mode» class { allowed=[extrinsic-mode] }', () => {
model.createExtrinsicMode('Love');
const result = generateAlloy(model);

expect(result).toContain(generateFact('rigid',['rigidity[Love,Aspect,exists]']));
expect(result).toContain(generateWorldFieldForClass('Love','Aspect'));
expect(result).toContain(generateWorldFact('Love','Aspect'));
});

it('should transform «mode» class { allowed=[intrinsic-mode, extrinsic-mode] }', () => {
// const _class = OntoumlFactory.createMode('Belief');
model.createClass('Belief', ClassStereotype.MODE, [OntologicalNature.intrinsic_mode, OntologicalNature.extrinsic_mode]);
const result = generateAlloy(model);

expect(result).toContain(generateFact('rigid',['rigidity[Belief,Aspect,exists]']));
expect(result).toContain(generateWorldFieldForClass('Belief','Aspect'));
expect(result).toContain(generateWorldFact('Belief','Aspect'));
});

//role is for dynamic types, we instantiate by individuals of a single type..
//role antirigid sortal, rolemixin antirigid sortal

//there is no difference between the transformation of a role and a roleMixin
it('should transform «roleMixin» class', () => {
model.createRoleMixin('Customer',);
const result = generateAlloy(model);

expect(result).toContain(generateFact('antirigid',['antirigidity[Customer,Object,exists]']));
expect(result).toContain(generateWorldFieldForClass('Customer','Object'));
expect(result).toContain(generateWorldFact('Customer','Object'));
});

//there is no difference between the transformation of a phase and a phaseMixin
it('should transform «phaseMixin» class', () => {
model.createPhaseMixin('Infant');
const result = generateAlloy(model);

expect(result).toContain(generateFact('antirigid',['antirigidity[Infant,Object,exists]']));
expect(result).toContain(generateWorldFieldForClass('Infant','Object'));
expect(result).toContain(generateWorldFact('Infant','Object'));
});

it('should transform «category» class', () => {
model.createCategory('Animal');
const result = generateAlloy(model);

expect(result).toContain(generateFact('rigid',['rigidity[Animal,Object,exists]']));
expect(result).toContain(generateWorldFieldForClass('Animal','Object'));
expect(result).toContain(generateWorldFact('Animal','Object'));
});

//TODO figure out how to handle mixins
// it('should transform «mixin» class', () => {
// model.createMixin('Seatable');
// const result = generateAlloy(model);

// expect(result).toContain('');
// });


});
});


Loading