diff options
Diffstat (limited to 'addons/gdUnit4/src/fuzzers')
| -rw-r--r-- | addons/gdUnit4/src/fuzzers/BoolFuzzer.gd | 24 | ||||
| -rw-r--r-- | addons/gdUnit4/src/fuzzers/BoolFuzzer.gd.uid | 1 | ||||
| -rw-r--r-- | addons/gdUnit4/src/fuzzers/FloatFuzzer.gd | 37 | ||||
| -rw-r--r-- | addons/gdUnit4/src/fuzzers/FloatFuzzer.gd.uid | 1 | ||||
| -rw-r--r-- | addons/gdUnit4/src/fuzzers/Fuzzer.gd | 80 | ||||
| -rw-r--r-- | addons/gdUnit4/src/fuzzers/Fuzzer.gd.uid | 1 | ||||
| -rw-r--r-- | addons/gdUnit4/src/fuzzers/IntFuzzer.gd | 77 | ||||
| -rw-r--r-- | addons/gdUnit4/src/fuzzers/IntFuzzer.gd.uid | 1 | ||||
| -rw-r--r-- | addons/gdUnit4/src/fuzzers/StringFuzzer.gd | 112 | ||||
| -rw-r--r-- | addons/gdUnit4/src/fuzzers/StringFuzzer.gd.uid | 1 | ||||
| -rw-r--r-- | addons/gdUnit4/src/fuzzers/Vector2Fuzzer.gd | 45 | ||||
| -rw-r--r-- | addons/gdUnit4/src/fuzzers/Vector2Fuzzer.gd.uid | 1 | ||||
| -rw-r--r-- | addons/gdUnit4/src/fuzzers/Vector3Fuzzer.gd | 48 | ||||
| -rw-r--r-- | addons/gdUnit4/src/fuzzers/Vector3Fuzzer.gd.uid | 1 |
14 files changed, 430 insertions, 0 deletions
diff --git a/addons/gdUnit4/src/fuzzers/BoolFuzzer.gd b/addons/gdUnit4/src/fuzzers/BoolFuzzer.gd new file mode 100644 index 0000000..906ee2c --- /dev/null +++ b/addons/gdUnit4/src/fuzzers/BoolFuzzer.gd @@ -0,0 +1,24 @@ +## A fuzzer that generates random boolean values for testing.[br] +## +## This is useful for testing code paths that +## depend on boolean conditions, flags, or toggle states.[br] +## +## [b]Usage example:[/b] +## [codeblock] +## func test_toggle_feature(fuzzer := BoolFuzzer.new(), _fuzzer_iterations = 100): +## var enabled := fuzzer.next_value() +## my_feature.set_enabled(enabled) +## assert_bool(my_feature.is_enabled()),is_equal(enabled) +## [/codeblock] +class_name BoolFuzzer +extends Fuzzer + + +## Generates a random boolean value.[br] +## +## Returns either [code]true[/code] or [code]false[/code] with equal probability. +## This method is called automatically during fuzz testing iterations.[br] +## +## @returns A randomly generated boolean value ([code]true[/code] or [code]false[/code]). +func next_value() -> bool: + return randi() % 2 diff --git a/addons/gdUnit4/src/fuzzers/BoolFuzzer.gd.uid b/addons/gdUnit4/src/fuzzers/BoolFuzzer.gd.uid new file mode 100644 index 0000000..f2a9436 --- /dev/null +++ b/addons/gdUnit4/src/fuzzers/BoolFuzzer.gd.uid @@ -0,0 +1 @@ +uid://c0b4yc7wahhsc diff --git a/addons/gdUnit4/src/fuzzers/FloatFuzzer.gd b/addons/gdUnit4/src/fuzzers/FloatFuzzer.gd new file mode 100644 index 0000000..5da1a77 --- /dev/null +++ b/addons/gdUnit4/src/fuzzers/FloatFuzzer.gd @@ -0,0 +1,37 @@ +## A fuzzer that generates random floating-point values within a specified range.[br] +## +## This is particularly useful for testing numerical calculations, +## physics simulations, shader parameters, or any code that processes floating-point +## values.[br] +## +## [b]Usage example:[/b] +## [codeblock] +## func test_calculate_damage(fuzzer := FloatFuzzer.new(0.0, 100.0), _fuzzer_iterations := 500): +## var damage := fuzzer.next_value() +## var result = calculate_damage_reduction(damage) +## assert_float(result).is_between(0.0, damage) +## [/codeblock] +## [br] +## [b]Note:[/b] The range is inclusive on both ends, and values are uniformly distributed. +class_name FloatFuzzer +extends Fuzzer + +## Minimum value (inclusive) for generated floats. +var _from: float = 0 +## Maximum value (inclusive) for generated floats. +var _to: float = 0 + +func _init(from: float, to: float) -> void: + assert(from <= to, "Invalid range!") + _from = from + _to = to + + +## Generates a random float value within the configured range.[br] +## +## Returns a uniformly distributed random float between [member _from] and +## [member _to] (inclusive). Each call produces a new random value.[br] +## +## @returns A random float value within the specified range. +func next_value() -> float: + return randf_range(_from, _to) diff --git a/addons/gdUnit4/src/fuzzers/FloatFuzzer.gd.uid b/addons/gdUnit4/src/fuzzers/FloatFuzzer.gd.uid new file mode 100644 index 0000000..3c67b8a --- /dev/null +++ b/addons/gdUnit4/src/fuzzers/FloatFuzzer.gd.uid @@ -0,0 +1 @@ +uid://droy0thepcy diff --git a/addons/gdUnit4/src/fuzzers/Fuzzer.gd b/addons/gdUnit4/src/fuzzers/Fuzzer.gd new file mode 100644 index 0000000..e4e597d --- /dev/null +++ b/addons/gdUnit4/src/fuzzers/Fuzzer.gd @@ -0,0 +1,80 @@ +## Base interface for fuzz testing.[br] +## +## Fuzzer is an abstract base class that provides the foundation for creating +## custom fuzzers used in automated testing. Fuzz testing (fuzzing) is a software +## testing technique that involves providing invalid, unexpected, or random data +## as inputs to a program to find bugs and potential security vulnerabilities. +## [br][br] +## To use a fuzzer in your test cases, add optional parameters to your test function: +## [codeblock] +## func test_foo(fuzzer := Fuzzers.randomInt(), _fuzzer_iterations := 10, _fuzzer_seed := 12345): +## var value := fuzzer.next_value() +## # Test logic using the fuzzed value +## [/codeblock] +## [br] +## @tutorial(Fuzzing on Wikipedia): https://en.wikipedia.org/wiki/Fuzzing +@abstract +class_name Fuzzer +extends RefCounted + +## Default number of iterations for fuzz testing when not specified. +const ITERATION_DEFAULT_COUNT := 1000 +## Parameter name for passing the fuzzer instance to test functions. +const ARGUMENT_FUZZER_INSTANCE := "fuzzer" +## Parameter name for specifying the number of iterations in test functions. +const ARGUMENT_ITERATIONS := "fuzzer_iterations" +## Parameter name for specifying the random seed in test functions. +const ARGUMENT_SEED := "fuzzer_seed" + +## Current iteration index during fuzzing execution. +var _iteration_index := 0 +## Maximum number of iterations to run for this fuzzer. +var _iteration_limit := ITERATION_DEFAULT_COUNT + + +## Generates the next fuzz value.[br] +## +## This abstract method must be implemented by derived classes to provide +## the specific fuzzing logic for generating test values.[br] +## +## [b]Example implementation:[/b] +## [codeblock] +## func next_value() -> int: +## return randi_range(0, 100) +## [/codeblock] +## +## @returns The next generated fuzz value. The type depends on the specific fuzzer implementation. +@abstract +func next_value() -> Variant + + +## Returns the current iteration index.[br] +## +## Useful for tracking progress during fuzzing or for debugging purposes +## when a specific iteration causes a failure.[br] +## +## [b]Example:[/b] +## [codeblock] +## if fuzzer.iteration_index() % 100 == 0: +## print("Processed %d iterations" % fuzzer.iteration_index()) +## [/codeblock] +## +## @returns The current iteration index, starting from 0. +func iteration_index() -> int: + return _iteration_index + + +## Returns the maximum number of iterations for this fuzzer.[br] +## +## This value determines how many times the fuzzer will generate values +## during a test run. It can be overridden by the [code]fuzzer_iterations[/code] +## parameter in test functions.[br] +## +## [b]Example:[/b] +## [codeblock] +## print("Running %d fuzzing iterations" % fuzzer.iteration_limit()) +## [/codeblock] +## +## @returns The maximum number of iterations to be executed. +func iteration_limit() -> int: + return _iteration_limit diff --git a/addons/gdUnit4/src/fuzzers/Fuzzer.gd.uid b/addons/gdUnit4/src/fuzzers/Fuzzer.gd.uid new file mode 100644 index 0000000..ca5a34d --- /dev/null +++ b/addons/gdUnit4/src/fuzzers/Fuzzer.gd.uid @@ -0,0 +1 @@ +uid://dnqosea1sx5f4 diff --git a/addons/gdUnit4/src/fuzzers/IntFuzzer.gd b/addons/gdUnit4/src/fuzzers/IntFuzzer.gd new file mode 100644 index 0000000..4100d51 --- /dev/null +++ b/addons/gdUnit4/src/fuzzers/IntFuzzer.gd @@ -0,0 +1,77 @@ +## A fuzzer that generates random integer values with optional even/odd constraints.[br] +## +## It supports three modes: normal (any integer), even-only, +## and odd-only generation. This is useful for testing array indices, loop counters, +## enumeration values, or any code that processes integer values.[br] +## +## [b]Usage example:[/b] +## [codeblock] +## # Test with any integer in range +## func test_array_access(fuzzer = IntFuzzer.new(0, 99), fuzzer_iterations = 100): +## var index = fuzzer.next_value() +## var array = create_array(100) +## assert(array[index] != null) +## +## # Test with only even numbers +## func test_even_processing(fuzzer := IntFuzzer.new(0, 100, IntFuzzer.EVEN)): +## var even_num := fuzzer.next_value() +## assert_int(even_num % 2).is_equal(0) +## [/codeblock] +class_name IntFuzzer +extends Fuzzer + + +## Generates any integer within the range. +enum { + NORMAL, ## Generate any integer within the specified range. + EVEN, ## Generate only even integers within the specified range. + ODD ## Generate only odd integers within the specified range. +} + + +## Minimum value (inclusive) for generated integers. +var _from: int = 0 +## Maximum value (inclusive) for generated integers. +var _to: int = 0 +## Generation mode: NORMAL, EVEN, or ODD. +var _mode: int = NORMAL + + +func _init(from: int, to: int, mode: int = NORMAL) -> void: + assert(from <= to, "Invalid range!") + _from = from + _to = to + _mode = mode + + +## Generates a random integer value based on the configured mode.[br] +## +## Returns a random integer between [member _from] and [member _to] (inclusive).[br] +## The value will be constrained according to the [member _mode]:[br] +## - [constant NORMAL]: Any integer in the range[br] +## - [constant EVEN]: Only even integers[br] +## - [constant ODD]: Only odd integers[br] +## +## [b]Example:[/b] +## [codeblock] +## var normal_fuzzer = IntFuzzer.new(1, 10, IntFuzzer.NORMAL) +## var even_fuzzer = IntFuzzer.new(1, 10, IntFuzzer.EVEN) +## var odd_fuzzer = IntFuzzer.new(1, 10, IntFuzzer.ODD) +## +## print(normal_fuzzer.next_value()) # Could be any: 1, 2, 3, ..., 10 +## print(even_fuzzer.next_value()) # Only even: 2, 4, 6, 8, 10 +## print(odd_fuzzer.next_value()) # Only odd: 1, 3, 5, 7, 9 +## [/codeblock] +## +## @returns A random integer value within the specified range and mode +func next_value() -> int: + var value := randi_range(_from, _to) + match _mode: + NORMAL: + return value + EVEN: + return int((value / 2.0) * 2) + ODD: + return int((value / 2.0) * 2 + 1) + _: + return value diff --git a/addons/gdUnit4/src/fuzzers/IntFuzzer.gd.uid b/addons/gdUnit4/src/fuzzers/IntFuzzer.gd.uid new file mode 100644 index 0000000..e5f1d95 --- /dev/null +++ b/addons/gdUnit4/src/fuzzers/IntFuzzer.gd.uid @@ -0,0 +1 @@ +uid://bt16fv8esh0f8 diff --git a/addons/gdUnit4/src/fuzzers/StringFuzzer.gd b/addons/gdUnit4/src/fuzzers/StringFuzzer.gd new file mode 100644 index 0000000..277b4ac --- /dev/null +++ b/addons/gdUnit4/src/fuzzers/StringFuzzer.gd @@ -0,0 +1,112 @@ +## A fuzzer that generates random strings with configurable length and character sets.[br] +## +## It supports custom character sets defined by patterns or ranges, +## making it ideal for testing input validation, text processing, parsers, or any +## code that handles string data.[br] +## +## The fuzzer uses a pattern syntax to define allowed characters:[br] +## - Single characters: [code]abc[/code] allows 'a', 'b', 'c'[br] +## - Ranges: [code]a-z[/code] allows lowercase letters[br] +## - Special patterns: [code]\\w[/code] (word chars), [code]\\p{L}[/code] (letters), [code]\\p{N}[/code] (numbers)[br] +## +## [b]Usage example:[/b] +## [codeblock] +## # Test with alphanumeric strings +## func test_username(fuzzer := StringFuzzer.new(3, 20, "a-zA-Z0-9"), _fuzzer_iterations := 100): +## var username _= fuzzer.next_value() +## assert_bool(validate_username(username)).is_true() +## +## # Test with special characters +## func test_password(fuzzer := StringFuzzer.new(8, 32, "a-zA-Z0-9!@#$%"), _fuzzer_iterations := 100) -> void: +## var password := fuzzer.next_value() +## assert_str(password).has_length(8, Comparator.GREATER_EQUAL).has_length(32, Comparator.LESS_EQUAL) +## [/codeblock] +class_name StringFuzzer +extends Fuzzer + +## Default character set pattern including word characters, letters, numbers, and common symbols.[br] +## Includes: word characters (\\w), Unicode letters (\\p{L}), Unicode numbers (\\p{N}), +## and the characters: +, -, _, ' +const DEFAULT_CHARSET = "\\w\\p{L}\\p{N}+-_'" + +## Minimum length for generated strings (inclusive). +var _min_length: int +## Maximum length for generated strings (inclusive). +var _max_length: int +## Array of character codes that can be used in generated strings. +var _charset: PackedInt32Array + + +func _init(min_length: int, max_length: int, pattern: String = DEFAULT_CHARSET) -> void: + _min_length = min_length + _max_length = max_length + 1 # +1 for inclusive + assert(not null or not pattern.is_empty()) + assert(_min_length > 0 and _min_length < _max_length) + _charset = _extract_charset(pattern) + + +## Generates a random string based on configured parameters.[br] +## +## Creates a string with random length between [member _min_length] and +## [member _max_length], using only characters from the configured charset. +## Each character is selected randomly and independently.[br] +## +## [b]Example:[/b] +## [codeblock] +## var fuzzer = StringFuzzer.new(5, 10, "ABC") +## for i in range(5): +## var str = fuzzer.next_value() +## print("Generated: ", str) +## # Possible outputs: "ABCAB", "BCAABCA", "CCCBAA", etc. +## assert(str.length() >= 5 and str.length() <= 10) +## for c in str: +## assert(c in ["A", "B", "C"]) +## [/codeblock] +## +## @returns A random string matching the configured constraints. +func next_value() -> String: + var value := PackedInt32Array() + var max_char := len(_charset) + var length: int = max(_min_length, randi() % _max_length) + for i in length: + @warning_ignore("return_value_discarded") + value.append(_charset[randi() % max_char]) + return value.to_byte_array().get_string_from_utf32() + + +static func _extract_charset(pattern: String) -> PackedInt32Array: + var reg := RegEx.new() + if reg.compile(pattern) != OK: + push_error("Invalid pattern to generate Strings! Use e.g '\\w\\p{L}\\p{N}+-_'") + return PackedInt32Array() + + var charset := PackedInt32Array() + var char_before := -1 + var index := 0 + while index < pattern.length(): + var char_current := pattern.unicode_at(index) + # - range token at first or last pos? + if char_current == 45 and (index == 0 or index == pattern.length()-1): + charset.append(char_current) + index += 1 + continue + index += 1 + # range starts + if char_current == 45 and char_before != -1: + var char_next := pattern.unicode_at(index) + var characters := _build_chars(char_before, char_next) + for character in characters: + charset.append(character) + char_before = -1 + index += 1 + continue + char_before = char_current + charset.append(char_current) + return charset + + +static func _build_chars(from: int, to: int) -> PackedInt32Array: + var characters := PackedInt32Array() + for character in range(from+1, to+1): + characters.append(character) + return characters diff --git a/addons/gdUnit4/src/fuzzers/StringFuzzer.gd.uid b/addons/gdUnit4/src/fuzzers/StringFuzzer.gd.uid new file mode 100644 index 0000000..3fa5555 --- /dev/null +++ b/addons/gdUnit4/src/fuzzers/StringFuzzer.gd.uid @@ -0,0 +1 @@ +uid://b8l1qcoler3pb diff --git a/addons/gdUnit4/src/fuzzers/Vector2Fuzzer.gd b/addons/gdUnit4/src/fuzzers/Vector2Fuzzer.gd new file mode 100644 index 0000000..70ef31b --- /dev/null +++ b/addons/gdUnit4/src/fuzzers/Vector2Fuzzer.gd @@ -0,0 +1,45 @@ +## A fuzzer that generates random Vector2 values within a specified rectangular range.[br] +## +## This is particularly useful for testing 2D physics, movement +## systems, UI positioning, sprite coordinates, or any code that processes 2D vectors.[br] +## +## The fuzzer generates vectors where each component (x, y) is independently randomized +## within its respective range, creating a uniform distribution over the rectangular area.[br] +## +## [b]Usage example:[/b] +## [codeblock] +## # Test 2D movement within screen bounds +## func test_movement(fuzzer := Vector2Fuzzer.new(Vector2.ZERO, Vector2(1920, 1080)), _fuzzer_iterations := 200) -> void: +## var position := fuzzer.next_value() +## player.set_position(position) +## +## [/codeblock] +class_name Vector2Fuzzer +extends Fuzzer + + +## Minimum bounds for the generated vectors (inclusive for both x and y). +var _from: Vector2 +## Maximum bounds for the generated vectors (inclusive for both x and y). +var _to: Vector2 + + +func _init(from: Vector2, to: Vector2) -> void: + assert(from <= to, "Invalid range!") + _from = from + _to = to + + +## Generates a random Vector2 within the configured rectangular range.[br] +## +## Returns a Vector2 where each component is independently randomized:[br] +## - x: random float between [code]_from.x[/code] and [code]_to.x[/code][br] +## - y: random float between [code]_from.y[/code] and [code]_to.y[/code][br] +## +## The distribution is uniform over the rectangular area defined by the bounds.[br] +## +## @returns A random Vector2 within the specified range. +func next_value() -> Vector2: + var x := randf_range(_from.x, _to.x) + var y := randf_range(_from.y, _to.y) + return Vector2(x, y) diff --git a/addons/gdUnit4/src/fuzzers/Vector2Fuzzer.gd.uid b/addons/gdUnit4/src/fuzzers/Vector2Fuzzer.gd.uid new file mode 100644 index 0000000..c68746c --- /dev/null +++ b/addons/gdUnit4/src/fuzzers/Vector2Fuzzer.gd.uid @@ -0,0 +1 @@ +uid://dvpctakk4c5u0 diff --git a/addons/gdUnit4/src/fuzzers/Vector3Fuzzer.gd b/addons/gdUnit4/src/fuzzers/Vector3Fuzzer.gd new file mode 100644 index 0000000..b54870d --- /dev/null +++ b/addons/gdUnit4/src/fuzzers/Vector3Fuzzer.gd @@ -0,0 +1,48 @@ +## A fuzzer that generates random Vector3 values within a specified box range.[br] +## +## This is particularly useful for testing 3D physics, spatial +## positioning, camera systems, particle effects, or any code that processes 3D vectors.[br] +## +## The fuzzer generates vectors where each component (x, y, z) is independently +## randomized within its respective range, creating a uniform distribution over the +## 3D box volume.[br] +## +## [b]Usage example:[/b] +## [codeblock] +## # Test 3D object placement within world bounds +## func test_spawn_position(fuzzer := Vector3Fuzzer.new(Vector3(-100, 0, -100), Vector3(100, 50, 100)), _fuzzer_iterations := 300): +## var position := fuzzer.next_value() +## var object = spawn_object(position) +## +## [/codeblock] +class_name Vector3Fuzzer +extends Fuzzer + + +## Minimum bounds for the generated vectors (inclusive for x, y, and z). +var _from: Vector3 +## Maximum bounds for the generated vectors (inclusive for x, y, and z). +var _to: Vector3 + + +func _init(from: Vector3, to: Vector3) -> void: + assert(from <= to, "Invalid range!") + _from = from + _to = to + + +## Generates a random Vector3 within the configured box range.[br] +## +## Returns a Vector3 where each component is independently randomized:[br] +## - x: random float between [code]_from.x[/code] and [code]_to.x[/code][br] +## - y: random float between [code]_from.y[/code] and [code]_to.y[/code][br] +## - z: random float between [code]_from.z[/code] and [code]_to.z[/code][br] +## +## The distribution is uniform over the 3D box volume defined by the bounds.[br] +## +## @returns A random Vector3 within the specified range. +func next_value() -> Vector3: + var x := randf_range(_from.x, _to.x) + var y := randf_range(_from.y, _to.y) + var z := randf_range(_from.z, _to.z) + return Vector3(x, y, z) diff --git a/addons/gdUnit4/src/fuzzers/Vector3Fuzzer.gd.uid b/addons/gdUnit4/src/fuzzers/Vector3Fuzzer.gd.uid new file mode 100644 index 0000000..cba3a8f --- /dev/null +++ b/addons/gdUnit4/src/fuzzers/Vector3Fuzzer.gd.uid @@ -0,0 +1 @@ +uid://cde6yudknpbgf |
