@voxgig/sdkgen 0.36.0 → 0.37.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.
Files changed (135) hide show
  1. package/bin/voxgig-sdkgen +1 -1
  2. package/dist/cmp/Main.js +0 -12
  3. package/dist/cmp/Main.js.map +1 -1
  4. package/package.json +1 -1
  5. package/project/.sdk/src/cmp/go/Config_go.ts +6 -2
  6. package/project/.sdk/src/cmp/js/EntityBase_js.ts +34 -0
  7. package/project/.sdk/src/cmp/js/Main_js.ts +10 -0
  8. package/project/.sdk/src/cmp/js/ReadmeExplanation_js.ts +33 -0
  9. package/project/.sdk/src/cmp/js/ReadmeHowto_js.ts +123 -0
  10. package/project/.sdk/src/cmp/js/ReadmeModel_js.ts +152 -0
  11. package/project/.sdk/src/cmp/js/ReadmeTopHowto_js.ts +25 -0
  12. package/project/.sdk/src/cmp/js/ReadmeTopQuick_js.ts +65 -0
  13. package/project/.sdk/src/cmp/js/ReadmeTopTest_js.ts +36 -0
  14. package/project/.sdk/src/cmp/js/TestDirect_js.ts +53 -5
  15. package/project/.sdk/src/cmp/js/TestEntity_js.ts +114 -20
  16. package/project/.sdk/src/cmp/js/fragment/Entity.fragment.js +7 -139
  17. package/project/.sdk/src/cmp/js/fragment/EntityBase.fragment.js +149 -0
  18. package/project/.sdk/src/cmp/js/fragment/EntityCreateOp.fragment.js +6 -10
  19. package/project/.sdk/src/cmp/js/fragment/EntityListOp.fragment.js +6 -10
  20. package/project/.sdk/src/cmp/js/fragment/EntityLoadOp.fragment.js +7 -11
  21. package/project/.sdk/src/cmp/js/fragment/EntityRemoveOp.fragment.js +7 -11
  22. package/project/.sdk/src/cmp/js/fragment/EntityUpdateOp.fragment.js +7 -11
  23. package/project/.sdk/src/cmp/js/fragment/Main.fragment.js +2 -0
  24. package/project/.sdk/src/cmp/js/fragment/SdkError.fragment.js +0 -2
  25. package/project/.sdk/src/cmp/lua/Config_lua.ts +6 -2
  26. package/project/.sdk/src/cmp/lua/TestEntity_lua.ts +3 -1
  27. package/project/.sdk/src/cmp/php/Config_php.ts +6 -2
  28. package/project/.sdk/src/cmp/php/TestDirect_php.ts +2 -2
  29. package/project/.sdk/src/cmp/php/TestEntity_php.ts +10 -15
  30. package/project/.sdk/src/cmp/py/Config_py.ts +6 -2
  31. package/project/.sdk/src/cmp/py/TestEntity_py.ts +3 -1
  32. package/project/.sdk/src/cmp/rb/Config_rb.ts +6 -2
  33. package/project/.sdk/src/cmp/ts/Main_ts.ts +7 -0
  34. package/project/.sdk/tm/go/feature/log_feature.go +1 -1
  35. package/project/.sdk/tm/go/test/runner_test.go +16 -2
  36. package/project/.sdk/tm/js/src/Context.js +142 -0
  37. package/project/.sdk/tm/js/src/Control.js +16 -0
  38. package/project/.sdk/tm/js/src/Operation.js +19 -0
  39. package/project/.sdk/tm/js/src/Point.js +24 -0
  40. package/project/.sdk/tm/js/src/README.md +1 -0
  41. package/project/.sdk/tm/js/src/Response.js +19 -0
  42. package/project/.sdk/tm/js/src/Result.js +21 -0
  43. package/project/.sdk/tm/js/src/Spec.js +26 -0
  44. package/project/.sdk/tm/js/src/feature/README.md +1 -0
  45. package/project/.sdk/tm/js/src/feature/base/BaseFeature.js +45 -0
  46. package/project/.sdk/tm/js/src/feature/log/LogFeature.js +46 -47
  47. package/project/.sdk/tm/js/src/feature/test/TestFeature.js +207 -0
  48. package/project/.sdk/tm/js/src/types.js +22 -0
  49. package/project/.sdk/tm/js/src/utility/CleanUtility.js +31 -0
  50. package/project/.sdk/tm/js/src/utility/DoneUtility.js +11 -4
  51. package/project/.sdk/tm/js/src/utility/FeatureAddUtility.js +42 -0
  52. package/project/.sdk/tm/js/src/utility/FeatureHookUtility.js +25 -0
  53. package/project/.sdk/tm/js/src/utility/FeatureInitUtility.js +11 -0
  54. package/project/.sdk/tm/js/src/utility/FetcherUtility.js +28 -0
  55. package/project/.sdk/tm/js/src/utility/MakeContextUtility.js +11 -0
  56. package/project/.sdk/tm/js/src/utility/MakeErrorUtility.js +55 -0
  57. package/project/.sdk/tm/js/src/utility/MakeFetchDefUtility.js +44 -0
  58. package/project/.sdk/tm/js/src/utility/MakeOptionsUtility.js +93 -0
  59. package/project/.sdk/tm/js/src/utility/MakePointUtility.js +77 -0
  60. package/project/.sdk/tm/js/src/utility/MakeRequestUtility.js +63 -0
  61. package/project/.sdk/tm/js/src/utility/MakeResponseUtility.js +55 -0
  62. package/project/.sdk/tm/js/src/utility/MakeResultUtility.js +54 -0
  63. package/project/.sdk/tm/js/src/utility/MakeSpecUtility.js +58 -0
  64. package/project/.sdk/tm/js/src/utility/MakeUrlUtility.js +40 -0
  65. package/project/.sdk/tm/js/src/utility/ParamUtility.js +61 -0
  66. package/project/.sdk/tm/js/src/utility/PrepareAuthUtility.js +41 -0
  67. package/project/.sdk/tm/js/src/utility/PrepareBodyUtility.js +25 -0
  68. package/project/.sdk/tm/js/src/utility/PrepareHeadersUtility.js +18 -0
  69. package/project/.sdk/tm/js/src/utility/{MethodUtility.js → PrepareMethodUtility.js} +7 -7
  70. package/project/.sdk/tm/js/src/utility/PrepareParamsUtility.js +25 -0
  71. package/project/.sdk/tm/js/src/utility/PreparePathUtility.js +13 -0
  72. package/project/.sdk/tm/js/src/utility/PrepareQueryUtility.js +26 -0
  73. package/project/.sdk/tm/js/src/utility/README.md +1 -0
  74. package/project/.sdk/tm/js/src/utility/ResultBasicUtility.js +34 -0
  75. package/project/.sdk/tm/js/src/utility/ResultBodyUtility.js +18 -0
  76. package/project/.sdk/tm/js/src/utility/ResultHeadersUtility.js +22 -0
  77. package/project/.sdk/tm/js/src/utility/StructUtility.js +2219 -1078
  78. package/project/.sdk/tm/js/src/utility/TransformRequestUtility.js +28 -0
  79. package/project/.sdk/tm/js/src/utility/TransformResponseUtility.js +31 -0
  80. package/project/.sdk/tm/js/src/utility/Utility.js +61 -61
  81. package/project/.sdk/tm/js/test/README.md +1 -0
  82. package/project/.sdk/tm/js/test/exists.test.js +16 -0
  83. package/project/.sdk/tm/js/test/runner.js +323 -107
  84. package/project/.sdk/tm/js/test/utility/Custom.test.js +41 -63
  85. package/project/.sdk/tm/js/test/utility/PrimaryUtility.test.js +390 -116
  86. package/project/.sdk/tm/js/test/utility/StructUtility.test.js +728 -175
  87. package/project/.sdk/tm/js/test/utility/index.js +9 -0
  88. package/project/.sdk/tm/js/test/utility.js +72 -0
  89. package/project/.sdk/tm/lua/test/primary_utility_test.lua +1213 -0
  90. package/project/.sdk/tm/lua/test/runner.lua +2 -2
  91. package/project/.sdk/tm/lua/test/struct_runner.lua +602 -0
  92. package/project/.sdk/tm/lua/test/struct_utility_test.lua +959 -0
  93. package/project/.sdk/tm/lua/utility/struct/struct.lua +10 -0
  94. package/project/.sdk/tm/php/feature/TestFeature.php +59 -96
  95. package/project/.sdk/tm/php/test/PrimaryUtilityTest.php +1309 -0
  96. package/project/.sdk/tm/php/test/Runner.php +24 -1
  97. package/project/.sdk/tm/php/test/StructRunner.php +275 -0
  98. package/project/.sdk/tm/php/test/StructUtilityTest.php +1336 -0
  99. package/project/.sdk/tm/php/utility/Fetcher.php +6 -2
  100. package/project/.sdk/tm/php/utility/MakeOptions.php +5 -1
  101. package/project/.sdk/tm/php/utility/MakeResult.php +3 -0
  102. package/project/.sdk/tm/php/utility/Param.php +9 -7
  103. package/project/.sdk/tm/php/utility/struct/Struct.php +312 -208
  104. package/project/.sdk/tm/py/test/runner.py +13 -0
  105. package/project/.sdk/tm/py/test/struct_runner.py +411 -0
  106. package/project/.sdk/tm/py/test/test_primary_utility.py +1101 -0
  107. package/project/.sdk/tm/py/test/test_struct_utility.py +751 -0
  108. package/project/.sdk/tm/rb/test/primary_utility_test.rb +1083 -0
  109. package/project/.sdk/tm/rb/test/runner.rb +5 -0
  110. package/project/.sdk/tm/rb/test/struct_runner.rb +309 -0
  111. package/project/.sdk/tm/rb/test/struct_utility_test.rb +670 -0
  112. package/src/cmp/Main.ts +1 -16
  113. package/project/.sdk/src/cmp/js/Quick_js.ts +0 -78
  114. package/project/.sdk/src/cmp/js/TestAcceptEntity_js.ts +0 -13
  115. package/project/.sdk/src/cmp/js/TestAccept_js.ts +0 -18
  116. package/project/.sdk/tm/js/src/utility/AuthUtility.js +0 -21
  117. package/project/.sdk/tm/js/src/utility/BodyUtility.js +0 -29
  118. package/project/.sdk/tm/js/src/utility/ErrorUtility.js +0 -33
  119. package/project/.sdk/tm/js/src/utility/FindparamUtility.js +0 -31
  120. package/project/.sdk/tm/js/src/utility/FullurlUtility.js +0 -39
  121. package/project/.sdk/tm/js/src/utility/HeadersUtility.js +0 -13
  122. package/project/.sdk/tm/js/src/utility/JoinurlUtility.js +0 -14
  123. package/project/.sdk/tm/js/src/utility/OperatorUtility.js +0 -44
  124. package/project/.sdk/tm/js/src/utility/OptionsUtility.js +0 -54
  125. package/project/.sdk/tm/js/src/utility/ParamsUtility.js +0 -21
  126. package/project/.sdk/tm/js/src/utility/QueryUtility.js +0 -21
  127. package/project/.sdk/tm/js/src/utility/ReqformUtility.js +0 -32
  128. package/project/.sdk/tm/js/src/utility/RequestUtility.js +0 -48
  129. package/project/.sdk/tm/js/src/utility/ResbasicUtility.js +0 -27
  130. package/project/.sdk/tm/js/src/utility/ResbodyUtility.js +0 -15
  131. package/project/.sdk/tm/js/src/utility/ResformUtility.js +0 -34
  132. package/project/.sdk/tm/js/src/utility/ResheadersUtility.js +0 -19
  133. package/project/.sdk/tm/js/src/utility/ResponseUtility.js +0 -37
  134. package/project/.sdk/tm/js/src/utility/ResultUtility.js +0 -28
  135. package/project/.sdk/tm/js/src/utility/SpecUtility.js +0 -35
