@malloydata/malloy-tests 0.0.140-dev240409200123 → 0.0.140
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/package.json
CHANGED
|
@@ -21,13 +21,13 @@
|
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@jest/globals": "^29.4.3",
|
|
24
|
-
"@malloydata/db-bigquery": "^0.0.140
|
|
25
|
-
"@malloydata/db-duckdb": "^0.0.140
|
|
26
|
-
"@malloydata/db-postgres": "^0.0.140
|
|
27
|
-
"@malloydata/db-snowflake": "^0.0.140
|
|
28
|
-
"@malloydata/db-trino": "^0.0.140
|
|
29
|
-
"@malloydata/malloy": "^0.0.140
|
|
30
|
-
"@malloydata/render": "^0.0.140
|
|
24
|
+
"@malloydata/db-bigquery": "^0.0.140",
|
|
25
|
+
"@malloydata/db-duckdb": "^0.0.140",
|
|
26
|
+
"@malloydata/db-postgres": "^0.0.140",
|
|
27
|
+
"@malloydata/db-snowflake": "^0.0.140",
|
|
28
|
+
"@malloydata/db-trino": "^0.0.140",
|
|
29
|
+
"@malloydata/malloy": "^0.0.140",
|
|
30
|
+
"@malloydata/render": "^0.0.140",
|
|
31
31
|
"jsdom": "^22.1.0",
|
|
32
32
|
"luxon": "^2.4.0",
|
|
33
33
|
"madge": "^6.0.0"
|
|
@@ -36,5 +36,5 @@
|
|
|
36
36
|
"@types/jsdom": "^21.1.1",
|
|
37
37
|
"@types/luxon": "^2.4.0"
|
|
38
38
|
},
|
|
39
|
-
"version": "0.0.140
|
|
39
|
+
"version": "0.0.140"
|
|
40
40
|
}
|
|
@@ -150,7 +150,8 @@ describe.each(runtimes.runtimeList)('%s', (databaseName, runtime) => {
|
|
|
150
150
|
`).malloyResultMatches(expressionModel, {
|
|
151
151
|
'o.by_state.state': 'TX',
|
|
152
152
|
'o.by_state.airport_count': 1845,
|
|
153
|
-
|
|
153
|
+
'o.airport_count': 11146,
|
|
154
|
+
'o.inline/inline_sum': 11146,
|
|
154
155
|
'airport_count': 19701,
|
|
155
156
|
});
|
|
156
157
|
});
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
LogMessage,
|
|
32
32
|
SingleConnectionRuntime,
|
|
33
33
|
} from '@malloydata/malloy';
|
|
34
|
+
import {inspect} from 'util';
|
|
34
35
|
|
|
35
36
|
type ExpectedResultRow = Record<string, unknown>;
|
|
36
37
|
type ExpectedResult = ExpectedResultRow | ExpectedResultRow[];
|
|
@@ -50,9 +51,18 @@ declare global {
|
|
|
50
51
|
* await expect('query').malloyResultMatches(runtime, {colName: colValue});
|
|
51
52
|
* await expect('query').malloyResultMatches(runtime, [{colName: colValue}]);
|
|
52
53
|
*
|
|
53
|
-
* * If "colName" has a dot in it, it is assumed to be a reference to a value in a nest
|
|
54
54
|
* * If you use an array, the number of rows in the result must match the rows in the match
|
|
55
55
|
* * The empty match {} accepts ANY data, but will errror if there is not a row
|
|
56
|
+
* * If the query is tagged with # test.debug then the test will fail and the result will be printed
|
|
57
|
+
* * If the query is tagged with # test.verbose then the result will be printed only if the test fails
|
|
58
|
+
* * A match key of nestName.colName expects nestName to be a query which returns multiple rows, it will match
|
|
59
|
+
* fields from the first row of the rows of nestName
|
|
60
|
+
* * A match key of nestName/colName expects nestName to be a record/struct type
|
|
61
|
+
*
|
|
62
|
+
* In addition, the query is checked for the following tags
|
|
63
|
+
*
|
|
64
|
+
* * test.verbose -- If the test fails, also pretty-print the result data
|
|
65
|
+
* * test.debug -- Force test failure, and the result data will be printed
|
|
56
66
|
*
|
|
57
67
|
* @param querySrc Malloy source, last query in source will be run
|
|
58
68
|
* @param runtime Database connection runtime OR Model ( for the call to loadQuery )
|
|
@@ -118,6 +128,8 @@ expect.extend({
|
|
|
118
128
|
};
|
|
119
129
|
}
|
|
120
130
|
|
|
131
|
+
const queryTags = (await query.getPreparedQuery()).tagParse().tag;
|
|
132
|
+
const queryTestTag = queryTags.tag('test');
|
|
121
133
|
let result: Result;
|
|
122
134
|
try {
|
|
123
135
|
result = await query.run();
|
|
@@ -139,34 +151,36 @@ expect.extend({
|
|
|
139
151
|
return {pass: false, message: () => failMsg};
|
|
140
152
|
}
|
|
141
153
|
|
|
142
|
-
const debug = querySrc.indexOf('--debug') >= 0;
|
|
143
154
|
const allRows = Array.isArray(shouldEqual) ? shouldEqual : [shouldEqual];
|
|
144
|
-
let i = 0;
|
|
145
155
|
const fails: string[] = [];
|
|
146
|
-
|
|
147
|
-
if (debug) {
|
|
148
|
-
fails.push(
|
|
149
|
-
`Debug: Result Data: ${JSON.stringify(result.data.toObject())}`
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
156
|
const gotRows = result.data.toObject().length;
|
|
157
|
+
|
|
154
158
|
if (Array.isArray(shouldEqual)) {
|
|
155
159
|
if (gotRows !== allRows.length) {
|
|
156
160
|
fails.push(`Expected result.rows=${allRows.length} Got: ${gotRows}`);
|
|
157
161
|
}
|
|
158
162
|
}
|
|
163
|
+
let matchRow = 0;
|
|
159
164
|
for (const expected of allRows) {
|
|
160
165
|
for (const [name, value] of Object.entries(expected)) {
|
|
161
166
|
const pExpect = JSON.stringify(value);
|
|
162
|
-
const row = allRows.length > 1 ? `[${
|
|
167
|
+
const row = allRows.length > 1 ? `[${matchRow}]` : '';
|
|
163
168
|
const expected = `Expected ${row}{${name}: ${pExpect}}`;
|
|
164
169
|
try {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
+
// the internet taught me this, use lookahead/behind to preserve delimiters
|
|
171
|
+
// but we are splitting on / and .
|
|
172
|
+
const nestParse = name.split(/(?=[./])|(?<=[./])/g);
|
|
173
|
+
|
|
174
|
+
const resultPath = [matchRow, nestParse[0]];
|
|
175
|
+
for (
|
|
176
|
+
let pathCursor = 1;
|
|
177
|
+
pathCursor < nestParse.length;
|
|
178
|
+
pathCursor += 2
|
|
179
|
+
) {
|
|
180
|
+
if (nestParse[pathCursor] === '.') {
|
|
181
|
+
resultPath.push(0);
|
|
182
|
+
}
|
|
183
|
+
resultPath.push(nestParse[pathCursor + 1]);
|
|
170
184
|
}
|
|
171
185
|
const got = result.data.path(...resultPath).value;
|
|
172
186
|
const pGot = JSON.stringify(got);
|
|
@@ -181,10 +195,19 @@ expect.extend({
|
|
|
181
195
|
fails.push(`${expected} Error: ${e.message}`);
|
|
182
196
|
}
|
|
183
197
|
}
|
|
184
|
-
|
|
198
|
+
matchRow += 1;
|
|
199
|
+
}
|
|
200
|
+
const failedTest = fails.length > 0;
|
|
201
|
+
const debugFail = queryTestTag?.has('debug');
|
|
202
|
+
if (debugFail || (failedTest && queryTestTag?.has('verbose'))) {
|
|
203
|
+
fails.unshift(`Result Data: ${humanReadable(result.data.toObject())}\n`);
|
|
185
204
|
}
|
|
186
|
-
|
|
205
|
+
|
|
206
|
+
if (fails.length > 0) {
|
|
187
207
|
const fromSQL = ' ' + (await query.getSQL()).split('\n').join('\n ');
|
|
208
|
+
if (debugFail && !failedTest) {
|
|
209
|
+
fails.push('\nTest forced failure (# test.debug)');
|
|
210
|
+
}
|
|
188
211
|
const failMsg = `SQL Generated:\n${fromSQL}\n${fails.join('\n')}`;
|
|
189
212
|
return {pass: false, message: () => failMsg};
|
|
190
213
|
}
|
|
@@ -213,3 +236,7 @@ function errorLogToString(src: string, msgs: LogMessage[]) {
|
|
|
213
236
|
}
|
|
214
237
|
return lovely;
|
|
215
238
|
}
|
|
239
|
+
|
|
240
|
+
function humanReadable(thing: unknown): string {
|
|
241
|
+
return inspect(thing, {breakLength: 72, depth: Infinity});
|
|
242
|
+
}
|