@voxgig/sdkgen 4.8.1 → 4.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/voxgig-sdkgen +1 -1
- package/dist/action/doctor.d.ts +1 -0
- package/dist/action/doctor.js +50 -2
- package/dist/action/doctor.js.map +1 -1
- package/dist/helpers/naming.js +4 -2
- package/dist/helpers/naming.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/model/sdkgen.aon +21 -0
- package/package.json +2 -2
- package/project/.sdk/model/feature/secrets.aon +120 -18
- package/project/.sdk/model/target/c.aon +10 -0
- package/project/.sdk/model/target/clojure.aon +13 -0
- package/project/.sdk/model/target/cpp.aon +10 -0
- package/project/.sdk/model/target/csharp.aon +9 -0
- package/project/.sdk/model/target/dart.aon +10 -0
- package/project/.sdk/model/target/elixir.aon +9 -0
- package/project/.sdk/model/target/go.aon +13 -0
- package/project/.sdk/model/target/java.aon +9 -0
- package/project/.sdk/model/target/js.aon +7 -0
- package/project/.sdk/model/target/kotlin.aon +9 -0
- package/project/.sdk/model/target/lean.aon +17 -0
- package/project/.sdk/model/target/lua.aon +8 -0
- package/project/.sdk/model/target/ocaml.aon +9 -0
- package/project/.sdk/model/target/perl.aon +8 -0
- package/project/.sdk/model/target/php.aon +8 -0
- package/project/.sdk/model/target/py.aon +13 -0
- package/project/.sdk/model/target/rb.aon +8 -0
- package/project/.sdk/model/target/rust.aon +10 -0
- package/project/.sdk/model/target/scala.aon +21 -2
- package/project/.sdk/model/target/swift.aon +18 -0
- package/project/.sdk/model/target/ts.aon +13 -0
- package/project/.sdk/src/cmp/clojure/Package_clojure.ts +9 -2
- package/project/.sdk/src/cmp/cpp/Gitignore_cpp.ts +3 -0
- package/project/.sdk/src/cmp/dart/Test_dart.ts +2 -0
- package/project/.sdk/src/cmp/elixir/Package_elixir.ts +4 -1
- package/project/.sdk/src/cmp/go/Config_go.ts +59 -2
- package/project/.sdk/src/cmp/go/Main_go.ts +8 -2
- package/project/.sdk/src/cmp/java/Test_java.ts +6 -5
- package/project/.sdk/src/cmp/kotlin/Test_kotlin.ts +6 -5
- package/project/.sdk/src/cmp/lean/Package_lean.ts +23 -0
- package/project/.sdk/src/cmp/lean/ReadmeInstall_lean.ts +1 -0
- package/project/.sdk/src/cmp/lean/ReadmeTopTest_lean.ts +1 -0
- package/project/.sdk/src/cmp/ocaml/Gitignore_ocaml.ts +1 -0
- package/project/.sdk/src/cmp/ocaml/Main_ocaml.ts +7 -3
- package/project/.sdk/src/cmp/py/Config_py.ts +82 -1
- package/project/.sdk/src/cmp/py/Main_py.ts +44 -0
- package/project/.sdk/src/cmp/py/fragment/Main.fragment.py +2 -0
- package/project/.sdk/src/cmp/swift/Main_swift.ts +10 -0
- package/project/.sdk/src/cmp/swift/Package_swift.ts +13 -1
- package/project/.sdk/src/cmp/ts/Config_ts.ts +42 -17
- package/project/.sdk/src/cmp/ts/fragment/Config.data.fragment.ts +13 -1
- package/project/.sdk/src/cmp/ts/fragment/Config.fragment.ts +13 -1
- package/project/.sdk/tm/c/Makefile +38 -3
- package/project/.sdk/tm/c/tests/omni_resolver.h +361 -0
- package/project/.sdk/tm/c/tests/omni_smoke_test.c +237 -0
- package/project/.sdk/tm/c/tests/primary_corpus_test.c +205 -284
- package/project/.sdk/tm/c/tests/struct_corpus_test.c +292 -212
- package/project/.sdk/tm/c/tests/vendor/omni/json.c +811 -0
- package/project/.sdk/tm/c/tests/vendor/omni/omni.h +240 -0
- package/project/.sdk/tm/c/tests/vendor/omni/runner.c +940 -0
- package/project/.sdk/tm/c/tests/vendor/omni/util.c +351 -0
- package/project/.sdk/tm/c/utility/struct/utility.c +7 -2
- package/project/.sdk/tm/clojure/test/sdk/test/omni.clj +401 -0
- package/project/.sdk/tm/clojure/test/sdk/test/omni_smoke.clj +81 -0
- package/project/.sdk/tm/clojure/test/sdk/test/primary.clj +92 -58
- package/project/.sdk/tm/clojure/test/sdk/test/struct_corpus.clj +122 -149
- package/project/.sdk/tm/clojure/test/sdk/test_runner.clj +8 -3
- package/project/.sdk/tm/clojure/test/vendor/omni/voxgig/omni/json.clj +145 -0
- package/project/.sdk/tm/clojure/test/vendor/omni/voxgig/omni/runner.clj +445 -0
- package/project/.sdk/tm/clojure/test/vendor/omni/voxgig/omni/util.clj +145 -0
- package/project/.sdk/tm/cpp/Makefile +5 -1
- package/project/.sdk/tm/cpp/test/omni_resolver.hpp +473 -0
- package/project/.sdk/tm/cpp/test/omni_smoke_test.cpp +209 -0
- package/project/.sdk/tm/cpp/test/primary_utility_test.cpp +243 -184
- package/project/.sdk/tm/cpp/test/runner_support.hpp +68 -181
- package/project/.sdk/tm/cpp/test/struct_corpus_test.cpp +183 -56
- package/project/.sdk/tm/cpp/test/vendor/omni/json.hpp +406 -0
- package/project/.sdk/tm/cpp/test/vendor/omni/omni.hpp +751 -0
- package/project/.sdk/tm/cpp/test/vendor/omni/util.hpp +256 -0
- package/project/.sdk/tm/cpp/utility/pipeline.hpp +7 -1
- package/project/.sdk/tm/csharp/test/OmniResolver.cs +491 -0
- package/project/.sdk/tm/csharp/test/OmniSmokeTest.cs +106 -0
- package/project/.sdk/tm/csharp/test/PrimaryUtilityTest.cs +299 -316
- package/project/.sdk/tm/csharp/test/Runner.cs +104 -269
- package/project/.sdk/tm/csharp/test/StructUtilityTest.cs +535 -724
- package/project/.sdk/tm/csharp/test/vendor/omni/Runner.cs +864 -0
- package/project/.sdk/tm/csharp/test/vendor/omni/Util.cs +347 -0
- package/project/.sdk/tm/csharp/utility/MakeSpec.cs +3 -1
- package/project/.sdk/tm/csharp/utility/PrepareMethod.cs +6 -1
- package/project/.sdk/tm/csharp/utility/struct/Struct.cs +21 -5
- package/project/.sdk/tm/dart/test/omni.dart +520 -0
- package/project/.sdk/tm/dart/test/omni_smoke_test.dart +143 -0
- package/project/.sdk/tm/dart/test/primary_test.dart +86 -28
- package/project/.sdk/tm/dart/test/struct_test.dart +438 -11
- package/project/.sdk/tm/dart/test/vendor/omni/omni.dart +7 -0
- package/project/.sdk/tm/dart/test/vendor/omni/runner.dart +653 -0
- package/project/.sdk/tm/dart/test/vendor/omni/util.dart +232 -0
- package/project/.sdk/tm/elixir/Makefile +11 -3
- package/project/.sdk/tm/elixir/test/omni_smoke_test.exs +117 -0
- package/project/.sdk/tm/elixir/test/primary_utility_test.exs +341 -16
- package/project/.sdk/tm/elixir/test/struct_corpus_test.exs +554 -9
- package/project/.sdk/tm/elixir/test/support/omni.ex +377 -0
- package/project/.sdk/tm/elixir/test/vendor/omni/json.ex +122 -0
- package/project/.sdk/tm/elixir/test/vendor/omni/runner.ex +623 -0
- package/project/.sdk/tm/elixir/test/vendor/omni/util.ex +187 -0
- package/project/.sdk/tm/go/core/context.go +32 -16
- package/project/.sdk/tm/go/feature/secrets/plugin/capability.go +261 -0
- package/project/.sdk/tm/go/feature/secrets/plugin/catalog.go +78 -0
- package/project/.sdk/tm/go/feature/secrets/plugin/config.go +652 -0
- package/project/.sdk/tm/go/feature/secrets/plugin/depend.go +250 -0
- package/project/.sdk/tm/go/feature/secrets/plugin/env.go +194 -0
- package/project/.sdk/tm/go/feature/secrets/plugin/export.go +80 -0
- package/project/.sdk/tm/go/feature/secrets/plugin/graph.go +238 -0
- package/project/.sdk/tm/go/feature/secrets/plugin/host.go +1575 -0
- package/project/.sdk/tm/go/feature/secrets/plugin/order.go +248 -0
- package/project/.sdk/tm/go/feature/secrets/plugin/point.go +184 -0
- package/project/.sdk/tm/go/feature/secrets/plugin/ref.go +123 -0
- package/project/.sdk/tm/go/feature/secrets/plugin/resolve.go +79 -0
- package/project/.sdk/tm/go/feature/secrets/plugin/types.go +296 -0
- package/project/.sdk/tm/go/feature/secrets/plugin/util.go +87 -0
- package/project/.sdk/tm/go/feature/secrets/plugin/version.go +161 -0
- package/project/.sdk/tm/go/feature/secrets/plugins/aws/aws.go +292 -0
- package/project/.sdk/tm/go/feature/secrets/plugins/aws/sigv4.go +201 -0
- package/project/.sdk/tm/go/feature/secrets/plugins/azuresecrets/azuresecrets.go +187 -0
- package/project/.sdk/tm/go/feature/secrets/plugins/boru/boru.go +184 -0
- package/project/.sdk/tm/go/feature/secrets/plugins/doppler/doppler.go +114 -0
- package/project/.sdk/tm/go/feature/secrets/plugins/gcpsecrets/gcpsecrets.go +156 -0
- package/project/.sdk/tm/go/feature/secrets/plugins/hashicorp/hashicorp.go +209 -0
- package/project/.sdk/tm/go/feature/secrets/plugins/httpjson/httpjson.go +241 -0
- package/project/.sdk/tm/go/feature/secrets/plugins/infisical/infisical.go +151 -0
- package/project/.sdk/tm/go/feature/secrets/plugins/onepassword/onepassword.go +152 -0
- package/project/.sdk/tm/go/feature/secrets/plugins/secretspec/secretspec.go +143 -0
- package/project/.sdk/tm/go/feature/secrets/sekreto/addr.go +120 -0
- package/project/.sdk/tm/go/feature/secrets/sekreto/providers.go +439 -0
- package/project/.sdk/tm/go/feature/secrets/sekreto/sekreto.go +685 -0
- package/project/.sdk/tm/go/feature/secrets_feature.go +675 -0
- package/project/.sdk/tm/go/src/feature/secrets/.gitkeep +0 -0
- package/project/.sdk/tm/go/test/feature/secrets/secrets_feature_test.go +799 -0
- package/project/.sdk/tm/go/test/omni/omni.go +897 -0
- package/project/.sdk/tm/go/test/omni/util.go +360 -0
- package/project/.sdk/tm/go/test/omniresolver_test.go +748 -0
- package/project/.sdk/tm/go/test/omnismoke_test.go +112 -0
- package/project/.sdk/tm/go/test/primary_utility_test.go +123 -191
- package/project/.sdk/tm/go/test/struct_utility_test.go +323 -16
- package/project/.sdk/tm/go/test/testsupport_test.go +294 -0
- package/project/.sdk/tm/go/utility/make_options.go +8 -1
- package/project/.sdk/tm/go/utility/prepare_method.go +5 -1
- package/project/.sdk/tm/go/utility/struct/voxgigstruct.go +2 -2
- package/project/.sdk/tm/java/test/OmniResolver.java +355 -0
- package/project/.sdk/tm/java/test/OmniSmokeTest.java +99 -0
- package/project/.sdk/tm/java/test/PrimaryUtilityTest.java +254 -280
- package/project/.sdk/tm/java/test/RunnerSupport.java +9 -194
- package/project/.sdk/tm/java/test/StructCorpusTest.java +119 -42
- package/project/.sdk/tm/java/test/vendor/omni/Json.java +287 -0
- package/project/.sdk/tm/java/test/vendor/omni/Runner.java +851 -0
- package/project/.sdk/tm/java/test/vendor/omni/Util.java +322 -0
- package/project/.sdk/tm/java/utility/MakeSpec.java +3 -1
- package/project/.sdk/tm/java/utility/PrepareMethod.java +5 -5
- package/project/.sdk/tm/java/utility/struct/Struct.java +17 -4
- package/project/.sdk/tm/js/src/utility/StructUtility.js +3 -3
- package/project/.sdk/tm/js/test/omni.js +251 -0
- package/project/.sdk/tm/js/test/omni.test.js +105 -0
- package/project/.sdk/tm/js/test/utility/PrimaryUtility.test.js +6 -2
- package/project/.sdk/tm/js/test/utility/StructUtility.test.js +27 -2
- package/project/.sdk/tm/js/test/vendor/omni/index.js +77 -0
- package/project/.sdk/tm/js/test/vendor/omni/runner.js +613 -0
- package/project/.sdk/tm/js/test/vendor/omni/util.js +212 -0
- package/project/.sdk/tm/kotlin/core/Utility.kt +1 -1
- package/project/.sdk/tm/kotlin/test/OmniResolver.kt +343 -0
- package/project/.sdk/tm/kotlin/test/OmniSmokeTest.kt +100 -0
- package/project/.sdk/tm/kotlin/test/PrimaryUtilityTest.kt +244 -262
- package/project/.sdk/tm/kotlin/test/RunnerSupport.kt +9 -178
- package/project/.sdk/tm/kotlin/test/StructCorpusTest.kt +121 -32
- package/project/.sdk/tm/kotlin/test/vendor/omni/Json.kt +264 -0
- package/project/.sdk/tm/kotlin/test/vendor/omni/Runner.kt +615 -0
- package/project/.sdk/tm/kotlin/test/vendor/omni/Util.kt +139 -0
- package/project/.sdk/tm/kotlin/utility/MakeSpecUrl.kt +6 -3
- package/project/.sdk/tm/kotlin/utility/Prepare.kt +6 -6
- package/project/.sdk/tm/kotlin/utility/struct/Struct.kt +18 -2
- package/project/.sdk/tm/lean/Makefile +12 -5
- package/project/.sdk/tm/lean/src/SdkUtility.lean +14 -1
- package/project/.sdk/tm/lean/test/OmniResolver.lean +358 -0
- package/project/.sdk/tm/lean/test/OmniSmoke.lean +174 -0
- package/project/.sdk/tm/lean/test/StructCorpus.lean +245 -574
- package/project/.sdk/tm/lean/test/TPrimaryUtility.lean +155 -291
- package/project/.sdk/tm/lean/test/vendor/omni/Omni.lean +997 -0
- package/project/.sdk/tm/lua/test/omni.lua +456 -0
- package/project/.sdk/tm/lua/test/omni_smoke_test.lua +103 -0
- package/project/.sdk/tm/lua/test/primary_utility_test.lua +250 -509
- package/project/.sdk/tm/lua/test/struct_utility_test.lua +161 -70
- package/project/.sdk/tm/lua/test/vendor/omni/json.lua +268 -0
- package/project/.sdk/tm/lua/test/vendor/omni/regex.lua +385 -0
- package/project/.sdk/tm/lua/test/vendor/omni/runner.lua +641 -0
- package/project/.sdk/tm/lua/test/vendor/omni/util.lua +282 -0
- package/project/.sdk/tm/lua/utility/prepare_method.lua +5 -1
- package/project/.sdk/tm/lua/utility/struct/regex.lua +663 -0
- package/project/.sdk/tm/lua/utility/struct/struct.lua +660 -420
- package/project/.sdk/tm/ocaml/Makefile +37 -12
- package/project/.sdk/tm/ocaml/test/omni_resolver.ml +284 -0
- package/project/.sdk/tm/ocaml/test/omni_smoke_test.ml +169 -0
- package/project/.sdk/tm/ocaml/test/primary_utility_test.ml +84 -100
- package/project/.sdk/tm/ocaml/test/struct_corpus.ml +225 -201
- package/project/.sdk/tm/ocaml/test/vendor/omni/omni.ml +1157 -0
- package/project/.sdk/tm/perl/lib/Voxgig/Struct.pm +88 -12
- package/project/.sdk/tm/perl/t/omni.pm +647 -0
- package/project/.sdk/tm/perl/t/omni_smoke.t +87 -0
- package/project/.sdk/tm/perl/t/primary_utility.t +189 -487
- package/project/.sdk/tm/perl/t/struct_utility.t +455 -389
- package/project/.sdk/tm/perl/t/vendor/omni/Voxgig/Omni/Runner.pm +649 -0
- package/project/.sdk/tm/perl/t/vendor/omni/Voxgig/Omni/Util.pm +253 -0
- package/project/.sdk/tm/perl/t/vendor/omni/Voxgig/Omni.pm +24 -0
- package/project/.sdk/tm/perl/utility/prepare_method.pm +7 -2
- package/project/.sdk/tm/php/test/Omni.php +691 -0
- package/project/.sdk/tm/php/test/OmniSmokeTest.php +93 -0
- package/project/.sdk/tm/php/test/PrimaryUtilityTest.php +210 -571
- package/project/.sdk/tm/php/test/StructUtilityTest.php +320 -342
- package/project/.sdk/tm/php/test/vendor/omni/Runner.php +644 -0
- package/project/.sdk/tm/php/test/vendor/omni/Util.php +283 -0
- package/project/.sdk/tm/php/utility/MakeSpec.php +10 -3
- package/project/.sdk/tm/php/utility/PrepareBody.php +7 -1
- package/project/.sdk/tm/php/utility/PrepareMethod.php +6 -2
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/__init__.py +36 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/capability.py +141 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/catalog.py +50 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/config.py +333 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/depend.py +198 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/env.py +147 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/export.py +52 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/graph.py +139 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/host.py +1053 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/order.py +171 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/point.py +95 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/ref.py +116 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/resolve.py +59 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/types.py +87 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/version.py +112 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/__init__.py +74 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/addr.py +116 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/aws.py +192 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/azuresecrets.py +120 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/boru.py +140 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/doppler.py +62 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/gcpsecrets.py +101 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/hashicorp.py +152 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/httpjson.py +115 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/infisical.py +92 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/onepassword.py +101 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/secretspec.py +119 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/sigv4.py +125 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/providers.py +211 -0
- package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/sekreto.py +455 -0
- package/project/.sdk/tm/py/pkg/feature/secrets_feature.py +467 -0
- package/project/.sdk/tm/py/pkg/utility/prepare_method.py +5 -1
- package/project/.sdk/tm/py/pkg/utility/voxgig_struct/__init__.py +0 -2
- package/project/.sdk/tm/py/pkg/utility/voxgig_struct/voxgig_struct.py +780 -529
- package/project/.sdk/tm/py/src/feature/secrets/.gitkeep +0 -0
- package/project/.sdk/tm/py/test/feature/__init__.py +0 -0
- package/project/.sdk/tm/py/test/feature/secrets/__init__.py +0 -0
- package/project/.sdk/tm/py/test/feature/secrets/test_secrets.py +337 -0
- package/project/.sdk/tm/py/test/omni.py +415 -0
- package/project/.sdk/tm/py/test/test_omni_smoke.py +74 -0
- package/project/.sdk/tm/py/test/test_primary_utility.py +144 -668
- package/project/.sdk/tm/py/test/test_struct_utility.py +74 -27
- package/project/.sdk/tm/py/test/voxgig_omni/__init__.py +62 -0
- package/project/.sdk/tm/py/test/voxgig_omni/runner.py +566 -0
- package/project/.sdk/tm/py/test/voxgig_omni/util.py +237 -0
- package/project/.sdk/tm/rb/test/omni.rb +505 -0
- package/project/.sdk/tm/rb/test/omni_smoke_test.rb +72 -0
- package/project/.sdk/tm/rb/test/primary_utility_test.rb +174 -560
- package/project/.sdk/tm/rb/test/struct_utility_test.rb +13 -7
- package/project/.sdk/tm/rb/test/vendor/omni/runner.rb +493 -0
- package/project/.sdk/tm/rb/test/vendor/omni/util.rb +199 -0
- package/project/.sdk/tm/rb/test/vendor/omni/voxgig_omni.rb +15 -0
- package/project/.sdk/tm/rb/utility/prepare_method.rb +5 -1
- package/project/.sdk/tm/rust/tests/common/mod.rs +19 -242
- package/project/.sdk/tm/rust/tests/omni_resolver/mod.rs +888 -0
- package/project/.sdk/tm/rust/tests/omni_smoke_test.rs +286 -0
- package/project/.sdk/tm/rust/tests/primary_utility_test.rs +318 -312
- package/project/.sdk/tm/rust/tests/struct_utility_test.rs +66 -28
- package/project/.sdk/tm/rust/tests/vendor/omni/json.rs +412 -0
- package/project/.sdk/tm/rust/tests/vendor/omni/mod.rs +38 -0
- package/project/.sdk/tm/rust/tests/vendor/omni/regex.rs +392 -0
- package/project/.sdk/tm/rust/tests/vendor/omni/runner.rs +1001 -0
- package/project/.sdk/tm/rust/tests/vendor/omni/util.rs +161 -0
- package/project/.sdk/tm/rust/utility/prepare_method.rs +5 -1
- package/project/.sdk/tm/scala/Makefile +16 -6
- package/project/.sdk/tm/scala/sdktest/OmniResolver.scala +497 -0
- package/project/.sdk/tm/scala/sdktest/OmniSmoke.scala +192 -0
- package/project/.sdk/tm/scala/sdktest/PrimaryCorpus.scala +47 -19
- package/project/.sdk/tm/scala/sdktest/StructCorpus.scala +0 -0
- package/project/.sdk/tm/scala/sdktest/vendor/omni/Json.scala +229 -0
- package/project/.sdk/tm/scala/sdktest/vendor/omni/Runner.scala +552 -0
- package/project/.sdk/tm/scala/sdktest/vendor/omni/Util.scala +104 -0
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/Struct/Constants.swift +10 -0
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/Struct/Inject.swift +28 -5
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/Struct/Injection.swift +5 -1
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/Struct/Minor.swift +4 -1
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/Struct/Validate.swift +15 -5
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/Prepare.swift +6 -1
- package/project/.sdk/tm/swift/Tests/ProjectNameSDKTests/OmniResolver.swift +474 -0
- package/project/.sdk/tm/swift/Tests/ProjectNameSDKTests/OmniSmokeTest.swift +107 -0
- package/project/.sdk/tm/swift/Tests/ProjectNameSDKTests/PrimaryUtilityTest.swift +141 -178
- package/project/.sdk/tm/swift/Tests/ProjectNameSDKTests/Runner.swift +17 -113
- package/project/.sdk/tm/swift/Tests/ProjectNameSDKTests/StructUtilityTest.swift +295 -446
- package/project/.sdk/tm/swift/Tests/vendor/omni/Json.swift +364 -0
- package/project/.sdk/tm/swift/Tests/vendor/omni/Runner.swift +730 -0
- package/project/.sdk/tm/swift/Tests/vendor/omni/Util.swift +162 -0
- package/project/.sdk/tm/ts/src/feature/secrets/SecretsFeature.ts +7 -0
- package/project/.sdk/tm/ts/src/feature/secrets/plugin/Capability.ts +148 -0
- package/project/.sdk/tm/ts/src/feature/secrets/plugin/Catalog.ts +55 -0
- package/project/.sdk/tm/ts/src/feature/secrets/plugin/Config.ts +344 -0
- package/project/.sdk/tm/ts/src/feature/secrets/plugin/Depend.ts +205 -0
- package/project/.sdk/tm/ts/src/feature/secrets/plugin/Env.ts +138 -0
- package/project/.sdk/tm/ts/src/feature/secrets/plugin/Export.ts +46 -0
- package/project/.sdk/tm/ts/src/feature/secrets/plugin/FeatureHost.ts +349 -0
- package/project/.sdk/tm/ts/src/feature/secrets/plugin/Graph.ts +181 -0
- package/project/.sdk/tm/ts/src/feature/secrets/plugin/Host.ts +1132 -0
- package/project/.sdk/tm/ts/src/feature/secrets/plugin/Order.ts +177 -0
- package/project/.sdk/tm/ts/src/feature/secrets/plugin/Point.ts +119 -0
- package/project/.sdk/tm/ts/src/feature/secrets/plugin/Ref.ts +102 -0
- package/project/.sdk/tm/ts/src/feature/secrets/plugin/Resolve.ts +61 -0
- package/project/.sdk/tm/ts/src/feature/secrets/plugin/Types.ts +112 -0
- package/project/.sdk/tm/ts/src/feature/secrets/plugin/Version.ts +100 -0
- package/project/.sdk/tm/ts/src/feature/secrets/plugin/index.ts +37 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Sekreto.ts +163 -30
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/index.ts +27 -22
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/{provider → plugins}/aws.ts +26 -36
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/{provider → plugins}/azuresecrets.ts +19 -21
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/{provider → plugins}/boru.ts +36 -17
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/{provider → plugins}/doppler.ts +14 -21
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/{provider → plugins}/gcpsecrets.ts +27 -27
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/{provider → plugins}/hashicorp.ts +25 -39
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/plugins/httpjson.ts +99 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/{provider → plugins}/infisical.ts +14 -16
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/{provider → plugins}/onepassword.ts +15 -22
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/plugins/secretspec.ts +98 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/{Sigv4.ts → plugins/sigv4.ts} +7 -6
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/addr.ts +97 -23
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/builtin.ts +37 -0
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/dotenv.ts +4 -17
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/env.ts +4 -16
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/file.ts +11 -25
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/memory.ts +6 -23
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/support.ts +106 -39
- package/project/.sdk/tm/ts/src/utility/StructUtility.ts +3 -3
- package/project/.sdk/tm/ts/test/omni.ts +104 -32
- package/project/.sdk/tm/ts/test/utility/StructUtility.test.ts +27 -0
- package/project/.sdk/tm/ts/test/vendor/omni/Runner.ts +32 -5
- package/project/.sdk/tm/ts/test/vendor/omni/Util.ts +2 -2
- package/project/.sdk/tm/ts/test/vendor/omni/index.ts +2 -2
- package/project/.sdk/tm/zig/test/primary_utility_test.zig +1 -1
- package/project/.sdk/tm/zig/test/struct_runner.zig +5 -4
- package/project/sdkgen-package.json +1 -1
- package/src/action/doctor.ts +66 -2
- package/src/helpers/naming.ts +4 -2
- package/project/.sdk/tm/c/tests/runner.h +0 -274
- package/project/.sdk/tm/cpp/test/struct_runner.hpp +0 -314
- package/project/.sdk/tm/csharp/test/StructRunner.cs +0 -276
- package/project/.sdk/tm/dart/test/runner.dart +0 -406
- package/project/.sdk/tm/dart/test/struct_corpus.dart +0 -531
- package/project/.sdk/tm/elixir/test/support/struct_corpus.ex +0 -1088
- package/project/.sdk/tm/go/test/runner_test.go +0 -629
- package/project/.sdk/tm/go/test/struct_runner_test.go +0 -1094
- package/project/.sdk/tm/java/test/StructRunner.java +0 -281
- package/project/.sdk/tm/js/test/runner.js +0 -387
- package/project/.sdk/tm/kotlin/test/StructRunner.kt +0 -177
- package/project/.sdk/tm/lua/test/struct_runner.lua +0 -602
- package/project/.sdk/tm/ocaml/test/corpus_runner.ml +0 -185
- package/project/.sdk/tm/perl/t/struct_runner.pm +0 -275
- package/project/.sdk/tm/php/test/StructRunner.php +0 -275
- package/project/.sdk/tm/py/test/struct_runner.py +0 -411
- package/project/.sdk/tm/rb/test/struct_runner.rb +0 -309
- package/project/.sdk/tm/rust/tests/struct_runner/mod.rs +0 -424
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/Registry.ts +0 -90
- package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/http.ts +0 -66
- package/project/.sdk/tm/ts/test/vendor/omni/compat.ts +0 -188
|
@@ -0,0 +1,1157 @@
|
|
|
1
|
+
(* VENDORED: @voxgig/omni sdk-20260904-1610-0 (ocaml/src/omni.ml) *)
|
|
2
|
+
(* Source: https://github.com/voxgig/omni @ 8c3e1b573a8d35796f7fc45e3226b977023cabf7 [tag: sdk-20260904-1610-0] *)
|
|
3
|
+
(* License: MIT (c) voxgig - see repository LICENSE. Do not edit: resync from upstream. *)
|
|
4
|
+
(* Omni: the shared multi-language test runner (OCaml port).
|
|
5
|
+
|
|
6
|
+
A test spec is plain JSON. The same spec file drives the same tests in
|
|
7
|
+
every language that ships an omni port.
|
|
8
|
+
|
|
9
|
+
Port of the canonical TypeScript implementation
|
|
10
|
+
(typescript/src/Runner.ts). Behaviour must match, case for case.
|
|
11
|
+
|
|
12
|
+
Self-contained by design: the runner carries its own JSON value model,
|
|
13
|
+
parser and regex engine, so that it can test *any* library - including
|
|
14
|
+
one that provides those same operations - and adds no dependencies. *)
|
|
15
|
+
|
|
16
|
+
(* ---- the JSON value model ------------------------------------------ *)
|
|
17
|
+
|
|
18
|
+
(* `Absent` is the marker for "no value at all", as distinct from `Null`. *)
|
|
19
|
+
type json =
|
|
20
|
+
| Absent
|
|
21
|
+
| Null
|
|
22
|
+
| Bool of bool
|
|
23
|
+
| Num of float
|
|
24
|
+
| Str of string
|
|
25
|
+
| JList of json list
|
|
26
|
+
| JMap of (string * json) list
|
|
27
|
+
|
|
28
|
+
let nullmark = "__NULL__" (* Value is JSON null. *)
|
|
29
|
+
let undefmark = "__UNDEF__" (* Value is not present. *)
|
|
30
|
+
let existsmark = "__EXISTS__" (* Value exists (not undefined). *)
|
|
31
|
+
|
|
32
|
+
let ismap = function JMap _ -> true | _ -> false
|
|
33
|
+
let islist = function JList _ -> true | _ -> false
|
|
34
|
+
let isnode val_ = ismap val_ || islist val_
|
|
35
|
+
let isabsent = function Absent -> true | _ -> false
|
|
36
|
+
let isnull = function Null -> true | _ -> false
|
|
37
|
+
let isnone val_ = isabsent val_ || isnull val_
|
|
38
|
+
let isnum = function Num _ -> true | _ -> false
|
|
39
|
+
let isstr = function Str _ -> true | _ -> false
|
|
40
|
+
|
|
41
|
+
let asnum = function Num v -> Some v | _ -> None
|
|
42
|
+
let asstr = function Str v -> Some v | _ -> None
|
|
43
|
+
let aslist = function JList v -> Some v | _ -> None
|
|
44
|
+
let asmap = function JMap v -> Some v | _ -> None
|
|
45
|
+
|
|
46
|
+
(* Read a map entry. Returns Absent when missing. *)
|
|
47
|
+
let jget val_ key =
|
|
48
|
+
match val_ with
|
|
49
|
+
| JMap entries -> (try List.assoc key entries with Not_found -> Absent)
|
|
50
|
+
| _ -> Absent
|
|
51
|
+
|
|
52
|
+
(* Is a map key present at all (even with a null value)? *)
|
|
53
|
+
let jhas val_ key =
|
|
54
|
+
match val_ with JMap entries -> List.mem_assoc key entries | _ -> false
|
|
55
|
+
|
|
56
|
+
(* A copy of a map with one entry set (no-op for non-maps). *)
|
|
57
|
+
let jset val_ key entry =
|
|
58
|
+
match val_ with
|
|
59
|
+
| JMap entries ->
|
|
60
|
+
if List.mem_assoc key entries then
|
|
61
|
+
JMap (List.map (fun (k, e) -> if k = key then (k, entry) else (k, e)) entries)
|
|
62
|
+
else JMap (entries @ [ (key, entry) ])
|
|
63
|
+
| other -> other
|
|
64
|
+
|
|
65
|
+
(* ---- errors -------------------------------------------------------- *)
|
|
66
|
+
|
|
67
|
+
(* A test failure (or a malformed spec). Distinct from an exception raised
|
|
68
|
+
by the subject under test, which is a candidate for an `err`
|
|
69
|
+
expectation. *)
|
|
70
|
+
exception Omni_error of string
|
|
71
|
+
|
|
72
|
+
let omni_error message = Omni_error message
|
|
73
|
+
|
|
74
|
+
(* ---- number and string rendering ----------------------------------- *)
|
|
75
|
+
|
|
76
|
+
(* Render a number the same way in every port: 5.0 prints as 5. *)
|
|
77
|
+
let numstr value =
|
|
78
|
+
if Float.is_nan value || Float.is_integer value = false then
|
|
79
|
+
if Float.is_nan value || value = Float.infinity || value = Float.neg_infinity then "null"
|
|
80
|
+
else Printf.sprintf "%.17g" value
|
|
81
|
+
else if Float.abs value < 9007199254740992.0 then Printf.sprintf "%.0f" value
|
|
82
|
+
else Printf.sprintf "%.17g" value
|
|
83
|
+
|
|
84
|
+
(* Render a string as a JSON string literal. *)
|
|
85
|
+
let quote value =
|
|
86
|
+
let buf = Buffer.create (String.length value + 2) in
|
|
87
|
+
Buffer.add_char buf '"';
|
|
88
|
+
String.iter
|
|
89
|
+
(fun ch ->
|
|
90
|
+
match ch with
|
|
91
|
+
| '"' -> Buffer.add_string buf "\\\""
|
|
92
|
+
| '\\' -> Buffer.add_string buf "\\\\"
|
|
93
|
+
| '\n' -> Buffer.add_string buf "\\n"
|
|
94
|
+
| '\r' -> Buffer.add_string buf "\\r"
|
|
95
|
+
| '\t' -> Buffer.add_string buf "\\t"
|
|
96
|
+
| _ ->
|
|
97
|
+
if Char.code ch < 0x20 then Buffer.add_string buf (Printf.sprintf "\\u%04x" (Char.code ch))
|
|
98
|
+
else Buffer.add_char buf ch)
|
|
99
|
+
value;
|
|
100
|
+
Buffer.add_char buf '"';
|
|
101
|
+
Buffer.contents buf
|
|
102
|
+
|
|
103
|
+
(* Compact JSON text with map keys sorted, identical in every port. *)
|
|
104
|
+
let rec jsonstr value =
|
|
105
|
+
match value with
|
|
106
|
+
| Absent -> "undefined"
|
|
107
|
+
| Null -> "null"
|
|
108
|
+
| Bool flag -> if flag then "true" else "false"
|
|
109
|
+
| Num entry -> numstr entry
|
|
110
|
+
| Str text -> quote text
|
|
111
|
+
| JList entries -> "[" ^ String.concat "," (List.map jsonstr entries) ^ "]"
|
|
112
|
+
| JMap entries ->
|
|
113
|
+
let sorted = List.sort (fun (a, _) (b, _) -> compare a b) entries in
|
|
114
|
+
"{" ^ String.concat "," (List.map (fun (key, e) -> quote key ^ ":" ^ jsonstr e) sorted) ^ "}"
|
|
115
|
+
|
|
116
|
+
(* Strings verbatim, everything else as compact JSON. *)
|
|
117
|
+
let stringify value = match value with Str text -> text | other -> jsonstr other
|
|
118
|
+
|
|
119
|
+
(* Render a path as a dotted string. *)
|
|
120
|
+
let pathify path = String.concat "." path
|
|
121
|
+
|
|
122
|
+
(* ---- json parser --------------------------------------------------- *)
|
|
123
|
+
|
|
124
|
+
let parse text =
|
|
125
|
+
let len = String.length text in
|
|
126
|
+
let pos = ref 0 in
|
|
127
|
+
|
|
128
|
+
let fail reason = raise (Omni_error (Printf.sprintf "omni: %s at %d" reason !pos)) in
|
|
129
|
+
|
|
130
|
+
let skipws () =
|
|
131
|
+
while
|
|
132
|
+
!pos < len
|
|
133
|
+
&& (match text.[!pos] with ' ' | '\t' | '\n' | '\r' -> true | _ -> false)
|
|
134
|
+
do
|
|
135
|
+
incr pos
|
|
136
|
+
done
|
|
137
|
+
in
|
|
138
|
+
|
|
139
|
+
let word want value =
|
|
140
|
+
let wlen = String.length want in
|
|
141
|
+
if !pos + wlen <= len && String.sub text !pos wlen = want then (
|
|
142
|
+
pos := !pos + wlen;
|
|
143
|
+
value)
|
|
144
|
+
else fail "bad JSON literal"
|
|
145
|
+
in
|
|
146
|
+
|
|
147
|
+
let parsestring () =
|
|
148
|
+
if !pos >= len || text.[!pos] <> '"' then fail "expected string";
|
|
149
|
+
incr pos;
|
|
150
|
+
let buf = Buffer.create 16 in
|
|
151
|
+
let result = ref None in
|
|
152
|
+
while !result = None do
|
|
153
|
+
if !pos >= len then fail "unterminated JSON string";
|
|
154
|
+
let ch = text.[!pos] in
|
|
155
|
+
incr pos;
|
|
156
|
+
if ch = '"' then result := Some (Buffer.contents buf)
|
|
157
|
+
else if ch <> '\\' then Buffer.add_char buf ch
|
|
158
|
+
else begin
|
|
159
|
+
if !pos >= len then fail "unterminated JSON string";
|
|
160
|
+
let escape = text.[!pos] in
|
|
161
|
+
incr pos;
|
|
162
|
+
match escape with
|
|
163
|
+
| '"' -> Buffer.add_char buf '"'
|
|
164
|
+
| '\\' -> Buffer.add_char buf '\\'
|
|
165
|
+
| '/' -> Buffer.add_char buf '/'
|
|
166
|
+
| 'b' -> Buffer.add_char buf '\b'
|
|
167
|
+
| 'f' -> Buffer.add_char buf '\012'
|
|
168
|
+
| 'n' -> Buffer.add_char buf '\n'
|
|
169
|
+
| 'r' -> Buffer.add_char buf '\r'
|
|
170
|
+
| 't' -> Buffer.add_char buf '\t'
|
|
171
|
+
| 'u' ->
|
|
172
|
+
if !pos + 4 > len then fail "bad JSON unicode escape";
|
|
173
|
+
(* Exactly four hex digits: int_of_string would accept '_'
|
|
174
|
+
separators and raise Failure on other junk. *)
|
|
175
|
+
let hexdigit ch =
|
|
176
|
+
match ch with
|
|
177
|
+
| '0' .. '9' -> Char.code ch - Char.code '0'
|
|
178
|
+
| 'a' .. 'f' -> Char.code ch - Char.code 'a' + 10
|
|
179
|
+
| 'A' .. 'F' -> Char.code ch - Char.code 'A' + 10
|
|
180
|
+
| _ -> fail "bad JSON unicode escape"
|
|
181
|
+
in
|
|
182
|
+
let code = ref 0 in
|
|
183
|
+
for step = 0 to 3 do
|
|
184
|
+
code := (!code * 16) + hexdigit text.[!pos + step]
|
|
185
|
+
done;
|
|
186
|
+
let code = !code in
|
|
187
|
+
pos := !pos + 4;
|
|
188
|
+
(* UTF-8 encode. *)
|
|
189
|
+
if code < 0x80 then Buffer.add_char buf (Char.chr code)
|
|
190
|
+
else if code < 0x800 then begin
|
|
191
|
+
Buffer.add_char buf (Char.chr (0xC0 lor (code lsr 6)));
|
|
192
|
+
Buffer.add_char buf (Char.chr (0x80 lor (code land 0x3F)))
|
|
193
|
+
end
|
|
194
|
+
else begin
|
|
195
|
+
Buffer.add_char buf (Char.chr (0xE0 lor (code lsr 12)));
|
|
196
|
+
Buffer.add_char buf (Char.chr (0x80 lor ((code lsr 6) land 0x3F)));
|
|
197
|
+
Buffer.add_char buf (Char.chr (0x80 lor (code land 0x3F)))
|
|
198
|
+
end
|
|
199
|
+
| _ -> fail "bad JSON escape"
|
|
200
|
+
end
|
|
201
|
+
done;
|
|
202
|
+
match !result with Some text -> text | None -> fail "unterminated JSON string"
|
|
203
|
+
in
|
|
204
|
+
|
|
205
|
+
let parsenumber () =
|
|
206
|
+
let start = !pos in
|
|
207
|
+
if !pos < len && (text.[!pos] = '-' || text.[!pos] = '+') then incr pos;
|
|
208
|
+
while
|
|
209
|
+
!pos < len
|
|
210
|
+
&& (match text.[!pos] with
|
|
211
|
+
| '0' .. '9' | '.' | 'e' | 'E' | '-' | '+' -> true
|
|
212
|
+
| _ -> false)
|
|
213
|
+
do
|
|
214
|
+
incr pos
|
|
215
|
+
done;
|
|
216
|
+
let span = String.sub text start (!pos - start) in
|
|
217
|
+
match float_of_string_opt span with
|
|
218
|
+
| Some value -> Num value
|
|
219
|
+
| None -> fail ("bad JSON number [" ^ span ^ "]")
|
|
220
|
+
in
|
|
221
|
+
|
|
222
|
+
let rec parsevalue () =
|
|
223
|
+
if !pos >= len then fail "unexpected end of JSON";
|
|
224
|
+
match text.[!pos] with
|
|
225
|
+
| '{' -> parsemap ()
|
|
226
|
+
| '[' -> parselist ()
|
|
227
|
+
| '"' -> Str (parsestring ())
|
|
228
|
+
| 't' -> word "true" (Bool true)
|
|
229
|
+
| 'f' -> word "false" (Bool false)
|
|
230
|
+
| 'n' -> word "null" Null
|
|
231
|
+
| _ -> parsenumber ()
|
|
232
|
+
and parsemap () =
|
|
233
|
+
incr pos;
|
|
234
|
+
skipws ();
|
|
235
|
+
if !pos < len && text.[!pos] = '}' then begin
|
|
236
|
+
incr pos;
|
|
237
|
+
JMap []
|
|
238
|
+
end
|
|
239
|
+
else begin
|
|
240
|
+
let entries = ref [] in
|
|
241
|
+
let running = ref true in
|
|
242
|
+
while !running do
|
|
243
|
+
skipws ();
|
|
244
|
+
let key = parsestring () in
|
|
245
|
+
skipws ();
|
|
246
|
+
if !pos >= len || text.[!pos] <> ':' then fail "expected ':'";
|
|
247
|
+
incr pos;
|
|
248
|
+
skipws ();
|
|
249
|
+
let value = parsevalue () in
|
|
250
|
+
(* A duplicate key overrides the earlier value (last wins), as in
|
|
251
|
+
the canonical implementation. *)
|
|
252
|
+
if List.mem_assoc key !entries then
|
|
253
|
+
entries := List.map (fun (k, e) -> if k = key then (k, value) else (k, e)) !entries
|
|
254
|
+
else entries := !entries @ [ (key, value) ];
|
|
255
|
+
skipws ();
|
|
256
|
+
if !pos >= len then fail "unterminated JSON object";
|
|
257
|
+
if text.[!pos] = ',' then incr pos
|
|
258
|
+
else if text.[!pos] = '}' then begin
|
|
259
|
+
incr pos;
|
|
260
|
+
running := false
|
|
261
|
+
end
|
|
262
|
+
else fail "expected ',' or '}'"
|
|
263
|
+
done;
|
|
264
|
+
JMap !entries
|
|
265
|
+
end
|
|
266
|
+
and parselist () =
|
|
267
|
+
incr pos;
|
|
268
|
+
skipws ();
|
|
269
|
+
if !pos < len && text.[!pos] = ']' then begin
|
|
270
|
+
incr pos;
|
|
271
|
+
JList []
|
|
272
|
+
end
|
|
273
|
+
else begin
|
|
274
|
+
let entries = ref [] in
|
|
275
|
+
let running = ref true in
|
|
276
|
+
while !running do
|
|
277
|
+
skipws ();
|
|
278
|
+
entries := !entries @ [ parsevalue () ];
|
|
279
|
+
skipws ();
|
|
280
|
+
if !pos >= len then fail "unterminated JSON array";
|
|
281
|
+
if text.[!pos] = ',' then incr pos
|
|
282
|
+
else if text.[!pos] = ']' then begin
|
|
283
|
+
incr pos;
|
|
284
|
+
running := false
|
|
285
|
+
end
|
|
286
|
+
else fail "expected ',' or ']'"
|
|
287
|
+
done;
|
|
288
|
+
JList !entries
|
|
289
|
+
end
|
|
290
|
+
in
|
|
291
|
+
|
|
292
|
+
skipws ();
|
|
293
|
+
let value = parsevalue () in
|
|
294
|
+
skipws ();
|
|
295
|
+
if !pos < len then fail "trailing JSON content";
|
|
296
|
+
value
|
|
297
|
+
|
|
298
|
+
(* ---- util ---------------------------------------------------------- *)
|
|
299
|
+
|
|
300
|
+
(* Deep copy a JSON value (the value model is immutable). *)
|
|
301
|
+
let clone value = value
|
|
302
|
+
|
|
303
|
+
(* Read a value by path. Returns Absent when any step is missing. *)
|
|
304
|
+
let rec getpath value path =
|
|
305
|
+
match path with
|
|
306
|
+
| [] -> value
|
|
307
|
+
| part :: rest ->
|
|
308
|
+
let next =
|
|
309
|
+
match value with
|
|
310
|
+
| JList entries -> (
|
|
311
|
+
match int_of_string_opt part with
|
|
312
|
+
| Some index when index >= 0 && index < List.length entries -> List.nth entries index
|
|
313
|
+
| _ -> Absent)
|
|
314
|
+
| JMap _ -> jget value part
|
|
315
|
+
| _ -> Absent
|
|
316
|
+
in
|
|
317
|
+
if isabsent next then Absent else getpath next rest
|
|
318
|
+
|
|
319
|
+
(* Depth-first walk: children first, then the containing node. *)
|
|
320
|
+
let rec walk value apply path =
|
|
321
|
+
let next =
|
|
322
|
+
match value with
|
|
323
|
+
| JList entries ->
|
|
324
|
+
JList (List.mapi (fun index entry -> walk entry apply (path @ [ string_of_int index ])) entries)
|
|
325
|
+
| JMap entries -> JMap (List.map (fun (key, entry) -> (key, walk entry apply (path @ [ key ]))) entries)
|
|
326
|
+
| other -> other
|
|
327
|
+
in
|
|
328
|
+
apply next path
|
|
329
|
+
|
|
330
|
+
(* Deep structural equality: numbers by value, bools never numbers. *)
|
|
331
|
+
let rec deepequal a b =
|
|
332
|
+
match (a, b) with
|
|
333
|
+
| Absent, Absent -> true
|
|
334
|
+
| Null, Null -> true
|
|
335
|
+
| Bool x, Bool y -> x = y
|
|
336
|
+
| Num x, Num y -> x = y || (Float.is_nan x && Float.is_nan y)
|
|
337
|
+
| Str x, Str y -> x = y
|
|
338
|
+
| JList x, JList y -> List.length x = List.length y && List.for_all2 deepequal x y
|
|
339
|
+
| JMap x, JMap y ->
|
|
340
|
+
List.length x = List.length y
|
|
341
|
+
&& List.for_all
|
|
342
|
+
(fun (key, entry) -> List.mem_assoc key y && deepequal entry (List.assoc key y))
|
|
343
|
+
x
|
|
344
|
+
| _ -> false
|
|
345
|
+
|
|
346
|
+
(* ---- regex engine --------------------------------------------------- *)
|
|
347
|
+
|
|
348
|
+
(* Omni specs match error messages with `/pattern/` expectations, so every
|
|
349
|
+
port needs a regex. OCaml's Str has a different dialect, so omni carries
|
|
350
|
+
this engine, a direct port of the Rust one (rust/src/regex.rs). *)
|
|
351
|
+
|
|
352
|
+
type reitem =
|
|
353
|
+
| IChar of char
|
|
354
|
+
| IRange of char * char
|
|
355
|
+
| IDigit of bool
|
|
356
|
+
| IWord of bool
|
|
357
|
+
| ISpace of bool
|
|
358
|
+
|
|
359
|
+
type renode =
|
|
360
|
+
| RChar of char
|
|
361
|
+
| RAny
|
|
362
|
+
| RClass of reitem list * bool
|
|
363
|
+
| RStart
|
|
364
|
+
| REnd
|
|
365
|
+
| RSeq of renode list
|
|
366
|
+
| RAlt of renode list
|
|
367
|
+
| RRepeat of renode * int * int option * bool
|
|
368
|
+
|
|
369
|
+
exception Regex_error of string
|
|
370
|
+
|
|
371
|
+
let regex_parse pattern =
|
|
372
|
+
let len = String.length pattern in
|
|
373
|
+
let pos = ref 0 in
|
|
374
|
+
|
|
375
|
+
let escapenode escape =
|
|
376
|
+
match escape with
|
|
377
|
+
| 'd' -> RClass ([ IDigit false ], false)
|
|
378
|
+
| 'D' -> RClass ([ IDigit false ], true)
|
|
379
|
+
| 'w' -> RClass ([ IWord false ], false)
|
|
380
|
+
| 'W' -> RClass ([ IWord false ], true)
|
|
381
|
+
| 's' -> RClass ([ ISpace false ], false)
|
|
382
|
+
| 'S' -> RClass ([ ISpace false ], true)
|
|
383
|
+
| 'n' -> RChar '\n'
|
|
384
|
+
| 'r' -> RChar '\r'
|
|
385
|
+
| 't' -> RChar '\t'
|
|
386
|
+
| other -> RChar other
|
|
387
|
+
in
|
|
388
|
+
|
|
389
|
+
let parseclass () =
|
|
390
|
+
incr pos;
|
|
391
|
+
let negated = !pos < len && pattern.[!pos] = '^' in
|
|
392
|
+
if negated then incr pos;
|
|
393
|
+
let items = ref [] in
|
|
394
|
+
let first = ref true in
|
|
395
|
+
let result = ref None in
|
|
396
|
+
while !result = None do
|
|
397
|
+
if !pos >= len then raise (Regex_error "omni: unterminated regex class");
|
|
398
|
+
let ch = pattern.[!pos] in
|
|
399
|
+
if ch = ']' && not !first then begin
|
|
400
|
+
incr pos;
|
|
401
|
+
result := Some (RClass (!items, negated))
|
|
402
|
+
end
|
|
403
|
+
else begin
|
|
404
|
+
first := false;
|
|
405
|
+
if ch = '\\' && !pos + 1 < len then begin
|
|
406
|
+
let escape = pattern.[!pos + 1] in
|
|
407
|
+
pos := !pos + 2;
|
|
408
|
+
items :=
|
|
409
|
+
!items
|
|
410
|
+
@ [ (match escape with
|
|
411
|
+
| 'd' -> IDigit false
|
|
412
|
+
| 'w' -> IWord false
|
|
413
|
+
| 's' -> ISpace false
|
|
414
|
+
| 'n' -> IChar '\n'
|
|
415
|
+
| 'r' -> IChar '\r'
|
|
416
|
+
| 't' -> IChar '\t'
|
|
417
|
+
| other -> IChar other) ]
|
|
418
|
+
end
|
|
419
|
+
else begin
|
|
420
|
+
incr pos;
|
|
421
|
+
if !pos + 1 < len && pattern.[!pos] = '-' && pattern.[!pos + 1] <> ']' then begin
|
|
422
|
+
items := !items @ [ IRange (ch, pattern.[!pos + 1]) ];
|
|
423
|
+
pos := !pos + 2
|
|
424
|
+
end
|
|
425
|
+
else items := !items @ [ IChar ch ]
|
|
426
|
+
end
|
|
427
|
+
end
|
|
428
|
+
done;
|
|
429
|
+
match !result with Some node -> node | None -> raise (Regex_error "omni: bad regex class")
|
|
430
|
+
in
|
|
431
|
+
|
|
432
|
+
let parsecount () =
|
|
433
|
+
let start = !pos in
|
|
434
|
+
incr pos;
|
|
435
|
+
let digits = Buffer.create 4 in
|
|
436
|
+
while !pos < len && pattern.[!pos] >= '0' && pattern.[!pos] <= '9' do
|
|
437
|
+
Buffer.add_char digits pattern.[!pos];
|
|
438
|
+
incr pos
|
|
439
|
+
done;
|
|
440
|
+
if Buffer.length digits = 0 then begin
|
|
441
|
+
pos := start;
|
|
442
|
+
None
|
|
443
|
+
end
|
|
444
|
+
else begin
|
|
445
|
+
(* A count too large for an int degrades to a literal `{`, rather
|
|
446
|
+
than leaking a Failure out of the parser. *)
|
|
447
|
+
match int_of_string_opt (Buffer.contents digits) with
|
|
448
|
+
| None ->
|
|
449
|
+
pos := start;
|
|
450
|
+
None
|
|
451
|
+
| Some min ->
|
|
452
|
+
if !pos < len && pattern.[!pos] = '}' then begin
|
|
453
|
+
incr pos;
|
|
454
|
+
Some (min, Some min)
|
|
455
|
+
end
|
|
456
|
+
else if !pos < len && pattern.[!pos] = ',' then begin
|
|
457
|
+
incr pos;
|
|
458
|
+
let maxdigits = Buffer.create 4 in
|
|
459
|
+
while !pos < len && pattern.[!pos] >= '0' && pattern.[!pos] <= '9' do
|
|
460
|
+
Buffer.add_char maxdigits pattern.[!pos];
|
|
461
|
+
incr pos
|
|
462
|
+
done;
|
|
463
|
+
if !pos < len && pattern.[!pos] = '}' then begin
|
|
464
|
+
incr pos;
|
|
465
|
+
if Buffer.length maxdigits = 0 then Some (min, None)
|
|
466
|
+
else
|
|
467
|
+
match int_of_string_opt (Buffer.contents maxdigits) with
|
|
468
|
+
| Some maxval -> Some (min, Some maxval)
|
|
469
|
+
| None ->
|
|
470
|
+
pos := start;
|
|
471
|
+
None
|
|
472
|
+
end
|
|
473
|
+
else begin
|
|
474
|
+
pos := start;
|
|
475
|
+
None
|
|
476
|
+
end
|
|
477
|
+
end
|
|
478
|
+
else begin
|
|
479
|
+
pos := start;
|
|
480
|
+
None
|
|
481
|
+
end
|
|
482
|
+
end
|
|
483
|
+
in
|
|
484
|
+
|
|
485
|
+
let rec parsealt () =
|
|
486
|
+
let branches = ref [ parseseq () ] in
|
|
487
|
+
while !pos < len && pattern.[!pos] = '|' do
|
|
488
|
+
incr pos;
|
|
489
|
+
branches := !branches @ [ parseseq () ]
|
|
490
|
+
done;
|
|
491
|
+
match !branches with [ single ] -> single | many -> RAlt many
|
|
492
|
+
and parseseq () =
|
|
493
|
+
let nodes = ref [] in
|
|
494
|
+
while !pos < len && pattern.[!pos] <> '|' && pattern.[!pos] <> ')' do
|
|
495
|
+
let atom = parseatom () in
|
|
496
|
+
nodes := !nodes @ [ parserepeat atom ]
|
|
497
|
+
done;
|
|
498
|
+
RSeq !nodes
|
|
499
|
+
and parserepeat atom =
|
|
500
|
+
if !pos >= len then atom
|
|
501
|
+
else
|
|
502
|
+
let bounds =
|
|
503
|
+
match pattern.[!pos] with
|
|
504
|
+
| '*' ->
|
|
505
|
+
incr pos;
|
|
506
|
+
Some (0, None)
|
|
507
|
+
| '+' ->
|
|
508
|
+
incr pos;
|
|
509
|
+
Some (1, None)
|
|
510
|
+
| '?' ->
|
|
511
|
+
incr pos;
|
|
512
|
+
Some (0, Some 1)
|
|
513
|
+
| '{' -> parsecount ()
|
|
514
|
+
| _ -> None
|
|
515
|
+
in
|
|
516
|
+
match bounds with
|
|
517
|
+
| None -> atom
|
|
518
|
+
| Some (min, max) ->
|
|
519
|
+
let greedy = not (!pos < len && pattern.[!pos] = '?') in
|
|
520
|
+
if not greedy then incr pos;
|
|
521
|
+
RRepeat (atom, min, max, greedy)
|
|
522
|
+
and parseatom () =
|
|
523
|
+
let ch = pattern.[!pos] in
|
|
524
|
+
if ch = '(' then begin
|
|
525
|
+
incr pos;
|
|
526
|
+
if !pos + 1 < len && pattern.[!pos] = '?' && pattern.[!pos + 1] = ':' then pos := !pos + 2;
|
|
527
|
+
let inner = parsealt () in
|
|
528
|
+
if !pos >= len || pattern.[!pos] <> ')' then raise (Regex_error "omni: unbalanced regex group");
|
|
529
|
+
incr pos;
|
|
530
|
+
inner
|
|
531
|
+
end
|
|
532
|
+
else if ch = '[' then parseclass ()
|
|
533
|
+
else if ch = '.' then begin
|
|
534
|
+
incr pos;
|
|
535
|
+
RAny
|
|
536
|
+
end
|
|
537
|
+
else if ch = '^' then begin
|
|
538
|
+
incr pos;
|
|
539
|
+
RStart
|
|
540
|
+
end
|
|
541
|
+
else if ch = '$' then begin
|
|
542
|
+
incr pos;
|
|
543
|
+
REnd
|
|
544
|
+
end
|
|
545
|
+
else if ch = '\\' then begin
|
|
546
|
+
incr pos;
|
|
547
|
+
if !pos >= len then raise (Regex_error "omni: trailing backslash in regex");
|
|
548
|
+
let escape = pattern.[!pos] in
|
|
549
|
+
incr pos;
|
|
550
|
+
escapenode escape
|
|
551
|
+
end
|
|
552
|
+
else begin
|
|
553
|
+
incr pos;
|
|
554
|
+
RChar ch
|
|
555
|
+
end
|
|
556
|
+
in
|
|
557
|
+
|
|
558
|
+
let root = parsealt () in
|
|
559
|
+
if !pos < len then raise (Regex_error ("omni: bad regex: " ^ pattern));
|
|
560
|
+
root
|
|
561
|
+
|
|
562
|
+
let isword ch =
|
|
563
|
+
(ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || ch = '_'
|
|
564
|
+
|
|
565
|
+
let isdigitch ch = ch >= '0' && ch <= '9'
|
|
566
|
+
let isspacech ch = ch = ' ' || ch = '\t' || ch = '\n' || ch = '\r' || ch = '\012'
|
|
567
|
+
|
|
568
|
+
let classmatch items negated ch =
|
|
569
|
+
let hit =
|
|
570
|
+
List.exists
|
|
571
|
+
(fun item ->
|
|
572
|
+
match item with
|
|
573
|
+
| IChar want -> ch = want
|
|
574
|
+
| IRange (from, upto) -> from <= ch && ch <= upto
|
|
575
|
+
| IDigit invert -> isdigitch ch <> invert
|
|
576
|
+
| IWord invert -> isword ch <> invert
|
|
577
|
+
| ISpace invert -> isspacech ch <> invert)
|
|
578
|
+
items
|
|
579
|
+
in
|
|
580
|
+
hit <> negated
|
|
581
|
+
|
|
582
|
+
let rec matchnode node text pos cont =
|
|
583
|
+
let len = String.length text in
|
|
584
|
+
match node with
|
|
585
|
+
| RChar want -> pos < len && text.[pos] = want && cont (pos + 1)
|
|
586
|
+
| RAny -> pos < len && cont (pos + 1)
|
|
587
|
+
| RClass (items, negated) -> pos < len && classmatch items negated text.[pos] && cont (pos + 1)
|
|
588
|
+
| RStart -> pos = 0 && cont pos
|
|
589
|
+
| REnd -> pos = len && cont pos
|
|
590
|
+
| RSeq nodes -> matchseq nodes text pos cont
|
|
591
|
+
| RAlt branches -> List.exists (fun branch -> matchnode branch text pos cont) branches
|
|
592
|
+
| RRepeat (inner, min, max, greedy) -> matchrepeat inner min max greedy 0 text pos cont
|
|
593
|
+
|
|
594
|
+
and matchseq nodes text pos cont =
|
|
595
|
+
match nodes with
|
|
596
|
+
| [] -> cont pos
|
|
597
|
+
| head :: rest -> matchnode head text pos (fun next -> matchseq rest text next cont)
|
|
598
|
+
|
|
599
|
+
and matchrepeat inner min max greedy count text pos cont =
|
|
600
|
+
let canmore = match max with None -> true | Some limit -> count < limit in
|
|
601
|
+
let takemore () =
|
|
602
|
+
canmore
|
|
603
|
+
&& matchnode inner text pos (fun next ->
|
|
604
|
+
(* A zero-width repeat would loop forever. *)
|
|
605
|
+
next > pos && matchrepeat inner min max greedy (count + 1) text next cont)
|
|
606
|
+
in
|
|
607
|
+
let stopnow () = count >= min && cont pos in
|
|
608
|
+
if greedy then takemore () || stopnow () else stopnow () || takemore ()
|
|
609
|
+
|
|
610
|
+
(* Is the pattern found anywhere in the text? *)
|
|
611
|
+
let regex_find pattern text =
|
|
612
|
+
match regex_parse pattern with
|
|
613
|
+
| exception Regex_error _ -> false
|
|
614
|
+
| root ->
|
|
615
|
+
let len = String.length text in
|
|
616
|
+
let rec attempt start =
|
|
617
|
+
if start > len then false
|
|
618
|
+
else if matchnode root text start (fun _ -> true) then true
|
|
619
|
+
else attempt (start + 1)
|
|
620
|
+
in
|
|
621
|
+
attempt 0
|
|
622
|
+
|
|
623
|
+
(* ---- runner -------------------------------------------------------- *)
|
|
624
|
+
|
|
625
|
+
(* The function under test. Arguments arrive as JSON values; failure is
|
|
626
|
+
reported by raising. *)
|
|
627
|
+
type subject = json list -> json
|
|
628
|
+
|
|
629
|
+
(* A subject that may MUTATE its arguments, which `match.args` can then assert
|
|
630
|
+
on. `minor/setpath` is the case in point: eight of its nine entries assert
|
|
631
|
+
that the store was rewritten in place, and `merge/integrity` all six.
|
|
632
|
+
|
|
633
|
+
OCaml's `json` is immutable, so a consumer holding a converted copy has no
|
|
634
|
+
way to write through a `json list`. The arguments arrive as an ARRAY it may
|
|
635
|
+
overwrite in place, and the runner reads it back after the call.
|
|
636
|
+
|
|
637
|
+
Separate from `subject` rather than replacing it: a signature change would
|
|
638
|
+
break every consumer for a capability most subjects do not need. omni-rust
|
|
639
|
+
and omni-cpp carry the same pair, for the same reason. Dynamic-language
|
|
640
|
+
ports need neither - their shims write the mutation back into omni's own
|
|
641
|
+
object, because the value is shared. *)
|
|
642
|
+
type subject_args = json array -> json
|
|
643
|
+
|
|
644
|
+
(* Run-time options for a set of test entries. *)
|
|
645
|
+
type flags = { null : bool; name : string option }
|
|
646
|
+
|
|
647
|
+
let default_flags = { null = true; name = None }
|
|
648
|
+
let nonull_flags = { null = false; name = None }
|
|
649
|
+
|
|
650
|
+
(* The host of the system under test. Every hook is optional. *)
|
|
651
|
+
type provider = {
|
|
652
|
+
subject : (string -> subject option) option;
|
|
653
|
+
client : (json -> provider) option;
|
|
654
|
+
contextify : (json -> json) option;
|
|
655
|
+
inject : (json -> json -> json) option;
|
|
656
|
+
(* Build the `match.err` base from the failure, REPLACING [errify].
|
|
657
|
+
|
|
658
|
+
OCaml reports a subject failure as its message and nothing else, so a
|
|
659
|
+
library whose errors carry a code has no other way to put one in the
|
|
660
|
+
base. The hook receives that message and returns the base, letting a
|
|
661
|
+
spec assert [match: {err: {code: "x"}}] instead of pattern-matching
|
|
662
|
+
prose. *)
|
|
663
|
+
errify : (string -> json) option;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
let empty_provider =
|
|
667
|
+
{ subject = None; client = None; contextify = None; inject = None; errify = None }
|
|
668
|
+
|
|
669
|
+
(* The newest spec format version this runner understands. A spec with no
|
|
670
|
+
OMNI block is version 0: the original, lenient format, frozen forever.
|
|
671
|
+
Version 1 turns on strict entry validation (see checkentry). *)
|
|
672
|
+
let specversion = 1
|
|
673
|
+
|
|
674
|
+
(* Capability strings this runner supports beyond the version baseline. A
|
|
675
|
+
spec's OMNI.requires list is checked against this: an unknown
|
|
676
|
+
capability refuses the spec loudly at load time, instead of a lagging
|
|
677
|
+
port silently mis-running it. (Empty today; future format features
|
|
678
|
+
mint a string here.) *)
|
|
679
|
+
let capabilities : string list = []
|
|
680
|
+
|
|
681
|
+
(* The complete set of fields an entry may carry. Under version 1 anything
|
|
682
|
+
else is an error: an unrecognised key is almost always a typo'd
|
|
683
|
+
assertion, and a typo'd assertion is a test that silently stopped
|
|
684
|
+
testing. *)
|
|
685
|
+
let entryfields = [ "in"; "args"; "ctx"; "out"; "err"; "match"; "client"; "id"; "doc" ]
|
|
686
|
+
|
|
687
|
+
(* Load a spec: a path to a JSON file. *)
|
|
688
|
+
let loadspec path =
|
|
689
|
+
if not (Sys.file_exists path) then raise (Omni_error ("omni: cannot read spec: " ^ path));
|
|
690
|
+
let channel = open_in_bin path in
|
|
691
|
+
let length = in_channel_length channel in
|
|
692
|
+
let text = really_input_string channel length in
|
|
693
|
+
close_in channel;
|
|
694
|
+
parse text
|
|
695
|
+
|
|
696
|
+
(* Read the spec's format version from its optional top-level OMNI block,
|
|
697
|
+
and refuse a spec this runner cannot faithfully run: a version newer
|
|
698
|
+
than specversion, or a required capability not in capabilities. Only a
|
|
699
|
+
genuinely absent OMNI key is legacy - `OMNI: null` (or a malformed
|
|
700
|
+
requires/version) is a spec error, checked by presence, not by a null
|
|
701
|
+
test, so a present null is never mistaken for absence. *)
|
|
702
|
+
let resolveversion alltests =
|
|
703
|
+
if not (jhas alltests "OMNI") then 0
|
|
704
|
+
else
|
|
705
|
+
let meta = jget alltests "OMNI" in
|
|
706
|
+
if not (ismap meta) then raise (Omni_error "omni: malformed OMNI version block");
|
|
707
|
+
|
|
708
|
+
let version =
|
|
709
|
+
match jget meta "version" with
|
|
710
|
+
| Num v when Float.is_integer v -> v
|
|
711
|
+
| _ -> raise (Omni_error "omni: malformed OMNI version block")
|
|
712
|
+
in
|
|
713
|
+
|
|
714
|
+
if version < 0.0 || float_of_int specversion < version then
|
|
715
|
+
raise (Omni_error ("omni: unsupported spec version: " ^ numstr version));
|
|
716
|
+
|
|
717
|
+
(if jhas meta "requires" then
|
|
718
|
+
match jget meta "requires" with
|
|
719
|
+
| JList items ->
|
|
720
|
+
List.iter
|
|
721
|
+
(fun cap ->
|
|
722
|
+
match cap with
|
|
723
|
+
| Str text when List.mem text capabilities -> ()
|
|
724
|
+
| _ -> raise (Omni_error ("omni: spec requires unsupported capability: " ^ stringify cap)))
|
|
725
|
+
items
|
|
726
|
+
| _ -> raise (Omni_error "omni: malformed OMNI requires list"));
|
|
727
|
+
|
|
728
|
+
int_of_float version
|
|
729
|
+
|
|
730
|
+
(* Find `primary.<name>`, then `<name>`, then the whole spec. *)
|
|
731
|
+
let resolvespec name alltests =
|
|
732
|
+
if name = "" then alltests
|
|
733
|
+
else
|
|
734
|
+
let primary = jget (jget alltests "primary") name in
|
|
735
|
+
if not (isabsent primary) then primary
|
|
736
|
+
else
|
|
737
|
+
let section = jget alltests name in
|
|
738
|
+
if not (isabsent section) then section else alltests
|
|
739
|
+
|
|
740
|
+
(* Nulls (and absent values) become NULLMARK. Always a fresh copy. *)
|
|
741
|
+
let rec fixjson value donull =
|
|
742
|
+
(* Canonical returns the value UNCHANGED when donull is false
|
|
743
|
+
(typescript/src/Runner.ts): absent stays absent and null stays null.
|
|
744
|
+
Answering Null for both collapsed two states the corpus distinguishes, so
|
|
745
|
+
a subject that correctly returned nothing was compared against null and
|
|
746
|
+
marked wrong - `minor/clone#13`, `minor/getprop#4`, `minor/getelem#9`.
|
|
747
|
+
Same defect the other ports carried (#17, #23, #25); this one was missed
|
|
748
|
+
because no consumer had exercised it. *)
|
|
749
|
+
if isnone value then (if donull then Str nullmark else value)
|
|
750
|
+
else
|
|
751
|
+
match value with
|
|
752
|
+
| JList entries -> JList (List.map (fun entry -> fixjson entry donull) entries)
|
|
753
|
+
| JMap entries -> JMap (List.map (fun (key, entry) -> (key, fixjson entry donull)) entries)
|
|
754
|
+
| other -> other
|
|
755
|
+
|
|
756
|
+
(* The JSON form of an error: always at least {name,message}. *)
|
|
757
|
+
let errify message = JMap [ ("name", Str "Error"); ("message", Str message) ]
|
|
758
|
+
|
|
759
|
+
(* The message an `err` expectation matches. *)
|
|
760
|
+
let errmessage err =
|
|
761
|
+
match err with
|
|
762
|
+
| Omni_error message -> message
|
|
763
|
+
| Failure message -> message
|
|
764
|
+
| other -> Printexc.to_string other
|
|
765
|
+
|
|
766
|
+
(* Match one leaf: /regex/ or case-insensitive substring for strings. *)
|
|
767
|
+
let matchval check base =
|
|
768
|
+
if deepequal check base then true
|
|
769
|
+
else
|
|
770
|
+
let want =
|
|
771
|
+
match asstr check with
|
|
772
|
+
| Some text when text = undefmark || text = nullmark -> Null
|
|
773
|
+
| _ -> check
|
|
774
|
+
in
|
|
775
|
+
if isnone want then isnone base || asstr base = Some nullmark
|
|
776
|
+
else
|
|
777
|
+
match asstr want with
|
|
778
|
+
(* An empty want is not a wildcard: the empty string is a substring of
|
|
779
|
+
everything, so `match:{out:""}` (or `err:""`) would accept any value. *)
|
|
780
|
+
| Some "" -> asstr base = Some ""
|
|
781
|
+
| Some text ->
|
|
782
|
+
let basestr = stringify base in
|
|
783
|
+
let tlen = String.length text in
|
|
784
|
+
if tlen > 2 && text.[0] = '/' && text.[tlen - 1] = '/' then
|
|
785
|
+
regex_find (String.sub text 1 (tlen - 2)) basestr
|
|
786
|
+
else
|
|
787
|
+
let lowbase = String.lowercase_ascii basestr in
|
|
788
|
+
let lowwant = String.lowercase_ascii text in
|
|
789
|
+
let blen = String.length lowbase in
|
|
790
|
+
let wlen = String.length lowwant in
|
|
791
|
+
let rec search at =
|
|
792
|
+
if at + wlen > blen then false
|
|
793
|
+
else if String.sub lowbase at wlen = lowwant then true
|
|
794
|
+
else search (at + 1)
|
|
795
|
+
in
|
|
796
|
+
wlen = 0 || search 0
|
|
797
|
+
| None -> deepequal want base
|
|
798
|
+
|
|
799
|
+
(* Convert NULLMARK sentinels back into real nulls. *)
|
|
800
|
+
let nullmodifier value =
|
|
801
|
+
match asstr value with
|
|
802
|
+
| Some text when text = nullmark -> Null
|
|
803
|
+
| Some text ->
|
|
804
|
+
let buf = Buffer.create (String.length text) in
|
|
805
|
+
let mlen = String.length nullmark in
|
|
806
|
+
let at = ref 0 in
|
|
807
|
+
while !at < String.length text do
|
|
808
|
+
if !at + mlen <= String.length text && String.sub text !at mlen = nullmark then begin
|
|
809
|
+
Buffer.add_string buf "null";
|
|
810
|
+
at := !at + mlen
|
|
811
|
+
end
|
|
812
|
+
else begin
|
|
813
|
+
Buffer.add_char buf text.[!at];
|
|
814
|
+
incr at
|
|
815
|
+
end
|
|
816
|
+
done;
|
|
817
|
+
Str (Buffer.contents buf)
|
|
818
|
+
| None -> value
|
|
819
|
+
|
|
820
|
+
(* The spec-defined part of an entry (drop runner bookkeeping). *)
|
|
821
|
+
let entrysummary entry =
|
|
822
|
+
match entry with
|
|
823
|
+
| JMap entries ->
|
|
824
|
+
JMap (List.filter (fun (key, _) -> key <> "res" && key <> "thrown" && key <> "ctx") entries)
|
|
825
|
+
| other -> other
|
|
826
|
+
|
|
827
|
+
(* The label of one entry, for failure messages. *)
|
|
828
|
+
let entryref label index entry =
|
|
829
|
+
let id = jget entry "id" in
|
|
830
|
+
let idpart = if isabsent id then "" else " (" ^ stringify id ^ ")" in
|
|
831
|
+
Printf.sprintf "%s[%d]%s" label index idpart
|
|
832
|
+
|
|
833
|
+
let fail label index entry reason expected actual =
|
|
834
|
+
let buf = Buffer.create 128 in
|
|
835
|
+
Buffer.add_string buf (Printf.sprintf "omni: %s: %s" (entryref label index entry) reason);
|
|
836
|
+
(match expected with
|
|
837
|
+
| Some text -> Buffer.add_string buf ("\n expected: " ^ text)
|
|
838
|
+
| None -> ());
|
|
839
|
+
(match actual with Some text -> Buffer.add_string buf ("\n actual: " ^ text) | None -> ());
|
|
840
|
+
Buffer.add_string buf ("\n entry: " ^ stringify (entrysummary entry));
|
|
841
|
+
Omni_error (Buffer.contents buf)
|
|
842
|
+
|
|
843
|
+
(* Strict entry validation, applied when the spec declares version 1 or
|
|
844
|
+
later. The lenient format converts each of these mistakes into a
|
|
845
|
+
silent pass or a dead field; here they fail with the entry named. *)
|
|
846
|
+
let checkentry label index entry =
|
|
847
|
+
(match entry with
|
|
848
|
+
| JMap fields ->
|
|
849
|
+
List.iter
|
|
850
|
+
(fun (key, _) ->
|
|
851
|
+
if not (List.mem key entryfields) then
|
|
852
|
+
raise (fail label index entry ("unknown entry field: " ^ key) None None))
|
|
853
|
+
fields
|
|
854
|
+
| _ -> raise (fail label index entry "entry is not a map" None None));
|
|
855
|
+
|
|
856
|
+
let argsources = List.length (List.filter (fun key -> jhas entry key) [ "in"; "args"; "ctx" ]) in
|
|
857
|
+
if 1 < argsources then
|
|
858
|
+
raise (fail label index entry "entry has more than one of in, args, ctx" None None);
|
|
859
|
+
|
|
860
|
+
(* `err` here is a presence-and-non-null check (an `err: null` entry is
|
|
861
|
+
not "expects an error"), but `out` is presence alone - the two
|
|
862
|
+
sentinels the rest of the runner distinguishes throughout. *)
|
|
863
|
+
if (not (isnone (jget entry "err"))) && jhas entry "out" then
|
|
864
|
+
raise (fail label index entry "entry has both err and out" None None);
|
|
865
|
+
|
|
866
|
+
if jhas entry "id" && not (isstr (jget entry "id")) then
|
|
867
|
+
raise (fail label index entry "entry id is not a string" None None)
|
|
868
|
+
|
|
869
|
+
(* Validate a version-1 group up front, against the AUTHORED entries -
|
|
870
|
+
null-normalisation would otherwise rewrite an authored null (e.g. id:
|
|
871
|
+
null) into a sentinel string and hide it from validation. A malformed
|
|
872
|
+
spec is a spec error, not a test result, so it fails before any
|
|
873
|
+
subject runs. *)
|
|
874
|
+
let checkset label testspec normalset =
|
|
875
|
+
let origset =
|
|
876
|
+
if ismap testspec then
|
|
877
|
+
match aslist (jget testspec "set") with Some entries -> entries | None -> normalset
|
|
878
|
+
else normalset
|
|
879
|
+
in
|
|
880
|
+
|
|
881
|
+
let emptyflag = match jget testspec "empty" with Bool true -> true | _ -> false in
|
|
882
|
+
|
|
883
|
+
if [] = origset && not emptyflag then raise (Omni_error ("omni: empty test set: " ^ label));
|
|
884
|
+
|
|
885
|
+
List.iteri (fun index entry -> checkentry label index entry) origset
|
|
886
|
+
|
|
887
|
+
(* Check that every leaf of `check` is present, and matches, in `base`. *)
|
|
888
|
+
let rec matchcheck label index entry check base path =
|
|
889
|
+
let where = if path = [] then "<root>" else pathify path in
|
|
890
|
+
match check with
|
|
891
|
+
| JList entries ->
|
|
892
|
+
List.iteri
|
|
893
|
+
(fun at subcheck -> matchcheck label index entry subcheck base (path @ [ string_of_int at ]))
|
|
894
|
+
entries
|
|
895
|
+
| JMap entries ->
|
|
896
|
+
List.iter (fun (key, subcheck) -> matchcheck label index entry subcheck base (path @ [ key ])) entries
|
|
897
|
+
| leaf ->
|
|
898
|
+
let baseval = getpath base path in
|
|
899
|
+
(* The sentinels are tested BEFORE the identity check below. Otherwise a
|
|
900
|
+
subject returning the literal string "__UNDEF__" satisfies an
|
|
901
|
+
assertion that the key is absent - two mutually exclusive states
|
|
902
|
+
passing one check. A sentinel that accepts its own literal is not a
|
|
903
|
+
sentinel. (NULLMARK still accepts NULLMARK: under the default null
|
|
904
|
+
flag a real null has already been normalised to it, so the two are
|
|
905
|
+
genuinely indistinguishable here - that one needs a raw-value escape,
|
|
906
|
+
not an ordering change.) *)
|
|
907
|
+
|
|
908
|
+
(* Explicitly absent: satisfied only by a genuinely missing key, never
|
|
909
|
+
by a present null (the distinction the sentinels exist to keep). *)
|
|
910
|
+
if asstr leaf = Some undefmark then begin
|
|
911
|
+
if not (isabsent baseval) then
|
|
912
|
+
raise
|
|
913
|
+
(fail label index entry ("expected absent at " ^ where) (Some "absent")
|
|
914
|
+
(Some (stringify baseval)))
|
|
915
|
+
end
|
|
916
|
+
(* Explicitly null: satisfied only by a present null. *)
|
|
917
|
+
else if asstr leaf = Some nullmark then begin
|
|
918
|
+
if not (isnull baseval || asstr baseval = Some nullmark) then
|
|
919
|
+
raise
|
|
920
|
+
(fail label index entry ("expected null at " ^ where) (Some "null")
|
|
921
|
+
(Some (stringify baseval)))
|
|
922
|
+
end
|
|
923
|
+
(* Explicitly present: any present value, including null. *)
|
|
924
|
+
else if asstr leaf = Some existsmark then begin
|
|
925
|
+
if isabsent baseval then
|
|
926
|
+
raise
|
|
927
|
+
(fail label index entry ("expected present at " ^ where) (Some "present") (Some "absent"))
|
|
928
|
+
end
|
|
929
|
+
(* Identical values match. This sits below the sentinel branches on
|
|
930
|
+
purpose - see the note above. *)
|
|
931
|
+
else if deepequal leaf baseval then ()
|
|
932
|
+
(* A concrete expectation never matches a missing key - a match leaf
|
|
933
|
+
against an absent value must fail, not substring-match "undefined". *)
|
|
934
|
+
else if isabsent baseval then
|
|
935
|
+
raise
|
|
936
|
+
(fail label index entry ("match failed at " ^ where) (Some (stringify leaf)) (Some "absent"))
|
|
937
|
+
else if not (matchval leaf baseval) then
|
|
938
|
+
raise
|
|
939
|
+
(fail label index entry ("match failed at " ^ where) (Some (stringify leaf))
|
|
940
|
+
(Some (stringify baseval)))
|
|
941
|
+
|
|
942
|
+
let checkresult label index entry args res =
|
|
943
|
+
let entryerr = jget entry "err" in
|
|
944
|
+
if not (isnone entryerr) then
|
|
945
|
+
raise
|
|
946
|
+
(fail label index entry "expected error did not occur" (Some (stringify entryerr))
|
|
947
|
+
(Some (stringify res)));
|
|
948
|
+
|
|
949
|
+
let check = jget entry "match" in
|
|
950
|
+
let matched = not (isnone check) in
|
|
951
|
+
|
|
952
|
+
if matched then begin
|
|
953
|
+
let base =
|
|
954
|
+
JMap
|
|
955
|
+
[
|
|
956
|
+
("in", jget entry "in");
|
|
957
|
+
("args", JList args);
|
|
958
|
+
("out", jget entry "res");
|
|
959
|
+
("ctx", jget entry "ctx");
|
|
960
|
+
]
|
|
961
|
+
in
|
|
962
|
+
matchcheck label index entry check base []
|
|
963
|
+
end;
|
|
964
|
+
|
|
965
|
+
let out = jget entry "out" in
|
|
966
|
+
|
|
967
|
+
if deepequal res out then ()
|
|
968
|
+
(* NOTE: a match with no explicit out is a complete check on its own. *)
|
|
969
|
+
else if matched && (isnone out || asstr out = Some nullmark) then ()
|
|
970
|
+
else raise (fail label index entry "result mismatch" (Some (stringify out)) (Some (stringify res)))
|
|
971
|
+
|
|
972
|
+
(* The error base a `match.err` sees: the provider's own, when it has one. *)
|
|
973
|
+
let errbase message (provider : provider) =
|
|
974
|
+
match provider.errify with Some hook -> hook message | None -> errify message
|
|
975
|
+
|
|
976
|
+
let handleerror label index entry message provider =
|
|
977
|
+
let entryerr = jget entry "err" in
|
|
978
|
+
|
|
979
|
+
if isnone entryerr then
|
|
980
|
+
raise (fail label index entry "unexpected error" None (Some message))
|
|
981
|
+
else
|
|
982
|
+
let istrue = match entryerr with Bool true -> true | _ -> false in
|
|
983
|
+
if istrue || matchval entryerr (Str message) then begin
|
|
984
|
+
let check = jget entry "match" in
|
|
985
|
+
if not (isnone check) then
|
|
986
|
+
let base =
|
|
987
|
+
JMap
|
|
988
|
+
[
|
|
989
|
+
("in", jget entry "in");
|
|
990
|
+
("out", jget entry "res");
|
|
991
|
+
("ctx", jget entry "ctx");
|
|
992
|
+
("err", errbase message provider);
|
|
993
|
+
]
|
|
994
|
+
in
|
|
995
|
+
matchcheck label index entry check base []
|
|
996
|
+
end
|
|
997
|
+
else
|
|
998
|
+
raise (fail label index entry "error mismatch" (Some (stringify entryerr)) (Some message))
|
|
999
|
+
|
|
1000
|
+
(* What a runner returns for one named spec section. *)
|
|
1001
|
+
type runpack = {
|
|
1002
|
+
spec : json;
|
|
1003
|
+
set : string -> json;
|
|
1004
|
+
runset : json -> subject option -> unit;
|
|
1005
|
+
runsetflags : json -> flags -> subject option -> unit;
|
|
1006
|
+
(* Everything runsetflags does, for a subject that may rewrite its
|
|
1007
|
+
arguments. See `subject_args`. *)
|
|
1008
|
+
runsetflags_args : json -> flags -> subject_args -> unit;
|
|
1009
|
+
defsubject : subject option;
|
|
1010
|
+
client : provider;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
let resolvesubject name (provider : provider) =
|
|
1014
|
+
if name = "" then None
|
|
1015
|
+
else match provider.subject with None -> None | Some resolve -> resolve name
|
|
1016
|
+
|
|
1017
|
+
(* Make a runner for a spec value and a provider. Resolving the version
|
|
1018
|
+
here - outside the returned closure - fails fast: a spec this runner
|
|
1019
|
+
cannot faithfully run is refused as soon as the runner is made, before
|
|
1020
|
+
any group name is even chosen. *)
|
|
1021
|
+
let make_runner_spec alltests (provider : provider) =
|
|
1022
|
+
let specversion = resolveversion alltests in
|
|
1023
|
+
fun name store ->
|
|
1024
|
+
let spec = resolvespec name alltests in
|
|
1025
|
+
|
|
1026
|
+
(* A spec may define clients that a given test run never references. *)
|
|
1027
|
+
let clients =
|
|
1028
|
+
match (asmap (jget (jget spec "DEF") "client"), provider.client) with
|
|
1029
|
+
| Some entries, Some clientmaker ->
|
|
1030
|
+
List.map
|
|
1031
|
+
(fun (clientname, cdef) ->
|
|
1032
|
+
let copts = jget (jget cdef "test") "options" in
|
|
1033
|
+
let copts = if isabsent copts then JMap [] else copts in
|
|
1034
|
+
let copts =
|
|
1035
|
+
match (provider.inject, store) with
|
|
1036
|
+
| Some inject, Some storeval when ismap storeval -> inject copts storeval
|
|
1037
|
+
| _ -> copts
|
|
1038
|
+
in
|
|
1039
|
+
(clientname, clientmaker copts))
|
|
1040
|
+
entries
|
|
1041
|
+
| _ -> []
|
|
1042
|
+
in
|
|
1043
|
+
|
|
1044
|
+
let defsubject = resolvesubject name provider in
|
|
1045
|
+
|
|
1046
|
+
let drive testspec flags testsubject (argsubject : subject_args option) =
|
|
1047
|
+
let label =
|
|
1048
|
+
match flags.name with Some text -> text | None -> if name = "" then "set" else name
|
|
1049
|
+
in
|
|
1050
|
+
|
|
1051
|
+
let usesubject =
|
|
1052
|
+
match (argsubject, testsubject, defsubject) with
|
|
1053
|
+
| Some _, _, _ -> None
|
|
1054
|
+
| None, Some found, _ -> Some found
|
|
1055
|
+
| None, None, Some found -> Some found
|
|
1056
|
+
| None, None, None -> raise (Omni_error ("omni: no test subject for: " ^ label))
|
|
1057
|
+
in
|
|
1058
|
+
|
|
1059
|
+
let testspecmap = fixjson testspec flags.null in
|
|
1060
|
+
let testset =
|
|
1061
|
+
match aslist (jget testspecmap "set") with
|
|
1062
|
+
| Some entries -> entries
|
|
1063
|
+
| None -> raise (Omni_error ("omni: test spec has no set: " ^ label))
|
|
1064
|
+
in
|
|
1065
|
+
|
|
1066
|
+
(* Validated against the AUTHORED `testspec`, not the null-normalised
|
|
1067
|
+
`testset` above - see checkset. *)
|
|
1068
|
+
if 1 <= specversion then checkset label testspec testset;
|
|
1069
|
+
|
|
1070
|
+
List.iteri
|
|
1071
|
+
(fun index rawentry ->
|
|
1072
|
+
if not (ismap rawentry) then
|
|
1073
|
+
raise (Omni_error (Printf.sprintf "omni: %s[%d]: entry is not a map" label index));
|
|
1074
|
+
|
|
1075
|
+
(* An entry with no `out` expects a null (or absent) result. *)
|
|
1076
|
+
let entry =
|
|
1077
|
+
if flags.null && isnone (jget rawentry "out") then jset rawentry "out" (Str nullmark)
|
|
1078
|
+
else rawentry
|
|
1079
|
+
in
|
|
1080
|
+
|
|
1081
|
+
let entrysubject =
|
|
1082
|
+
match (usesubject, asstr (jget entry "client")) with
|
|
1083
|
+
| None, _ -> None
|
|
1084
|
+
| Some found, None -> Some found
|
|
1085
|
+
| Some found, Some clientname -> (
|
|
1086
|
+
match List.assoc_opt clientname clients with
|
|
1087
|
+
| None -> raise (Omni_error ("omni: unknown client: " ^ clientname))
|
|
1088
|
+
| Some client -> (
|
|
1089
|
+
match resolvesubject name client with Some other -> Some other | None -> Some found))
|
|
1090
|
+
in
|
|
1091
|
+
|
|
1092
|
+
(* Build the argument list: `ctx`, `args`, or `in`. *)
|
|
1093
|
+
let hasctx = jhas entry "ctx" in
|
|
1094
|
+
let hasargs = jhas entry "args" in
|
|
1095
|
+
let args =
|
|
1096
|
+
if hasctx then [ jget entry "ctx" ]
|
|
1097
|
+
else if hasargs then
|
|
1098
|
+
match aslist (jget entry "args") with Some list -> list | None -> [ jget entry "args" ]
|
|
1099
|
+
else [ clone (jget entry "in") ]
|
|
1100
|
+
in
|
|
1101
|
+
|
|
1102
|
+
let args, entry =
|
|
1103
|
+
if (hasctx || hasargs) && args <> [] && ismap (List.hd args) then
|
|
1104
|
+
let first =
|
|
1105
|
+
match provider.contextify with
|
|
1106
|
+
| Some contextify -> contextify (List.hd args)
|
|
1107
|
+
| None -> List.hd args
|
|
1108
|
+
in
|
|
1109
|
+
(* The resolved client is a live provider (closures over the
|
|
1110
|
+
system under test), and this port's json carries no
|
|
1111
|
+
host-object variant to hold one - so canonical's
|
|
1112
|
+
`first.client = testpack.client` becomes presence, not
|
|
1113
|
+
identity: enough for a subject to prove the runner
|
|
1114
|
+
attached a client at all. *)
|
|
1115
|
+
let first = jset first "client" (Bool true) in
|
|
1116
|
+
(first :: List.tl args, jset entry "ctx" first)
|
|
1117
|
+
else (args, entry)
|
|
1118
|
+
in
|
|
1119
|
+
|
|
1120
|
+
(* An args-subject may overwrite its argument array; the runner reads
|
|
1121
|
+
it back so `match.args` sees what the subject actually did. *)
|
|
1122
|
+
let invoke () =
|
|
1123
|
+
match (argsubject, entrysubject) with
|
|
1124
|
+
| Some call, _ ->
|
|
1125
|
+
let cells = Array.of_list args in
|
|
1126
|
+
let res = call cells in
|
|
1127
|
+
(Array.to_list cells, res)
|
|
1128
|
+
| None, Some call -> (args, call args)
|
|
1129
|
+
| None, None -> raise (Omni_error ("omni: no test subject for: " ^ label))
|
|
1130
|
+
in
|
|
1131
|
+
|
|
1132
|
+
match invoke () with
|
|
1133
|
+
| args, res ->
|
|
1134
|
+
let fixed = fixjson res flags.null in
|
|
1135
|
+
checkresult label index (jset entry "res" fixed) args fixed
|
|
1136
|
+
| exception Omni_error message -> raise (Omni_error message)
|
|
1137
|
+
| exception err -> handleerror label index entry (errmessage err) provider)
|
|
1138
|
+
testset
|
|
1139
|
+
in
|
|
1140
|
+
|
|
1141
|
+
let runsetflags testspec flags testsubject = drive testspec flags testsubject None in
|
|
1142
|
+
let runsetflags_args testspec flags argsubject =
|
|
1143
|
+
drive testspec flags None (Some argsubject)
|
|
1144
|
+
in
|
|
1145
|
+
|
|
1146
|
+
{
|
|
1147
|
+
spec;
|
|
1148
|
+
set = (fun setname -> jget spec setname);
|
|
1149
|
+
runset = (fun testspec testsubject -> runsetflags testspec default_flags testsubject);
|
|
1150
|
+
runsetflags;
|
|
1151
|
+
runsetflags_args;
|
|
1152
|
+
defsubject;
|
|
1153
|
+
client = provider;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
(* Make a runner for a spec file path and a provider. *)
|
|
1157
|
+
let make_runner path (provider : provider) = make_runner_spec (loadspec path) provider
|