mirror of
https://gitlab.com/openstapps/openstapps.git
synced 2025-12-30 10:02:51 +00:00
155 lines
5.3 KiB
TypeScript
155 lines
5.3 KiB
TypeScript
/*
|
|
* Copyright (C) 2018 StApps
|
|
* This program is free software: you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License as published by the Free
|
|
* Software Foundation, version 3.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
import {
|
|
isLightweightClass,
|
|
isLightweightEnum,
|
|
isUnionType,
|
|
LightweightAliasDefinition,
|
|
LightweightProjectWithIndex,
|
|
LightweightType,
|
|
LightweightClassDefinition,
|
|
LightweightDefinition,
|
|
LightweightProperty,
|
|
} from '@openstapps/easy-ast';
|
|
import {expect} from 'chai';
|
|
|
|
process.on('unhandledRejection', error => {
|
|
throw error;
|
|
});
|
|
|
|
describe('Features', () => {
|
|
let project: LightweightProjectWithIndex;
|
|
let thingNames: string[];
|
|
let things: LightweightClassDefinition[];
|
|
let thingsWithoutReferences: LightweightClassDefinition[];
|
|
|
|
before(function () {
|
|
this.timeout(15_000);
|
|
this.slow(10_000);
|
|
|
|
project = new LightweightProjectWithIndex('src');
|
|
|
|
const thingsReflection = project.definitions['SCIndexableThings'] as LightweightAliasDefinition;
|
|
expect(isLightweightEnum(thingsReflection)).to.be.true;
|
|
expect(isUnionType(thingsReflection.type!)).to.be.true;
|
|
|
|
thingsReflection.type!.specificationTypes!.push({
|
|
flags: 524_288,
|
|
referenceName: 'SCDiff',
|
|
});
|
|
|
|
expect(thingsReflection.type?.specificationTypes?.map(it => it.referenceName)).not.to.include(undefined);
|
|
thingNames = thingsReflection.type?.specificationTypes?.map(type => type.referenceName!) ?? [];
|
|
things = thingNames.map(it => project.definitions[it]).filter(isLightweightClass);
|
|
thingsWithoutReferences = thingNames
|
|
.map(it => project.definitions[`${it}WithoutReferences`])
|
|
.filter(isLightweightClass);
|
|
});
|
|
|
|
const inheritedProperties = function (
|
|
classLike: LightweightClassDefinition,
|
|
): Record<string, LightweightProperty> | undefined {
|
|
const extendClause = [
|
|
...(classLike.implementedDefinitions ?? []),
|
|
...(classLike.extendedDefinitions ?? []),
|
|
];
|
|
const properties = {...classLike.properties};
|
|
|
|
for (const definition of extendClause) {
|
|
const object = project.definitions[definition.referenceName!];
|
|
if (isLightweightClass(object)) {
|
|
Object.assign(properties, inheritedProperties(object));
|
|
} else {
|
|
Object.assign(properties, object);
|
|
}
|
|
}
|
|
|
|
return properties;
|
|
};
|
|
|
|
it('should have an origin', () => {
|
|
for (const thing of things) {
|
|
expect(inheritedProperties(thing)?.['origin']).not.to.be.undefined;
|
|
}
|
|
});
|
|
|
|
it('should not have duplicate names', () => {
|
|
const names = new Set<string>();
|
|
|
|
for (const fileName in project.files) {
|
|
const file = project.files[fileName];
|
|
for (const definition in file) {
|
|
const definitionName = file[definition].name;
|
|
expect(names).not.to.include(definitionName);
|
|
names.add(definitionName);
|
|
}
|
|
}
|
|
});
|
|
|
|
it('should not have properties referencing SCThing', () => {
|
|
const allPropertyReferenceNames: (property: LightweightProperty) => string[] = property =>
|
|
[
|
|
property.type.referenceName!,
|
|
...Object.values(property.properties ?? []).flatMap(allPropertyReferenceNames),
|
|
].filter(it => !!it);
|
|
|
|
const typeHasSCThingReferences: (type?: LightweightType) => boolean = type =>
|
|
type?.referenceName
|
|
? hasSCThingReferences(project.definitions[type.referenceName])
|
|
: type?.specificationTypes?.some(typeHasSCThingReferences) === true;
|
|
|
|
const hasSCThingReferences: (definition?: LightweightDefinition) => boolean = definition =>
|
|
isLightweightClass(definition)
|
|
? Object.values(inheritedProperties(definition) ?? [])
|
|
.flatMap(it => Object.values(it.properties ?? []).flatMap(allPropertyReferenceNames))
|
|
.map(it => project.definitions[it] as LightweightDefinition)
|
|
.some(it => it.name === 'SCThing' || hasSCThingReferences(it))
|
|
: definition
|
|
? typeHasSCThingReferences(definition.type)
|
|
: false;
|
|
|
|
for (const thing of things) {
|
|
expect(hasSCThingReferences(thing)).to.be.false;
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Checks if a definition is an SCThing
|
|
*/
|
|
function extendsSCThing(definition?: LightweightDefinition): boolean {
|
|
return isLightweightClass(definition)
|
|
? [
|
|
...((definition as LightweightClassDefinition).extendedDefinitions ?? []),
|
|
...((definition as LightweightClassDefinition).implementedDefinitions ?? []),
|
|
]
|
|
.map(it => it.referenceName)
|
|
.filter(it => !!it)
|
|
.some(it => it === 'SCThing' || extendsSCThing(project.definitions[it!]))
|
|
: false;
|
|
}
|
|
|
|
it('should extend SCThing if it is an SCThing', () => {
|
|
for (const thing of things) {
|
|
expect(extendsSCThing(thing)).to.be.true;
|
|
}
|
|
});
|
|
|
|
it('should not extend SCThing if it is an SCThingWithoutReferences', () => {
|
|
for (const thingWithoutReferences of thingsWithoutReferences) {
|
|
expect(extendsSCThing(thingWithoutReferences)).to.be.false;
|
|
}
|
|
});
|
|
});
|