From d42890627e62105b4bbaeae4440e5d03f2c42f63 Mon Sep 17 00:00:00 2001 From: Marcus Sanatan Date: Thu, 14 Aug 2025 19:53:33 -0400 Subject: [PATCH 1/8] Add a base Unity project to run unit tests in --- TestProjects/UnityMCPTests/.gitignore | 105 +++++ TestProjects/UnityMCPTests/Assets/Scenes.meta | 8 + .../Assets/Scenes/SampleScene.unity | 267 ++++++++++++ .../Assets/Scenes/SampleScene.unity.meta | 7 + .../UnityMCPTests/Packages/manifest.json | 46 ++ .../UnityMCPTests/Packages/packages-lock.json | 408 ++++++++++++++++++ .../Settings.json | 7 + .../ProjectSettings/ProjectVersion.txt | 2 + .../UnityMCPTests/ProjectSettings/boot.config | 0 9 files changed, 850 insertions(+) create mode 100644 TestProjects/UnityMCPTests/.gitignore create mode 100644 TestProjects/UnityMCPTests/Assets/Scenes.meta create mode 100644 TestProjects/UnityMCPTests/Assets/Scenes/SampleScene.unity create mode 100644 TestProjects/UnityMCPTests/Assets/Scenes/SampleScene.unity.meta create mode 100644 TestProjects/UnityMCPTests/Packages/manifest.json create mode 100644 TestProjects/UnityMCPTests/Packages/packages-lock.json create mode 100644 TestProjects/UnityMCPTests/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json create mode 100644 TestProjects/UnityMCPTests/ProjectSettings/ProjectVersion.txt create mode 100644 TestProjects/UnityMCPTests/ProjectSettings/boot.config diff --git a/TestProjects/UnityMCPTests/.gitignore b/TestProjects/UnityMCPTests/.gitignore new file mode 100644 index 00000000..b2ee8bfa --- /dev/null +++ b/TestProjects/UnityMCPTests/.gitignore @@ -0,0 +1,105 @@ +# This .gitignore file should be placed at the root of your Unity project directory +# +# Get latest from https://github.com/github/gitignore/blob/main/Unity.gitignore +# +.utmp/ +/[Ll]ibrary/ +/[Tt]emp/ +/[Oo]bj/ +/[Bb]uild/ +/[Bb]uilds/ +/[Ll]ogs/ +/[Uu]ser[Ss]ettings/ +*.log + +# By default unity supports Blender asset imports, *.blend1 blender files do not need to be commited to version control. +*.blend1 +*.blend1.meta + +# MemoryCaptures can get excessive in size. +# They also could contain extremely sensitive data +/[Mm]emoryCaptures/ + +# Recordings can get excessive in size +/[Rr]ecordings/ + +# Uncomment this line if you wish to ignore the asset store tools plugin +# /[Aa]ssets/AssetStoreTools* + +# Autogenerated Jetbrains Rider plugin +/[Aa]ssets/Plugins/Editor/JetBrains* +# Jetbrains Rider personal-layer settings +*.DotSettings.user + +# Visual Studio cache directory +.vs/ + +# Gradle cache directory +.gradle/ + +# Autogenerated VS/MD/Consulo solution and project files +ExportedObj/ +.consulo/ +*.csproj +*.unityproj +*.sln +*.suo +*.tmp +*.user +*.userprefs +*.pidb +*.booproj +*.svd +*.pdb +*.mdb +*.opendb +*.VC.db + +# Unity3D generated meta files +*.pidb.meta +*.pdb.meta +*.mdb.meta + +# Unity3D generated file on crash reports +sysinfo.txt + +# Mono auto generated files +mono_crash.* + +# Builds +*.apk +*.aab +*.unitypackage +*.unitypackage.meta +*.app + +# Crashlytics generated file +crashlytics-build.properties + +# TestRunner generated files +InitTestScene*.unity* + +# Addressables default ignores, before user customizations +/ServerData +/[Aa]ssets/StreamingAssets/aa* +/[Aa]ssets/AddressableAssetsData/link.xml* +/[Aa]ssets/Addressables_Temp* +# By default, Addressables content builds will generate addressables_content_state.bin +# files in platform-specific subfolders, for example: +# /Assets/AddressableAssetsData/OSX/addressables_content_state.bin +/[Aa]ssets/AddressableAssetsData/*/*.bin* + +# Visual Scripting auto-generated files +/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Flow/UnitOptions.db +/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Flow/UnitOptions.db.meta +/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Core/Property Providers +/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Core/Property Providers.meta + +# Auto-generated scenes by play mode tests +/[Aa]ssets/[Ii]nit[Tt]est[Ss]cene*.unity* + +.vscode +.cursor +.windsurf +.claude +.DS_Store diff --git a/TestProjects/UnityMCPTests/Assets/Scenes.meta b/TestProjects/UnityMCPTests/Assets/Scenes.meta new file mode 100644 index 00000000..64dc9d31 --- /dev/null +++ b/TestProjects/UnityMCPTests/Assets/Scenes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6c928dbbf09c0412393726aeb9208bc4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/Assets/Scenes/SampleScene.unity b/TestProjects/UnityMCPTests/Assets/Scenes/SampleScene.unity new file mode 100644 index 00000000..c39e5814 --- /dev/null +++ b/TestProjects/UnityMCPTests/Assets/Scenes/SampleScene.unity @@ -0,0 +1,267 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 0 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 705507994} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 12 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 500 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 500 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 2 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_LightingSettings: {fileID: 0} +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &705507993 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 705507995} + - component: {fileID: 705507994} + m_Layer: 0 + m_Name: Directional Light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!108 &705507994 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 705507993} + m_Enabled: 1 + serializedVersion: 8 + m_Type: 1 + m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_CookieSize: 10 + m_Shadows: + m_Type: 2 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_Lightmapping: 1 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 +--- !u!4 &705507995 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 705507993} + m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} + m_LocalPosition: {x: 0, y: 3, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} +--- !u!1 &963194225 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 963194228} + - component: {fileID: 963194227} + - component: {fileID: 963194226} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &963194226 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 +--- !u!20 &963194227 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} + m_projectionMatrixMode: 1 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_GateFitMode: 2 + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 1 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &963194228 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInternal: {fileID: 0} + m_GameObject: {fileID: 963194225} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/TestProjects/UnityMCPTests/Assets/Scenes/SampleScene.unity.meta b/TestProjects/UnityMCPTests/Assets/Scenes/SampleScene.unity.meta new file mode 100644 index 00000000..952bd1e9 --- /dev/null +++ b/TestProjects/UnityMCPTests/Assets/Scenes/SampleScene.unity.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9fc0d4010bbf28b4594072e72b8655ab +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/Packages/manifest.json b/TestProjects/UnityMCPTests/Packages/manifest.json new file mode 100644 index 00000000..566a18d6 --- /dev/null +++ b/TestProjects/UnityMCPTests/Packages/manifest.json @@ -0,0 +1,46 @@ +{ + "dependencies": { + "com.coplaydev.unity-mcp": "file:/Users/marcussanatan/Projects/unity-mcp/UnityMcpBridge", + "com.unity.collab-proxy": "2.5.2", + "com.unity.feature.development": "1.0.1", + "com.unity.ide.rider": "3.0.31", + "com.unity.ide.visualstudio": "2.0.22", + "com.unity.ide.vscode": "1.2.5", + "com.unity.test-framework": "1.1.33", + "com.unity.textmeshpro": "3.0.6", + "com.unity.timeline": "1.6.5", + "com.unity.ugui": "1.0.0", + "com.unity.visualscripting": "1.9.4", + "com.unity.modules.ai": "1.0.0", + "com.unity.modules.androidjni": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.cloth": "1.0.0", + "com.unity.modules.director": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.physics2d": "1.0.0", + "com.unity.modules.screencapture": "1.0.0", + "com.unity.modules.terrain": "1.0.0", + "com.unity.modules.terrainphysics": "1.0.0", + "com.unity.modules.tilemap": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.uielements": "1.0.0", + "com.unity.modules.umbra": "1.0.0", + "com.unity.modules.unityanalytics": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.unitywebrequesttexture": "1.0.0", + "com.unity.modules.unitywebrequestwww": "1.0.0", + "com.unity.modules.vehicles": "1.0.0", + "com.unity.modules.video": "1.0.0", + "com.unity.modules.vr": "1.0.0", + "com.unity.modules.wind": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } +} diff --git a/TestProjects/UnityMCPTests/Packages/packages-lock.json b/TestProjects/UnityMCPTests/Packages/packages-lock.json new file mode 100644 index 00000000..3daa5b34 --- /dev/null +++ b/TestProjects/UnityMCPTests/Packages/packages-lock.json @@ -0,0 +1,408 @@ +{ + "dependencies": { + "com.coplaydev.unity-mcp": { + "version": "file:/Users/marcussanatan/Projects/unity-mcp/UnityMcpBridge", + "depth": 0, + "source": "local", + "dependencies": { + "com.unity.nuget.newtonsoft-json": "3.0.2" + } + }, + "com.unity.collab-proxy": { + "version": "2.5.2", + "depth": 0, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.editorcoroutines": { + "version": "1.0.0", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.ext.nunit": { + "version": "1.0.6", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.feature.development": { + "version": "1.0.1", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.ide.visualstudio": "2.0.22", + "com.unity.ide.rider": "3.0.31", + "com.unity.ide.vscode": "1.2.5", + "com.unity.editorcoroutines": "1.0.0", + "com.unity.performance.profile-analyzer": "1.2.2", + "com.unity.test-framework": "1.1.33", + "com.unity.testtools.codecoverage": "1.2.6" + } + }, + "com.unity.ide.rider": { + "version": "3.0.31", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ext.nunit": "1.0.6" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ide.visualstudio": { + "version": "2.0.22", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.1.9" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ide.vscode": { + "version": "1.2.5", + "depth": 0, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.nuget.newtonsoft-json": { + "version": "3.2.1", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.performance.profile-analyzer": { + "version": "1.2.2", + "depth": 1, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.settings-manager": { + "version": "1.0.3", + "depth": 2, + "source": "registry", + "dependencies": {}, + "url": "https://packages.unity.com" + }, + "com.unity.test-framework": { + "version": "1.1.33", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ext.nunit": "1.0.6", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.testtools.codecoverage": { + "version": "1.2.6", + "depth": 1, + "source": "registry", + "dependencies": { + "com.unity.test-framework": "1.0.16", + "com.unity.settings-manager": "1.0.1" + }, + "url": "https://packages.unity.com" + }, + "com.unity.textmeshpro": { + "version": "3.0.6", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ugui": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.timeline": { + "version": "1.6.5", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.director": "1.0.0", + "com.unity.modules.animation": "1.0.0", + "com.unity.modules.particlesystem": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.ugui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0" + } + }, + "com.unity.visualscripting": { + "version": "1.9.4", + "depth": 0, + "source": "registry", + "dependencies": { + "com.unity.ugui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + }, + "url": "https://packages.unity.com" + }, + "com.unity.modules.ai": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.androidjni": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.animation": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.assetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.audio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.cloth": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.director": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.animation": "1.0.0" + } + }, + "com.unity.modules.imageconversion": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.imgui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.jsonserialize": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.particlesystem": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.physics2d": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.screencapture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.subsystems": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.terrain": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.terrainphysics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.terrain": "1.0.0" + } + }, + "com.unity.modules.tilemap": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics2d": "1.0.0" + } + }, + "com.unity.modules.ui": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.uielements": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.uielementsnative": "1.0.0" + } + }, + "com.unity.modules.uielementsnative": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": { + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.imgui": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.umbra": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unityanalytics": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0" + } + }, + "com.unity.modules.unitywebrequest": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.unitywebrequestassetbundle": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestaudio": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.audio": "1.0.0" + } + }, + "com.unity.modules.unitywebrequesttexture": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.unitywebrequestwww": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.unitywebrequest": "1.0.0", + "com.unity.modules.unitywebrequestassetbundle": "1.0.0", + "com.unity.modules.unitywebrequestaudio": "1.0.0", + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.assetbundle": "1.0.0", + "com.unity.modules.imageconversion": "1.0.0" + } + }, + "com.unity.modules.vehicles": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0" + } + }, + "com.unity.modules.video": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.audio": "1.0.0", + "com.unity.modules.ui": "1.0.0", + "com.unity.modules.unitywebrequest": "1.0.0" + } + }, + "com.unity.modules.vr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.xr": "1.0.0" + } + }, + "com.unity.modules.wind": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": {} + }, + "com.unity.modules.xr": { + "version": "1.0.0", + "depth": 0, + "source": "builtin", + "dependencies": { + "com.unity.modules.physics": "1.0.0", + "com.unity.modules.jsonserialize": "1.0.0", + "com.unity.modules.subsystems": "1.0.0" + } + } + } +} diff --git a/TestProjects/UnityMCPTests/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json b/TestProjects/UnityMCPTests/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json new file mode 100644 index 00000000..ad11087f --- /dev/null +++ b/TestProjects/UnityMCPTests/ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json @@ -0,0 +1,7 @@ +{ + "m_Name": "Settings", + "m_Path": "ProjectSettings/Packages/com.unity.testtools.codecoverage/Settings.json", + "m_Dictionary": { + "m_DictionaryValues": [] + } +} \ No newline at end of file diff --git a/TestProjects/UnityMCPTests/ProjectSettings/ProjectVersion.txt b/TestProjects/UnityMCPTests/ProjectSettings/ProjectVersion.txt new file mode 100644 index 00000000..8386a052 --- /dev/null +++ b/TestProjects/UnityMCPTests/ProjectSettings/ProjectVersion.txt @@ -0,0 +1,2 @@ +m_EditorVersion: 2021.3.45f1 +m_EditorVersionWithRevision: 2021.3.45f1 (0da89fac8e79) diff --git a/TestProjects/UnityMCPTests/ProjectSettings/boot.config b/TestProjects/UnityMCPTests/ProjectSettings/boot.config new file mode 100644 index 00000000..e69de29b From dd47fdf8cc097eff755e5e8e315d22f8b3a11831 Mon Sep 17 00:00:00 2001 From: Marcus Sanatan Date: Thu, 14 Aug 2025 19:57:35 -0400 Subject: [PATCH 2/8] Add Windsurf IDE support so I can test more easily --- TestProjects/UnityMCPTests/Packages/manifest.json | 1 + TestProjects/UnityMCPTests/Packages/packages-lock.json | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/TestProjects/UnityMCPTests/Packages/manifest.json b/TestProjects/UnityMCPTests/Packages/manifest.json index 566a18d6..d486c704 100644 --- a/TestProjects/UnityMCPTests/Packages/manifest.json +++ b/TestProjects/UnityMCPTests/Packages/manifest.json @@ -6,6 +6,7 @@ "com.unity.ide.rider": "3.0.31", "com.unity.ide.visualstudio": "2.0.22", "com.unity.ide.vscode": "1.2.5", + "com.unity.ide.windsurf": "https://github.com/Asuta/com.unity.ide.windsurf.git", "com.unity.test-framework": "1.1.33", "com.unity.textmeshpro": "3.0.6", "com.unity.timeline": "1.6.5", diff --git a/TestProjects/UnityMCPTests/Packages/packages-lock.json b/TestProjects/UnityMCPTests/Packages/packages-lock.json index 3daa5b34..72de9eb9 100644 --- a/TestProjects/UnityMCPTests/Packages/packages-lock.json +++ b/TestProjects/UnityMCPTests/Packages/packages-lock.json @@ -68,6 +68,15 @@ "dependencies": {}, "url": "https://packages.unity.com" }, + "com.unity.ide.windsurf": { + "version": "https://github.com/Asuta/com.unity.ide.windsurf.git", + "depth": 0, + "source": "git", + "dependencies": { + "com.unity.test-framework": "1.1.9" + }, + "hash": "6161accf3e7beab96341813913e714c7e2fb5c5d" + }, "com.unity.nuget.newtonsoft-json": { "version": "3.2.1", "depth": 1, From 1787985a18c50a3d82eba8a33c88edbaa134b7da Mon Sep 17 00:00:00 2001 From: Marcus Sanatan Date: Thu, 14 Aug 2025 19:58:27 -0400 Subject: [PATCH 3/8] Add a dummy script --- TestProjects/UnityMCPTests/Assets/Scripts.meta | 8 ++++++++ TestProjects/UnityMCPTests/Assets/Scripts/Hello.cs | 11 +++++++++++ .../UnityMCPTests/Assets/Scripts/Hello.cs.meta | 11 +++++++++++ 3 files changed, 30 insertions(+) create mode 100644 TestProjects/UnityMCPTests/Assets/Scripts.meta create mode 100644 TestProjects/UnityMCPTests/Assets/Scripts/Hello.cs create mode 100644 TestProjects/UnityMCPTests/Assets/Scripts/Hello.cs.meta diff --git a/TestProjects/UnityMCPTests/Assets/Scripts.meta b/TestProjects/UnityMCPTests/Assets/Scripts.meta new file mode 100644 index 00000000..868e1279 --- /dev/null +++ b/TestProjects/UnityMCPTests/Assets/Scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fe422ce9e144a4a348d4372fd00afd17 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/Assets/Scripts/Hello.cs b/TestProjects/UnityMCPTests/Assets/Scripts/Hello.cs new file mode 100644 index 00000000..ab996431 --- /dev/null +++ b/TestProjects/UnityMCPTests/Assets/Scripts/Hello.cs @@ -0,0 +1,11 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class Hello : MonoBehaviour +{ + void Start() + { + Debug.Log("Hello World"); + } +} diff --git a/TestProjects/UnityMCPTests/Assets/Scripts/Hello.cs.meta b/TestProjects/UnityMCPTests/Assets/Scripts/Hello.cs.meta new file mode 100644 index 00000000..6b1e1268 --- /dev/null +++ b/TestProjects/UnityMCPTests/Assets/Scripts/Hello.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bebdf68a6876b425494ee770d20f70ef +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 21f8517c1c35e3f8b0c05ff407b18976993d3b77 Mon Sep 17 00:00:00 2001 From: Marcus Sanatan Date: Thu, 14 Aug 2025 22:05:03 -0400 Subject: [PATCH 4/8] feat: add unit tests for CommandRegistry and document prefab asset workflows --- TestProjects/UnityMCPTests/Assets/Tests.meta | 8 +++++ .../UnityMCPTests/Assets/Tests/EditMode.meta | 8 +++++ .../Tests/EditMode/CommandRegistryTests.cs | 30 +++++++++++++++++++ .../EditMode/CommandRegistryTests.cs.meta | 11 +++++++ .../EditMode/UnityMCPTests.EditMode.asmdef | 25 ++++++++++++++++ .../UnityMCPTests.EditMode.asmdef.meta | 7 +++++ 6 files changed, 89 insertions(+) create mode 100644 TestProjects/UnityMCPTests/Assets/Tests.meta create mode 100644 TestProjects/UnityMCPTests/Assets/Tests/EditMode.meta create mode 100644 TestProjects/UnityMCPTests/Assets/Tests/EditMode/CommandRegistryTests.cs create mode 100644 TestProjects/UnityMCPTests/Assets/Tests/EditMode/CommandRegistryTests.cs.meta create mode 100644 TestProjects/UnityMCPTests/Assets/Tests/EditMode/UnityMCPTests.EditMode.asmdef create mode 100644 TestProjects/UnityMCPTests/Assets/Tests/EditMode/UnityMCPTests.EditMode.asmdef.meta diff --git a/TestProjects/UnityMCPTests/Assets/Tests.meta b/TestProjects/UnityMCPTests/Assets/Tests.meta new file mode 100644 index 00000000..d40f34fe --- /dev/null +++ b/TestProjects/UnityMCPTests/Assets/Tests.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9f7ba5b24c9aa4f89866aca2a81cd78e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/Assets/Tests/EditMode.meta b/TestProjects/UnityMCPTests/Assets/Tests/EditMode.meta new file mode 100644 index 00000000..5b6dbdd5 --- /dev/null +++ b/TestProjects/UnityMCPTests/Assets/Tests/EditMode.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6a74c5895837a475695408d1a7373098 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/Assets/Tests/EditMode/CommandRegistryTests.cs b/TestProjects/UnityMCPTests/Assets/Tests/EditMode/CommandRegistryTests.cs new file mode 100644 index 00000000..32716869 --- /dev/null +++ b/TestProjects/UnityMCPTests/Assets/Tests/EditMode/CommandRegistryTests.cs @@ -0,0 +1,30 @@ +using System; +using Newtonsoft.Json; +using NUnit.Framework; +using UnityMcpBridge.Editor.Tools; + +namespace UnityMCPTests.EditMode +{ + public class CommandRegistryTests + { + [Test] + public void GetHandler_ReturnsNull_ForUnknownCommand() + { + var unknown = "HandleDoesNotExist"; + var handler = CommandRegistry.GetHandler(unknown); + Assert.IsNull(handler, "Expected null handler for unknown command name."); + } + + [Test] + public void GetHandler_ReturnsManageGameObjectHandler() + { + var handler = CommandRegistry.GetHandler("HandleManageGameObject"); + Assert.IsNotNull(handler, "Expected a handler for HandleManageGameObject."); + + var methodInfo = handler.Method; + Assert.AreEqual("HandleCommand", methodInfo.Name, "Handler method name should be HandleCommand."); + Assert.AreEqual(typeof(ManageGameObject), methodInfo.DeclaringType, "Handler should be declared on ManageGameObject."); + Assert.IsNull(handler.Target, "Handler should be a static method (no target instance)."); + } + } +} diff --git a/TestProjects/UnityMCPTests/Assets/Tests/EditMode/CommandRegistryTests.cs.meta b/TestProjects/UnityMCPTests/Assets/Tests/EditMode/CommandRegistryTests.cs.meta new file mode 100644 index 00000000..39a7ddcb --- /dev/null +++ b/TestProjects/UnityMCPTests/Assets/Tests/EditMode/CommandRegistryTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ed0df02ef7d99451f9f3b2bc3e3aba28 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/TestProjects/UnityMCPTests/Assets/Tests/EditMode/UnityMCPTests.EditMode.asmdef b/TestProjects/UnityMCPTests/Assets/Tests/EditMode/UnityMCPTests.EditMode.asmdef new file mode 100644 index 00000000..da9c807c --- /dev/null +++ b/TestProjects/UnityMCPTests/Assets/Tests/EditMode/UnityMCPTests.EditMode.asmdef @@ -0,0 +1,25 @@ +{ + "name": "UnityMCPTests.EditMode", + "rootNamespace": "", + "references": [ + "UnityMcpBridge.Editor", + "UnityEngine.TestRunner", + "UnityEditor.TestRunner" + ], + "includePlatforms": [ + "Editor" + ], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": true, + "precompiledReferences": [ + "nunit.framework.dll", + "Newtonsoft.Json.dll" + ], + "autoReferenced": false, + "defineConstraints": [ + "UNITY_INCLUDE_TESTS" + ], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/TestProjects/UnityMCPTests/Assets/Tests/EditMode/UnityMCPTests.EditMode.asmdef.meta b/TestProjects/UnityMCPTests/Assets/Tests/EditMode/UnityMCPTests.EditMode.asmdef.meta new file mode 100644 index 00000000..0508ee3c --- /dev/null +++ b/TestProjects/UnityMCPTests/Assets/Tests/EditMode/UnityMCPTests.EditMode.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b28bd738cf38847dfa90ffcbfb130965 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From 2b531ffa3f8b42d4b8f36db5afbd5cd85a079e03 Mon Sep 17 00:00:00 2001 From: Marcus Sanatan Date: Thu, 14 Aug 2025 22:19:13 -0400 Subject: [PATCH 5/8] Run tests when code is pushed to main --- .github/workflows/unity-tests.yml | 58 +++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 .github/workflows/unity-tests.yml diff --git a/.github/workflows/unity-tests.yml b/.github/workflows/unity-tests.yml new file mode 100644 index 00000000..bc1360ec --- /dev/null +++ b/.github/workflows/unity-tests.yml @@ -0,0 +1,58 @@ +name: Unity Tests + +on: + push: + branches: [ main, unit-tests ] + paths: + - TestProjects/UnityMCPTests/** + - UnityMcpBridge/Editor/** + - .github/workflows/unity-tests.yml + +jobs: + testAllModes: + name: Test in ${{ matrix.testMode }} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + projectPath: + - TestProjects/UnityMCPTests + testMode: + - editmode + unityVersion: + - 2021.3.45f1 + steps: + # Checkout + - name: Checkout repository + uses: actions/checkout@v4 + with: + lfs: true + + # Cache + - uses: actions/cache@v3 + with: + path: ${{ matrix.projectPath }}/Library + key: Library-${{ matrix.projectPath }}-${{ matrix.unityVersion }} + restore-keys: | + Library-${{ matrix.projectPath }}- + Library- + + # Test + - name: Run tests + uses: game-ci/unity-test-runner@v4 + id: tests + env: + UNITY_EMAIL: ${{ secrets.UNITY_EMAIL }} + UNITY_PASSWORD: ${{ secrets.UNITY_PASSWORD }} + UNITY_LICENSE: ${{ secrets.UNITY_LICENSE }} + with: + projectPath: ${{ matrix.projectPath }} + unityVersion: ${{ matrix.unityVersion }} + testMode: ${{ matrix.testMode }} + + # Upload test results + - uses: actions/upload-artifact@v3 + if: always() + with: + name: Test results for ${{ matrix.testMode }} + path: ${{ steps.tests.outputs.artifactsPath }} From a827e644b1fe9a4fc8058a570ee5c4ec59627f09 Mon Sep 17 00:00:00 2001 From: Marcus Sanatan Date: Thu, 14 Aug 2025 22:29:59 -0400 Subject: [PATCH 6/8] Bump version of actions --- .github/workflows/unity-tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/unity-tests.yml b/.github/workflows/unity-tests.yml index bc1360ec..5b474b49 100644 --- a/.github/workflows/unity-tests.yml +++ b/.github/workflows/unity-tests.yml @@ -29,7 +29,7 @@ jobs: lfs: true # Cache - - uses: actions/cache@v3 + - uses: actions/cache@v4 with: path: ${{ matrix.projectPath }}/Library key: Library-${{ matrix.projectPath }}-${{ matrix.unityVersion }} @@ -51,7 +51,7 @@ jobs: testMode: ${{ matrix.testMode }} # Upload test results - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 if: always() with: name: Test results for ${{ matrix.testMode }} From 23a9e743e7d3b24ec250bbdcd70c520f0b689a75 Mon Sep 17 00:00:00 2001 From: Marcus Sanatan Date: Thu, 14 Aug 2025 22:39:11 -0400 Subject: [PATCH 7/8] Install the MCP plugin via relative path --- TestProjects/UnityMCPTests/Packages/manifest.json | 2 +- TestProjects/UnityMCPTests/Packages/packages-lock.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/TestProjects/UnityMCPTests/Packages/manifest.json b/TestProjects/UnityMCPTests/Packages/manifest.json index d486c704..d378a0a8 100644 --- a/TestProjects/UnityMCPTests/Packages/manifest.json +++ b/TestProjects/UnityMCPTests/Packages/manifest.json @@ -1,6 +1,6 @@ { "dependencies": { - "com.coplaydev.unity-mcp": "file:/Users/marcussanatan/Projects/unity-mcp/UnityMcpBridge", + "com.coplaydev.unity-mcp": "file:../../../UnityMcpBridge", "com.unity.collab-proxy": "2.5.2", "com.unity.feature.development": "1.0.1", "com.unity.ide.rider": "3.0.31", diff --git a/TestProjects/UnityMCPTests/Packages/packages-lock.json b/TestProjects/UnityMCPTests/Packages/packages-lock.json index 72de9eb9..51cb01d4 100644 --- a/TestProjects/UnityMCPTests/Packages/packages-lock.json +++ b/TestProjects/UnityMCPTests/Packages/packages-lock.json @@ -1,7 +1,7 @@ { "dependencies": { "com.coplaydev.unity-mcp": { - "version": "file:/Users/marcussanatan/Projects/unity-mcp/UnityMcpBridge", + "version": "file:../../../UnityMcpBridge", "depth": 0, "source": "local", "dependencies": { From 16fb151bd70823f8c3deacb1ec4b6ff37ebf6c16 Mon Sep 17 00:00:00 2001 From: Marcus Sanatan Date: Thu, 14 Aug 2025 22:43:21 -0400 Subject: [PATCH 8/8] Remove test branch from GH workflow --- .github/workflows/unity-tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/unity-tests.yml b/.github/workflows/unity-tests.yml index 5b474b49..e1dea5a2 100644 --- a/.github/workflows/unity-tests.yml +++ b/.github/workflows/unity-tests.yml @@ -2,7 +2,7 @@ name: Unity Tests on: push: - branches: [ main, unit-tests ] + branches: [ main ] paths: - TestProjects/UnityMCPTests/** - UnityMcpBridge/Editor/**