Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a260324
Update the parser for migration
AswinRajGopal Sep 25, 2025
00b37a5
Added a test to cover the package migration.
AswinRajGopal Oct 2, 2025
d637adf
Revert "Added a test to cover the package migration."
AswinRajGopal Oct 3, 2025
4e76813
Revert "Update the parser for migration"
AswinRajGopal Oct 3, 2025
a8ba533
The the processors are split by , instead of ; it was typo
AswinRajGopal Oct 3, 2025
ff05b1d
Robust handling of migration logic
AswinRajGopal Oct 6, 2025
829c4aa
Added test to cover the migration
AswinRajGopal Oct 6, 2025
9467adf
Update test
AswinRajGopal Oct 7, 2025
3e490f1
Address PR feeback.
AswinRajGopal Oct 7, 2025
a31d971
Address PR comments.
AswinRajGopal Oct 7, 2025
817ff0e
Update the test to include more than one processors in actionmap.
AswinRajGopal Oct 7, 2025
2914bf7
Removed redundant call
AswinRajGopal Oct 7, 2025
6daabc9
Revert changes and moved the function changes to NameAndParameters as…
AswinRajGopal Oct 8, 2025
6aca9db
Bring back the test which verifies the migration along with processed…
AswinRajGopal Oct 10, 2025
f3f7ea5
Update the test as per review comments.
AswinRajGopal Oct 16, 2025
f5b06da
Simply the code removing redundancy - as these checks are handled in …
AswinRajGopal Oct 16, 2025
6b4c75a
Add check incase if raw string is null.
AswinRajGopal Oct 16, 2025
64076cb
Reformatting files.
AswinRajGopal Oct 16, 2025
f042f1e
Merge branch 'develop' into isxb-1678/fix-customprocessor-serialise-r…
ekcoh Oct 21, 2025
14dfb97
Merge branch 'develop' into isxb-1678/fix-customprocessor-serialise-r…
LeoUnity Oct 24, 2025
836d6e8
Update Changelog
AswinRajGopal Oct 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions Assets/Tests/InputSystem.Editor/CustomProcessorEnumTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,5 +108,58 @@ public IEnumerator ProcessorEnum_ShouldSerializeByValue_WhenSerializedToAsset()

yield return null;
}

[Test]
public void Migration_ShouldProduceValidActionAsset_WithEnumProcessorConverted()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you document what the intent of this test case is inline in code?

My interpretation is that you want to verify that processors defined in a certain way in .inputaction json are parsed/preserved correctly when imported (with migration)? If this is the case I suggest you convert this into a functional test instead of doing a lot of string comparisons. Here is a rough example (coded directly into web interface so it may contain errors but hope you get the idea):

const string legacyJson = "<as before>"; // Consider including binding in JSON to avoid writing code for it
var asset = InputActionAsset.FromJson(legacyJson);
var gamepad = InputSystem.AddDevice<Gamepad>();
var action = asset.FindAction("Player/Move");
action.Enable();

// Make sure deadzone processor is applied
Set(gamepad.leftStick, new Vector2(InputSystem.settings.defaultDeadzoneMin * 0.9f, 0.0f));
Assert.That(action.ReadValue<Vector2>(), Is.Equal(Vecto2.zero)); // Filtered by deadzone

// Make sure invert processor is applied
Set(gamepad.leftStick, new Vector2(1.0f, 0.0f));
Assert.That(action.ReadValue<Vector2>(), Is.Equal(-Vector2.right)); // Inverted

// Make sure custom processor is applied
Set(gamepad.leftStick, new Vector2(0.5f, 0.0f));
Assert.That(action.ReadValue<Vector2>(), Is.Equal(something)); // Not sure how custom should change value, so change this to what is appropriate

Ideally order dependency can be proven through the same test case.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure I'll change it into a functional test.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you see any pros/cons with changing approach? Would such a functional test miss some aspect of this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My view about authoring a regression test is to cover only the migration case where we actually verify that a JSON with a custom processor and some neighboring processors like stickdeadzone or invertVector are parsed properly after migration.

The functional tests already exists which covers most of the functionals in the input system generic tests. However it will be robust to club both of these for this case.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, that is also fine so keep this if you want. Not sure @LeoUnity has additional perspective?
Not sure we already test this specific processor order somewhere else?

