xdbc 1.0.211 → 1.0.213
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/.gitattributes +8 -0
- package/.github/workflows/ci.yml +51 -0
- package/.vscode/tasks.json +23 -23
- package/CODE_OF_CONDUCT.md +1 -1
- package/README.md +1 -0
- package/__tests__/DBC/AE.test.ts +1 -1
- package/__tests__/DBC/DEFINED.test.ts +49 -49
- package/__tests__/DBC/Decorators.test.ts +334 -332
- package/__tests__/DBC/HasAttribute.test.ts +56 -52
- package/__tests__/DBC/IF.test.ts +57 -57
- package/__tests__/DBC/OR.test.ts +1 -1
- package/__tests__/DBC/UNDEFINED.test.ts +41 -41
- package/__tests__/DBC/ZOD.test.ts +50 -50
- package/biome.json +40 -33
- package/dist/DBC/AE.d.ts +117 -0
- package/dist/DBC/COMPARISON/GREATER.d.ts +13 -0
- package/dist/DBC/COMPARISON/GREATER_OR_EQUAL.d.ts +13 -0
- package/dist/DBC/COMPARISON/LESS.d.ts +13 -0
- package/dist/DBC/COMPARISON/LESS_OR_EQUAL.d.ts +13 -0
- package/dist/DBC/COMPARISON.d.ts +70 -0
- package/dist/DBC/DEFINED.d.ts +62 -0
- package/dist/DBC/EQ/DIFFERENT.d.ts +26 -0
- package/dist/DBC/EQ.d.ts +70 -0
- package/dist/DBC/HasAttribute.d.ts +72 -0
- package/dist/DBC/IF.d.ts +90 -0
- package/dist/DBC/INSTANCE.d.ts +84 -0
- package/dist/DBC/JSON.OP.d.ts +94 -0
- package/dist/DBC/JSON.Parse.d.ts +69 -0
- package/dist/DBC/OR.d.ts +104 -0
- package/dist/DBC/REGEX.d.ts +96 -0
- package/dist/DBC/TYPE.d.ts +75 -0
- package/dist/DBC/UNDEFINED.d.ts +62 -0
- package/dist/DBC/ZOD.d.ts +72 -0
- package/dist/DBC.d.ts +244 -0
- package/dist/Demo.d.ts +20 -0
- package/dist/bundle.js +2297 -0
- package/docs/assets/highlight.css +22 -22
- package/docs/assets/icons.js +17 -17
- package/docs/assets/main.js +60 -60
- package/docs/assets/style.css +1640 -1640
- package/docs/classes/DBC.DBC.html +98 -98
- package/docs/classes/DBC_AE.AE.html +160 -160
- package/docs/classes/DBC_EQ.EQ.html +131 -131
- package/docs/classes/DBC_GREATER.GREATER.html +139 -139
- package/docs/classes/DBC_INSTANCE.INSTANCE.html +130 -130
- package/docs/classes/DBC_JSON.OP.JSON_OP.html +138 -138
- package/docs/classes/DBC_JSON.Parse.JSON_Parse.html +129 -129
- package/docs/classes/DBC_OR.OR.html +137 -137
- package/docs/classes/DBC_REGEX.REGEX.html +136 -136
- package/docs/classes/DBC_TYPE.TYPE.html +130 -130
- package/docs/classes/Demo.Demo.html +14 -14
- package/docs/hierarchy.html +1 -1
- package/docs/index.html +1 -1
- package/docs/modules/DBC.html +1 -1
- package/docs/modules/DBC_AE.html +1 -1
- package/docs/modules/DBC_EQ.html +1 -1
- package/docs/modules/DBC_GREATER.html +1 -1
- package/docs/modules/DBC_INSTANCE.html +1 -1
- package/docs/modules/DBC_JSON.OP.html +1 -1
- package/docs/modules/DBC_JSON.Parse.html +1 -1
- package/docs/modules/DBC_OR.html +1 -1
- package/docs/modules/DBC_REGEX.html +1 -1
- package/docs/modules/DBC_TYPE.html +1 -1
- package/docs/modules/Demo.html +1 -1
- package/jest.config.js +29 -18
- package/package.json +6 -2
- package/src/DBC/AE.ts +14 -9
- package/src/DBC/COMPARISON/GREATER.ts +2 -2
- package/src/DBC/COMPARISON.ts +159 -136
- package/src/DBC/DEFINED.ts +10 -10
- package/src/DBC/EQ/DIFFERENT.ts +3 -3
- package/src/DBC/EQ.ts +25 -9
- package/src/DBC/HasAttribute.ts +17 -3
- package/src/DBC/IF.ts +63 -19
- package/src/DBC/INSTANCE.ts +29 -14
- package/src/DBC/JSON.OP.ts +18 -3
- package/src/DBC/JSON.Parse.ts +21 -4
- package/src/DBC/OR.ts +12 -7
- package/src/DBC/REGEX.ts +30 -21
- package/src/DBC/TYPE.ts +15 -11
- package/src/DBC/UNDEFINED.ts +7 -10
- package/src/DBC/ZOD.ts +14 -9
- package/src/DBC.ts +165 -69
- package/src/Demo.ts +21 -18
- package/test.drawio +0 -0
- package/tsconfig.json +3 -5
- package/tsconfig.test.json +6 -11
- package/webpack.config.js +1 -1
|
@@ -1,365 +1,367 @@
|
|
|
1
1
|
import "reflect-metadata";
|
|
2
2
|
import { DBC } from "../../src/DBC";
|
|
3
|
-
import {
|
|
4
|
-
import { TYPE } from "../../src/DBC/TYPE";
|
|
5
|
-
import { EQ } from "../../src/DBC/EQ";
|
|
3
|
+
import { AE } from "../../src/DBC/AE";
|
|
6
4
|
import { GREATER } from "../../src/DBC/COMPARISON/GREATER";
|
|
7
5
|
import { GREATER_OR_EQUAL } from "../../src/DBC/COMPARISON/GREATER_OR_EQUAL";
|
|
8
6
|
import { LESS } from "../../src/DBC/COMPARISON/LESS";
|
|
9
7
|
import { LESS_OR_EQUAL } from "../../src/DBC/COMPARISON/LESS_OR_EQUAL";
|
|
8
|
+
import { EQ } from "../../src/DBC/EQ";
|
|
10
9
|
import { DIFFERENT } from "../../src/DBC/EQ/DIFFERENT";
|
|
11
10
|
import { INSTANCE } from "../../src/DBC/INSTANCE";
|
|
12
|
-
import { AE } from "../../src/DBC/AE";
|
|
13
11
|
import { OR } from "../../src/DBC/OR";
|
|
12
|
+
import { REGEX } from "../../src/DBC/REGEX";
|
|
13
|
+
import { TYPE } from "../../src/DBC/TYPE";
|
|
14
14
|
|
|
15
15
|
// Ensure a DBC instance is registered (DBC.ts module-level code does this via DBC.register)
|
|
16
16
|
const dbc: DBC = (window as any).WaXCode?.DBC;
|
|
17
17
|
|
|
18
18
|
describe("Decorator: @PRE (Preconditions)", () => {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
19
|
+
class PreTestSubject {
|
|
20
|
+
@DBC.ParamvalueProvider
|
|
21
|
+
public regexPre(@REGEX.PRE(/^[A-Z]+$/) input: string): string {
|
|
22
|
+
return input;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@DBC.ParamvalueProvider
|
|
26
|
+
public typePre(@TYPE.PRE("string") input: unknown): unknown {
|
|
27
|
+
return input;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@DBC.ParamvalueProvider
|
|
31
|
+
public eqPre(@EQ.PRE("hello") input: string): string {
|
|
32
|
+
return input;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@DBC.ParamvalueProvider
|
|
36
|
+
public greaterPre(@GREATER.PRE(5) input: number): number {
|
|
37
|
+
return input;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@DBC.ParamvalueProvider
|
|
41
|
+
public greaterOrEqualPre(@GREATER_OR_EQUAL.PRE(5) input: number): number {
|
|
42
|
+
return input;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@DBC.ParamvalueProvider
|
|
46
|
+
public lessPre(@LESS.PRE(10) input: number): number {
|
|
47
|
+
return input;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@DBC.ParamvalueProvider
|
|
51
|
+
public lessOrEqualPre(@LESS_OR_EQUAL.PRE(10) input: number): number {
|
|
52
|
+
return input;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@DBC.ParamvalueProvider
|
|
56
|
+
public differentPre(
|
|
57
|
+
@DIFFERENT.PRE("forbidden", undefined) input: string,
|
|
58
|
+
): string {
|
|
59
|
+
return input;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@DBC.ParamvalueProvider
|
|
63
|
+
public instancePre(@INSTANCE.PRE(Date) input: unknown): unknown {
|
|
64
|
+
return input;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@DBC.ParamvalueProvider
|
|
68
|
+
public aePre(@AE.PRE([new TYPE("string")]) input: unknown[]): unknown[] {
|
|
69
|
+
return input;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
@DBC.ParamvalueProvider
|
|
73
|
+
public orPre(@OR.PRE([new EQ("a"), new EQ("b")]) input: string): string {
|
|
74
|
+
return input;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const subject = new PreTestSubject();
|
|
79
|
+
|
|
80
|
+
// REGEX.PRE
|
|
81
|
+
test("REGEX.PRE passes with matching value", () => {
|
|
82
|
+
expect(() => subject.regexPre("ABC")).not.toThrow();
|
|
83
|
+
});
|
|
84
|
+
test("REGEX.PRE throws on non-matching value", () => {
|
|
85
|
+
expect(() => subject.regexPre("abc123")).toThrow();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// TYPE.PRE
|
|
89
|
+
test("TYPE.PRE passes with correct type", () => {
|
|
90
|
+
expect(() => subject.typePre("hello")).not.toThrow();
|
|
91
|
+
});
|
|
92
|
+
test("TYPE.PRE throws with wrong type", () => {
|
|
93
|
+
expect(() => subject.typePre(42)).toThrow();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
// EQ.PRE
|
|
97
|
+
test("EQ.PRE passes with equal value", () => {
|
|
98
|
+
expect(() => subject.eqPre("hello")).not.toThrow();
|
|
99
|
+
});
|
|
100
|
+
test("EQ.PRE throws with non-equal value", () => {
|
|
101
|
+
expect(() => subject.eqPre("world")).toThrow();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// GREATER.PRE
|
|
105
|
+
test("GREATER.PRE passes with value > reference", () => {
|
|
106
|
+
expect(() => subject.greaterPre(10)).not.toThrow();
|
|
107
|
+
});
|
|
108
|
+
test("GREATER.PRE throws with value <= reference", () => {
|
|
109
|
+
expect(() => subject.greaterPre(5)).toThrow();
|
|
110
|
+
});
|
|
111
|
+
test("GREATER.PRE throws with value < reference", () => {
|
|
112
|
+
expect(() => subject.greaterPre(3)).toThrow();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
// GREATER_OR_EQUAL.PRE
|
|
116
|
+
test("GREATER_OR_EQUAL.PRE passes with value >= reference", () => {
|
|
117
|
+
expect(() => subject.greaterOrEqualPre(5)).not.toThrow();
|
|
118
|
+
});
|
|
119
|
+
test("GREATER_OR_EQUAL.PRE passes with value > reference", () => {
|
|
120
|
+
expect(() => subject.greaterOrEqualPre(10)).not.toThrow();
|
|
121
|
+
});
|
|
122
|
+
test("GREATER_OR_EQUAL.PRE throws with value < reference", () => {
|
|
123
|
+
expect(() => subject.greaterOrEqualPre(3)).toThrow();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// LESS.PRE
|
|
127
|
+
test("LESS.PRE passes with value < reference", () => {
|
|
128
|
+
expect(() => subject.lessPre(5)).not.toThrow();
|
|
129
|
+
});
|
|
130
|
+
test("LESS.PRE throws with value >= reference", () => {
|
|
131
|
+
expect(() => subject.lessPre(10)).toThrow();
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// LESS_OR_EQUAL.PRE
|
|
135
|
+
test("LESS_OR_EQUAL.PRE passes with value <= reference", () => {
|
|
136
|
+
expect(() => subject.lessOrEqualPre(10)).not.toThrow();
|
|
137
|
+
});
|
|
138
|
+
test("LESS_OR_EQUAL.PRE throws with value > reference", () => {
|
|
139
|
+
expect(() => subject.lessOrEqualPre(15)).toThrow();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// DIFFERENT.PRE
|
|
143
|
+
test("DIFFERENT.PRE passes with different value", () => {
|
|
144
|
+
expect(() => subject.differentPre("allowed")).not.toThrow();
|
|
145
|
+
});
|
|
146
|
+
test("DIFFERENT.PRE throws with equal value", () => {
|
|
147
|
+
expect(() => subject.differentPre("forbidden")).toThrow();
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// INSTANCE.PRE
|
|
151
|
+
test("INSTANCE.PRE passes with correct instance", () => {
|
|
152
|
+
expect(() => subject.instancePre(new Date())).not.toThrow();
|
|
153
|
+
});
|
|
154
|
+
test("INSTANCE.PRE throws with wrong instance", () => {
|
|
155
|
+
expect(() => subject.instancePre("not a date")).toThrow();
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// AE.PRE
|
|
159
|
+
test("AE.PRE passes with all elements matching", () => {
|
|
160
|
+
expect(() => subject.aePre(["a", "b", "c"])).not.toThrow();
|
|
161
|
+
});
|
|
162
|
+
test("AE.PRE throws when an element does not match", () => {
|
|
163
|
+
expect(() => subject.aePre(["a", 42, "c"])).toThrow();
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// OR.PRE
|
|
167
|
+
test("OR.PRE passes when one contract is satisfied", () => {
|
|
168
|
+
expect(() => subject.orPre("a")).not.toThrow();
|
|
169
|
+
});
|
|
170
|
+
test("OR.PRE throws when no contract is satisfied", () => {
|
|
171
|
+
expect(() => subject.orPre("c")).toThrow();
|
|
172
|
+
});
|
|
171
173
|
});
|
|
172
174
|
|
|
173
175
|
describe("Decorator: @POST (Postconditions)", () => {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
176
|
+
class PostTestSubject {
|
|
177
|
+
@REGEX.POST(/^OK:.*$/)
|
|
178
|
+
@DBC.ParamvalueProvider
|
|
179
|
+
public formatResponse(@TYPE.PRE("string") input: string): string {
|
|
180
|
+
return `OK:${input}`;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
@REGEX.POST(/^OK:.*$/)
|
|
184
|
+
public failingPost(): string {
|
|
185
|
+
return "FAIL";
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
@EQ.POST("hello")
|
|
189
|
+
public eqPost(returnThis: string): string {
|
|
190
|
+
return returnThis;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const subject = new PostTestSubject();
|
|
195
|
+
|
|
196
|
+
test("POST passes when return value matches", () => {
|
|
197
|
+
expect(() => subject.formatResponse("test")).not.toThrow();
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
test("POST throws when return value does not match", () => {
|
|
201
|
+
expect(() => subject.failingPost()).toThrow();
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
test("EQ.POST passes with matching return value", () => {
|
|
205
|
+
expect(() => subject.eqPost("hello")).not.toThrow();
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
test("EQ.POST throws with non-matching return value", () => {
|
|
209
|
+
expect(() => subject.eqPost("world")).toThrow();
|
|
210
|
+
});
|
|
209
211
|
});
|
|
210
212
|
|
|
211
213
|
describe("Decorator: @INVARIANT (Field contracts)", () => {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
214
|
+
test("INVARIANT allows valid initial value", () => {
|
|
215
|
+
expect(() => {
|
|
216
|
+
class InvariantSubject {
|
|
217
|
+
@REGEX.INVARIANT(/^[A-Z]+$/)
|
|
218
|
+
public code = "ABC";
|
|
219
|
+
}
|
|
220
|
+
new InvariantSubject();
|
|
221
|
+
}).not.toThrow();
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test("INVARIANT throws on invalid initial value", () => {
|
|
225
|
+
expect(() => {
|
|
226
|
+
class InvariantSubject {
|
|
227
|
+
@REGEX.INVARIANT(/^[A-Z]+$/)
|
|
228
|
+
public code = "abc123";
|
|
229
|
+
}
|
|
230
|
+
new InvariantSubject();
|
|
231
|
+
}).toThrow();
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
test("INVARIANT throws on invalid reassignment", () => {
|
|
235
|
+
class InvariantSubject {
|
|
236
|
+
@REGEX.INVARIANT(/^[A-Z]+$/)
|
|
237
|
+
public code = "ABC";
|
|
238
|
+
}
|
|
239
|
+
const obj = new InvariantSubject();
|
|
240
|
+
expect(() => {
|
|
241
|
+
obj.code = "invalid!";
|
|
242
|
+
}).toThrow();
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
test("INVARIANT allows valid reassignment", () => {
|
|
246
|
+
class InvariantSubject {
|
|
247
|
+
@REGEX.INVARIANT(/^[A-Z]+$/)
|
|
248
|
+
public code = "ABC";
|
|
249
|
+
}
|
|
250
|
+
const obj = new InvariantSubject();
|
|
251
|
+
expect(() => {
|
|
252
|
+
obj.code = "XYZ";
|
|
253
|
+
}).not.toThrow();
|
|
254
|
+
});
|
|
253
255
|
});
|
|
254
256
|
|
|
255
257
|
describe("Decorator: @ParamvalueProvider", () => {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
258
|
+
test("ParamvalueProvider passes multiple parameter contracts", () => {
|
|
259
|
+
class MultiParam {
|
|
260
|
+
@DBC.ParamvalueProvider
|
|
261
|
+
public method(
|
|
262
|
+
@TYPE.PRE("string") a: string,
|
|
263
|
+
@TYPE.PRE("number") b: number,
|
|
264
|
+
): string {
|
|
265
|
+
return `${a}:${b}`;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
const obj = new MultiParam();
|
|
269
|
+
expect(() => obj.method("hello", 42)).not.toThrow();
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
test("ParamvalueProvider catches second parameter violation", () => {
|
|
273
|
+
class MultiParam {
|
|
274
|
+
@DBC.ParamvalueProvider
|
|
275
|
+
public method(
|
|
276
|
+
@TYPE.PRE("string") a: string,
|
|
277
|
+
@TYPE.PRE("number") b: number,
|
|
278
|
+
): string {
|
|
279
|
+
return `${a}:${b}`;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
const obj = new MultiParam();
|
|
283
|
+
expect(() => obj.method("hello", "not a number" as any)).toThrow();
|
|
284
|
+
});
|
|
283
285
|
});
|
|
284
286
|
|
|
285
287
|
describe("DBC infringement settings", () => {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
288
|
+
class InfringementTest {
|
|
289
|
+
@DBC.ParamvalueProvider
|
|
290
|
+
public method(@TYPE.PRE("string") input: unknown): unknown {
|
|
291
|
+
return input;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
test("Violations throw DBC.Infringement by default", () => {
|
|
296
|
+
const obj = new InfringementTest();
|
|
297
|
+
expect(() => obj.method(42)).toThrow(/XDBC Infringement/);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
test("Error message includes class name, method name, and parameter info", () => {
|
|
301
|
+
const obj = new InfringementTest();
|
|
302
|
+
try {
|
|
303
|
+
obj.method(42);
|
|
304
|
+
fail("Should have thrown");
|
|
305
|
+
} catch (e: any) {
|
|
306
|
+
expect(e.message).toContain("InfringementTest");
|
|
307
|
+
expect(e.message).toContain("method");
|
|
308
|
+
expect(e.message).toContain("1st parameter");
|
|
309
|
+
}
|
|
310
|
+
});
|
|
309
311
|
});
|
|
310
312
|
|
|
311
313
|
describe("DBC.register()", () => {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
314
|
+
test("registers an instance at the default path", () => {
|
|
315
|
+
const custom = new DBC();
|
|
316
|
+
DBC.register(custom);
|
|
317
|
+
expect((window as any).WaXCode.DBC).toBe(custom);
|
|
318
|
+
// Restore original
|
|
319
|
+
DBC.register(dbc);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
test("registers an instance at a custom path", () => {
|
|
323
|
+
const custom = new DBC();
|
|
324
|
+
DBC.register(custom, "TestVendor.DBC");
|
|
325
|
+
expect((window as any).TestVendor.DBC).toBe(custom);
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
test("constructor does not auto-mount to globalThis", () => {
|
|
329
|
+
const original = (window as any).WaXCode.DBC;
|
|
330
|
+
const orphan = new DBC();
|
|
331
|
+
// Constructor should NOT have replaced the registered instance
|
|
332
|
+
expect((window as any).WaXCode.DBC).toBe(original);
|
|
333
|
+
expect(orphan).not.toBe(original);
|
|
334
|
+
});
|
|
333
335
|
});
|
|
334
336
|
|
|
335
337
|
describe("DBC.isolated()", () => {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
338
|
+
test("provides a temporary DBC instance and restores the original", () => {
|
|
339
|
+
const original = (window as any).WaXCode.DBC;
|
|
340
|
+
let isolatedInstance: DBC | undefined;
|
|
341
|
+
DBC.isolated((tempDbc) => {
|
|
342
|
+
isolatedInstance = tempDbc;
|
|
343
|
+
expect(tempDbc).not.toBe(original);
|
|
344
|
+
expect((window as any).WaXCode.DBC).toBe(tempDbc);
|
|
345
|
+
});
|
|
346
|
+
// After isolated() returns, the original is restored
|
|
347
|
+
expect((window as any).WaXCode.DBC).toBe(original);
|
|
348
|
+
expect(isolatedInstance).toBeDefined();
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
test("restores original even if callback throws", () => {
|
|
352
|
+
const original = (window as any).WaXCode.DBC;
|
|
353
|
+
expect(() => {
|
|
354
|
+
DBC.isolated(() => {
|
|
355
|
+
throw new Error("test error");
|
|
356
|
+
});
|
|
357
|
+
}).toThrow("test error");
|
|
358
|
+
expect((window as any).WaXCode.DBC).toBe(original);
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
test("isolated instance has independent settings", () => {
|
|
362
|
+
DBC.isolated((tempDbc) => {
|
|
363
|
+
tempDbc.executionSettings.checkPreconditions = false;
|
|
364
|
+
expect(dbc.executionSettings.checkPreconditions).toBe(true);
|
|
365
|
+
});
|
|
366
|
+
});
|
|
365
367
|
});
|