diff --git a/src/Tests/pytest.ini b/src/Tests/pytest.ini new file mode 100644 index 0000000..3b665da --- /dev/null +++ b/src/Tests/pytest.ini @@ -0,0 +1,7 @@ +[pytest] +pythonpath = . .. src +testpaths = tests +addopts = -v --tb=short +python_files = test_*.py +python_classes = Test* +python_functions = test_* \ No newline at end of file diff --git a/src/Tests/requirements.txt b/src/Tests/requirements.txt new file mode 100644 index 0000000..55b033e --- /dev/null +++ b/src/Tests/requirements.txt @@ -0,0 +1 @@ +pytest \ No newline at end of file diff --git a/src/Tests/src/bubble_sort.py b/src/Tests/src/bubble_sort.py new file mode 100644 index 0000000..cfe73dc --- /dev/null +++ b/src/Tests/src/bubble_sort.py @@ -0,0 +1,7 @@ +def bubble_sort(array: list) -> list: + for index_1 in range(len(array)): + for index_2 in range(index_1 + 1, len(array)): + if array[index_1] > array[index_2]: + array[index_1], array[index_2] = array[index_2], array[index_1] + + return array diff --git a/src/Tests/src/heap_sort.py b/src/Tests/src/heap_sort.py new file mode 100644 index 0000000..054adde --- /dev/null +++ b/src/Tests/src/heap_sort.py @@ -0,0 +1,27 @@ +def heap_sort(array: list) -> list: + length = len(array) + + for index in range(length // 2 - 1, -1, -1): + heapify(array, length, index) + + for index in range(length - 1, 0, -1): + array[0], array[index] = array[index], array[0] + heapify(array, index, 0) + + return array + + +def heapify(array: list, length: int, index: int) -> None: + largest = index + left = 2 * index + 1 + right = 2 * index + 2 + + if left < length and array[left] > array[largest]: + largest = left + + if right < length and array[right] > array[largest]: + largest = right + + if largest != index: + array[index], array[largest] = array[largest], array[index] + heapify(array, length, largest) diff --git a/src/Tests/src/quick_sort.py b/src/Tests/src/quick_sort.py new file mode 100644 index 0000000..642c98f --- /dev/null +++ b/src/Tests/src/quick_sort.py @@ -0,0 +1,10 @@ +def quick_sort(array: list) -> list: + if len(array) <= 1: + return array + + pivot = array[len(array) // 2] + left = [x for x in array if x < pivot] + middle = [x for x in array if x == pivot] + right = [x for x in array if x > pivot] + + return quick_sort(left) + middle + quick_sort(right) diff --git a/src/Tests/src/selection_sort.py b/src/Tests/src/selection_sort.py new file mode 100644 index 0000000..7fda3ef --- /dev/null +++ b/src/Tests/src/selection_sort.py @@ -0,0 +1,10 @@ +def selection_sort(array: list) -> list: + for index_1 in range(len(array)): + min_idx = index_1 + for index_2 in range(index_1 + 1, len(array)): + if array[index_2] < array[min_idx]: + min_idx = index_2 + + array[index_1], array[min_idx] = array[min_idx], array[index_1] + + return array diff --git a/src/Tests/tests/__init__.py b/src/Tests/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/Tests/tests/test_heapsort.py b/src/Tests/tests/test_heapsort.py new file mode 100644 index 0000000..f17efba --- /dev/null +++ b/src/Tests/tests/test_heapsort.py @@ -0,0 +1,31 @@ +from Tests.src.heap_sort import heap_sort + + +def test_sort_empty_list() -> None: + assert heap_sort([]) == [] + + +def test_sort_single_element() -> None: + assert heap_sort([5]) == [5] + assert heap_sort([-1]) == [-1] + assert heap_sort([0]) == [0] + + +def test_sort_positive_numbers() -> None: + assert heap_sort([3, 1, 4, 1, 5]) == [1, 1, 3, 4, 5] + assert heap_sort([5, 4, 3, 2, 1]) == [1, 2, 3, 4, 5] + + +def test_sort_negative_numbers() -> None: + assert heap_sort([-3, -1, -4, -1, -5]) == [-5, -4, -3, -1, -1] + assert heap_sort([-1, -2, -3, -4, -5]) == [-5, -4, -3, -2, -1] + + +def test_sort_mixed_numbers() -> None: + assert heap_sort([3, -1, 0, -2, 5]) == [-2, -1, 0, 3, 5] + assert heap_sort([0, -1, 1, -2, 2]) == [-2, -1, 0, 1, 2] + + +def test_sort_strings() -> None: + assert heap_sort(["banana", "apple", "cherry"]) == ["apple", "banana", "cherry"] + assert heap_sort(["z", "a", "m"]) == ["a", "m", "z"] diff --git a/src/Tests/tests/test_property_based.py b/src/Tests/tests/test_property_based.py new file mode 100644 index 0000000..78d09d6 --- /dev/null +++ b/src/Tests/tests/test_property_based.py @@ -0,0 +1,73 @@ +import pytest +import random +from collections import Counter + +from src.heap_sort import heap_sort +from src.quick_sort import quick_sort +from src.bubble_sort import bubble_sort +from src.selection_sort import selection_sort + +SORTING_FUNCTIONS = [heap_sort, quick_sort, bubble_sort, selection_sort] + + +@pytest.fixture +def unsorted_lists() -> list[list]: + sizes = [5, 10, 15, 20, 30, 50] + lists = [] + for size in sizes: + array = [] + for _ in range(size): + array.append(random.randint(-100, 100)) + lists.append(array) + + return lists + + +@pytest.mark.parametrize("sorting_function", SORTING_FUNCTIONS) +def test_orderliness(sorting_function, unsorted_lists) -> None: + for unsorted_list in unsorted_lists: + sorted_array = sorting_function(unsorted_list) + for index in range(1, len(sorted_array)): + assert sorted_array[index] >= sorted_array[index - 1] + + +@pytest.mark.parametrize("sorting_function", SORTING_FUNCTIONS) +def test_elements_sameness(sorting_function, unsorted_lists) -> None: + for unsorted_list in unsorted_lists: + sorted_list = sorting_function(unsorted_list) + assert Counter(sorted_list) == Counter(unsorted_list) + + +@pytest.mark.parametrize("sorting_function", SORTING_FUNCTIONS) +def test_idempotency(sorting_function, unsorted_lists): + for unsorted_list in unsorted_lists: + first_sort = sorting_function(unsorted_list.copy()) + second_sort = sorting_function(first_sort.copy()) + + assert first_sort == second_sort + + +@pytest.fixture( + params=[ + [], + [1], + [1, 1, 1], + [1, 2, 3, 4, 5], + [5, 4, 3, 2, 1], + [1, 3, 2, 3, 1], + [-1, -5, 2, -3, 0], + [100, -100, 0, 50, -50], + [1] * 100, + list(range(100, 0, -1)), + ] +) +def edge_case_list(request): + return request.param + + +@pytest.mark.parametrize("sorting_function", SORTING_FUNCTIONS) +def test_edge_cases(sorting_function, edge_case_list): + original = edge_case_list.copy() + sorted_list = sorting_function(edge_case_list) + + assert sorted_list == sorted(original)