-
-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add integration tests from godot physics tests. Fix inertia issue aga…
- Loading branch information
Showing
132 changed files
with
7,101 additions
and
43 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
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,94 @@ | ||
extends Node | ||
|
||
enum TEST_MODE { | ||
REGRESSION, | ||
QUALITY, | ||
PERFORMANCE | ||
} | ||
|
||
# View | ||
var WINDOW_SIZE := Vector2(1152,648) | ||
var NUMBER_TEST_PER_ROW := 2 | ||
var MAXIMUM_PARALLEL_TESTS := NUMBER_TEST_PER_ROW * NUMBER_TEST_PER_ROW | ||
|
||
# Output | ||
var DEBUG := false | ||
var VERBOSE := true | ||
var NB_TESTS_COMPLETED := 0 | ||
var MONITOR_PASSED := 0 | ||
var MONITOR_FAILED := 0 | ||
var MONITOR_EXPECTED_TO_FAIL: Array[String] = [] | ||
var MONITOR_REGRESSION: Array[String] = [] | ||
var MONITOR_IMRPOVEMENT: Array[String] = [] | ||
var TEST_PASSED := 0 | ||
|
||
var RUN_2D_TEST := true | ||
var RUN_3D_TEST := false | ||
|
||
var engine_2d = "GodotPhysics2D" | ||
var engine_3d = "GodotPhysics3D" | ||
|
||
var PERFORMANCE_RESULT := {} | ||
|
||
func _process(_delta: float) -> void: | ||
if Input.is_action_just_pressed("ui_cancel"): | ||
exit() | ||
|
||
func _ready() -> void: | ||
get_tree().debug_collisions_hint = true | ||
|
||
var setting_2d_engine = ProjectSettings.get("physics/2d/physics_engine") | ||
if setting_2d_engine != "DEFAULT" and setting_2d_engine != "GodotPhysics2D": | ||
engine_2d = setting_2d_engine | ||
|
||
var setting_3d_engine = ProjectSettings.get("physics/3d/physics_engine") | ||
if setting_3d_engine != "DEFAULT" and setting_3d_engine != "GodotPhysics3D": | ||
engine_3d = setting_3d_engine | ||
|
||
func exit(p_code := 0) -> void: | ||
await get_tree().create_timer(1).timeout # sometimes the application quits before printing everything in the output | ||
get_tree().quit(p_code) | ||
|
||
func print_summary(duration: float) -> void: | ||
var status = "FAILED" if Global.MONITOR_REGRESSION.size() != 0 else "SUCCESS" | ||
var color = "red" if Global.MONITOR_REGRESSION.size() != 0 else "green" | ||
|
||
if Global.VERBOSE and Global.MONITOR_EXPECTED_TO_FAIL.size() != 0: | ||
print_rich("\n[indent]%d Monitor(s) expected to fail:[/indent]" % [Global.MONITOR_EXPECTED_TO_FAIL.size()]) | ||
var cpt := 0 | ||
for expected in Global.MONITOR_EXPECTED_TO_FAIL: | ||
cpt += 1 | ||
print_rich("[indent][indent]%d. %s[/indent][/indent]" % [cpt, expected]) | ||
|
||
if Global.MONITOR_REGRESSION.size() != 0: | ||
print_rich("\n[indent]%d Regression(s):[/indent]" % [Global.MONITOR_REGRESSION.size()]) | ||
var cpt := 0 | ||
for regression in Global.MONITOR_REGRESSION: | ||
cpt += 1 | ||
print_rich("[indent][indent][color=red]%d. %s[/color][/indent][/indent]" % [cpt, regression]) | ||
if Global.MONITOR_IMRPOVEMENT.size() != 0: | ||
print_rich("\n[indent]%d Improvement(s):[/indent]" % [Global.MONITOR_IMRPOVEMENT.size()]) | ||
var cpt := 0 | ||
for improvement in Global.MONITOR_IMRPOVEMENT: | ||
cpt += 1 | ||
print_rich("[indent][indent][color=green]%d. %s[/color][/indent][/indent]" % [cpt, improvement]) | ||
|
||
var extra = "" | ||
if Global.MONITOR_REGRESSION.size() != 0 or Global.MONITOR_IMRPOVEMENT.size() != 0: | ||
extra = " | " | ||
if Global.MONITOR_REGRESSION.size() != 0: | ||
extra += "☹ %d regression(s) " % Global.MONITOR_REGRESSION.size() | ||
if Global.MONITOR_IMRPOVEMENT.size() != 0: | ||
extra += "❤️ %d improvement(s)" % Global.MONITOR_IMRPOVEMENT.size() | ||
|
||
print_rich("\n[color=%s] > COMPLETED IN %.2fs | STATUS: %s (PASSED MONITORS: %d/%d)%s[/color]" % [color, duration, status, Global.MONITOR_PASSED, Global.MONITOR_PASSED + Global.MONITOR_FAILED, extra]) | ||
|
||
func print_engine() -> void: | ||
if Global.VERBOSE: | ||
var engine_txt := "" | ||
if Global.RUN_2D_TEST: | ||
engine_txt += " | 2D → %s" % [Global.engine_2d] | ||
if Global.RUN_3D_TEST: | ||
engine_txt += " | 3D → %s" % [Global.engine_3d] | ||
|
||
print_rich("[color=orange] > ENGINE:%s[/color]\n" % engine_txt) |
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,10 @@ | ||
extends Node | ||
|
||
func vec2_equals(v1: Vector2, v2: Vector2, tolerance := 0.00001) -> bool: | ||
return f_equals(v1.x, v2.x, tolerance) and f_equals(v1.y, v2.y, tolerance) | ||
|
||
func vec3_equals(v1: Vector3, v2: Vector3, tolerance := 0.00001) -> bool: | ||
return f_equals(v1.x, v2.x, tolerance) and f_equals(v1.y, v2.y, tolerance) and f_equals(v1.z, v2.z, tolerance) | ||
|
||
func f_equals(f1: float, f2: float, tolerance := 0.00001) -> bool: | ||
return abs(f1 - f2) <= tolerance |
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,88 @@ | ||
extends Node | ||
class_name Monitor | ||
signal completed | ||
|
||
var multi_test_list: Array[Dictionary] = [] | ||
var multi_test_current := 0 | ||
var monitor_duration := 0.0 | ||
var monitor_maximum_duration := 10.0 | ||
var error_message := "" | ||
var success := false | ||
var started := false | ||
var frame := 0 # physics frame | ||
var expected_to_fail := false | ||
var engine_expected_to_fail: Array[String] = [] | ||
|
||
var text: Dictionary: | ||
set(value): | ||
text = value | ||
|
||
func _init() -> void: | ||
process_mode = Node.PROCESS_MODE_DISABLED | ||
|
||
func test_start() -> void: | ||
process_mode = Node.PROCESS_MODE_INHERIT | ||
started = true | ||
|
||
func is_test_passed() -> bool: | ||
return success | ||
|
||
func is_expected_to_fail() -> bool: | ||
if engine_expected_to_fail.size() > 0: | ||
if Global.engine_2d in engine_expected_to_fail or Global.engine_3d in engine_expected_to_fail: | ||
return true | ||
return expected_to_fail | ||
|
||
func is_sub_test_expected_to_fail(p_test:Dictionary) -> bool: | ||
if p_test["engine_expected_to_fail"].size() > 0: | ||
if Global.engine_2d in p_test["engine_expected_to_fail"] or Global.engine_3d in p_test["engine_expected_to_fail"]: | ||
return true | ||
return p_test["expected_to_fail"] | ||
|
||
func _process(delta: float) -> void: | ||
# Maximum duration | ||
monitor_duration += delta | ||
if monitor_duration > monitor_maximum_duration: | ||
error_message = "The maximum duration has been exceeded (> %.1f s)" % [monitor_maximum_duration] | ||
monitor_completed() | ||
return | ||
|
||
func monitor_name() -> String: | ||
@warning_ignore("assert_always_false") | ||
assert(false, "ERROR: You must implement monitor_name()") | ||
return "" | ||
|
||
func monitor_completed() -> void: | ||
completed.emit() | ||
process_mode = PROCESS_MODE_DISABLED | ||
|
||
func failed(p_message = ""): | ||
error_message = p_message | ||
success = false | ||
monitor_completed() | ||
|
||
func passed(): | ||
success = true | ||
monitor_completed() | ||
|
||
func add_sub_test(p_name: String, p_expected_to_fail := false) -> void: | ||
multi_test_list.append({ | ||
"name": p_name, | ||
"result": false, | ||
"errors": [], | ||
"expected_to_fail": p_expected_to_fail, | ||
"engine_expected_to_fail": [] | ||
}) | ||
|
||
func add_test_expected_to_fail(): | ||
multi_test_list[multi_test_current].expected_to_fail = true | ||
|
||
func add_test_engine_expected_to_fail(p_engine: Array[String]): | ||
multi_test_list[multi_test_current].engine_expected_to_fail.append_array(p_engine) | ||
|
||
func add_test_error(p_error: String): | ||
multi_test_list[multi_test_current].errors.append(p_error) | ||
|
||
func add_test_result(p_result: bool): | ||
multi_test_list[multi_test_current].result = p_result | ||
multi_test_current += 1 |
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,110 @@ | ||
class_name PhysicsPerformanceTest2D | ||
extends PhysicsTest2D | ||
|
||
var NB_FRAME_SMOOTHING = 5 | ||
var WARMING_SKIPPED_FRAMES = 20 | ||
|
||
var _total_frame := 0 | ||
var _fps_label : Label | ||
|
||
var _current_fps := 60.0 | ||
var _prev_tick_ms := -1.0 | ||
|
||
var _max_fps := 0.0 | ||
var _min_fps := 9999.0 | ||
var _average_fps := 0.0 | ||
var _average_record := 0 | ||
var _smoothed_fps := 60.0 | ||
|
||
var _frame_cpt := 0 | ||
var _fps_buffer := 0.0 | ||
|
||
var extra_text := [] | ||
|
||
var _warming := true # wait few frame before start monitoring | ||
|
||
func _init() -> void: | ||
process_mode = PROCESS_MODE_DISABLED | ||
|
||
func _process(_delta: float) -> void: | ||
|
||
_frame_cpt += 1 | ||
_total_frame += 1 | ||
|
||
# Skip Frames | ||
if _warming and _frame_cpt == WARMING_SKIPPED_FRAMES: | ||
_warming = false | ||
|
||
if _warming: | ||
return | ||
|
||
# Start Computing FPS | ||
if _prev_tick_ms == -1.0: | ||
_prev_tick_ms = Time.get_ticks_usec() | ||
_frame_cpt = 0 | ||
return | ||
|
||
var new_tick: float = Time.get_ticks_usec() | ||
_current_fps = 1000000.0 / (new_tick - _prev_tick_ms) | ||
_prev_tick_ms = new_tick | ||
|
||
# Smooth FPS and compute average | ||
_fps_buffer += _current_fps | ||
|
||
if _frame_cpt == NB_FRAME_SMOOTHING: | ||
_smoothed_fps = _fps_buffer / _frame_cpt | ||
_frame_cpt = 0 | ||
_fps_buffer = 0.0 | ||
_average_record += 1 | ||
_average_fps += _smoothed_fps | ||
|
||
if _smoothed_fps > _max_fps: | ||
_max_fps = _smoothed_fps | ||
if _smoothed_fps < _min_fps: | ||
_min_fps = _smoothed_fps | ||
|
||
if _total_frame % 30 ==0 and _fps_label: | ||
_fps_label.text = "%d FPS" % [_smoothed_fps] | ||
|
||
func get_smoothed_fps(): | ||
return _smoothed_fps | ||
|
||
func get_fps(): | ||
return _current_fps | ||
|
||
func test_start() -> void: | ||
super() | ||
|
||
_fps_label = Label.new() | ||
_fps_label.position = Vector2(20,40) | ||
_fps_label.set("theme_override_font_sizes/font_size", 18) | ||
add_child(_fps_label) | ||
|
||
process_mode = Node.PROCESS_MODE_INHERIT | ||
|
||
func register_result(p_name: String, result: String): | ||
if not Global.PERFORMANCE_RESULT.has(get_name()): | ||
Global.PERFORMANCE_RESULT[get_name()] = [] | ||
Global.PERFORMANCE_RESULT[get_name()].append([p_name, _min_fps, _max_fps, _average_fps / _average_record, result]) | ||
|
||
func test_completed(delay := 0) -> void: | ||
super() | ||
if not extra_text.is_empty(): | ||
for s in extra_text: | ||
output += "[indent][indent][color=green]%s[/color][/indent][/indent]\n" % [s] | ||
if Global.PERFORMANCE_RESULT.has(get_name()): | ||
for result in Global.PERFORMANCE_RESULT[get_name()]: | ||
output += "[indent][indent][color=orange] → %s : [b]%s[/b][/color] - [color=purple][b]FPS[/b] | min: [b]%d[/b] max: [b]%d[/b] avg: [b]%d[/b][/color][/indent][/indent]\n" % [result[0], result[4], result[1], result[2], result[3]] | ||
else: | ||
output += "[indent][indent][color=orange] Simulation completed[/color][/indent][/indent]\n" | ||
print_rich(output) | ||
process_mode = PROCESS_MODE_DISABLED | ||
if delay != 0: | ||
await get_tree().create_timer(delay).timeout | ||
|
||
if has_method("clean"): | ||
call("clean") | ||
|
||
completed.emit() | ||
queue_free() | ||
|
Oops, something went wrong.