Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f1984d4
Gitignore the .godot dir
Zoomulator Jun 16, 2023
c324509
Godot 4 auto-upgrade
Zoomulator Jun 16, 2023
ffa9733
Opening and saving the project
Zoomulator Jun 16, 2023
6ae009f
Update target framework to net6.0 and godot SDK
Zoomulator Jun 16, 2023
2aaf274
Fix changes with Vector2
Zoomulator Jun 16, 2023
751c73d
Fix Transform2D changes
Zoomulator Jun 16, 2023
9269b42
Fix mouse button enum changes
Zoomulator Jun 16, 2023
2558f03
FindNode is not called FindChild
Zoomulator Jun 16, 2023
863a81d
Fix enum to Variant casts
Zoomulator Jun 16, 2023
b0293ed
Fix Variant to String conversions
Zoomulator Jun 16, 2023
bb6ca83
Fix PackedScene Instantiate call
Zoomulator Jun 16, 2023
542fc00
Fix the UI querying the viewport size
Zoomulator Jun 16, 2023
612aa52
Fix remaining Variant errors
Zoomulator Jun 16, 2023
161d7d2
CanvasItem.Update is now called QueueRedraw
Zoomulator Jun 16, 2023
664c9ad
Fix auto-convert mistake with Path
Zoomulator Jun 16, 2023
46d173b
Fix override _Process method signatures
Zoomulator Jun 16, 2023
afc993b
Button.Pressed property is called ButtonPressed
Zoomulator Jun 16, 2023
d9db082
Godot.OS.Execute changed signature
Zoomulator Jun 16, 2023
c6633a9
Fix target assembly OptionButton items
Zoomulator Jun 16, 2023
f7f8249
Fix TreeItem child iteration
Zoomulator Jun 16, 2023
eaace31
Fix CharacterBody2D changes
Zoomulator Jun 16, 2023
69512d2
Fix the file system operations
Zoomulator Jun 16, 2023
6abb05a
Missing partial keyword
Zoomulator Jun 16, 2023
06148f2
Add MustBeVariant attribute to generic type arg
Zoomulator Jun 16, 2023
b6f7834
Signal delegate names must end with EventHandler
Zoomulator Jun 16, 2023
734195b
Update langversion to 10
Zoomulator Jun 16, 2023
1400f03
Godot changed a project.godot entry after passing build
Zoomulator Jun 16, 2023
71c8b9d
Removed conflicting reference causing build warning
Zoomulator Jun 16, 2023
bd199f3
Fix target assembly options not being cleared
Zoomulator Jun 16, 2023
26b228b
Copy assemblies to fix xunit.core not being found
Zoomulator Jun 16, 2023
0fd1639
Fix target assembly path resolution
Zoomulator Jun 17, 2023
82c4285
Brute force assembly resolution
Zoomulator Jun 17, 2023
56f7208
Auto-format on file with few changes
Zoomulator Jun 18, 2023
5366d16
Idle frame is called process_frame
Zoomulator Jun 17, 2023
d7d5121
Make tests run via the main Godot thread
Zoomulator Jun 17, 2023
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@

