@voxgig/sdkgen 0.25.0 → 0.28.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 (213) hide show
  1. package/bin/voxgig-sdkgen +6 -6
  2. package/dist/action/action.js +1 -2
  3. package/dist/action/action.js.map +1 -1
  4. package/dist/action/feature.js +4 -2
  5. package/dist/action/feature.js.map +1 -1
  6. package/dist/action/target.js +4 -2
  7. package/dist/action/target.js.map +1 -1
  8. package/dist/cmp/Entity.js +2 -1
  9. package/dist/cmp/Entity.js.map +1 -1
  10. package/dist/cmp/Feature.js +11 -9
  11. package/dist/cmp/Feature.js.map +1 -1
  12. package/dist/cmp/FeatureHook.js +2 -1
  13. package/dist/cmp/FeatureHook.js.map +1 -1
  14. package/dist/cmp/Main.js +6 -2
  15. package/dist/cmp/Main.js.map +1 -1
  16. package/dist/cmp/ReadmeEntity.js +2 -1
  17. package/dist/cmp/ReadmeEntity.js.map +1 -1
  18. package/dist/cmp/Test.d.ts +2 -0
  19. package/dist/cmp/Test.js +17 -0
  20. package/dist/cmp/Test.js.map +1 -0
  21. package/dist/sdkgen.d.ts +2 -1
  22. package/dist/sdkgen.js +17 -28
  23. package/dist/sdkgen.js.map +1 -1
  24. package/dist/tsconfig.tsbuildinfo +1 -1
  25. package/dist/types.d.ts +3 -1
  26. package/dist/types.js +4 -0
  27. package/dist/types.js.map +1 -1
  28. package/model/sdkgen.jsonic +9 -9
  29. package/package.json +8 -6
  30. package/project/.sdk/model/feature/log.jsonic +3 -3
  31. package/project/.sdk/model/feature/test.jsonic +8 -3
  32. package/project/.sdk/model/target/go.jsonic +19 -4
  33. package/project/.sdk/model/target/js.jsonic +2 -2
  34. package/project/.sdk/model/target/ts.jsonic +5 -5
  35. package/project/.sdk/src/cmp/go/Config_go.ts +119 -0
  36. package/project/.sdk/src/cmp/go/EntityOperation_go.ts +48 -0
  37. package/project/.sdk/src/cmp/go/Entity_go.ts +67 -0
  38. package/project/.sdk/src/cmp/go/MainEntity_go.ts +22 -0
  39. package/project/.sdk/src/cmp/go/Main_go.ts +209 -0
  40. package/project/.sdk/src/cmp/go/Package_go.ts +89 -0
  41. package/project/.sdk/src/cmp/go/TestDirect_go.ts +373 -0
  42. package/project/.sdk/src/cmp/go/TestEntity_go.ts +341 -0
  43. package/project/.sdk/src/cmp/go/Test_go.ts +37 -0
  44. package/project/.sdk/src/cmp/go/fragment/Entity.fragment.go +146 -0
  45. package/project/.sdk/src/cmp/go/fragment/EntityCreateOp.fragment.go +35 -0
  46. package/project/.sdk/src/cmp/go/fragment/EntityListOp.fragment.go +26 -0
  47. package/project/.sdk/src/cmp/go/fragment/EntityLoadOp.fragment.go +38 -0
  48. package/project/.sdk/src/cmp/go/fragment/EntityRemoveOp.fragment.go +38 -0
  49. package/project/.sdk/src/cmp/go/fragment/EntityUpdateOp.fragment.go +38 -0
  50. package/project/.sdk/src/cmp/go/fragment/Main.fragment.go +250 -0
  51. package/project/.sdk/src/cmp/go/fragment/SdkError.fragment.go +22 -0
  52. package/project/.sdk/src/cmp/go/tsconfig.json +15 -0
  53. package/project/.sdk/src/cmp/go/utility_go.ts +88 -0
  54. package/project/.sdk/src/cmp/js/Main_js.ts +3 -3
  55. package/project/.sdk/src/cmp/js/Quick_js.ts +1 -1
  56. package/project/.sdk/src/cmp/js/fragment/EntityCreateOp.fragment.js +6 -6
  57. package/project/.sdk/src/cmp/js/fragment/EntityListOp.fragment.js +6 -6
  58. package/project/.sdk/src/cmp/js/fragment/EntityLoadOp.fragment.js +6 -6
  59. package/project/.sdk/src/cmp/js/fragment/EntityRemoveOp.fragment.js +6 -6
  60. package/project/.sdk/src/cmp/js/fragment/EntityUpdateOp.fragment.js +6 -6
  61. package/project/.sdk/src/cmp/js/fragment/Main.fragment.js +85 -1
  62. package/project/.sdk/src/cmp/ts/Config_ts.ts +53 -6
  63. package/project/.sdk/src/cmp/ts/EntityOperation_ts.ts +3 -21
  64. package/project/.sdk/src/cmp/ts/Entity_ts.ts +3 -5
  65. package/project/.sdk/src/cmp/ts/Main_ts.ts +23 -13
  66. package/project/.sdk/src/cmp/ts/Package_ts.ts +30 -11
  67. package/project/.sdk/src/cmp/ts/SdkError_ts.ts +42 -0
  68. package/project/.sdk/src/cmp/ts/TestDirect_ts.ts +288 -0
  69. package/project/.sdk/src/cmp/ts/TestEntity_ts.ts +349 -2
  70. package/project/.sdk/src/cmp/ts/TestMain_ts.ts +0 -3
  71. package/project/.sdk/src/cmp/ts/Test_ts.ts +23 -3
  72. package/project/.sdk/src/cmp/ts/fragment/Config.fragment.ts +38 -5
  73. package/project/.sdk/src/cmp/ts/fragment/Direct.test.fragment.ts +30 -0
  74. package/project/.sdk/src/cmp/ts/fragment/Entity.fragment.ts +50 -38
  75. package/project/.sdk/src/cmp/ts/fragment/Entity.test.fragment.ts +9 -7
  76. package/project/.sdk/src/cmp/ts/fragment/EntityCreateOp.fragment.ts +47 -31
  77. package/project/.sdk/src/cmp/ts/fragment/EntityListOp.fragment.ts +49 -31
  78. package/project/.sdk/src/cmp/ts/fragment/EntityLoadOp.fragment.ts +50 -33
  79. package/project/.sdk/src/cmp/ts/fragment/EntityRemoveOp.fragment.ts +51 -32
  80. package/project/.sdk/src/cmp/ts/fragment/EntityUpdateOp.fragment.ts +51 -31
  81. package/project/.sdk/src/cmp/ts/fragment/Main.fragment.ts +166 -34
  82. package/project/.sdk/src/cmp/ts/fragment/SdkError.fragment.ts +25 -0
  83. package/project/.sdk/src/cmp/ts/tsconfig.json +15 -0
  84. package/project/.sdk/src/cmp/ts/utility_ts.ts +55 -1
  85. package/project/.sdk/tm/go/Makefile +10 -0
  86. package/project/.sdk/tm/go/core/context.go +267 -0
  87. package/project/.sdk/tm/go/core/control.go +7 -0
  88. package/project/.sdk/tm/go/core/error.go +25 -0
  89. package/project/.sdk/tm/go/core/helpers.go +33 -0
  90. package/project/.sdk/tm/go/core/operation.go +61 -0
  91. package/project/.sdk/tm/go/core/response.go +55 -0
  92. package/project/.sdk/tm/go/core/result.go +73 -0
  93. package/project/.sdk/tm/go/core/spec.go +97 -0
  94. package/project/.sdk/tm/go/core/target.go +102 -0
  95. package/project/.sdk/tm/go/core/types.go +44 -0
  96. package/project/.sdk/tm/go/core/utility_type.go +54 -0
  97. package/project/.sdk/tm/go/feature/base_feature.go +40 -0
  98. package/project/.sdk/tm/go/feature/test_feature.go +196 -0
  99. package/project/.sdk/tm/go/src/feature/README.md +1 -0
  100. package/project/.sdk/tm/go/src/feature/base/.gitkeep +0 -0
  101. package/project/.sdk/tm/go/src/feature/test/.gitkeep +0 -0
  102. package/project/.sdk/tm/go/test/custom_utility_test.go +80 -0
  103. package/project/.sdk/tm/go/test/exists_test.go +16 -0
  104. package/project/.sdk/tm/go/test/primary_utility_test.go +899 -0
  105. package/project/.sdk/tm/go/test/runner_test.go +428 -0
  106. package/project/.sdk/tm/go/test/struct_runner_test.go +1094 -0
  107. package/project/.sdk/tm/go/test/struct_utility_test.go +1423 -0
  108. package/project/.sdk/tm/go/utility/clean.go +7 -0
  109. package/project/.sdk/tm/go/utility/done.go +20 -0
  110. package/project/.sdk/tm/go/utility/feature_add.go +10 -0
  111. package/project/.sdk/tm/go/utility/feature_hook.go +30 -0
  112. package/project/.sdk/tm/go/utility/feature_init.go +30 -0
  113. package/project/.sdk/tm/go/utility/fetcher.go +102 -0
  114. package/project/.sdk/tm/go/utility/make_context.go +7 -0
  115. package/project/.sdk/tm/go/utility/make_error.go +69 -0
  116. package/project/.sdk/tm/go/utility/make_fetch_def.go +44 -0
  117. package/project/.sdk/tm/go/utility/make_options.go +130 -0
  118. package/project/.sdk/tm/go/utility/make_request.go +59 -0
  119. package/project/.sdk/tm/go/utility/make_response.go +46 -0
  120. package/project/.sdk/tm/go/utility/make_result.go +55 -0
  121. package/project/.sdk/tm/go/utility/make_spec.go +68 -0
  122. package/project/.sdk/tm/go/utility/make_target.go +95 -0
  123. package/project/.sdk/tm/go/utility/make_url.go +41 -0
  124. package/project/.sdk/tm/go/utility/param.go +66 -0
  125. package/project/.sdk/tm/go/utility/prepare_auth.go +40 -0
  126. package/project/.sdk/tm/go/utility/prepare_body.go +14 -0
  127. package/project/.sdk/tm/go/utility/prepare_headers.go +22 -0
  128. package/project/.sdk/tm/go/utility/prepare_method.go +21 -0
  129. package/project/.sdk/tm/go/utility/prepare_params.go +41 -0
  130. package/project/.sdk/tm/go/utility/prepare_path.go +21 -0
  131. package/project/.sdk/tm/go/utility/prepare_query.go +47 -0
  132. package/project/.sdk/tm/go/utility/register.go +39 -0
  133. package/project/.sdk/tm/go/utility/result_basic.go +31 -0
  134. package/project/.sdk/tm/go/utility/result_body.go +17 -0
  135. package/project/.sdk/tm/go/utility/result_headers.go +22 -0
  136. package/project/.sdk/tm/go/utility/struct/go.mod +3 -0
  137. package/project/.sdk/tm/go/utility/struct/voxgigstruct.go +4891 -0
  138. package/project/.sdk/tm/go/utility/transform_request.go +32 -0
  139. package/project/.sdk/tm/go/utility/transform_response.go +45 -0
  140. package/project/.sdk/tm/js/src/feature/log/LogFeature.js +2 -2
  141. package/project/.sdk/tm/ts/src/Context.ts +144 -0
  142. package/project/.sdk/tm/ts/src/Control.ts +20 -0
  143. package/project/.sdk/tm/ts/src/Operation.ts +24 -0
  144. package/project/.sdk/tm/ts/src/Response.ts +26 -0
  145. package/project/.sdk/tm/ts/src/Result.ts +30 -0
  146. package/project/.sdk/tm/ts/src/Spec.ts +40 -0
  147. package/project/.sdk/tm/ts/src/Target.ts +36 -0
  148. package/project/.sdk/tm/ts/src/feature/base/BaseFeature.ts +1 -1
  149. package/project/.sdk/tm/ts/src/feature/log/LogFeature.ts +2 -2
  150. package/project/.sdk/tm/ts/src/feature/test/TestFeature.ts +158 -104
  151. package/project/.sdk/tm/ts/src/types.ts +18 -78
  152. package/project/.sdk/tm/ts/src/utility/CleanUtility.ts +17 -31
  153. package/project/.sdk/tm/ts/src/utility/DoneUtility.ts +3 -4
  154. package/project/.sdk/tm/ts/src/utility/{AddfeatureUtility.ts → FeatureAddUtility.ts} +2 -2
  155. package/project/.sdk/tm/ts/src/utility/{FeaturehookUtility.ts → FeatureHookUtility.ts} +8 -5
  156. package/project/.sdk/tm/ts/src/utility/FeatureInitUtility.ts +15 -0
  157. package/project/.sdk/tm/ts/src/utility/FetcherUtility.ts +20 -2
  158. package/project/.sdk/tm/ts/src/utility/MakeContextUtility.ts +27 -0
  159. package/project/.sdk/tm/ts/src/utility/{ErrorUtility.ts → MakeErrorUtility.ts} +10 -6
  160. package/project/.sdk/tm/ts/src/utility/MakeFetchDefUtility.ts +46 -0
  161. package/project/.sdk/tm/ts/src/utility/{OptionsUtility.ts → MakeOptionsUtility.ts} +32 -7
  162. package/project/.sdk/tm/ts/src/utility/MakeRequestUtility.ts +66 -0
  163. package/project/.sdk/tm/ts/src/utility/MakeResponseUtility.ts +61 -0
  164. package/project/.sdk/tm/ts/src/utility/MakeResultUtility.ts +56 -0
  165. package/project/.sdk/tm/ts/src/utility/MakeSpecUtility.ts +61 -0
  166. package/project/.sdk/tm/ts/src/utility/MakeTargetUtility.ts +76 -0
  167. package/project/.sdk/tm/ts/src/utility/MakeUrlUtility.ts +61 -0
  168. package/project/.sdk/tm/ts/src/utility/{FindparamUtility.ts → ParamUtility.ts} +28 -8
  169. package/project/.sdk/tm/ts/src/utility/{AuthUtility.ts → PrepareAuthUtility.ts} +10 -4
  170. package/project/.sdk/tm/ts/src/utility/PrepareBodyUtility.ts +32 -0
  171. package/project/.sdk/tm/ts/src/utility/{HeadersUtility.ts → PrepareHeadersUtility.ts} +5 -7
  172. package/project/.sdk/tm/ts/src/utility/{MethodUtility.ts → PrepareMethodUtility.ts} +6 -6
  173. package/project/.sdk/tm/ts/src/utility/PrepareParamsUtility.ts +37 -0
  174. package/project/.sdk/tm/ts/src/utility/PreparePathUtility.ts +17 -0
  175. package/project/.sdk/tm/ts/src/utility/PrepareQueryUtility.ts +30 -0
  176. package/project/.sdk/tm/ts/src/utility/{ResbasicUtility.ts → ResultBasicUtility.ts} +12 -7
  177. package/project/.sdk/tm/ts/src/utility/ResultBodyUtility.ts +22 -0
  178. package/project/.sdk/tm/ts/src/utility/ResultHeadersUtility.ts +26 -0
  179. package/project/.sdk/tm/ts/src/utility/StructUtility.ts +1113 -525
  180. package/project/.sdk/tm/ts/src/utility/{ReqformUtility.ts → TransformRequestUtility.ts} +9 -7
  181. package/project/.sdk/tm/ts/src/utility/{ResformUtility.ts → TransformResponseUtility.ts} +11 -8
  182. package/project/.sdk/tm/ts/src/utility/Utility.ts +52 -65
  183. package/project/.sdk/tm/ts/test/exists.test.ts +0 -1
  184. package/project/.sdk/tm/ts/test/runner.ts +36 -13
  185. package/project/.sdk/tm/ts/test/utility/Custom.test.ts +30 -29
  186. package/project/.sdk/tm/ts/test/utility/PrimaryUtility.test.ts +385 -168
  187. package/project/.sdk/tm/ts/test/utility/StructUtility.test.ts +433 -189
  188. package/src/action/action.ts +1 -2
  189. package/src/action/feature.ts +7 -2
  190. package/src/action/target.ts +7 -7
  191. package/src/cmp/Entity.ts +7 -1
  192. package/src/cmp/Feature.ts +11 -9
  193. package/src/cmp/FeatureHook.ts +6 -1
  194. package/src/cmp/Main.ts +12 -2
  195. package/src/cmp/ReadmeEntity.ts +6 -1
  196. package/src/cmp/Test.ts +31 -0
  197. package/src/sdkgen.ts +19 -34
  198. package/src/types.ts +10 -1
  199. package/project/.sdk/src/cmp/ts/EntityTest_ts.ts +0 -180
  200. package/project/.sdk/tm/ts/src/utility/BodyUtility.ts +0 -29
  201. package/project/.sdk/tm/ts/src/utility/ContextUtility.ts +0 -67
  202. package/project/.sdk/tm/ts/src/utility/FullurlUtility.ts +0 -46
  203. package/project/.sdk/tm/ts/src/utility/InitfeatureUtility.ts +0 -13
  204. package/project/.sdk/tm/ts/src/utility/JoinurlUtility.ts +0 -15
  205. package/project/.sdk/tm/ts/src/utility/OperatorUtility.ts +0 -90
  206. package/project/.sdk/tm/ts/src/utility/ParamsUtility.ts +0 -37
  207. package/project/.sdk/tm/ts/src/utility/QueryUtility.ts +0 -27
  208. package/project/.sdk/tm/ts/src/utility/RequestUtility.ts +0 -66
  209. package/project/.sdk/tm/ts/src/utility/ResbodyUtility.ts +0 -19
  210. package/project/.sdk/tm/ts/src/utility/ResheadersUtility.ts +0 -23
  211. package/project/.sdk/tm/ts/src/utility/ResponseUtility.ts +0 -30
  212. package/project/.sdk/tm/ts/src/utility/ResultUtility.ts +0 -36
  213. package/project/.sdk/tm/ts/src/utility/SpecUtility.ts +0 -61