{
var legacyJson = @"
{
""name"": ""InputSystem_Actions"",
""maps"": [
{
""name"": ""Player"",
""id"": ""df70fa95-8a34-4494-b137-73ab6b9c7d37"",
""actions"": [
{
""name"": ""Move"",
""type"": ""Value"",
""id"": ""351f2ccd-1f9f-44bf-9bec-d62ac5c5f408"",
""expectedControlType"": ""Vector2"",
""processors"": ""StickDeadzone,InvertVector2(invertX=false),Custom(SomeEnum=1)"",
""interactions"": """",
""initialStateCheck"": true
}
]
}
],
""controlSchemes"": [],
""version"": 0
}";

// Parse and migrate the legacy JSON
var asset = InputActionAsset.FromJson(legacyJson);

// Object is valid after migration
Assert.That(asset, Is.Not.Null, "Migration failed to produce a valid InputActionAsset.");

var map = asset.FindActionMap("Player");
Assert.That(map, Is.Not.Null, "Expected Player map to exist.");

var action = map.FindAction("Move");
Assert.That(action, Is.Not.Null, "Expected Move action to exist.");

var processors = action.processors;

// Verify processor order and that enum was converted properly
Assert.That(processors, Does.Contain("StickDeadzone"), "StickDeadzone processor missing.");
Assert.That(processors, Does.Contain("InvertVector2(invertX=false)"), "InvertVector2 missing.");
Assert.That(processors, Does.Contain("Custom(SomeEnum=20)"), "Custom(SomeEnum=1) should migrate to SomeEnum=20 (OptionB).");

// Verify To JSON
var toJson = asset.ToJson();
var reloaded = InputActionAsset.FromJson(toJson);
Assert.That(reloaded, Is.Not.Null, "Reloaded asset after migration is null.");
Assert.That(reloaded.FindAction("Player/Move"), Is.Not.Null, "Reloaded asset did not contain expected Move action.");
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -1027,43 +1027,37 @@ internal void MigrateJson(ref ReadFileJson parsedJson)
continue;

var list = NameAndParameters.ParseMultiple(raw).ToList();
var rebuilt = new List<string>(list.Count);
var converted = new List<NameAndParameters>(list.Count);
foreach (var nap in list)
{
var procType = InputSystem.TryGetProcessor(nap.name);
if (nap.parameters.Count == 0 || procType == null)
{
rebuilt.Add(nap.ToString());
converted.Add(nap);
continue;
}

var dict = nap.parameters.ToDictionary(p => p.name, p => p.value.ToString());
var anyChanged = false;
foreach (var field in procType.GetFields(BindingFlags.Public | BindingFlags.Instance).Where(f => f.FieldType.IsEnum))
var updatedParameters = new List<NamedValue>(nap.parameters.Count);
foreach (var param in nap.parameters)
{
if (dict.TryGetValue(field.Name, out var ordS) && int.TryParse(ordS, out var ord))
var updatedPar = param;
var fieldInfo = procType.GetField(param.name, BindingFlags.Public | BindingFlags.Instance);
if(fieldInfo != null && fieldInfo.FieldType.IsEnum)
{
var values = Enum.GetValues(field.FieldType).Cast<object>().ToArray();
if (ord >= 0 && ord < values.Length)
var index = param.value.ToInt32();
var values = Enum.GetValues(fieldInfo.FieldType);
if(index >= 0 && index < values.Length)
{
dict[field.Name] = Convert.ToInt32(values[ord]).ToString();
anyChanged = true;
var convertedValue = Convert.ToInt32(values.GetValue(index));
updatedPar = NamedValue.From(param.name, convertedValue);
}
}
updatedParameters.Add(updatedPar);
}

if (!anyChanged)
{
rebuilt.Add(nap.ToString());
}
else
{
var paramText = string.Join(",", dict.Select(kv => $"{kv.Key}={kv.Value}"));
rebuilt.Add($"{nap.name}({paramText})");
}
converted.Add(NameAndParameters.Create(nap.name, updatedParameters));
}

actionJson.processors = string.Join(";", rebuilt);
actionJson.processors = NameAndParameters.SerializeMultiple(converted);
mapJson.actions[ai] = actionJson;
}
parsedJson.maps[mi] = mapJson;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,7 @@ private void OnParametersChanged(ParameterListView listView, int index)

private static string ToSerializableString(IEnumerable<NameAndParameters> parametersForEachListItem)
{
if (parametersForEachListItem == null)
return string.Empty;

return string.Join(NamedValue.Separator,
parametersForEachListItem.Select(x => x.ToString()).ToArray());
return NameAndParameters.SerializeMultiple(parametersForEachListItem);
}

public override void RedrawUI(InputActionsEditorState state)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,24 @@
return $"{name}({parameterString})";
}

internal static string SerializeMultiple(IEnumerable<NameAndParameters> list)
{
if(list == null)
return string.Empty;

Check warning on line 33 in Packages/com.unity.inputsystem/InputSystem/Utilities/NameAndParameters.cs

View check run for this annotation

Codecov GitHub.com / codecov/patch

Packages/com.unity.inputsystem/InputSystem/Utilities/NameAndParameters.cs#L33

Added line #L33 was not covered by tests

return string.Join(NamedValue.Separator, list.Select(x => x.ToString()).ToArray());
}

internal static NameAndParameters Create(string name, IList<NamedValue> parameters)
{
var result = new NameAndParameters
{
name = name,
parameters = new ReadOnlyArray<NamedValue>(parameters.ToArray())
};
return result;
}

public static IEnumerable<NameAndParameters> ParseMultiple(string text)
{
List<NameAndParameters> list = null;
Expand Down