@@ -0,0 +1,1309 @@
1
+ <?php
2
+ declare(strict_types=1);
3
+
4
+ // ProjectName SDK primary utility test
5
+
6
+ require_once __DIR__ . '/../projectname_sdk.php';
7
+ require_once __DIR__ . '/Runner.php';
8
+
9
+ use PHPUnit\Framework\TestCase;
10
+ use Voxgig\Struct\Struct;
11
+
12
+ class PrimaryUtilityTest extends TestCase
13
+ {
14
+ private static ?array $test_spec = null;
15
+
16
+ private static function load_test_spec(): array
17
+ {
18
+ if (self::$test_spec !== null) {
19
+ return self::$test_spec;
20
+ }
21
+ $path = __DIR__ . '/../../.sdk/test/test.json';
22
+ $content = file_get_contents($path);
23
+ if ($content === false) {
24
+ throw new RuntimeException("Failed to load test.json: $path");
25
+ }
26
+ $data = json_decode($content, true);
27
+ if (json_last_error() !== JSON_ERROR_NONE) {
28
+ throw new RuntimeException("Failed to parse test.json: " . json_last_error_msg());
29
+ }
30
+ self::$test_spec = $data;
31
+ return $data;
32
+ }
33
+
34
+ private static function get_spec(?array $spec, string ...$keys): ?array
35
+ {
36
+ $cur = $spec;
37
+ foreach ($keys as $key) {
38
+ if (!is_array($cur) || !array_key_exists($key, $cur)) {
39
+ return null;
40
+ }
41
+ $cur = $cur[$key];
42
+ }
43
+ return is_array($cur) ? $cur : null;
44
+ }
45
+
46
+ private function runset(?array $testspec, callable $subject): void
47
+ {
48
+ if ($testspec === null || !isset($testspec['set']) || !is_array($testspec['set'])) {
49
+ return;
50
+ }
51
+ $set = $testspec['set'];
52
+
53
+ foreach ($set as $i => $entry) {
54
+ if (!is_array($entry)) {
55
+ continue;
56
+ }
57
+
58
+ $mark = '';
59
+ if (isset($entry['mark'])) {
60
+ $mark = " (mark={$entry['mark']})";
61
+ }
62
+
63
+ $result = null;
64
+ $err = null;
65
+
66
+ try {
67
+ [$result, $err] = $subject($entry);
68
+ } catch (\Throwable $e) {
69
+ $err = $e;
70
+ }
71
+
72
+ $expected_err = $entry['err'] ?? null;
73
+
74
+ if ($err !== null) {
75
+ if ($expected_err !== null) {
76
+ $err_msg = ($err instanceof \Throwable) ? $err->getMessage() : (string)$err;
77
+ if (is_string($expected_err)) {
78
+ $this->assertTrue(
79
+ $this->match_string($expected_err, $err_msg),
80
+ "entry {$i}{$mark}: error mismatch: got \"{$err_msg}\", want contains \"{$expected_err}\""
81
+ );
82
+ }
83
+ // err: true means any error is acceptable
84
+
85
+ if (isset($entry['match']) && is_array($entry['match'])) {
86
+ $result_map = [
87
+ 'in' => $entry['in'] ?? null,
88
+ 'out' => $this->json_normalize($result),
89
+ 'err' => ['message' => ($err instanceof \Throwable) ? $err->getMessage() : (string)$err],
90
+ ];
91
+ $this->match_deep($i, $mark, $entry['match'], $result_map, '');
92
+ }
93
+ continue;
94
+ }
95
+ $err_msg = ($err instanceof \Throwable) ? $err->getMessage() : (string)$err;
96
+ $this->fail("entry {$i}{$mark}: unexpected error: {$err_msg}");
97
+ continue;
98
+ }
99
+
100
+ if ($expected_err !== null) {
101
+ $this->fail(
102
+ "entry {$i}{$mark}: expected error containing \"{$expected_err}\" but got result: "
103
+ . json_encode($result)
104
+ );
105
+ continue;
106
+ }
107
+
108
+ $matched = false;
109
+ if (isset($entry['match']) && is_array($entry['match'])) {
110
+ $result_map = [
111
+ 'in' => $entry['in'] ?? null,
112
+ 'out' => $this->json_normalize($result),
113
+ ];
114
+ if (isset($entry['args'])) {
115
+ $result_map['args'] = $entry['args'];
116
+ } elseif (isset($entry['in'])) {
117
+ $result_map['args'] = [$entry['in']];
118
+ }
119
+ if (isset($entry['ctx'])) {
120
+ $result_map['ctx'] = $entry['ctx'];
121
+ }
122
+ $this->match_deep($i, $mark, $entry['match'], $result_map, '');
123
+ $this->assertTrue(true, "entry {$i}{$mark}: match completed");
124
+ $matched = true;
125
+ }
126
+
127
+ $expected_out = $entry['out'] ?? null;
128
+ if ($expected_out === null && $matched) {
129
+ continue;
130
+ }
131
+ if ($expected_out !== null) {
132
+ $norm_result = $this->json_normalize($result);
133
+ $norm_expected = $this->json_normalize($expected_out);
134
+ $this->assertEquals(
135
+ $norm_expected,
136
+ $norm_result,
137
+ "entry {$i}{$mark}: output mismatch"
138
+ );
139
+ }
140
+ }
141
+ }
142
+
143
+ private function json_normalize(mixed $val): mixed
144
+ {
145
+ if ($val === null) {
146
+ return null;
147
+ }
148
+ $j = json_encode($val);
149
+ if ($j === false) {
150
+ return $val;
151
+ }
152
+ return json_decode($j, true);
153
+ }
154
+
155
+ private function match_deep(int $entry_idx, string $mark, mixed $check, mixed $base, string $path): void
156
+ {
157
+ if ($check === null) {
158
+ return;
159
+ }
160
+
161
+ if (is_array($check) && !$this->is_list($check)) {
162
+ // Associative array (map)
163
+ foreach ($check as $key => $check_val) {
164
+ $child_path = $path . '.' . $key;
165
+ $base_val = null;
166
+ if (is_array($base) && array_key_exists($key, $base)) {
167
+ $base_val = $base[$key];
168
+ }
169
+ $this->match_deep($entry_idx, $mark, $check_val, $base_val, $child_path);
170
+ }
171
+ } elseif (is_array($check) && $this->is_list($check)) {
172
+ // Indexed array (list)
173
+ foreach ($check as $i => $check_val) {
174
+ $child_path = $path . "[{$i}]";
175
+ $base_val = null;
176
+ if (is_array($base) && isset($base[$i])) {
177
+ $base_val = $base[$i];
178
+ }
179
+ $this->match_deep($entry_idx, $mark, $check_val, $base_val, $child_path);
180
+ }
181
+ } else {
182
+ if (is_string($check) && $check === '__EXISTS__') {
183
+ $this->assertNotNull(
184
+ $base,
185
+ "entry {$entry_idx}{$mark}: match {$path}: expected value to exist but got null"
186
+ );
187
+ return;
188
+ }
189
+ if (is_string($check) && $check === '__UNDEF__') {
190
+ $this->assertNull(
191
+ $base,
192
+ "entry {$entry_idx}{$mark}: match {$path}: expected null but got " . json_encode($base)
193
+ );
194
+ return;
195
+ }
196
+
197
+ $norm_check = $this->json_normalize($check);
198
+ $norm_base = $this->json_normalize($base);
199
+
200
+ if ($norm_check !== $norm_base) {
201
+ if (is_string($check) && $check !== '') {
202
+ $base_str = Struct::stringify($base);
203
+ if ($this->match_string($check, $base_str)) {
204
+ return;
205
+ }
206
+ }
207
+ $this->assertEquals(
208
+ $norm_check,
209
+ $norm_base,
210
+ "entry {$entry_idx}{$mark}: match {$path}"
211
+ );
212
+ }
213
+ }
214
+ }
215
+
216
+ private function match_string(string $pattern, string $val): bool
217
+ {
218
+ if (strlen($pattern) >= 2 && $pattern[0] === '/' && $pattern[strlen($pattern) - 1] === '/') {
219
+ $re = substr($pattern, 1, -1);
220
+ return (bool)preg_match('/' . $re . '/', $val);
221
+ }
222
+ return str_contains(strtolower($val), strtolower($pattern));
223
+ }
224
+
225
+ private function is_list(array $arr): bool
226
+ {
227
+ if (empty($arr)) {
228
+ return true;
229
+ }
230
+ return array_keys($arr) === range(0, count($arr) - 1);
231
+ }
232
+
233
+ private static function make_ctx_from_map(
234
+ ?array $ctxmap,
235
+ ProjectNameSDK $client,
236
+ ProjectNameUtility $utility
237
+ ): ProjectNameContext {
238
+ if ($ctxmap === null) {
239
+ $ctxmap = [];
240
+ }
241
+
242
+ $ctx = new ProjectNameContext($ctxmap, null);
243
+
244
+ $ctx->client = $client;
245
+ $ctx->utility = $utility;
246
+
247
+ if ($ctx->options === null) {
248
+ $ctx->options = $client->options_map();
249
+ }
250
+
251
+ // Handle spec from JSON map
252
+ if (isset($ctxmap['spec']) && is_array($ctxmap['spec'])) {
253
+ $ctx->spec = new ProjectNameSpec($ctxmap['spec']);
254
+ }
255
+
256
+ // Handle result from JSON map
257
+ if (isset($ctxmap['result']) && is_array($ctxmap['result'])) {
258
+ $ctx->result = new ProjectNameResult($ctxmap['result']);
259
+ if (isset($ctxmap['result']['err']) && is_array($ctxmap['result']['err'])) {
260
+ $msg = $ctxmap['result']['err']['message'] ?? '';
261
+ $ctx->result->err = new ProjectNameError('', $msg);
262
+ }
263
+ }
264
+
265
+ // Handle response from JSON map
266
+ if (isset($ctxmap['response']) && is_array($ctxmap['response'])) {
267
+ $ctx->response = new ProjectNameResponse($ctxmap['response']);
268
+ if (isset($ctxmap['response']['body'])) {
269
+ $body_copy = $ctxmap['response']['body'];
270
+ $ctx->response->json_func = function () use ($body_copy) { return $body_copy; };
271
+ $ctx->response->body = $body_copy;
272
+ }
273
+ if (isset($ctxmap['response']['headers']) && is_array($ctxmap['response']['headers'])) {
274
+ $lower_headers = [];
275
+ foreach ($ctxmap['response']['headers'] as $k => $v) {
276
+ $lower_headers[strtolower($k)] = $v;
277
+ }
278
+ $ctx->response->headers = $lower_headers;
279
+ }
280
+ }
281
+
282
+ return $ctx;
283
+ }
284
+
285
+ private static function fixctx(ProjectNameContext $ctx, ProjectNameSDK $client): void
286
+ {
287
+ if ($ctx->client !== null && $ctx->options === null) {
288
+ $ctx->options = $ctx->client->options_map();
289
+ }
290
+ }
291
+
292
+ private static function err_from_map(?array $m): ?ProjectNameError
293
+ {
294
+ if ($m === null) {
295
+ return null;
296
+ }
297
+ $msg = $m['message'] ?? '';
298
+ if ($msg === '') {
299
+ return null;
300
+ }
301
+ $code = $m['code'] ?? '';
302
+ return new ProjectNameError($code, $msg);
303
+ }
304
+
305
+ private static function make_test_ctx(
306
+ ProjectNameSDK $client,
307
+ ProjectNameUtility $utility,
308
+ ?array $overrides = null
309
+ ): ProjectNameContext {
310
+ $ctxmap = [
311
+ 'opname' => 'load',
312
+ 'client' => $client,
313
+ 'utility' => $utility,
314
+ ];
315
+ if ($overrides !== null) {
316
+ foreach ($overrides as $k => $v) {
317
+ $ctxmap[$k] = $v;
318
+ }
319
+ }
320
+ return ($utility->make_context)($ctxmap, $client->get_root_ctx());
321
+ }
322
+
323
+ private static function make_test_full_ctx(
324
+ ProjectNameSDK $client,
325
+ ProjectNameUtility $utility
326
+ ): ProjectNameContext {
327
+ $ctx = self::make_test_ctx($client, $utility);
328
+ $ctx->point = [
329
+ 'parts' => ['items', '{id}'],
330
+ 'args' => ['params' => [['name' => 'id', 'reqd' => true]]],
331
+ 'params' => ['id'],
332
+ 'alias' => [],
333
+ 'select' => [],
334
+ 'active' => true,
335
+ 'transform' => [],
336
+ ];
337
+ $ctx->match = ['id' => 'item01'];
338
+ $ctx->reqmatch = ['id' => 'item01'];
339
+ return $ctx;
340
+ }
341
+
342
+
343
+ // === Test: exists ===
344
+
345
+ public function test_exists(): void
346
+ {
347
+ $client = ProjectNameSDK::test(null, null);
348
+ $utility = $client->get_utility();
349
+
350
+ $this->assertNotNull($utility->clean, 'clean should not be null');
351
+ $this->assertNotNull($utility->done, 'done should not be null');
352
+ $this->assertNotNull($utility->make_error, 'make_error should not be null');
353
+ $this->assertNotNull($utility->feature_add, 'feature_add should not be null');
354
+ $this->assertNotNull($utility->feature_hook, 'feature_hook should not be null');
355
+ $this->assertNotNull($utility->feature_init, 'feature_init should not be null');
356
+ $this->assertNotNull($utility->fetcher, 'fetcher should not be null');
357
+ $this->assertNotNull($utility->make_fetch_def, 'make_fetch_def should not be null');
358
+ $this->assertNotNull($utility->make_context, 'make_context should not be null');
359
+ $this->assertNotNull($utility->make_options, 'make_options should not be null');
360
+ $this->assertNotNull($utility->make_request, 'make_request should not be null');
361
+ $this->assertNotNull($utility->make_response, 'make_response should not be null');
362
+ $this->assertNotNull($utility->make_result, 'make_result should not be null');
363
+ $this->assertNotNull($utility->make_point, 'make_point should not be null');
364
+ $this->assertNotNull($utility->make_spec, 'make_spec should not be null');
365
+ $this->assertNotNull($utility->make_url, 'make_url should not be null');
366
+ $this->assertNotNull($utility->param, 'param should not be null');
367
+ $this->assertNotNull($utility->prepare_auth, 'prepare_auth should not be null');
368
+ $this->assertNotNull($utility->prepare_body, 'prepare_body should not be null');
369
+ $this->assertNotNull($utility->prepare_headers, 'prepare_headers should not be null');
370
+ $this->assertNotNull($utility->prepare_method, 'prepare_method should not be null');
371
+ $this->assertNotNull($utility->prepare_params, 'prepare_params should not be null');
372
+ $this->assertNotNull($utility->prepare_path, 'prepare_path should not be null');
373
+ $this->assertNotNull($utility->prepare_query, 'prepare_query should not be null');
374
+ $this->assertNotNull($utility->result_basic, 'result_basic should not be null');
375
+ $this->assertNotNull($utility->result_body, 'result_body should not be null');
376
+ $this->assertNotNull($utility->result_headers, 'result_headers should not be null');
377
+ $this->assertNotNull($utility->transform_request, 'transform_request should not be null');
378
+ $this->assertNotNull($utility->transform_response, 'transform_response should not be null');
379
+ }
380
+
381
+
382
+ // === Test: clean-basic ===
383
+
384
+ public function test_clean_basic(): void
385
+ {
386
+ $client = ProjectNameSDK::test(null, null);
387
+ $utility = $client->get_utility();
388
+ $ctx = self::make_test_ctx($client, $utility);
389
+ $val = ['key' => 'secret123', 'name' => 'test'];
390
+ $cleaned = ($utility->clean)($ctx, $val);
391
+ $this->assertNotNull($cleaned, 'cleaned should not be null');
392
+ }
393
+
394
+
395
+ // === Test: done-basic ===
396
+
397
+ public function test_done_basic(): void
398
+ {
399
+ $spec = self::load_test_spec();
400
+ $primary = self::get_spec($spec, 'primary');
401
+ $client = ProjectNameSDK::test(null, null);
402
+ $utility = $client->get_utility();
403
+
404
+ $this->runset(self::get_spec($primary, 'done', 'basic'), function (array $entry) use ($client, $utility) {
405
+ $ctxmap = $entry['ctx'] ?? [];
406
+ $ctx = self::make_ctx_from_map($ctxmap, $client, $utility);
407
+ self::fixctx($ctx, $client);
408
+ return ($utility->done)($ctx);
409
+ });
410
+ }
411
+
412
+
413
+ // === Test: makeError-basic ===
414
+
415
+ public function test_make_error_basic(): void
416
+ {
417
+ $spec = self::load_test_spec();
418
+ $primary = self::get_spec($spec, 'primary');
419
+ $client = ProjectNameSDK::test(null, null);
420
+ $utility = $client->get_utility();
421
+
422
+ $this->runset(self::get_spec($primary, 'makeError', 'basic'), function (array $entry) use ($client, $utility) {
423
+ $args = $entry['args'] ?? [];
424
+ if (empty($args)) {
425
+ $args = [[]];
426
+ }
427
+
428
+ $ctxmap = $args[0] ?? [];
429
+ if (!is_array($ctxmap)) {
430
+ $ctxmap = [];
431
+ }
432
+ $ctx = self::make_ctx_from_map($ctxmap, $client, $utility);
433
+ self::fixctx($ctx, $client);
434
+
435
+ $err = null;
436
+ if (count($args) > 1 && is_array($args[1])) {
437
+ $err = self::err_from_map($args[1]);
438
+ }
439
+
440
+ return ($utility->make_error)($ctx, $err);
441
+ });
442
+ }
443
+
444
+
445
+ // === Test: makeError-no-throw ===
446
+
447
+ public function test_make_error_no_throw(): void
448
+ {
449
+ $client = ProjectNameSDK::test(null, null);
450
+ $utility = $client->get_utility();
451
+ $ctx = self::make_test_full_ctx($client, $utility);
452
+ $ctx->ctrl->throw_err = false;
453
+ $ctx->result = new ProjectNameResult([
454
+ 'ok' => false,
455
+ 'resdata' => ['id' => 'safe01'],
456
+ ]);
457
+
458
+ [$out, $err] = ($utility->make_error)($ctx, $ctx->make_error('test_code', 'test message'));
459
+ $this->assertNull($err, 'expected no error');
460
+ $this->assertIsArray($out);
461
+ $this->assertEquals('safe01', $out['id']);
462
+ }
463
+
464
+
465
+ // === Test: featureAdd-basic ===
466
+
467
+ public function test_feature_add_basic(): void
468
+ {
469
+ $client = ProjectNameSDK::test(null, null);
470
+ $utility = $client->get_utility();
471
+ $ctx = self::make_test_ctx($client, $utility);
472
+ $start_len = count($client->features);
473
+
474
+ $feature = new ProjectNameBaseFeature();
475
+ ($utility->feature_add)($ctx, $feature);
476
+
477
+ $this->assertEquals($start_len + 1, count($client->features));
478
+ }
479
+
480
+
481
+ // === Test: featureHook-basic ===
482
+
483
+ public function test_feature_hook_basic(): void
484
+ {
485
+ $hook_client = ProjectNameSDK::test(null, null);
486
+ $hook_utility = $hook_client->get_utility();
487
+ $ctx = self::make_test_ctx($hook_client, $hook_utility);
488
+
489
+ $called = false;
490
+ $hook_feature = new class extends ProjectNameBaseFeature {
491
+ public $hook_fn = null;
492
+ public function TestHook(ProjectNameContext $ctx): void
493
+ {
494
+ if ($this->hook_fn !== null) {
495
+ ($this->hook_fn)();
496
+ }
497
+ }
498
+ };
499
+ $hook_feature->hook_fn = function () use (&$called) { $called = true; };
500
+ $hook_client->features = [$hook_feature];
501
+
502
+ ($hook_utility->feature_hook)($ctx, 'TestHook');
503
+ $this->assertTrue($called, 'expected TestHook to be called');
504
+ }
505
+
506
+
507
+ // === Test: featureInit-basic ===
508
+
509
+ public function test_feature_init_basic(): void
510
+ {
511
+ $init_client = ProjectNameSDK::test(null, null);
512
+ $init_utility = $init_client->get_utility();
513
+ $ctx = self::make_test_ctx($init_client, $init_utility);
514
+ $ctx->options['feature'] = [
515
+ 'initfeat' => ['active' => true],
516
+ ];
517
+
518
+ $init_called = false;
519
+ $feature = new class extends ProjectNameBaseFeature {
520
+ public $init_fn = null;
521
+ public function __construct()
522
+ {
523
+ parent::__construct();
524
+ $this->name = 'initfeat';
525
+ $this->active = true;
526
+ }
527
+ public function init(ProjectNameContext $ctx, array $options): void
528
+ {
529
+ if ($this->init_fn !== null) {
530
+ ($this->init_fn)();
531
+ }
532
+ }
533
+ };
534
+ $feature->init_fn = function () use (&$init_called) { $init_called = true; };
535
+
536
+ ($init_utility->feature_init)($ctx, $feature);
537
+ $this->assertTrue($init_called, 'expected init to be called');
538
+ }
539
+
540
+
541
+ // === Test: featureInit-inactive ===
542
+
543
+ public function test_feature_init_inactive(): void
544
+ {
545
+ $init_client = ProjectNameSDK::test(null, null);
546
+ $init_utility = $init_client->get_utility();
547
+ $ctx = self::make_test_ctx($init_client, $init_utility);
548
+ $ctx->options['feature'] = [
549
+ 'nofeat' => ['active' => false],
550
+ ];
551
+
552
+ $init_called = false;
553
+ $feature = new class extends ProjectNameBaseFeature {
554
+ public $init_fn = null;
555
+ public function __construct()
556
+ {
557
+ parent::__construct();
558
+ $this->name = 'nofeat';
559
+ $this->active = false;
560
+ }
561
+ public function init(ProjectNameContext $ctx, array $options): void
562
+ {
563
+ if ($this->init_fn !== null) {
564
+ ($this->init_fn)();
565
+ }
566
+ }
567
+ };
568
+ $feature->init_fn = function () use (&$init_called) { $init_called = true; };
569
+
570
+ ($init_utility->feature_init)($ctx, $feature);
571
+ $this->assertFalse($init_called, 'expected init NOT to be called for inactive feature');
572
+ }
573
+
574
+
575
+ // === Test: fetcher-live ===
576
+
577
+ public function test_fetcher_live(): void
578
+ {
579
+ $calls = [];
580
+ $live_client = new ProjectNameSDK([
581
+ 'system' => [
582
+ 'fetch' => function (string $url, array $fetchdef) use (&$calls) {
583
+ $calls[] = ['url' => $url, 'init' => $fetchdef];
584
+ return [['status' => 200, 'statusText' => 'OK'], null];
585
+ },
586
+ ],
587
+ ]);
588
+ $live_utility = $live_client->get_utility();
589
+ $ctx = ($live_utility->make_context)([
590
+ 'opname' => 'load',
591
+ 'client' => $live_client,
592
+ 'utility' => $live_utility,
593
+ ], null);
594
+
595
+ $fetchdef = ['method' => 'GET', 'headers' => []];
596
+ [$_, $err] = ($live_utility->fetcher)($ctx, 'http://example.com/test', $fetchdef);
597
+ $this->assertNull($err, 'expected no error');
598
+ $this->assertCount(1, $calls, 'expected 1 call');
599
+ $this->assertEquals('http://example.com/test', $calls[0]['url']);
600
+ }
601
+
602
+
603
+ // === Test: fetcher-blocked-test-mode ===
604
+
605
+ public function test_fetcher_blocked_test_mode(): void
606
+ {
607
+ $blocked_client = new ProjectNameSDK([
608
+ 'system' => [
609
+ 'fetch' => function (string $url, array $fetchdef) {
610
+ return [[], null];
611
+ },
612
+ ],
613
+ ]);
614
+ $blocked_client->mode = 'test';
615
+
616
+ $blocked_utility = $blocked_client->get_utility();
617
+ $ctx = ($blocked_utility->make_context)([
618
+ 'opname' => 'load',
619
+ 'client' => $blocked_client,
620
+ 'utility' => $blocked_utility,
621
+ ], null);
622
+
623
+ $fetchdef = ['method' => 'GET', 'headers' => []];
624
+ [$_, $err] = ($blocked_utility->fetcher)($ctx, 'http://example.com/test', $fetchdef);
625
+ $this->assertNotNull($err, 'expected error for test mode fetch');
626
+ $err_msg = ($err instanceof \Throwable) ? $err->getMessage() : (string)$err;
627
+ $this->assertTrue(
628
+ str_contains(strtolower($err_msg), 'blocked'),
629
+ "expected error containing 'blocked', got: {$err_msg}"
630
+ );
631
+ }
632
+
633
+
634
+ // === Test: makeContext-basic ===
635
+
636
+ public function test_make_context_basic(): void
637
+ {
638
+ $spec = self::load_test_spec();
639
+ $primary = self::get_spec($spec, 'primary');
640
+ $client = ProjectNameSDK::test(null, null);
641
+ $utility = $client->get_utility();
642
+
643
+ $this->runset(self::get_spec($primary, 'makeContext', 'basic'), function (array $entry) use ($client, $utility) {
644
+ $in = $entry['in'] ?? null;
645
+ if (is_array($in)) {
646
+ $ctx = ($utility->make_context)($in, null);
647
+ $out = [
648
+ 'id' => $ctx->id,
649
+ ];
650
+ if ($ctx->op !== null) {
651
+ $out['op'] = [
652
+ 'name' => $ctx->op->name,
653
+ 'input' => $ctx->op->input,
654
+ ];
655
+ }
656
+ return [$out, null];
657
+ }
658
+ return [null, null];
659
+ });
660
+ }
661
+
662
+
663
+ // === Test: makeFetchDef-basic ===
664
+
665
+ public function test_make_fetch_def_basic(): void
666
+ {
667
+ $client = ProjectNameSDK::test(null, null);
668
+ $utility = $client->get_utility();
669
+ $ctx = self::make_test_full_ctx($client, $utility);
670
+ $ctx->spec = new ProjectNameSpec([
671
+ 'base' => 'http://localhost:8080',
672
+ 'prefix' => '/api',
673
+ 'path' => 'items/{id}',
674
+ 'suffix' => '',
675
+ 'params' => ['id' => 'item01'],
676
+ 'query' => [],
677
+ 'headers' => ['content-type' => 'application/json'],
678
+ 'method' => 'GET',
679
+ 'step' => 'start',
680
+ ]);
681
+ $ctx->result = new ProjectNameResult([]);
682
+
683
+ [$fetchdef, $err] = ($utility->make_fetch_def)($ctx);
684
+ $this->assertNull($err, 'should not be error');
685
+ $this->assertNotNull($fetchdef);
686
+ $this->assertEquals('GET', $fetchdef['method']);
687
+ $url = $fetchdef['url'] ?? '';
688
+ $this->assertTrue(str_contains($url, '/api/items/item01'), "expected url to contain /api/items/item01, got {$url}");
689
+ $this->assertEquals('application/json', $fetchdef['headers']['content-type']);
690
+ $this->assertArrayNotHasKey('body', $fetchdef);
691
+ }
692
+
693
+
694
+ // === Test: makeFetchDef-with-body ===
695
+
696
+ public function test_make_fetch_def_with_body(): void
697
+ {
698
+ $client = ProjectNameSDK::test(null, null);
699
+ $utility = $client->get_utility();
700
+ $ctx = self::make_test_full_ctx($client, $utility);
701
+ $ctx->spec = new ProjectNameSpec([
702
+ 'base' => 'http://localhost:8080',
703
+ 'prefix' => '',
704
+ 'path' => 'items',
705
+ 'suffix' => '',
706
+ 'params' => [],
707
+ 'query' => [],
708
+ 'headers' => [],
709
+ 'method' => 'POST',
710
+ 'step' => 'start',
711
+ 'body' => ['name' => 'test'],
712
+ ]);
713
+ $ctx->result = new ProjectNameResult([]);
714
+
715
+ [$fetchdef, $err] = ($utility->make_fetch_def)($ctx);
716
+ $this->assertNull($err, 'should not be error');
717
+ $this->assertNotNull($fetchdef);
718
+ $this->assertEquals('POST', $fetchdef['method']);
719
+ $body_str = $fetchdef['body'] ?? null;
720
+ $this->assertIsString($body_str, 'expected body string');
721
+ $this->assertTrue(str_contains($body_str, '"name"'), "expected body to contain name, got {$body_str}");
722
+ }
723
+
724
+
725
+ // === Test: makeOptions-basic ===
726
+
727
+ public function test_make_options_basic(): void
728
+ {
729
+ $spec = self::load_test_spec();
730
+ $primary = self::get_spec($spec, 'primary');
731
+ $client = ProjectNameSDK::test(null, null);
732
+ $utility = $client->get_utility();
733
+
734
+ $this->runset(self::get_spec($primary, 'makeOptions', 'basic'), function (array $entry) use ($client, $utility) {
735
+ $in = $entry['in'] ?? [];
736
+ $ctx = ($utility->make_context)([
737
+ 'options' => $in['options'] ?? null,
738
+ 'config' => $in['config'] ?? null,
739
+ ], null);
740
+ $ctx->client = $client;
741
+ $ctx->utility = $utility;
742
+ return [($utility->make_options)($ctx), null];
743
+ });
744
+ }
745
+
746
+
747
+ // === Test: makeRequest-basic ===
748
+
749
+ public function test_make_request_basic(): void
750
+ {
751
+ $spec = self::load_test_spec();
752
+ $primary = self::get_spec($spec, 'primary');
753
+ $client = ProjectNameSDK::test(null, null);
754
+ $utility = $client->get_utility();
755
+
756
+ $this->runset(self::get_spec($primary, 'makeRequest', 'basic'), function (array &$entry) use ($client, $utility) {
757
+ $ctxmap = $entry['ctx'] ?? [];
758
+ $ctx = self::make_ctx_from_map($ctxmap, $client, $utility);
759
+ $ctx->options = $client->options_map();
760
+
761
+ [$_, $err] = ($utility->make_request)($ctx);
762
+
763
+ // Update entry ctx for match checking
764
+ if ($ctx->response !== null) {
765
+ $entry['ctx']['response'] = 'exists';
766
+ }
767
+ if ($ctx->result !== null) {
768
+ $entry['ctx']['result'] = 'exists';
769
+ }
770
+
771
+ return [null, $err];
772
+ });
773
+ }
774
+
775
+
776
+ // === Test: makeResponse-basic ===
777
+
778
+ public function test_make_response_basic(): void
779
+ {
780
+ $spec = self::load_test_spec();
781
+ $primary = self::get_spec($spec, 'primary');
782
+ $client = ProjectNameSDK::test(null, null);
783
+ $utility = $client->get_utility();
784
+
785
+ $this->runset(self::get_spec($primary, 'makeResponse', 'basic'), function (array &$entry) use ($client, $utility) {
786
+ $ctxmap = $entry['ctx'] ?? [];
787
+ $ctx = self::make_ctx_from_map($ctxmap, $client, $utility);
788
+ self::fixctx($ctx, $client);
789
+
790
+ [$_, $err] = ($utility->make_response)($ctx);
791
+
792
+ // Update entry ctx for match with result data
793
+ if ($ctx->result !== null) {
794
+ $entry['ctx']['result'] = [
795
+ 'ok' => $ctx->result->ok,
796
+ 'status' => $ctx->result->status,
797
+ 'statusText' => $ctx->result->status_text,
798
+ 'headers' => $ctx->result->headers,
799
+ 'body' => $ctx->result->body,
800
+ ];
801
+ }
802
+
803
+ return [null, $err];
804
+ });
805
+ }
806
+
807
+
808
+ // === Test: makeResult-basic ===
809
+
810
+ public function test_make_result_basic(): void
811
+ {
812
+ $client = ProjectNameSDK::test(null, null);
813
+ $utility = $client->get_utility();
814
+ $ctx = self::make_test_full_ctx($client, $utility);
815
+ $ctx->spec = new ProjectNameSpec([
816
+ 'base' => 'http://localhost:8080',
817
+ 'prefix' => '/api',
818
+ 'path' => 'items/{id}',
819
+ 'suffix' => '',
820
+ 'params' => ['id' => 'item01'],
821
+ 'query' => [],
822
+ 'headers' => [],
823
+ 'method' => 'GET',
824
+ 'step' => 'start',
825
+ ]);
826
+ $ctx->result = new ProjectNameResult([
827
+ 'ok' => true,
828
+ 'status' => 200,
829
+ 'statusText' => 'OK',
830
+ 'headers' => [],
831
+ 'resdata' => ['id' => 'item01', 'name' => 'Test'],
832
+ ]);
833
+
834
+ [$result, $err] = ($utility->make_result)($ctx);
835
+ $this->assertNull($err, 'expected no error');
836
+ $this->assertNotNull($result);
837
+ $this->assertEquals(200, $result->status);
838
+ }
839
+
840
+
841
+ // === Test: makeResult-no-spec ===
842
+
843
+ public function test_make_result_no_spec(): void
844
+ {
845
+ $client = ProjectNameSDK::test(null, null);
846
+ $utility = $client->get_utility();
847
+ $ctx = self::make_test_full_ctx($client, $utility);
848
+ $ctx->spec = null;
849
+ $ctx->result = new ProjectNameResult([
850
+ 'ok' => true,
851
+ 'status' => 200,
852
+ 'statusText' => 'OK',
853
+ 'headers' => [],
854
+ ]);
855
+
856
+ [$_, $err] = ($utility->make_result)($ctx);
857
+ $this->assertNotNull($err, 'expected error for null spec');
858
+ }
859
+
860
+
861
+ // === Test: makeResult-no-result ===
862
+
863
+ public function test_make_result_no_result(): void
864
+ {
865
+ $client = ProjectNameSDK::test(null, null);
866
+ $utility = $client->get_utility();
867
+ $ctx = self::make_test_full_ctx($client, $utility);
868
+ $ctx->spec = new ProjectNameSpec(['step' => 'start']);
869
+ $ctx->result = null;
870
+
871
+ [$_, $err] = ($utility->make_result)($ctx);
872
+ $this->assertNotNull($err, 'expected error for null result');
873
+ }
874
+
875
+
876
+ // === Test: makeSpec-basic ===
877
+
878
+ public function test_make_spec_basic(): void
879
+ {
880
+ $spec = self::load_test_spec();
881
+ $primary = self::get_spec($spec, 'primary');
882
+ $setup_opts = self::get_spec($primary, 'makeSpec', 'DEF', 'setup', 'a');
883
+ $spec_client = ProjectNameSDK::test(null, $setup_opts);
884
+ $spec_utility = $spec_client->get_utility();
885
+ $client = ProjectNameSDK::test(null, null);
886
+ $utility = $client->get_utility();
887
+
888
+ $this->runset(self::get_spec($primary, 'makeSpec', 'basic'), function (array &$entry) use ($spec_client, $spec_utility, $utility) {
889
+ $ctxmap = $entry['ctx'] ?? [];
890
+ $ctx = self::make_ctx_from_map($ctxmap, $spec_client, $spec_utility);
891
+ $ctx->options = $spec_client->options_map();
892
+
893
+ [$_, $err] = ($utility->make_spec)($ctx);
894
+
895
+ // Update entry ctx for match
896
+ if ($ctx->spec !== null) {
897
+ $entry['ctx']['spec'] = [
898
+ 'base' => $ctx->spec->base,
899
+ 'prefix' => $ctx->spec->prefix,
900
+ 'suffix' => $ctx->spec->suffix,
901
+ 'method' => $ctx->spec->method,
902
+ 'params' => $ctx->spec->params,
903
+ 'query' => $ctx->spec->query,
904
+ 'headers' => $ctx->spec->headers,
905
+ 'step' => $ctx->spec->step,
906
+ ];
907
+ }
908
+
909
+ return [null, $err];
910
+ });
911
+ }
912
+
913
+
914
+ // === Test: makePoint-basic ===
915
+
916
+ public function test_make_point_basic(): void
917
+ {
918
+ $client = ProjectNameSDK::test(null, null);
919
+ $utility = $client->get_utility();
920
+ $ctx = self::make_test_ctx($client, $utility);
921
+ $point = [
922
+ 'parts' => ['items', '{id}'],
923
+ 'args' => ['params' => []],
924
+ 'params' => [],
925
+ 'alias' => [],
926
+ 'select' => [],
927
+ 'active' => true,
928
+ 'transform' => [],
929
+ ];
930
+ $ctx->op->points = [$point];
931
+
932
+ [$_, $err] = ($utility->make_point)($ctx);
933
+ $this->assertNull($err, 'expected no error');
934
+ $this->assertNotNull($ctx->point, 'expected point to be set');
935
+ }
936
+
937
+
938
+ // === Test: makeUrl-basic ===
939
+
940
+ public function test_make_url_basic(): void
941
+ {
942
+ $spec = self::load_test_spec();
943
+ $primary = self::get_spec($spec, 'primary');
944
+ $client = ProjectNameSDK::test(null, null);
945
+ $utility = $client->get_utility();
946
+
947
+ $this->runset(self::get_spec($primary, 'makeUrl', 'basic'), function (array $entry) use ($client, $utility) {
948
+ $ctxmap = $entry['ctx'] ?? [];
949
+ $ctx = self::make_ctx_from_map($ctxmap, $client, $utility);
950
+ if ($ctx->result === null) {
951
+ $ctx->result = new ProjectNameResult([]);
952
+ }
953
+ return ($utility->make_url)($ctx);
954
+ });
955
+ }
956
+
957
+
958
+ // === Test: operator-basic ===
959
+
960
+ public function test_operator_basic(): void
961
+ {
962
+ $spec = self::load_test_spec();
963
+ $primary = self::get_spec($spec, 'primary');
964
+
965
+ $this->runset(self::get_spec($primary, 'operator', 'basic'), function (array $entry) {
966
+ $in = $entry['in'] ?? [];
967
+ $op = new ProjectNameOperation($in);
968
+ return [[
969
+ 'entity' => $op->entity,
970
+ 'name' => $op->name,
971
+ 'input' => $op->input,
972
+ 'points' => $op->points,
973
+ ], null];
974
+ });
975
+ }
976
+
977
+
978
+ // === Test: param-basic ===
979
+
980
+ public function test_param_basic(): void
981
+ {
982
+ $spec = self::load_test_spec();
983
+ $primary = self::get_spec($spec, 'primary');
984
+ $client = ProjectNameSDK::test(null, null);
985
+ $utility = $client->get_utility();
986
+
987
+ $this->runset(self::get_spec($primary, 'param', 'basic'), function (array &$entry) use ($client, $utility) {
988
+ $args = $entry['args'] ?? [];
989
+ if (count($args) < 2) {
990
+ return [null, null];
991
+ }
992
+
993
+ $ctxmap = $args[0] ?? [];
994
+ if (!is_array($ctxmap)) {
995
+ $ctxmap = [];
996
+ }
997
+ $ctx = self::make_ctx_from_map($ctxmap, $client, $utility);
998
+ $paramdef = $args[1];
999
+
1000
+ $result = ($utility->param)($ctx, $paramdef);
1001
+
1002
+ // Update entry ctx for match
1003
+ if (isset($entry['match']) && is_array($entry['match'])) {
1004
+ if (isset($entry['match']['ctx']) && is_array($entry['match']['ctx'])) {
1005
+ $ctx_match = $entry['match']['ctx'];
1006
+ if (!isset($entry['ctx'])) {
1007
+ $entry['ctx'] = [];
1008
+ }
1009
+ if (isset($ctx_match['spec']) && is_array($ctx_match['spec'])) {
1010
+ if ($ctx->spec !== null) {
1011
+ if (isset($ctx_match['spec']['alias'])) {
1012
+ $entry['ctx']['spec'] = [
1013
+ 'alias' => $ctx->spec->alias_map,
1014
+ ];
1015
+ }
1016
+ }
1017
+ }
1018
+ }
1019
+ }
1020
+
1021
+ return [$result, null];
1022
+ });
1023
+ }
1024
+
1025
+
1026
+ // === Test: prepareAuth-basic ===
1027
+
1028
+ public function test_prepare_auth_basic(): void
1029
+ {
1030
+ $spec = self::load_test_spec();
1031
+ $primary = self::get_spec($spec, 'primary');
1032
+ $setup_opts = self::get_spec($primary, 'prepareAuth', 'DEF', 'setup', 'a');
1033
+ $auth_client = ProjectNameSDK::test(null, $setup_opts);
1034
+ $auth_utility = $auth_client->get_utility();
1035
+ $client = ProjectNameSDK::test(null, null);
1036
+ $utility = $client->get_utility();
1037
+
1038
+ $this->runset(self::get_spec($primary, 'prepareAuth', 'basic'), function (array &$entry) use ($auth_client, $auth_utility, $utility) {
1039
+ $ctxmap = $entry['ctx'] ?? [];
1040
+ $ctx = self::make_ctx_from_map($ctxmap, $auth_client, $auth_utility);
1041
+ self::fixctx($ctx, $auth_client);
1042
+
1043
+ [$_, $err] = ($utility->prepare_auth)($ctx);
1044
+
1045
+ // Update entry ctx for match
1046
+ if ($ctx->spec !== null) {
1047
+ $entry['ctx']['spec'] = [
1048
+ 'headers' => $ctx->spec->headers,
1049
+ ];
1050
+ }
1051
+
1052
+ return [null, $err];
1053
+ });
1054
+ }
1055
+
1056
+
1057
+ // === Test: prepareBody-basic ===
1058
+
1059
+ public function test_prepare_body_basic(): void
1060
+ {
1061
+ $spec = self::load_test_spec();
1062
+ $primary = self::get_spec($spec, 'primary');
1063
+ $client = ProjectNameSDK::test(null, null);
1064
+ $utility = $client->get_utility();
1065
+
1066
+ $this->runset(self::get_spec($primary, 'prepareBody', 'basic'), function (array $entry) use ($client, $utility) {
1067
+ $ctxmap = $entry['ctx'] ?? [];
1068
+ $ctx = self::make_ctx_from_map($ctxmap, $client, $utility);
1069
+ self::fixctx($ctx, $client);
1070
+ return [($utility->prepare_body)($ctx), null];
1071
+ });
1072
+ }
1073
+
1074
+
1075
+ // === Test: prepareHeaders-basic ===
1076
+
1077
+ public function test_prepare_headers_basic(): void
1078
+ {
1079
+ $spec = self::load_test_spec();
1080
+ $primary = self::get_spec($spec, 'primary');
1081
+ $client = ProjectNameSDK::test(null, null);
1082
+ $utility = $client->get_utility();
1083
+
1084
+ $this->runset(self::get_spec($primary, 'prepareHeaders', 'basic'), function (array $entry) use ($client, $utility) {
1085
+ $ctxmap = $entry['ctx'] ?? [];
1086
+ $ctx = self::make_ctx_from_map($ctxmap, $client, $utility);
1087
+ return [($utility->prepare_headers)($ctx), null];
1088
+ });
1089
+ }
1090
+
1091
+
1092
+ // === Test: prepareMethod-basic ===
1093
+
1094
+ public function test_prepare_method_basic(): void
1095
+ {
1096
+ $spec = self::load_test_spec();
1097
+ $primary = self::get_spec($spec, 'primary');
1098
+ $client = ProjectNameSDK::test(null, null);
1099
+ $utility = $client->get_utility();
1100
+
1101
+ $this->runset(self::get_spec($primary, 'prepareMethod', 'basic'), function (array $entry) use ($client, $utility) {
1102
+ $ctxmap = $entry['ctx'] ?? [];
1103
+ $ctx = self::make_ctx_from_map($ctxmap, $client, $utility);
1104
+ return [($utility->prepare_method)($ctx), null];
1105
+ });
1106
+ }
1107
+
1108
+
1109
+ // === Test: prepareParams-basic ===
1110
+
1111
+ public function test_prepare_params_basic(): void
1112
+ {
1113
+ $spec = self::load_test_spec();
1114
+ $primary = self::get_spec($spec, 'primary');
1115
+ $client = ProjectNameSDK::test(null, null);
1116
+ $utility = $client->get_utility();
1117
+
1118
+ $this->runset(self::get_spec($primary, 'prepareParams', 'basic'), function (array $entry) use ($client, $utility) {
1119
+ $ctxmap = $entry['ctx'] ?? [];
1120
+ $ctx = self::make_ctx_from_map($ctxmap, $client, $utility);
1121
+ return [($utility->prepare_params)($ctx), null];
1122
+ });
1123
+ }
1124
+
1125
+
1126
+ // === Test: preparePath-basic ===
1127
+
1128
+ public function test_prepare_path_basic(): void
1129
+ {
1130
+ $client = ProjectNameSDK::test(null, null);
1131
+ $utility = $client->get_utility();
1132
+ $ctx = self::make_test_full_ctx($client, $utility);
1133
+ $ctx->point = [
1134
+ 'parts' => ['api', 'planet', '{id}'],
1135
+ 'args' => ['params' => []],
1136
+ ];
1137
+
1138
+ $path = ($utility->prepare_path)($ctx);
1139
+ $this->assertEquals('api/planet/{id}', $path);
1140
+ }
1141
+
1142
+
1143
+ // === Test: preparePath-single ===
1144
+
1145
+ public function test_prepare_path_single(): void
1146
+ {
1147
+ $client = ProjectNameSDK::test(null, null);
1148
+ $utility = $client->get_utility();
1149
+ $ctx = self::make_test_full_ctx($client, $utility);
1150
+ $ctx->point = [
1151
+ 'parts' => ['items'],
1152
+ 'args' => ['params' => []],
1153
+ ];
1154
+
1155
+ $path = ($utility->prepare_path)($ctx);
1156
+ $this->assertEquals('items', $path);
1157
+ }
1158
+
1159
+
1160
+ // === Test: prepareQuery-basic ===
1161
+
1162
+ public function test_prepare_query_basic(): void
1163
+ {
1164
+ $spec = self::load_test_spec();
1165
+ $primary = self::get_spec($spec, 'primary');
1166
+ $client = ProjectNameSDK::test(null, null);
1167
+ $utility = $client->get_utility();
1168
+
1169
+ $this->runset(self::get_spec($primary, 'prepareQuery', 'basic'), function (array $entry) use ($client, $utility) {
1170
+ $ctxmap = $entry['ctx'] ?? [];
1171
+ $ctx = self::make_ctx_from_map($ctxmap, $client, $utility);
1172
+ return [($utility->prepare_query)($ctx), null];
1173
+ });
1174
+ }
1175
+
1176
+
1177
+ // === Test: resultBasic-basic ===
1178
+
1179
+ public function test_result_basic_basic(): void
1180
+ {
1181
+ $spec = self::load_test_spec();
1182
+ $primary = self::get_spec($spec, 'primary');
1183
+ $client = ProjectNameSDK::test(null, null);
1184
+ $utility = $client->get_utility();
1185
+
1186
+ $this->runset(self::get_spec($primary, 'resultBasic', 'basic'), function (array $entry) use ($client, $utility) {
1187
+ $ctxmap = $entry['ctx'] ?? [];
1188
+ $ctx = self::make_ctx_from_map($ctxmap, $client, $utility);
1189
+ self::fixctx($ctx, $client);
1190
+
1191
+ $result = ($utility->result_basic)($ctx);
1192
+
1193
+ $out = [
1194
+ 'status' => $result->status,
1195
+ 'statusText' => $result->status_text,
1196
+ ];
1197
+ if ($result->err !== null) {
1198
+ $err_msg = ($result->err instanceof ProjectNameError) ? $result->err->msg : (string)$result->err;
1199
+ $out['err'] = ['message' => $err_msg];
1200
+ }
1201
+
1202
+ return [$out, null];
1203
+ });
1204
+ }
1205
+
1206
+
1207
+ // === Test: resultBody-basic ===
1208
+
1209
+ public function test_result_body_basic(): void
1210
+ {
1211
+ $spec = self::load_test_spec();
1212
+ $primary = self::get_spec($spec, 'primary');
1213
+ $client = ProjectNameSDK::test(null, null);
1214
+ $utility = $client->get_utility();
1215
+
1216
+ $this->runset(self::get_spec($primary, 'resultBody', 'basic'), function (array &$entry) use ($client, $utility) {
1217
+ $ctxmap = $entry['ctx'] ?? [];
1218
+ $ctx = self::make_ctx_from_map($ctxmap, $client, $utility);
1219
+
1220
+ ($utility->result_body)($ctx);
1221
+
1222
+ // Update entry ctx for match
1223
+ if ($ctx->result !== null) {
1224
+ $entry['ctx']['result'] = [
1225
+ 'body' => $ctx->result->body,
1226
+ ];
1227
+ }
1228
+
1229
+ return [null, null];
1230
+ });
1231
+ }
1232
+
1233
+
1234
+ // === Test: resultHeaders-basic ===
1235
+
1236
+ public function test_result_headers_basic(): void
1237
+ {
1238
+ $spec = self::load_test_spec();
1239
+ $primary = self::get_spec($spec, 'primary');
1240
+ $client = ProjectNameSDK::test(null, null);
1241
+ $utility = $client->get_utility();
1242
+
1243
+ $this->runset(self::get_spec($primary, 'resultHeaders', 'basic'), function (array &$entry) use ($client, $utility) {
1244
+ $ctxmap = $entry['ctx'] ?? [];
1245
+ $ctx = self::make_ctx_from_map($ctxmap, $client, $utility);
1246
+
1247
+ ($utility->result_headers)($ctx);
1248
+
1249
+ // Update entry ctx for match
1250
+ if ($ctx->result !== null) {
1251
+ $entry['ctx']['result'] = [
1252
+ 'headers' => $ctx->result->headers,
1253
+ ];
1254
+ }
1255
+
1256
+ return [null, null];
1257
+ });
1258
+ }
1259
+
1260
+
1261
+ // === Test: transformRequest-basic ===
1262
+
1263
+ public function test_transform_request_basic(): void
1264
+ {
1265
+ $spec = self::load_test_spec();
1266
+ $primary = self::get_spec($spec, 'primary');
1267
+ $client = ProjectNameSDK::test(null, null);
1268
+ $utility = $client->get_utility();
1269
+
1270
+ $this->runset(self::get_spec($primary, 'transformRequest', 'basic'), function (array &$entry) use ($client, $utility) {
1271
+ $ctxmap = $entry['ctx'] ?? [];
1272
+ $ctx = self::make_ctx_from_map($ctxmap, $client, $utility);
1273
+
1274
+ $result = ($utility->transform_request)($ctx);
1275
+
1276
+ // Update entry ctx for match (step changed)
1277
+ if ($ctx->spec !== null && isset($entry['ctx']['spec']) && is_array($entry['ctx']['spec'])) {
1278
+ $entry['ctx']['spec']['step'] = $ctx->spec->step;
1279
+ }
1280
+
1281
+ return [$result, null];
1282
+ });
1283
+ }
1284
+
1285
+
1286
+ // === Test: transformResponse-basic ===
1287
+
1288
+ public function test_transform_response_basic(): void
1289
+ {
1290
+ $spec = self::load_test_spec();
1291
+ $primary = self::get_spec($spec, 'primary');
1292
+ $client = ProjectNameSDK::test(null, null);
1293
+ $utility = $client->get_utility();
1294
+
1295
+ $this->runset(self::get_spec($primary, 'transformResponse', 'basic'), function (array &$entry) use ($client, $utility) {
1296
+ $ctxmap = $entry['ctx'] ?? [];
1297
+ $ctx = self::make_ctx_from_map($ctxmap, $client, $utility);
1298
+
1299
+ $result = ($utility->transform_response)($ctx);
1300
+
1301
+ // Update entry ctx for match (step changed)
1302
+ if ($ctx->spec !== null && isset($entry['ctx']['spec']) && is_array($entry['ctx']['spec'])) {
1303
+ $entry['ctx']['spec']['step'] = $ctx->spec->step;
1304
+ }
1305
+
1306
+ return [$result, null];
1307
+ });
1308
+ }
1309
+ }