-
-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
GD-129: Enable CSharp test support - Initial Commit (#210)
* GD-129: Enable CSharp test support - Initial Commit - Decoupling TestSuite and TestCase class from Godot class and mark it as internal - introduce the new await functions - addapt test coverage - simplify/cleanup GdUnitRumner - Fixed a number of timer issues that were causing print errors. - Rework on test interruption handling and added a new awaiter class to prevent unreleased timers - bump to version 2.0.0-beta
- Loading branch information
1 parent
39a596d
commit ad8c17b
Showing
142 changed files
with
8,514 additions
and
600 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
name: CI GdUnit3 on Godot Mono 3.3.x | ||
on: [push] | ||
|
||
jobs: | ||
testing: | ||
strategy: | ||
matrix: | ||
godot: [mono-3.3.3, mono-3.3.4, mono-3.4.1, mono-3.4.2] | ||
|
||
name: GdUnit3 Selftest on Godot ${{ matrix.godot }} | ||
runs-on: ubuntu-latest | ||
container: | ||
image: barichello/godot-ci:${{ matrix.godot }} | ||
|
||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v2 | ||
with: | ||
lfs: true | ||
|
||
- name: Compile | ||
run: | | ||
nuget restore | ||
mkdir -p .mono/assemblies/Debug | ||
cp /usr/local/bin/GodotSharp/Api/Release/* .mono/assemblies/Debug | ||
msbuild | ||
- name: Run Selftes | ||
timeout-minutes: 7 | ||
env: | ||
GODOT_BIN: "/usr/local/bin/godot" | ||
shell: bash | ||
run: ./runtest.sh --selftest | ||
|
||
- name: Collect Test Reports | ||
uses: actions/upload-artifact@v2 | ||
with: | ||
name: Report_${{ matrix.godot }} | ||
path: reports/** |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,3 +23,6 @@ gdUnit3-examples/ | |
# temporary generated files | ||
GdUnitRunner.cfg | ||
reports/ | ||
|
||
.fake | ||
.ionide |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
using System; | ||
using System.Collections; | ||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
|
||
namespace GdUnit3 | ||
{ | ||
using Asserts; | ||
|
||
/// <summary> | ||
/// A collection of assertions and helpers to verify values | ||
/// </summary> | ||
public sealed class Assertions | ||
{ | ||
/// <summary> | ||
/// An Assertion to verify boolean values | ||
/// </summary> | ||
/// <param name="current">The current boolean value to verify</param> | ||
/// <returns>IBoolAssert</returns> | ||
public static IBoolAssert AssertBool(bool current) => new BoolAssert(current); | ||
|
||
/// <summary> | ||
/// An Assertion to verify string values | ||
/// </summary> | ||
/// <param name="current">The current string value to verify</param> | ||
/// <param name="expectResult"></param> | ||
/// <returns></returns> | ||
public static IStringAssert AssertString(string current) => new StringAssert(current); | ||
|
||
/// <summary> | ||
/// An Assertion to verify integer values | ||
/// </summary> | ||
/// <param name="current">The current integer value to verify</param> | ||
/// <param name="expectResult"></param> | ||
/// <returns></returns> | ||
public static IIntAssert AssertInt(int current) => new IntAssert(current); | ||
|
||
/// <summary> | ||
/// An Assertion to verify double values | ||
/// </summary> | ||
/// <param name="current">The current double value to verify</param> | ||
/// <param name="expectResult"></param> | ||
/// <returns></returns> | ||
public static IDoubleAssert AssertFloat(double current) => new DoubleAssert(current); | ||
|
||
/// <summary> | ||
/// An Assertion to verify object values | ||
/// </summary> | ||
/// <param name="current">The current double value to verify</param> | ||
/// <param name="expectResult"></param> | ||
/// <returns></returns> | ||
public static IObjectAssert AssertObject(object current) => new ObjectAssert(current); | ||
|
||
/// <summary> | ||
/// An Assertion to verify array values | ||
/// </summary> | ||
/// <param name="current">The current array value to verify</param> | ||
/// <param name="expectResult"></param> | ||
/// <returns></returns> | ||
public static IArrayAssert AssertArray(IEnumerable current) => new ArrayAssert(current); | ||
|
||
|
||
public static IAssertBase<T> AssertThat<T>(T current) | ||
{ | ||
if (typeof(string) == typeof(T)) | ||
return (IAssertBase<T>)AssertString(Convert.ToString(current)); | ||
if (typeof(bool) == typeof(T)) | ||
return (IAssertBase<T>)AssertBool(Convert.ToBoolean(current)); | ||
if (typeof(int) == typeof(T)) | ||
return (IAssertBase<T>)AssertInt(Convert.ToInt32(current)); | ||
if (typeof(double) == typeof(T)) | ||
return (IAssertBase<T>)AssertFloat(Convert.ToDouble(current)); | ||
if (typeof(IEnumerable) == typeof(T)) | ||
return (IAssertBase<T>)AssertArray(current as IEnumerable); | ||
return (IAssertBase<T>)AssertObject(current as object); | ||
} | ||
|
||
public static IStringAssert AssertThat(string current) => AssertString(current); | ||
public static IBoolAssert AssertThat(bool current) => AssertBool(current); | ||
public static IIntAssert AssertThat(int current) => AssertInt(current); | ||
public static IDoubleAssert AssertThat(double current) => AssertFloat(current); | ||
public static IObjectAssert AssertThat(object current) => AssertObject(current); | ||
public static IArrayAssert AssertThat(IEnumerable current) => AssertArray(current); | ||
|
||
|
||
/// <summary> | ||
/// An Assertion to verify for expecting exceptions | ||
/// </summary> | ||
/// <param name="supplier">A function callback where throw possible exceptions</param> | ||
/// <returns>IExceptionAssert</returns> | ||
public static IExceptionAssert AssertThrown<T>(Func<T> supplier) => new ExceptionAssert<T>(supplier); | ||
|
||
/// <summary> | ||
/// An Assertion to verify for expecting exceptions when performing a task. | ||
/// <example> | ||
/// <code> | ||
/// await AssertThrown(task.WithTimeout(500)) | ||
/// .ContinueWith(result => result.Result.HasMessage("timed out after 500ms.")); | ||
/// </code> | ||
/// </example> | ||
/// </summary> | ||
/// <param name="task">A task where throw possible exceptions</param> | ||
/// <returns>a task of <c>IExceptionAssert</c> to await</returns> | ||
public async static Task<IExceptionAssert> AssertThrown<T>(Task<T> task) | ||
{ | ||
try | ||
{ | ||
await task; | ||
return default; | ||
} | ||
catch (Exception e) | ||
{ | ||
return new ExceptionAssert<T>(e); | ||
} | ||
} | ||
|
||
public async static Task<IExceptionAssert> AssertThrown(Task task) | ||
{ | ||
try | ||
{ | ||
await task; | ||
return default; | ||
} | ||
catch (Exception e) | ||
{ | ||
return new ExceptionAssert<object>(e); | ||
} | ||
} | ||
|
||
/// ----------- Helpers ------------------------------------------------------------------------------------------------------- | ||
|
||
///<summary> | ||
/// A litle helper to auto freeing your created objects after test execution | ||
/// </summary> | ||
public static T AutoFree<T>(T obj) => Executions.Monitors.MemoryPool.RegisterForAutoFree(obj); | ||
|
||
/// <summary> | ||
/// Buils a tuple by given values | ||
/// </summary> | ||
public static ITuple Tuple(params object[] args) => new GdUnit3.Asserts.Tuple(args); | ||
|
||
/// <summary> | ||
/// Builds an extractor by given method name and optional arguments | ||
/// </summary> | ||
public static IValueExtractor Extr(string methodName, params object[] args) => new ValueExtractor(methodName, args); | ||
|
||
/// <summary> | ||
/// A helper to return given enumerable as string representation | ||
/// </summary> | ||
public static string AaString(IEnumerable values) | ||
{ | ||
var items = new List<string>(); | ||
foreach (var value in values) | ||
{ | ||
items.Add(value != null ? value.ToString() : "Null"); | ||
} | ||
return string.Join(", ", items); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
class_name GdUnitAwaiter | ||
extends Reference | ||
|
||
|
||
# Waits for a specified signal in an interval of 50ms sent from the <source>, and terminates with an error after the specified timeout has elapsed. | ||
# source: the object from which the signal is emitted | ||
# signal_name: signal name | ||
# args: the expected signal arguments as an array | ||
# timeout: the timeout in ms, default is set to 2000ms | ||
static func await_signal_on(test_suite :WeakRef, source :Object, signal_name :String, args :Array = [], timeout_millis :int = 2000) -> GDScriptFunctionState: | ||
var line_number := GdUnitAssertImpl._get_line_number(); | ||
var awaiter = GdUnitSignalAwaiter.new(timeout_millis) | ||
yield(awaiter.on_signal(source, signal_name, args), "completed") | ||
if awaiter.is_interrupted(): | ||
var failure = "await_signal_on(%s, %s) timed out after %sms" % [signal_name, args, timeout_millis] | ||
GdUnitAssertImpl.new(test_suite.get_ref(), signal_name).report_error(failure, line_number) | ||
return | ||
|
||
# Waits for a specified signal sent from the <source> between idle frames and aborts with an error after the specified timeout has elapsed | ||
# source: the object from which the signal is emitted | ||
# signal_name: signal name | ||
# args: the expected signal arguments as an array | ||
# timeout: the timeout in ms, default is set to 2000ms | ||
static func await_signal_idle_frames(test_suite :WeakRef, source :Object, signal_name :String, args :Array = [], timeout_millis :int = 2000) -> GDScriptFunctionState: | ||
var line_number := GdUnitAssertImpl._get_line_number(); | ||
var awaiter = GdUnitSignalAwaiter.new(timeout_millis, true) | ||
yield(awaiter.on_signal(source, signal_name, args), "completed") | ||
if awaiter.is_interrupted(): | ||
var failure = "await_signal_idle_frames(%s, %s) timed out after %sms" % [signal_name, args, timeout_millis] | ||
GdUnitAssertImpl.new(test_suite.get_ref(), signal_name).report_error(failure, line_number) | ||
return | ||
|
||
# Waits for for a given amount of milliseconds | ||
# example: | ||
# # waits for 100ms | ||
# yield(GdUnitAwaiter.await_millis(myNode, 100), "completed") | ||
# use this waiter and not `yield(get_tree().create_timer(), "timeout") to prevent errors when a test case is timed out | ||
static func await_millis(parent: Node, milliSec :int) -> GDScriptFunctionState: | ||
var timer :Timer = parent.auto_free(Timer.new()) | ||
parent.add_child(timer) | ||
timer.set_one_shot(true) | ||
timer.start(milliSec * 0.001) | ||
return yield(timer, "timeout") | ||
|
||
# Waits until the next idle frame | ||
static func await_idle_frame() -> GDScriptFunctionState: | ||
return yield(Engine.get_main_loop(), "idle_frame") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
class_name GdUnitConstants | ||
extends Reference | ||
|
||
const NO_ARG = "<--null-->" |
Oops, something went wrong.