@alpsckr/unitycli 0.4.2 → 0.4.4
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/README.md +5 -5
- package/contracts/command-contract.json +109 -217
- package/contracts/package-files.json +374 -294
- package/contracts/stable-session/direct-call-semantics.json +8 -2
- package/contracts/tool-completion-contract.json +148 -672
- package/dist/bridge/admission.d.ts +17 -1
- package/dist/bridge/admission.js +2 -0
- package/dist/bridge/admission.js.map +1 -1
- package/dist/bridge/domains/asset.js +3 -1
- package/dist/bridge/domains/asset.js.map +1 -1
- package/dist/bridge/domains/camera.js +39 -7
- package/dist/bridge/domains/camera.js.map +1 -1
- package/dist/bridge/domains/console.js +2 -1
- package/dist/bridge/domains/console.js.map +1 -1
- package/dist/bridge/domains/doctor.d.ts +3 -0
- package/dist/bridge/domains/doctor.js +8 -0
- package/dist/bridge/domains/doctor.js.map +1 -0
- package/dist/bridge/domains/editor.js +0 -4
- package/dist/bridge/domains/editor.js.map +1 -1
- package/dist/bridge/domains/game-object.js +4 -12
- package/dist/bridge/domains/game-object.js.map +1 -1
- package/dist/bridge/domains/graphics.js +1 -16
- package/dist/bridge/domains/graphics.js.map +1 -1
- package/dist/bridge/domains/object.js +3 -0
- package/dist/bridge/domains/object.js.map +1 -1
- package/dist/bridge/domains/physics.js +1 -2
- package/dist/bridge/domains/physics.js.map +1 -1
- package/dist/bridge/domains/profiler.js +18 -7
- package/dist/bridge/domains/profiler.js.map +1 -1
- package/dist/bridge/domains/project-tool.js +4 -0
- package/dist/bridge/domains/project-tool.js.map +1 -1
- package/dist/bridge/domains/reflection.js +10 -2
- package/dist/bridge/domains/reflection.js.map +1 -1
- package/dist/bridge/domains/runtime-tool.js +3 -0
- package/dist/bridge/domains/runtime-tool.js.map +1 -1
- package/dist/bridge/domains/scene.js +3 -8
- package/dist/bridge/domains/scene.js.map +1 -1
- package/dist/bridge/domains/screenshot.js +30 -6
- package/dist/bridge/domains/screenshot.js.map +1 -1
- package/dist/bridge/domains/ui.js +3 -1
- package/dist/bridge/domains/ui.js.map +1 -1
- package/dist/bridge/index.d.ts +5 -5
- package/dist/bridge/index.js +6 -9
- package/dist/bridge/index.js.map +1 -1
- package/dist/bridge/registry.js +3 -5
- package/dist/bridge/registry.js.map +1 -1
- package/dist/bridge/session-supervisor.d.ts +6 -3
- package/dist/bridge/session-supervisor.js +122 -34
- package/dist/bridge/session-supervisor.js.map +1 -1
- package/dist/bridge/types.d.ts +6 -5
- package/dist/bridge/types.js +16 -2
- package/dist/bridge/types.js.map +1 -1
- package/dist/catalog-protocol.d.ts +64 -0
- package/dist/catalog-protocol.js +460 -0
- package/dist/catalog-protocol.js.map +1 -0
- package/dist/cli-commands/command.js +84 -61
- package/dist/cli-commands/command.js.map +1 -1
- package/dist/cli-commands/extensions.js +70 -50
- package/dist/cli-commands/extensions.js.map +1 -1
- package/dist/cli-commands/instances.js +1 -1
- package/dist/cli-commands/instances.js.map +1 -1
- package/dist/cli-process-owners.d.ts +6 -0
- package/dist/cli-process-owners.js +27 -0
- package/dist/cli-process-owners.js.map +1 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +20 -5
- package/dist/cli.js.map +1 -1
- package/dist/contracts/command-contract.js +14 -4
- package/dist/contracts/command-contract.js.map +1 -1
- package/dist/doctor.d.ts +4 -6
- package/dist/doctor.js +429 -398
- package/dist/doctor.js.map +1 -1
- package/dist/editor-blocker-observer.d.ts +2 -1
- package/dist/editor-blocker-observer.js +40 -13
- package/dist/editor-blocker-observer.js.map +1 -1
- package/dist/extension-availability.d.ts +27 -9
- package/dist/extension-availability.js +96 -56
- package/dist/extension-availability.js.map +1 -1
- package/dist/extensions/descriptor-loader.d.ts +2 -2
- package/dist/extensions/descriptor-loader.js +3 -4
- package/dist/extensions/descriptor-loader.js.map +1 -1
- package/dist/extensions/index.d.ts +1 -1
- package/dist/extensions/index.js +1 -1
- package/dist/extensions/index.js.map +1 -1
- package/dist/extensions/installer.d.ts +24 -7
- package/dist/extensions/installer.js +142 -66
- package/dist/extensions/installer.js.map +1 -1
- package/dist/extensions/registry.js +3 -5
- package/dist/extensions/registry.js.map +1 -1
- package/dist/extensions/state-contract.d.ts +11 -0
- package/dist/extensions/state-contract.js +50 -0
- package/dist/extensions/state-contract.js.map +1 -0
- package/dist/instances.d.ts +13 -1
- package/dist/instances.js +26 -0
- package/dist/instances.js.map +1 -1
- package/dist/package-manager.d.ts +0 -24
- package/dist/package-manager.js +5 -58
- package/dist/package-manager.js.map +1 -1
- package/dist/project-tool-discovery.d.ts +5 -2
- package/dist/project-tool-discovery.js +22 -18
- package/dist/project-tool-discovery.js.map +1 -1
- package/dist/runtime-code.js +1 -1
- package/dist/runtime-code.js.map +1 -1
- package/dist/tool-name.d.ts +4 -0
- package/dist/tool-name.js +15 -0
- package/dist/tool-name.js.map +1 -0
- package/dist/tools/.generated-completion-registry.d.ts +2 -0
- package/dist/tools/.generated-completion-registry.js +763 -325
- package/dist/tools/.generated-completion-registry.js.map +1 -1
- package/dist/tools/.generated-registry.d.ts +6 -11
- package/dist/tools/.generated-registry.js +6 -11
- package/dist/tools/.generated-registry.js.map +1 -1
- package/dist/tools/.generated-schemas.js +11 -16
- package/dist/tools/.generated-schemas.js.map +1 -1
- package/dist/tools/asset/refresh-status.d.ts +3 -0
- package/dist/tools/asset/refresh-status.js +12 -0
- package/dist/tools/asset/refresh-status.js.map +1 -0
- package/dist/tools/asset/refresh.js +7 -3
- package/dist/tools/asset/refresh.js.map +1 -1
- package/dist/tools/build/player-status.d.ts +3 -0
- package/dist/tools/build/player-status.js +12 -0
- package/dist/tools/build/player-status.js.map +1 -0
- package/dist/tools/build/run.js +1 -1
- package/dist/tools/build/run.js.map +1 -1
- package/dist/tools/catalog-control.d.ts +22 -0
- package/dist/tools/catalog-control.js +335 -0
- package/dist/tools/catalog-control.js.map +1 -0
- package/dist/tools/catalog.d.ts +7 -9
- package/dist/tools/catalog.js +66 -45
- package/dist/tools/catalog.js.map +1 -1
- package/dist/tools/commands.d.ts +1 -1
- package/dist/tools/commands.js +44 -11
- package/dist/tools/commands.js.map +1 -1
- package/dist/tools/define.js +3 -2
- package/dist/tools/define.js.map +1 -1
- package/dist/tools/dispatcher.d.ts +53 -6
- package/dist/tools/dispatcher.js +277 -108
- package/dist/tools/dispatcher.js.map +1 -1
- package/dist/tools/editor/compile.js +1 -1
- package/dist/tools/editor/compile.js.map +1 -1
- package/dist/tools/editor/play-mode-status.d.ts +3 -0
- package/dist/tools/editor/play-mode-status.js +12 -0
- package/dist/tools/editor/play-mode-status.js.map +1 -0
- package/dist/tools/editor/readiness.d.ts +0 -1
- package/dist/tools/editor/readiness.js +0 -1
- package/dist/tools/editor/readiness.js.map +1 -1
- package/dist/tools/editor/refresh.d.ts +7 -3
- package/dist/tools/editor/refresh.js +20 -15
- package/dist/tools/editor/refresh.js.map +1 -1
- package/dist/tools/editor/state.d.ts +2 -2
- package/dist/tools/editor/state.js +13 -12
- package/dist/tools/editor/state.js.map +1 -1
- package/dist/tools/metadata/derived.js +1 -7
- package/dist/tools/metadata/derived.js.map +1 -1
- package/dist/tools/metadata/status.js +1 -12
- package/dist/tools/metadata/status.js.map +1 -1
- package/dist/tools/metadata/types.d.ts +0 -2
- package/dist/tools/navmesh/live.js +1 -1
- package/dist/tools/navmesh/live.js.map +1 -1
- package/dist/tools/occlusion/live.js +1 -1
- package/dist/tools/occlusion/live.js.map +1 -1
- package/dist/tools/package/deploy.js +2 -2
- package/dist/tools/package/deploy.js.map +1 -1
- package/dist/tools/package/embed.js +1 -1
- package/dist/tools/package/embed.js.map +1 -1
- package/dist/tools/package/install-status.d.ts +3 -0
- package/dist/tools/package/install-status.js +12 -0
- package/dist/tools/package/install-status.js.map +1 -0
- package/dist/tools/package/install.js +3 -3
- package/dist/tools/package/install.js.map +1 -1
- package/dist/tools/package/live-resolve.js +45 -12
- package/dist/tools/package/live-resolve.js.map +1 -1
- package/dist/tools/package/registry-clear.js.map +1 -1
- package/dist/tools/package/registry-set.js.map +1 -1
- package/dist/tools/package/remove-status.d.ts +3 -0
- package/dist/tools/package/remove-status.js +12 -0
- package/dist/tools/package/remove-status.js.map +1 -0
- package/dist/tools/package/remove.js +3 -3
- package/dist/tools/package/remove.js.map +1 -1
- package/dist/tools/package/resolve.js +3 -3
- package/dist/tools/package/resolve.js.map +1 -1
- package/dist/tools/package/restore.js +2 -2
- package/dist/tools/package/restore.js.map +1 -1
- package/dist/tools/package/scoped-registry-add.js.map +1 -1
- package/dist/tools/status/support.d.ts +13 -0
- package/dist/tools/status/support.js +28 -0
- package/dist/tools/status/support.js.map +1 -0
- package/dist/tools/test/cancel.js +2 -2
- package/dist/tools/test/cancel.js.map +1 -1
- package/dist/tools/test/run-status.d.ts +3 -0
- package/dist/tools/test/run-status.js +12 -0
- package/dist/tools/test/run-status.js.map +1 -0
- package/dist/tools/test/run.js +7 -4
- package/dist/tools/test/run.js.map +1 -1
- package/dist/tools/tools/group-summaries.js +10 -14
- package/dist/tools/tools/group-summaries.js.map +1 -1
- package/docs/architecture.md +4 -4
- package/docs/availability-differences.md +4 -4
- package/docs/command-execution.md +4 -3
- package/docs/error-codes.md +13 -5
- package/docs/extensions.md +1 -7
- package/docs/risk-and-side-effects.md +4 -3
- package/docs/safety-boundaries.md +3 -1
- package/docs/target-and-instance.md +1 -1
- package/docs/tool-discovery.md +17 -10
- package/docs/tool-execution.md +18 -7
- package/extensions/cinemachine/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
- package/extensions/hdrp/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
- package/extensions/probuilder/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
- package/extensions/urp/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
- package/extensions/vfx-graph/unitypkg/Editor/UnityCliExtensionAssembly.cs +3 -0
- package/package.json +2 -4
- package/skills/unitycli/SKILL.md +35 -42
- package/skills/unitycli/manifest.json +1 -1
- package/skills/unitycli/references/operation-protocol.md +3 -3
- package/unitypkg/Editor/AssemblyInfo.cs +5 -0
- package/unitypkg/Editor/Bridge/BridgeCommandRegistry.cs +49 -14
- package/unitypkg/Editor/Bridge/BridgeHttpServer.cs +9 -35
- package/unitypkg/Editor/Bridge/BridgeQueueState.cs +672 -0
- package/unitypkg/Editor/Bridge/BridgeWorkQueue.cs +970 -120
- package/unitypkg/Editor/BridgeStartupStateMachine.cs +59 -1
- package/unitypkg/Editor/Commands/ProjectToolCommands.cs +4 -0
- package/unitypkg/Editor/Commands/RuntimeToolCommands.cs +3 -0
- package/unitypkg/Editor/Generated/UnityCliToolCompletionRegistry.g.cs +379 -14
- package/unitypkg/Editor/Infrastructure/CodeExecSupport.cs +28 -13
- package/unitypkg/Editor/Infrastructure/RegistryOwnershipResolver.cs +132 -105
- package/unitypkg/Editor/Infrastructure/UnityCliActiveOperation.cs +138 -29
- package/unitypkg/Editor/Infrastructure/UnityCliAdmission.cs +1856 -237
- package/unitypkg/Editor/Infrastructure/UnityCliDoctorDiagnostics.cs +220 -0
- package/unitypkg/Editor/Infrastructure/UnityCliDurableStatusCoordinator.cs +118 -0
- package/unitypkg/Editor/Infrastructure/UnityCliEditorStateSnapshot.cs +2 -1
- package/unitypkg/Editor/Infrastructure/UnityCliHierarchyPager.cs +203 -0
- package/unitypkg/Editor/Infrastructure/UnityCliInstanceCleanup.cs +2 -1
- package/unitypkg/Editor/Infrastructure/UnityCliInstanceRegistry.cs +201 -63
- package/unitypkg/Editor/Infrastructure/UnityCliJson.cs +2 -3
- package/unitypkg/Editor/Infrastructure/UnityCliLiveBuildCoordinator.cs +289 -46
- package/unitypkg/Editor/Infrastructure/UnityCliLiveRefreshCoordinator.cs +87 -53
- package/unitypkg/Editor/Infrastructure/UnityCliNavMeshBakeCoordinator.cs +4 -4
- package/unitypkg/Editor/Infrastructure/UnityCliObjectRef.cs +128 -25
- package/unitypkg/Editor/Infrastructure/UnityCliObjectSerializer.cs +435 -327
- package/unitypkg/Editor/Infrastructure/UnityCliOcclusionBakeCoordinator.cs +4 -4
- package/unitypkg/Editor/Infrastructure/UnityCliOperationCoordinator.cs +351 -53
- package/unitypkg/Editor/Infrastructure/UnityCliPackageResolveCoordinator.cs +118 -18
- package/unitypkg/Editor/Infrastructure/UnityCliPackageResolveState.cs +20 -1
- package/unitypkg/Editor/Infrastructure/UnityCliReadGeneration.cs +97 -0
- package/unitypkg/Editor/Infrastructure/UnityCliReflection.cs +644 -133
- package/unitypkg/Editor/Infrastructure/UnityCliReloadOperation.cs +128 -41
- package/unitypkg/Editor/Infrastructure/UnityCliRuntimeExecutor.cs +14 -84
- package/unitypkg/Editor/Infrastructure/UnityCliSerializer.cs +220 -0
- package/unitypkg/Editor/Infrastructure/UnityCliSessionMutationLease.cs +69 -29
- package/unitypkg/Editor/Infrastructure/UnityCliTestRunCoordinator.cs +440 -54
- package/unitypkg/Editor/Infrastructure/UnityCliWaiter.cs +128 -35
- package/unitypkg/Editor/ProjectTools/IUnityCliTool.cs +9 -1
- package/unitypkg/Editor/ProjectTools/OfficialAttributeToolRegistry.cs +32 -31
- package/unitypkg/Editor/ProjectTools/ProjectToolRegistry.cs +607 -458
- package/unitypkg/Editor/ProjectTools/ProjectToolSchemaValidator.cs +35 -7
- package/unitypkg/Editor/ProjectTools/RegisteredTool.cs +501 -60
- package/unitypkg/Editor/ProjectTools/UnityCliProjectToolContext.cs +21 -0
- package/unitypkg/Editor/ProjectTools/UnityCliSchemaDeriver.cs +36 -7
- package/unitypkg/Editor/ProjectTools/UnityCliToolName.cs +30 -0
- package/unitypkg/Editor/Properties/AssemblyInfo.cs +3 -0
- package/unitypkg/Editor/Tools/asset/get-data.cs +16 -7
- package/unitypkg/Editor/Tools/build/BuildSceneStateTool.cs +23 -3
- package/unitypkg/Editor/Tools/build/BuildToolDtos.cs +2 -1
- package/unitypkg/Editor/Tools/build/scene/add.cs +6 -3
- package/unitypkg/Editor/Tools/build/scene/disable.cs +1 -1
- package/unitypkg/Editor/Tools/build/scene/enable.cs +1 -1
- package/unitypkg/Editor/Tools/build/scene/list.cs +1 -1
- package/unitypkg/Editor/Tools/build/scene/remove.cs +13 -3
- package/unitypkg/Editor/Tools/camera/CameraToolSupport.cs +38 -38
- package/unitypkg/Editor/Tools/camera/multiview.cs +13 -6
- package/unitypkg/Editor/Tools/camera/screenshot.cs +14 -7
- package/unitypkg/Editor/Tools/component/get.cs +16 -9
- package/unitypkg/Editor/Tools/component/modify.cs +6 -4
- package/unitypkg/Editor/Tools/console/clear.cs +7 -6
- package/unitypkg/Editor/Tools/console/get.cs +48 -16
- package/unitypkg/Editor/Tools/editor/EditorToolSupport.cs +143 -28
- package/unitypkg/Editor/Tools/editor/menu-items.cs +1 -1
- package/unitypkg/Editor/Tools/editor/play.cs +2 -11
- package/unitypkg/Editor/Tools/editor/selection.cs +1 -1
- package/unitypkg/Editor/Tools/editor/stop.cs +2 -11
- package/unitypkg/Editor/Tools/editor/windows.cs +1 -1
- package/unitypkg/Editor/Tools/go/GameObjectToolSupport.cs +54 -4
- package/unitypkg/Editor/Tools/go/delete.cs +1 -1
- package/unitypkg/Editor/Tools/go/find.cs +167 -70
- package/unitypkg/Editor/Tools/graphics/GraphicsToolSupport.cs +25 -0
- package/unitypkg/Editor/Tools/graphics/light-probe-group.cs +9 -3
- package/unitypkg/Editor/Tools/graphics/pipeline-info.cs +1 -1
- package/unitypkg/Editor/Tools/graphics/pipeline-settings.cs +1 -1
- package/unitypkg/Editor/Tools/graphics/quality.cs +2 -2
- package/unitypkg/Editor/Tools/graphics/reflection-probe.cs +3 -3
- package/unitypkg/Editor/Tools/graphics/stats.cs +1 -1
- package/unitypkg/Editor/Tools/object/ObjectToolSupport.cs +4 -4
- package/unitypkg/Editor/Tools/object/get-data.cs +9 -7
- package/unitypkg/Editor/Tools/object/modify.cs +7 -5
- package/unitypkg/Editor/Tools/physics/raycast.cs +24 -6
- package/unitypkg/Editor/Tools/prefab/stage.cs +1 -1
- package/unitypkg/Editor/Tools/profiler/ProfilerFrameDebuggerSupport.cs +94 -21
- package/unitypkg/Editor/Tools/profiler/ProfilerMemorySnapshotSupport.cs +397 -10
- package/unitypkg/Editor/Tools/profiler/ProfilerToolSupport.cs +18 -4
- package/unitypkg/Editor/Tools/profiler/frame-debugger/enable.cs +1 -1
- package/unitypkg/Editor/Tools/profiler/frame-debugger/events.cs +88 -87
- package/unitypkg/Editor/Tools/profiler/hierarchy.cs +278 -112
- package/unitypkg/Editor/Tools/profiler/memory-snapshot/compare.cs +9 -5
- package/unitypkg/Editor/Tools/profiler/memory-snapshot/list.cs +37 -35
- package/unitypkg/Editor/Tools/profiler/memory-snapshot/take.cs +99 -97
- package/unitypkg/Editor/Tools/project/info.cs +1 -1
- package/unitypkg/Editor/Tools/project/layers.cs +1 -1
- package/unitypkg/Editor/Tools/project/tags.cs +1 -1
- package/unitypkg/Editor/Tools/reflection/method/call.cs +9 -7
- package/unitypkg/Editor/Tools/reflection/method/find.cs +27 -37
- package/unitypkg/Editor/Tools/reflection/type/schema.cs +24 -28
- package/unitypkg/Editor/Tools/scene/gameobject/component.cs +8 -5
- package/unitypkg/Editor/Tools/scene/gameobject/components.cs +10 -7
- package/unitypkg/Editor/Tools/scene/gameobject-support.cs +104 -8
- package/unitypkg/Editor/Tools/scene/gameobject.cs +37 -16
- package/unitypkg/Editor/Tools/scene/hierarchy.cs +146 -142
- package/unitypkg/Editor/Tools/screenshot/EditorElementCaptureToolSupport.cs +77 -25
- package/unitypkg/Editor/Tools/screenshot/ScreenshotToolSupport.cs +315 -95
- package/unitypkg/Editor/Tools/screenshot/editor-element.cs +7 -5
- package/unitypkg/Editor/Tools/screenshot/game-view.cs +35 -21
- package/unitypkg/Editor/Tools/screenshot/isolated-object.cs +29 -23
- package/unitypkg/Editor/Tools/screenshot/orbit.cs +37 -25
- package/unitypkg/Editor/Tools/screenshot/scene-view.cs +25 -18
- package/unitypkg/Editor/Tools/screenshot/screen.cs +177 -17
- package/unitypkg/Editor/Tools/screenshot/surround.cs +83 -79
- package/unitypkg/Editor/Tools/ui/render-preview.cs +16 -11
- package/unitypkg/Editor/UnityCliBridge.cs +97 -34
- package/unitypkg/Runtime/Infrastructure/UnityCliRuntimeBridge.cs +753 -122
- package/unitypkg/Runtime/Properties/AssemblyInfo.cs +5 -0
- package/unitypkg/Runtime/UnityCli.Runtime.asmdef +1 -1
- package/unitypkg/Shared/AssemblyInfo.cs +4 -0
- package/unitypkg/Shared/UnityCliAdmissionPool.cs +265 -75
- package/unitypkg/Shared/UnityCliBridgeQueuePolicy.cs +410 -0
- package/unitypkg/Shared/UnityCliBridgeWorkItemState.cs +47 -0
- package/unitypkg/Shared/UnityCliExceptionProjection.cs +151 -0
- package/unitypkg/Shared/UnityCliQueuePublication.cs +30 -0
- package/unitypkg/Shared/UnityCliRequestBudget.cs +352 -0
- package/unitypkg/Shared/UnityCliRuntimeRequestPublication.cs +107 -0
- package/unitypkg/Tests/Editor/UnityCli.Editor.Tests.asmdef +2 -2
- package/unitypkg/Tests/Editor/UnityCliAdmissionCoordinatorIntegrationTests.cs +1329 -0
- package/unitypkg/Tests/Editor/UnityCliAdmissionPoolTests.cs +311 -114
- package/unitypkg/Tests/Editor/UnityCliAdmissionRepairStateTests.cs +94 -0
- package/unitypkg/Tests/Editor/UnityCliBridgeAdmissionIntegrationTests.cs +1229 -0
- package/unitypkg/Tests/Editor/UnityCliBridgeQueuePolicyTests.cs +412 -0
- package/unitypkg/Tests/Editor/UnityCliContinuationIntegrationTests.cs +292 -0
- package/unitypkg/Tests/Editor/UnityCliDiagnosticBoundaryTests.cs +120 -0
- package/unitypkg/Tests/Editor/UnityCliDurableStatusTests.cs +84 -0
- package/unitypkg/Tests/Editor/UnityCliExceptionProjectionTests.cs +72 -0
- package/unitypkg/Tests/Editor/UnityCliInstancePublicationRetryTests.cs +180 -97
- package/unitypkg/Tests/Editor/UnityCliMemoryReflectionIntegrationTests.cs +434 -0
- package/unitypkg/Tests/Editor/UnityCliRequestBudgetTests.cs +615 -0
- package/unitypkg/Tests/Editor/UnityCliRuntimeBridgeIntegrationTests.cs +520 -0
- package/unitypkg/Tests/Editor/UnityCliToolCatalogTests.cs +562 -0
- package/unitypkg/Tests/Runtime/UnityCli.Runtime.Tests.asmdef +23 -0
- package/unitypkg/Tests/Runtime/UnityCliRuntimeCatalogValidationTests.cs +29 -0
- package/unitypkg/package.json +1 -1
- package/contracts/static-capability-catalog.json +0 -48226
- package/dist/bridge/domains/diagnose.d.ts +0 -2
- package/dist/bridge/domains/diagnose.js +0 -11
- package/dist/bridge/domains/diagnose.js.map +0 -1
- package/dist/bridge/domains/extension.d.ts +0 -8
- package/dist/bridge/domains/extension.js +0 -20
- package/dist/bridge/domains/extension.js.map +0 -1
- package/dist/capabilities.d.ts +0 -5
- package/dist/capabilities.js +0 -84
- package/dist/capabilities.js.map +0 -1
- package/dist/static-capability-catalog.d.ts +0 -13
- package/dist/static-capability-catalog.js +0 -41
- package/dist/static-capability-catalog.js.map +0 -1
- package/dist/tools/diagnose/capabilities.d.ts +0 -13
- package/dist/tools/diagnose/capabilities.js +0 -34
- package/dist/tools/diagnose/capabilities.js.map +0 -1
- package/dist/tools/package/info.d.ts +0 -19
- package/dist/tools/package/info.js +0 -27
- package/dist/tools/package/info.js.map +0 -1
- package/dist/tools/package/list.d.ts +0 -27
- package/dist/tools/package/list.js +0 -21
- package/dist/tools/package/list.js.map +0 -1
- package/dist/tools/package/registry-get.d.ts +0 -10
- package/dist/tools/package/registry-get.js +0 -22
- package/dist/tools/package/registry-get.js.map +0 -1
- package/dist/tools/package/scoped-registry-list.d.ts +0 -14
- package/dist/tools/package/scoped-registry-list.js +0 -22
- package/dist/tools/package/scoped-registry-list.js.map +0 -1
- package/dist/tools/package/search.d.ts +0 -17
- package/dist/tools/package/search.js +0 -39
- package/dist/tools/package/search.js.map +0 -1
- package/dist/tools/package/status.d.ts +0 -21
- package/dist/tools/package/status.js +0 -37
- package/dist/tools/package/status.js.map +0 -1
- package/dist/tools/tools/describe.d.ts +0 -27
- package/dist/tools/tools/describe.js +0 -35
- package/dist/tools/tools/describe.js.map +0 -1
- package/dist/tools/tools/group-list.d.ts +0 -16
- package/dist/tools/tools/group-list.js +0 -38
- package/dist/tools/tools/group-list.js.map +0 -1
- package/dist/tools/tools/group.d.ts +0 -13
- package/dist/tools/tools/group.js +0 -34
- package/dist/tools/tools/group.js.map +0 -1
- package/dist/tools/tools/pagination.d.ts +0 -17
- package/dist/tools/tools/pagination.js +0 -28
- package/dist/tools/tools/pagination.js.map +0 -1
- package/dist/tools/tools/search.d.ts +0 -15
- package/dist/tools/tools/search.js +0 -42
- package/dist/tools/tools/search.js.map +0 -1
- package/unitypkg/Editor/Tools/diagnose/preflight.cs +0 -269
- package/unitypkg/Editor/Tools/editor/console.cs +0 -26
- package/unitypkg/Editor/Tools/extension/status.cs +0 -87
- package/unitypkg/Editor/Tools/go/inspect.cs +0 -49
- package/unitypkg/Editor/Tools/graphics/pipeline-quality.cs +0 -24
- package/unitypkg/Editor/Tools/graphics/probe-positions.cs +0 -58
- package/unitypkg/Editor/Tools/graphics/settings.cs +0 -104
- package/unitypkg/Editor/Tools/graphics/stats-counters.cs +0 -28
- package/unitypkg/Editor/Tools/graphics/stats-memory.cs +0 -21
- package/unitypkg/Editor/Tools/instances/list.cs +0 -71
- package/unitypkg/Editor/Tools/physics/raycast-all.cs +0 -67
- package/unitypkg/Editor/Tools/scene/build-settings.cs +0 -69
- package/unitypkg/Editor/Tools/scene/data.cs +0 -125
- package/unitypkg/Editor/Tools/tests/list.cs +0 -98
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
#if UNITY_EDITOR
|
|
2
|
+
using System;
|
|
3
|
+
using System.Collections;
|
|
4
|
+
using System.CodeDom.Compiler;
|
|
5
|
+
using System.Collections.Generic;
|
|
6
|
+
using System.Linq;
|
|
7
|
+
using System.Reflection;
|
|
8
|
+
using System.Text;
|
|
9
|
+
using System.Threading;
|
|
10
|
+
using System.Threading.Tasks;
|
|
11
|
+
using Microsoft.CSharp;
|
|
12
|
+
using NUnit.Framework;
|
|
13
|
+
|
|
14
|
+
namespace UnityCli.Tests
|
|
15
|
+
{
|
|
16
|
+
public static class UnityCliToolCatalogFixtureProbe
|
|
17
|
+
{
|
|
18
|
+
private static readonly object Sync = new object();
|
|
19
|
+
private static readonly Dictionary<string, int> DescribeCounts = new Dictionary<string, int>(StringComparer.Ordinal);
|
|
20
|
+
|
|
21
|
+
public static void Reset()
|
|
22
|
+
{
|
|
23
|
+
lock (Sync)
|
|
24
|
+
{
|
|
25
|
+
DescribeCounts.Clear();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
public static void RecordDescribe(string providerName)
|
|
30
|
+
{
|
|
31
|
+
lock (Sync)
|
|
32
|
+
{
|
|
33
|
+
int current;
|
|
34
|
+
DescribeCounts.TryGetValue(providerName, out current);
|
|
35
|
+
DescribeCounts[providerName] = current + 1;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
public static Dictionary<string, int> Snapshot()
|
|
40
|
+
{
|
|
41
|
+
lock (Sync)
|
|
42
|
+
{
|
|
43
|
+
return new Dictionary<string, int>(DescribeCounts, StringComparer.Ordinal);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public sealed class UnityCliToolCatalogTests
|
|
49
|
+
{
|
|
50
|
+
private static Assembly[] compiledProjectToolProviderAssemblies;
|
|
51
|
+
private Type bridgeType;
|
|
52
|
+
private Type builderType;
|
|
53
|
+
private Type providerKindType;
|
|
54
|
+
private Type registeredToolType;
|
|
55
|
+
private Type ownershipType;
|
|
56
|
+
private FieldInfo publishedField;
|
|
57
|
+
private FieldInfo healthField;
|
|
58
|
+
private object publishedTemplate;
|
|
59
|
+
|
|
60
|
+
[SetUp]
|
|
61
|
+
public void SetUp()
|
|
62
|
+
{
|
|
63
|
+
bridgeType = Type.GetType("UnityCli.UnityCliBridge, UnityCli.Editor", true);
|
|
64
|
+
builderType = Type.GetType("UnityCli.UnityCliToolCatalogBuilder, UnityCli.Editor", true);
|
|
65
|
+
providerKindType = Type.GetType("UnityCli.UnityCliToolProviderKind, UnityCli.Editor", true);
|
|
66
|
+
registeredToolType = Type.GetType("UnityCli.RegisteredTool, UnityCli.Editor", true);
|
|
67
|
+
ownershipType = Type.GetType("UnityCli.RegistryToolOwnership, UnityCli.Editor", true);
|
|
68
|
+
publishedField = Field("publishedProjectToolCatalog");
|
|
69
|
+
healthField = Field("projectToolCatalogHealth");
|
|
70
|
+
publishedTemplate = FirstValue(Property(publishedField.GetValue(null), "ExecutableTools").GetValue(publishedField.GetValue(null)));
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
[Test]
|
|
74
|
+
public void StaticConstructorPublishesOneImmutableDescriptorSnapshotAndLaterReadsDoNoDiscoveryWork()
|
|
75
|
+
{
|
|
76
|
+
var first = ReadPublishedSnapshot();
|
|
77
|
+
var second = ReadPublishedSnapshot();
|
|
78
|
+
Assert.That(second, Is.SameAs(first));
|
|
79
|
+
Assert.That((int)Field("projectToolCatalogConstructionCount").GetValue(null), Is.EqualTo(1));
|
|
80
|
+
Assert.That(Int(first, "DiscoveryPassCount"), Is.EqualTo(1));
|
|
81
|
+
Assert.That(Int(first, "ProviderMetadataReadCount"), Is.EqualTo(Int(first, "ProviderAssemblyCount")));
|
|
82
|
+
Assert.That(Int(first, "AggregateSuccessLogCount"), Is.EqualTo(1));
|
|
83
|
+
|
|
84
|
+
var descriptor = FirstTool(first);
|
|
85
|
+
foreach (var privateExecutionMember in new[] { "InvokeAsync", "RequestType", "ResultType", "OfficialAttributeBinding", "OwnerIdentity" })
|
|
86
|
+
Assert.That(descriptor.GetType().GetProperty(privateExecutionMember, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance), Is.Null, privateExecutionMember);
|
|
87
|
+
Assert.That(descriptor.GetType().GetProperties().Where(property => property.SetMethod != null), Is.Empty);
|
|
88
|
+
|
|
89
|
+
var firstExamples = (IList)Invoke(descriptor, "CloneExamples");
|
|
90
|
+
var firstExample = (IDictionary<string, object>)firstExamples[0];
|
|
91
|
+
firstExample["description"] = "mutated test copy";
|
|
92
|
+
var secondExamples = (IList)Invoke(descriptor, "CloneExamples");
|
|
93
|
+
Assert.That(((IDictionary<string, object>)secondExamples[0])["description"], Is.Not.EqualTo("mutated test copy"));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
[Test]
|
|
97
|
+
public void CatalogFingerprintIsCachedStableAndBindsPublishedDescriptorContent()
|
|
98
|
+
{
|
|
99
|
+
var previousCatalog = publishedField.GetValue(null);
|
|
100
|
+
var previousHealth = healthField.GetValue(null);
|
|
101
|
+
try
|
|
102
|
+
{
|
|
103
|
+
var firstBuilder = NewBuilder(1, 1);
|
|
104
|
+
Add(firstBuilder, Definition("fixture.fingerprint", "project", "native", "fixture"), "ProjectInterface");
|
|
105
|
+
var firstSnapshot = PublishThroughProductionSlot(firstBuilder, 1L);
|
|
106
|
+
var firstFingerprint = (string)Property(firstSnapshot, "ToolCatalogFingerprint").GetValue(firstSnapshot);
|
|
107
|
+
|
|
108
|
+
var sameBuilder = NewBuilder(1, 1);
|
|
109
|
+
Add(sameBuilder, Definition("fixture.fingerprint", "project", "native", "fixture"), "ProjectInterface");
|
|
110
|
+
var sameSnapshot = PublishThroughProductionSlot(sameBuilder, 999L);
|
|
111
|
+
var sameFingerprint = (string)Property(sameSnapshot, "ToolCatalogFingerprint").GetValue(sameSnapshot);
|
|
112
|
+
|
|
113
|
+
var changedBuilder = NewBuilder(1, 1);
|
|
114
|
+
Add(changedBuilder, Definition("fixture.fingerprint", "project", "native", "fixture", "Changed fixture summary."), "ProjectInterface");
|
|
115
|
+
var changedSnapshot = PublishThroughProductionSlot(changedBuilder, 1L);
|
|
116
|
+
var changedFingerprint = (string)Property(changedSnapshot, "ToolCatalogFingerprint").GetValue(changedSnapshot);
|
|
117
|
+
|
|
118
|
+
Assert.That(firstFingerprint, Does.Match("^[0-9a-f]{64}$"));
|
|
119
|
+
Assert.That(Property(firstSnapshot, "ToolCatalogFingerprint").GetValue(firstSnapshot), Is.SameAs(firstFingerprint));
|
|
120
|
+
Assert.That(sameFingerprint, Is.EqualTo(firstFingerprint));
|
|
121
|
+
Assert.That(changedFingerprint, Is.Not.EqualTo(firstFingerprint));
|
|
122
|
+
}
|
|
123
|
+
finally
|
|
124
|
+
{
|
|
125
|
+
publishedField.SetValue(null, previousCatalog);
|
|
126
|
+
healthField.SetValue(null, previousHealth);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
[Test]
|
|
131
|
+
public void ProviderMetadataCountersAndThreeHundredOneEntriesFlowThroughProductionPublication()
|
|
132
|
+
{
|
|
133
|
+
var previousCatalog = publishedField.GetValue(null);
|
|
134
|
+
var previousHealth = healthField.GetValue(null);
|
|
135
|
+
try
|
|
136
|
+
{
|
|
137
|
+
UnityCliToolCatalogFixtureProbe.Reset();
|
|
138
|
+
var fixtureAssemblies = CompileProjectToolProviderAssemblies(301);
|
|
139
|
+
var builder = Activator.CreateInstance(builderType, true);
|
|
140
|
+
var collect = bridgeType.GetMethod("CollectProjectToolCatalog", BindingFlags.NonPublic | BindingFlags.Static);
|
|
141
|
+
collect.Invoke(null, new object[] { AppDomain.CurrentDomain.GetAssemblies(), builder });
|
|
142
|
+
var snapshot = PublishThroughProductionSlot(builder, 12L);
|
|
143
|
+
Assert.That(ReadPublishedSnapshot(), Is.SameAs(snapshot));
|
|
144
|
+
Assert.That(Int(snapshot, "ProviderAssemblyCount"), Is.GreaterThanOrEqualTo(302));
|
|
145
|
+
Assert.That(Int(snapshot, "ProjectInterfaceToolCount"), Is.GreaterThanOrEqualTo(301));
|
|
146
|
+
Assert.That(Int(snapshot, "ToolCount"), Is.GreaterThanOrEqualTo(301));
|
|
147
|
+
|
|
148
|
+
var descriptors = ((IEnumerable)Property(snapshot, "Descriptors").GetValue(snapshot)).Cast<object>().ToList();
|
|
149
|
+
var fixtureDescriptorNames = descriptors
|
|
150
|
+
.Select(item => (string)Property(item, "Name").GetValue(item))
|
|
151
|
+
.Where(name => name.StartsWith("fixture.generated.", StringComparison.Ordinal))
|
|
152
|
+
.ToList();
|
|
153
|
+
var describeCounts = UnityCliToolCatalogFixtureProbe.Snapshot();
|
|
154
|
+
|
|
155
|
+
Assert.That(fixtureAssemblies.Length, Is.EqualTo(301));
|
|
156
|
+
Assert.That(fixtureAssemblies.All(assembly => assembly.GetTypes().Count(type => !type.IsAbstract && type.Name.StartsWith("GeneratedTool", StringComparison.Ordinal)) == 1), Is.True);
|
|
157
|
+
Assert.That(fixtureDescriptorNames.Count, Is.EqualTo(301));
|
|
158
|
+
Assert.That(fixtureDescriptorNames.Distinct(StringComparer.Ordinal).Count(), Is.EqualTo(301));
|
|
159
|
+
Assert.That(describeCounts.Count, Is.EqualTo(301));
|
|
160
|
+
Assert.That(describeCounts.Values.All(count => count == 1), Is.True);
|
|
161
|
+
Assert.That(fixtureDescriptorNames, Is.EquivalentTo(describeCounts.Keys));
|
|
162
|
+
}
|
|
163
|
+
finally
|
|
164
|
+
{
|
|
165
|
+
publishedField.SetValue(null, previousCatalog);
|
|
166
|
+
healthField.SetValue(null, previousHealth);
|
|
167
|
+
UnityCliToolCatalogFixtureProbe.Reset();
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
[Test]
|
|
172
|
+
public void NthEntryFailureCannotReplaceThePublishedSlot()
|
|
173
|
+
{
|
|
174
|
+
var previousCatalog = publishedField.GetValue(null);
|
|
175
|
+
var previousHealth = healthField.GetValue(null);
|
|
176
|
+
try
|
|
177
|
+
{
|
|
178
|
+
var candidate = NewBuilder(1, 1);
|
|
179
|
+
Add(candidate, Definition("fixture.published", "project", "native", "fixture"), "ProjectInterface");
|
|
180
|
+
PublishThroughProductionSlot(candidate, 1L);
|
|
181
|
+
var publishedCandidate = publishedField.GetValue(null);
|
|
182
|
+
|
|
183
|
+
var failed = NewBuilder(1, 1);
|
|
184
|
+
Add(failed, Definition("fixture.first", "project", "native", "fixture"), "ProjectInterface");
|
|
185
|
+
Assert.That(() => Add(failed, Definition("fixture.first", "project", "native", "fixture"), "ProjectInterface"), Throws.TypeOf<TargetInvocationException>());
|
|
186
|
+
Assert.That(() => PublishThroughProductionSlot(failed, 1L), Throws.TypeOf<TargetInvocationException>());
|
|
187
|
+
Assert.That(publishedField.GetValue(null), Is.SameAs(publishedCandidate));
|
|
188
|
+
Assert.That(ReadPublishedSnapshot(), Is.SameAs(Property(publishedCandidate, "Snapshot").GetValue(publishedCandidate)));
|
|
189
|
+
}
|
|
190
|
+
finally
|
|
191
|
+
{
|
|
192
|
+
publishedField.SetValue(null, previousCatalog);
|
|
193
|
+
healthField.SetValue(null, previousHealth);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
[Test]
|
|
198
|
+
public void UnhealthyHealthSnapshotRemainsReadableWhileCatalogReaderFailsClosed()
|
|
199
|
+
{
|
|
200
|
+
var previousCatalog = publishedField.GetValue(null);
|
|
201
|
+
var previousHealth = healthField.GetValue(null);
|
|
202
|
+
try
|
|
203
|
+
{
|
|
204
|
+
var healthType = Type.GetType("UnityCli.UnityCliToolCatalogHealthSnapshot, UnityCli.Editor", true);
|
|
205
|
+
var health = Activator.CreateInstance(healthType, BindingFlags.Instance | BindingFlags.NonPublic, null,
|
|
206
|
+
new object[] { false, 0, "bounded failure", "reload domain" }, null);
|
|
207
|
+
publishedField.SetValue(null, null);
|
|
208
|
+
healthField.SetValue(null, health);
|
|
209
|
+
|
|
210
|
+
var healthReader = bridgeType.GetProperty("ProjectToolCatalogHealthSnapshotReader", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
|
|
211
|
+
var observed = healthReader.GetType().GetMethod("Read", BindingFlags.Public | BindingFlags.Instance).Invoke(healthReader, null);
|
|
212
|
+
Assert.That((bool)Property(observed, "Ready").GetValue(observed), Is.False);
|
|
213
|
+
Assert.That((string)Property(observed, "Failure").GetValue(observed), Is.EqualTo("bounded failure"));
|
|
214
|
+
var exception = Assert.Throws<TargetInvocationException>(() => ReadPublishedSnapshot());
|
|
215
|
+
Assert.That(((UnityCliBridge.BridgeCommandException)exception.InnerException).Code, Is.EqualTo("E_TOOL_REGISTRY_UNHEALTHY"));
|
|
216
|
+
}
|
|
217
|
+
finally
|
|
218
|
+
{
|
|
219
|
+
publishedField.SetValue(null, previousCatalog);
|
|
220
|
+
healthField.SetValue(null, previousHealth);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
[Test]
|
|
225
|
+
public void DuplicateInvalidOrOversizedDescriptorFaultsBuilderWithoutPublication()
|
|
226
|
+
{
|
|
227
|
+
var duplicate = NewBuilder(1, 1);
|
|
228
|
+
Add(duplicate, Definition("fixture.duplicate", "project", "native", "fixture"), "ProjectInterface");
|
|
229
|
+
Assert.That(() => Add(duplicate, Definition("fixture.duplicate", "project", "native", "fixture"), "ProjectInterface"), Throws.TypeOf<TargetInvocationException>());
|
|
230
|
+
Assert.That(() => PublishThroughProductionSlot(duplicate, 1L), Throws.TypeOf<TargetInvocationException>());
|
|
231
|
+
|
|
232
|
+
var oversized = NewBuilder(1, 1);
|
|
233
|
+
Assert.That(() => Add(oversized, Definition("fixture." + new string('n', 249), "project", "native", "fixture"), "ProjectInterface"), Throws.TypeOf<TargetInvocationException>());
|
|
234
|
+
Assert.That(() => PublishThroughProductionSlot(oversized, 1L), Throws.TypeOf<TargetInvocationException>());
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
[Test]
|
|
238
|
+
public void MultibyteDescriptorBoundsAndCompleteCatalogEnvelopesUseUtf8Bytes()
|
|
239
|
+
{
|
|
240
|
+
var accepted = NewBuilder(1, 1);
|
|
241
|
+
Assert.That(() => Add(accepted, Definition("fixture.utf8.accepted", "project", "native", new string('组', 85), new string('界', 170) + "ab"), "ProjectInterface"), Throws.Nothing);
|
|
242
|
+
|
|
243
|
+
var rejected = NewBuilder(1, 1);
|
|
244
|
+
Assert.That(() => Add(rejected, Definition("fixture.utf8.too-long", "project", "native", new string('组', 85), new string('界', 170) + "abc"), "ProjectInterface"),
|
|
245
|
+
Throws.TypeOf<TargetInvocationException>());
|
|
246
|
+
var rejectedGroup = NewBuilder(1, 1);
|
|
247
|
+
Assert.That(() => Add(rejectedGroup, Definition("fixture.utf8.group-too-long", "project", "native", new string('组', 86)), "ProjectInterface"),
|
|
248
|
+
Throws.TypeOf<TargetInvocationException>());
|
|
249
|
+
|
|
250
|
+
var previousCatalog = publishedField.GetValue(null);
|
|
251
|
+
var previousHealth = healthField.GetValue(null);
|
|
252
|
+
try
|
|
253
|
+
{
|
|
254
|
+
var builder = NewBuilder(4096, 1);
|
|
255
|
+
for (var index = 0; index < 4096; index++)
|
|
256
|
+
Add(builder, Definition("fixture.bound." + index.ToString("D4"), "project", "native", "g" + index.ToString("D4"), new string('界', 170)), "ProjectInterface");
|
|
257
|
+
PublishThroughProductionSlot(builder, 1L);
|
|
258
|
+
var summaryRequest = CursorSummaryRequest(null, null);
|
|
259
|
+
((IDictionary<string, object>)summaryRequest.Input)["limit"] = 101;
|
|
260
|
+
var summary = bridgeType.GetMethod("ProjectToolCatalogSummary", BindingFlags.NonPublic | BindingFlags.Static)
|
|
261
|
+
.Invoke(null, new object[] { summaryRequest, false });
|
|
262
|
+
Assert.That(Encoding.UTF8.GetByteCount(UnityCliSerializer.Serialize(summary)), Is.LessThanOrEqualTo(256 * 1024));
|
|
263
|
+
Assert.That(((IList)((IDictionary<string, object>)summary)["tools"]).Count, Is.EqualTo(101));
|
|
264
|
+
Assert.That((bool)((IDictionary<string, object>)summary)["hasMore"], Is.True);
|
|
265
|
+
|
|
266
|
+
var groupsRequest = new UnityCli.Protocol.BridgeRequest
|
|
267
|
+
{
|
|
268
|
+
Input = new Dictionary<string, object> { { "reservedNames", new List<object>() } }
|
|
269
|
+
};
|
|
270
|
+
var groups = bridgeType.GetMethod("ProjectToolCatalogGroups", BindingFlags.NonPublic | BindingFlags.Static)
|
|
271
|
+
.Invoke(null, new object[] { groupsRequest, false });
|
|
272
|
+
Assert.That(Encoding.UTF8.GetByteCount(UnityCliSerializer.Serialize(groups)), Is.LessThanOrEqualTo(2 * 1024 * 1024));
|
|
273
|
+
Assert.That(((IList)((IDictionary<string, object>)groups)["groups"]).Count, Is.EqualTo(4096));
|
|
274
|
+
}
|
|
275
|
+
finally
|
|
276
|
+
{
|
|
277
|
+
publishedField.SetValue(null, previousCatalog);
|
|
278
|
+
healthField.SetValue(null, previousHealth);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
[Test]
|
|
283
|
+
public void SerializedSummaryBudgetTruncatesWithAnAccurateSignedBoundary()
|
|
284
|
+
{
|
|
285
|
+
var names = Enumerable.Range(0, 101).Select(index => "fixture.bytes." + index.ToString("D3")).ToList();
|
|
286
|
+
var pageNames = names.ToList();
|
|
287
|
+
var tools = names.Select(name => (object)new Dictionary<string, object>
|
|
288
|
+
{
|
|
289
|
+
{ "name", name }, { "summary", new string('界', 170) + "ab" }, { "group", "fixture" },
|
|
290
|
+
{ "target", "editor" }, { "contractProfile", "native" }, { "commandName", name },
|
|
291
|
+
{ "available", false }, { "unavailableReason", new string('界', 682) }
|
|
292
|
+
}).ToList();
|
|
293
|
+
var bounded = (IDictionary<string, object>)bridgeType.GetMethod("BoundSignedCatalogSummaryData", BindingFlags.NonPublic | BindingFlags.Static)
|
|
294
|
+
.Invoke(null, new object[] { new string('g', 64), 101, names, 0, pageNames, tools, new string('s', 64) });
|
|
295
|
+
Assert.That(Encoding.UTF8.GetByteCount(UnityCliSerializer.Serialize(bounded)), Is.LessThanOrEqualTo(256 * 1024));
|
|
296
|
+
var emittedNames = ((IEnumerable)bounded["pageNames"]).Cast<object>().Select(Convert.ToString).ToList();
|
|
297
|
+
Assert.That(emittedNames.Count, Is.InRange(1, 100));
|
|
298
|
+
Assert.That((bool)bounded["hasMore"], Is.True);
|
|
299
|
+
var tokenFields = Encoding.UTF8.GetString(FromBase64Url(((string)bounded["continuationToken"]).Split('.')[0])).Split('\n');
|
|
300
|
+
Assert.That(Encoding.UTF8.GetString(Convert.FromBase64String(tokenFields[2])), Is.EqualTo(emittedNames.Last()));
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
[Test]
|
|
304
|
+
public void EditorContinuationRejectsAlteredExistingAndUnknownBoundariesInSameGeneration()
|
|
305
|
+
{
|
|
306
|
+
var previousCatalog = publishedField.GetValue(null);
|
|
307
|
+
var previousHealth = healthField.GetValue(null);
|
|
308
|
+
try
|
|
309
|
+
{
|
|
310
|
+
var builder = NewBuilder(1, 1);
|
|
311
|
+
foreach (var name in new[] { "fixture.cursor.a", "fixture.cursor.b", "fixture.cursor.c" })
|
|
312
|
+
Add(builder, Definition(name, "project", "native", "fixture"), "ProjectInterface");
|
|
313
|
+
PublishThroughProductionSlot(builder, 1L);
|
|
314
|
+
var summary = bridgeType.GetMethod("ProjectToolCatalogSummary", BindingFlags.NonPublic | BindingFlags.Static);
|
|
315
|
+
var firstRequest = CursorSummaryRequest(null, null);
|
|
316
|
+
var first = (IDictionary<string, object>)summary.Invoke(null, new object[] { firstRequest, false });
|
|
317
|
+
var token = (string)first["continuationToken"];
|
|
318
|
+
var generation = (string)first["catalogGeneration"];
|
|
319
|
+
foreach (var boundary in new[] { "fixture.cursor.c", "fixture.cursor.unknown" })
|
|
320
|
+
{
|
|
321
|
+
var request = CursorSummaryRequest(generation, AlterCursorBoundary(token, boundary));
|
|
322
|
+
var exception = Assert.Throws<TargetInvocationException>(() => summary.Invoke(null, new object[] { request, false }));
|
|
323
|
+
Assert.That(((UnityCliBridge.BridgeCommandException)exception.InnerException).Code, Is.EqualTo("E_DISCOVERY_CURSOR_INVALID"), boundary);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
finally
|
|
327
|
+
{
|
|
328
|
+
publishedField.SetValue(null, previousCatalog);
|
|
329
|
+
healthField.SetValue(null, previousHealth);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
[Test]
|
|
334
|
+
public void EditorDescribeAcceptsOneExactFallbackWhileRuntimeDescribeRejectsIt()
|
|
335
|
+
{
|
|
336
|
+
var describe = bridgeType.GetMethod("ProjectToolCatalogDescribe", BindingFlags.NonPublic | BindingFlags.Static);
|
|
337
|
+
var request = new UnityCli.Protocol.BridgeRequest
|
|
338
|
+
{
|
|
339
|
+
Input = new Dictionary<string, object> { { "name", "fixture.missing" }, { "fallbackName", "fixture.also-missing" } }
|
|
340
|
+
};
|
|
341
|
+
Assert.That(() => describe.Invoke(null, new object[] { request, false }), Throws.Nothing);
|
|
342
|
+
var exception = Assert.Throws<TargetInvocationException>(() => describe.Invoke(null, new object[] { request, true }));
|
|
343
|
+
Assert.That(((UnityCliBridge.BridgeCommandException)exception.InnerException).Code, Is.EqualTo("E_SCHEMA_INVALID"));
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
[Test]
|
|
347
|
+
public void PrivateCatalogReadersRejectUnknownInputBeforeSnapshotProjection()
|
|
348
|
+
{
|
|
349
|
+
var request = new UnityCli.Protocol.BridgeRequest
|
|
350
|
+
{
|
|
351
|
+
Input = new Dictionary<string, object> { { "limit", 20L }, { "unknown", true } }
|
|
352
|
+
};
|
|
353
|
+
var summary = bridgeType.GetMethod("ProjectToolCatalogSummary", BindingFlags.NonPublic | BindingFlags.Static);
|
|
354
|
+
var exception = Assert.Throws<TargetInvocationException>(() => summary.Invoke(null, new object[] { request, false }));
|
|
355
|
+
Assert.That(((UnityCliBridge.BridgeCommandException)exception.InnerException).Code, Is.EqualTo("E_SCHEMA_INVALID"));
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
[Test]
|
|
359
|
+
public void UnsupportedOfficialSignatureOrReturnTypeCannotPublishPendingTable()
|
|
360
|
+
{
|
|
361
|
+
var validate = bridgeType.GetMethod("ValidateOfficialMethodSignature", BindingFlags.NonPublic | BindingFlags.Static);
|
|
362
|
+
var invalidMethod = GetType().GetMethod("InstanceOfficialMethod", BindingFlags.NonPublic | BindingFlags.Instance);
|
|
363
|
+
Assert.That(() => validate.Invoke(null, new object[] { invalidMethod }), Throws.TypeOf<TargetInvocationException>());
|
|
364
|
+
|
|
365
|
+
var output = bridgeType.GetMethod("BuildOfficialOutputContract", BindingFlags.NonPublic | BindingFlags.Static);
|
|
366
|
+
Assert.That(() => output.Invoke(null, new object[] { typeof(ValueTask<int>) }), Throws.TypeOf<TargetInvocationException>());
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
private void InstanceOfficialMethod() { }
|
|
370
|
+
private static UnityCli.Protocol.BridgeRequest CursorSummaryRequest(string generation, string token)
|
|
371
|
+
{
|
|
372
|
+
var input = new Dictionary<string, object>
|
|
373
|
+
{
|
|
374
|
+
{ "limit", 1L }, { "reservedNames", new List<object>() }, { "localNames", new List<object>() },
|
|
375
|
+
{ "cursorContext", new string('a', 64) }
|
|
376
|
+
};
|
|
377
|
+
if (generation != null) input["expectedCatalogGeneration"] = generation;
|
|
378
|
+
if (token != null) input["cursorToken"] = token;
|
|
379
|
+
return new UnityCli.Protocol.BridgeRequest { Input = input };
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
private static string AlterCursorBoundary(string token, string boundary)
|
|
383
|
+
{
|
|
384
|
+
var parts = token.Split('.');
|
|
385
|
+
var payload = Encoding.UTF8.GetString(FromBase64Url(parts[0])).Split('\n');
|
|
386
|
+
payload[2] = Convert.ToBase64String(Encoding.UTF8.GetBytes(boundary));
|
|
387
|
+
return ToBase64Url(Encoding.UTF8.GetBytes(string.Join("\n", payload))) + "." + parts[1];
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
private static string ToBase64Url(byte[] value)
|
|
391
|
+
{
|
|
392
|
+
return Convert.ToBase64String(value).TrimEnd('=').Replace('+', '-').Replace('/', '_');
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
private static byte[] FromBase64Url(string value)
|
|
396
|
+
{
|
|
397
|
+
var normalized = value.Replace('-', '+').Replace('_', '/');
|
|
398
|
+
normalized = normalized.PadRight(normalized.Length + (4 - normalized.Length % 4) % 4, '=');
|
|
399
|
+
return Convert.FromBase64String(normalized);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
private static void StaticOfficialMethod() { }
|
|
403
|
+
|
|
404
|
+
private object ReadPublishedSnapshot()
|
|
405
|
+
{
|
|
406
|
+
var reader = bridgeType.GetProperty("ProjectToolCatalogSnapshotReader", BindingFlags.NonPublic | BindingFlags.Static).GetValue(null);
|
|
407
|
+
return reader.GetType().GetMethod("Read", BindingFlags.Public | BindingFlags.Instance).Invoke(reader, null);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
private static object FirstTool(object snapshot)
|
|
411
|
+
{
|
|
412
|
+
var descriptors = Property(snapshot, "Descriptors").GetValue(snapshot) as IEnumerable;
|
|
413
|
+
return descriptors.Cast<object>().First();
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
private static object FirstValue(object dictionary)
|
|
417
|
+
{
|
|
418
|
+
var values = Property(dictionary, "Values").GetValue(dictionary) as IEnumerable;
|
|
419
|
+
return values.Cast<object>().First();
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
private object NewBuilder(int assemblies, int providers)
|
|
423
|
+
{
|
|
424
|
+
var builder = Activator.CreateInstance(builderType, true);
|
|
425
|
+
Invoke(builder, "BeginDiscovery", assemblies, providers);
|
|
426
|
+
for (var index = 0; index < providers; index++) Invoke(builder, "RecordProviderMetadata", "fixture.provider." + index);
|
|
427
|
+
return builder;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
private object Definition(string name, string source, string profile, string group, string summary = "Fixture summary.")
|
|
431
|
+
{
|
|
432
|
+
var descriptor = new ToolDescriptor
|
|
433
|
+
{
|
|
434
|
+
Name = name,
|
|
435
|
+
Summary = summary,
|
|
436
|
+
Description = "Fixture descriptor for production catalog publication validation.",
|
|
437
|
+
Group = group,
|
|
438
|
+
DestructiveHint = false,
|
|
439
|
+
SideEffects = new string[0],
|
|
440
|
+
SupportsDryRun = false,
|
|
441
|
+
Permissions = new string[0],
|
|
442
|
+
RequiresPackages = new string[0],
|
|
443
|
+
Examples = new[] { new ToolExample { Description = "Fixture", Input = new Dictionary<string, object>() } },
|
|
444
|
+
Target = "editor",
|
|
445
|
+
PlayModeSupport = profile == "official-attribute" ? "unknown" : "supported",
|
|
446
|
+
DefaultTimeoutMs = 30000,
|
|
447
|
+
MaxTimeoutMs = 60000
|
|
448
|
+
};
|
|
449
|
+
var implementationType = source == "built-in" ? bridgeType : GetType();
|
|
450
|
+
var extensionId = source == "extension" ? "fixture" : null;
|
|
451
|
+
var ownership = Activator.CreateInstance(ownershipType, BindingFlags.Instance | BindingFlags.NonPublic, null,
|
|
452
|
+
new object[] { source, extensionId, implementationType.Assembly, implementationType }, null);
|
|
453
|
+
object binding = null;
|
|
454
|
+
if (profile == "official-attribute")
|
|
455
|
+
{
|
|
456
|
+
var bindingType = Type.GetType("UnityCli.OfficialAttributeToolBinding, UnityCli.Editor", true);
|
|
457
|
+
var parameterType = Type.GetType("UnityCli.OfficialAttributeParameterBinding, UnityCli.Editor", true);
|
|
458
|
+
binding = Activator.CreateInstance(bindingType, true);
|
|
459
|
+
Property(binding, "Method").SetValue(binding, GetType().GetMethod("StaticOfficialMethod", BindingFlags.NonPublic | BindingFlags.Static));
|
|
460
|
+
Property(binding, "DeclaredResultType").SetValue(binding, typeof(void));
|
|
461
|
+
Property(binding, "Parameters").SetValue(binding, Activator.CreateInstance(typeof(List<>).MakeGenericType(parameterType)));
|
|
462
|
+
}
|
|
463
|
+
var invoke = Property(publishedTemplate, "InvokeAsync").GetValue(publishedTemplate);
|
|
464
|
+
var constructor = registeredToolType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Instance).Single();
|
|
465
|
+
return constructor.Invoke(new[]
|
|
466
|
+
{
|
|
467
|
+
descriptor, ownership, "{}", "{}", "editorSession", profile,
|
|
468
|
+
typeof(Dictionary<string, object>), typeof(Dictionary<string, object>), Completion(name, source), binding, invoke
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
private static Assembly[] CompileProjectToolProviderAssemblies(int count)
|
|
473
|
+
{
|
|
474
|
+
if (compiledProjectToolProviderAssemblies != null && compiledProjectToolProviderAssemblies.Length == count)
|
|
475
|
+
return compiledProjectToolProviderAssemblies;
|
|
476
|
+
|
|
477
|
+
var assemblies = new List<Assembly>(count);
|
|
478
|
+
for (var index = 0; index < count; index++)
|
|
479
|
+
assemblies.Add(CompileProjectToolProviderAssembly(index));
|
|
480
|
+
|
|
481
|
+
compiledProjectToolProviderAssemblies = assemblies.ToArray();
|
|
482
|
+
return compiledProjectToolProviderAssemblies;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
private static Assembly CompileProjectToolProviderAssembly(int index)
|
|
486
|
+
{
|
|
487
|
+
var suffix = index.ToString("D3");
|
|
488
|
+
var source = new StringBuilder();
|
|
489
|
+
source.AppendLine("using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using UnityCli;");
|
|
490
|
+
source.AppendLine("namespace UnityCli.GeneratedCatalogFixture" + suffix + " {");
|
|
491
|
+
source.AppendLine("public sealed class FixtureRequest {} public sealed class FixtureResult {}");
|
|
492
|
+
source.AppendLine("public sealed class GeneratedTool" + suffix + " : IUnityCliTool<FixtureRequest, FixtureResult> {");
|
|
493
|
+
source.AppendLine("public ToolDescriptor Describe() { global::UnityCli.Tests.UnityCliToolCatalogFixtureProbe.RecordDescribe(\"fixture.generated." + suffix + "\"); return new ToolDescriptor { Name=\"fixture.generated." + suffix
|
|
494
|
+
+ "\", Summary=\"Generated fixture.\", Description=\"Production collector fixture.\", Group=\"fixture\", Examples=new[]{new ToolExample{Description=\"Fixture\", Input=new Dictionary<string, object>()}}, Completion=new ToolCompletionDescriptor{ExecutionClass=\"atomic\", CompletionPredicate=\"typed-business-terminal\", ProofSource=\"typed-result-and-effect-readback\", ReloadPolicy=\"caller-responsibility\", TimeoutError=\"E_EXECUTION_TIMEOUT\", OutcomeUnknownPolicy=\"caller-responsibility\", CompletionDriverId=\"atomic-typed-result-v1\"} }; }");
|
|
495
|
+
source.AppendLine("public ValueTask<FixtureResult> ExecuteAsync(FixtureRequest request, UnityCliProjectToolContext ctx, CancellationToken ct) { return new ValueTask<FixtureResult>(new FixtureResult()); }}");
|
|
496
|
+
source.AppendLine("}");
|
|
497
|
+
using (var provider = new CSharpCodeProvider())
|
|
498
|
+
{
|
|
499
|
+
var parameters = new CompilerParameters
|
|
500
|
+
{
|
|
501
|
+
GenerateExecutable = false,
|
|
502
|
+
GenerateInMemory = true,
|
|
503
|
+
CompilerOptions = "/langversion:latest",
|
|
504
|
+
OutputAssembly = "UnityCli.GeneratedCatalogFixture" + suffix + ".dll"
|
|
505
|
+
};
|
|
506
|
+
parameters.ReferencedAssemblies.Add("System.dll");
|
|
507
|
+
parameters.ReferencedAssemblies.Add("System.Core.dll");
|
|
508
|
+
parameters.ReferencedAssemblies.Add(typeof(IUnityCliTool<,>).Assembly.Location);
|
|
509
|
+
parameters.ReferencedAssemblies.Add(typeof(UnityCliToolCatalogFixtureProbe).Assembly.Location);
|
|
510
|
+
var result = provider.CompileAssemblyFromSource(parameters, source.ToString());
|
|
511
|
+
var failures = result.Errors.Cast<CompilerError>().Where(error => !error.IsWarning).Select(error => error.ToString()).ToArray();
|
|
512
|
+
Assert.That(failures, Is.Empty, string.Join(Environment.NewLine, failures));
|
|
513
|
+
return result.CompiledAssembly;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
private object Completion(string name, string source)
|
|
518
|
+
{
|
|
519
|
+
var type = Type.GetType("UnityCli.UnityCliToolCompletionContract, UnityCli.Editor", true);
|
|
520
|
+
var constructor = type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).Single();
|
|
521
|
+
var owner = source == "extension" ? "extension:fixture" : source;
|
|
522
|
+
return constructor.Invoke(new object[]
|
|
523
|
+
{
|
|
524
|
+
name, owner, "direct-terminal", "atomic", "typed-result-schema-v1", "typed-handler-result",
|
|
525
|
+
"fail-before-effect", "E_EXECUTION_TIMEOUT", "not-applicable-read-only", "direct-typed-result-v1", "none", false
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
private object PublishThroughProductionSlot(object builder, long elapsedMilliseconds)
|
|
530
|
+
{
|
|
531
|
+
var method = bridgeType.GetMethod("PublishProjectToolCatalog", BindingFlags.NonPublic | BindingFlags.Static);
|
|
532
|
+
return method.Invoke(null, new[] { builder, (object)elapsedMilliseconds });
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
private void Add(object builder, object definition, string providerKind)
|
|
536
|
+
{
|
|
537
|
+
Invoke(builder, "Add", definition, Enum.Parse(providerKindType, providerKind));
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
private static object Invoke(object target, string name, params object[] args)
|
|
541
|
+
{
|
|
542
|
+
var method = target.GetType().GetMethod(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
|
|
543
|
+
return method.Invoke(target, args);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
private FieldInfo Field(string name)
|
|
547
|
+
{
|
|
548
|
+
return bridgeType.GetField(name, BindingFlags.NonPublic | BindingFlags.Static) ?? throw new MissingFieldException(name);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
private static PropertyInfo Property(object target, string name)
|
|
552
|
+
{
|
|
553
|
+
return target.GetType().GetProperty(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) ?? throw new MissingMemberException(name);
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
private static int Int(object target, string name)
|
|
557
|
+
{
|
|
558
|
+
return Convert.ToInt32(Property(target, name).GetValue(target));
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
#endif
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "UnityCli.Runtime.Tests",
|
|
3
|
+
"rootNamespace": "UnityCli.Tests",
|
|
4
|
+
"references": [
|
|
5
|
+
"UnityCli.Runtime"
|
|
6
|
+
],
|
|
7
|
+
"includePlatforms": [
|
|
8
|
+
"Editor"
|
|
9
|
+
],
|
|
10
|
+
"excludePlatforms": [],
|
|
11
|
+
"allowUnsafeCode": false,
|
|
12
|
+
"overrideReferences": false,
|
|
13
|
+
"precompiledReferences": [],
|
|
14
|
+
"autoReferenced": false,
|
|
15
|
+
"defineConstraints": [
|
|
16
|
+
"UNITY_INCLUDE_TESTS"
|
|
17
|
+
],
|
|
18
|
+
"versionDefines": [],
|
|
19
|
+
"noEngineReferences": false,
|
|
20
|
+
"optionalUnityReferences": [
|
|
21
|
+
"TestAssemblies"
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
using System;
|
|
2
|
+
using System.Collections.Generic;
|
|
3
|
+
using System.Reflection;
|
|
4
|
+
using NUnit.Framework;
|
|
5
|
+
|
|
6
|
+
namespace UnityCli.Tests
|
|
7
|
+
{
|
|
8
|
+
public sealed class UnityCliRuntimeCatalogValidationTests
|
|
9
|
+
{
|
|
10
|
+
[Test]
|
|
11
|
+
public void RuntimeDescribeAcceptsOnlyTheExactNamePayload()
|
|
12
|
+
{
|
|
13
|
+
var bridge = Type.GetType("UnityCli.UnityCliRuntimeBridge, UnityCli.Runtime", true);
|
|
14
|
+
var validate = bridge.GetMethod("ValidateRuntimeCatalogInput", BindingFlags.NonPublic | BindingFlags.Static);
|
|
15
|
+
var exact = new Dictionary<string, object> { { "name", "runtime.state" } };
|
|
16
|
+
Assert.That(() => validate.Invoke(null, new object[] { "runtime-tool.describe", exact }), Throws.Nothing);
|
|
17
|
+
|
|
18
|
+
var fallback = new Dictionary<string, object>
|
|
19
|
+
{
|
|
20
|
+
{ "name", "runtime.state" },
|
|
21
|
+
{ "fallbackName", "UnityPipeline_runtime.state" }
|
|
22
|
+
};
|
|
23
|
+
var exception = Assert.Throws<TargetInvocationException>(() =>
|
|
24
|
+
validate.Invoke(null, new object[] { "runtime-tool.describe", fallback }));
|
|
25
|
+
Assert.That(exception.InnerException, Is.TypeOf<FormatException>());
|
|
26
|
+
Assert.That(exception.InnerException.Message, Does.Contain("unknown field"));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|