% =============================================== % ТЕСТЫ ДЛЯ LAB9 TASK1 % Автоматические тесты всех предикатов % =============================================== % Запуск всех тестов run_tests :- write('=== ЗАПУСК АВТОМАТИЧЕСКИХ ТЕСТОВ ==='), nl, test_max, test_factorial, test_digit_sum, test_square_free, test_list_operations, test_remove_by_digit_sum, write('=== ВСЕ ТЕСТЫ ЗАВЕРШЕНЫ ==='), nl. % =============================================== % ТЕСТЫ ДЛЯ MAX/4 % =============================================== test_max :- write('--- Тестирование max/4 ---'), nl, % Тест 1: обычные числа (max(5, 3, 7, 7) -> write('✓ max(5,3,7,7) - ПРОЙДЕН') ; write('✗ max(5,3,7,7) - ПРОВАЛЕН')), nl, % Тест 2: отрицательные числа (max(-5, -3, -7, -3) -> write('✓ max(-5,-3,-7,-3) - ПРОЙДЕН') ; write('✗ max(-5,-3,-7,-3) - ПРОВАЛЕН')), nl, % Тест 3: одинаковые числа (max(5, 5, 5, 5) -> write('✓ max(5,5,5,5) - ПРОЙДЕН') ; write('✗ max(5,5,5,5) - ПРОВАЛЕН')), nl, % Тест 4: генерация максимума max(10, 20, 15, Z), (Z =:= 20 -> write('✓ max(10,20,15,Z) где Z=20 - ПРОЙДЕН') ; write('✗ max(10,20,15,Z) - ПРОВАЛЕН')), nl, nl. % =============================================== % ТЕСТЫ ДЛЯ ФАКТОРИАЛОВ % =============================================== test_factorial :- write('--- Тестирование факториалов ---'), nl, % Тест базового случая (fact_up(0, 1) -> write('✓ fact_up(0,1) - ПРОЙДЕН') ; write('✗ fact_up(0,1) - ПРОВАЛЕН')), nl, (fact_down(0, 1) -> write('✓ fact_down(0,1) - ПРОЙДЕН') ; write('✗ fact_down(0,1) - ПРОВАЛЕН')), nl, % Тест небольших значений TestValues = [1, 3, 5, 6], forall(member(N, TestValues), test_factorial_value(N)), % Тест эквивалентности рекурсий test_factorial_equivalence([0, 1, 2, 3, 4, 5, 6, 7]), nl. test_factorial_value(N) :- fact_up(N, F1), fact_down(N, F2), write('fact_up('), write(N), write(') = '), write(F1), write(', fact_down('), write(N), write(') = '), write(F2), (F1 =:= F2 -> write(' ✓') ; write(' ✗')), nl. test_factorial_equivalence([]). test_factorial_equivalence([N|Rest]) :- fact_up(N, F1), fact_down(N, F2), (F1 =:= F2 -> write('✓ Факториалы '), write(N), write(' эквивалентны') ; write('✗ Факториалы '), write(N), write(' НЕ эквивалентны')), nl, test_factorial_equivalence(Rest). % =============================================== % ТЕСТЫ ДЛЯ СУММЫ ЦИФР % =============================================== test_digit_sum :- write('--- Тестирование суммы цифр ---'), nl, % Тест базового случая (digit_sum_up(0, 0) -> write('✓ digit_sum_up(0,0) - ПРОЙДЕН') ; write('✗ digit_sum_up(0,0) - ПРОВАЛЕН')), nl, (digit_sum_down(0, 0) -> write('✓ digit_sum_down(0,0) - ПРОЙДЕН') ; write('✗ digit_sum_down(0,0) - ПРОВАЛЕН')), nl, % Тест известных значений TestCases = [(123, 6), (456, 15), (999, 27), (1000, 1), (12345, 15)], forall(member((N, ExpectedSum), TestCases), test_digit_sum_value(N, ExpectedSum)), % Тест эквивалентности рекурсий test_digit_sum_equivalence([0, 1, 12, 123, 1234, 12345, 999, 1000]), nl. test_digit_sum_value(N, ExpectedSum) :- digit_sum_up(N, S1), digit_sum_down(N, S2), write('digit_sum для '), write(N), write(': up='), write(S1), write(', down='), write(S2), write(', ожидалось='), write(ExpectedSum), ((S1 =:= ExpectedSum, S2 =:= ExpectedSum) -> write(' ✓') ; write(' ✗')), nl. test_digit_sum_equivalence([]). test_digit_sum_equivalence([N|Rest]) :- digit_sum_up(N, S1), digit_sum_down(N, S2), (S1 =:= S2 -> write('✓ Суммы цифр '), write(N), write(' эквивалентны') ; write('✗ Суммы цифр '), write(N), write(' НЕ эквивалентны')), nl, test_digit_sum_equivalence(Rest). % =============================================== % ТЕСТЫ ДЛЯ SQUARE_FREE % =============================================== test_square_free :- write('--- Тестирование square_free ---'), nl, % Числа, свободные от квадратов SquareFreeNumbers = [1, 2, 3, 5, 6, 7, 10, 11, 13, 14, 15], forall(member(N, SquareFreeNumbers), test_square_free_positive(N)), % Числа, НЕ свободные от квадратов NonSquareFreeNumbers = [4, 8, 9, 12, 16, 18, 20, 24, 25, 27], forall(member(N, NonSquareFreeNumbers), test_square_free_negative(N)), nl. test_square_free_positive(N) :- (square_free(N) -> write('✓ '), write(N), write(' корректно определено как свободное от квадратов') ; write('✗ '), write(N), write(' ошибочно определено как НЕ свободное от квадратов')), nl. test_square_free_negative(N) :- (\+ square_free(N) -> write('✓ '), write(N), write(' корректно определено как НЕ свободное от квадратов') ; write('✗ '), write(N), write(' ошибочно определено как свободное от квадратов')), nl. % =============================================== % ТЕСТЫ ДЛЯ ОПЕРАЦИЙ СО СПИСКАМИ % =============================================== test_list_operations :- write('--- Тестирование операций со списками ---'), nl, % Тест пустого списка (sum_list_down([], 0) -> write('✓ sum_list_down([],0) - ПРОЙДЕН') ; write('✗ sum_list_down([],0) - ПРОВАЛЕН')), nl, (sum_list_up([], 0) -> write('✓ sum_list_up([],0) - ПРОЙДЕН') ; write('✗ sum_list_up([],0) - ПРОВАЛЕН')), nl, % Тест одного элемента (sum_list_down([5], 5) -> write('✓ sum_list_down([5],5) - ПРОЙДЕН') ; write('✗ sum_list_down([5],5) - ПРОВАЛЕН')), nl, (sum_list_up([5], 5) -> write('✓ sum_list_up([5],5) - ПРОЙДЕН') ; write('✗ sum_list_up([5],5) - ПРОВАЛЕН')), nl, % Тест различных списков TestLists = [ ([1, 2, 3], 6), ([10, 20, 30], 60), ([-1, 1, -2, 2], 0), ([0, 0, 0], 0), ([100], 100) ], forall(member((List, ExpectedSum), TestLists), test_list_sum(List, ExpectedSum)), % Тест эквивалентности рекурсий test_list_sum_equivalence([ [], [1], [1, 2], [1, 2, 3], [1, 2, 3, 4, 5], [-1, -2, -3], [0, 0, 0, 0] ]), nl. test_list_sum(List, ExpectedSum) :- sum_list_down(List, S1), sum_list_up(List, S2), write('Сумма '), write(List), write(': down='), write(S1), write(', up='), write(S2), write(', ожидалось='), write(ExpectedSum), ((S1 =:= ExpectedSum, S2 =:= ExpectedSum) -> write(' ✓') ; write(' ✗')), nl. test_list_sum_equivalence([]). test_list_sum_equivalence([List|Rest]) :- sum_list_down(List, S1), sum_list_up(List, S2), (S1 =:= S2 -> write('✓ Суммы списка '), write(List), write(' эквивалентны') ; write('✗ Суммы списка '), write(List), write(' НЕ эквивалентны')), nl, test_list_sum_equivalence(Rest). % =============================================== % ТЕСТЫ ДЛЯ УДАЛЕНИЯ ПО СУММЕ ЦИФР % =============================================== test_remove_by_digit_sum :- write('--- Тестирование remove_by_digit_sum ---'), nl, % Тест пустого списка (remove_by_digit_sum([], 5, []) -> write('✓ remove_by_digit_sum([],5,[]) - ПРОЙДЕН') ; write('✗ remove_by_digit_sum([],5,[]) - ПРОВАЛЕН')), nl, % Тест удаления всех элементов remove_by_digit_sum([11, 20, 101, 110], 2, Result1), (Result1 = [] -> write('✓ Удаление всех элементов с суммой цифр 2 - ПРОЙДЕН') ; write('✗ Удаление всех элементов с суммой цифр 2 - ПРОВАЛЕН')), nl, % Тест удаления части элементов remove_by_digit_sum([12, 21, 34, 43, 50], 3, Result2), Expected2 = [34, 43, 50], (Result2 = Expected2 -> write('✓ Частичное удаление элементов - ПРОЙДЕН') ; write('✗ Частичное удаление элементов - ПРОВАЛЕН')), nl, % Тест с нецелыми элементами remove_by_digit_sum([12, abc, 21, -5, 30], 3, Result3), Expected3 = [abc, -5], (Result3 = Expected3 -> write('✓ Обработка нецелых элементов - ПРОЙДЕН') ; write('✗ Обработка нецелых элементов - ПРОВАЛЕН')), nl, % Дополнительные тесты TestCases = [ (([123, 456, 789], 6), [456, 789]), (([1, 11, 111, 1111], 1), [11, 111]), (([0, 10, 100, 1000], 1), [0]), (([999, 888, 777], 27), [888, 777]) ], forall(member(((List, TargetSum), Expected), TestCases), test_remove_case(List, TargetSum, Expected)), nl. test_remove_case(List, TargetSum, Expected) :- remove_by_digit_sum(List, TargetSum, Result), write('remove_by_digit_sum('), write(List), write(', '), write(TargetSum), write(') = '), write(Result), write(', ожидалось: '), write(Expected), (Result = Expected -> write(' ✓') ; write(' ✗')), nl. % =============================================== % ДОПОЛНИТЕЛЬНЫЕ ТЕСТЫ % =============================================== % Тест производительности performance_test :- write('--- Тест производительности ---'), nl, write('Тестирование факториала для больших чисел:'), nl, TestNumbers = [10, 15, 20], forall(member(N, TestNumbers), test_factorial_performance(N)), write('Тестирование суммы цифр для больших чисел:'), nl, BigNumbers = [12345, 123456, 1234567], forall(member(N, BigNumbers), test_digit_sum_performance(N)), nl. test_factorial_performance(N) :- get_time(T1), fact_up(N, F1), get_time(T2), fact_down(N, F2), get_time(T3), TimeUp is T2 - T1, TimeDown is T3 - T2, write('Факториал '), write(N), write(': up='), write(TimeUp), write('с, down='), write(TimeDown), write('с, результат='), write(F1), (F1 =:= F2 -> write(' ✓') ; write(' ✗')), nl. test_digit_sum_performance(N) :- get_time(T1), digit_sum_up(N, S1), get_time(T2), digit_sum_down(N, S2), get_time(T3), TimeUp is T2 - T1, TimeDown is T3 - T2, write('Сумма цифр '), write(N), write(': up='), write(TimeUp), write('с, down='), write(TimeDown), write('с, результат='), write(S1), (S1 =:= S2 -> write(' ✓') ; write(' ✗')), nl. % Стресс-тест stress_test :- write('--- Стресс-тест ---'), nl, write('Тестирование 100 случайных чисел для square_free:'), nl, stress_test_square_free(100), write('Тестирование 50 случайных списков для sum_list:'), nl, stress_test_list_sum(50), nl. stress_test_square_free(0) :- !. stress_test_square_free(N) :- N > 0, random(1, 100, TestNumber), (square_free(TestNumber) -> Result = 'free' ; Result = 'not_free'), (N mod 10 =:= 0 -> (write('Тест '), write(N), write(': '), write(TestNumber), write(' - '), write(Result), nl) ; true), N1 is N - 1, stress_test_square_free(N1). stress_test_list_sum(0) :- !. stress_test_list_sum(N) :- N > 0, random(1, 10, ListLength), generate_random_list(ListLength, TestList), sum_list_down(TestList, S1), sum_list_up(TestList, S2), (N mod 10 =:= 0 -> (write('Тест '), write(N), write(': '), write(TestList), write(' - суммы равны: '), (S1 =:= S2 -> write('да') ; write('нет')), nl) ; true), N1 is N - 1, stress_test_list_sum(N1). generate_random_list(0, []) :- !. generate_random_list(N, [H|T]) :- N > 0, random(0, 100, H), N1 is N - 1, generate_random_list(N1, T).