@@ -0,0 +1,899 @@
1
+ package sdktest
2
+
3
+ import (
4
+ "strings"
5
+ "testing"
6
+
7
+ sdk "GOMODULE"
8
+
9
+ vs "github.com/voxgig/struct"
10
+ )
11
+
12
+ func TestPrimaryUtility(t *testing.T) {
13
+ spec := loadTestSpec(t)
14
+ primary := getSpec(spec, "primary")
15
+ if primary == nil {
16
+ t.Fatal("primary section not found in test.json")
17
+ }
18
+
19
+ client := sdk.TestSDK(nil, nil)
20
+ utility := client.GetUtility()
21
+
22
+ t.Run("exists", func(t *testing.T) {
23
+ if utility.Clean == nil {
24
+ t.Error("Clean should not be nil")
25
+ }
26
+ if utility.Done == nil {
27
+ t.Error("Done should not be nil")
28
+ }
29
+ if utility.MakeError == nil {
30
+ t.Error("MakeError should not be nil")
31
+ }
32
+ if utility.FeatureAdd == nil {
33
+ t.Error("FeatureAdd should not be nil")
34
+ }
35
+ if utility.FeatureHook == nil {
36
+ t.Error("FeatureHook should not be nil")
37
+ }
38
+ if utility.FeatureInit == nil {
39
+ t.Error("FeatureInit should not be nil")
40
+ }
41
+ if utility.Fetcher == nil {
42
+ t.Error("Fetcher should not be nil")
43
+ }
44
+ if utility.MakeFetchDef == nil {
45
+ t.Error("MakeFetchDef should not be nil")
46
+ }
47
+ if utility.MakeContext == nil {
48
+ t.Error("MakeContext should not be nil")
49
+ }
50
+ if utility.MakeOptions == nil {
51
+ t.Error("MakeOptions should not be nil")
52
+ }
53
+ if utility.MakeRequest == nil {
54
+ t.Error("MakeRequest should not be nil")
55
+ }
56
+ if utility.MakeResponse == nil {
57
+ t.Error("MakeResponse should not be nil")
58
+ }
59
+ if utility.MakeResult == nil {
60
+ t.Error("MakeResult should not be nil")
61
+ }
62
+ if utility.MakeTarget == nil {
63
+ t.Error("MakeTarget should not be nil")
64
+ }
65
+ if utility.MakeSpec == nil {
66
+ t.Error("MakeSpec should not be nil")
67
+ }
68
+ if utility.MakeUrl == nil {
69
+ t.Error("MakeUrl should not be nil")
70
+ }
71
+ if utility.Param == nil {
72
+ t.Error("Param should not be nil")
73
+ }
74
+ if utility.PrepareAuth == nil {
75
+ t.Error("PrepareAuth should not be nil")
76
+ }
77
+ if utility.PrepareBody == nil {
78
+ t.Error("PrepareBody should not be nil")
79
+ }
80
+ if utility.PrepareHeaders == nil {
81
+ t.Error("PrepareHeaders should not be nil")
82
+ }
83
+ if utility.PrepareMethod == nil {
84
+ t.Error("PrepareMethod should not be nil")
85
+ }
86
+ if utility.PrepareParams == nil {
87
+ t.Error("PrepareParams should not be nil")
88
+ }
89
+ if utility.PreparePath == nil {
90
+ t.Error("PreparePath should not be nil")
91
+ }
92
+ if utility.PrepareQuery == nil {
93
+ t.Error("PrepareQuery should not be nil")
94
+ }
95
+ if utility.ResultBasic == nil {
96
+ t.Error("ResultBasic should not be nil")
97
+ }
98
+ if utility.ResultBody == nil {
99
+ t.Error("ResultBody should not be nil")
100
+ }
101
+ if utility.ResultHeaders == nil {
102
+ t.Error("ResultHeaders should not be nil")
103
+ }
104
+ if utility.TransformRequest == nil {
105
+ t.Error("TransformRequest should not be nil")
106
+ }
107
+ if utility.TransformResponse == nil {
108
+ t.Error("TransformResponse should not be nil")
109
+ }
110
+ })
111
+
112
+ t.Run("clean-basic", func(t *testing.T) {
113
+ ctx := makeTestCtx(client, utility, nil)
114
+ val := map[string]any{"key": "secret123", "name": "test"}
115
+ cleaned := utility.Clean(ctx, val)
116
+ if cleaned == nil {
117
+ t.Error("cleaned should not be nil")
118
+ }
119
+ })
120
+
121
+ t.Run("done-basic", func(t *testing.T) {
122
+ runset(t, getSpec(primary, "done", "basic"), func(entry map[string]any) (any, error) {
123
+ ctxmap, _ := entry["ctx"].(map[string]any)
124
+ ctx := makeCtxFromMap(ctxmap, client, utility)
125
+ fixctx(ctx, client)
126
+ return utility.Done(ctx)
127
+ })
128
+ })
129
+
130
+ t.Run("makeError-basic", func(t *testing.T) {
131
+ runset(t, getSpec(primary, "makeError", "basic"), func(entry map[string]any) (any, error) {
132
+ args, _ := entry["args"].([]any)
133
+ if len(args) == 0 {
134
+ args = []any{map[string]any{}}
135
+ }
136
+
137
+ ctxmap, _ := args[0].(map[string]any)
138
+ if ctxmap == nil {
139
+ ctxmap = map[string]any{}
140
+ }
141
+ ctx := makeCtxFromMap(ctxmap, client, utility)
142
+ fixctx(ctx, client)
143
+
144
+ var err error
145
+ if len(args) > 1 {
146
+ if errMap, ok := args[1].(map[string]any); ok {
147
+ err = errFromMap(errMap)
148
+ }
149
+ }
150
+
151
+ return utility.MakeError(ctx, err)
152
+ })
153
+ })
154
+
155
+ t.Run("makeError-no-throw", func(t *testing.T) {
156
+ ctx := makeTestFullCtx(client, utility)
157
+ f := false
158
+ ctx.Ctrl.Throw = &f
159
+ ctx.Result = sdk.NewResult(map[string]any{
160
+ "ok": false,
161
+ "resdata": map[string]any{"id": "safe01"},
162
+ })
163
+
164
+ out, err := utility.MakeError(ctx, ctx.MakeError("test_code", "test message"))
165
+ if err != nil {
166
+ t.Errorf("expected no error, got: %v", err)
167
+ }
168
+ if outMap, ok := out.(map[string]any); ok {
169
+ if outMap["id"] != "safe01" {
170
+ t.Errorf("expected id=safe01, got: %v", outMap["id"])
171
+ }
172
+ } else {
173
+ t.Errorf("expected map result, got: %T", out)
174
+ }
175
+ })
176
+
177
+ t.Run("featureAdd-basic", func(t *testing.T) {
178
+ ctx := makeTestCtx(client, utility, nil)
179
+ startLen := len(client.Features)
180
+
181
+ feature := sdk.NewBaseFeature()
182
+ utility.FeatureAdd(ctx, feature)
183
+
184
+ if len(client.Features) != startLen+1 {
185
+ t.Errorf("expected %d features, got %d", startLen+1, len(client.Features))
186
+ }
187
+ })
188
+
189
+ t.Run("featureHook-basic", func(t *testing.T) {
190
+ hookClient := sdk.TestSDK(nil, nil)
191
+ hookUtility := hookClient.GetUtility()
192
+ ctx := makeTestCtx(hookClient, hookUtility, nil)
193
+
194
+ called := false
195
+ hookFeature := &testHookFeature{
196
+ BaseFeature: sdk.NewBaseFeature(),
197
+ hookFn: func() { called = true },
198
+ }
199
+ hookClient.Features = []sdk.Feature{hookFeature}
200
+
201
+ hookUtility.FeatureHook(ctx, "TestHook")
202
+ if !called {
203
+ t.Error("expected TestHook to be called")
204
+ }
205
+ })
206
+
207
+ t.Run("featureInit-basic", func(t *testing.T) {
208
+ initClient := sdk.TestSDK(nil, nil)
209
+ initUtility := initClient.GetUtility()
210
+ ctx := makeTestCtx(initClient, initUtility, nil)
211
+ ctx.Options["feature"] = map[string]any{
212
+ "initfeat": map[string]any{"active": true},
213
+ }
214
+
215
+ initCalled := false
216
+ feature := &testInitFeature{
217
+ BaseFeature: sdk.NewBaseFeature(),
218
+ name: "initfeat",
219
+ active: true,
220
+ initFn: func() { initCalled = true },
221
+ }
222
+
223
+ initUtility.FeatureInit(ctx, feature)
224
+ if !initCalled {
225
+ t.Error("expected init to be called")
226
+ }
227
+ })
228
+
229
+ t.Run("featureInit-inactive", func(t *testing.T) {
230
+ initClient := sdk.TestSDK(nil, nil)
231
+ initUtility := initClient.GetUtility()
232
+ ctx := makeTestCtx(initClient, initUtility, nil)
233
+ ctx.Options["feature"] = map[string]any{
234
+ "nofeat": map[string]any{"active": false},
235
+ }
236
+
237
+ initCalled := false
238
+ feature := &testInitFeature{
239
+ BaseFeature: sdk.NewBaseFeature(),
240
+ name: "nofeat",
241
+ active: false,
242
+ initFn: func() { initCalled = true },
243
+ }
244
+
245
+ initUtility.FeatureInit(ctx, feature)
246
+ if initCalled {
247
+ t.Error("expected init NOT to be called for inactive feature")
248
+ }
249
+ })
250
+
251
+ t.Run("fetcher-live", func(t *testing.T) {
252
+ calls := []map[string]any{}
253
+ liveClient := sdk.NewProjectNameSDK(map[string]any{
254
+ "system": map[string]any{
255
+ "fetch": func(url string, fetchdef map[string]any) (map[string]any, error) {
256
+ calls = append(calls, map[string]any{"url": url, "init": fetchdef})
257
+ return map[string]any{"status": 200, "statusText": "OK"}, nil
258
+ },
259
+ },
260
+ })
261
+ liveUtility := liveClient.GetUtility()
262
+ ctx := liveUtility.MakeContext(map[string]any{
263
+ "opname": "load",
264
+ "client": liveClient,
265
+ "utility": liveUtility,
266
+ }, nil)
267
+
268
+ fetchdef := map[string]any{"method": "GET", "headers": map[string]any{}}
269
+ _, err := liveUtility.Fetcher(ctx, "http://example.com/test", fetchdef)
270
+ if err != nil {
271
+ t.Errorf("expected no error, got: %v", err)
272
+ }
273
+ if len(calls) != 1 {
274
+ t.Errorf("expected 1 call, got %d", len(calls))
275
+ }
276
+ if calls[0]["url"] != "http://example.com/test" {
277
+ t.Errorf("expected url http://example.com/test, got %v", calls[0]["url"])
278
+ }
279
+ })
280
+
281
+ t.Run("fetcher-blocked-test-mode", func(t *testing.T) {
282
+ // Create a live SDK then set mode to test (not using TestSDK, which installs test feature)
283
+ blockedClient := sdk.NewProjectNameSDK(map[string]any{
284
+ "system": map[string]any{
285
+ "fetch": func(url string, fetchdef map[string]any) (map[string]any, error) {
286
+ return map[string]any{}, nil
287
+ },
288
+ },
289
+ })
290
+ blockedClient.Mode = "test"
291
+
292
+ blockedUtility := blockedClient.GetUtility()
293
+ ctx := blockedUtility.MakeContext(map[string]any{
294
+ "opname": "load",
295
+ "client": blockedClient,
296
+ "utility": blockedUtility,
297
+ }, nil)
298
+
299
+ fetchdef := map[string]any{"method": "GET", "headers": map[string]any{}}
300
+ _, err := blockedUtility.Fetcher(ctx, "http://example.com/test", fetchdef)
301
+ if err == nil {
302
+ t.Error("expected error for test mode fetch")
303
+ } else if !strings.Contains(err.Error(), "blocked") {
304
+ t.Errorf("expected error containing 'blocked', got: %v", err)
305
+ }
306
+ })
307
+
308
+ t.Run("makeContext-basic", func(t *testing.T) {
309
+ runset(t, getSpec(primary, "makeContext", "basic"), func(entry map[string]any) (any, error) {
310
+ in := entry["in"]
311
+ if inMap, ok := in.(map[string]any); ok {
312
+ ctx := utility.MakeContext(inMap, nil)
313
+ out := map[string]any{
314
+ "id": ctx.Id,
315
+ }
316
+ if ctx.Op != nil {
317
+ out["op"] = map[string]any{
318
+ "name": ctx.Op.Name,
319
+ "input": ctx.Op.Input,
320
+ }
321
+ }
322
+ return out, nil
323
+ }
324
+ return nil, nil
325
+ })
326
+ })
327
+
328
+ t.Run("makeFetchDef-basic", func(t *testing.T) {
329
+ ctx := makeTestFullCtx(client, utility)
330
+ ctx.Spec = sdk.NewSpec(map[string]any{
331
+ "base": "http://localhost:8080",
332
+ "prefix": "/api",
333
+ "path": "items/{id}",
334
+ "suffix": "",
335
+ "params": map[string]any{"id": "item01"},
336
+ "query": map[string]any{},
337
+ "headers": map[string]any{"content-type": "application/json"},
338
+ "method": "GET",
339
+ "step": "start",
340
+ })
341
+ ctx.Result = sdk.NewResult(map[string]any{})
342
+
343
+ fetchdef, err := utility.MakeFetchDef(ctx)
344
+ if err != nil {
345
+ t.Errorf("should not be error: %v", err)
346
+ return
347
+ }
348
+ if fetchdef["method"] != "GET" {
349
+ t.Errorf("expected method GET, got %v", fetchdef["method"])
350
+ }
351
+ url, _ := fetchdef["url"].(string)
352
+ if !strings.Contains(url, "/api/items/item01") {
353
+ t.Errorf("expected url to contain /api/items/item01, got %v", url)
354
+ }
355
+ if fetchdef["headers"].(map[string]any)["content-type"] != "application/json" {
356
+ t.Error("expected content-type header")
357
+ }
358
+ if fetchdef["body"] != nil {
359
+ t.Error("expected nil body")
360
+ }
361
+ })
362
+
363
+ t.Run("makeFetchDef-with-body", func(t *testing.T) {
364
+ ctx := makeTestFullCtx(client, utility)
365
+ ctx.Spec = sdk.NewSpec(map[string]any{
366
+ "base": "http://localhost:8080",
367
+ "prefix": "",
368
+ "path": "items",
369
+ "suffix": "",
370
+ "params": map[string]any{},
371
+ "query": map[string]any{},
372
+ "headers": map[string]any{},
373
+ "method": "POST",
374
+ "step": "start",
375
+ "body": map[string]any{"name": "test"},
376
+ })
377
+ ctx.Result = sdk.NewResult(map[string]any{})
378
+
379
+ fetchdef, err := utility.MakeFetchDef(ctx)
380
+ if err != nil {
381
+ t.Errorf("should not be error: %v", err)
382
+ return
383
+ }
384
+ if fetchdef["method"] != "POST" {
385
+ t.Errorf("expected method POST, got %v", fetchdef["method"])
386
+ }
387
+ bodyStr, ok := fetchdef["body"].(string)
388
+ if !ok {
389
+ t.Errorf("expected body string, got %T", fetchdef["body"])
390
+ return
391
+ }
392
+ if !strings.Contains(bodyStr, "\"name\"") {
393
+ t.Errorf("expected body to contain name, got %v", bodyStr)
394
+ }
395
+ })
396
+
397
+ t.Run("makeOptions-basic", func(t *testing.T) {
398
+ runset(t, getSpec(primary, "makeOptions", "basic"), func(entry map[string]any) (any, error) {
399
+ in, _ := entry["in"].(map[string]any)
400
+ ctx := utility.MakeContext(map[string]any{
401
+ "options": in["options"],
402
+ "config": in["config"],
403
+ }, nil)
404
+ ctx.Client = client
405
+ ctx.Utility = utility
406
+ return utility.MakeOptions(ctx), nil
407
+ })
408
+ })
409
+
410
+ t.Run("makeRequest-basic", func(t *testing.T) {
411
+ runset(t, getSpec(primary, "makeRequest", "basic"), func(entry map[string]any) (any, error) {
412
+ ctxmap, _ := entry["ctx"].(map[string]any)
413
+ ctx := makeCtxFromMap(ctxmap, client, utility)
414
+ ctx.Options = client.OptionsMap()
415
+
416
+ _, err := utility.MakeRequest(ctx)
417
+ if err != nil {
418
+ return nil, err
419
+ }
420
+
421
+ // Update entry ctx for match checking
422
+ entryCtx, _ := entry["ctx"].(map[string]any)
423
+ if ctx.Response != nil {
424
+ entryCtx["response"] = "exists"
425
+ }
426
+ if ctx.Result != nil {
427
+ entryCtx["result"] = "exists"
428
+ }
429
+
430
+ return nil, nil
431
+ })
432
+ })
433
+
434
+ t.Run("makeResponse-basic", func(t *testing.T) {
435
+ runset(t, getSpec(primary, "makeResponse", "basic"), func(entry map[string]any) (any, error) {
436
+ ctxmap, _ := entry["ctx"].(map[string]any)
437
+ ctx := makeCtxFromMap(ctxmap, client, utility)
438
+ fixctx(ctx, client)
439
+
440
+ _, err := utility.MakeResponse(ctx)
441
+ if err != nil {
442
+ return nil, err
443
+ }
444
+
445
+ // Update entry ctx for match checking with result data
446
+ entryCtx, _ := entry["ctx"].(map[string]any)
447
+ if ctx.Result != nil {
448
+ entryCtx["result"] = map[string]any{
449
+ "ok": ctx.Result.Ok,
450
+ "status": ctx.Result.Status,
451
+ "statusText": ctx.Result.StatusText,
452
+ "headers": ctx.Result.Headers,
453
+ "body": ctx.Result.Body,
454
+ }
455
+ }
456
+
457
+ return nil, nil
458
+ })
459
+ })
460
+
461
+ t.Run("makeResult-basic", func(t *testing.T) {
462
+ ctx := makeTestFullCtx(client, utility)
463
+ ctx.Spec = sdk.NewSpec(map[string]any{
464
+ "base": "http://localhost:8080",
465
+ "prefix": "/api",
466
+ "path": "items/{id}",
467
+ "suffix": "",
468
+ "params": map[string]any{"id": "item01"},
469
+ "query": map[string]any{},
470
+ "headers": map[string]any{},
471
+ "method": "GET",
472
+ "step": "start",
473
+ })
474
+ ctx.Result = sdk.NewResult(map[string]any{
475
+ "ok": true,
476
+ "status": 200,
477
+ "statusText": "OK",
478
+ "headers": map[string]any{},
479
+ "resdata": map[string]any{"id": "item01", "name": "Test"},
480
+ })
481
+
482
+ result, err := utility.MakeResult(ctx)
483
+ if err != nil {
484
+ t.Errorf("expected no error, got: %v", err)
485
+ return
486
+ }
487
+ if result.Status != 200 {
488
+ t.Errorf("expected status 200, got %d", result.Status)
489
+ }
490
+ })
491
+
492
+ t.Run("makeResult-no-spec", func(t *testing.T) {
493
+ ctx := makeTestFullCtx(client, utility)
494
+ ctx.Spec = nil
495
+ ctx.Result = sdk.NewResult(map[string]any{
496
+ "ok": true,
497
+ "status": 200,
498
+ "statusText": "OK",
499
+ "headers": map[string]any{},
500
+ })
501
+
502
+ _, err := utility.MakeResult(ctx)
503
+ if err == nil {
504
+ t.Error("expected error for nil spec")
505
+ }
506
+ })
507
+
508
+ t.Run("makeResult-no-result", func(t *testing.T) {
509
+ ctx := makeTestFullCtx(client, utility)
510
+ ctx.Spec = sdk.NewSpec(map[string]any{"step": "start"})
511
+ ctx.Result = nil
512
+
513
+ _, err := utility.MakeResult(ctx)
514
+ if err == nil {
515
+ t.Error("expected error for nil result")
516
+ }
517
+ })
518
+
519
+ t.Run("makeSpec-basic", func(t *testing.T) {
520
+ setupOpts := getSpec(primary, "makeSpec", "DEF", "setup", "a")
521
+ specClient := sdk.TestSDK(nil, setupOpts)
522
+ specUtility := specClient.GetUtility()
523
+
524
+ runset(t, getSpec(primary, "makeSpec", "basic"), func(entry map[string]any) (any, error) {
525
+ ctxmap, _ := entry["ctx"].(map[string]any)
526
+ ctx := makeCtxFromMap(ctxmap, specClient, specUtility)
527
+ ctx.Options = specClient.OptionsMap()
528
+
529
+ _, err := utility.MakeSpec(ctx)
530
+ if err != nil {
531
+ return nil, err
532
+ }
533
+
534
+ // Update entry ctx for match
535
+ entryCtx, _ := entry["ctx"].(map[string]any)
536
+ if ctx.Spec != nil {
537
+ entryCtx["spec"] = map[string]any{
538
+ "base": ctx.Spec.Base,
539
+ "prefix": ctx.Spec.Prefix,
540
+ "suffix": ctx.Spec.Suffix,
541
+ "method": ctx.Spec.Method,
542
+ "params": ctx.Spec.Params,
543
+ "query": ctx.Spec.Query,
544
+ "headers": ctx.Spec.Headers,
545
+ "step": ctx.Spec.Step,
546
+ }
547
+ }
548
+
549
+ return nil, nil
550
+ })
551
+ })
552
+
553
+ t.Run("makeTarget-basic", func(t *testing.T) {
554
+ ctx := makeTestCtx(client, utility, nil)
555
+ target := map[string]any{
556
+ "parts": []any{"items", "{id}"},
557
+ "args": map[string]any{"params": []any{}},
558
+ "params": []any{},
559
+ "alias": map[string]any{},
560
+ "select": map[string]any{},
561
+ "active": true,
562
+ "transform": map[string]any{},
563
+ }
564
+ ctx.Op.Targets = []map[string]any{target}
565
+
566
+ _, err := utility.MakeTarget(ctx)
567
+ if err != nil {
568
+ t.Errorf("expected no error, got: %v", err)
569
+ return
570
+ }
571
+ if ctx.Target == nil {
572
+ t.Error("expected target to be set")
573
+ }
574
+ })
575
+
576
+ t.Run("makeUrl-basic", func(t *testing.T) {
577
+ runset(t, getSpec(primary, "makeUrl", "basic"), func(entry map[string]any) (any, error) {
578
+ ctxmap, _ := entry["ctx"].(map[string]any)
579
+ ctx := makeCtxFromMap(ctxmap, client, utility)
580
+ if ctx.Result == nil {
581
+ ctx.Result = sdk.NewResult(map[string]any{})
582
+ }
583
+ return utility.MakeUrl(ctx)
584
+ })
585
+ })
586
+
587
+ t.Run("operator-basic", func(t *testing.T) {
588
+ runset(t, getSpec(primary, "operator", "basic"), func(entry map[string]any) (any, error) {
589
+ in, _ := entry["in"].(map[string]any)
590
+ op := sdk.NewOperation(in)
591
+ return map[string]any{
592
+ "entity": op.Entity,
593
+ "name": op.Name,
594
+ "input": op.Input,
595
+ "targets": op.Targets,
596
+ }, nil
597
+ })
598
+ })
599
+
600
+ t.Run("param-basic", func(t *testing.T) {
601
+ runset(t, getSpec(primary, "param", "basic"), func(entry map[string]any) (any, error) {
602
+ args, _ := entry["args"].([]any)
603
+ if len(args) < 2 {
604
+ return nil, nil
605
+ }
606
+
607
+ ctxmap, _ := args[0].(map[string]any)
608
+ if ctxmap == nil {
609
+ ctxmap = map[string]any{}
610
+ }
611
+ ctx := makeCtxFromMap(ctxmap, client, utility)
612
+ paramdef := args[1]
613
+
614
+ result := utility.Param(ctx, paramdef)
615
+
616
+ // Update entry ctx for match
617
+ if matchSpec, ok := entry["match"].(map[string]any); ok {
618
+ if ctxMatch, ok := matchSpec["ctx"].(map[string]any); ok {
619
+ entryCtx, _ := entry["ctx"].(map[string]any)
620
+ if entryCtx == nil {
621
+ entryCtx = map[string]any{}
622
+ entry["ctx"] = entryCtx
623
+ }
624
+ // Copy spec alias back to entry ctx for matching
625
+ if specMatch, ok := ctxMatch["spec"].(map[string]any); ok {
626
+ if ctx.Spec != nil {
627
+ if entryCtx["spec"] == nil {
628
+ entryCtx["spec"] = map[string]any{}
629
+ }
630
+ if aliasMatch, ok := specMatch["alias"].(map[string]any); ok {
631
+ _ = aliasMatch
632
+ entryCtx["spec"] = map[string]any{
633
+ "alias": ctx.Spec.Alias,
634
+ }
635
+ }
636
+ }
637
+ }
638
+ }
639
+ }
640
+
641
+ return result, nil
642
+ })
643
+ })
644
+
645
+ t.Run("prepareAuth-basic", func(t *testing.T) {
646
+ setupOpts := getSpec(primary, "prepareAuth", "DEF", "setup", "a")
647
+ authClient := sdk.TestSDK(nil, setupOpts)
648
+ authUtility := authClient.GetUtility()
649
+
650
+ runset(t, getSpec(primary, "prepareAuth", "basic"), func(entry map[string]any) (any, error) {
651
+ ctxmap, _ := entry["ctx"].(map[string]any)
652
+ ctx := makeCtxFromMap(ctxmap, authClient, authUtility)
653
+ fixctx(ctx, authClient)
654
+
655
+ _, err := utility.PrepareAuth(ctx)
656
+ if err != nil {
657
+ return nil, err
658
+ }
659
+
660
+ // Update entry ctx for match
661
+ entryCtx, _ := entry["ctx"].(map[string]any)
662
+ if ctx.Spec != nil {
663
+ entryCtx["spec"] = map[string]any{
664
+ "headers": ctx.Spec.Headers,
665
+ }
666
+ }
667
+
668
+ return nil, nil
669
+ })
670
+ })
671
+
672
+ t.Run("prepareBody-basic", func(t *testing.T) {
673
+ runset(t, getSpec(primary, "prepareBody", "basic"), func(entry map[string]any) (any, error) {
674
+ ctxmap, _ := entry["ctx"].(map[string]any)
675
+ ctx := makeCtxFromMap(ctxmap, client, utility)
676
+ fixctx(ctx, client)
677
+ return utility.PrepareBody(ctx), nil
678
+ })
679
+ })
680
+
681
+ t.Run("prepareHeaders-basic", func(t *testing.T) {
682
+ runset(t, getSpec(primary, "prepareHeaders", "basic"), func(entry map[string]any) (any, error) {
683
+ ctxmap, _ := entry["ctx"].(map[string]any)
684
+ ctx := makeCtxFromMap(ctxmap, client, utility)
685
+ return utility.PrepareHeaders(ctx), nil
686
+ })
687
+ })
688
+
689
+ t.Run("prepareMethod-basic", func(t *testing.T) {
690
+ runset(t, getSpec(primary, "prepareMethod", "basic"), func(entry map[string]any) (any, error) {
691
+ ctxmap, _ := entry["ctx"].(map[string]any)
692
+ ctx := makeCtxFromMap(ctxmap, client, utility)
693
+ return utility.PrepareMethod(ctx), nil
694
+ })
695
+ })
696
+
697
+ t.Run("prepareParams-basic", func(t *testing.T) {
698
+ runset(t, getSpec(primary, "prepareParams", "basic"), func(entry map[string]any) (any, error) {
699
+ ctxmap, _ := entry["ctx"].(map[string]any)
700
+ ctx := makeCtxFromMap(ctxmap, client, utility)
701
+ return utility.PrepareParams(ctx), nil
702
+ })
703
+ })
704
+
705
+ t.Run("preparePath-basic", func(t *testing.T) {
706
+ ctx := makeTestFullCtx(client, utility)
707
+ ctx.Target = map[string]any{
708
+ "parts": []any{"api", "planet", "{id}"},
709
+ "args": map[string]any{"params": []any{}},
710
+ }
711
+
712
+ path := utility.PreparePath(ctx)
713
+ if path != "api/planet/{id}" {
714
+ t.Errorf("expected api/planet/{id}, got %s", path)
715
+ }
716
+ })
717
+
718
+ t.Run("preparePath-single", func(t *testing.T) {
719
+ ctx := makeTestFullCtx(client, utility)
720
+ ctx.Target = map[string]any{
721
+ "parts": []any{"items"},
722
+ "args": map[string]any{"params": []any{}},
723
+ }
724
+
725
+ path := utility.PreparePath(ctx)
726
+ if path != "items" {
727
+ t.Errorf("expected items, got %s", path)
728
+ }
729
+ })
730
+
731
+ t.Run("prepareQuery-basic", func(t *testing.T) {
732
+ runset(t, getSpec(primary, "prepareQuery", "basic"), func(entry map[string]any) (any, error) {
733
+ ctxmap, _ := entry["ctx"].(map[string]any)
734
+ ctx := makeCtxFromMap(ctxmap, client, utility)
735
+ return utility.PrepareQuery(ctx), nil
736
+ })
737
+ })
738
+
739
+ t.Run("resultBasic-basic", func(t *testing.T) {
740
+ runset(t, getSpec(primary, "resultBasic", "basic"), func(entry map[string]any) (any, error) {
741
+ ctxmap, _ := entry["ctx"].(map[string]any)
742
+ ctx := makeCtxFromMap(ctxmap, client, utility)
743
+ fixctx(ctx, client)
744
+
745
+ result := utility.ResultBasic(ctx)
746
+
747
+ out := map[string]any{
748
+ "status": result.Status,
749
+ "statusText": result.StatusText,
750
+ }
751
+ if result.Err != nil {
752
+ out["err"] = map[string]any{
753
+ "message": result.Err.Error(),
754
+ }
755
+ }
756
+
757
+ return out, nil
758
+ })
759
+ })
760
+
761
+ t.Run("resultBody-basic", func(t *testing.T) {
762
+ runset(t, getSpec(primary, "resultBody", "basic"), func(entry map[string]any) (any, error) {
763
+ ctxmap, _ := entry["ctx"].(map[string]any)
764
+ ctx := makeCtxFromMap(ctxmap, client, utility)
765
+
766
+ utility.ResultBody(ctx)
767
+
768
+ // Update entry ctx for match
769
+ entryCtx, _ := entry["ctx"].(map[string]any)
770
+ if ctx.Result != nil {
771
+ entryCtx["result"] = map[string]any{
772
+ "body": ctx.Result.Body,
773
+ }
774
+ }
775
+
776
+ return nil, nil
777
+ })
778
+ })
779
+
780
+ t.Run("resultHeaders-basic", func(t *testing.T) {
781
+ runset(t, getSpec(primary, "resultHeaders", "basic"), func(entry map[string]any) (any, error) {
782
+ ctxmap, _ := entry["ctx"].(map[string]any)
783
+ ctx := makeCtxFromMap(ctxmap, client, utility)
784
+
785
+ utility.ResultHeaders(ctx)
786
+
787
+ // Update entry ctx for match
788
+ entryCtx, _ := entry["ctx"].(map[string]any)
789
+ if ctx.Result != nil {
790
+ entryCtx["result"] = map[string]any{
791
+ "headers": ctx.Result.Headers,
792
+ }
793
+ }
794
+
795
+ return nil, nil
796
+ })
797
+ })
798
+
799
+ t.Run("transformRequest-basic", func(t *testing.T) {
800
+ runset(t, getSpec(primary, "transformRequest", "basic"), func(entry map[string]any) (any, error) {
801
+ ctxmap, _ := entry["ctx"].(map[string]any)
802
+ ctx := makeCtxFromMap(ctxmap, client, utility)
803
+
804
+ result := utility.TransformRequest(ctx)
805
+
806
+ // Update entry ctx for match (step changed)
807
+ entryCtx, _ := entry["ctx"].(map[string]any)
808
+ if ctx.Spec != nil {
809
+ if specMap, ok := entryCtx["spec"].(map[string]any); ok {
810
+ specMap["step"] = ctx.Spec.Step
811
+ }
812
+ }
813
+
814
+ return result, nil
815
+ })
816
+ })
817
+
818
+ t.Run("transformResponse-basic", func(t *testing.T) {
819
+ runset(t, getSpec(primary, "transformResponse", "basic"), func(entry map[string]any) (any, error) {
820
+ ctxmap, _ := entry["ctx"].(map[string]any)
821
+ ctx := makeCtxFromMap(ctxmap, client, utility)
822
+
823
+ result := utility.TransformResponse(ctx)
824
+
825
+ // Update entry ctx for match (step changed)
826
+ entryCtx, _ := entry["ctx"].(map[string]any)
827
+ if ctx.Spec != nil {
828
+ if specMap, ok := entryCtx["spec"].(map[string]any); ok {
829
+ specMap["step"] = ctx.Spec.Step
830
+ }
831
+ }
832
+
833
+ return result, nil
834
+ })
835
+ })
836
+ }
837
+
838
+ // Helper: test hook feature for featureHook test
839
+ type testHookFeature struct {
840
+ *sdk.BaseFeature
841
+ hookFn func()
842
+ }
843
+
844
+ func (f *testHookFeature) TestHook(ctx *sdk.Context) {
845
+ if f.hookFn != nil {
846
+ f.hookFn()
847
+ }
848
+ }
849
+
850
+ // Helper: test init feature for featureInit test
851
+ type testInitFeature struct {
852
+ *sdk.BaseFeature
853
+ name string
854
+ active bool
855
+ initFn func()
856
+ }
857
+
858
+ func (f *testInitFeature) GetName() string { return f.name }
859
+ func (f *testInitFeature) GetActive() bool { return f.active }
860
+ func (f *testInitFeature) Init(ctx *sdk.Context, options map[string]any) {
861
+ if f.initFn != nil {
862
+ f.initFn()
863
+ }
864
+ }
865
+
866
+ // Helper: create basic test context
867
+ func makeTestCtx(client *sdk.ProjectNameSDK, utility *sdk.Utility, overrides map[string]any) *sdk.Context {
868
+ ctxmap := map[string]any{
869
+ "opname": "load",
870
+ "client": client,
871
+ "utility": utility,
872
+ }
873
+ if overrides != nil {
874
+ for k, v := range overrides {
875
+ ctxmap[k] = v
876
+ }
877
+ }
878
+ return utility.MakeContext(ctxmap, client.GetRootCtx())
879
+ }
880
+
881
+ // Helper: create full test context with target and match
882
+ func makeTestFullCtx(client *sdk.ProjectNameSDK, utility *sdk.Utility) *sdk.Context {
883
+ ctx := makeTestCtx(client, utility, nil)
884
+ ctx.Target = map[string]any{
885
+ "parts": []any{"items", "{id}"},
886
+ "args": map[string]any{"params": []any{map[string]any{"name": "id", "reqd": true}}},
887
+ "params": []any{"id"},
888
+ "alias": map[string]any{},
889
+ "select": map[string]any{},
890
+ "active": true,
891
+ "transform": map[string]any{},
892
+ }
893
+ ctx.Match = map[string]any{"id": "item01"}
894
+ ctx.Reqmatch = map[string]any{"id": "item01"}
895
+ return ctx
896
+ }
897
+
898
+ // useVS prevents unused import error
899
+ var _ = vs.Clone