diff --git a/collaboration/retrospective.md b/collaboration/retrospective.md index 74e18813b..9c0f276f9 100644 --- a/collaboration/retrospective.md +++ b/collaboration/retrospective.md @@ -1,23 +1,95 @@ - - # Retrospective -## Stop Doing +This document reflects on the successes, challenges, and lessons learned during the +**Team Code Review Project**. + +--- + +## What Went Well + +1. **Effective Communication** + - Regular updates and support through Slack helped foster a collaborative and supportive environment. + - Open communication allowed team members to share challenges and solutions effectively. + +2. **Teamwork and Mutual supportip** + - Members actively supported each other, contributing to a positive learning environment. + - Troubleshooting challenges as a team became one of our best practices. + +3. **Workflow and Task Management** + - The project board provided a high-level view of tasks and responsibilities, helping active members track progress and stay organized. + - The group followed the planned workflow and met the overall project deadline despite some internal delays. -## Continue Doing +4. **Clean Code Practices** + - Team members wrote clean, readable code, aligning with the goals of effective communication through written code. + - Code reviews highlighted opportunities for improvement, further enhancing code quality. -## Start Doing +--- + +## What Could Be Improved + +1. **Procrastination** + - Some tasks were left until the last moment, creating unnecessary pressure and delays. + - Push-related challenges and issues took longer than expected to resolve, impacting group timelines. + +2. **Engagement** + - Not all team members were consistently active, resulting in uneven distribution of workload. + - More effort is needed to encourage and engage inactive members to contribute to the project. + +3. **Unforeseen Challenges** + - Issues with the extension update (Ruff) and unexpected technical challenges consumed additional time. + - Assumptions about group-wide familiarity with tools like Git and Python slowed down certain workflows. + +--- ## Lessons Learned -______________________________________________________________________ +- **Communication is Key**: + Consistent and open communication between team members was critical for overcoming challenges and maintaining morale. +- **Team Troubleshooting Works**: + Collaborating on problem-solving not only sped up issue resolution but also helped everyone learn new skills. +- **Clean Code Matters**: + Writing clear and easy-to-read code significantly improved understanding during reviews and handoffs. +- **Adaptability Is Crucial**: + Challenges like the Ruff extension update reminded us to remain adaptable and willing + to consult wider community and documentation when needed. + +--- + +## Actionable Recommendations + +### What We Should Stop Doing + +- **Procrastination**: Start addressing tasks earlier in the workflow to prevent last-minute bottlenecks. + +### What We Should Continue Doing + +- **Support and Mentorship**: Maintain a collaborative and supportive environment via Slack. +- **Open Communication**: Keep the Slack channel active for daily check-ins and updates. + +### What We Should Start Doing + +- **Regular Sync-Up Meetings**: Incorporate more frequent team meetings to check progress and align on tasks. +- **Encourage Engagement**: Actively engage and support less active team members to ensure an equitable distribution of workload. +- **Work-Life Balance**: Focus on balancing project work with personal commitments to avoid burnout. + +--- + +## Reflections on Strategy + +### What Worked + +- The workflow on the project board provided clarity on task progress and ownership. +- Active members of the team successfully completed tasks +- within the instructor-set timeframe. -## Strategy vs. Board +### What Didn’t Work -### What parts of your plan went as expected? +- Internal deadlines were delayed due to technical challenges and inconsistent participation. +- Unexpected issues like the Ruff extension update consumed additional time and disrupted the workflow. -### What parts of your plan did not work out? +### What Needed to Be Added -### Did you need to add things that weren't in your strategy? +- Regular check-ins to monitor progress and adjust strategies in real time. +- Revisiting recorded lectures and team discussions became an unplanned but necessary part of the workflow. -### Or remove extra steps? +--- diff --git a/solutions/calculate_supplier_performance_score.py b/solutions/calculate_supplier_performance_score.py new file mode 100644 index 000000000..576bdd07e --- /dev/null +++ b/solutions/calculate_supplier_performance_score.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +A module for calculating the performance score of a supplier. +Module contents: + - Calculates the performance score of a supplier based on delivery reliability + +Created on 2025-01-07 +Author: Idris Pamiri +""" + +import doctest + + +def calculate_supplier_performance_score( + on_time_deliveries: int, + total_deliveries: int, + defective_items: int, + total_items: int, +) -> float: + """ + Evaluates supplier performance based on delivery reliability and defect rates. + + The function calculates a performance score (0-100) by combining the percentage + of on-time deliveries and the percentage of defect-free items. The two metrics + are equally weighted in the score. + + Parameters: + on_time_deliveries (int): Number of on-time deliveries. + total_deliveries (int): Total number of deliveries (must be greater than 0). + defective_items (int): Number of defective items. + total_items (int): Total items delivered (must be greater than 0). + + Returns: + float: Supplier performance score (0-100). + + Raises: + ValueError: If any input is negative or total_deliveries/total_items is zero. + + Examples: + >>> calculate_supplier_performance_score(45, 50, 10, 100) + 90.0 + >>> calculate_supplier_performance_score(10, 10, 0, 20) + 100.0 + >>> calculate_supplier_performance_score(0, 10, 5, 20) + 37.5 + """ + # Defensive programming with assertions + assert isinstance(on_time_deliveries, int), "on_time_deliveries must be an integer" + assert isinstance(total_deliveries, int), "total_deliveries must be an integer" + assert isinstance(defective_items, int), "defective_items must be an integer" + assert isinstance(total_items, int), "total_items must be an integer" + + if total_deliveries <= 0: + raise ValueError("Total deliveries must be greater than zero") + if total_items <= 0: + raise ValueError("Total items must be greater than zero") + if on_time_deliveries < 0 or defective_items < 0: + raise ValueError("on_time_deliveries and defective_items cannot be negative") + if on_time_deliveries > total_deliveries: + raise ValueError("on_time_deliveries cannot exceed total_deliveries") + if defective_items > total_items: + raise ValueError("defective_items cannot exceed total_items") + + # Calculate delivery score and defect score + delivery_score = (on_time_deliveries / total_deliveries) * 100 + defect_score = ((total_items - defective_items) / total_items) * 100 + + # Calculate overall performance score + performance_score = (delivery_score + defect_score) / 2 + + return performance_score + + +if __name__ == "__main__": + doctest.testmod() diff --git a/solutions/check_coprime.py b/solutions/check_coprime.py new file mode 100644 index 000000000..30e8614ae --- /dev/null +++ b/solutions/check_coprime.py @@ -0,0 +1,53 @@ +"""Module to check if two numbers are relatively prime. + +This module defines a function to determine whether two numbers (Integer) are relatively +prime, meaning they have no common factors than 1. + +@author: Vahab +@Created: 11/01/2025 +""" + + +def check_coprime(first_integer: int, second_integer: int) -> bool: + """Check if two numbers are relatively prime. + + Two numbers are relatively prime when there + are no common factors other than 1 + + Parameters: + first_integer (int): The first number (must be a positive integer). + second_integer (int): The second number (must be a positive integer). + + + Returns: + bool: True if the numbers are relatively prime, False otherwise. + + Raises: + ValueError: If either of the inputs is not a positive integer. + TypeError: If either of the inputs is not an integer. + + >>> check_coprime(15, 28) + True + >>> check_coprime(8, 12) + False + >>> check_coprime(7, 9) + True + """ + + # Check if inputs are integers + if not isinstance(first_integer, int) or not isinstance(second_integer, int): + raise TypeError("Both inputs must be integers.") + + # Check if inputs are positive integers + if first_integer <= 0 or second_integer <= 0: + raise ValueError("Both numbers must be positive integers.") + + # Find the smaller of the two numbers + smaller = min(first_integer, second_integer) + + # Check for any common factors greater than 1 + for i in range(2, smaller + 1): + if first_integer % i == 0 and second_integer % i == 0: + return False + + return True diff --git a/solutions/find_highest_alpha_position.py b/solutions/find_highest_alpha_position.py new file mode 100644 index 000000000..c03ce0617 --- /dev/null +++ b/solutions/find_highest_alpha_position.py @@ -0,0 +1,52 @@ +"""Module for finding the highest alphabetical position in a text string. + +This module provides functionality to find the alphabetical position (1-26) +of the character that appears latest in the alphabet within a given text. + +@author: Musab Kaymak +@created: 01/09/2025 +""" + + +def find_highest_alpha_position(text: str) -> int: + """Find the alphabetical position of the latest alphabet character in text. + + Parameters: + text (str): The input text to analyze. Must contain at least one letter + and only contain English letters. Numbers and special characters are ignored. + + Returns: + int: The highest alphabetical position (1-26) found in the text. + 'a' is position 1, 'z' is position 26. + + Raises: + ValueError: If the text is empty or contains no letters. + ValueError: If the text contains non-ASCII letters. + + Examples: + >>> find_highest_alpha_position("flower") + 23 + >>> find_highest_alpha_position("apple") + 16 + >>> find_highest_alpha_position("ZEBRA") + 26 + """ + if not text: + raise ValueError("Input text cannot be empty") + + if not any(c.isalpha() for c in text): + raise ValueError("Input text must contain at least one letter") + + if not all(c.isascii() for c in text): + raise ValueError("Input text must contain only English characters") + + alphabet = "abcdefghijklmnopqrstuvwxyz" + max_position = 0 + + for char in text.lower(): + if char.isalpha(): + position = alphabet.index(char.lower()) + 1 + if position > max_position: + max_position = position + + return max_position diff --git a/solutions/fizzbuzz.py b/solutions/fizzbuzz.py new file mode 100644 index 000000000..74ccc54d1 --- /dev/null +++ b/solutions/fizzbuzz.py @@ -0,0 +1,67 @@ +""" +Module resolving FizzBuzz problem according to given rules. + +Module contents: + - fizzbuzz: take integer n and prints numbers from 1 to n + with the rules. + +Created: 01/04/2025 +Author: Svitlana Musiienko + +""" + + +def fizzbuzz(n: int) -> list: + """ + Fizzbuz function takes an integer n as input and prints the numbers + from 1 to n with the rules: + - if a number is divisible by 3, print 'Fizz' instead of the number; + - if a number is divisible by 5, print 'Buzz' instead of the number; + - if a number is divisible by both 3 and 5, print 'FizzBuzz'; + - otherwise, print the number itself. + + Parameters: integer number (n) + + Returns: return list of numbers from 1 to n where numbers + divisible by 3 and 5 are replaced with fizz and buzz and fizzbuzz + + Raises: + AssertionError: if the argument is not integer + AssertionError: if the argument is less than 0 + + Example: + + >>> fizzbuzz (0) + [] + + >>> fizzbuzz (5) + [1, 2, 'Fizz', 4, 'Buzz'] + + >>> fizzbuzz(15) + [1, 2, 'Fizz', 4, 'Buzz', 'Fizz', 7, 8, 'Fizz', 'Buzz', 11, 'Fizz', 13, 14, 'FizzBuzz'] + + """ + # the number should be an integer greater than 0 + assert isinstance(n, int) + # the number is less than 0 + assert n >= 0 + + result = [] + # loop through numbers from 1 to n + for num in range(1, n + 1): + # check if the number is divisible by both 3 and 5 + if num % 3 == 0 and num % 5 == 0: + # print "FizzBuzz" for multiples of both 3 and 5 + result.append("FizzBuzz") + # check if the number is divisible by 3 only + elif num % 3 == 0: + # print "Fizz" for multiples of 3 + result.append("Fizz") + # check if the number is divisible by 5 only + elif num % 5 == 0: + # print "Buzz" for multiples of 5 + result.append("Buzz") + # print the number if none of the above conditions are met + else: + result.append(num) + return result diff --git a/solutions/get_even_numbers.py b/solutions/get_even_numbers.py new file mode 100644 index 000000000..123f15b51 --- /dev/null +++ b/solutions/get_even_numbers.py @@ -0,0 +1,49 @@ +""" +Module for filtering even numbers from a list of integers. + +This module provides a function that takes a list of integers as input +and returns a list of all even numbers from the input list. + +@author: Vahab +@created: 01/11/2025 +""" + +from typing import List + + +def get_even_numbers(numbers: List[int]) -> List[int]: + """ + Filters even numbers from a list of integers. + + Parameters: + numbers (List[int]): A list of integers to filter. + + Returns: + List[int]: A list containing all even numbers from the input list. + + Raises: + TypeError: If the input is not a list or contains non-integer elements. + + Example: + >>> get_even_numbers([1, 2, 3, 4, 5, 6]) + [2, 4, 6] + >>> get_even_numbers([1, 3, 5]) + [] + >>> get_even_numbers([]) + [] + """ + # Check the input is a list + if not isinstance(numbers, list): + raise TypeError("Input must be a list.") + + # Check the list items are only integers + if not all(isinstance(n, int) for n in numbers): + raise TypeError("All elements in the list must be integers.") + + # Filters the even number from input list and store them in a list + return [n for n in numbers if n % 2 == 0] + + +if __name__ == "__main__": + example_input = [1, 2, 3, 4, 5, 6] + print(get_even_numbers(example_input)) diff --git a/solutions/get_prime_numbers.py b/solutions/get_prime_numbers.py new file mode 100644 index 000000000..cb2820dc4 --- /dev/null +++ b/solutions/get_prime_numbers.py @@ -0,0 +1,51 @@ +# prime_numbers.py + +""" +This module provides a function to find all prime numbers up to a given integer. + +Function: + - get_prime_numbers: Returns a list of prime numbers less than or equal to a given integer. +Created on: January 6, 2025 +@author: Melat Assefa +""" + +from typing import List + + +def get_prime_numbers(n: int) -> List[int]: + """ + Returns a list of all prime numbers less than or equal to the given integer. + + Parameters: + n (int): The upper limit integer to find prime numbers up to. + + Returns: + List[int]: A list of prime numbers less than or equal to n. + + Raises: + ValueError: If n is less than 2. + TypeError: If n is not an integer. + + Examples: + >>> get_prime_numbers(10) + [2, 3, 5, 7] + >>> get_prime_numbers(2) + [2] + >>> get_prime_numbers(1) + [] + """ + if not isinstance(n, int): + raise TypeError("Input must be an integer.") + if n < 2: + return [] + + primes = [] + for num in range(2, n + 1): + is_prime = True + for i in range(2, int(num**0.5) + 1): + if num % i == 0: + is_prime = False + break + if is_prime: + primes.append(num) + return primes diff --git a/solutions/pine_tree_art.py b/solutions/pine_tree_art.py new file mode 100644 index 000000000..8bf95f0f2 --- /dev/null +++ b/solutions/pine_tree_art.py @@ -0,0 +1,54 @@ +""" +Module for generating and displaying ASCII art of a pine tree. + +This module provides a function to create a visual representation of a pine tree +with customizable height and trunk dimensions. + +Author: fevziismailsahin +Created: 01/09/2025 +""" + + +def pine_tree_art(height: int = 10, trunk_width: int = 3, trunk_height: int = 3) -> str: + """ + Generate an ASCII art representation of a pine tree. + + Parameters: + height (int): The height of the tree (default is 10). + trunk_width (int): The width of the tree trunk (default is 3). + trunk_height (int): The height of the tree trunk (default is 3). + + Returns: + str: The generated ASCII art as a string. + """ + + # Type checks + if ( + not isinstance(height, int) + or not isinstance(trunk_width, int) + or not isinstance(trunk_height, int) + ): + raise TypeError("Height, trunk_width, and trunk_height must be integers") + + # Defensive assertions + if height <= 0: + raise ValueError("Height must be a positive integer") + if trunk_width <= 0: + raise ValueError("Trunk width must be a positive integer") + if trunk_height <= 0: + raise ValueError("Trunk height must be a positive integer") + + # Create the foliage of the tree + tree = [] + for i in range(height): + spaces = " " * (height - i - 1) # Add spaces for alignment (center the stars) + stars = "*" * (2 * i + 1) # Create the stars for the current level + tree.append(spaces + stars) # Append to tree list with correct alignment + + # Create the trunk of the tree + trunk = " " * (height - trunk_width // 2 - 1) + "|" * trunk_width # Centered trunk + for _ in range(trunk_height): + tree.append(trunk) + + # Return the tree as a single string with an extra newline at the end + return "\n".join(tree) + "\n" diff --git a/solutions/shipment_time_estimation.py b/solutions/shipment_time_estimation.py index e531a878d..657edca44 100644 --- a/solutions/shipment_time_estimation.py +++ b/solutions/shipment_time_estimation.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ -A module estimation of delivery time based on 2 arguments +A module estimation of delivery time based on 2 argument Module contents: - Calculates the estimated delivery time based on the distance and average speed. diff --git a/solutions/tests/test_calculate_supplier_performance_score.py b/solutions/tests/test_calculate_supplier_performance_score.py new file mode 100644 index 000000000..2afd0ac9b --- /dev/null +++ b/solutions/tests/test_calculate_supplier_performance_score.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Test module for Calculating the performance score of a supplier. + +Test categories: + - Standard cases: correct inputs for on_time_deliveries, total_deliveries, + defective_items, total_items; + - Edge cases; + - Defensive tests: wrong input types, assertions; + +Created on 2025-01-07 +Author: Idris Pamiri +""" + +import unittest + +from ..calculate_supplier_performance_score import calculate_supplier_performance_score + + +class TestCalculatingPerformanceScore(unittest.TestCase): + """Test suite for Calculating the performance score of a supplier.""" + + # Standard cases: correct inputs + def test_standard_case_1(self): + """Test with typical valid inputs for on-time deliveries, total deliveries, + defective items, and total items.""" + self.assertAlmostEqual( + calculate_supplier_performance_score(45, 50, 10, 100), 90.0 + ) + + def test_standard_case_2(self): + """Test with perfect performance: 100% on-time deliveries and defect-free items.""" + self.assertAlmostEqual( + calculate_supplier_performance_score(10, 10, 0, 20), 100.0 + ) + + def test_standard_case_3(self): + """Test with partial performance: some defective items and partial on-time deliveries.""" + self.assertAlmostEqual(calculate_supplier_performance_score(0, 10, 5, 20), 37.5) + + # Edge cases: testing zero or near-zero values + def test_zero_deliveries(self): + """Test when total deliveries is zero, which should raise a ValueError.""" + with self.assertRaises(ValueError): + calculate_supplier_performance_score(0, 0, 0, 10) + + def test_zero_items(self): + """Test when total items is zero, which should raise a ValueError.""" + with self.assertRaises(ValueError): + calculate_supplier_performance_score(5, 10, 1, 0) + + def test_full_performance(self): + """Test when all deliveries are on time and there are no defective item(s), + which should return a 100% score.""" + self.assertAlmostEqual( + calculate_supplier_performance_score(100, 100, 0, 100), 100.0 + ) + + def test_zero_performance(self): + """Test when all deliveries are late and defective, which should return a 0% score.""" + self.assertAlmostEqual(calculate_supplier_performance_score(0, 10, 10, 10), 0.0) + + # Defensive tests: wrong input types, assertions + def test_invalid_on_time_deliveries_type(self): + """Test when 'on_time_deliveries' is not an integer, which should + raise an AssertionError.""" + with self.assertRaises(AssertionError): + calculate_supplier_performance_score("five", 10, 2, 100) + + def test_invalid_total_deliveries_type(self): + """Test when 'total_deliveries' is not an integer, which should raise an AssertionError.""" + with self.assertRaises(AssertionError): + calculate_supplier_performance_score(10, "ten", 2, 100) + + def test_invalid_defective_items_type(self): + """Test when 'defective_items' is not an integer, which should raise an AssertionError.""" + with self.assertRaises(AssertionError): + calculate_supplier_performance_score(10, 10, "two", 100) + + def test_invalid_total_items_type(self): + """Test when 'total_items' is not an integer, which should raise an AssertionError.""" + with self.assertRaises(AssertionError): + calculate_supplier_performance_score(10, 10, 2, "hundred") + + def test_negative_on_time_deliveries(self): + """Test when 'on_time_deliveries' is negative, which should raise a ValueError.""" + with self.assertRaises(ValueError): + calculate_supplier_performance_score(-5, 10, 2, 100) + + def test_negative_defective_items(self): + """Test when 'defective_items' is negative, which should raise a ValueError.""" + with self.assertRaises(ValueError): + calculate_supplier_performance_score(10, 10, -2, 100) + + def test_on_time_deliveries_exceed_total_deliveries(self): + """Test when 'on_time_deliveries' exceeds 'total_deliveries', which should + raise a ValueError.""" + with self.assertRaises(ValueError): + calculate_supplier_performance_score(15, 10, 2, 100) + + def test_defective_items_exceed_total_items(self): + """Test when 'defective_items' exceeds 'total_items', which + should raise a ValueError.""" + with self.assertRaises(ValueError): + calculate_supplier_performance_score(10, 10, 120, 100) + + +if __name__ == "__main__": + unittest.main() diff --git a/solutions/tests/test_check_coprime.py b/solutions/tests/test_check_coprime.py new file mode 100644 index 000000000..0cd2afef5 --- /dev/null +++ b/solutions/tests/test_check_coprime.py @@ -0,0 +1,53 @@ +"""Tests for check_coprime function. + + +This module contains unit tests to ensure the check_coprime function works as expected, +including handling edge cases and defensive assertions. + +@author: Vahab +@created: 11/01/2025 +""" + +import unittest + + +from solutions.check_coprime import check_coprime + + +class TestCoprimeFunction(unittest.TestCase): + """Test cases for the check_coprime function.""" + + def test_coprime_true(self): + """Test case where the numbers are relatively prime.""" + self.assertTrue(check_coprime(15, 28)) + + def test_coprime_false(self): + """Test case where the numbers are not relatively prime.""" + self.assertFalse(check_coprime(8, 12)) + + def test_coprime_same_value(self): + """Test case where both numbers are the same and greater than 1.""" + self.assertFalse(check_coprime(12, 12)) + + def test_coprime_negative_input(self): + """Test case where negative numbers are provided.""" + with self.assertRaises(ValueError): + check_coprime(-5, 28) + + def test_coprime_non_integer_input(self): + """Test case where non-integer inputs are provided.""" + with self.assertRaises(TypeError): + check_coprime("15", 28) + + def test_coprime_large_numbers(self): + """Test case with large numbers to check performance.""" + self.assertTrue(check_coprime(1, 100)) + + def test_coprime_edge_case(self): + """Test case where one input is 0.""" + with self.assertRaises(ValueError): + check_coprime(0, 10) + + +if __name__ == "__main__": + unittest.main() diff --git a/solutions/tests/test_find_highest_alpha_position.py b/solutions/tests/test_find_highest_alpha_position.py new file mode 100644 index 000000000..051185ba7 --- /dev/null +++ b/solutions/tests/test_find_highest_alpha_position.py @@ -0,0 +1,60 @@ +"""Tests for the find_highest_alpha_position function. + +@author: Musab Kaymak +@created: 01/09/2025 +""" + +import unittest + +from solutions.find_highest_alpha_position import find_highest_alpha_position + + +class TestFindHighestAlphaPosition(unittest.TestCase): + """Test cases for the find_highest_alpha_position function.""" + + def test_simple_word(self): + """Test with a simple lowercase word.""" + self.assertEqual(find_highest_alpha_position("flower"), 23) + + def test_uppercase_word(self): + """Test with an uppercase word.""" + self.assertEqual(find_highest_alpha_position("ZEBRA"), 26) + + def test_mixed_case_word(self): + """Test with a mixed case word.""" + self.assertEqual(find_highest_alpha_position("PyThOn"), 25) + + def test_single_letter(self): + """Test with a single letter.""" + self.assertEqual(find_highest_alpha_position("a"), 1) + + def test_with_spaces(self): + """Test with text containing spaces.""" + self.assertEqual(find_highest_alpha_position("hello world"), 23) + + def test_with_numbers(self): + """Test with text containing numbers.""" + self.assertEqual(find_highest_alpha_position("hello123"), 15) + + def test_with_special_characters(self): + """Test with text containing special characters.""" + self.assertEqual(find_highest_alpha_position("hello!@#"), 15) + + def test_empty_string(self): + """Test that empty string raises ValueError.""" + with self.assertRaises(ValueError, msg="Input text cannot be empty"): + find_highest_alpha_position("") + + def test_no_letters(self): + """Test that string with no letters raises ValueError.""" + with self.assertRaises( + ValueError, msg="Input text must contain at least one letter." + ): + find_highest_alpha_position("123") + + def test_non_english_characters(self): + """Test that non-English characters raise ValueError.""" + with self.assertRaises( + ValueError, msg="Input text must contain only English characters." + ): + find_highest_alpha_position("héllo") diff --git a/solutions/tests/test_fizzbuzz.py b/solutions/tests/test_fizzbuzz.py new file mode 100644 index 000000000..f83404f14 --- /dev/null +++ b/solutions/tests/test_fizzbuzz.py @@ -0,0 +1,71 @@ +""" +Module represents unit test for fizzbuzz_challenge + +Created on 01/05/2024 +Author Svitlana Musiienko +""" + +import unittest + +from ..fizzbuzz import fizzbuzz + + +class TestFizzBuzz(unittest.TestCase): + """Test the fizzbuzz function""" + + def test_fizz(self): + """Check the numbers which are devisable by 3""" + actual = fizzbuzz(6) + expected = [1, 2, "Fizz", 4, "Buzz", "Fizz"] + self.assertEqual(actual, expected) + + def test_buzz(self): + """Check the numbers which are devisable by 5""" + actual = fizzbuzz(10) + expected = [1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz"] + self.assertEqual(actual, expected) + + def test_fizzbuzz(self): + """Check the numbers which are devisable both by 3 and 5""" + actual = fizzbuzz(15) + expected = [ + 1, + 2, + "Fizz", + 4, + "Buzz", + "Fizz", + 7, + 8, + "Fizz", + "Buzz", + 11, + "Fizz", + 13, + 14, + "FizzBuzz", + ] + self.assertEqual(actual, expected) + + def test_other(self): + """Check the numbers which are not devisable by 3 or 5 or both""" + actual = fizzbuzz(2) + expected = [ + 1, + 2, + ] + self.assertEqual(actual, expected) + + def test_less_than_0(self): + """Check the assertion error if the numbers less than 0""" + with self.assertRaises(AssertionError): + fizzbuzz(-1) + + def test_not_an_integer(self): + """Check the assertion error if the argument is not integer""" + with self.assertRaises(AssertionError): + fizzbuzz(2.0) + + +if __name__ == "__main__": + unittest.main() diff --git a/solutions/tests/test_get_even_numbers.py b/solutions/tests/test_get_even_numbers.py new file mode 100644 index 000000000..a2ffde8fd --- /dev/null +++ b/solutions/tests/test_get_even_numbers.py @@ -0,0 +1,64 @@ +""" +Unit tests for get_even_numbers function. + +@created: 01/11/2025 +@author: Vahab +""" + +import unittest + +from solutions.get_even_numbers import get_even_numbers + + +class TestGetEvenNumbers(unittest.TestCase): + """ + Tests for the get_even_numbers function. + """ + + def test_basic_functionality(self): + """ + Test: Check if the function returns the correct even numbers from a list. + """ + self.assertEqual(get_even_numbers([1, 2, 3, 4, 5, 6]), [2, 4, 6]) + + def test_no_even_numbers(self): + """ + Test: Check if the function returns an empty list when no even numbers are present. + """ + self.assertEqual(get_even_numbers([1, 3, 5]), []) + + def test_empty_list(self): + """ + Test: Check if the function handles an empty list correctly. + """ + self.assertEqual(get_even_numbers([]), []) + + def test_negative_numbers(self): + """ + Test: Check if the function correctly identifies even negative numbers. + """ + self.assertEqual(get_even_numbers([-1, -2, -3, -4]), [-2, -4]) + + def test_large_numbers(self): + """ + Test: Check if the function handles large numbers correctly. + """ + self.assertEqual(get_even_numbers([10**6, 10**9 + 1]), [10**6]) + + def test_invalid_input_not_list(self): + """ + Test: Check if the function raises a TypeError for non-list inputs. + """ + with self.assertRaises(TypeError): + get_even_numbers("not a list") + + def test_invalid_input_non_integer_elements(self): + """ + Test: Check if the function raises a TypeError for lists with non-integer elements. + """ + with self.assertRaises(TypeError): + get_even_numbers([1, 2, "three", 4]) + + +if __name__ == "__main__": + unittest.main() diff --git a/solutions/tests/test_get_prime_numbers.py b/solutions/tests/test_get_prime_numbers.py new file mode 100644 index 000000000..d4f67a400 --- /dev/null +++ b/solutions/tests/test_get_prime_numbers.py @@ -0,0 +1,59 @@ +# tests/test_prime_numbers.py + +""" +Unit tests for the get_prime_numbers function. +This test suite includes: +- Regular cases: Typical inputs that the function is expected to handle. +- Edge cases: Inputs that are at the boundary of what the function should handle. +- Error cases: Inputs that should raise exception due to invalid input. + +Created on: January 6, 2025 +@author: Melat Assefa +""" + +import unittest +from solutions.get_prime_numbers import get_prime_numbers + + +class TestGetPrimeNumbers(unittest.TestCase): + """Test cases for the get_prime_numbers function.""" + + # Regular Cases + def test_primes_up_to_10(self): + """Regular case: Test that the function returns correct primes up to 10.""" + self.assertEqual(get_prime_numbers(10), [2, 3, 5, 7]) + + def test_primes_up_to_2(self): + """Regular case: Test that the function returns correct primes up to 2.""" + self.assertEqual(get_prime_numbers(2), [2]) + + # Edge Cases + def test_no_primes_below_2_for_1(self): + """Edge case: Test that the function returns an empty list for n = 1.""" + self.assertEqual(get_prime_numbers(1), []) + + def test_no_primes_below_2_for_0(self): + """Edge case: Test that the function returns an empty list for n = 0.""" + self.assertEqual(get_prime_numbers(0), []) + + def test_no_primes_below_2_for_negative(self): + """Edge case: Test that the function returns an empty list for negative n.""" + self.assertEqual(get_prime_numbers(-5), []) + + def test_large_number(self): + """Edge case: Test the function with a larger number.""" + self.assertEqual(get_prime_numbers(20), [2, 3, 5, 7, 11, 13, 17, 19]) + + # Error Cases + def test_non_integer_input_raises_type_error(self): + """Error case: Test that the function raises a TypeError for non-integer input.""" + with self.assertRaises(TypeError): + get_prime_numbers("ten") + with self.assertRaises(TypeError): + get_prime_numbers(5.5) + with self.assertRaises(TypeError): + get_prime_numbers(None) + + +if __name__ == "__main__": + unittest.main() diff --git a/solutions/tests/test_pine_tree_art.py b/solutions/tests/test_pine_tree_art.py new file mode 100644 index 000000000..cc91aee1d --- /dev/null +++ b/solutions/tests/test_pine_tree_art.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Unit test module for generating ASCII art of a pine tree. + +Test categories: + - Standard cases: correct inputs for height, trunk_width, trunk_height; + - Edge cases; + - Defensive tests: wrong input types, assertions; + +Created on 2025-01-11 +Author: fevziismailsahin +""" + +import unittest + +from ..pine_tree_art import pine_tree_art + + +class TestPineTreeArt(unittest.TestCase): + """Test suite for generating ASCII art of a pine tree.""" + + # Standard cases: correct inputs + def test_standard_case_1(self): + """Test with typical valid inputs for height, trunk_width, trunk_height.""" + expected_result = ( + " *\n" + " ***\n" + " *****\n" + " *******\n" + " *********\n" + " ***********\n" + " *************\n" + " ***************\n" + " *****************\n" + "*******************\n" + " |||\n" + " |||\n" + " |||\n" + ) + self.assertEqual(pine_tree_art(10, 3, 3), expected_result) + + def test_standard_case_2(self): + """Test with smaller tree height and trunk dimensions.""" + expected_result = ( + " *\n ***\n *****\n *******\n*********\n |||\n |||\n |||\n" + ) + self.assertEqual(pine_tree_art(5, 3, 3), expected_result) + + # Edge cases: testing zero or near-zero values + def test_zero_height(self): + """Test when height is zero, which should raise a ValueError.""" + with self.assertRaises(ValueError): + pine_tree_art(0, 3, 3) + + def test_zero_trunk_width(self): + """Test when trunk width is zero, which should raise a ValueError.""" + with self.assertRaises(ValueError): + pine_tree_art(10, 0, 3) + + def test_zero_trunk_height(self): + """Test when trunk height is zero, which should raise a ValueError.""" + with self.assertRaises(ValueError): + pine_tree_art(10, 3, 0) + + # Defensive tests: wrong input types, assertions + def test_invalid_height_type(self): + """Test when 'height' is not an integer, which should raise a TypeError.""" + with self.assertRaises(TypeError): + pine_tree_art("ten", 3, 3) + + def test_invalid_trunk_width_type(self): + """Test when 'trunk_width' is not an integer, which should raise a TypeError.""" + with self.assertRaises(TypeError): + pine_tree_art(10, "three", 3) + + def test_invalid_trunk_height_type(self): + """Test when 'trunk_height' is not an integer, which should raise a TypeError.""" + with self.assertRaises(TypeError): + pine_tree_art(10, 3, "three") + + +if __name__ == "__main__": + unittest.main() diff --git a/solutions/tests/test_shipment_time_estimation.py b/solutions/tests/test_shipment_time_estimation.py index f15ef7e1e..83352804b 100644 --- a/solutions/tests/test_shipment_time_estimation.py +++ b/solutions/tests/test_shipment_time_estimation.py @@ -60,7 +60,7 @@ def test_negative_speed(self): shipment_time_estimation(10, -5) def test_non_numeric_distance(self): - """It should raise an assertion error for non-numeric distance""" + """It should raise an assertion error for non-numeric distances""" with self.assertRaises(AssertionError): shipment_time_estimation("ten", 10)