diff --git a/tests/unit/validation.gd b/tests/unit/validation.gd new file mode 100644 index 0000000..7a85c03 --- /dev/null +++ b/tests/unit/validation.gd @@ -0,0 +1,157 @@ +extends 'res://tests/unitbase.gd' + +func test_single_matches_type() -> void: + # Init CORE + load_framework() + + for data in [ "Test!", 666.69, Node.new() ]: + var single: CoreValidationSingle = core.validation.get_single(data, self) + + # Ignore that integer enum cast warning. + # Our code is not the issues, Godot's is. + # typeof() returns an int instead of Variant.Type, + # which produces a warning. It is valid though. + if !await single.matches_type([typeof(data)]).evaluate(): + rerror(type_string(typeof(data)) + " test failed: " + str(single.failures)) + + rok() + +func test_single_matches_class() -> void: + # Init CORE + load_framework() + + var single: CoreValidationSingle = null + + # exact=false test + for data in [ Node.new(), RichTextLabel.new(), NinePatchRect.new() ]: + single = core.validation.get_single(data, self) + + if !await single.matches_class(data.get_class(), false).evaluate(): + rerror(data.get_class() + " test failed: " + str(single.failures)) + + # exact=true test + single = core.validation.get_single(Button.new(), self) + if await single.matches_class("Control", true).evaluate(): + rerror("Exact Control test failed: " + str(single.failures)) + + rok() + +func test_in_range_correct() -> void: + await _in_range_processor({ 600: Vector2i(505, 666), 4.0: Vector2(PI, TAU) }, true) + +func test_in_range_incorrect() -> void: + await _in_range_processor({ -5: Vector2i(1, 5), 999999.0: Vector2(7827.551, 612844.11) }, false) + +func _in_range_processor(test_data: Dictionary, correct: bool) -> void: + # Define variables + var fail: bool = false + var type: String = "correct" if correct else "incorrect" + var single: CoreValidationSingle = null + var item: int = -1 + + # Init CORE + load_framework() + + for data in test_data: + item += 1 # Increase item count, useful for debugging + single = core.validation.get_single(data, self) + + # Add rule depending on type + match(typeof(data)): + Variant.Type.TYPE_INT: single.in_range_int(test_data[data].x, test_data[data].y) + Variant.Type.TYPE_FLOAT: single.in_range_float(test_data[data].x, test_data[data].y) + _: await lcrash("Invalid data type " + type_string(typeof(data)) + "for " + type + " in_range test for item " + str(item)) + + # Evaluate rules + var result: bool = await single.evaluate() + + # Check if rule got correctly evaluated + # 'result' | 'correct' | fail? + # TRUE | TRUE | FAIL + # FALSE | TRUE | PASS + # FALSE | FALSE | FAIL + # TRUE | FALSE | PASS + if (!result and correct) or (result and !correct): + rerror("in_range test (" + type + ") for item " + str(item) + " failed (result=" + str(result) + "): " + str(single.failures)) + fail = true # Mark test as failed, prevents test_status overwrites + elif !fail: rok() # Pass test if !fail + +func test_has_minimum_correct() -> void: + await _has_minimum_processor({ 5: 1, 5.21: 1.64 }, true) + +func test_has_minimum_incorrect() -> void: + await _has_minimum_processor({ 61: 69, 1.64: 5.21 }, false) + +func _has_minimum_processor(test_data: Dictionary, correct: bool) -> void: + # Define variables + var fail: bool = false + var type: String = "correct" if correct else "incorrect" + var single: CoreValidationSingle = null + var item: int = -1 + + # Init CORE + load_framework() + + for data in test_data: + item += 1 # Increase item count, useful for debugging + single = core.validation.get_single(data, self) + + # Add rule depending on type + match(typeof(data)): + Variant.Type.TYPE_INT: single.has_minimum_int(test_data[data]) + Variant.Type.TYPE_FLOAT: single.has_minimum_float(test_data[data]) + _: await lcrash("Invalid data type " + type_string(typeof(data)) + "for " + type + " has_minimum test for item " + str(item)) + + # Evaluate rules + var result: bool = await single.evaluate() + + # Check if rule got correctly evaluated + # 'result' | 'correct' | fail? + # TRUE | TRUE | FAIL + # FALSE | TRUE | PASS + # FALSE | FALSE | FAIL + # TRUE | FALSE | PASS + if (!result and correct) or (result and !correct): + rerror("has_minimum test (" + type + ") for item " + str(item) + " failed (result=" + str(result) + "): " + str(single.failures)) + fail = true # Mark test as failed, prevents test_status overwrites + elif !fail: rok() # Pass test if !fail + +func test_has_maximum_correct() -> void: + await _has_maximum_processor({ 61: 69, 1.64: 5.21 }, true) + +func test_has_maximum_incorrect() -> void: + await _has_maximum_processor({ 5: 1, 5.21: 1.64 }, false) + +func _has_maximum_processor(test_data: Dictionary, correct: bool) -> void: + # Define variables + var fail: bool = false + var type: String = "correct" if correct else "incorrect" + var single: CoreValidationSingle = null + var item: int = -1 + + # Init CORE + load_framework() + + for data in test_data: + item += 1 # Increase item count, useful for debugging + single = core.validation.get_single(data, self) + + # Add rule depending on type + match(typeof(data)): + Variant.Type.TYPE_INT: single.has_maximum_int(test_data[data]) + Variant.Type.TYPE_FLOAT: single.has_maximum_float(test_data[data]) + _: await lcrash("Invalid data type " + type_string(typeof(data)) + "for " + type + " has_maximum test for item " + str(item)) + + # Evaluate rules + var result: bool = await single.evaluate() + + # Check if rule got correctly evaluated + # 'result' | 'correct' | fail? + # TRUE | TRUE | FAIL + # FALSE | TRUE | PASS + # FALSE | FALSE | FAIL + # TRUE | FALSE | PASS + if (!result and correct) or (result and !correct): + rerror("has_maximum test (" + type + ") for item " + str(item) + " failed (result=" + str(result) + "): " + str(single.failures)) + fail = true # Mark test as failed, prevents test_status overwrites + elif !fail: rok() # Pass test if !fail