@voxgig/sdkgen 0.36.0 → 0.38.1
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/bin/voxgig-sdkgen +1 -1
- package/dist/cmp/Main.js +0 -12
- package/dist/cmp/Main.js.map +1 -1
- package/package.json +2 -3
- package/project/.sdk/model/feature/log.jsonic +1 -1
- package/project/.sdk/model/target/js.jsonic +1 -1
- package/project/.sdk/model/target/py.jsonic +1 -1
- package/project/.sdk/model/target/ts.jsonic +2 -2
- package/project/.sdk/src/cmp/go/Config_go.ts +6 -2
- package/project/.sdk/src/cmp/js/EntityBase_js.ts +34 -0
- package/project/.sdk/src/cmp/js/Main_js.ts +10 -0
- package/project/.sdk/src/cmp/js/ReadmeExplanation_js.ts +33 -0
- package/project/.sdk/src/cmp/js/ReadmeHowto_js.ts +123 -0
- package/project/.sdk/src/cmp/js/ReadmeModel_js.ts +152 -0
- package/project/.sdk/src/cmp/js/ReadmeTopHowto_js.ts +25 -0
- package/project/.sdk/src/cmp/js/ReadmeTopQuick_js.ts +65 -0
- package/project/.sdk/src/cmp/js/ReadmeTopTest_js.ts +36 -0
- package/project/.sdk/src/cmp/js/TestDirect_js.ts +53 -5
- package/project/.sdk/src/cmp/js/TestEntity_js.ts +114 -20
- package/project/.sdk/src/cmp/js/fragment/Entity.fragment.js +7 -139
- package/project/.sdk/src/cmp/js/fragment/EntityBase.fragment.js +149 -0
- package/project/.sdk/src/cmp/js/fragment/EntityCreateOp.fragment.js +6 -10
- package/project/.sdk/src/cmp/js/fragment/EntityListOp.fragment.js +6 -10
- package/project/.sdk/src/cmp/js/fragment/EntityLoadOp.fragment.js +7 -11
- package/project/.sdk/src/cmp/js/fragment/EntityRemoveOp.fragment.js +7 -11
- package/project/.sdk/src/cmp/js/fragment/EntityUpdateOp.fragment.js +7 -11
- package/project/.sdk/src/cmp/js/fragment/Main.fragment.js +2 -0
- package/project/.sdk/src/cmp/js/fragment/SdkError.fragment.js +0 -2
- package/project/.sdk/src/cmp/lua/Config_lua.ts +6 -2
- package/project/.sdk/src/cmp/lua/TestEntity_lua.ts +3 -1
- package/project/.sdk/src/cmp/php/Config_php.ts +6 -2
- package/project/.sdk/src/cmp/php/Package_php.ts +2 -2
- package/project/.sdk/src/cmp/php/TestDirect_php.ts +2 -2
- package/project/.sdk/src/cmp/php/TestEntity_php.ts +10 -15
- package/project/.sdk/src/cmp/py/Config_py.ts +6 -2
- package/project/.sdk/src/cmp/py/Package_py.ts +1 -1
- package/project/.sdk/src/cmp/py/TestEntity_py.ts +3 -1
- package/project/.sdk/src/cmp/rb/Config_rb.ts +6 -2
- package/project/.sdk/src/cmp/ts/Main_ts.ts +7 -0
- package/project/.sdk/tm/go/feature/log_feature.go +1 -1
- package/project/.sdk/tm/go/test/runner_test.go +16 -2
- package/project/.sdk/tm/js/src/Context.js +142 -0
- package/project/.sdk/tm/js/src/Control.js +16 -0
- package/project/.sdk/tm/js/src/Operation.js +19 -0
- package/project/.sdk/tm/js/src/Point.js +24 -0
- package/project/.sdk/tm/js/src/README.md +1 -0
- package/project/.sdk/tm/js/src/Response.js +19 -0
- package/project/.sdk/tm/js/src/Result.js +21 -0
- package/project/.sdk/tm/js/src/Spec.js +26 -0
- package/project/.sdk/tm/js/src/feature/README.md +1 -0
- package/project/.sdk/tm/js/src/feature/base/BaseFeature.js +45 -0
- package/project/.sdk/tm/js/src/feature/log/LogFeature.js +46 -47
- package/project/.sdk/tm/js/src/feature/test/TestFeature.js +207 -0
- package/project/.sdk/tm/js/src/types.js +22 -0
- package/project/.sdk/tm/js/src/utility/CleanUtility.js +31 -0
- package/project/.sdk/tm/js/src/utility/DoneUtility.js +11 -4
- package/project/.sdk/tm/js/src/utility/FeatureAddUtility.js +42 -0
- package/project/.sdk/tm/js/src/utility/FeatureHookUtility.js +25 -0
- package/project/.sdk/tm/js/src/utility/FeatureInitUtility.js +11 -0
- package/project/.sdk/tm/js/src/utility/FetcherUtility.js +28 -0
- package/project/.sdk/tm/js/src/utility/MakeContextUtility.js +11 -0
- package/project/.sdk/tm/js/src/utility/MakeErrorUtility.js +55 -0
- package/project/.sdk/tm/js/src/utility/MakeFetchDefUtility.js +44 -0
- package/project/.sdk/tm/js/src/utility/MakeOptionsUtility.js +93 -0
- package/project/.sdk/tm/js/src/utility/MakePointUtility.js +77 -0
- package/project/.sdk/tm/js/src/utility/MakeRequestUtility.js +63 -0
- package/project/.sdk/tm/js/src/utility/MakeResponseUtility.js +55 -0
- package/project/.sdk/tm/js/src/utility/MakeResultUtility.js +54 -0
- package/project/.sdk/tm/js/src/utility/MakeSpecUtility.js +58 -0
- package/project/.sdk/tm/js/src/utility/MakeUrlUtility.js +40 -0
- package/project/.sdk/tm/js/src/utility/ParamUtility.js +61 -0
- package/project/.sdk/tm/js/src/utility/PrepareAuthUtility.js +41 -0
- package/project/.sdk/tm/js/src/utility/PrepareBodyUtility.js +25 -0
- package/project/.sdk/tm/js/src/utility/PrepareHeadersUtility.js +18 -0
- package/project/.sdk/tm/js/src/utility/{MethodUtility.js → PrepareMethodUtility.js} +7 -7
- package/project/.sdk/tm/js/src/utility/PrepareParamsUtility.js +25 -0
- package/project/.sdk/tm/js/src/utility/PreparePathUtility.js +13 -0
- package/project/.sdk/tm/js/src/utility/PrepareQueryUtility.js +26 -0
- package/project/.sdk/tm/js/src/utility/README.md +1 -0
- package/project/.sdk/tm/js/src/utility/ResultBasicUtility.js +34 -0
- package/project/.sdk/tm/js/src/utility/ResultBodyUtility.js +18 -0
- package/project/.sdk/tm/js/src/utility/ResultHeadersUtility.js +22 -0
- package/project/.sdk/tm/js/src/utility/StructUtility.js +2219 -1078
- package/project/.sdk/tm/js/src/utility/TransformRequestUtility.js +28 -0
- package/project/.sdk/tm/js/src/utility/TransformResponseUtility.js +31 -0
- package/project/.sdk/tm/js/src/utility/Utility.js +61 -61
- package/project/.sdk/tm/js/test/README.md +1 -0
- package/project/.sdk/tm/js/test/exists.test.js +16 -0
- package/project/.sdk/tm/js/test/runner.js +323 -107
- package/project/.sdk/tm/js/test/utility/Custom.test.js +41 -63
- package/project/.sdk/tm/js/test/utility/PrimaryUtility.test.js +390 -116
- package/project/.sdk/tm/js/test/utility/StructUtility.test.js +728 -175
- package/project/.sdk/tm/js/test/utility/index.js +9 -0
- package/project/.sdk/tm/js/test/utility.js +72 -0
- package/project/.sdk/tm/lua/test/primary_utility_test.lua +1213 -0
- package/project/.sdk/tm/lua/test/runner.lua +2 -2
- package/project/.sdk/tm/lua/test/struct_runner.lua +602 -0
- package/project/.sdk/tm/lua/test/struct_utility_test.lua +959 -0
- package/project/.sdk/tm/lua/utility/struct/struct.lua +10 -0
- package/project/.sdk/tm/php/feature/TestFeature.php +59 -96
- package/project/.sdk/tm/php/test/PrimaryUtilityTest.php +1309 -0
- package/project/.sdk/tm/php/test/Runner.php +24 -1
- package/project/.sdk/tm/php/test/StructRunner.php +275 -0
- package/project/.sdk/tm/php/test/StructUtilityTest.php +1336 -0
- package/project/.sdk/tm/php/utility/Fetcher.php +6 -2
- package/project/.sdk/tm/php/utility/MakeOptions.php +5 -1
- package/project/.sdk/tm/php/utility/MakeResult.php +3 -0
- package/project/.sdk/tm/php/utility/Param.php +9 -7
- package/project/.sdk/tm/php/utility/struct/Struct.php +312 -208
- package/project/.sdk/tm/py/test/runner.py +13 -0
- package/project/.sdk/tm/py/test/struct_runner.py +411 -0
- package/project/.sdk/tm/py/test/test_primary_utility.py +1101 -0
- package/project/.sdk/tm/py/test/test_struct_utility.py +751 -0
- package/project/.sdk/tm/rb/test/primary_utility_test.rb +1083 -0
- package/project/.sdk/tm/rb/test/runner.rb +5 -0
- package/project/.sdk/tm/rb/test/struct_runner.rb +309 -0
- package/project/.sdk/tm/rb/test/struct_utility_test.rb +670 -0
- package/src/cmp/Main.ts +1 -16
- package/project/.sdk/src/cmp/js/Quick_js.ts +0 -78
- package/project/.sdk/src/cmp/js/TestAcceptEntity_js.ts +0 -13
- package/project/.sdk/src/cmp/js/TestAccept_js.ts +0 -18
- package/project/.sdk/tm/js/src/utility/AuthUtility.js +0 -21
- package/project/.sdk/tm/js/src/utility/BodyUtility.js +0 -29
- package/project/.sdk/tm/js/src/utility/ErrorUtility.js +0 -33
- package/project/.sdk/tm/js/src/utility/FindparamUtility.js +0 -31
- package/project/.sdk/tm/js/src/utility/FullurlUtility.js +0 -39
- package/project/.sdk/tm/js/src/utility/HeadersUtility.js +0 -13
- package/project/.sdk/tm/js/src/utility/JoinurlUtility.js +0 -14
- package/project/.sdk/tm/js/src/utility/OperatorUtility.js +0 -44
- package/project/.sdk/tm/js/src/utility/OptionsUtility.js +0 -54
- package/project/.sdk/tm/js/src/utility/ParamsUtility.js +0 -21
- package/project/.sdk/tm/js/src/utility/QueryUtility.js +0 -21
- package/project/.sdk/tm/js/src/utility/ReqformUtility.js +0 -32
- package/project/.sdk/tm/js/src/utility/RequestUtility.js +0 -48
- package/project/.sdk/tm/js/src/utility/ResbasicUtility.js +0 -27
- package/project/.sdk/tm/js/src/utility/ResbodyUtility.js +0 -15
- package/project/.sdk/tm/js/src/utility/ResformUtility.js +0 -34
- package/project/.sdk/tm/js/src/utility/ResheadersUtility.js +0 -19
- package/project/.sdk/tm/js/src/utility/ResponseUtility.js +0 -37
- package/project/.sdk/tm/js/src/utility/ResultUtility.js +0 -28
- package/project/.sdk/tm/js/src/utility/SpecUtility.js +0 -35
|
@@ -75,3 +75,16 @@ class ProjectNameTestRunner:
|
|
|
75
75
|
else:
|
|
76
76
|
out.append(item)
|
|
77
77
|
return out
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# Module-level convenience functions.
|
|
81
|
+
def load_env_local():
|
|
82
|
+
ProjectNameTestRunner.load_env_local()
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def env_override(m):
|
|
86
|
+
return ProjectNameTestRunner.env_override(m)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def entity_list_to_data(lst):
|
|
90
|
+
return ProjectNameTestRunner.entity_list_to_data(lst)
|
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
# Vendored from voxgig/struct/py
|
|
2
|
+
# Test runner that uses the test model in build/test.
|
|
3
|
+
|
|
4
|
+
import os
|
|
5
|
+
import json
|
|
6
|
+
import re
|
|
7
|
+
from typing import Any, Dict, List, Callable, TypedDict, Optional, Union
|
|
8
|
+
|
|
9
|
+
from utility.voxgig_struct import voxgig_struct as vs
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
NULLMARK = '__NULL__' # Value is JSON null
|
|
13
|
+
UNDEFMARK = '__UNDEF__' # Value is not present (thus, undefined)
|
|
14
|
+
EXISTSMARK = '__EXISTS__' # Value exists (not undefined).
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class RunPack(TypedDict):
|
|
18
|
+
spec: Dict[str, Any]
|
|
19
|
+
runset: Callable
|
|
20
|
+
runsetflags: Callable
|
|
21
|
+
subject: Callable
|
|
22
|
+
client: Optional[Any]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def makeRunner(testfile: str, client: Any):
|
|
26
|
+
|
|
27
|
+
def runner(
|
|
28
|
+
name: str,
|
|
29
|
+
store: Any = None,
|
|
30
|
+
) -> RunPack:
|
|
31
|
+
store = store or {}
|
|
32
|
+
|
|
33
|
+
utility = client.utility()
|
|
34
|
+
structUtils = utility.struct
|
|
35
|
+
|
|
36
|
+
spec = resolve_spec(name, testfile)
|
|
37
|
+
clients = resolve_clients(client, spec, store, structUtils)
|
|
38
|
+
subject = resolve_subject(name, utility)
|
|
39
|
+
|
|
40
|
+
def runsetflags(testspec, flags, testsubject):
|
|
41
|
+
nonlocal subject, clients
|
|
42
|
+
|
|
43
|
+
subject = testsubject or subject
|
|
44
|
+
flags = resolve_flags(flags)
|
|
45
|
+
testspecmap = fixJSON(testspec, flags)
|
|
46
|
+
testset = testspecmap['set']
|
|
47
|
+
|
|
48
|
+
for entry in testset:
|
|
49
|
+
try:
|
|
50
|
+
entry = resolve_entry(entry, flags)
|
|
51
|
+
|
|
52
|
+
testpack = resolve_testpack(name, entry, subject, client, clients)
|
|
53
|
+
args = resolve_args(entry, testpack, utility, structUtils)
|
|
54
|
+
|
|
55
|
+
# Execute the test function
|
|
56
|
+
res = testpack["subject"](*args)
|
|
57
|
+
res = fixJSON(res, flags)
|
|
58
|
+
entry['res'] = res
|
|
59
|
+
check_result(entry, args, res, structUtils)
|
|
60
|
+
|
|
61
|
+
except Exception as err:
|
|
62
|
+
handle_error(entry, err, structUtils)
|
|
63
|
+
|
|
64
|
+
def runset(testspec, testsubject):
|
|
65
|
+
return runsetflags(testspec, {}, testsubject)
|
|
66
|
+
|
|
67
|
+
runpack = {
|
|
68
|
+
"spec": spec,
|
|
69
|
+
"runset": runset,
|
|
70
|
+
"runsetflags": runsetflags,
|
|
71
|
+
"subject": subject,
|
|
72
|
+
"client": client
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return runpack
|
|
76
|
+
|
|
77
|
+
return runner
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def resolve_spec(name: str, testfile: str) -> Dict[str, Any]:
|
|
81
|
+
with open(testfile, 'r', encoding='utf-8') as f:
|
|
82
|
+
alltests = json.load(f)
|
|
83
|
+
|
|
84
|
+
if 'primary' in alltests and name in alltests['primary']:
|
|
85
|
+
spec = alltests['primary'][name]
|
|
86
|
+
elif name in alltests:
|
|
87
|
+
spec = alltests[name]
|
|
88
|
+
else:
|
|
89
|
+
spec = alltests
|
|
90
|
+
|
|
91
|
+
return spec
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def resolve_clients(client: Any, spec: Dict[str, Any], store: Any, structUtils: Any) -> Dict[str, Any]:
|
|
95
|
+
clients = {}
|
|
96
|
+
if 'DEF' in spec and 'client' in spec['DEF']:
|
|
97
|
+
for client_name, client_val in structUtils.items(spec['DEF']['client']):
|
|
98
|
+
# Get client options
|
|
99
|
+
client_opts = client_val.get('test', {}).get('options', {})
|
|
100
|
+
|
|
101
|
+
# Apply store injections if needed
|
|
102
|
+
if isinstance(store, dict) and structUtils.inject:
|
|
103
|
+
structUtils.inject(client_opts, store)
|
|
104
|
+
|
|
105
|
+
# Create and store the client using the passed client object
|
|
106
|
+
clients[client_name] = client.tester(client_opts)
|
|
107
|
+
|
|
108
|
+
return clients
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def resolve_subject(name: str, container: Any):
|
|
112
|
+
return getattr(container, name, getattr(container.struct, name, None))
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def check_result(entry, args, res, structUtils):
|
|
116
|
+
matched = False
|
|
117
|
+
|
|
118
|
+
if 'match' in entry:
|
|
119
|
+
result = {'in': entry.get('in'), 'args': args, 'out': entry.get('res'), 'ctx': entry.get('ctx')}
|
|
120
|
+
match(
|
|
121
|
+
entry['match'],
|
|
122
|
+
result,
|
|
123
|
+
structUtils
|
|
124
|
+
)
|
|
125
|
+
matched = True
|
|
126
|
+
|
|
127
|
+
out = entry.get('out')
|
|
128
|
+
|
|
129
|
+
if out == res:
|
|
130
|
+
return
|
|
131
|
+
|
|
132
|
+
# NOTE: allow match with no out
|
|
133
|
+
if matched and (NULLMARK == out or out is None):
|
|
134
|
+
return
|
|
135
|
+
|
|
136
|
+
try:
|
|
137
|
+
cleaned_res = json.loads(json.dumps(res, default=str))
|
|
138
|
+
except:
|
|
139
|
+
# If can't be serialized just use the original
|
|
140
|
+
cleaned_res = res
|
|
141
|
+
|
|
142
|
+
# Compare result with expected output using deep equality
|
|
143
|
+
if cleaned_res != out:
|
|
144
|
+
raise AssertionError(
|
|
145
|
+
f"Expected: {out}, got: {cleaned_res}\n"
|
|
146
|
+
f"Test: {entry.get('name', 'unknown')}"
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def handle_error(entry, err, structUtils):
|
|
151
|
+
# Record the error in the entry
|
|
152
|
+
entry['thrown'] = err
|
|
153
|
+
entry_err = entry.get('err')
|
|
154
|
+
|
|
155
|
+
# If the test expects an error
|
|
156
|
+
if entry_err is not None:
|
|
157
|
+
# If it's any error or matches expected pattern
|
|
158
|
+
if entry_err is True or matchval(entry_err, str(err), structUtils):
|
|
159
|
+
# If we also need to match error details
|
|
160
|
+
if 'match' in entry:
|
|
161
|
+
match(
|
|
162
|
+
entry['match'],
|
|
163
|
+
{
|
|
164
|
+
'in': entry.get('in'),
|
|
165
|
+
'out': entry.get('res'),
|
|
166
|
+
'ctx': entry.get('ctx'),
|
|
167
|
+
'err': fixJSON(err)
|
|
168
|
+
},
|
|
169
|
+
structUtils
|
|
170
|
+
)
|
|
171
|
+
# Error was expected, continue
|
|
172
|
+
return True
|
|
173
|
+
|
|
174
|
+
# Expected error didn't match the actual error
|
|
175
|
+
raise AssertionError(
|
|
176
|
+
f"ERROR MATCH: [{structUtils.stringify(entry_err)}] <=> [{str(err)}]"
|
|
177
|
+
)
|
|
178
|
+
# If the test doesn't expect an error
|
|
179
|
+
elif isinstance(err, AssertionError):
|
|
180
|
+
# Propagate assertion errors with added context
|
|
181
|
+
raise AssertionError(
|
|
182
|
+
f"{str(err)}\nTest: {entry.get('name', 'unknown')}"
|
|
183
|
+
)
|
|
184
|
+
else:
|
|
185
|
+
# For other errors, include the full error stack
|
|
186
|
+
import traceback
|
|
187
|
+
raise AssertionError(
|
|
188
|
+
f"{traceback.format_exc()}\nTest: {entry.get('name', 'unknown')}"
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def resolve_testpack(
|
|
193
|
+
name,
|
|
194
|
+
entry,
|
|
195
|
+
subject,
|
|
196
|
+
client,
|
|
197
|
+
clients,
|
|
198
|
+
):
|
|
199
|
+
testpack = {
|
|
200
|
+
"client": client,
|
|
201
|
+
"subject": subject,
|
|
202
|
+
"utility": client.utility(),
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if 'client' in entry:
|
|
206
|
+
testpack["client"] = clients[entry['client']]
|
|
207
|
+
testpack["utility"] = testpack["client"].utility()
|
|
208
|
+
testpack["subject"] = resolve_subject(name, testpack["utility"])
|
|
209
|
+
|
|
210
|
+
return testpack
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def resolve_args(entry, testpack, utility, structUtils):
|
|
214
|
+
args = []
|
|
215
|
+
|
|
216
|
+
if 'ctx' in entry:
|
|
217
|
+
args = [entry['ctx']]
|
|
218
|
+
elif 'args' in entry:
|
|
219
|
+
args = entry['args']
|
|
220
|
+
elif 'in' in entry:
|
|
221
|
+
args = [structUtils.clone(entry['in'])]
|
|
222
|
+
|
|
223
|
+
# If we have context or arguments, we might need to patch them
|
|
224
|
+
if ('ctx' in entry or 'args' in entry) and len(args) > 0:
|
|
225
|
+
first = args[0]
|
|
226
|
+
if structUtils.ismap(first):
|
|
227
|
+
# Clone the argument
|
|
228
|
+
first = structUtils.clone(first)
|
|
229
|
+
first = utility.contextify(first)
|
|
230
|
+
args[0] = first
|
|
231
|
+
entry['ctx'] = first
|
|
232
|
+
first.client = testpack["client"]
|
|
233
|
+
first.utility = testpack["utility"]
|
|
234
|
+
|
|
235
|
+
return args
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def resolve_flags(flags: Dict[str, Any] = None) -> Dict[str, bool]:
|
|
239
|
+
if flags is None:
|
|
240
|
+
flags = {}
|
|
241
|
+
|
|
242
|
+
flags["null"] = flags.get("null", True)
|
|
243
|
+
|
|
244
|
+
return flags
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
def resolve_entry(entry: Dict[str, Any], flags: Dict[str, bool]) -> Dict[str, Any]:
|
|
248
|
+
# Set default output value for missing 'out' field
|
|
249
|
+
if 'out' not in entry and flags.get("null", True):
|
|
250
|
+
entry["out"] = NULLMARK
|
|
251
|
+
|
|
252
|
+
return entry
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def fixJSON(obj, flags={}):
|
|
256
|
+
# Handle nulls
|
|
257
|
+
if obj is None:
|
|
258
|
+
return NULLMARK if flags.get("null", True) else None
|
|
259
|
+
|
|
260
|
+
# Handle errors
|
|
261
|
+
if isinstance(obj, Exception):
|
|
262
|
+
return {
|
|
263
|
+
**vars(obj),
|
|
264
|
+
'name': type(obj).__name__,
|
|
265
|
+
'message': str(obj)
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
# Handle collections recursively
|
|
269
|
+
elif isinstance(obj, list):
|
|
270
|
+
return [fixJSON(item, flags) for item in obj]
|
|
271
|
+
elif isinstance(obj, dict):
|
|
272
|
+
return {k: fixJSON(v, flags) for k, v in obj.items()}
|
|
273
|
+
|
|
274
|
+
# Return everything else unchanged
|
|
275
|
+
return obj
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def jsonfallback(obj):
|
|
279
|
+
return f"<non-serializable: {type(obj).__name__}>"
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def match(check, base, structUtils):
|
|
283
|
+
base = structUtils.clone(base)
|
|
284
|
+
|
|
285
|
+
# Use walk function to iterate through the check structure
|
|
286
|
+
def walk_apply(_key, val, _parent, path):
|
|
287
|
+
if not structUtils.isnode(val):
|
|
288
|
+
baseval = structUtils.getpath(base, path)
|
|
289
|
+
|
|
290
|
+
if baseval == val:
|
|
291
|
+
return val
|
|
292
|
+
|
|
293
|
+
# Explicit undefined expected
|
|
294
|
+
if UNDEFMARK == val and baseval is None:
|
|
295
|
+
return val
|
|
296
|
+
|
|
297
|
+
# Explicit defined expected
|
|
298
|
+
if EXISTSMARK == val and baseval is not None:
|
|
299
|
+
return val
|
|
300
|
+
|
|
301
|
+
if not matchval(val, baseval, structUtils):
|
|
302
|
+
raise AssertionError(
|
|
303
|
+
f"MATCH: {'.'.join(map(str, path))}: "
|
|
304
|
+
f"[{structUtils.stringify(val)}] <=> [{structUtils.stringify(baseval)}]"
|
|
305
|
+
)
|
|
306
|
+
return val
|
|
307
|
+
|
|
308
|
+
# Use walk to apply the check function to each node
|
|
309
|
+
structUtils.walk(check, walk_apply)
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
def matchval(check, base, structUtils):
|
|
313
|
+
# Handle undefined special case
|
|
314
|
+
if check == '__UNDEF__' or check == NULLMARK:
|
|
315
|
+
check = None
|
|
316
|
+
|
|
317
|
+
if check == base:
|
|
318
|
+
return True
|
|
319
|
+
|
|
320
|
+
# String-based pattern matching
|
|
321
|
+
if isinstance(check, str):
|
|
322
|
+
# Convert base to string for comparison
|
|
323
|
+
base_str = structUtils.stringify(base)
|
|
324
|
+
|
|
325
|
+
# Check for regex pattern with /pattern/ syntax
|
|
326
|
+
regex_match = re.match(r'^/(.+)/$', check)
|
|
327
|
+
|
|
328
|
+
if regex_match:
|
|
329
|
+
pattern = regex_match.group(1)
|
|
330
|
+
return re.search(pattern, base_str) is not None
|
|
331
|
+
else:
|
|
332
|
+
# Case-insensitive substring check
|
|
333
|
+
return structUtils.stringify(check).lower() in base_str.lower()
|
|
334
|
+
|
|
335
|
+
# Functions automatically pass
|
|
336
|
+
elif callable(check):
|
|
337
|
+
return True
|
|
338
|
+
|
|
339
|
+
# No match
|
|
340
|
+
return False
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def nullModifier(val, key, parent, _state=None, _current=None, _store=None):
|
|
344
|
+
if NULLMARK == val:
|
|
345
|
+
parent[key] = None
|
|
346
|
+
elif isinstance(val, str):
|
|
347
|
+
parent[key] = val.replace(NULLMARK, "null")
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
# StructTestClient shim for running struct tests in the SDK context.
|
|
351
|
+
# Wraps voxgig_struct as the struct utility, providing the client
|
|
352
|
+
# interface expected by the runner.
|
|
353
|
+
|
|
354
|
+
class StructContext:
|
|
355
|
+
def __init__(self):
|
|
356
|
+
self.client = None
|
|
357
|
+
self.utility = None
|
|
358
|
+
self.meta = {}
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
class StructTestUtility:
|
|
362
|
+
def __init__(self, opts=None):
|
|
363
|
+
self._opts = opts
|
|
364
|
+
self.struct = vs.StructUtility()
|
|
365
|
+
|
|
366
|
+
def contextify(self, ctxmap):
|
|
367
|
+
ctx = StructContext()
|
|
368
|
+
meta = ctxmap.get('meta', {})
|
|
369
|
+
for k, v in meta.items():
|
|
370
|
+
ctx.meta[k] = v
|
|
371
|
+
return ctx
|
|
372
|
+
|
|
373
|
+
def check(self, ctx):
|
|
374
|
+
zed = "ZED"
|
|
375
|
+
|
|
376
|
+
if self._opts is None:
|
|
377
|
+
zed += ""
|
|
378
|
+
else:
|
|
379
|
+
foo = self._opts.get("foo")
|
|
380
|
+
zed += "0" if foo is None else str(foo)
|
|
381
|
+
|
|
382
|
+
zed += "_"
|
|
383
|
+
zed += str(ctx.meta.get("bar"))
|
|
384
|
+
|
|
385
|
+
return {"zed": zed}
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
class StructTestClient:
|
|
389
|
+
def __init__(self, opts=None):
|
|
390
|
+
self._opts = opts or {}
|
|
391
|
+
self._utility = StructTestUtility(opts)
|
|
392
|
+
|
|
393
|
+
@staticmethod
|
|
394
|
+
def test(opts=None):
|
|
395
|
+
return StructTestClient(opts)
|
|
396
|
+
|
|
397
|
+
def tester(self, opts=None):
|
|
398
|
+
return StructTestClient(self._opts if opts is None else opts)
|
|
399
|
+
|
|
400
|
+
def utility(self):
|
|
401
|
+
return self._utility
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
# Export the necessary components similar to TypeScript
|
|
405
|
+
__all__ = [
|
|
406
|
+
'NULLMARK',
|
|
407
|
+
'UNDEFMARK',
|
|
408
|
+
'nullModifier',
|
|
409
|
+
'makeRunner',
|
|
410
|
+
'StructTestClient',
|
|
411
|
+
]
|