Skip to content

Commit 665d11d

Browse files
authored
NEW: Add tests for Project wide actions (#1742)
* project-wide actions: add missing control schemes to some bindings * ensure we only load the InputActionsAsset containing the projectwide actions at runtime * add some tests for project wide settings * Temporarily disable some tests in Player which have issues with ProjectWide actions * run code formatter * review comments
1 parent a7763b3 commit 665d11d

9 files changed

Lines changed: 261 additions & 10 deletions

File tree

Assets/Tests/InputSystem/CoreTests_Actions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5020,7 +5020,7 @@ public void Actions_WhenControlsUpdate_TimeoutsAreCarriedOver()
50205020
[Category("Actions")]
50215021
public void Actions_WhenControlsUpdate_InProgressActionsKeepGoing()
50225022
{
5023-
#if UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS && UNITY_EDITOR
5023+
#if UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS
50245024
// @TODO: This should not need disabled for this test (https://jira.unity3d.com/browse/ISX-1455)
50255025
// Causes: "[Assert] Could not find active control after binding resolution"
50265026
// when RemoveDevice() called

Assets/Tests/InputSystem/CoreTests_Devices.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4390,7 +4390,7 @@ public void TODO_Devices_CanHijackEventStreamOfDevice()
43904390
[TestCase(false, InputSettings.BackgroundBehavior.ResetAndDisableNonBackgroundDevices, InputSettings.EditorInputBehaviorInPlayMode.AllDeviceInputAlwaysGoesToGameView)]
43914391
public unsafe void Devices_CanHandleFocusChanges(bool appRunInBackground, InputSettings.BackgroundBehavior backgroundBehavior, InputSettings.EditorInputBehaviorInPlayMode editorInputBehaviorInPlayMode)
43924392
{
4393-
#if UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS && UNITY_EDITOR
4393+
#if UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS
43944394
// @TODO: This should not need disabled for this test (https://jira.unity3d.com/browse/ISX-1455)
43954395
// Causes: "[Assert] Could not find active control after binding resolution"
43964396
// due to: mouse3 = InputSystem.AddDevice<Mouse>();
@@ -5363,7 +5363,7 @@ public void Devices_RemovingKeyboardMakesNextKeyboardCurrent()
53635363
[Category("Devices")]
53645364
public void Devices_RemovingDevice_MakesNextDeviceOfTypeCurrent()
53655365
{
5366-
#if UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS && UNITY_EDITOR
5366+
#if UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS
53675367
// @TODO: This should not need disabled for this test (https://jira.unity3d.com/browse/ISX-1455)
53685368
// Causes: "[Assert] Could not find active control after binding resolution"
53695369
// during point where Pointer is removed
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
#if UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS
2+
3+
using System;
4+
using System.IO;
5+
using NUnit.Framework;
6+
using UnityEditor;
7+
using UnityEngine;
8+
using UnityEngine.InputSystem;
9+
10+
#if UNITY_EDITOR
11+
using UnityEngine.InputSystem.Editor;
12+
#endif
13+
14+
internal partial class CoreTests
15+
{
16+
const string TestCategory = "ProjectWideActions";
17+
const string TestAssetPath = "Assets/TestInputManager.asset";
18+
string m_TemplateAssetPath;
19+
20+
#if UNITY_EDITOR
21+
const int initialActionCount = 2;
22+
const int initialMapCount = 1;
23+
#else
24+
const int initialActionCount = 17;
25+
const int initialMapCount = 2;
26+
#endif
27+
28+
[SetUp]
29+
public override void Setup()
30+
{
31+
// @TODO: Currently we can only inject the TestActionsAsset in PlayMode tests.
32+
// It would be nice to be able to inject it as a Preloaded asset into the Player tests so
33+
// we don't need different tests for the player.
34+
// This also means these tests are dependant on the content of InputManager.asset not being changed.
35+
#if UNITY_EDITOR
36+
// This asset takes the place of ProjectSettings/InputManager.asset for the sake of testing, as we don't
37+
// really want to go changing that asset in every test.
38+
// This is used as a backing for `InputSystem.actions` in PlayMode tests.
39+
var testAsset = ScriptableObject.CreateInstance<TestActionsAsset>();
40+
AssetDatabase.CreateAsset(testAsset, TestAssetPath);
41+
42+
// Create a template `InputActionAsset` containing some test actions.
43+
// This will then be used to populate the initially empty `TestActionsAsset` when it is first acessed.
44+
var templateActions = ScriptableObject.CreateInstance<InputActionAsset>();
45+
templateActions.name = "TestAsset";
46+
var map = templateActions.AddActionMap("InitialActionMapOne");
47+
map.AddAction("InitialActionOne");
48+
map.AddAction("InitialActionTwo");
49+
50+
m_TemplateAssetPath = Path.Combine(Environment.CurrentDirectory, "Assets/ProjectWideActionsTemplate.inputactions");
51+
File.WriteAllText(m_TemplateAssetPath, templateActions.ToJson());
52+
53+
ProjectWideActionsAsset.SetAssetPaths(m_TemplateAssetPath, TestAssetPath);
54+
#endif
55+
56+
base.Setup();
57+
}
58+
59+
[TearDown]
60+
public override void TearDown()
61+
{
62+
#if UNITY_EDITOR
63+
ProjectWideActionsAsset.Reset();
64+
65+
if (File.Exists(m_TemplateAssetPath))
66+
File.Delete(m_TemplateAssetPath);
67+
68+
AssetDatabase.DeleteAsset(TestAssetPath);
69+
#endif
70+
71+
base.TearDown();
72+
}
73+
74+
#if UNITY_EDITOR
75+
[Test]
76+
[Category(TestCategory)]
77+
public void ProjectWideActionsAsset_TemplateAssetIsInstalledOnFirstUse()
78+
{
79+
var asset = ProjectWideActionsAsset.GetOrCreate();
80+
81+
Assert.That(asset, Is.Not.Null);
82+
Assert.That(asset.actionMaps.Count, Is.EqualTo(initialMapCount));
83+
Assert.That(asset.actionMaps[0].actions.Count, Is.EqualTo(initialActionCount));
84+
Assert.That(asset.actionMaps[0].actions[0].name, Is.EqualTo("InitialActionOne"));
85+
}
86+
87+
[Test]
88+
[Category(TestCategory)]
89+
public void ProjectWideActionsAsset_CanModifySaveAndLoadAsset()
90+
{
91+
var asset = ProjectWideActionsAsset.GetOrCreate();
92+
93+
Assert.That(asset, Is.Not.Null);
94+
Assert.That(asset.actionMaps.Count, Is.EqualTo(initialMapCount));
95+
Assert.That(asset.actionMaps[0].actions.Count, Is.EqualTo(initialActionCount));
96+
Assert.That(asset.actionMaps[0].actions[0].name, Is.EqualTo("InitialActionOne"));
97+
98+
asset.Disable(); // Cannot modify active actions
99+
100+
// Add more actions
101+
asset.actionMaps[0].AddAction("ActionTwo");
102+
asset.actionMaps[0].AddAction("ActionThree");
103+
104+
// Modify existing
105+
asset.actionMaps[0].actions[0].Rename("FirstAction");
106+
107+
// Add another map
108+
asset.AddActionMap("ActionMapTwo").AddAction("AnotherAction");
109+
110+
// Save
111+
AssetDatabase.SaveAssets();
112+
113+
// Reload
114+
asset = ProjectWideActionsAsset.GetOrCreate();
115+
116+
Assert.That(asset, Is.Not.Null);
117+
Assert.That(asset.actionMaps.Count, Is.EqualTo(initialMapCount + 1));
118+
Assert.That(asset.actionMaps[0].actions.Count, Is.EqualTo(initialActionCount + 2));
119+
Assert.That(asset.actionMaps[1].actions.Count, Is.EqualTo(1));
120+
Assert.That(asset.actionMaps[0].actions[0].name, Is.EqualTo("FirstAction"));
121+
Assert.That(asset.actionMaps[1].actions[0].name, Is.EqualTo("AnotherAction"));
122+
}
123+
124+
#endif
125+
126+
[Test]
127+
[Category(TestCategory)]
128+
public void ProjectWideActions_AreEnabledByDefault()
129+
{
130+
Assert.That(InputSystem.actions, Is.Not.Null);
131+
Assert.That(InputSystem.actions.enabled, Is.True);
132+
}
133+
134+
[Test]
135+
[Category(TestCategory)]
136+
public void ProjectWideActions_ContainsTemplateActions()
137+
{
138+
Assert.That(InputSystem.actions, Is.Not.Null);
139+
Assert.That(InputSystem.actions.actionMaps.Count, Is.EqualTo(initialMapCount));
140+
141+
#if UNITY_EDITOR
142+
Assert.That(InputSystem.actions.actionMaps[0].actions.Count, Is.EqualTo(initialActionCount));
143+
Assert.That(InputSystem.actions.actionMaps[0].actions[0].name, Is.EqualTo("InitialActionOne"));
144+
#else
145+
Assert.That(InputSystem.actions.actionMaps[0].actions.Count, Is.EqualTo(9));
146+
Assert.That(InputSystem.actions.actionMaps[0].actions[0].name, Is.EqualTo("Move"));
147+
#endif
148+
}
149+
150+
[Test]
151+
[Category(TestCategory)]
152+
public void ProjectWideActions_AppearInEnabledActions()
153+
{
154+
var enabledActions = InputSystem.ListEnabledActions();
155+
Assert.That(enabledActions, Has.Count.EqualTo(initialActionCount));
156+
157+
// Add more actions also work
158+
var action = new InputAction(name: "standaloneAction");
159+
action.Enable();
160+
161+
enabledActions = InputSystem.ListEnabledActions();
162+
Assert.That(enabledActions, Has.Count.EqualTo(initialActionCount + 1));
163+
Assert.That(enabledActions, Has.Exactly(1).SameAs(action));
164+
165+
// Disabling works
166+
InputSystem.actions.Disable();
167+
enabledActions = InputSystem.ListEnabledActions();
168+
Assert.That(enabledActions, Has.Count.EqualTo(1));
169+
Assert.That(enabledActions, Has.Exactly(1).SameAs(action));
170+
}
171+
172+
[Test]
173+
[Category(TestCategory)]
174+
public void ProjectWideActions_CanReplaceExistingActions()
175+
{
176+
// Initial State
177+
Assert.That(InputSystem.actions, Is.Not.Null);
178+
Assert.That(InputSystem.actions.enabled, Is.True);
179+
var enabledActions = InputSystem.ListEnabledActions();
180+
Assert.That(enabledActions, Has.Count.EqualTo(initialActionCount));
181+
182+
// Build new asset
183+
var asset = ScriptableObject.CreateInstance<InputActionAsset>();
184+
var map1 = new InputActionMap("replacedMap1");
185+
var map2 = new InputActionMap("replacedMap2");
186+
var action1 = map1.AddAction("replacedAction1", InputActionType.Button);
187+
var action2 = map1.AddAction("replacedAction2", InputActionType.Button);
188+
var action3 = map1.AddAction("replacedAction3", InputActionType.Button);
189+
var action4 = map2.AddAction("replacedAction4", InputActionType.Button);
190+
191+
action1.AddBinding("<Gamepad>/buttonSouth");
192+
action2.AddBinding("<Gamepad>/buttonWest");
193+
action3.AddBinding("<Gamepad>/buttonNorth");
194+
action4.AddBinding("<Gamepad>/buttonEast");
195+
asset.AddActionMap(map1);
196+
asset.AddActionMap(map2);
197+
198+
// Replace project-wide actions
199+
InputSystem.actions = asset;
200+
201+
// State after replacing
202+
Assert.That(InputSystem.actions, Is.Not.Null);
203+
Assert.That(InputSystem.actions.enabled, Is.True);
204+
enabledActions = InputSystem.ListEnabledActions();
205+
Assert.That(enabledActions, Has.Count.EqualTo(4));
206+
207+
Assert.That(InputSystem.actions.actionMaps.Count, Is.EqualTo(2));
208+
Assert.That(InputSystem.actions.actionMaps[0].actions.Count, Is.EqualTo(3));
209+
Assert.That(InputSystem.actions.actionMaps[0].actions[0].name, Is.EqualTo("replacedAction1"));
210+
Assert.That(InputSystem.actions.actionMaps[1].actions.Count, Is.EqualTo(1));
211+
Assert.That(InputSystem.actions.actionMaps[1].actions[0].name, Is.EqualTo("replacedAction4"));
212+
}
213+
}
214+
215+
#endif

Assets/Tests/InputSystem/CoreTests_ProjectWideActions.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
using UnityEngine;
2+
3+
internal class TestActionsAsset : ScriptableObject
4+
{
5+
}

Assets/Tests/InputSystem/TestActionsAsset.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Packages/com.unity.inputsystem/InputSystem/Editor/ProjectWideActions/ProjectWideActionsAsset.cs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,26 @@ internal static class ProjectWideActionsAsset
1212
{
1313
internal const string kDefaultAssetPath = "Packages/com.unity.inputsystem/InputSystem/Editor/ProjectWideActions/ProjectWideActionsTemplate.inputactions";
1414
internal const string kAssetPath = "ProjectSettings/InputManager.asset";
15-
internal const string kAssetName = "ProjectWideInputActions";
15+
internal const string kAssetName = InputSystem.kProjectWideActionsAssetName;
1616

1717
static string s_DefaultAssetPath = kDefaultAssetPath;
1818
static string s_AssetPath = kAssetPath;
1919

20-
// For Testing
20+
#if UNITY_INCLUDE_TESTS
2121
internal static void SetAssetPaths(string defaultAssetPath, string assetPath)
2222
{
2323
s_DefaultAssetPath = defaultAssetPath;
2424
s_AssetPath = assetPath;
2525
}
2626

27+
internal static void Reset()
28+
{
29+
s_DefaultAssetPath = kDefaultAssetPath;
30+
s_AssetPath = kAssetPath;
31+
}
32+
33+
#endif
34+
2735
[InitializeOnLoadMethod]
2836
internal static void InstallProjectWideActions()
2937
{

Packages/com.unity.inputsystem/InputSystem/Editor/ProjectWideActions/ProjectWideActionsTemplate.inputactions

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@
314314
"path": "<Keyboard>/enter",
315315
"interactions": "",
316316
"processors": "",
317-
"groups": "",
317+
"groups": "Keyboard&Mouse",
318318
"action": "Attack",
319319
"isComposite": false,
320320
"isPartOfComposite": false
@@ -347,7 +347,7 @@
347347
"path": "<Keyboard>/leftShift",
348348
"interactions": "",
349349
"processors": "",
350-
"groups": "",
350+
"groups": "Keyboard&Mouse",
351351
"action": "Sprint",
352352
"isComposite": false,
353353
"isPartOfComposite": false
@@ -369,7 +369,7 @@
369369
"path": "<XRController>/trigger",
370370
"interactions": "",
371371
"processors": "",
372-
"groups": "",
372+
"groups": "XR",
373373
"action": "Sprint",
374374
"isComposite": false,
375375
"isPartOfComposite": false
@@ -446,7 +446,7 @@
446446
"path": "<Gamepad>/buttonNorth",
447447
"interactions": "",
448448
"processors": "",
449-
"groups": "",
449+
"groups": "Gamepad",
450450
"action": "Interact",
451451
"isComposite": false,
452452
"isPartOfComposite": false

Packages/com.unity.inputsystem/InputSystem/InputSystem.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3012,6 +3012,7 @@ internal static bool ShouldDrawWarningIconForBinding(string bindingPath)
30123012
#if UNITY_INPUT_SYSTEM_PROJECT_WIDE_ACTIONS
30133013

30143014
private static InputActionAsset s_projectWideActions;
3015+
internal const string kProjectWideActionsAssetName = "ProjectWideInputActions";
30153016

30163017
/// <summary>
30173018
/// An input action asset (see <see cref="InputActionAsset"/>) which is always available by default.
@@ -3039,7 +3040,7 @@ public static InputActionAsset actions
30393040
s_projectWideActions, true);
30403041
}
30413042
#else
3042-
s_projectWideActions = Resources.FindObjectsOfTypeAll<InputActionAsset>().FirstOrDefault();
3043+
s_projectWideActions = Resources.FindObjectsOfTypeAll<InputActionAsset>().FirstOrDefault(o => o != null && o.name == kProjectWideActionsAssetName);
30433044
#endif
30443045

30453046
if (s_projectWideActions == null)

0 commit comments

Comments
 (0)