.godot
*.user
*.userosscache
*.sln.docstates
Expand Down
14 changes: 6 additions & 8 deletions GodotXUnit.csproj
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
<Project Sdk="Godot.NET.Sdk/3.3.0">
<Project Sdk="Godot.NET.Sdk/4.1.0-beta.2">
<PropertyGroup>
<ProjectGuid>{B6A000AB-04AE-4D1E-A0D5-93911E363F6D}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>GodotXUnit</RootNamespace>
<AssemblyName>GodotXUnit</AssemblyName>
<GodotProjectGeneratorVersion>1.0.0.0</GodotProjectGeneratorVersion>
<LangVersion>8</LangVersion>
<TargetFramework>net472</TargetFramework>
<LangVersion>10</LangVersion>
<TargetFramework>net6.0</TargetFramework>
<!--The following properties were overriden during migration to prevent errors.
Enabling them may require other manual changes to the project and its files.-->
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<Deterministic>false</Deterministic>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="addons\GodotXUnit\Plugin.cs" />
<Compile Include="addons\GodotXUnit\GodotTestRunner.cs" />
Expand Down Expand Up @@ -43,7 +41,7 @@
<Content Include="addons\GodotXUnit\README" />
<Content Include="addons\GodotXUnit\runner\EmptyScene.tscn" />
<Content Include="addons\GodotXUnit\runner\GodotTestRunnerScene.tscn" />
<Content Include="addons\GodotXUnit\runner\RiderTestRunner\Runner.tscn" Condition="'$(Configuration)' == 'Debug' "/>
<Content Include="addons\GodotXUnit\runner\RiderTestRunner\Runner.tscn" Condition="'$(Configuration)' == 'Debug' " />
<Content Include="addons\GodotXUnit\XUnitDock.tscn" />
<Content Include="addons\GodotXUnit\_work\.gdignore" />
</ItemGroup>
Expand All @@ -53,4 +51,4 @@
<Name>GodotXUnitApi</Name>
</ProjectReference>
</ItemGroup>
</Project>
</Project>
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ timeouts. full example at ./tests/PhysicsCollisionTest.cs
[GodotFact(Scene = "res://test_scenes/PhysicsCollisionTest.tscn")]
public async void TestOhNoTooSlowOfFall()
{
var ball = (AVerySpecialBall) GDU.CurrentScene.FindNode("AVerySpecialBall");
var ball = (AVerySpecialBall) GDU.CurrentScene.FindChild("AVerySpecialBall");
Assert.NotNull(ball);

// it will throw a TimeoutException here because the gravity value is too low
Expand Down
2 changes: 1 addition & 1 deletion addons/GodotXUnit/GodotTestRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace GodotXUnit
{
public class GodotTestRunner : GodotXUnitRunnerBase
public partial class GodotTestRunner : GodotXUnitRunnerBase
{

}
Expand Down
48 changes: 26 additions & 22 deletions addons/GodotXUnit/GodotXUnitApi/GDI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ public static class GDI
/// </summary>
public static float PositionXByScreenPercent(float percent)
{
return GDU.Viewport.Size.x * percent;
return GDU.ViewportSize.X * percent;
}

/// <summary>
/// gets the y pixel position based on the percent of the screen
/// </summary>
public static float PositionYByScreenPercent(float percent)
{
return GDU.Viewport.Size.y * percent;
return GDU.ViewportSize.Y * percent;
}

/// <summary>
/// gets a vector2 representing the pixel positions based on the screen percents.
/// </summary>
Expand All @@ -44,34 +44,38 @@ public static Vector2 PositionBy2DWorldPos(Vector2 worldPos)
var scene = GDU.CurrentScene as Node2D;
if (scene == null)
throw new Exception("scene root must be a Node2D to use this method");
return (scene.GetViewportTransform() * scene.GetGlobalTransform()).Xform(worldPos);
return (scene.GetViewportTransform() * scene.GetGlobalTransform()) * worldPos;
}


// There exists a mouse_button_to_mask in the C++ code, but it's not exposed.
private static MouseButtonMask MouseButtonToMask(MouseButton index) =>
(MouseButtonMask)(1 << ((int)index) - 1);

/// <summary>
/// sends an mouse down event into godot
/// </summary>
public static void InputMouseDown(Vector2 screenPosition, ButtonList index = ButtonList.Left)
public static void InputMouseDown(Vector2 screenPosition, MouseButton index = MouseButton.Left)
{
var inputEvent = new InputEventMouseButton();
inputEvent.GlobalPosition = screenPosition;
inputEvent.Position = screenPosition;
inputEvent.Pressed = true;
inputEvent.ButtonIndex = (int) index;
inputEvent.ButtonMask = (int) index;
inputEvent.ButtonIndex = index;
inputEvent.ButtonMask = MouseButtonToMask(index);
Input.ParseInputEvent(inputEvent);
}

/// <summary>
/// sends an mouse up event into godot
/// </summary>
public static void InputMouseUp(Vector2 screenPosition, ButtonList index = ButtonList.Left)
public static void InputMouseUp(Vector2 screenPosition, MouseButton index = MouseButton.Left)
{
var inputEvent = new InputEventMouseButton();
inputEvent.GlobalPosition = screenPosition;
inputEvent.Position = screenPosition;
inputEvent.Pressed = false;
inputEvent.ButtonIndex = (int) index;
inputEvent.ButtonMask = (int) index;
inputEvent.ButtonIndex = index;
inputEvent.ButtonMask = MouseButtonToMask(index);
Input.ParseInputEvent(inputEvent);
}

Expand Down Expand Up @@ -99,7 +103,7 @@ public static void InputMouseMove(Vector2 screenPosition)
/// <param name="screenPercentY">same as PositionByScreenPercent</param>
/// <param name="index">the button index</param>
/// <returns>the task that will resolve when the simulation is finished</returns>
public static async Task SimulateMouseClick(float screenPercentX, float screenPercentY, ButtonList index = ButtonList.Left)
public static async Task SimulateMouseClick(float screenPercentX, float screenPercentY, MouseButton index = MouseButton.Left)
{
var position = PositionByScreenPercent(screenPercentX, screenPercentY);
await SimulateMouseClick(position, index);
Expand All @@ -117,7 +121,7 @@ public static async Task SimulateMouseClick(float screenPercentX, float screenPe
/// <param name="screenPercentX">same as PositionByScreenPercent</param>
/// <param name="screenPercentY">same as PositionByScreenPercent</param>
/// <param name="index">the button index</param>
public static void SimulateMouseClickNoWait(float screenPercentX, float screenPercentY, ButtonList index = ButtonList.Left)
public static void SimulateMouseClickNoWait(float screenPercentX, float screenPercentY, MouseButton index = MouseButton.Left)
{
#pragma warning disable 4014
SimulateMouseClick(screenPercentX, screenPercentY, index);
Expand All @@ -138,7 +142,7 @@ public static void SimulateMouseClickNoWait(float screenPercentX, float screenPe
/// <param name="position">the position of where to click</param>
/// <param name="index">the button index</param>
/// <returns>the task that will resolve when the simulation is finished</returns>
public static async Task SimulateMouseClick(Vector2 position, ButtonList index = ButtonList.Left)
public static async Task SimulateMouseClick(Vector2 position, MouseButton index = MouseButton.Left)
{
await GDU.OnProcessAwaiter;
InputMouseMove(position);
Expand All @@ -150,7 +154,7 @@ public static async Task SimulateMouseClick(Vector2 position, ButtonList index =
await GDU.OnProcessAwaiter;
await GDU.OnProcessAwaiter;
}

/// <summary>
/// simulates a click with these steps:
/// - send a mouse moved event to the requested position
Expand All @@ -162,13 +166,13 @@ public static async Task SimulateMouseClick(Vector2 position, ButtonList index =
/// </summary>
/// <param name="position">the position of where to click</param>
/// <param name="index">the button index</param>
public static void SimulateMouseClickNoWait(Vector2 position, ButtonList index = ButtonList.Left)
public static void SimulateMouseClickNoWait(Vector2 position, MouseButton index = MouseButton.Left)
{
#pragma warning disable 4014
SimulateMouseClick(position, index);
#pragma warning restore 4014
}

/// <summary>
/// simulates a mouse drag with these steps:
/// - move mouse to start position
Expand All @@ -187,7 +191,7 @@ public static void SimulateMouseClickNoWait(Vector2 position, ButtonList index =
/// <returns>the task that will resolve when the simulation is finished</returns>
public static async Task SimulateMouseDrag(float startScreenPercentX, float startScreenPercentY,
float endScreenPercentX, float endScreenPercentY,
ButtonList index = ButtonList.Left)
MouseButton index = MouseButton.Left)
{
var start = PositionByScreenPercent(startScreenPercentX, startScreenPercentY);
var end = PositionByScreenPercent(endScreenPercentX, endScreenPercentY);
Expand All @@ -211,7 +215,7 @@ public static async Task SimulateMouseDrag(float startScreenPercentX, float star
/// <param name="index">the button index</param>
public static void SimulateMouseDragNoWait(float startScreenPercentX, float startScreenPercentY,
float endScreenPercentX, float endScreenPercentY,
ButtonList index = ButtonList.Left)
MouseButton index = MouseButton.Left)
{
#pragma warning disable 4014
SimulateMouseDrag(startScreenPercentX, startScreenPercentY, endScreenPercentX, endScreenPercentY, index);
Expand All @@ -232,7 +236,7 @@ public static void SimulateMouseDragNoWait(float startScreenPercentX, float star
/// <param name="end">the position of where the drag ends</param>
/// <param name="index">the button index</param>
/// <returns>the task that will resolve when the simulation is finished</returns>
public static async Task SimulateMouseDrag(Vector2 start, Vector2 end, ButtonList index = ButtonList.Left)
public static async Task SimulateMouseDrag(Vector2 start, Vector2 end, MouseButton index = MouseButton.Left)
{
await GDU.OnProcessAwaiter;
InputMouseMove(start);
Expand Down Expand Up @@ -260,7 +264,7 @@ public static async Task SimulateMouseDrag(Vector2 start, Vector2 end, ButtonLis
/// <param name="start">the position of where the drag starts</param>
/// <param name="end">the position of where the drag ends</param>
/// <param name="index">the button index</param>
public static void SimulateMouseDragNoWait(Vector2 start, Vector2 end, ButtonList index = ButtonList.Left)
public static void SimulateMouseDragNoWait(Vector2 start, Vector2 end, MouseButton index = MouseButton.Left)
{
#pragma warning disable 4014
SimulateMouseDrag(start, end, index);
Expand Down
44 changes: 26 additions & 18 deletions addons/GodotXUnit/GodotXUnitApi/GDU.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,19 @@ public static Node2D Instance
public static SignalAwaiter OnPhysicsProcessAwaiter =>
Instance.ToSignal(Instance, "OnPhysicsProcess");

public static SignalAwaiter OnIdleFrameAwaiter =>
Instance.ToSignal(Instance.GetTree(), "idle_frame");
public static SignalAwaiter OnProcessFrameAwaiter =>
Instance.ToSignal(Instance.GetTree(), SceneTree.SignalName.ProcessFrame);

public static SceneTree Tree => Instance.GetTree();

public static Viewport Viewport => Instance.GetViewport();

public static Vector2I ViewportSize => Instance.GetViewport() switch
{
Window window => window.ContentScaleSize,
SubViewport subViewport => subViewport.Size,
var vp => throw new Exception($"Unexpected viewport type {vp.GetType().Name}")
};


public static Node CurrentScene => Instance.GetTree().CurrentScene;

/// <summary>
Expand All @@ -67,19 +73,19 @@ public static async Task WaitForFrames(int count)
for (int i = 0; i < count; i++)
await OnProcessAwaiter;
}

/// <summary>
/// helper to wrap a SignalAwaiter to return the first element from a signal
/// result into the desired type.
/// </summary>
/// <param name="awaiter">the target signal to wrap</param>
/// <typeparam name="T">the type to cast to</typeparam>
/// <returns>the task that awaits and casts when resolved</returns>
public static async Task<T> AwaitType<T>(this SignalAwaiter awaiter)
public static async Task<T> AwaitType<[MustBeVariant] T>(this SignalAwaiter awaiter)
{
return (T) (await awaiter)[0];
return (await awaiter)[0].As<T>();
}

/// <summary>
/// creates a task for a godot signal with a timeout.
/// </summary>
Expand All @@ -89,15 +95,15 @@ public static async Task<T> AwaitType<T>(this SignalAwaiter awaiter)
/// <param name="throwOnTimeout">makes this task throw an exception on timeout. otherwise, just resolves</param>
/// <returns>the new task with the given timeout</returns>
/// <exception cref="TimeoutException">only throws if throwOnTimeout is true</exception>
public static async Task<object[]> ToSignalWithTimeout(
this Godot.Object source,
public static async Task<Variant[]> ToSignalWithTimeout(
this GodotObject source,
string signal,
int timeoutMillis,
bool throwOnTimeout = true)
{
return await source.ToSignal(source, signal).AwaitWithTimeout(timeoutMillis, throwOnTimeout);
}

/// <summary>
/// wraps the given SignalAwaiter in a task with a timeout.
/// </summary>
Expand All @@ -106,14 +112,14 @@ public static async Task<object[]> ToSignalWithTimeout(
/// <param name="throwOnTimeout">makes this task throw an exception on timeout. otherwise, just resolves</param>
/// <returns>the new task with the given timeout</returns>
/// <exception cref="TimeoutException">only throws if throwOnTimeout is true</exception>
public static Task<object[]> AwaitWithTimeout(
public static Task<Variant[]> AwaitWithTimeout(
this SignalAwaiter awaiter,
int timeoutMillis,
bool throwOnTimeout = true)
{
return Task.Run(async () => await awaiter).AwaitWithTimeout(timeoutMillis, throwOnTimeout);
}

/// <summary>
/// wraps a task with a task that will resolve after the wrapped task
/// or after the specified amount of time (either by exiting or by throwing
Expand All @@ -132,14 +138,15 @@ public static async Task AwaitWithTimeout(
var task = Task.Run(async () => await wrapping);
using var token = new CancellationTokenSource();
var completedTask = await Task.WhenAny(task, Task.Delay(timeoutMillis, token.Token));
if (completedTask == task) {
if (completedTask == task)
{
token.Cancel();
await task;
}
if (throwOnTimeout)
throw new TimeoutException($"signal {wrapping} timed out after {timeoutMillis}ms.");
}

/// <summary>
/// wraps a task with a task that will resolve after the wrapped task
/// or after the specified amount of time (either by exiting or by throwing
Expand All @@ -154,12 +161,13 @@ public static async Task AwaitWithTimeout(
public static async Task<T> AwaitWithTimeout<T>(
this Task<T> wrapping,
int timeoutMillis,
bool throwOnTimeout = true)
bool throwOnTimeout = true)
{
var task = Task.Run(async () => await wrapping);
using var token = new CancellationTokenSource();
var completedTask = await Task.WhenAny(task, Task.Delay(timeoutMillis, token.Token));
if (completedTask == task) {
if (completedTask == task)
{
token.Cancel();
return await task;
}
Expand All @@ -181,7 +189,7 @@ public static async Task RequestDrawing(int frames, Action<Node2D> drawer)
{
for (int i = 0; i < frames; i++)
{
((GodotXUnitRunnerBase) Instance).RequestDraw(drawer);
((GodotXUnitRunnerBase)Instance).RequestDraw(drawer);
await Instance.ToSignal(Instance, "OnDrawRequestDone");
}
}
Expand Down
2 changes: 1 addition & 1 deletion addons/GodotXUnit/GodotXUnitApi/GodotFactAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public void IsInPhysicsProcess()
*/
[XunitTestCaseDiscoverer("GodotXUnitApi.Internal.GodotFactDiscoverer", "GodotXUnitApi")]
// ReSharper disable once ClassWithVirtualMembersNeverInherited.Global
public class GodotFactAttribute : FactAttribute
public partial class GodotFactAttribute : FactAttribute
{
/// <summary>
/// loads the given scene before the test starts and loads an empty scene after
Expand Down
6 changes: 3 additions & 3 deletions addons/GodotXUnit/GodotXUnitApi/GodotXUnitApi.csproj
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<Project Sdk="Godot.NET.Sdk/3.3.0">
<Project Sdk="Godot.NET.Sdk/4.1.0-beta.2">
<PropertyGroup>
<Version>1.0.0</Version>
<authors>rexfleischer</authors>
<TargetFramework>net472</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<AssemblyName>GodotXUnitApi</AssemblyName>
<RootNamespace>GodotXUnitApi</RootNamespace>
<LangVersion>8</LangVersion>
<LangVersion>10</LangVersion>
<PackageId>GodotXUnitApi</PackageId>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
Expand Down
Loading