@machinemetrics/io-adapter-lib 2.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.circleci/config.yml +141 -0
- package/.eslintrc.json +36 -0
- package/.gitattributes +12 -0
- package/CHANGELOG.md +544 -0
- package/README.md +2 -0
- package/index.js +17 -0
- package/lib/config/adapterConfig.js +535 -0
- package/lib/config/common/allowDenyList.js +58 -0
- package/lib/config/common/jsonPath.js +44 -0
- package/lib/config/common/labjackU3T4Common.js +227 -0
- package/lib/config/common/validations.js +142 -0
- package/lib/config/configError.js +32 -0
- package/lib/config/device/adam-6052Config.js +103 -0
- package/lib/config/device/brotherHTTPConfig.js +215 -0
- package/lib/config/device/ethernetIPConfig.js +191 -0
- package/lib/config/device/ifmIotConfig.js +245 -0
- package/lib/config/device/jsonHttpConfig.js +76 -0
- package/lib/config/device/labjackT4Config.js +39 -0
- package/lib/config/device/labjackT7Config.js +192 -0
- package/lib/config/device/labjackU3Config.js +32 -0
- package/lib/config/device/modbusTcpConfig.js +336 -0
- package/lib/config/device/mqttBaseConfig.js +70 -0
- package/lib/config/device/mqttConfig.js +113 -0
- package/lib/config/device/mqttLincolnConfig.js +62 -0
- package/lib/config/device/mtconnectAdapterConfig.js +42 -0
- package/lib/config/device/mtconnectBaseConfig.js +136 -0
- package/lib/config/device/mtconnectConfig.js +52 -0
- package/lib/config/device/mtconnectHaasConfig.js +15 -0
- package/lib/config/device/nullConfig.js +81 -0
- package/lib/config/device/opcuaConfig.js +205 -0
- package/lib/config/device/pcccConfig.js +88 -0
- package/lib/config/engineConfigV1.js +382 -0
- package/lib/config/engineConfigV2.js +106 -0
- package/lib/config/generator/counterGenConfig.js +15 -0
- package/lib/config/generator/cronGenConfig.js +33 -0
- package/lib/config/generator/dateTimeGenConfig.js +33 -0
- package/lib/config/index.js +339 -0
- package/lib/config/transformConfigUtil.js +296 -0
- package/lib/engine/dataOutput.js +357 -0
- package/lib/engine/deviceOutput.js +186 -0
- package/lib/engine/engineV1.js +480 -0
- package/lib/engine/engineV2.js +719 -0
- package/lib/engine/index.js +34 -0
- package/lib/engine/transformBuilderV1.js +111 -0
- package/lib/engine/transformBuilderV2.js +74 -0
- package/lib/expressionService.js +330 -0
- package/lib/math.js +142 -0
- package/lib/transform/accumulate.js +98 -0
- package/lib/transform/average.js +56 -0
- package/lib/transform/debounce.js +152 -0
- package/lib/transform/downsample.js +69 -0
- package/lib/transform/edge.js +34 -0
- package/lib/transform/expression.js +91 -0
- package/lib/transform/fallingEdge.js +70 -0
- package/lib/transform/fromBuffer.js +89 -0
- package/lib/transform/hash.js +41 -0
- package/lib/transform/ignoreValue.js +118 -0
- package/lib/transform/index.js +93 -0
- package/lib/transform/invert.js +25 -0
- package/lib/transform/latch.js +99 -0
- package/lib/transform/latchValue.js +115 -0
- package/lib/transform/logicAnd.js +67 -0
- package/lib/transform/logicOr.js +67 -0
- package/lib/transform/map.js +115 -0
- package/lib/transform/max.js +57 -0
- package/lib/transform/maxLength.js +39 -0
- package/lib/transform/min.js +57 -0
- package/lib/transform/minDelta.js +40 -0
- package/lib/transform/offDelay.js +89 -0
- package/lib/transform/onDelay.js +89 -0
- package/lib/transform/patternEscape.js +24 -0
- package/lib/transform/patternMatch.js +194 -0
- package/lib/transform/patternReplace.js +170 -0
- package/lib/transform/patternTest.js +85 -0
- package/lib/transform/rateOfChange.js +56 -0
- package/lib/transform/reject.js +115 -0
- package/lib/transform/resample.js +96 -0
- package/lib/transform/risingEdge.js +90 -0
- package/lib/transform/risingEdgeCounter.js +179 -0
- package/lib/transform/sampleInterval.js +12 -0
- package/lib/transform/source.js +116 -0
- package/lib/transform/state.js +201 -0
- package/lib/transform/threshold.js +52 -0
- package/lib/transform/toBuffer.js +159 -0
- package/lib/transform/toggle.js +118 -0
- package/lib/transform/transformState.js +193 -0
- package/lib/transform/trim.js +27 -0
- package/lib/transform/util/chainSource.js +96 -0
- package/lib/transform/util/ringBuffer.js +34 -0
- package/lib/transform/valueChange.js +34 -0
- package/lib/transform/valueDecrease.js +38 -0
- package/lib/transform/valueIncrease.js +38 -0
- package/lib/transform/valueIncreaseDiff.js +66 -0
- package/lib/transform/whenUnavailable.js +73 -0
- package/lib/transform/windowCount.js +86 -0
- package/lib/util/fileUtil.js +44 -0
- package/package.json +38 -0
- package/test/.eslintrc.json +15 -0
- package/test/chainedTransform.test.js +88 -0
- package/test/conditions.test.js +118 -0
- package/test/config/ab-pccc.test.js +41 -0
- package/test/config/adam-6052.test.js +16 -0
- package/test/config/adapter.test.js +109 -0
- package/test/config/brother-http.test.js +19 -0
- package/test/config/ethernet-ip.test.js +19 -0
- package/test/config/ifm-iot.test.js +20 -0
- package/test/config/json-http.test.js +47 -0
- package/test/config/labjack-t4.test.js +78 -0
- package/test/config/labjack-t7.test.js +18 -0
- package/test/config/labjack-u3.test.js +17 -0
- package/test/config/modbusTcp.test.js +87 -0
- package/test/config/mqtt.test.js +19 -0
- package/test/config/mqttLincoln.test.js +29 -0
- package/test/config/mtconnect.test.js +63 -0
- package/test/config/mtconnectAdapter.test.js +124 -0
- package/test/config/mtconnectHaas.test.js +15 -0
- package/test/config/null.test.js +16 -0
- package/test/config/opcua.test.js +97 -0
- package/test/config-tests.js +102 -0
- package/test/configFiles/conditions.yml +37 -0
- package/test/configFiles/data-items-legacy.yml +24 -0
- package/test/configFiles/data-items-shorthand.yml +14 -0
- package/test/configFiles/data-items.yml +12 -0
- package/test/configFiles/device/ab-pccc-default.yml +3 -0
- package/test/configFiles/device/ab-pccc-full.yml +13 -0
- package/test/configFiles/device/adam-6052-default.yml +2 -0
- package/test/configFiles/device/brother-http-default.yml +3 -0
- package/test/configFiles/device/ethernet-ip-default.yml +2 -0
- package/test/configFiles/device/ifm-iot-default.yml +2 -0
- package/test/configFiles/device/json-http-bad-prop.yml +13 -0
- package/test/configFiles/device/json-http-bad-prop2.yml +13 -0
- package/test/configFiles/device/json-http-default.yml +3 -0
- package/test/configFiles/device/json-http-std.yml +13 -0
- package/test/configFiles/device/labjack-t4-condition-exprs.yaml +46 -0
- package/test/configFiles/device/labjack-t4-default.yml +3 -0
- package/test/configFiles/device/labjack-t4-pins-alt.yaml +41 -0
- package/test/configFiles/device/labjack-t4-pins.yaml +40 -0
- package/test/configFiles/device/labjack-t4-v1.yaml +29 -0
- package/test/configFiles/device/labjack-t7-default.yml +2 -0
- package/test/configFiles/device/labjack-u3-default.yml +2 -0
- package/test/configFiles/device/modbus-partial.yml +4 -0
- package/test/configFiles/device/modbus-std-extended.yaml +23 -0
- package/test/configFiles/device/modbus-std.yaml +34 -0
- package/test/configFiles/device/modbus-tcp-default.yml +3 -0
- package/test/configFiles/device/mqtt-default.yml +2 -0
- package/test/configFiles/device/mqtt-lincoln-default.yml +3 -0
- package/test/configFiles/device/mqtt-lincoln-full.yml +7 -0
- package/test/configFiles/device/mtconnect-adapter-default.yml +3 -0
- package/test/configFiles/device/mtconnect-adapter-keys.yaml +18 -0
- package/test/configFiles/device/mtconnect-complex-keys.yaml +17 -0
- package/test/configFiles/device/mtconnect-default.yml +3 -0
- package/test/configFiles/device/mtconnect-duplicate-allow-keys.yaml +10 -0
- package/test/configFiles/device/mtconnect-duplicate-declare-keys.yaml +8 -0
- package/test/configFiles/device/mtconnect-duplicate-deny-keys.yaml +10 -0
- package/test/configFiles/device/mtconnect-haas-default.yml +3 -0
- package/test/configFiles/device/mtconnect-std.yaml +18 -0
- package/test/configFiles/device/null-default.yml +1 -0
- package/test/configFiles/device/opcua-bad-tag.yml +18 -0
- package/test/configFiles/device/opcua-bad-tag2.yml +18 -0
- package/test/configFiles/device/opcua-default.yml +3 -0
- package/test/configFiles/device/opcua-std.yml +18 -0
- package/test/configFiles/dump-test.yml +11 -0
- package/test/configFiles/expressionCond.yml +46 -0
- package/test/configFiles/min-config-t4.yaml +4 -0
- package/test/configFiles/min-config-u3.yaml +3 -0
- package/test/configFiles/missing-device.yaml +2 -0
- package/test/configFiles/parse-error1.yml +9 -0
- package/test/configFiles/parse-error2.yml +9 -0
- package/test/configFiles/repro/buffer-convert-repro.yml +15 -0
- package/test/configFiles/repro/chained-delay-timing-repro.yml +13 -0
- package/test/configFiles/repro/count-init-repro.yml +45 -0
- package/test/configFiles/repro/cycle-break-repro.yml +44 -0
- package/test/configFiles/repro/debounce-repro.yml +46 -0
- package/test/configFiles/repro/diff-count-repro.yml +34 -0
- package/test/configFiles/repro/engine-hang-repro.yml +9 -0
- package/test/configFiles/repro/latch-apm-repro.yml +26 -0
- package/test/configFiles/repro/lockout-count-repro.yml +33 -0
- package/test/configFiles/repro/program-extract-repro.yml +38 -0
- package/test/configFiles/repro/state-latch-repro.yml +47 -0
- package/test/configFiles/repro/ternary-repro.yml +26 -0
- package/test/configFiles/transform/debounce.yml +12 -0
- package/test/configFiles/transform/expression.yml +34 -0
- package/test/configFiles/transform/ignoreValue.yml +31 -0
- package/test/configFiles/transform/latch.yml +11 -0
- package/test/configFiles/transform/latchValue.yml +31 -0
- package/test/configFiles/transform/logicAnd.yml +14 -0
- package/test/configFiles/transform/logicOr.yml +14 -0
- package/test/configFiles/transform/map.yml +19 -0
- package/test/configFiles/transform/maxLength.yml +13 -0
- package/test/configFiles/transform/offDelay.yml +12 -0
- package/test/configFiles/transform/pattern-escape.yml +10 -0
- package/test/configFiles/transform/pattern-match.yml +57 -0
- package/test/configFiles/transform/pattern-replace.yml +34 -0
- package/test/configFiles/transform/pattern-test.yml +25 -0
- package/test/configFiles/transform/reject.yml +24 -0
- package/test/configFiles/transform/risingEdgeCounter.yml +36 -0
- package/test/configFiles/transform/source.yml +20 -0
- package/test/configFiles/transform/state.yml +56 -0
- package/test/configFiles/transform/toggle.yml +19 -0
- package/test/configFiles/transform/whenUnavailable.yml +19 -0
- package/test/dataFiles/noisy-pulse.txt +11330 -0
- package/test/dataItems.test.js +140 -0
- package/test/engine-v1-tests.js +418 -0
- package/test/engine-v2-tests.js +284 -0
- package/test/expression-tests.js +171 -0
- package/test/expressionService.test.js +154 -0
- package/test/expressionServiceCondition.test.js +130 -0
- package/test/repro/buffer-convert-repro.test.js +38 -0
- package/test/repro/chained-delay-timing-repro.test.js +34 -0
- package/test/repro/count-init-repro.test.js +46 -0
- package/test/repro/cylce-break-repro.test.js +57 -0
- package/test/repro/debounce-repro.test.js +65 -0
- package/test/repro/diff-count-repro.test.js +79 -0
- package/test/repro/engine-hang-repro.test.js +38 -0
- package/test/repro/latch-apm-repro.test.js +119 -0
- package/test/repro/lockout-count-repro.test.js +84 -0
- package/test/repro/program-extract-repro.test.js +40 -0
- package/test/repro/state-latch-repro.test.js +63 -0
- package/test/repro/ternary-repro.test.js +43 -0
- package/test/transform/accumulte.test.js +18 -0
- package/test/transform/average.test.js +22 -0
- package/test/transform/debounce.test.js +70 -0
- package/test/transform/downsample.test.js +30 -0
- package/test/transform/edge.test.js +27 -0
- package/test/transform/expression.test.js +189 -0
- package/test/transform/fallingEdge.test.js +59 -0
- package/test/transform/fromBuffer.test.js +60 -0
- package/test/transform/hash.test.js +34 -0
- package/test/transform/ignoreValue.test.js +123 -0
- package/test/transform/invert.test.js +26 -0
- package/test/transform/latch.test.js +33 -0
- package/test/transform/latchValue.test.js +126 -0
- package/test/transform/logicAnd.test.js +80 -0
- package/test/transform/logicOr.test.js +80 -0
- package/test/transform/map.test.js +42 -0
- package/test/transform/max.test.js +30 -0
- package/test/transform/maxLength.test.js +32 -0
- package/test/transform/min.test.js +30 -0
- package/test/transform/minDelta.test.js +14 -0
- package/test/transform/offDelay.test.js +123 -0
- package/test/transform/onDelay.test.js +105 -0
- package/test/transform/patternEscape.test.js +18 -0
- package/test/transform/patternMatch.test.js +177 -0
- package/test/transform/patternReplace.test.js +95 -0
- package/test/transform/patternTest.test.js +105 -0
- package/test/transform/rateOfChange.test.js +34 -0
- package/test/transform/reject.test.js +56 -0
- package/test/transform/resample.test.js +193 -0
- package/test/transform/risingEdge.test.js +60 -0
- package/test/transform/risingEdgeCounter.test.js +227 -0
- package/test/transform/sampleInterval.test.js +22 -0
- package/test/transform/source.test.js +137 -0
- package/test/transform/state.test.js +248 -0
- package/test/transform/threshold.test.js +78 -0
- package/test/transform/toBuffer.test.js +60 -0
- package/test/transform/toggle.test.js +92 -0
- package/test/transform/trim.test.js +30 -0
- package/test/transform/valueChange.test.js +14 -0
- package/test/transform/valueDecrease.test.js +32 -0
- package/test/transform/valueIncrease.test.js +32 -0
- package/test/transform/valueIncreaseDiff.test.js +32 -0
- package/test/transform/whenUnavailable.test.js +93 -0
- package/test/transform/windowCount.test.js +26 -0
- package/test/util/testUtils.js +405 -0
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const _ = require('lodash');
|
|
4
|
+
const EventEmitter = require('eventemitter3');
|
|
5
|
+
const expect = require('chai').expect;
|
|
6
|
+
const Transform = require('../lib/transform');
|
|
7
|
+
const EngineV2 = require('../lib/engine/engineV2');
|
|
8
|
+
const ExpressionService = require('../lib/expressionService');
|
|
9
|
+
|
|
10
|
+
describe('EngineV2 tests', function () {
|
|
11
|
+
describe('Pin source tests', function () {
|
|
12
|
+
it('adds 0 reffed pin sources', function () {
|
|
13
|
+
const exprsvc = new ExpressionService();
|
|
14
|
+
const source = new ValueSource(exprsvc);
|
|
15
|
+
const pool = new EngineV2({ expressionService: exprsvc });
|
|
16
|
+
pool.addValueSource(source);
|
|
17
|
+
|
|
18
|
+
expect(_.size(pool.pool)).to.eq(0);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('adds 3 reffed pin sources', function () {
|
|
22
|
+
const exprsvc = new ExpressionService();
|
|
23
|
+
const source = new ValueSource(exprsvc);
|
|
24
|
+
const pool = new EngineV2({ expressionService: exprsvc });
|
|
25
|
+
|
|
26
|
+
exprsvc.addExpression({ expression: 'pin-0', path: 'test1' });
|
|
27
|
+
exprsvc.addExpression({ expression: 'pin-1', path: 'test2' });
|
|
28
|
+
exprsvc.addExpression({ expression: 'pin-4', path: 'test3' });
|
|
29
|
+
pool.addValueSource(source);
|
|
30
|
+
|
|
31
|
+
expect(_.size(pool.pool)).to.eq(3);
|
|
32
|
+
expect(pool.pool['pin-0'].name).to.eq('pin-0');
|
|
33
|
+
expect(pool.pool['pin-1'].name).to.eq('pin-1');
|
|
34
|
+
expect(pool.pool['pin-4'].name).to.eq('pin-4');
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('emits direct pin-source events', function () {
|
|
38
|
+
const exprsvc = new ExpressionService();
|
|
39
|
+
const source = new ValueSource(exprsvc);
|
|
40
|
+
const pool = new EngineV2({ expressionService: exprsvc });
|
|
41
|
+
exprsvc.addExpression({ expression: 'pin-1', path: 'test2' });
|
|
42
|
+
|
|
43
|
+
pool.addValueSource(source);
|
|
44
|
+
|
|
45
|
+
const updates = [];
|
|
46
|
+
pool.on('update', (name, value, valueTime) => {
|
|
47
|
+
expect(name).to.eq('pin-1');
|
|
48
|
+
updates.push([value, valueTime]);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
source.sendValues('pin-1', [
|
|
52
|
+
[1, 1], [3, 2], [3, 3], [5, 4], [2, 5],
|
|
53
|
+
]);
|
|
54
|
+
expect(updates).to.deep.equal([
|
|
55
|
+
[1, 1], [3, 2], [5, 4], [2, 5],
|
|
56
|
+
]);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
describe('Array tests', function () {
|
|
61
|
+
it('passes through arrays', function () {
|
|
62
|
+
const exprsvc = new ExpressionService();
|
|
63
|
+
const source = new ValueSource(exprsvc);
|
|
64
|
+
const pool = new EngineV2({ expressionService: exprsvc });
|
|
65
|
+
exprsvc.addExpression({ expression: 'pin-1', path: 'test2' });
|
|
66
|
+
|
|
67
|
+
pool.addValueSource(source);
|
|
68
|
+
|
|
69
|
+
const updates = [];
|
|
70
|
+
pool.on('update', (name, value, valueTime) => {
|
|
71
|
+
expect(name).to.eq('pin-1');
|
|
72
|
+
updates.push([value, valueTime]);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
source.sendValues('pin-1', [
|
|
76
|
+
[[1, 0], 1], [[3, 0], 2], [[3, 0], 3], [[5, 0], 4], [[2, 0], 5],
|
|
77
|
+
]);
|
|
78
|
+
expect(updates).to.deep.equal([
|
|
79
|
+
[[1, 0], 1], [[3, 0], 2], [[5, 0], 4], [[2, 0], 5],
|
|
80
|
+
]);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe('Variable tests', function () {
|
|
85
|
+
it('pin -> variable -> out', function () {
|
|
86
|
+
const exprsvc = new ExpressionService();
|
|
87
|
+
const source = new ValueSource(exprsvc);
|
|
88
|
+
const engine = new EngineV2({ expressionService: exprsvc });
|
|
89
|
+
|
|
90
|
+
const sourceExpression = 'pin-1';
|
|
91
|
+
exprsvc.addExpression({ expression: sourceExpression, path: 'test1' });
|
|
92
|
+
engine.addValueSource(source);
|
|
93
|
+
|
|
94
|
+
const filter = new Transform.source({
|
|
95
|
+
engine,
|
|
96
|
+
path: 'test1',
|
|
97
|
+
rootPath: 'test1',
|
|
98
|
+
baseTransform: true,
|
|
99
|
+
args: {
|
|
100
|
+
expression: sourceExpression,
|
|
101
|
+
},
|
|
102
|
+
}).chain(new Transform.threshold({ args: { threshold: 3 } }));
|
|
103
|
+
engine.addVariable('exec', filter);
|
|
104
|
+
|
|
105
|
+
const updates = [];
|
|
106
|
+
engine.on('update', (name, value, valueTime) => {
|
|
107
|
+
if (name === 'exec') {
|
|
108
|
+
updates.push([value, valueTime]);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
source.sendValues('pin-1', [
|
|
113
|
+
[1, 1], [3, 2], [3, 3], [5, 4], [2, 5],
|
|
114
|
+
]);
|
|
115
|
+
expect(updates).to.deep.equal([
|
|
116
|
+
[false, 1], [true, 2], [false, 5],
|
|
117
|
+
]);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('pin -> variable -> out (reverse attach)', function () {
|
|
121
|
+
const exprsvc = new ExpressionService();
|
|
122
|
+
const engine = new EngineV2({ expressionService: exprsvc });
|
|
123
|
+
|
|
124
|
+
const sourceExpression = 'pin-1';
|
|
125
|
+
exprsvc.addName({ name: 'pin-1', channel: 'device', defaultValue: 0 });
|
|
126
|
+
exprsvc.addExpression({ expression: sourceExpression, path: 'test1' });
|
|
127
|
+
|
|
128
|
+
const filter = new Transform.source({
|
|
129
|
+
engine,
|
|
130
|
+
path: 'test1',
|
|
131
|
+
rootPath: 'test1',
|
|
132
|
+
baseTransform: true,
|
|
133
|
+
args: {
|
|
134
|
+
expression: sourceExpression,
|
|
135
|
+
},
|
|
136
|
+
}).chain(new Transform.threshold({ args: { threshold: 3 } }));
|
|
137
|
+
engine.addVariable('exec', filter);
|
|
138
|
+
|
|
139
|
+
const source = new ValueSource(exprsvc);
|
|
140
|
+
engine.addValueSource(source);
|
|
141
|
+
|
|
142
|
+
const updates = [];
|
|
143
|
+
engine.on('update', (name, value, valueTime) => {
|
|
144
|
+
if (name === 'exec') {
|
|
145
|
+
updates.push([value, valueTime]);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
source.sendValues('pin-1', [
|
|
150
|
+
[1, 1], [3, 2], [3, 3], [5, 4], [2, 5],
|
|
151
|
+
]);
|
|
152
|
+
expect(updates).to.deep.equal([
|
|
153
|
+
[false, 1], [true, 2], [false, 5],
|
|
154
|
+
]);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it('pin -> variable -> variable -> out', function () {
|
|
158
|
+
const exprsvc = new ExpressionService();
|
|
159
|
+
const source = new ValueSource(exprsvc);
|
|
160
|
+
const engine = new EngineV2({ expressionService: exprsvc });
|
|
161
|
+
|
|
162
|
+
const sourceExpression1 = 'pin-1';
|
|
163
|
+
const sourceExpression2 = 'exec';
|
|
164
|
+
exprsvc.addName({ name: 'exec', defaultValue: 0, channel: 'engine' });
|
|
165
|
+
exprsvc.addExpression({ expression: sourceExpression1, path: 'test1' });
|
|
166
|
+
exprsvc.addExpression({ expression: sourceExpression2, path: 'test2' });
|
|
167
|
+
engine.addValueSource(source);
|
|
168
|
+
|
|
169
|
+
const filter = new Transform.source({
|
|
170
|
+
engine,
|
|
171
|
+
path: 'test1',
|
|
172
|
+
rootPath: 'test1',
|
|
173
|
+
baseTransform: true,
|
|
174
|
+
args: {
|
|
175
|
+
expression: sourceExpression1,
|
|
176
|
+
},
|
|
177
|
+
}).chain(new Transform.threshold({ args: { threshold: 3 } }));
|
|
178
|
+
engine.addVariable('exec', filter);
|
|
179
|
+
|
|
180
|
+
const filter2 = new Transform.source({
|
|
181
|
+
engine,
|
|
182
|
+
path: 'test2',
|
|
183
|
+
rootPath: 'test2',
|
|
184
|
+
baseTransform: true,
|
|
185
|
+
args: {
|
|
186
|
+
expression: sourceExpression2,
|
|
187
|
+
},
|
|
188
|
+
}).chain(new Transform.risingEdgeCounter({
|
|
189
|
+
engine,
|
|
190
|
+
path: 'test3',
|
|
191
|
+
rootPath: 'test2',
|
|
192
|
+
args: {},
|
|
193
|
+
}));
|
|
194
|
+
engine.addVariable('count', filter2);
|
|
195
|
+
|
|
196
|
+
const updates = [];
|
|
197
|
+
engine.on('update', (name, value, valueTime) => {
|
|
198
|
+
if (name === 'count') {
|
|
199
|
+
updates.push([value, valueTime]);
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
source.sendValues('pin-1', [
|
|
204
|
+
[1, 1], [3, 2], [3, 3], [5, 4], [2, 5],
|
|
205
|
+
]);
|
|
206
|
+
expect(updates).to.deep.equal([
|
|
207
|
+
[0, 1], [1, 2],
|
|
208
|
+
]);
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
describe('Pending tests', function () {
|
|
213
|
+
it('Pending change updates happen before state updates', function () {
|
|
214
|
+
const exprsvc = new ExpressionService();
|
|
215
|
+
const source = new ValueSource(exprsvc);
|
|
216
|
+
const engine = new EngineV2({ expressionService: exprsvc });
|
|
217
|
+
|
|
218
|
+
const sourceExpression = 'pin-1';
|
|
219
|
+
exprsvc.addExpression({ expression: sourceExpression, path: 'test1' });
|
|
220
|
+
engine.addValueSource(source);
|
|
221
|
+
|
|
222
|
+
const filter = new Transform.source({
|
|
223
|
+
engine,
|
|
224
|
+
path: 'test1',
|
|
225
|
+
rootPath: 'test1',
|
|
226
|
+
baseTransform: true,
|
|
227
|
+
args: {
|
|
228
|
+
expression: sourceExpression,
|
|
229
|
+
},
|
|
230
|
+
}).chain(new Transform.threshold({ args: { threshold: 2 } }))
|
|
231
|
+
.chain(new Transform.offDelay(2));
|
|
232
|
+
engine.addVariable('test', filter);
|
|
233
|
+
|
|
234
|
+
const updates = [];
|
|
235
|
+
engine.on('update', (name, value, valueTime) => {
|
|
236
|
+
if (name === 'test') {
|
|
237
|
+
updates.push([value, valueTime]);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
expect(filter.chainSupportsPendingChange()).to.eq(true);
|
|
242
|
+
expect(filter.chainNextPendingChange()).to.eq(null);
|
|
243
|
+
|
|
244
|
+
source.sendValues('pin-1', [
|
|
245
|
+
[5, 1], [1.5, 2],
|
|
246
|
+
]);
|
|
247
|
+
expect(filter.chainNextPendingChange()).to.eq(4);
|
|
248
|
+
|
|
249
|
+
source.sendValues('pin-1', [
|
|
250
|
+
[3, 3], [1.5, 6], [3, 9],
|
|
251
|
+
]);
|
|
252
|
+
|
|
253
|
+
expect(updates).to.deep.equal([
|
|
254
|
+
[true, 1], [false, 8], [true, 9],
|
|
255
|
+
]);
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
class ValueSource extends EventEmitter {
|
|
261
|
+
constructor(expressionService) {
|
|
262
|
+
super();
|
|
263
|
+
this.config = {};
|
|
264
|
+
this.config.pins = {
|
|
265
|
+
0: { pin: 0, mode: 'analog' },
|
|
266
|
+
1: { pin: 1, mode: 'analog' },
|
|
267
|
+
4: { pin: 4, mode: 'digital' },
|
|
268
|
+
};
|
|
269
|
+
|
|
270
|
+
_.each(this.config.pins, (pin) => {
|
|
271
|
+
expressionService.addName({
|
|
272
|
+
name: `pin-${pin.pin}`,
|
|
273
|
+
defaultValue: 0,
|
|
274
|
+
channel: 'device',
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
sendValues(pin, arr) {
|
|
280
|
+
_.each(arr, ([value, time]) => {
|
|
281
|
+
this.emit('update', pin, value, time);
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const expect = require('chai').expect;
|
|
4
|
+
const math = require('../lib/math');
|
|
5
|
+
|
|
6
|
+
describe('Expression tests', function () {
|
|
7
|
+
it('flags', function () {
|
|
8
|
+
expect(math.compile('flag(17, 0)').evaluate({})).to.eq(true);
|
|
9
|
+
expect(math.compile('flag(17, 1)').evaluate({})).to.eq(false);
|
|
10
|
+
expect(math.compile('flag(17, 4)').evaluate({})).to.eq(true);
|
|
11
|
+
expect(math.compile('flag(xx, 4)').evaluate({ xx: 17 })).to.eq(true);
|
|
12
|
+
expect(math.compile('flag([true, false, true, false], 0)').evaluate({})).to.eq(true);
|
|
13
|
+
expect(math.compile('flag([true, false, true, false], 1)').evaluate({})).to.eq(false);
|
|
14
|
+
expect(math.compile('flag([true, false, true, false], 6)').evaluate({})).to.eq(false);
|
|
15
|
+
expect(math.compile('flag(xx, 2)').evaluate({ xx: [true, false, true] })).to.eq(true);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('string equality', function () {
|
|
19
|
+
expect(math.compile('equalText("abc", "abc")').evaluate({})).to.eq(true);
|
|
20
|
+
expect(math.compile('equalText("abc", "def")').evaluate({})).to.eq(false);
|
|
21
|
+
expect(math.compile('equalText(xx, "def")').evaluate({ xx: 'abc' })).to.eq(false);
|
|
22
|
+
expect(math.compile('equalText(xx, "abc")').evaluate({ xx: 'abc' })).to.eq(true);
|
|
23
|
+
expect(math.compile('equalText(xx, "abc")').evaluate({ xx: 25 })).to.eq(false);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('string concat', function () {
|
|
27
|
+
expect(math.compile('concat("abc", "def")').evaluate({})).to.eq('abcdef');
|
|
28
|
+
expect(math.compile('concat("abc", 123)').evaluate({})).to.eq('abc123');
|
|
29
|
+
expect(math.compile('concat(456, 123)').evaluate({})).to.eq('456123');
|
|
30
|
+
expect(math.compile('concat("abc", "def", "ghi")').evaluate({})).to.eq('abcdefghi');
|
|
31
|
+
expect(math.compile('concat(xx, yy)').evaluate({ xx: 'abc', yy: 25 })).to.eq('abc25');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('compound expressions', function () {
|
|
35
|
+
expect(math.compile('xx + 5').evaluate({ xx: 7 })).to.eq(12);
|
|
36
|
+
expect(math.compile('(xx + 5)').evaluate({ xx: 7 })).to.eq(12);
|
|
37
|
+
expect(math.compile('(5 + xx)').evaluate({ xx: 7 })).to.eq(12);
|
|
38
|
+
expect(math.compile('(xx + yy)').evaluate({ xx: 7, yy: 5 })).to.eq(12);
|
|
39
|
+
expect(math.compile('min(xx, yy)').evaluate({ xx: 7, yy: 5 })).to.eq(5);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('equality override', function () {
|
|
43
|
+
expect(math.compile('"abc" == "abc"').evaluate({})).to.eq(true);
|
|
44
|
+
expect(math.compile('"abc" == "def"').evaluate({})).to.eq(false);
|
|
45
|
+
expect(math.compile('4 == 4').evaluate({})).to.eq(true);
|
|
46
|
+
expect(math.compile('4 == 5').evaluate({})).to.eq(false);
|
|
47
|
+
expect(math.compile('4 == "4"').evaluate({})).to.eq(true);
|
|
48
|
+
expect(math.compile('4 == "5"').evaluate({})).to.eq(false);
|
|
49
|
+
expect(math.compile('"4" == 4').evaluate({})).to.eq(true);
|
|
50
|
+
expect(math.compile('"5" == 4').evaluate({})).to.eq(false);
|
|
51
|
+
expect(math.compile('xx == "abc"').evaluate({ xx: 'abc' })).to.eq(true);
|
|
52
|
+
expect(math.compile('xx == "abc"').evaluate({ xx: 'def' })).to.eq(false);
|
|
53
|
+
expect(math.compile('xx == 4').evaluate({ xx: 4 })).to.eq(true);
|
|
54
|
+
expect(math.compile('xx == 4').evaluate({ xx: '4' })).to.eq(true);
|
|
55
|
+
expect(math.compile('xx == "4"').evaluate({ xx: '4' })).to.eq(true);
|
|
56
|
+
expect(math.compile('xx == "4"').evaluate({ xx: 4 })).to.eq(true);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('string start', function () {
|
|
60
|
+
expect(math.compile('startsWith("abcdef", "abc")').evaluate({})).to.eq(true);
|
|
61
|
+
expect(math.compile('startsWith("abcdef", "bcd")').evaluate({})).to.eq(false);
|
|
62
|
+
expect(math.compile('startsWith(42, "abc")').evaluate({})).to.eq(false);
|
|
63
|
+
expect(math.compile('startsWith(xx, "abc")').evaluate({ xx: 'abcdef' })).to.eq(true);
|
|
64
|
+
expect(math.compile('startsWith(xx, "bcd")').evaluate({ xx: 'abcdef' })).to.eq(false);
|
|
65
|
+
expect(math.compile('startsWith(xx, yy)').evaluate({ xx: 'abcdef', yy: 'abc' })).to.eq(true);
|
|
66
|
+
expect(math.compile('startsWith(xx, yy)').evaluate({ xx: 'abcdef', yy: 'bcd' })).to.eq(false);
|
|
67
|
+
expect(math.compile('startsWith(xx, yy)').evaluate({ xx: 42, yy: 'bcd' })).to.eq(false);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('string end', function () {
|
|
71
|
+
expect(math.compile('endsWith("abcdef", "def")').evaluate({})).to.eq(true);
|
|
72
|
+
expect(math.compile('endsWith("abcdef", "cde")').evaluate({})).to.eq(false);
|
|
73
|
+
expect(math.compile('endsWith(42, "def")').evaluate({})).to.eq(false);
|
|
74
|
+
expect(math.compile('endsWith(xx, "def")').evaluate({ xx: 'abcdef' })).to.eq(true);
|
|
75
|
+
expect(math.compile('endsWith(xx, "cde")').evaluate({ xx: 'abcdef' })).to.eq(false);
|
|
76
|
+
expect(math.compile('endsWith(xx, yy)').evaluate({ xx: 'abcdef', yy: 'def' })).to.eq(true);
|
|
77
|
+
expect(math.compile('endsWith(xx, yy)').evaluate({ xx: 'abcdef', yy: 'cde' })).to.eq(false);
|
|
78
|
+
expect(math.compile('endsWith(xx, yy)').evaluate({ xx: 42, yy: 'def' })).to.eq(false);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('string contains', function () {
|
|
82
|
+
expect(math.compile('contains("abcdef", "bcd")').evaluate({})).to.eq(true);
|
|
83
|
+
expect(math.compile('contains("abcdef", "abcdef")').evaluate({})).to.eq(true);
|
|
84
|
+
expect(math.compile('contains("abcdef", "")').evaluate({})).to.eq(true);
|
|
85
|
+
expect(math.compile('contains("abcdef", "efg")').evaluate({})).to.eq(false);
|
|
86
|
+
expect(math.compile('contains(42, "abc")').evaluate({})).to.eq(false);
|
|
87
|
+
expect(math.compile('contains(xx, "bcd")').evaluate({ xx: 'abcdef' })).to.eq(true);
|
|
88
|
+
expect(math.compile('contains(xx, "efg")').evaluate({ xx: 'abcdef' })).to.eq(false);
|
|
89
|
+
expect(math.compile('contains(xx, yy)').evaluate({ xx: 'abcdef', yy: 'bcd' })).to.eq(true);
|
|
90
|
+
expect(math.compile('contains(xx, yy)').evaluate({ xx: 'abcdef', yy: 'efg' })).to.eq(false);
|
|
91
|
+
expect(math.compile('contains(xx, yy)').evaluate({ xx: 42, yy: 'bcd' })).to.eq(false);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('array contains', function () {
|
|
95
|
+
expect(math.compile('contains(["a", "b", "c"], "a")').evaluate({})).to.eq(true);
|
|
96
|
+
expect(math.compile('contains(["a", "b", "c"], "f")').evaluate({})).to.eq(false);
|
|
97
|
+
expect(math.compile('contains([1, 2, 3], 2)').evaluate({})).to.eq(true);
|
|
98
|
+
expect(math.compile('contains([1, 2, 3], "2")').evaluate({})).to.eq(true);
|
|
99
|
+
expect(math.compile('contains([], 0)').evaluate({})).to.eq(false);
|
|
100
|
+
expect(math.compile('contains(xx, "2")').evaluate({ xx: [1, 2, 3] })).to.eq(true);
|
|
101
|
+
expect(math.compile('contains(xx, yy)').evaluate({ xx: [1, 2, 3], yy: '2' })).to.eq(true);
|
|
102
|
+
expect(math.compile('contains(xx, yy)').evaluate({ xx: [1, 2, 3], yy: 4 })).to.eq(false);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('string test', function () {
|
|
106
|
+
// Parsing limitation probably means we need to double-escape (or quad-escape?) any regex character class
|
|
107
|
+
expect(math.compile('test("port9001", "port")').evaluate({})).to.eq(true);
|
|
108
|
+
expect(math.compile('test("port9001", "\\\\d+$")').evaluate({})).to.eq(true);
|
|
109
|
+
expect(math.compile('test("port9001", "^port\\\\d+$")').evaluate({})).to.eq(true);
|
|
110
|
+
expect(math.compile('test("port9001x", "^port\\\\d+$")').evaluate({})).to.eq(false);
|
|
111
|
+
expect(math.compile('test(xx, "\\\\d+$")').evaluate({ xx: 'port9001' })).to.eq(true);
|
|
112
|
+
expect(math.compile('test(xx, "^port\\\\d+$")').evaluate({ xx: 'port9001' })).to.eq(true);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('string match', function () {
|
|
116
|
+
expect(math.compile('match("port9001", "port")').evaluate({})).to.eq('port');
|
|
117
|
+
expect(math.compile('match("port9001", "\\\\d+$")').evaluate({})).to.eq('9001');
|
|
118
|
+
expect(math.compile('match("port9001", "^port\\\\d+$")').evaluate({})).to.eq('port9001');
|
|
119
|
+
expect(math.compile('match("port9001x", "^port\\\\d+$")').evaluate({})).to.eq('');
|
|
120
|
+
expect(math.compile('match("port9001", "^port(\\\\d+)$", 0)').evaluate({})).to.eq('port9001');
|
|
121
|
+
expect(math.compile('match("port9001", "^port(\\\\d+)$", 1)').evaluate({})).to.eq('9001');
|
|
122
|
+
expect(math.compile('match(xx, "\\\\d+$")').evaluate({ xx: 'port9001' })).to.eq('9001');
|
|
123
|
+
expect(math.compile('match(xx, "^port\\\\d+$")').evaluate({ xx: 'port9001' })).to.eq('port9001');
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('string replace', function () {
|
|
127
|
+
expect(math.compile('replace("port9001", "9002", "")').evaluate({})).to.eq('port9001');
|
|
128
|
+
expect(math.compile('replace("port9001", ".*", "")').evaluate({})).to.eq('');
|
|
129
|
+
expect(math.compile('replace("port9001", "port", "")').evaluate({})).to.eq('9001');
|
|
130
|
+
expect(math.compile('replace("port9001", "port(\\\\d+)$", "$1")').evaluate({})).to.eq('9001');
|
|
131
|
+
expect(math.compile('replace(xx, "port", "")').evaluate({ xx: 'port9001' })).to.eq('9001');
|
|
132
|
+
expect(math.compile('replace(xx, "port(\\\\d+)$", "$1")').evaluate({ xx: 'port9001' })).to.eq('9001');
|
|
133
|
+
expect(math.compile('replace(xx, "\\\\d+$", yy)').evaluate({ xx: 'port9001', yy: 8080 })).to.eq('port8080');
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('md5', function () {
|
|
137
|
+
expect(math.compile('md5("braitsch")').evaluate({})).to.eq('9b74c9897bac770ffc029102a200c5de');
|
|
138
|
+
expect(math.compile('md5(xx)').evaluate({ xx: 'braitsch' })).to.eq('9b74c9897bac770ffc029102a200c5de');
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('lpad', function () {
|
|
142
|
+
expect(math.compile('lpad("test", 8, "x")').evaluate({})).to.eq('xxxxtest');
|
|
143
|
+
expect(math.compile('lpad(xx, 8, "x")').evaluate({ xx: 'test' })).to.eq('xxxxtest');
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it('rpad', function () {
|
|
147
|
+
expect(math.compile('rpad("test", 8, "x")').evaluate({})).to.eq('testxxxx');
|
|
148
|
+
expect(math.compile('rpad(xx, 8, "x")').evaluate({ xx: 'test' })).to.eq('testxxxx');
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('asc', function () {
|
|
152
|
+
expect(math.compile('asc(82)').evaluate({})).to.eq('R');
|
|
153
|
+
expect(math.compile('asc(xx)').evaluate({ xx: 82 })).to.eq('R');
|
|
154
|
+
expect(math.compile('asc(xx)').evaluate({ xx: '82' })).to.eq('R');
|
|
155
|
+
expect(math.compile('asc([82])').evaluate({})).to.eq('R');
|
|
156
|
+
expect(math.compile('asc([82, 83, 84, 85])').evaluate({})).to.eq('RSTU');
|
|
157
|
+
expect(math.compile('asc([82, 83, 84, 0])').evaluate({})).to.eq('RST');
|
|
158
|
+
expect(math.compile('asc([xx, yy, zz])').evaluate({ xx: 82, yy: 83, zz: 84 })).to.eq('RST');
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('ord', function () {
|
|
162
|
+
expect(math.compile('ord("R")').evaluate({})).to.eq(82);
|
|
163
|
+
expect(math.compile('ord("R", 0)').evaluate({})).to.eq(82);
|
|
164
|
+
expect(math.compile('ord("RSTU", 2)').evaluate({})).to.eq(84);
|
|
165
|
+
expect(math.compile('ord(xx, yy)').evaluate({ xx: 'RSTU', yy: 2 })).to.eq(84);
|
|
166
|
+
// eslint-disable-next-line no-unused-expressions
|
|
167
|
+
expect(math.compile('ord("RSTU", 4)').evaluate({})).to.be.NaN;
|
|
168
|
+
// eslint-disable-next-line no-unused-expressions
|
|
169
|
+
expect(math.compile('ord(82)').evaluate({})).to.be.NaN;
|
|
170
|
+
});
|
|
171
|
+
});
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const expect = require('chai').expect;
|
|
4
|
+
const ExpressionService = require('../lib/expressionService');
|
|
5
|
+
|
|
6
|
+
describe('ExpressionService tests', function () {
|
|
7
|
+
it('has config available', function () {
|
|
8
|
+
const exprsvc = new ExpressionService({ device: 1 });
|
|
9
|
+
expect(exprsvc.config).to.deep.eq({ device: 1 });
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it('checks name legality', function () {
|
|
13
|
+
const exprsvc = new ExpressionService();
|
|
14
|
+
expect(exprsvc.isNameValid('simple')).to.eq(true);
|
|
15
|
+
expect(exprsvc.isNameValid('com-pound')).to.eq(true);
|
|
16
|
+
expect(exprsvc.isNameValid('double-com-pound')).to.eq(true);
|
|
17
|
+
expect(exprsvc.isNameValid('All91_legal-chars')).to.eq(true);
|
|
18
|
+
expect(exprsvc.isNameValid('-no-prefix')).to.eq(false);
|
|
19
|
+
expect(exprsvc.isNameValid('no-suffix-')).to.eq(false);
|
|
20
|
+
expect(exprsvc.isNameValid('no spaces')).to.eq(false);
|
|
21
|
+
expect(exprsvc.isNameValid('no!')).to.eq(false);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('handles identifier management', function () {
|
|
25
|
+
const exprsvc = new ExpressionService();
|
|
26
|
+
exprsvc.addName({ name: 'pin-0', defaultValue: 0, channel: 'primary' });
|
|
27
|
+
exprsvc.addName({ name: 'pin-1', defaultValue: 0, channel: 'device' });
|
|
28
|
+
exprsvc.addName({ name: 'pin-2', defaultValue: 2, channel: 'device' });
|
|
29
|
+
exprsvc.addName({ name: 'exec-1', defaultValue: 0, channel: 'engine' });
|
|
30
|
+
|
|
31
|
+
expect(exprsvc.definedNames()).to.deep.eq(['pin-0', 'pin-1', 'pin-2', 'exec-1']);
|
|
32
|
+
expect(exprsvc.definedNames('device')).to.deep.eq(['pin-1', 'pin-2']);
|
|
33
|
+
expect(exprsvc.definedNames('engine')).to.deep.eq(['exec-1']);
|
|
34
|
+
expect(exprsvc.definedNames('other')).to.deep.eq([]);
|
|
35
|
+
|
|
36
|
+
expect(exprsvc.referencedNames()).to.deep.eq([]);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('handles expression management', function () {
|
|
40
|
+
const exprsvc = new ExpressionService();
|
|
41
|
+
exprsvc.addName({ name: 'pin-0', defaultValue: 0, channel: 'primary' });
|
|
42
|
+
exprsvc.addName({ name: 'pin-1', defaultValue: 0, channel: 'device' });
|
|
43
|
+
exprsvc.addName({ name: 'pin-2', defaultValue: 2, channel: 'device' });
|
|
44
|
+
exprsvc.addName({ name: 'exec-1', defaultValue: 0, channel: 'engine' });
|
|
45
|
+
|
|
46
|
+
exprsvc.addExpression({ expression: 'pin-0', path: 'test1' });
|
|
47
|
+
exprsvc.addExpression({ expression: 'pin-1 + 3', path: 'test2' });
|
|
48
|
+
exprsvc.addExpression({ expression: 'pin-0 + pin-2', path: 'test3' });
|
|
49
|
+
exprsvc.addExpression({ expression: 'max(pin-0, pin-2)', path: 'test4' });
|
|
50
|
+
exprsvc.addExpression({ expression: 'max(pin-0,pin-2)', path: 'test5' });
|
|
51
|
+
|
|
52
|
+
expect(exprsvc.referencedNames()).to.deep.eq(['pin-0', 'pin-1', 'pin-2']);
|
|
53
|
+
expect(exprsvc.referencedNames('device')).to.deep.eq(['pin-1', 'pin-2']);
|
|
54
|
+
expect(exprsvc.referencedNames('engine')).to.deep.eq([]);
|
|
55
|
+
|
|
56
|
+
expect(exprsvc.expressionTriggers('test1')).to.deep.eq(['pin-0']);
|
|
57
|
+
expect(exprsvc.expressionTriggers('test2')).to.deep.eq(['pin-1']);
|
|
58
|
+
expect(exprsvc.expressionTriggers('test3')).to.deep.eq(['pin-0', 'pin-2']);
|
|
59
|
+
expect(exprsvc.expressionTriggers('test4')).to.deep.eq(['pin-0', 'pin-2']);
|
|
60
|
+
expect(exprsvc.expressionTriggers('test5')).to.deep.eq(['pin-0', 'pin-2']);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('compiles and tests expressions', function () {
|
|
64
|
+
const exprsvc = new ExpressionService();
|
|
65
|
+
exprsvc.addName({ name: 'pin-0', defaultValue: 0, channel: 'primary' });
|
|
66
|
+
exprsvc.addName({ name: 'pin-1', defaultValue: 0, channel: 'device' });
|
|
67
|
+
exprsvc.addName({ name: 'pin-2', defaultValue: 2, channel: 'device' });
|
|
68
|
+
exprsvc.addName({ name: 'exec-1', defaultValue: 0, channel: 'engine' });
|
|
69
|
+
|
|
70
|
+
const math1 = exprsvc.compileExpression('pin-0');
|
|
71
|
+
expect(math1.evaluate({ 'pin-0': 5 })).to.eq(5);
|
|
72
|
+
const math2 = exprsvc.compileExpression('pin-1 + pin-2 + 5');
|
|
73
|
+
expect(math2.evaluate({ 'pin-1': 3, 'pin-2': 14 })).to.eq(22);
|
|
74
|
+
|
|
75
|
+
expect(() => exprsvc.compileExpression('pin-4')).to.throw('Undefined symbol pin-4');
|
|
76
|
+
|
|
77
|
+
const math3 = exprsvc.compileExpression('this + 1', { this: 0 });
|
|
78
|
+
expect(math3.evaluate({ this: 6 })).to.eq(7);
|
|
79
|
+
|
|
80
|
+
expect(() => exprsvc.compileExpression('this + 1')).to.throw('Undefined symbol this');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
/* eslint-disable no-template-curly-in-string */
|
|
84
|
+
|
|
85
|
+
it('parses string expressions', function () {
|
|
86
|
+
const exprsvc = new ExpressionService();
|
|
87
|
+
|
|
88
|
+
const parts1 = exprsvc.parseStringExpr('');
|
|
89
|
+
expect(parts1.length).to.eq(1);
|
|
90
|
+
expect(parts1[0]).to.deep.eq({ text: '' });
|
|
91
|
+
|
|
92
|
+
const parts2 = exprsvc.parseStringExpr('test');
|
|
93
|
+
expect(parts2.length).to.eq(1);
|
|
94
|
+
expect(parts2[0]).to.deep.eq({ text: 'test' });
|
|
95
|
+
|
|
96
|
+
const parts3 = exprsvc.parseStringExpr('test ${var1}');
|
|
97
|
+
expect(parts3.length).to.eq(2);
|
|
98
|
+
expect(parts3[0]).to.deep.eq({ text: 'test ' });
|
|
99
|
+
expect(parts3[1]).to.deep.eq({ text: '${var1}', expression: 'var1' });
|
|
100
|
+
|
|
101
|
+
const parts4 = exprsvc.parseStringExpr('${var1} test');
|
|
102
|
+
expect(parts4.length).to.eq(2);
|
|
103
|
+
expect(parts4[0]).to.deep.eq({ text: '${var1}', expression: 'var1' });
|
|
104
|
+
expect(parts4[1]).to.deep.eq({ text: ' test' });
|
|
105
|
+
|
|
106
|
+
const parts5 = exprsvc.parseStringExpr('${var1}');
|
|
107
|
+
expect(parts5.length).to.eq(1);
|
|
108
|
+
expect(parts5[0]).to.deep.eq({ text: '${var1}', expression: 'var1' });
|
|
109
|
+
|
|
110
|
+
const parts6 = exprsvc.parseStringExpr('test ${var1}${var2} and ${x + y}');
|
|
111
|
+
expect(parts6.length).to.eq(5);
|
|
112
|
+
expect(parts6[0]).to.deep.eq({ text: 'test ' });
|
|
113
|
+
expect(parts6[1]).to.deep.eq({ text: '${var1}', expression: 'var1' });
|
|
114
|
+
expect(parts6[2]).to.deep.eq({ text: '${var2}', expression: 'var2' });
|
|
115
|
+
expect(parts6[3]).to.deep.eq({ text: ' and ' });
|
|
116
|
+
expect(parts6[4]).to.deep.eq({ text: '${x + y}', expression: 'x + y' });
|
|
117
|
+
|
|
118
|
+
const parts7 = exprsvc.parseStringExpr('test ${var1{\\}}');
|
|
119
|
+
expect(parts7.length).to.eq(2);
|
|
120
|
+
expect(parts7[0]).to.deep.eq({ text: 'test ' });
|
|
121
|
+
expect(parts7[1]).to.deep.eq({ text: '${var1{\\}}', expression: 'var1{}' });
|
|
122
|
+
|
|
123
|
+
const parts8 = exprsvc.parseStringExpr('test \\${var1} ${var1}');
|
|
124
|
+
expect(parts8.length).to.eq(2);
|
|
125
|
+
expect(parts8[0]).to.deep.eq({ text: 'test ${var1} ' });
|
|
126
|
+
expect(parts8[1]).to.deep.eq({ text: '${var1}', expression: 'var1' });
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('handles string expression management', function () {
|
|
130
|
+
const exprsvc = new ExpressionService();
|
|
131
|
+
exprsvc.addName({ name: 'pin-0', defaultValue: 0, channel: 'primary' });
|
|
132
|
+
exprsvc.addName({ name: 'pin-1', defaultValue: 0, channel: 'device' });
|
|
133
|
+
exprsvc.addName({ name: 'pin-2', defaultValue: 2, channel: 'device' });
|
|
134
|
+
exprsvc.addName({ name: 'exec-1', defaultValue: 0, channel: 'engine' });
|
|
135
|
+
|
|
136
|
+
exprsvc.addStringExpression({ string: 'code x', path: 'test1' });
|
|
137
|
+
expect(exprsvc.referencedNames()).to.deep.eq([]);
|
|
138
|
+
expect(exprsvc.expressionTriggers('test1')).to.deep.eq([]);
|
|
139
|
+
expect(exprsvc.hasStringExpression('test1')).to.eq(true);
|
|
140
|
+
expect(exprsvc.computeStringExpression('test1', {})).to.eq('code x');
|
|
141
|
+
|
|
142
|
+
exprsvc.addStringExpression({ string: 'code ${pin-0}', path: 'test2' });
|
|
143
|
+
expect(exprsvc.referencedNames()).to.deep.eq(['pin-0']);
|
|
144
|
+
expect(exprsvc.expressionTriggers('test2')).to.deep.eq(['pin-0']);
|
|
145
|
+
expect(exprsvc.hasStringExpression('test2')).to.eq(true);
|
|
146
|
+
expect(exprsvc.computeStringExpression('test2', { 'pin-0': 5 })).to.eq('code 5');
|
|
147
|
+
|
|
148
|
+
exprsvc.addStringExpression({ string: 'code ${pin-0} and ${pin-1 + pin-2}', path: 'test3' });
|
|
149
|
+
expect(exprsvc.referencedNames()).to.deep.eq(['pin-0', 'pin-1', 'pin-2']);
|
|
150
|
+
expect(exprsvc.expressionTriggers('test3')).to.deep.eq(['pin-0', 'pin-1', 'pin-2']);
|
|
151
|
+
expect(exprsvc.hasStringExpression('test3')).to.eq(true);
|
|
152
|
+
expect(exprsvc.computeStringExpression('test3', { 'pin-0': 5, 'pin-1': 10, 'pin-2': 20 })).to.eq('code 5 and 30');
|
|
153
|
+
});
|
|
154
|
+
});
|