diff --git a/src/GameplayKit/GKBehavior.cs b/src/GameplayKit/GKBehavior.cs index bf39623d3caf..de4eb67527bf 100644 --- a/src/GameplayKit/GKBehavior.cs +++ b/src/GameplayKit/GKBehavior.cs @@ -7,6 +7,8 @@ // Copyright 2015 Xamarin Inc. All rights reserved. // +#nullable enable + using System; using Foundation; @@ -18,7 +20,10 @@ public GKGoal this [nuint index] { } public NSNumber this [GKGoal goal] { - get { return ObjectForKeyedSubscript (goal); } + // The docs show that ObjectForKeyedSubscript should return 0.0 if the GKGoal is not + // available but actually returns null: https://developer.apple.com/documentation/gameplaykit/gkbehavior/1388723-objectforkeyedsubscript?language=objc + // radar filed here: https://feedbackassistant.apple.com/feedback/9979863 + get { return ObjectForKeyedSubscript (goal) ?? throw new ArgumentOutOfRangeException (nameof (goal)); } set { SetObject (value, goal); } } } diff --git a/src/GameplayKit/GKCompat.cs b/src/GameplayKit/GKCompat.cs index 8b64c9d2e959..002d069bd6f2 100644 --- a/src/GameplayKit/GKCompat.cs +++ b/src/GameplayKit/GKCompat.cs @@ -1,5 +1,7 @@ // Compatibility stubs +#nullable enable + using System; using Foundation; using ObjCRuntime; diff --git a/src/GameplayKit/GKComponentSystem.cs b/src/GameplayKit/GKComponentSystem.cs index 115dd03dc5ff..64023bf2caa3 100644 --- a/src/GameplayKit/GKComponentSystem.cs +++ b/src/GameplayKit/GKComponentSystem.cs @@ -7,6 +7,8 @@ // Copyright 2015 Xamarin Inc. All rights reserved. // +#nullable enable + using System; using Foundation; using ObjCRuntime; @@ -19,7 +21,7 @@ public GKComponentSystem () { } - public Type ComponentType { + public Type? ComponentType { get { return Class.Lookup (ComponentClass); } } diff --git a/src/GameplayKit/GKCompositeBehavior.cs b/src/GameplayKit/GKCompositeBehavior.cs index 56a52d70259c..8905013b3990 100644 --- a/src/GameplayKit/GKCompositeBehavior.cs +++ b/src/GameplayKit/GKCompositeBehavior.cs @@ -7,13 +7,15 @@ // Copyright 2016 Xamarin Inc. All rights reserved. // +#nullable enable + using System; using Foundation; namespace GameplayKit { public partial class GKCompositeBehavior { - public GKBehavior this [nuint index] { + public new GKBehavior this [nuint index] { get { return ObjectAtIndexedSubscript (index); } } diff --git a/src/GameplayKit/GKEntity.cs b/src/GameplayKit/GKEntity.cs index 3235f00c29cf..9c9828905aec 100644 --- a/src/GameplayKit/GKEntity.cs +++ b/src/GameplayKit/GKEntity.cs @@ -7,6 +7,8 @@ // Copyright 2015 Xamarin Inc. All rights reserved. // +#nullable enable + using System; using Foundation; using ObjCRuntime; @@ -19,7 +21,7 @@ public void RemoveComponent (Type componentType) RemoveComponent (GKState.GetClass (componentType, "componentType")); } - public GKComponent GetComponent (Type componentType) + public GKComponent? GetComponent (Type componentType) { return GetComponent (GKState.GetClass (componentType, "componentType")); } diff --git a/src/GameplayKit/GKGameModel.cs b/src/GameplayKit/GKGameModel.cs index 287f2431b1b5..5cc5cbd361de 100644 --- a/src/GameplayKit/GKGameModel.cs +++ b/src/GameplayKit/GKGameModel.cs @@ -1,3 +1,5 @@ +#nullable enable + using System; namespace GameplayKit { diff --git a/src/GameplayKit/GKGridGraph.cs b/src/GameplayKit/GKGridGraph.cs index f7e3675ec56c..87b52af4f3f3 100644 --- a/src/GameplayKit/GKGridGraph.cs +++ b/src/GameplayKit/GKGridGraph.cs @@ -7,6 +7,8 @@ // Copyright 2016 Xamarin Inc. All rights reserved. // +#nullable enable + using System; using ObjCRuntime; #if NET @@ -19,12 +21,12 @@ namespace GameplayKit { public partial class GKGridGraph { #if !NET - public virtual GKGridGraphNode GetNodeAt (Vector2i position) + public virtual GKGridGraphNode? GetNodeAt (Vector2i position) { return GetNodeAt (position); } #endif - public NodeType GetNodeAt (Vector2i position) where NodeType : GKGridGraphNode + public NodeType? GetNodeAt (Vector2i position) where NodeType : GKGridGraphNode { return Runtime.GetNSObject (_GetNodeAt (position)); } diff --git a/src/GameplayKit/GKObstacleGraph.cs b/src/GameplayKit/GKObstacleGraph.cs index 6b5fa74794de..20c1f000fc23 100644 --- a/src/GameplayKit/GKObstacleGraph.cs +++ b/src/GameplayKit/GKObstacleGraph.cs @@ -7,6 +7,8 @@ // Copyright 2016 Xamarin Inc. All rights reserved. // +#nullable enable + using System; using Foundation; using ObjCRuntime; @@ -54,12 +56,12 @@ public GKObstacleGraph (NSCoder coder) : base (coder) { } - public static GKObstacleGraph FromObstacles (GKPolygonObstacle [] obstacles, float bufferRadius) + public static new GKObstacleGraph? FromObstacles (GKPolygonObstacle [] obstacles, float bufferRadius) { return Runtime.GetNSObject > (GraphWithObstacles (obstacles, bufferRadius, new Class (typeof (NodeType)))); } - public NodeType [] GetNodes (GKPolygonObstacle obstacle) + public new NodeType [] GetNodes (GKPolygonObstacle obstacle) { return NSArray.ArrayFromHandle (_GetNodes (obstacle)); } diff --git a/src/GameplayKit/GKPath.cs b/src/GameplayKit/GKPath.cs index 2fcc0a2b4385..55d9147d41d8 100644 --- a/src/GameplayKit/GKPath.cs +++ b/src/GameplayKit/GKPath.cs @@ -7,6 +7,8 @@ // Copyright 2015 Xamarin Inc. All rights reserved. // +#nullable enable + using System; using Foundation; using ObjCRuntime; @@ -25,8 +27,8 @@ public partial class GKPath { public static GKPath FromPoints (Vector2[] points, float radius, bool cyclical) { - if (points == null) - throw new ArgumentNullException ("points"); + if (points is null) + ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (points)); var buffer = IntPtr.Zero; try { @@ -42,8 +44,8 @@ public static GKPath FromPoints (Vector2[] points, float radius, bool cyclical) [DesignatedInitializer] public GKPath (Vector2 [] points, float radius, bool cyclical) { - if (points == null) - throw new ArgumentNullException ("points"); + if (points is null) + ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (points)); var buffer = IntPtr.Zero; try { @@ -68,8 +70,8 @@ public GKPath (Vector2 [] points, float radius, bool cyclical) #endif public static GKPath FromPoints (Vector3 [] points, float radius, bool cyclical) { - if (points == null) - throw new ArgumentNullException ("points"); + if (points is null) + ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (points)); var buffer = IntPtr.Zero; try { @@ -95,8 +97,8 @@ public static GKPath FromPoints (Vector3 [] points, float radius, bool cyclical) #endif public GKPath (Vector3 [] points, float radius, bool cyclical) { - if (points == null) - throw new ArgumentNullException ("points"); + if (points is null) + ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (points)); var buffer = IntPtr.Zero; try { diff --git a/src/GameplayKit/GKPolygonObstacle.cs b/src/GameplayKit/GKPolygonObstacle.cs index 9b3c44d95753..c469723a3071 100644 --- a/src/GameplayKit/GKPolygonObstacle.cs +++ b/src/GameplayKit/GKPolygonObstacle.cs @@ -7,6 +7,8 @@ // Copyright 2015 Xamarin Inc. All rights reserved. // +#nullable enable + using System; using Foundation; using ObjCRuntime; @@ -22,8 +24,8 @@ public partial class GKPolygonObstacle { public static GKPolygonObstacle FromPoints (Vector2 [] points) { - if (points == null) - throw new ArgumentNullException ("points"); + if (points is null) + ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (points)); var size = Marshal.SizeOf (typeof (Vector2)); var length = points.Length * size; @@ -45,8 +47,8 @@ public static GKPolygonObstacle FromPoints (Vector2 [] points) static unsafe IntPtr GetPointer (Vector2[] points) { - if (points == null) - throw new ArgumentNullException ("points"); + if (points is null) + ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (points)); if (ctor_pointer != IntPtr.Zero) { // This can occur of a previous call to the base ctor threw an exception diff --git a/src/GameplayKit/GKPrimitives.cs b/src/GameplayKit/GKPrimitives.cs index b78dfb177911..323b0cfe9239 100644 --- a/src/GameplayKit/GKPrimitives.cs +++ b/src/GameplayKit/GKPrimitives.cs @@ -7,6 +7,8 @@ // Copyright 2016 Xamarin Inc. All rights reserved. // +#nullable enable + using System; using System.Runtime.InteropServices; using ObjCRuntime; @@ -72,8 +74,8 @@ public Vector3 [] Points { return points ?? (points = new Vector3 [3]); } set { - if (value == null) - throw new ArgumentNullException (nameof (value)); + if (value is null) + ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (value)); if (value.Length != 3) throw new ArgumentOutOfRangeException (nameof (value), "The length of the Value array must be 3"); points = value; diff --git a/src/GameplayKit/GKState.cs b/src/GameplayKit/GKState.cs index 9e3a65671571..c89638d03517 100644 --- a/src/GameplayKit/GKState.cs +++ b/src/GameplayKit/GKState.cs @@ -7,6 +7,8 @@ // Copyright 2015 Xamarin Inc. All rights reserved. // +#nullable enable + using System; using Foundation; using ObjCRuntime; @@ -16,8 +18,8 @@ public partial class GKState { internal static Class GetClass (Type type, string parameterName) { - if (type == null) - throw new ArgumentNullException (parameterName); + if (type is null) + ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (parameterName)); var klass = new Class (type); // most API do not accept null so we throw in managed code instead of crashing the app @@ -29,11 +31,11 @@ internal static Class GetClass (Type type, string parameterName) internal static Class GetClass (NSObject instance, string parameterName) { - if (instance == null) - throw new ArgumentNullException (parameterName); + if (instance is null) + ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (parameterName)); var klass = instance.Class; - if ((klass == null) || (klass.Handle == IntPtr.Zero)) + if ((klass is null) || (klass.Handle == IntPtr.Zero)) throw new ArgumentException ("Not an type exposed to ObjC", parameterName); return klass; diff --git a/src/GameplayKit/GKStateMachine.cs b/src/GameplayKit/GKStateMachine.cs index 5c258c567d9f..05322dd4a098 100644 --- a/src/GameplayKit/GKStateMachine.cs +++ b/src/GameplayKit/GKStateMachine.cs @@ -7,6 +7,8 @@ // Copyright 2015 Xamarin Inc. All rights reserved. // +#nullable enable + using System; using Foundation; using ObjCRuntime; @@ -14,12 +16,12 @@ namespace GameplayKit { public partial class GKStateMachine : NSObject { - public GKState GetState (Type stateType) + public GKState? GetState (Type stateType) { return GetState (GKState.GetClass (stateType, "stateType")); } - public GKState GetState (GKState state) + public GKState? GetState (GKState state) { return GetState (GKState.GetClass (state, "state")); } diff --git a/src/GameplayKit/NSArray_GameplayKit.cs b/src/GameplayKit/NSArray_GameplayKit.cs index 81b9427e68f5..01e473e1745a 100644 --- a/src/GameplayKit/NSArray_GameplayKit.cs +++ b/src/GameplayKit/NSArray_GameplayKit.cs @@ -7,6 +7,8 @@ // Copyright 2016 Xamarin Inc. All rights reserved. // +#nullable enable + using System; using Foundation; using ObjCRuntime; @@ -28,8 +30,8 @@ public static class NSArray_GameplayKit { [Export ("shuffledArrayWithRandomSource:")] public static T [] GetShuffledArray (this NSArray This, GKRandomSource randomSource) where T : class, INativeObject { - if (randomSource == null) - throw new ArgumentNullException (nameof (randomSource)); + if (randomSource is null) + ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (randomSource)); return NSArray.ArrayFromHandle (Messaging.IntPtr_objc_msgSend_IntPtr (This.Handle, Selector.GetHandle ("shuffledArrayWithRandomSource:"), randomSource.Handle)); } diff --git a/tests/monotouch-test/GameplayKit/GKBehaviorTests.cs b/tests/monotouch-test/GameplayKit/GKBehaviorTests.cs new file mode 100644 index 000000000000..b5d9f97d5874 --- /dev/null +++ b/tests/monotouch-test/GameplayKit/GKBehaviorTests.cs @@ -0,0 +1,42 @@ +// +// Unit tests for GKBehavior +// +// Authors: +// TJ Lambert +// +// +// Copyright 2022 Xamarin Inc. All rights reserved. +// + +#if !__WATCHOS__ + +using System; +using NUnit.Framework; + +using Foundation; +using GameplayKit; + +namespace MonoTouchFixtures.GamePlayKit { + [TestFixture] + [Preserve (AllMembers = true)] + public class GKBehaviorTests { + + [Test] + public void ObjectForKeyedSubscriptTest () + { + // Create 2 GKGoals to use in the gkBehavior + var goal1 = GKGoal.GetGoalToReachTargetSpeed (10); + var goal2 = GKGoal.GetGoalToReachTargetSpeed (15); + + // Create a GKGoal that will not be included in gkBehavior + var goal3 = GKGoal.GetGoalToReachTargetSpeed (15); + + // Create a GKBehavior from those first 2 goals + var gkBehavior = GKBehavior.FromGoals (new GKGoal [] { goal1, goal2 }); + + // Searching the gkBehavior for a non-exisitant goal should throw an ArgumentOutOfRangeException + Assert.Throws ( () => { _ = gkBehavior[goal3]; }, "The ObjectForKeyedSubscript indexer should throw ArgumentOutOfRangeException if the goal is not in the behavior's list of GKGoals."); + } + } +} +#endif