diff --git a/README.md b/README.md index b7cb85220..f080a1cc9 100644 --- a/README.md +++ b/README.md @@ -57,38 +57,17 @@ Link to commit:(same as for the first one) Screenshot of branch measurement: ![image](https://github.com/CatalinAnt/algorithms-SEP-95/assets/113595149/94eec9b6-3dd6-46e3-b087-40892eccc10e) -#### Abdullah Abdelkhalik - -pythagoras - -https://github.com/CatalinAnt/algorithms-SEP-95/commit/5651abafebe8ae3a5ea63e74883bb991acf19303 -![pythagoras_hits](https://github.com/CatalinAnt/algorithms-SEP-95/assets/114078193/0df1fa2b-2185-4b9f-ae65-5d969edb009b) -first_unique_char -https://github.com/CatalinAnt/algorithms-SEP-95/commit/c16f26e952322b2c1729778a4141a57103ba7658 -![first_unique_char_hits](https://github.com/CatalinAnt/algorithms-SEP-95/assets/114078193/10d7c45c-398e-4408-8f11-6771f51fa95c) -#### Abdullah Abdelkhalik -pythagoras -https://github.com/CatalinAnt/algorithms-SEP-95/commit/5651abafebe8ae3a5ea63e74883bb991acf19303 - -![pythagoras_hits](https://github.com/CatalinAnt/algorithms-SEP-95/assets/114078193/0df1fa2b-2185-4b9f-ae65-5d969edb009b) - - -first_unique_char - -https://github.com/CatalinAnt/algorithms-SEP-95/commit/c16f26e952322b2c1729778a4141a57103ba7658 - -![first_unique_char_hits](https://github.com/CatalinAnt/algorithms-SEP-95/assets/114078193/10d7c45c-398e-4408-8f11-6771f51fa95c) #### Almuthana Almustafa @@ -110,6 +89,41 @@ result: ![alt text](result_image_2.png) +#### Ayman Errahmouni + +##### Function 1: simplify_path_v2 + +[Link the commit](https://github.com/CatalinAnt/algorithms-SEP-95/pull/2/commits/22ee6fa1df4785596c603af61a725c558973eb0b) + +Screenshot of branch measurement:
+![alt text](image-7.png) + +##### Function 2: insertion_sort + +[Link to commit](https://github.com/CatalinAnt/algorithms-SEP-95/pull/2/commits/5dae7f28036f89b7f6ff673639a922dd714aff3e) + +Screenshot of branch measurement:
+![alt text](image-11.png) + +#### Catalin Antonescu + +##### Function 1: strong_password + +Link to commit: +[https://github.com/CatalinAnt/algorithms-SEP-95/commit/eaad6d32ecd73bb8fde876a4d4852cb522aea6f8](https://github.com/CatalinAnt/algorithms-SEP-95/commit/2b0b9187c1c040e4476b1ca14f2c2249273566b7) + +Screenshot of branch measurement: +![image](https://github.com/CatalinAnt/algorithms-SEP-95/assets/113595149/e718a47f-5ea0-412c-b250-25a193412164) + +##### Function 2: rotate_image + +Link to commit:(same as for the first one) +[https://github.com/CatalinAnt/algorithms-SEP-95/commit/eaad6d32ecd73bb8fde876a4d4852cb522aea6f8](https://github.com/CatalinAnt/algorithms-SEP-95/commit/2b0b9187c1c040e4476b1ca14f2c2249273566b7) + +Screenshot of branch measurement: +![image](https://github.com/CatalinAnt/algorithms-SEP-95/assets/113595149/94eec9b6-3dd6-46e3-b087-40892eccc10e) + + ## Coverage improvement ### Individual tests @@ -143,6 +157,7 @@ Old coverage:
Diff (LHS = new code, RHS = old code):
![LHS: new code, RHS: old code](image.png) +![alt text](image-9.png) New coverage:
![new coverage result (100%)](image-1.png) @@ -161,6 +176,8 @@ Diff (LHS: new code, RHS: old code):
![LHS: new code, RHS: old code](image-5.png)
(Changes in imports)
![LHS: new code, RHS: old code](image-6.png) +(Instrumentation)
+![alt text](image-8.png) Old coverage:
![Old coverage result (4%)](image-3.png) @@ -192,7 +209,6 @@ New coverage: For strong_password there was a 26% coverage improvement with the existing tool and 40% with manual measurement tool. - Test 2: In test_matrix: @@ -212,27 +228,7 @@ New coverage: For rotate_image, thre was a 33% coverage improvement with the existing tool and 25% with manual tool. -## Abdullah Abdelkhalik - -test_maths - -https://github.com/CatalinAnt/algorithms-SEP-95/commit/60832d9c672efd586848077cc41a52630d34371b - -![pythagoras_before](https://github.com/CatalinAnt/algorithms-SEP-95/assets/114078193/cf57112b-1aef-4a10-a41f-bd4b797e2012) - -![pythagoras_after](https://github.com/CatalinAnt/algorithms-SEP-95/assets/114078193/1aa45c17-46fc-49d3-944a-03c2276d1be6) - -the coverage is improved by 28%, the code only hit one of the five branches and cover only one of the three cases of the pythagoras theory. I added the other two cases, i could have a fourth case where none of the cases is present. - -test_strings - -https://github.com/CatalinAnt/algorithms-SEP-95/commit/5651abafebe8ae3a5ea63e74883bb991acf19303 -![first_unique_char_before](https://github.com/CatalinAnt/algorithms-SEP-95/assets/114078193/9910ec69-73b0-4c87-afc8-abc01f65a423) - -![first_unique_char_after](https://github.com/CatalinAnt/algorithms-SEP-95/assets/114078193/10859fac-776c-4a48-8a1c-9531afcbfa9b) - -The coverage is improved by 13%, the code only hit three out of five branches and only set up two examples. I added a case where there is no unique letter. ## Almuthana Almustafa @@ -267,6 +263,85 @@ existing tool result after: The coverage improved by 86% due to the creation of new tests. + + + + + + + + + + + + + + + + + + + + + + + +#### Abdullah Abdelkhalik + + +pythagoras + +https://github.com/CatalinAnt/algorithms-SEP-95/commit/5651abafebe8ae3a5ea63e74883bb991acf19303 + +![pythagoras_hits](https://github.com/CatalinAnt/algorithms-SEP-95/assets/114078193/c61bff67-be7e-4bd2-b892-0a0f2dada1f3) + + + + +first_unique_char + +https://github.com/CatalinAnt/algorithms-SEP-95/commit/c16f26e952322b2c1729778a4141a57103ba7658 + +![first_unique_char_hits (2)](https://github.com/CatalinAnt/algorithms-SEP-95/assets/114078193/8c1b704e-cadb-4f54-aea7-795005348538) + + + + + +## Improvements + +test_maths + +https://github.com/CatalinAnt/algorithms-SEP-95/commit/60832d9c672efd586848077cc41a52630d34371b + +![pythagoras_before](https://github.com/CatalinAnt/algorithms-SEP-95/assets/114078193/cf57112b-1aef-4a10-a41f-bd4b797e2012) + +![pythagoras_after](https://github.com/CatalinAnt/algorithms-SEP-95/assets/114078193/1aa45c17-46fc-49d3-944a-03c2276d1be6) + +the coverage is improved by 28%, the code only hit one of the five branches and cover only one of the three cases of the pythagoras theory. I added the other two cases, i could have a fourth case where none of the cases is present. + +test_strings + +https://github.com/CatalinAnt/algorithms-SEP-95/commit/5651abafebe8ae3a5ea63e74883bb991acf19303 + +![first_unique_char_before](https://github.com/CatalinAnt/algorithms-SEP-95/assets/114078193/9910ec69-73b0-4c87-afc8-abc01f65a423) + +![first_unique_char_after](https://github.com/CatalinAnt/algorithms-SEP-95/assets/114078193/10859fac-776c-4a48-8a1c-9531afcbfa9b) + +The coverage is improved by 13%, the code only hit three out of five branches and only set up two examples. I added a case where there is no unique letter. + + + + + + + + + + + + + ### Overall diff --git a/algorithms/maths/find_order_simple.py b/algorithms/maths/find_order_simple.py index 8f69773c7..732fcae62 100644 --- a/algorithms/maths/find_order_simple.py +++ b/algorithms/maths/find_order_simple.py @@ -11,17 +11,42 @@ import math +branch_coverage = { + "branch_6": False, + "branch_7": False, + "branch_8": False, + "branch_9": False, + "branch_10": False +} + def find_order(a, n): """ Find order for positive integer n and given integer a that satisfies gcd(a, n) = 1. """ + if (a == 1) & (n == 1): # Exception Handeling : 1 is the order of of 1 + branch_coverage["branch_6"] = True + print("branch_6") return 1 if math.gcd(a, n) != 1: + branch_coverage["branch_7"] = True + print("branch_7") print ("a and n should be relative prime!") return -1 for i in range(1, n): + branch_coverage["branch_8"] = True + print("branch_8") if pow(a, i) % n == 1: + branch_coverage["branch_9"] = True + print("branch_9") return i + branch_coverage["branch_10"] = True + print("branch_10") return -1 + +def print_coverage(): + for branch, hit in branch_coverage.items(): + print(f"{branch} was {'hit' if hit else 'not hit'}") + +print_coverage() \ No newline at end of file diff --git a/algorithms/maths/prime_check.py b/algorithms/maths/prime_check.py index 60e4427ab..532f7afba 100644 --- a/algorithms/maths/prime_check.py +++ b/algorithms/maths/prime_check.py @@ -1,17 +1,42 @@ +branch_coverage = { + "branch_1": False, # n <= 1 + "branch_2": False, # n == 2 or n == 3 + "branch_3": False, # n % 2 == 0 or n % 3 == 0 + "branch_4": False, # while j * j <= n + "branch_5": False # n % j == 0 or n % (j + 2) == 0 +} def prime_check(n): """Return True if n is a prime number Else return False. """ + print(f"Checking {n}") # Debugging statement if n <= 1: + branch_coverage["branch_1"] = True + print("branch_1") return False + if n == 2 or n == 3: + branch_coverage["branch_2"] = True + print("branch_2") return True if n % 2 == 0 or n % 3 == 0: + branch_coverage["branch_3"] = True + print("branch_3") return False j = 5 while j * j <= n: + branch_coverage["branch_4"] = True + print("branch_4") if n % j == 0 or n % (j + 2) == 0: + branch_coverage["branch_5"] = True + print("branch_5") return False j += 6 return True + +def print_coverage(): + for branch, hit in branch_coverage.items(): + print(f"{branch} was {'hit' if hit else 'not hit'}") + +print_coverage() diff --git a/algorithms/maths/pythagoras.py b/algorithms/maths/pythagoras.py index b24b682ac..386b821b3 100644 --- a/algorithms/maths/pythagoras.py +++ b/algorithms/maths/pythagoras.py @@ -2,6 +2,13 @@ Given the lengths of two of the three sides of a right angled triangle, this function returns the length of the third side. """ +branch_coverage = { + "branch_31": False, + "branch_32": False, + "branch_33": False, + "branch_34": False, + "branch_35": False +} def pythagoras(opposite, adjacent, hypotenuse): """ @@ -10,11 +17,25 @@ def pythagoras(opposite, adjacent, hypotenuse): """ try: if opposite == str("?"): + branch_coverage["branch_31"] = True return ("Opposite = " + str(((hypotenuse**2) - (adjacent**2))**0.5)) if adjacent == str("?"): + branch_coverage["branch_32"] = True return ("Adjacent = " + str(((hypotenuse**2) - (opposite**2))**0.5)) if hypotenuse == str("?"): + branch_coverage["branch_33"] = True return ("Hypotenuse = " + str(((opposite**2) + (adjacent**2))**0.5)) + branch_coverage["branch_34"] = True return "You already know the answer!" except: + branch_coverage["branch_35"] = True raise ValueError("invalid argument(s) were given.") + +def print_coverage(): + for branch, hit in branch_coverage.items(): + print(f"{branch} was {'hit' if hit else 'not hit'}") + +pythagoras(3, 2, "?") + +print_coverage() + diff --git a/algorithms/matrix/rotate_image.py b/algorithms/matrix/rotate_image.py index a8b5e4e77..f525e24bb 100644 --- a/algorithms/matrix/rotate_image.py +++ b/algorithms/matrix/rotate_image.py @@ -7,6 +7,14 @@ Could you do this in-place? """ +branch_coverage = { + "rotate_matrix_1": False, # if not branch for mat + "rotate_matrix_2": False, # invisible else branch + "rotate_matrix_3": False, # for branch + "rotate_matrix_4": False, # for branch + +} + # clockwise rotate # first reverse up to down, then swap the symmetry @@ -16,18 +24,38 @@ def rotate(mat): if not mat: + branch_coverage["rotate_matrix_1"] = True return mat + + branch_coverage["rotate_matrix_2"] = True + mat.reverse() for i in range(len(mat)): + branch_coverage["rotate_matrix_3"] = True + for j in range(i): + branch_coverage["rotate_matrix_4"] = True + mat[i][j], mat[j][i] = mat[j][i], mat[i][j] return mat -if __name__ == "__main__": - mat = [[1, 2, 3], - [4, 5, 6], - [7, 8, 9]] - print(mat) - rotate(mat) - print(mat) +def print_coverage(): + for branch, hit in branch_coverage.items(): + print(f"{branch} was {'hit' if hit else 'not hit'}") + total = len(branch_coverage) + hit = sum(branch_coverage.values()) + result = hit / total * 100 + + print("The total branch coverage is:", result, "%") + + +rotate([]) +print_coverage() +print("\n") +print_coverage() +rotate([[1, 2], [3, 4]]) +print("\n") +print_coverage() +rotate([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) +print("\n") diff --git a/algorithms/search/interpolation_search.py b/algorithms/search/interpolation_search.py index 5b1d00a1a..98a405431 100644 --- a/algorithms/search/interpolation_search.py +++ b/algorithms/search/interpolation_search.py @@ -13,6 +13,15 @@ from typing import List +branch_coverage = { + "branch_60": False, + "branch_61": False, + "branch_62": False, + "branch_63": False, + "branch_64": False, + +} + def interpolation_search(array: List[int], search_key: int) -> int: """ @@ -38,24 +47,36 @@ def interpolation_search(array: List[int], search_key: int) -> int: while (low <= high) and (array[low] <= search_key <= array[high]): # calculate the search position + branch_coverage["branch_60"] = True pos = low + int(((search_key - array[low]) * (high - low) / (array[high] - array[low]))) # search_key is found if array[pos] == search_key: + branch_coverage["branch_61"] = True return pos # if search_key is larger, search_key is in upper part if array[pos] < search_key: + branch_coverage["branch_62"] = True low = pos + 1 # if search_key is smaller, search_key is in lower part else: + branch_coverage["branch_63"] = True high = pos - 1 - + + branch_coverage["branch_64"] = True return -1 +def print_coverage(): + for branch, hit in branch_coverage.items(): + print(f"{branch} was {'hit' if hit else 'not hit'}") + + if __name__ == "__main__": import doctest doctest.testmod() +print_coverage() + diff --git a/algorithms/sort/insertion_sort.py b/algorithms/sort/insertion_sort.py index 06c86228d..f1f7613e4 100644 --- a/algorithms/sort/insertion_sort.py +++ b/algorithms/sort/insertion_sort.py @@ -1,3 +1,10 @@ +branch_coverage = { + "simulation": False, + "for": False, + "while": False, + "simulation-nested": False, +} + def insertion_sort(arr, simulation=False): """ Insertion Sort Complexity: O(n^2) @@ -5,13 +12,16 @@ def insertion_sort(arr, simulation=False): iteration = 0 if simulation: + branch_coverage["simulation"] = True print("iteration",iteration,":",*arr) for i in range(len(arr)): + branch_coverage["for"] = True cursor = arr[i] pos = i while pos > 0 and arr[pos - 1] > cursor: + branch_coverage["while"] = True # Swap the number down the list arr[pos] = arr[pos - 1] pos = pos - 1 @@ -19,7 +29,25 @@ def insertion_sort(arr, simulation=False): arr[pos] = cursor if simulation: + branch_coverage["simulation-nested"] = True iteration = iteration + 1 print("iteration",iteration,":",*arr) return arr + +def print_coverage(): + covered = 0 + print("branch coverage for `insertion_sort`:") + for branch, hit in branch_coverage.items(): + print(f"{branch} was {'hit' if hit else 'not hit'}") + if hit: covered += 1; + print(f"Branch coverage: {covered / len(branch_coverage) * 100}") + +insertion_sort([]) +insertion_sort([1]) +insertion_sort([69, 420]) +insertion_sort([420, 69]) +insertion_sort([0, 1, 2, 3, 4, 3, 2, 1, 0]) +insertion_sort([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], True) +insertion_sort([0, 1, 2, 3, 4, 3, 2, 1, 0], True) +print_coverage() diff --git a/algorithms/strings/first_unique_char.py b/algorithms/strings/first_unique_char.py index 44ba05e49..a1a57b521 100644 --- a/algorithms/strings/first_unique_char.py +++ b/algorithms/strings/first_unique_char.py @@ -11,17 +11,39 @@ Reference: https://leetcode.com/problems/first-unique-character-in-a-string/description/ """ + +branch_coverage = { + "branch_26": False, + "branch_27": False, + "branch_28": False, + "branch_29": False, + "branch_30": False, +} + def first_unique_char(s): """ :type s: str :rtype: int """ if (len(s) == 1): + branch_coverage["branch_26"] = True return 0 ban = [] for i in range(len(s)): + branch_coverage["branch_27"] = True if all(s[i] != s[k] for k in range(i + 1, len(s))) == True and s[i] not in ban: + branch_coverage["branch_28"] = True return i else: + branch_coverage["branch_29"] = True ban.append(s[i]) + branch_coverage["branch_30"] = True return -1 + +def print_coverage(): + for branch, hit in branch_coverage.items(): + print(f"{branch} was {'hit' if hit else 'not hit'}") + +first_unique_char("leetcode") +first_unique_char("loveleetcode") +print_coverage() diff --git a/algorithms/strings/strong_password.py b/algorithms/strings/strong_password.py index 85acd0223..b3e9317b8 100644 --- a/algorithms/strings/strong_password.py +++ b/algorithms/strings/strong_password.py @@ -29,15 +29,53 @@ Output: 1 (Because the password isn't strong, but she can make it strong by adding a single digit.) """ +branch_coverage = { + "strong_password_1": False, # if branch for any(i.isdigit() for i in password) == False + "strong_password_2": False, # if branch for any(i.islower() for i in password) == False + "strong_password_3": False, # if branch for any(i.isupper() for i in password) == False + "strong_password_4": False, # if branch for any(i in '!@#$%^&*()-+' for i in password) == False + "strong_password_5": False # invisible else branch + +} +counter = 0 + def strong_password(n, password): count_error = 0 # Return the minimum number of characters to make the password strong if any(i.isdigit() for i in password) == False: + branch_coverage["strong_password_1"] = True count_error = count_error + 1 if any(i.islower() for i in password) == False: + branch_coverage["strong_password_2"] = True count_error = count_error + 1 if any(i.isupper() for i in password) == False: + branch_coverage["strong_password_3"] = True count_error = count_error + 1 if any(i in '!@#$%^&*()-+' for i in password) == False: + branch_coverage["strong_password_4"] = True count_error = count_error + 1 + + branch_coverage["strong_password_5"] = True return max(count_error, 6 - n) + + +def print_coverage(): + for branch, hit in branch_coverage.items(): + print(f"{branch} was {'hit' if hit else 'not hit'}") + total = len(branch_coverage) + hit = sum(branch_coverage.values()) + result = hit / total * 100 + print("The total branch coverage is:", result, "%" ) + + +strong_password(11, "#Algorithms") +print_coverage() +print("\n") +strong_password(5, "12345") +print_coverage() +print("\n") +strong_password(5, "abcde") +print_coverage() +print("\n") +strong_password(3, "Ab1") +print_coverage() diff --git a/algorithms/unix/path/simplify_path.py b/algorithms/unix/path/simplify_path.py index 8880fc0c6..8f993b763 100644 --- a/algorithms/unix/path/simplify_path.py +++ b/algorithms/unix/path/simplify_path.py @@ -15,6 +15,12 @@ Reference: https://leetcode.com/problems/simplify-path/description/ """ +branch_coverage = { + "for": False, + "if": False, + "elif": False, +} + import os def simplify_path_v1(path): return os.path.abspath(path) @@ -22,8 +28,28 @@ def simplify_path_v1(path): def simplify_path_v2(path): stack, tokens = [], path.split("/") for token in tokens: + branch_coverage["for"] = True if token == ".." and stack: + branch_coverage["if"] = True stack.pop() elif token != ".." and token != "." and token: + branch_coverage["elif"] = True stack.append(token) + return "/" + "/".join(stack) + +def print_coverage(): + covered = 0 + print("branch coverage for `simplify_path_v2`:") + for branch, hit in branch_coverage.items(): + print(f"{branch} was {'hit' if hit else 'not hit'}") + if hit: covered += 1; + print(f"Branch coverage: {covered / len(branch_coverage) * 100}") + + +# simplify_path_v2(".") +# simplify_path_v2("/../") +# simplify_path_v2("/home//foo/") +# simplify_path_v2("") +# simplify_path_v2("/home/../") +print_coverage() diff --git a/image-1.png b/image-1.png new file mode 100644 index 000000000..7071337a2 Binary files /dev/null and b/image-1.png differ diff --git a/image-10.png b/image-10.png new file mode 100644 index 000000000..7e4ab2a58 Binary files /dev/null and b/image-10.png differ diff --git a/image-11.png b/image-11.png new file mode 100644 index 000000000..cebd821ad Binary files /dev/null and b/image-11.png differ diff --git a/image-2.png b/image-2.png new file mode 100644 index 000000000..77702129e Binary files /dev/null and b/image-2.png differ diff --git a/image-3.png b/image-3.png new file mode 100644 index 000000000..61fc9d074 Binary files /dev/null and b/image-3.png differ diff --git a/image-4.png b/image-4.png new file mode 100644 index 000000000..9b5c60694 Binary files /dev/null and b/image-4.png differ diff --git a/image-5.png b/image-5.png new file mode 100644 index 000000000..e65d38265 Binary files /dev/null and b/image-5.png differ diff --git a/image-6.png b/image-6.png new file mode 100644 index 000000000..78045907d Binary files /dev/null and b/image-6.png differ diff --git a/image-7.png b/image-7.png new file mode 100644 index 000000000..ffd360b0f Binary files /dev/null and b/image-7.png differ diff --git a/image-8.png b/image-8.png new file mode 100644 index 000000000..6e6eab6b2 Binary files /dev/null and b/image-8.png differ diff --git a/image-9.png b/image-9.png new file mode 100644 index 000000000..2a59acdd5 Binary files /dev/null and b/image-9.png differ diff --git a/image.png b/image.png new file mode 100644 index 000000000..2a9ba91c1 Binary files /dev/null and b/image.png differ diff --git a/tests/test_maths.py b/tests/test_maths.py index c4a54af03..8d6e5f383 100644 --- a/tests/test_maths.py +++ b/tests/test_maths.py @@ -1,3 +1,6 @@ +from algorithms.maths.prime_check import prime_check, print_coverage +import unittest + from algorithms.maths import ( power, power_recur, int_to_base, base_to_int, @@ -276,17 +279,45 @@ class TestPrimeTest(unittest.TestCase): Arguments: unittest {[type]} -- [description] """ + - def test_prime_test(self): + def test_prime_numbers(self): """ - checks all prime numbers between 2 up to 100. - Between 2 up to 100 exists 25 prime numbers! + Checks specific prime numbers between 2 up to 100. """ - counter = 0 - for i in range(2, 101): - if prime_check(i): - counter += 1 - self.assertEqual(25, counter) + primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97] + for prime in primes: + with self.subTest(n=prime): + self.assertTrue(prime_check(prime), f"{prime} should be prime") + + def test_non_prime_numbers(self): + """ + Checks specific non-prime numbers between 2 up to 100. + """ + non_primes = [4, 6, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 22, 24, 25, 26, 27, 28, 30, 32, 33, 34, 35, 36, 38, 39, 40, 42, 44, 45, 46, 48, 49, 50, 51, 52, 54, 55, 56, 57, 58, 60, 62, 63, 64, 65, 66, 68, 69, 70, 72, 74, 75, 76, 77, 78, 80, 81, 82, 84, 85, 86, 87, 88, 90, 91, 92, 93, 94, 95, 96, 98, 99, 100] + for non_prime in non_primes: + with self.subTest(n=non_prime): + self.assertFalse(prime_check(non_prime), f"{non_prime} should not be prime") + + def test_prime_check_coverage(self): + """ + Additional checks to cover all branches in prime_check function. + """ + self.assertFalse(prime_check(-1), "-1 should not be prime") # Branch 1 + self.assertFalse(prime_check(0), "0 should not be prime") # Branch 1 + self.assertFalse(prime_check(1), "1 should not be prime") # Branch 1 + self.assertTrue(prime_check(2), "2 should be prime") # Branch 2 + self.assertTrue(prime_check(3), "3 should be prime") # Branch 2 + self.assertFalse(prime_check(4), "4 should not be prime") # Branch 3 + self.assertFalse(prime_check(9), "9 should not be prime") # Branch 3 + self.assertFalse(prime_check(15), "15 should not be prime") # Branch 3, 4, 5 + self.assertTrue(prime_check(5), "5 should be prime") # Branch 4 + self.assertTrue(prime_check(7), "7 should be prime") # Branch 4 + self.assertFalse(prime_check(25), "25 should not be prime") # Branch 5 + self.assertFalse(prime_check(49), "49 should not be prime") # Branch 5 + self.assertFalse(prime_check(50), "50 should not be prime") # Branch 3 + self.assertTrue(prime_check(97), "97 should be prime") # Branch 4 + class TestPythagoras(unittest.TestCase): @@ -301,6 +332,16 @@ def test_pythagoras(self): self.assertEqual("Hypotenuse = 3.605551275463989", pythagoras(3, 2, "?")) + def test_opposite_calculation(self): + result = pythagoras("?", 4, 5) + expected = "Opposite = 3.0" + self.assertEqual(result, expected) + + def test_adjacent_calculation(self): + result = pythagoras(3, "?", 5) + expected = "Adjacent = 4.0" + self.assertEqual(result, expected) + class TestRabinMiller(unittest.TestCase): """[summary] @@ -434,10 +475,12 @@ class TestFindOrder(unittest.TestCase): """ def test_find_order_simple(self): - self.assertEqual(1, find_order(1, 1)) + self.assertEqual(1, find_order(1, 1)) # Should hit branch_1 self.assertEqual(6, find_order(3, 7)) self.assertEqual(-1, find_order(128, 256)) self.assertEqual(352, find_order(3, 353)) + self.assertEqual(-1, find_order(10, 20)) # Should hit branches 2, 3, 5 + class TestKrishnamurthyNumber(unittest.TestCase): diff --git a/tests/test_matrix.py b/tests/test_matrix.py index 262fdbe62..5961680cc 100644 --- a/tests/test_matrix.py +++ b/tests/test_matrix.py @@ -15,6 +15,8 @@ ) import unittest +from algorithms.matrix.rotate_image import rotate + class TestBombEnemy(unittest.TestCase): def test_3x4(self): @@ -228,6 +230,8 @@ def test_rotate_image(self): self.assertEqual(rotate_image.rotate( [[1, 2, 3], [4, 5, 6], [7, 8, 9]]), [[7, 4, 1], [8, 5, 2], [9, 6, 3]]) + self.assertEqual([],rotate_image.rotate([])) + self.assertEqual([[3, 1], [4, 2]],rotate([[1, 2], [3, 4]])) class TestSparseDotVector(unittest.TestCase): diff --git a/tests/test_search.py b/tests/test_search.py index f515cfcb9..f414cacc1 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -139,13 +139,28 @@ def test_next_greatest_letter(self): self.assertEqual("c", next_greatest_letter_v2(letters, target)) def test_interpolation_search(self): - array = [0, 3, 5, 5, 9, 12, 12, 15, 16, 19, 20] + array = [0, 3, 5, 5, 9, 12, 12, 15, 16, 19, 20, 25] + #, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100] + + # array = [0, 3, 5, 5, 9, 12, 12, 15, 16, 19, 20, 25] self.assertEqual(1, interpolation_search(array, 3)) self.assertEqual(2, interpolation_search(array, 5)) - self.assertEqual(6, interpolation_search(array, 12)) + self.assertEqual(5, interpolation_search(array, 12)) self.assertEqual(-1, interpolation_search(array, 22)) self.assertEqual(-1, interpolation_search(array, -10)) self.assertEqual(10, interpolation_search(array, 20)) + + # self.assertEqual(-1, interpolation_search(array, 1)) + # self.assertEqual(0, interpolation_search(array, 0)) # Found at the start + # self.assertEqual(interpolation_search(array, 12), 5) # Found in the middle, first occurrence + # self.assertEqual(-1, interpolation_search(array, 110)) # Not found, above maximum + # self.assertEqual(interpolation_search(array, 55), 17) # Found in the middle + # self.assertEqual(interpolation_search(array, 70), 20) # Found, single value in range + # self.assertEqual(interpolation_search(array, 22), -1) # Not found, above the range + # self.assertEqual(interpolation_search(array, 50), 16) # Found, single value in range + # self.assertEqual(interpolation_search(array, 45), 15) # Found, single value in range + + if __name__ == '__main__': diff --git a/tests/test_strings.py b/tests/test_strings.py index e7a68302a..4a4c8da90 100644 --- a/tests/test_strings.py +++ b/tests/test_strings.py @@ -479,6 +479,8 @@ class TestStrongPassword(unittest.TestCase): def test_strong_password(self): self.assertEqual(3, strong_password(3, "Ab1")) self.assertEqual(1, strong_password(11, "#Algorithms")) + self.assertEqual(3,strong_password(5, "12345")) + self.assertEqual(3,strong_password(5, "abcde")) class TestCaesarCipher(unittest.TestCase): @@ -568,6 +570,7 @@ class TestFirstUniqueChar(unittest.TestCase): def test_first_unique_char(self): self.assertEqual(0, first_unique_char("leetcode")) self.assertEqual(2, first_unique_char("loveleetcode")) + self.assertEqual(-1, first_unique_char("aabb")) class TestRepeatSubstring(unittest.TestCase): diff --git a/tests/test_unix.py b/tests/test_unix.py index 3cafba98f..e53881ef1 100644 --- a/tests/test_unix.py +++ b/tests/test_unix.py @@ -7,6 +7,9 @@ import os import unittest +from algorithms.unix import ( + print_coverage +) class TestUnixPath(unittest.TestCase): def test_join_with_slash(self): @@ -42,7 +45,26 @@ def test_split(self): self.assertEqual("test.py", expect_result[1]) def test_simplify_path(self): - self.assertEqual("/", simplify_path_v1("/../")) - self.assertEqual("/home/foo", simplify_path_v1("/home//foo/")) + root = None + pathsep = None + drive = None + if os.name == 'nt': + root = "" # Assumed to be ran on the C drive + pathsep = "\\" + drive = "C:\\" + elif os.name == 'posix': + root = "/" + pathsep = "/" + drive = "" + + self.assertEqual(drive + root, simplify_path_v1("/../")) + self.assertEqual(drive + root + pathsep.join(["home", "foo"]), simplify_path_v1("/home//foo/")) + + self.assertEqual("/", simplify_path_v2(".")) self.assertEqual("/", simplify_path_v2("/../")) self.assertEqual("/home/foo", simplify_path_v2("/home//foo/")) + self.assertEqual("/", simplify_path_v2("")) + self.assertEqual("/", simplify_path_v2("/home/../")) + + print_coverage() +