diff --git a/spec/mock_jasmine.ts b/spec/mock_jasmine.ts index e459c91748d41f4411bdb786cb0f0265e4fb11ca..2baf17136e0af0f3d14d27c2a7a5d47d49aa5395 100644 --- a/spec/mock_jasmine.ts +++ b/spec/mock_jasmine.ts @@ -37,6 +37,14 @@ export function xit(sTxt: string, fFun: () => void) { console.warn("*** " + sTxt + " ignored ***"); } +export function fail(m?: string) { + let s = "Test failed"; + if (m !== undefined) + s += ` (${m})`; + + console.error(s); +} + /** * Classe contenant les méthodes de comparaison de Jasmine. */ diff --git a/spec/value_ref/value_ref_circularity.spec.ts b/spec/value_ref/value_ref_circularity.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..bf06ed1bc8fb54aef939e17e30b5e7ae4aed6709 --- /dev/null +++ b/spec/value_ref/value_ref_circularity.spec.ts @@ -0,0 +1,104 @@ +import { NubTest, NubTestParams } from "../nubtest"; + +/** + * IMPORTANT ! + * Décommenter temporairement la ligne suivante (import { } from "./mock_jasmine") + * Pour exécuter ce code dans le débugger. + * Faire de même avec le fichier test_func.ts + */ +// import { describe, expect, it, xdescribe, xit, fail } from "../mock_jasmine"; + +let nub1: NubTest; +let nub2: NubTest; +let nub3: NubTest; +let prm1: NubTestParams; +let prm2: NubTestParams; +let prm3: NubTestParams; + +/** + * crée l'environnement de test. + * répété à chaque test car il manque un mock de beforeEach + */ +function createEnv() { + nub1 = new NubTest(new NubTestParams()); + prm1 = nub1.parameters as NubTestParams; + + nub2 = new NubTest(new NubTestParams()); + prm2 = nub2.parameters as NubTestParams; + + nub3 = new NubTest(new NubTestParams()); + prm3 = nub3.parameters as NubTestParams; +} + +describe("référence d'un paramètre à un autre : ", () => { + describe("vérification des références circulaires : ", () => { + it("test 1", () => { + // cas de figure (ne doit pas échouer) : + // nub2.A référence nub1.A + + createEnv(); + + try { + prm2.A.defineReference(nub1, "A"); // ne doit pas échouer + } + catch (e) { + fail(); + } + }); + + it("test 2", () => { + // cas de figure (ne doit pas échouer) : + // nub1.A référence nub2.A qui référence nub3.A + + createEnv(); + + try { + prm1.A.defineReference(nub2, "A"); + prm2.A.defineReference(nub3, "A"); + } + catch (e) { + fail(); + } + }); + + it("test 3", () => { + // cas de figure (doit échouer) : + // nub2.A référence nub1.A qui référence nub2.A + + createEnv(); + + try { + prm2.A.defineReference(nub1, "A"); // ne doit pas échouer + prm1.A.defineReference(nub2, "A"); // doit échouer + fail(); + } + catch (e) { + } + }); + + it("test 4", () => { + // cas de figure (doit échouer) : + // param1 référence param2 (OK) + // param3 référence param1 (OK) + // param2 référence param3 (doit échouer) + + createEnv(); + + try { + prm1.A.defineReference(nub2, "A"); // ne doit pas échouer + prm3.A.defineReference(nub1, "A"); // ne doit pas échouer + } + catch (e) { + fail(); + } + + + try { + prm2.A.defineReference(nub3, "A"); // doit échouer + fail(); + } + catch (e) { + } + }); + }); +}); diff --git a/src/nub.ts b/src/nub.ts index 02400b8a85f1835abcf7f330b0155d0f34b631e2..120c62739f492ed4f87776cb23efc4611370d555 100644 --- a/src/nub.ts +++ b/src/nub.ts @@ -6,6 +6,7 @@ import { ParamValues } from "./param/param-values"; import { ParamValueMode } from "./param/param-value-mode"; import { ParamDefinition } from "."; import { IReferencedNub } from "./value_ref/object_ref"; +import { IJalhydObject } from "./jalhyd_object"; /** * Classe abstraite de Noeud de calcul : classe de base pour tous les calculs @@ -228,34 +229,19 @@ export abstract class Nub extends ComputeNode implements IReferencedNub { } } - /** - * @returns liste des paramètres liables à un paramètre - * @param p paramètre qui sert de clé de recherche des paramètres liables - */ - // public getLinkableParameters(param: ParamDefinition): any[] { - // const res: any[] = []; - - // for (const p of this._prms) - // if (p.uid !== param.uid) - // switch (p.valueMode) { - // case ParamValueMode.SINGLE: - // case ParamValueMode.MINMAX: - // case ParamValueMode.LISTE: - // switch (param.symbol) { - // case "Z1": - // case "Z2": - // if (p.symbol === "Z1" || p.symbol === "Z2") - // res.push({ "param": p, "nub": this }); - // break; - - // default: - // if (p.symbol === param.symbol) - // res.push({ "param": p, "nub": this }); - // } - // } - - // return res; - // } + public getReferencedObject(desc: string): IJalhydObject { + const tmp = desc.split("."); + + if (tmp.length == 1) // paramètre (ex "Q") + return this.getParameter(desc); + + if (tmp[1] === "") // résultat (ex "Q.") + if (this._result !== undefined) + return this._result; + + // les autres objets référençables n'implémentant pas IJalhydObject... + return undefined; + } private addPrefix(str: string, prefix: string) { return prefix === undefined ? str : `${prefix}${str}`; diff --git a/src/param/param-base.ts b/src/param/param-base.ts index ce59f8aca3f95aa5fb22c3684234b02c860096e0..7abc917265dbae610368220155db952acdeffe1b 100644 --- a/src/param/param-base.ts +++ b/src/param/param-base.ts @@ -1,7 +1,7 @@ import { Interval } from "../util/interval"; import { Message, MessageCode } from "../util/message"; -import { JalhydObject } from "../jalhyd_object" +import { JalhydObject, IJalhydObject } from "../jalhyd_object" import { ParamDomain, ParamDomainValue } from "./param-domain"; import { ParamValues } from "./param-values"; import { ParamValueMode } from "./param-value-mode"; @@ -255,8 +255,39 @@ export class BaseParam extends JalhydObject implements INubReference, NamedItera // interface INubReference + /** + * vérifie l'absence de référence circulaire + * @param seenUids liste des uids déjà vérifiés + * @param o objet à tester (son uid est il déjà dans la liste ?) + */ + private checkReferenceCircularity(o: any, seenUids: number[]) { + if ("uid" in o) { + // if (o.uid in seenUids) + if (seenUids.indexOf(o.uid) !== -1) + throw new Error(`références circulaires détectées (uids : ${seenUids})`); + + seenUids.push(o.uid); + + if ("referencedObject" in o) { + const curr = o as INubReference; + const next = curr.referencedObject; + if (next !== undefined) + this.checkReferenceCircularity(next as IJalhydObject, seenUids); + } + } + } + public defineReference(target: IReferencedNub, desc: string) { - this._paramValues.defineReference(target, desc); + const oldDef = this._paramValues.referenceDefinition; + const oldTarget = this._paramValues.referencedNub; + try { + this._paramValues.defineReference(target, desc); + this.checkReferenceCircularity(this, []); + } + catch (e) { + this._paramValues.defineReference(oldTarget, oldDef); + throw e; + } } public get referenceDefinition(): string { @@ -287,6 +318,10 @@ export class BaseParam extends JalhydObject implements INubReference, NamedItera return this._paramValues.referencedValuesIterator; } + public get referencedObject(): IJalhydObject { + return this._paramValues.referencedObject; + } + // interface NamedIterableValues public get valuesIterator(): IterableIterator<number> { diff --git a/src/param/param-values.ts b/src/param/param-values.ts index bb3dd476223ad0c31c17e4eaef17707f5eb888fb..c6a3fead0f6b984c79baea606a0787a6a1d8051d 100644 --- a/src/param/param-values.ts +++ b/src/param/param-values.ts @@ -4,6 +4,7 @@ import { IReferencedNub, INubReference, NubReference } from "../value_ref/object import { Result } from ".."; import { ParamValueMode } from "./param-value-mode"; import { ParamValueIterator, IterableValues } from "./param-value-iterator"; +import { IJalhydObject } from "../jalhyd_object"; export class ParamValues implements INubReference, IterableValues { /** @@ -312,6 +313,12 @@ export class ParamValues implements INubReference, IterableValues { return this._nubRef.referencedValuesIterator; } + public get referencedObject(): IJalhydObject { + if (this.isReferenceDefined) + return this._nubRef.referencedObject; + return undefined; + } + // interface IterableValues public get valuesIterator(): IterableIterator<number> { diff --git a/src/value_ref/object_ref.ts b/src/value_ref/object_ref.ts index 9180de1d76daa06d97b5bdd1afec441773b0ac2b..cf392ddf15dabbac204483a741e1ba2a9ae623b3 100644 --- a/src/value_ref/object_ref.ts +++ b/src/value_ref/object_ref.ts @@ -1,5 +1,6 @@ import { ParamValues } from "../param/param-values"; import { Result } from ".."; +import { IJalhydObject } from "../jalhyd_object"; /** * Nub dont certaines valeurs sont référençables pour réutilisation @@ -28,6 +29,11 @@ export interface IReferencedNub { * itérateur sur les valeurs */ getReferencedValuesIterator(desc: string): IterableIterator<number>; + + /** + * objet (paramètre/résultat/résultat complémentaire) référencé + */ + getReferencedObject(desc: string): IJalhydObject; } /** @@ -70,6 +76,11 @@ export interface INubReference { * itérateur sur les valeurs référencées */ readonly referencedValuesIterator: IterableIterator<number>; + + /** + * objet (paramètre/résultat/résultat complémentaire) référencé + */ + readonly referencedObject: IJalhydObject; } /** @@ -136,4 +147,11 @@ export class NubReference implements INubReference { public get referencedValuesIterator(): IterableIterator<number> { return this._referencedNub.getReferencedValuesIterator(this._refDefinition); } + + /** + * objet (paramètre/résultat/résultat complémentaire) référencé + */ + public get referencedObject(): IJalhydObject { + return this._referencedNub.getReferencedObject(this._refDefinition); + } }