Browse Source

MPIDE-28: ✅: generator tests w/ fixes for scopes

Kyle P Davis 10 years ago
parent
commit
fb8f06949a
2 changed files with 176 additions and 84 deletions
  1. 12 15
      src/lib/generator/modellang.es6
  2. 164 69
      src/lib/generator/test/generator.js

+ 12 - 15
src/lib/generator/modellang.es6

@@ -9,24 +9,21 @@ module.exports = class Generator {
 		this.triggers = parsed.triggers;
 	}
 
-	*generate(obj, min, max, scope=1, n=0, i=0) {
-		console.log(`t=${obj.type}, id=${obj.id || ""}, n=${n}, i=${i}`);
+	*generate(obj, scope=1, n=0, i=0) {
+		let min = obj.scope && typeof obj.scope.min === "number" ? obj.scope.min : 1;
+		let max = obj.scope && typeof obj.scope.max === "number" ? obj.scope.max : scope;
+		console.log(`t=${obj.type}	id=${obj.id || `...${obj.body.length}`}	n=${n}	i=${i}	s=${scope}	min=${min}	max=${max}`);
 
-		let nextMin = obj.scope && typeof obj.scope.min === "number" ? Math.max(0, obj.scope.min) : 1;
-		let nextMax = obj.scope && typeof obj.scope.max === "number" ? Math.min(scope, obj.scope.max) : scope;
-
-		let id;
+		let id = null;
 		switch (obj.type) {
 
 			case "Behavior":
 				if (!obj.body) { // Behavior reference
 					let realObj = this.behaviors[obj.id];
 					if (!realObj || !realObj.body) throw new Error(`Unable to find referenced behavior: ${obj.id}`);
-					obj = realObj;
-					if (obj.body.length === 0) { // Atomic Behavior
-						yield [obj.id];
-						return; //break;
-					}
+					Object.defineProperty(obj, "body", { // use real body but keep it hidden (for debugging the AST mainly)
+						value: realObj.body,
+					});
 				}
 				/* falls through */
 			case "System": // or Behavior
@@ -35,17 +32,17 @@ module.exports = class Generator {
 				/* falls through */
 			case "Sequence": // or System or Behavior
 				let outs = [];
-				if (i === 0 && id) outs.push(id);
+				if (i === 0 && id !== null) outs.push(id);
 				if (i < obj.body.length) {
-					for (let nextEvts of this.generate(obj, min, max, scope, n, i + 1)) {
-						for (let evts of this.generate(obj.body[i], nextMin, nextMax, scope)) {
+					for (let evts of this.generate(obj.body[i], scope)) {
+						for (let nextEvts of this.generate(obj, scope, n, i + 1)) {
 							yield outs.concat(evts, nextEvts);
 						}
 					}
 				} else {
 					if (n >= min - 1) yield outs;
 					if (n < max - 1) {
-						for (let nextEvts of this.generate(obj, min, max, scope, n + 1, 0))
+						for (let nextEvts of this.generate(obj, scope, n + 1, 0))
 							yield outs.concat(nextEvts);
 					}
 				}

+ 164 - 69
src/lib/generator/test/generator.js

@@ -4,27 +4,39 @@ let assert = require("assert"),
 	Generator = require("../modellang");
 
 //EXAMPLE
-//	BEHAVIOR: foobarbaz = foo bar baz;
+//	SYSTEM: sys = abc+;
+//	BEHAVIOR: abc = a b c;
 let parsed = {
-	systems: {},
+	systems: {
+		sys: {type: "System", id: "sys", refs: ["abc"], scope: {min: 1, max: 1},
+			body: [
+				{type: "Sequence", scope: {min: 1, max: 1},
+					body: [
+						{type: "Behavior", id: "abc", scope: {min: 1, max: null}},
+					],
+				},
+			],
+		},
+	},
 	behaviors: {
-		foobarbaz: {type: "Behavior", id: "foobarbaz", refs: ["foo", "bar", "baz"],
+		abc: {type: "Behavior", id: "abc", refs: ["a", "b", "c"],
 			body: [
 				{type: "Sequence", scope: {min: 1, max: 1},
 					body: [
-						{type: "Behavior", id: "foo", scope: {min: 1, max: 1}},
-						{type: "Behavior", id: "bar", scope: {min: 1, max: 1}},
-						{type: "Behavior", id: "baz", scope: {min: 1, max: 1}},
+						{type: "Behavior", id: "a", scope: {min: 1, max: 1}},
+						{type: "Behavior", id: "b", scope: {min: 1, max: 1}},
+						{type: "Behavior", id: "c", scope: {min: 1, max: 1}},
 					],
 				},
 			],
 		},
-		foo: {type: "Behavior", id: "foo", refs: [], body: []},
-		bar: {type: "Behavior", id: "bar", refs: [], body: []},
-		baz: {type: "Behavior", id: "baz", refs: [], body: []},
+		a: {type: "Behavior", id: "a", body: []},
+		b: {type: "Behavior", id: "b", body: []},
+		c: {type: "Behavior", id: "c", body: []},
 	},
 	interactions: [],
 	triggers: [],
+	init: [],
 	errors: [],
 };
 
@@ -43,135 +55,218 @@ describe("Generator", function() {
 
 		describe("Behavior (leaf/atomic)", function() {
 
-			let obj = g.behaviors.foo;
+			// copy "a" behavior (atomic event) so that we can attach test min/max
+			let obj = Object.create(g.behaviors.a);
 
 			it("should return 1 trace if min=1, max=1", function() {
-				assert.deepEqual(getGenerated(obj, 1, 1), [
-					["foo"],
+				obj.scope = {min: 1, max: 1};
+				assert.deepEqual(getGenerated(obj), [
+					["a"],
 				]);
+				assert.deepEqual(getGenerated(obj), getGenerated(obj, 2), "should not be affected by scope if max is set");
 			});
 
-			it("should return 2 traces if min=1, max=2", function() {
-				assert.deepEqual(getGenerated(obj, 1, 2), [
-					["foo"],
-					["foo", "foo"],
+			it("should return 3 traces if min=1, max=3", function() {
+				obj.scope = {min: 1, max: 3};
+				assert.deepEqual(getGenerated(obj), [
+					["a"],
+					["a", "a"],
+					["a", "a", "a"],
 				]);
+				assert.deepEqual(getGenerated(obj), getGenerated(obj, 2), "should not be affected by scope if max is set");
 			});
 
-			it("should return 3 traces if min=1, max=3", function() {
-				assert.deepEqual(getGenerated(obj, 1, 3), [
-					["foo"],
-					["foo", "foo"],
-					["foo", "foo", "foo"],
+			it("should return 2 traces if min=2, max=3", function() {
+				obj.scope = {min: 2, max: 3};
+				assert.deepEqual(getGenerated(obj), [
+					["a", "a"],
+					["a", "a", "a"],
 				]);
+				assert.deepEqual(getGenerated(obj), getGenerated(obj, 2), "should not be affected by scope if max is set");
 			});
 
-			it("should return 2 traces if min=2, max=3", function() {
-				assert.deepEqual(getGenerated(obj, 2, 3), [
-					["foo", "foo"],
-					["foo", "foo", "foo"],
+			it("should return 1 trace if min=3, max=3", function() {
+				obj.scope = {min: 3, max: 3};
+				assert.deepEqual(getGenerated(obj), [
+					["a", "a", "a"],
 				]);
+				assert.deepEqual(getGenerated(obj), getGenerated(obj, 2), "should not be affected by scope if max is set");
 			});
 
 			it("should return 1 trace if min=3, max=3", function() {
-				assert.deepEqual(getGenerated(obj, 3, 3), [
-					["foo", "foo", "foo"],
+				obj.scope = {min: 3, max: 3};
+				assert.deepEqual(getGenerated(obj), [
+					["a", "a", "a"],
 				]);
+				assert.deepEqual(getGenerated(obj), getGenerated(obj, 2), "should not be affected by scope if max is set");
 			});
 
-			it("should not use scope", function() {
-				assert.deepEqual(getGenerated(obj, 1, 1, 1), getGenerated(obj, 1, 1, 10));
-				assert.deepEqual(getGenerated(obj, 1, 2, 1), getGenerated(obj, 1, 2, 10));
-				assert.deepEqual(getGenerated(obj, 1, 3, 1), getGenerated(obj, 1, 3, 10));
-				assert.deepEqual(getGenerated(obj, 2, 3, 1), getGenerated(obj, 2, 3, 10));
-				assert.deepEqual(getGenerated(obj, 3, 3, 1), getGenerated(obj, 3, 3, 10));
+			it("should use scope if max=null", function() {
+				obj.scope = {min: 1, max: null};
+				assert.deepEqual(getGenerated(obj, 1), [
+					["a"],
+				]);
+				assert.deepEqual(getGenerated(obj, 2), [
+					["a"],
+					["a", "a"],
+				]);
+				assert.deepEqual(getGenerated(obj, 3), [
+					["a"],
+					["a", "a"],
+					["a", "a", "a"],
+				]);
 			});
 
 		});
 
 		describe("Sequence", function() {
 
-			let obj = g.behaviors.foobarbaz.body[0];
+			// copy sequence from "abc" behavior so that we can attach test min/max
+			let obj = Object.create(g.behaviors.abc.body[0]);
 
 			it("should return 1 trace if min=1, max=1", function() {
-				assert.deepEqual(getGenerated(obj, 1, 1), [
-					["foo", "bar", "baz"],
+				obj.scope = {min: 1, max: 1};
+				assert.deepEqual(getGenerated(obj), [
+					["a", "b", "c"],
 				]);
+				assert.deepEqual(getGenerated(obj), getGenerated(obj, 2), "should not be affected by scope if max is set");
 			});
 
 			it("should return 2 traces if min=1, max=2", function() {
-				assert.deepEqual(getGenerated(obj, 1, 2), [
-					["foo", "bar", "baz"],
-					["foo", "bar", "baz", "foo", "bar", "baz"],
+				obj.scope = {min: 1, max: 2};
+				assert.deepEqual(getGenerated(obj), [
+					["a", "b", "c"],
+					["a", "b", "c", "a", "b", "c"],
 				]);
+				assert.deepEqual(getGenerated(obj), getGenerated(obj, 2), "should not be affected by scope if max is set");
 			});
 
 			it("should return 3 traces if min=1, max=3", function() {
-				assert.deepEqual(getGenerated(obj, 1, 3), [
-					["foo", "bar", "baz"],
-					["foo", "bar", "baz", "foo", "bar", "baz"],
-					["foo", "bar", "baz", "foo", "bar", "baz", "foo", "bar", "baz"],
+				obj.scope = {min: 1, max: 3};
+				assert.deepEqual(getGenerated(obj), [
+					["a", "b", "c"],
+					["a", "b", "c", "a", "b", "c"],
+					["a", "b", "c", "a", "b", "c", "a", "b", "c"],
 				]);
+				assert.deepEqual(getGenerated(obj), getGenerated(obj, 2), "should not be affected by scope if max is set");
 			});
 
 			it("should return 2 traces if min=2, max=3", function() {
-				assert.deepEqual(getGenerated(obj, 2, 3), [
-					["foo", "bar", "baz", "foo", "bar", "baz"],
-					["foo", "bar", "baz", "foo", "bar", "baz", "foo", "bar", "baz"],
+				obj.scope = {min: 2, max: 3};
+				assert.deepEqual(getGenerated(obj), [
+					["a", "b", "c", "a", "b", "c"],
+					["a", "b", "c", "a", "b", "c", "a", "b", "c"],
 				]);
+				assert.deepEqual(getGenerated(obj), getGenerated(obj, 2), "should not be affected by scope if max is set");
 			});
 
 			it("should return 1 trace if min=3, max=3", function() {
-				assert.deepEqual(getGenerated(obj, 3, 3), [
-					["foo", "bar", "baz", "foo", "bar", "baz", "foo", "bar", "baz"],
+				obj.scope = {min: 3, max: 3};
+				assert.deepEqual(getGenerated(obj), [
+					["a", "b", "c", "a", "b", "c", "a", "b", "c"],
 				]);
+				assert.deepEqual(getGenerated(obj), getGenerated(obj, 2), "should not be affected by scope if max is set");
 			});
 
-			it("should not use scope", function() {
-				assert.deepEqual(getGenerated(obj, 1, 1, 1), getGenerated(obj, 1, 1, 10));
-				assert.deepEqual(getGenerated(obj, 1, 2, 1), getGenerated(obj, 1, 2, 10));
-				assert.deepEqual(getGenerated(obj, 1, 3, 1), getGenerated(obj, 1, 3, 10));
-				assert.deepEqual(getGenerated(obj, 2, 3, 1), getGenerated(obj, 2, 3, 10));
-				assert.deepEqual(getGenerated(obj, 3, 3, 1), getGenerated(obj, 3, 3, 10));
+			it("should use scope if max=null", function() {
+				obj.scope = {min: 1, max: null};
+				assert.deepEqual(getGenerated(obj, 1), [
+					["a", "b", "c"],
+				]);
+				assert.deepEqual(getGenerated(obj, 2), [
+					["a", "b", "c"],
+					["a", "b", "c", "a", "b", "c"],
+				]);
+				assert.deepEqual(getGenerated(obj, 3), [
+					["a", "b", "c"],
+					["a", "b", "c", "a", "b", "c"],
+					["a", "b", "c", "a", "b", "c", "a", "b", "c"],
+				]);
 			});
 
 		});
 
 		describe("Behavior (parent/complex)", function() {
 
-			let obj = g.behaviors.foobarbaz;
+			// copy "abc" behavior so that we can attach test min/max
+			let obj = Object.create(g.behaviors.abc);
 
 			it("should return 1 trace if min=1, max=1", function() {
-				assert.deepEqual(getGenerated(obj, 1, 1), [
-					["foobarbaz", "foo", "bar", "baz"],
+				obj.scope = {min: 1, max: 1};
+				assert.deepEqual(getGenerated(obj), [
+					["abc", "a", "b", "c"],
 				]);
+				assert.deepEqual(getGenerated(obj), getGenerated(obj, 2), "should not be affected by scope if max is set");
 			});
 
 			it("should return 2 traces if min=1, max=2", function() {
-				assert.deepEqual(getGenerated(obj, 1, 2), [
-					["foobarbaz", "foo", "bar", "baz"],
-					["foobarbaz", "foo", "bar", "baz", "foobarbaz", "foo", "bar", "baz"],
+				obj.scope = {min: 1, max: 2};
+				assert.deepEqual(getGenerated(obj), [
+					["abc", "a", "b", "c"],
+					["abc", "a", "b", "c", "abc", "a", "b", "c"],
 				]);
+				assert.deepEqual(getGenerated(obj), getGenerated(obj, 2), "should not be affected by scope if max is set");
 			});
 
 			it("should return 3 traces if min=1, max=3", function() {
-				assert.deepEqual(getGenerated(obj, 1, 3), [
-					["foobarbaz", "foo", "bar", "baz"],
-					["foobarbaz", "foo", "bar", "baz", "foobarbaz", "foo", "bar", "baz"],
-					["foobarbaz", "foo", "bar", "baz", "foobarbaz", "foo", "bar", "baz", "foobarbaz", "foo", "bar", "baz"],
+				obj.scope = {min: 1, max: 3};
+				assert.deepEqual(getGenerated(obj), [
+					["abc", "a", "b", "c"],
+					["abc", "a", "b", "c", "abc", "a", "b", "c"],
+					["abc", "a", "b", "c", "abc", "a", "b", "c", "abc", "a", "b", "c"],
 				]);
+				assert.deepEqual(getGenerated(obj), getGenerated(obj, 2), "should not be affected by scope if max is set");
 			});
 
 			it("should return 2 traces if min=2, max=3", function() {
-				assert.deepEqual(getGenerated(obj, 2, 3), [
-					["foobarbaz", "foo", "bar", "baz", "foobarbaz", "foo", "bar", "baz"],
-					["foobarbaz", "foo", "bar", "baz", "foobarbaz", "foo", "bar", "baz", "foobarbaz", "foo", "bar", "baz"],
+				obj.scope = {min: 2, max: 3};
+				assert.deepEqual(getGenerated(obj), [
+					["abc", "a", "b", "c", "abc", "a", "b", "c"],
+					["abc", "a", "b", "c", "abc", "a", "b", "c", "abc", "a", "b", "c"],
 				]);
+				assert.deepEqual(getGenerated(obj), getGenerated(obj, 2), "should not be affected by scope if max is set");
 			});
 
 			it("should return 1 trace if min=3, max=3", function() {
-				assert.deepEqual(getGenerated(obj, 3, 3), [
-					["foobarbaz", "foo", "bar", "baz", "foobarbaz", "foo", "bar", "baz", "foobarbaz", "foo", "bar", "baz"],
+				obj.scope = {min: 3, max: 3};
+				assert.deepEqual(getGenerated(obj), [
+					["abc", "a", "b", "c", "abc", "a", "b", "c", "abc", "a", "b", "c"],
+				]);
+				assert.deepEqual(getGenerated(obj), getGenerated(obj, 2), "should not be affected by scope if max is set");
+			});
+
+			it("should use scope if max=null", function() {
+				obj.scope = {min: 1, max: null};
+				assert.deepEqual(getGenerated(obj, 1), [
+					["abc", "a", "b", "c"],
+				]);
+				assert.deepEqual(getGenerated(obj, 2), [
+					["abc", "a", "b", "c"],
+					["abc", "a", "b", "c", "abc", "a", "b", "c"],
+				]);
+				assert.deepEqual(getGenerated(obj, 3), [
+					["abc", "a", "b", "c"],
+					["abc", "a", "b", "c", "abc", "a", "b", "c"],
+					["abc", "a", "b", "c", "abc", "a", "b", "c", "abc", "a", "b", "c"],
+				]);
+			});
+
+		});
+
+		describe("System", function() {
+
+			let obj = g.systems.sys;
+
+			it("should return 1 trace if scope=1", function() {
+				assert.deepEqual(getGenerated(obj, 1), [
+					["sys", "abc", "a", "b", "c"],
+				]);
+			});
+
+			it("should return 2 traces if scope=2", function() {
+				assert.deepEqual(getGenerated(obj, 2), [
+					["sys", "abc", "a", "b", "c"],
+					["sys", "abc", "a", "b", "c", "abc", "a", "b", "c"],
 				]);
 			});