/* * 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 . */ 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 | 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(); 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; } }); });