Commit 9ef5c329 authored by Grand Francois's avatar Grand Francois
Browse files

#45 détection des références circulaires

Showing with 188 additions and 30 deletions
+188 -30
......@@ -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.
*/
......
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) {
}
});
});
});
......@@ -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}`;
......
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> {
......
......@@ -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> {
......
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);
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment