diff --git a/README.md b/README.md index e69de29bb..e3cd496a7 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,30 @@ +# 👋 Welcome: This is ⚡`PyRectifiers`⚡Group + +🚀 **"Alone we can do so little; together, we can achieve so much."** + +## We made this repository to practice what we learn in the `MIT Foundational Track` + +``` text +💡 Our Vision: +To collaborate, innovate, and deliver impactful solutions. +This repository serves as our central hub for all documentation, +project discussions, and code contributions. +``` + +### ⭐ Key Objectives + +* Contribute meaningful 2 challenges at least, and review peers' +code for continuous improvements. + +### 📂 Repository Structure + +* **`main`**: The primary branch containing stable and reviewed code. +* **`collaboration/`**: Contain our group's learning goals, constrains, and + scheduling our team's meeting. +* **`notes/`**: Project's and team's notes. +* **`solutions/`**: Python solutions and corresponding test files for coding challenges. + +### ✨ Our Journey + +Our team's key insights, learnings, and collaborative decision-making processes: +Documented all in [`collaboration/`](https://github.com/MIT-Emerging-Talent/ET6-foundations-group-25/tree/main/collaboration) diff --git a/collaboration/README.md b/collaboration/README.md index 20889b951..fee753ff9 100644 --- a/collaboration/README.md +++ b/collaboration/README.md @@ -1,5 +1,43 @@ -# Collaboration +# 🐍 We're the PyRectifiers 🛠️ - +## *We're here to rectify your Pythons!* - +--- + +## 📜 Group Norms + +### ⏰ Respecting Each Other’s Time + +- **Meetings** will be scheduled **at least one day a week**. +- **Additional Meetings** will be scheduled **48-hours** beforehand. +- 🗳️ **Meeting times** will be voted on in Slack the day before. + +### 📡 Communication + +- **Maintain communication** on Slack—let’s keep the discussions flowing! 💬 +- Feel free to **ask for help**; we’re here to support each other! 🙌 + +### 🗓️ Meetings + +- **Prepare for meetings** with pre-defined agendas beforehand. +- **Use Google Meet** for a smoother meeting experience. 🎥 +- **Weekly milestones** will help us track progress. 🏁 +- **Internal milestone** will be Jan. 7 ⏱ + +### 🏗️ Repository Management + +- Follow **naming conventions** for challenges that reflect their behavior. +- Preferably, the branches/issues will be named as *"GP25_challenge-name"* +- Choose **1 or 2 people** to handle repository updates to ensure consistency. + +### 🔧 Collaboration Tips + +- Stay **active on Slack** to stay in the loop and contribute effectively. 🖇️ +- Let’s make meetings productive and focused to avoid unnecessary delays. + +--- + +## 🤝 Together, We’ll Rectify Pythons! 🐍✨ + +With great communication, preparation, and teamwork? +We’ll keep things rectified—just like PyRectifiers should! 🎉 diff --git a/collaboration/communication.md b/collaboration/communication.md index 484652e0f..62ed14d36 100644 --- a/collaboration/communication.md +++ b/collaboration/communication.md @@ -1,54 +1,69 @@ - +## Communication Schedule -# Communication +| Day | How | The topic of discussion | +|------------|------------------|-----------------------------------------------| +| All | Slack | Various discussions | +| Sunday | Zoom/Google Meet | Introducing ourselves; Discussing Group Norms | +|(22/12/2024)| | | +| Tuesday | Google Meet | Discussing the Challenges (with a Demo) | +|(24/12/2024)| | | +| Friday |Google Meet | Discussing the Collaboration Documents, | +|(27/12/2024)| | assigning members, discussing the Challenges, | +| | | and working on the repository | +| Thursday | Google Meet | Discussing the work progress | +|(02/01/2025)| | | ______________________________________________________________________ -## Communication Schedule +## Communication Channels -| Day | How | The topic of discussion | | --- | :-: | ----------------------- | -| | | | +How often will we get in touch on each channel, and what we will discuss there: -## Communication Channels +- **Issues**: + - **Frequency**: As needed. + - **Purpose**: To track tasks, assign the responsibilities, and report the bugs. -how often will we get in touch on each channel, and what we will discuss there: +- **Pull Requests**: + - **Frequency**: Daily. + - **Purpose**: To share the codes and documents, review the contributions, + and approve changes. -- **Issues**: -- **Pull Requests**: -- **Slack/Discord**: -- **Video Calls**: +- **Slack**: + - **Frequency**: Daily. + - **Purpose**: To ask questions and provide answers, and to update the group members + on the work and the meetings. + +- **Video Calls**: + - **Frequency**: As discussed (often, twice a week). + - **Purpose**: To discuss the collaborative work in detail, and to organize + and plan the upcoming steps and future work. ______________________________________________________________________ ## Availability ### Availability for calling/messaging - -| Day | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday | | ------- | :----: | :-----: | :-------: | :------: | :----: | :------: | :----: | -| _name_ | | | | | | | | + +| Days | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday | +|-------------------------|:-------:|:--------:|:----------:|:---------:|:-------:|:---------:|:-------:| +| Amin Abd Elraheem | 9am-2pm | 9am-2pm | 9am-2pm | 9am-2pm | 9am-2pm | 9am-2pm | 9am-2pm | +| Mohamed Saeed | 9am-3pm | 9am-3pm | 9am-3pm | 9am-3pm | 9am-3pm | 9am-3pm | 9am-3pm | +| Name | ... | ... | ... | ... | ... | ... | ... | ### How many hours everyone has per day -- name: _5h_; -- name: _6h_; -- name: _5h_; -- name: _4h_; -- name: _3h_; +- Amin Abd Elraheem: _5hrs_ +- Mohamed Saeed: _6hrs_ +- Name: _...hrs_ ## Asking for Help -There's a fine line between confidently learning from your mistakes, and -stubbornly getting no where. Here is a general guide for when to ask for help -based on how long you've been stuck on the same problem: +There's a fine line between confidently learning from your mistakes, +and stubbornly getting nowhere. Here is a general guide for when to +ask for help based on how long you've been stuck on the same problem: -1. _0 -> 30 min_: Try on your own -1. _30 -> 60 min_: Ask your group for help -1. _60+ min_: Tag your coaches in Slack or GitHub +1. **0 -> 30 min**: Try on your own. +2. **30 -> 60 min**: Ask your group for help. +3. **60+ min**: Tag your coaches in Slack or GitHub. diff --git a/collaboration/constraints.md b/collaboration/constraints.md index 24079505c..173d80155 100644 --- a/collaboration/constraints.md +++ b/collaboration/constraints.md @@ -1,34 +1,62 @@ - # Constraints -Some boundaries around our project. +--- + +This file reflects some boundaries and challenges that may face our group and project ## External - +These are constraints coming from the outside and we (as a team) +have no control over, for example: + +- **Project deadlines** + - The project must be completed within 3 weeks, with a clear + deadline for each deliverable. +- **Programming Language: Python** + - Python will be used to build the project. No other languages + or frameworks will be used. +- **Version Control with GitHub:** + - The code related to the project has to be pushed to the GitHub + repository And pull requests should be reviewed before merging. +- **Testing Framework: Unittest** + - For testing purposes, the project will use unittest for Python. + And no other testing libraries or frameworks will be introduced. +- **Documentation Standards:** + - During the project, all code should have clear and concise + documentation (using docstrings). +- **Team Size:** + - A team of 10 members will work on this project. + All members will be expected to collaborate. ## Internal: Involuntary - +These are constraints that come from within our team and we have no +control over but we can work on mitigating them: + +- **Skills level:** + - Team members have different levels of experience and + familiarity with programming, Git&GitHub. + +- **amount of time available to work on the project** + - Due to work or life responsibilities, each team member + has a different amount of time that he can use to work on this project. +- **Communication issues** ## Internal: Voluntary - +These are the types of constraints that we’ve decided on to help scope the project. +They include: + +- coding style & conventions +- Follow the code review checklist for the project repository +- The number of hours you want to spend working +- Agreed to use Slack as the main communication channel +- Agreed to use Google Meet for meetings +- We may share the insights or challenges that we faced during problem-solving + to help others learn and reduce the potential time that may be wasted on debugging +- Meeting Frequency and Duration: + - Group meetings should be held at least once a week for up to 1 hour. That said, + team availability will factor into scheduling and it’s expected that all team + members will participate. +- Agreed on completing any outstanding tasks by **January** the **7th**. diff --git a/collaboration/learning_goals.md b/collaboration/learning_goals.md index 11c583d2b..eff08ad7d 100644 --- a/collaboration/learning_goals.md +++ b/collaboration/learning_goals.md @@ -1,5 +1,93 @@ # Learning Goals -## Collective +Our learning goals are categorized into two main areas: Focuses on Collective +Goals, that is improving together as a team and Individual Goals helping +individual areas of growth based on the aspirations of each member. This +structured approach guarantees both group development and individual development -## Individual +## Collective Learning Goals + +Together we seek to build a collaborative development environment where we +sharpen our technical and communication skills. Through practice and continuous +learning, we aim to develop a strong foundation in software development and Python +programming. Below are our key focus areas as a collective: + +1. Collaborative Development Skills + + - Develop effective collaboration practices through GitHub workflows, including: + - **Issues**: Creating, tracking, and assigning tasks. + - **Pull Requests (PRs)**: Submitting, reviewing, and merging pull + requests to ensure code quality. + - **Merging**: Understanding different merge strategies and resolving conflicts. + - **Projects**: Organizing tasks and milestones using GitHub Projects + for visual tracking. + - **Branching**: Managing branches effectively to keep the repository + clean and organized. + - **GitHub CLI**: Managing repositories, pull requests, and issues from + the terminal. + +2. Effective Communication + + - Enhance communication skills within the team through: + - **Slack**: Using Slack for group communication. + - **Regular Meetings**: Actively participating in group meetings and + discussions to ensure alignment on goals and progress. + - **Feedback and Collaboration**: Providing and receiving constructive + feedback in both code reviews and team discussions. + +3. Unit Testing + + - Learn and integrate unit testing in Python using the `unittest` module. + +4. Code Review Process + + - Develop an understanding of an effective code review process, including + giving and receiving constructive feedback to improve code quality. + +5. Efficient Development Practices + + - Focus on becoming more efficient developers by improving workflows, + debugging techniques, and programming skills. + +6. Python Programming + + - Strengthen Python programming skills by: + - Writing efficient and well-documented Python code. + +7. Docstring Documentation + + - Learning the art of writing clear and concise docstrings to document code effectively. + +## Individual Learning Goals + +### *Alexander Andom* + +- *Learn New Data Structures*: Learn and implement new data structures that are +unfamiliar or challenging. +- *Improve Debugging Skills*: Develop strategies for debugging code and +resolving issues more efficiently. +- *Deepen Knowledge of Testing Frameworks*: Learn to use `unittest` in Python +to write solid and detailed unit tests. + +### *Mohamed Saeed* + +- Mastering GitHub +- To foster my programming skills +- Improve my debugging skills + +### *Amin Abd Elraheem* + +- To Understand how to plan and execute projects on GitHub. +- Transform Ideas into Programs + +### *Kefah Albashityalshaer* + +- Improve my programming skills in Python, especially in writing unit test programs +- Mastering Code Review, making PRs, and the other GitHub teams' tasks. +- Improve my communication with the team. + +### *Tamir El-Waleed* + +- Improve my testing skills, in addition to mastering basic Git & Github behavior. +- Create a complete project from scratch, building my portfolio in the process. + \ No newline at end of file diff --git a/solutions/anagram_checker.py b/solutions/anagram_checker.py new file mode 100644 index 000000000..ee7da6c49 --- /dev/null +++ b/solutions/anagram_checker.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +A module to check if two strings are anagrams of each other. + +Module contents: + - anagram_checker: Function to check if two strings are anagrams of each other. + +Created on 01/01/2025 +@author: Mohamed Saeed + +""" + + +def anagram_checker(s1: str, s2: str) -> bool: + """ + Function to check if two strings are anagrams of each other. + + An anagram is a word or phrase formed by rearranging the letters of a different + word or phrase, typically using all the original letters exactly once. + + Parameters: + s1 (str): The first input string. + s2 (str): The second input string. + + Returns: + bool: True if the strings are anagrams, False otherwise. + + Raises: + assertionError: If the inputs are not strings. + + + Examples: + >>> anagram_checker("listen", "silent") + True + >>> anagram_checker("hello", "world") + False + >>> anagram_checker("rail safety", "fairy tales") + True + """ + assert isinstance(s1, str), "Input must be a string" + assert isinstance(s2, str), "Input must be a string" + assert len(s1) == len(s2), "Strings must have the same length." + + is_anagram = sorted(s1.replace(" ", "").lower()) == sorted( + s2.replace(" ", "").lower() + ) + return is_anagram diff --git a/solutions/binary_search.py b/solutions/binary_search.py new file mode 100644 index 000000000..d04434084 --- /dev/null +++ b/solutions/binary_search.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +A module for performing binary search on a sorted list. + +Binary Searching is a searching algorithm used in a sorted array by repeatedly dividing the search +interval in half. It works by repeatedly dividing the search interval in half until the target value +is found or the interval is empty.. + +Module contents: + - binary_search(arr, item, start, end): Searches for an item in a sorted list + within a specified range using the binary search algorithm. + +Created on 2025-01-02 +@author: Alexander Andom +""" + + +def binary_search(arr: list[int], item: int, start: int, end: int): + """ + Perform binary search to find the index of an item in a sorted list. + + Parameters: + arr : list[int], A sorted list of integers to search within. + item : int, The target item to search for. + start : int, The starting index of the search range. + end : int, The ending index of the search range. + + Returns: + int: The index of the item if found; otherwise, -1. + + Raises: + AssertionError: + - If 'arr' is not a list. + - If 'item' is not an integer. + - If 'start' or 'end' are not integers or are negative. + - If the input list is not sorted in ascending order. + + Example: + >>> arr = [1, 2, 3, 4, 5] + >>> binary_search(arr, 3, 0, len(arr) - 1) + 2 + + >>> binary_search(arr, 6, 0, len(arr) - 1) + -1 + + >>> binary_search(arr, 1, 0, len(arr) - 1) + 0 + """ + + assert isinstance(arr, list), "Input 'arr' must be a list." + assert isinstance(item, int), "Input 'item' must be an integer." + assert isinstance(start, int), "Input 'start' must be an integer." + assert start >= 0, "Input 'start' must be greater than or equal to 0." + assert isinstance(end, int), "Input 'end' must be an integer." + assert end >= 0, "Input 'end' must be greater than or equal to 0." + assert arr == sorted(arr), "Input list must be sorted." + + if len(arr) < 1 or end < 0 or start < 0: + return -1 + if start > end: + return -1 + mid = start + (end - start) // 2 + if item == arr[mid]: + return mid + if item < arr[mid]: + return binary_search(arr, item, start, mid - 1) + + return binary_search(arr, item, mid + 1, end) diff --git a/solutions/count_capitalized_words.py b/solutions/count_capitalized_words.py new file mode 100644 index 000000000..ff1c5f3a2 --- /dev/null +++ b/solutions/count_capitalized_words.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +A module for counting the words that begin with a capital letter (an uppercase letter) in a string. + +Module contents: + - count_capitalized_words: counts the words that begin with an uppercase letter in a string. + +Created on 05/01/2025 +@author: Amin +""" + + +def count_capitalized_words(text: str) -> int: + """Count the number of words that begin with an uppercase letter in a string. + + Parameters: + text: str, the input string to check + + Returns -> int: the number of words beginning with a capital letter in the text + + Raises: + AssertionError: if the argument is not a string + + >>> count_capitalized_words("word") + 0 + >>> count_capitalized_words("One more") + 1 + >>> count_capitalized_words("A B C") + 3 + """ + assert isinstance(text, str), "input must be a string" + + count = 0 + # Transform the original text into a list by splitting it + words = text.split() + # Loop through each element and count the capitalized words by checking the first letter + for i in words: + if i[0] == i[0].upper(): + count += 1 + return count diff --git a/solutions/is_leap_year.py b/solutions/is_leap_year.py new file mode 100644 index 000000000..584599079 --- /dev/null +++ b/solutions/is_leap_year.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +A module for determining if a year is a leap year. + +Module contents: + - is_leap_year(year): Determines if a year is a leap year. + +Leap year rules: + - A year is a leap year if it is divisible by 4. + - However, years divisible by 100 are not leap years , unless it is divisible by 400. + +Created on 2025-01-01 +@author: Alexander Andom +""" + + +def is_leap_year(year: int) -> bool: + """Check if a given year is a leap year. + + Parameters: + year : int, The year to check. + + Returns: + bool: True if the year is a leap year, False otherwise. + + Raises: + AssertionError: + - If 'year' is not an integer. + - If 'year' is less than 1583. + + Example: + >>> is_leap_year(2000) + True + + >>> is_leap_year(1900) + False + + >>> is_leap_year(2024) + True + """ + + assert isinstance(year, int), "year must be an integer" + assert year >= 1583, ( + "year must be greater than or equal to 1583 (1582 is start of Gregorian Calendar)" + ) + + return (year % 4 == 0) and (year % 100 != 0 or year % 400 == 0) diff --git a/solutions/is_palindrome.py b/solutions/is_palindrome.py new file mode 100644 index 000000000..5dc413355 --- /dev/null +++ b/solutions/is_palindrome.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +A module for checking if a string is a palindrome. + +A palindrome is a string that reads the same forwards and backwards,ignoring case and spaces. + +Module contents: + - is_palindrome(s): checks if a string is a palindrome. + +Created on 2024-01-01 +@author: Alexander Andom +""" + + +def is_palindrome(s: str) -> bool: + """ + Checks if the given string is a palindrome. + + Parameters: + s : str, The string to check. + + Returns: + bool: True if the string is a palindrome, False otherwise. + + Raises: + AssertionError: If the input is not a string. + + Examples: + >>> is_palindrome('madam') + True + + >>> is_palindrome('A man a plan a canal Panama') + True + + >>> is_palindrome('hello') + False + """ + + assert isinstance(s, str), "Input must be a string." + + s = s.replace(" ", "").lower() + return s == s[::-1] diff --git a/solutions/longest_substring.py b/solutions/longest_substring.py new file mode 100644 index 000000000..f5973d4b5 --- /dev/null +++ b/solutions/longest_substring.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +A module for finding the longest substring without repeating characters + +Module contents: + - longest_substring: Function to find the longest substring without repeating characters. + +Created on 2025-1-1 +@author: Mohamed Saeed + +""" + + +def longest_substring(s: str) -> str: + """ + Function to find the longest substring without repeating characters. + + Parameters: + s (str): The input string. + + Returns: + str: The longest substring without repeating characters. + + Raises: + assertionError: If the input is not a string + ValueError: If the input string is empty. + + Examples: + + >>> longest_substring("abcabcbb") + 'abc' + >>> longest_substring("bbbbb") + 'b' + >>> longest_substring("pwwekew") + 'wek' + """ + assert isinstance(s, str), "Input must be a string" + if not s: + raise ValueError("Input string cannot be empty") + + longest = "" + for i in range(len(s)): + substring = "" + for j in range(i, len(s)): + if s[j] == " ": + continue + if s[j] in substring: + break + substring += s[j] + if len(substring) > len(longest): + longest = substring + return longest diff --git a/solutions/max_integer.py b/solutions/max_integer.py new file mode 100644 index 000000000..e21b3af1d --- /dev/null +++ b/solutions/max_integer.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +A module for obtaining max integer from a list. + +Module contents: + - max_integer: Returns maximum integer from a list of integers + +Created on 2025-01-08 +Author: Tamir Elwaleeed +""" + + +def max_integer(my_list: list) -> int: + """Returns the max integer in a list of integers + If the list is empty, the function returns None + + Parameters: + my_list: list, the list to find the max from + + Returns -> int: the max integer from the list + + Raises: + AssertionError: if input is not a list + AssertionError: if one of the elements isn't a number + + Examples: + >>> max_integer([1, 2, 3, 4, 5]) + 5 + >>> max_integer([-1, -4, -5]) + -1 + >>> max_integer([]) + None + """ + assert isinstance(my_list, list), "input must be a list" + + if len(my_list) == 0: + return None + result = my_list[0] + i = 1 + while i < len(my_list): + if my_list[i] > result: + result = my_list[i] + i += 1 + return result diff --git a/solutions/maximum_length.py b/solutions/maximum_length.py new file mode 100644 index 000000000..5789a2f38 --- /dev/null +++ b/solutions/maximum_length.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +A module to find the maximum length of the +concatenation of a subsequence of arr that has unique characters. + +Return the maximum possible length of s + +Module contents: + - maxLength: Function to get the Maximum Length of a Concatenated String with Unique Characters + - backtrack: Helper function to perform backtracking + +Created on 2024-01-12 +Author: Kefah Albashityalshaer +""" + + +def max_length(arr: list) -> int: + """ + Function to get the Maximum Length of a Concatenated String with Unique Characters + + Takes a list of strings and returns the max length of concatenated string with unique characters + + Parameters: + arr: list of stings elements to process + + Returns -> int: the maximum length + + Examples: + >>> max_length(["un","iq","ue"]) + 4 + >>> max_length(["cha","r","act","ers"]) + 6 + >>> max_length(["abcdefghijklmnopqrstuvwxyz"]) + 26 + >>> max_length(["a", "bb", "ccc"]) + 1 + >>> max_length([]) + 0 + """ + assert isinstance(arr, list), "input should be a list of strings" + + # Helper function to perform backtracking + def backtrack(index, current_string): + # If the current string has duplicate characters, return 0 + if len(current_string) != len(set(current_string)): + return 0 + + # Calculate the maximum length by trying to add each subsequent string + max_length = len(current_string) + for i in range(index, len(arr)): + max_length = max(max_length, backtrack(i + 1, current_string + arr[i])) + return max_length + + # Start the backtracking from index 0 and an empty string + return backtrack(0, "") diff --git a/solutions/min_integer.py b/solutions/min_integer.py new file mode 100644 index 000000000..9c8fda491 --- /dev/null +++ b/solutions/min_integer.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +A module for obtaining min integer from a list. + +Module contents: + - min_integer: Returns minimum integer from a list of integers + +Created on 2025-01-09 +Author: Tamir Elwaleeed +""" + + +def min_integer(my_list: list) -> int: + """Returns the min integer in a list of integers + If the list is empty, the function returns None + + Parameters: + my_list: list, the list to find the min from + + Returns -> int: the min integer from the list + + Raises: + AssertionError: if input is not a list + + Examples: + >>> min_integer([1, 2, 3, 4, 5]) + 1 + >>> min_integer([-1, -4, -5]) + -5 + >>> min_integer([]) + None + """ + assert isinstance(my_list, list), "input must be a list" + + if len(my_list) == 0: + return None + result = my_list[0] + i = 1 + while i < len(my_list): + if my_list[i] < result: + result = my_list[i] + i += 1 + return result diff --git a/solutions/missing_number.py b/solutions/missing_number.py new file mode 100644 index 000000000..386100103 --- /dev/null +++ b/solutions/missing_number.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" + +A module that determines which number is missing out of a list. + +Module contents: + - missing_number: finds the missing number from a list. + +created on 04/01/2025 +@author: Alaa Mohamed + +""" + + +def missing_number(nums: list, n: int) -> int: + """Finds the missing numbers out of a list. + + Parameters: + nums: list, starting with zero and of any length + n: int, nums length should be greater than or equal to zero + + Returns: + list: with the missing numbers. + + Raises: + AssertionError: if one of the arguments is invalid. + + Examples: + >>> missing_number([0, 2], 3) + [1, 3] + >>> missing_number([0, 1, 3], 5) + [2, 4, 5] + >>> missing_number([0, 2], 2) + [1] + + """ + assert isinstance(n, int) + assert n >= 0 + + full_set = set(range(n + 1)) + # The expected set of numbers is from 0 to n + + nums_set = set(nums) + # The actual set of numbers present in the 'nums' list + + missing = list(full_set - nums_set) + + return missing diff --git a/solutions/missing_numbers2.py b/solutions/missing_numbers2.py new file mode 100644 index 000000000..8153b0025 --- /dev/null +++ b/solutions/missing_numbers2.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +A module that returns a sorted list of the missing numbers in a string of integers + +Module contents: + - missing_numbers2: creates a list with all the missing integers. + +Created on 06/01/2025 +@author: Amin +""" + + +def missing_numbers2(nums_string: str) -> list: + """Find the missing numbers in a list of integers. + + Parameters: + nums_string: string, the input string containing the integers to be checked + + Returns -> list: the list of the missing integers in the input string + Raises: + AssertionError: if the argument is not a list of integers + >>> missing_numbers2("0 1") + [] + >>> missing_numbers2("0 2 3") + [1] + >>> missing_numbers2("0 4") + [1, 2, 3] + >>> missing_numbers2("3 1 7") + [2, 4, 5, 6] + """ + assert isinstance(nums_string, str), ( + "input must be a string containing integers separated by spaces" + ) + # Transform the original numbers string into a list by splitting it + nums_list = nums_string.split() + nums = [] + # Transform each element of the list from str into an integer + for i in nums_list: + num = int(i) + nums.append(num) + miss = [] + # Identify the maximal number in the list + maximum = nums[0] + for i in nums: + if i > maximum: + maximum = i + # Identify the minimal number in the list + minimum = nums[0] + for i in nums: + if i < minimum: + minimum = i + for num in range(minimum + 1, maximum): + if num not in nums: + miss.append(num) + return miss diff --git a/solutions/multiplication_table.py b/solutions/multiplication_table.py new file mode 100644 index 000000000..c8a485b64 --- /dev/null +++ b/solutions/multiplication_table.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +This module contains a function to generate a multiplication table. +module contents: + - multiplication_table: Function to generate a multiplication table from 1 up to n. + +created on 05/01/2025 #dd/mm/yyyy +@author: Mohamed Saeed +""" + + +def multiplication_table(number: int, length: int) -> list: + """ + Function to generate a multiplication table. + + A multiplication table is a table of numbers that shows the results of + multiplying two numbers together. + + Parameters: + number (int): The number to generate the multiplication table for. + length (int): The length or range of the multiplication table. + + Returns: + list: A list of integers representing the multiplication table. + + Raises: + assertionError: If the input number is not an integer. + assertionError: If the input length (range) is not an integer. + assertionError: If the input number is not a positive integer. + assertionError: If the input length (range) is not a positive integer. + ValueError: If the input number is too large. + ValueError: If the input range is too large. + + Examples: + >>> multiplication_table(1, 5) + [1, 2, 3, 4, 5] + >>> multiplication_table(5, 10) + [5, 10, 15, 20, 25, 30, 35, 40, 45, 50] + >>> multiplication_table(7, 3) + [7, 14, 21] + """ + max_upper_limit = 1000 + + assert isinstance(number, int), "Input number must be an integer" + assert isinstance(length, int), "Input length must be an integer" + assert number > 0, "Number input must be a positive integer" + assert length > 0, "length input must be a positive integer" + assert number is not None, "Number input must not be None" + assert length is not None, "length input must not be None" + if number > max_upper_limit: + raise ValueError("Input number is too large") + if length > max_upper_limit: + raise ValueError("Input length is too large") + + table = [] + for j in range(1, length + 1): + product = number * j + table.append(product) + return table diff --git a/solutions/prime_numbers.py b/solutions/prime_numbers.py new file mode 100644 index 000000000..7675f7971 --- /dev/null +++ b/solutions/prime_numbers.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" + +A module that determines whether a given number is a prime number. + +Module contents: + - prime_numbers: checks if the given number is a prime number. + +created on 04/01/2025 +@author: Alaa Mohamed + +""" + + +def prime_numbers(number: int) -> bool: + """ + Checks if the given number is a prime number. + A number is considered prime if it's only divisible by one and itself. + + + Parameters: + number: input must be an integer. + + Returns -> bool: True if the number is prime, False otherwise. + + Raises: + AssertionError: if the input is not an integer. + + Examples: + >>> prime_numbers(1) + False + >>> prime_numbers(2) + True + >>> prime_numbers(3) + True + """ + assert isinstance(number, int), "input must be an integer" + + if number <= 1: + return False + for i in range(2, number): + if number % i == 0: + return False + return True diff --git a/solutions/tests/test_anagram_checker.py b/solutions/tests/test_anagram_checker.py new file mode 100644 index 000000000..e6878f9b0 --- /dev/null +++ b/solutions/tests/test_anagram_checker.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" +test module for anagram_checker function. +Contains correct tests to help identify bugs in the implementation. + +Test categories: + - Standard cases: typical string inputs + - Edge cases: empty strings, equal strings + - Defensive tests: invalid inputs + +created on 2024-12-28 +author: Mohamed Saeed +""" + +import unittest + +from ..anagram_checker import anagram_checker + + +class TestAnagramChecker(unittest.TestCase): + """ + Test class for the anagram_checker function. + """ + + def test_standard_cases(self): + """ + Test the function with standard inputs. + """ + self.assertTrue(anagram_checker("listen", "silent")) + + def test_edge_cases(self): + """ + Test the function with edge inputs. + """ + self.assertFalse(anagram_checker("hello", "world")) + + def test_empty_strings(self): + """ + Test the function with empty strings. + """ + self.assertTrue(anagram_checker("", "")) + + def test_equal_strings(self): + """ + Test the function with equal strings. + """ + self.assertTrue(anagram_checker("hello", "hello")) + + def test_numbers_as_strings(self): + """ + Test the function with numbers as strings. + """ + self.assertTrue(anagram_checker("123", "321")) + + def test_special_characters(self): + """ + Test the function with special characters. + """ + self.assertTrue(anagram_checker("@#$!", "!@#$")) + + def test_combination(self): + """ + Test the function with a combination of numbers, letters, and special characters. + """ + self.assertTrue(anagram_checker("12@asd#$", "s@a#$12d")) + + def test_case_insensitive(self): + """ + Test the function with case-insensitive strings. + """ + self.assertTrue(anagram_checker("Rail safety", "Fairy tales")) + + def test_defensive_cases(self): + """ + Test the function with invalid inputs. + """ + with self.assertRaises(AssertionError): + anagram_checker(123, 456) + + def test_unequal_length(self): + """ + Test the function with unequal length strings. + """ + with self.assertRaises(AssertionError): + anagram_checker("hello", "worlds") diff --git a/solutions/tests/test_binary_search.py b/solutions/tests/test_binary_search.py new file mode 100644 index 000000000..f6143ddfa --- /dev/null +++ b/solutions/tests/test_binary_search.py @@ -0,0 +1,101 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +A module for testing the binary_search function.. + +Test cases include: + - Valid inputs: Searching for elements within a sorted list. + - Edge cases: Searching for elements at the start, middle, or end of the list. + - Non-existent elements: Searching for elements not in the list. + - Invalid inputs: Providing invalid ranges or unsorted input. + +Created on 2025-01-02 +@author: Alexander Andom +""" + +import unittest + +from ..binary_search import binary_search + + +class TestBinarySearch(unittest.TestCase): + """Test the binary_search function""" + + def test_search_existing_middle(self): + """It should return the index of the item in the middle""" + arr = [1, 2, 3, 4, 5] + self.assertEqual(binary_search(arr, 3, 0, len(arr) - 1), 2) + + def test_search_existing_start(self): + """It should return the index of the item at the start""" + arr = [1, 2, 3, 4, 5] + self.assertEqual(binary_search(arr, 1, 0, len(arr) - 1), 0) + + def test_search_existing_end(self): + """It should return the index of the item at the end""" + arr = [1, 2, 3, 4, 5] + self.assertEqual(binary_search(arr, 5, 0, len(arr) - 1), 4) + + def test_search_nonexistent(self): + """It should return -1 for an item not in the list""" + arr = [1, 2, 3, 4, 5] + self.assertEqual(binary_search(arr, 6, 0, len(arr) - 1), -1) + + def test_search_invalid_range(self): + """It should return -1 for an invalid range""" + arr = [1, 2, 3, 4, 5] + self.assertEqual(binary_search(arr, 3, 3, 2), -1) + + def test_search_empty_list(self): + """It should return -1 for an empty list""" + arr = [] + self.assertEqual(binary_search(arr, 1, 0, 0), -1) + + def test_search_single_element_found(self): + """It should return the index for a single-element list""" + arr = [3] + self.assertEqual(binary_search(arr, 3, 0, 0), 0) + + def test_search_single_element_not_found(self): + """It should return -1 for a single-element list when the item is not found""" + arr = [3] + self.assertEqual(binary_search(arr, 4, 0, 0), -1) + + def test_invalid_arr(self): + """It should raise an assertion error if arr is not a list.""" + with self.assertRaises(AssertionError): + binary_search("not_a_list", 3, 0, 5) + + def test_invalid_item(self): + """It should raise an assertion error if item is not an integer.""" + with self.assertRaises(AssertionError): + binary_search([1, 2, 3], "3", 0, 2) + + def test_invalid_start_type(self): + """It should raise an assertion error if start is not an integer.""" + with self.assertRaises(AssertionError): + binary_search([1, 2, 3], 2, "start", 2) + + def test_invalid_start_value(self): + """It should raise an assertion error if start is negative.""" + with self.assertRaises(AssertionError): + binary_search([1, 2, 3], 2, -1, 2) + + def test_invalid_end_type(self): + """It should raise an assertion error if end is not an integer.""" + with self.assertRaises(AssertionError): + binary_search([1, 2, 3], 2, 0, "end") + + def test_invalid_end_value(self): + """It should raise an assertion error if end is negative.""" + with self.assertRaises(AssertionError): + binary_search([1, 2, 3], 2, 0, -2) + + def test_unsorted_list(self): + """It should raise an assertion error if the list is unsorted.""" + with self.assertRaises(AssertionError): + binary_search([3, 1, 2], 2, 0, 2) + + +if __name__ == "__main__": + unittest.main() diff --git a/solutions/tests/test_count_capitalized_words.py b/solutions/tests/test_count_capitalized_words.py new file mode 100644 index 000000000..d3108d945 --- /dev/null +++ b/solutions/tests/test_count_capitalized_words.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +A module for testing the count_capitalized_words function. + +Test cases include: + - Strings with capitalized words. + - Strings without capitalized words. + - Edge cases: empty strings, single-character strings, strings with mixed cases. + - Invalid inputs: non-string values (e.g., integers or floats). + +Created on 05/01/2025 +@author: Amin +""" + +import unittest + +from ..count_capitalized_words import count_capitalized_words + + +class TestCountCapitalizedWords(unittest.TestCase): + """Test the count_capitalized_words function""" + + def test_empty_string(self): + """It should return 0 for an empty string""" + self.assertEqual(count_capitalized_words(""), 0) + + def test_single_uppercase_character_string(self): + """It should return 1 for a string that contain a single uppercase character""" + self.assertEqual(count_capitalized_words("A"), 1) + + def test_no_uppercase(self): + """It should return 0 for strings without words starting with uppercase""" + self.assertEqual(count_capitalized_words("yes"), 0) + + def test_all_capitalized(self): + """It should count all the words in the string""" + self.assertEqual(count_capitalized_words("A Capitalized Sentence"), 3) + + def test_mixed_case(self): + """It should handle strings with words of mixed characters""" + self.assertEqual(count_capitalized_words("Happy new year"), 1) + + def test_uppercase_not_the_first_letter(self): + """It should return 0 if there is and uppercase but not as the first letter of a word""" + self.assertEqual(count_capitalized_words("this is an eXample"), 0) + + def test_not_string(self): + """It should raise AssertionError for non-string input""" + with self.assertRaises(AssertionError): + count_capitalized_words(101) diff --git a/solutions/tests/test_is_leap_year.py b/solutions/tests/test_is_leap_year.py new file mode 100644 index 000000000..cc92d465d --- /dev/null +++ b/solutions/tests/test_is_leap_year.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +A module for testing the is_leap_year function. + +Test cases include: + - Valid leap years (e.g., divisible by 4 but not 100, or divisible by 400). + - Non-leap years (e.g., not divisible by 4, or divisible by 100 but not 400). + - Years outside the Gregorian calendar (e.g., before 1583). + - Invalid inputs (e.g., non-integer values). + +Created on 2025-01-01 +@author: Alexander Andom +""" + +import unittest + +from ..is_leap_year import is_leap_year + + +class TestIsLeapYear(unittest.TestCase): + """Test the is_leap_year function""" + + def test_leap_year_2000(self): + """Test for a leap year: 2000""" + self.assertTrue(is_leap_year(2000)) + + def test_non_leap_year_1900(self): + """Test for a non-leap year: 1900""" + self.assertFalse(is_leap_year(1900)) + + def test_leap_year_2024(self): + """Test for a leap year: 2024""" + self.assertTrue(is_leap_year(2024)) + + def test_non_leap_year_2023(self): + """Test for a non-leap year: 2023""" + self.assertFalse(is_leap_year(2023)) + + def test_leap_year_2400(self): + """Test for a leap year: 2400""" + self.assertTrue(is_leap_year(2400)) + + def test_non_leap_year_2100(self): + """Test for a non-leap year: 2100""" + self.assertFalse(is_leap_year(2100)) + + def test_invalid_input_string(self): + """Test for invalid input: string""" + with self.assertRaises(AssertionError): + is_leap_year("two thousand") + + def test_invalid_input_float(self): + """Test for invalid input: float""" + with self.assertRaises(AssertionError): + is_leap_year(2000.5) + + def test_year_below_1583(self): + """Test for a year below 1583 to raise AssertionError""" + with self.assertRaises(AssertionError): + is_leap_year(1500) + + +if __name__ == "__main__": + unittest.main() diff --git a/solutions/tests/test_is_palindrome.py b/solutions/tests/test_is_palindrome.py new file mode 100644 index 000000000..8a7b0332f --- /dev/null +++ b/solutions/tests/test_is_palindrome.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +A module for testing the is_palindrome function. + +Test cases include: + - Valid palindromes: strings that are palindromes. + - Invalid palindromes: strings that are not palindromes. + - Edge cases: empty strings, single-character strings, strings with mixed cases or spaces. + - Invalid inputs: non-string values (e.g., integers or floats). + +Created on 2024-01-01 +@author: Alexander Andom +""" + +import unittest + +from ..is_palindrome import is_palindrome + + +class TestIsPalindrome(unittest.TestCase): + """Test the is_palindrome function""" + + def test_valid_palindrome_1(self): + """It should return True""" + result = is_palindrome("madam") + self.assertTrue(result) + + def test_valid_palindrome_2(self): + """It should return True""" + result = is_palindrome("racecar") + self.assertTrue(result) + + def test_valid_palindrome_3(self): + """This is should return True""" + result = is_palindrome("A man a plan a canal Panama") + self.assertTrue(result) + + def test_invalid_palindrome(self): + """It should return False""" + result = is_palindrome("hello") + self.assertFalse(result) + + def test_edge_case_empty_string(self): + """It should return True""" + result = is_palindrome("") + self.assertTrue(result) + + def test_edge_case_single_character(self): + """It should return True""" + result = is_palindrome("a") + self.assertTrue(result) + + def test_edge_case_spaces(self): + """It should return True)""" + result = is_palindrome("a b c b a") + self.assertTrue(result) + + def test_edge_case_mixed_case(self): + """It should return True""" + result = is_palindrome("MadAm") + self.assertTrue(result) + + def test_non_palindrome_mixed_characters(self): + """Test for non-palindrome with mixed characters""" + self.assertFalse(is_palindrome("Hello, world!")) + + def test_invalid_input_integer(self): + """This should raise an AssertionError""" + with self.assertRaises(AssertionError): + is_palindrome(12321) + + def test_invalid_input_float(self): + """This should raise an AssertionError""" + with self.assertRaises(AssertionError): + is_palindrome(123.21) + + +if __name__ == "__main__": + unittest.main() diff --git a/solutions/tests/test_longest_substring.py b/solutions/tests/test_longest_substring.py new file mode 100644 index 000000000..60bf6d38b --- /dev/null +++ b/solutions/tests/test_longest_substring.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Test module for long_substring function. +Contains correct tests to help identify bugs in the implementation. + +Test categories: + - Standard cases: typical string inputs + - Edge cases: empty strings, equal + - Defensive tests: invalid inputs + +Created on 2025-1-1 +Author: Mohamed Saeed +""" + +import unittest + +from ..longest_substring import longest_substring + + +class TestFindLongest(unittest.TestCase): + """ + Test class for the longest_substring function. + """ + + def test_standard_case(self): + """ + Test the function with standard inputs. + """ + self.assertEqual(longest_substring("abcabcbb"), "abc") + + def test_single_character(self): + """ + Test the function with a single character. + """ + self.assertEqual(longest_substring("a"), "a") + + def test_same_characters(self): + """ + Test the function with a string of the same characters. + """ + self.assertEqual(longest_substring("aaaaa"), "a") + + def test_unique_characters(self): + """ + Test the function with a string of unique characters. + """ + self.assertEqual(longest_substring("qwertyuiop"), "qwertyuiop") + + def test_long_string(self): + """ + Test the function with a long string. + """ + self.assertEqual(longest_substring("mohammedosmanmusasaeed"), "edosman") + + def test_numbers(self): + """ + Test the function with numbers. + """ + self.assertEqual(longest_substring("1234156789"), "234156789") + + def test_numbers_and_characters(self): + """ + Test the function with numbers and characters. + """ + self.assertEqual(longest_substring("1234ab14cd56789"), "ab14cd56789") + + def test_string_with_spaces(self): + """ + Test the function with spaces. + """ + self.assertEqual(longest_substring("a b c d e f g h i"), "abcdefghi") + + def test_empty_case(self): + """ + Test the function with edge inputs. + """ + with self.assertRaises(ValueError): + longest_substring("") + + def test_special_characters(self): + """ + Test the function with special characters. + """ + self.assertEqual(longest_substring("!@#@$%&"), "#@$%&") + + def test_defensive_cases(self): + """ + Test the function with invalid inputs. + """ + with self.assertRaises(AssertionError): + longest_substring(123) diff --git a/solutions/tests/test_max_integer.py b/solutions/tests/test_max_integer.py new file mode 100644 index 000000000..7720d6b02 --- /dev/null +++ b/solutions/tests/test_max_integer.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Test module for max_integer function. + +Test categories: + - Standard cases: typical lists with different lengths + - Edge cases: empty lists, single elements, strings + - Defensive tests: wrong input types, assertions + +Created on 2025-01-08 +Author: Tamir Elwaleeed +""" + +import unittest +from ..max_integer import max_integer + + +class TestMaxInteger(unittest.TestCase): + """Define unittests for max_integer([..]).""" + + def test_ordered_list(self): + """Test an ordered list of integers.""" + ordered = [1, 2, 3, 4] + self.assertEqual(max_integer(ordered), 4) + + def test_unordered_list(self): + """Test an unordered list of integers.""" + unordered = [1, 2, 4, 3] + self.assertEqual(max_integer(unordered), 4) + + def test_max_at_begginning(self): + """Test a list with a beginning max value.""" + max_at_beginning = [4, 3, 2, 1] + self.assertEqual(max_integer(max_at_beginning), 4) + + def test_empty_list(self): + """Test an empty list.""" + empty = [] + self.assertEqual(max_integer(empty), None) + + def test_one_element_list(self): + """Test a list with a single element.""" + one_element = [7] + self.assertEqual(max_integer(one_element), 7) + + def test_floats(self): + """Test a list of floats.""" + floats = [1.53, 6.33, -9.123, 15.2, 6.0] + self.assertEqual(max_integer(floats), 15.2) + + def test_ints_and_floats(self): + """Test a list of ints and floats.""" + ints_and_floats = [1.53, 15.5, -9, 15, 6] + self.assertEqual(max_integer(ints_and_floats), 15.5) + + def test_string(self): + """Test a string.""" + string = "Brennan" + with self.assertRaises(AssertionError): + max_integer(string) + + def test_list_of_strings(self): + """Test a list of strings.""" + strings = ["Brennan", "is", "my", "name"] + self.assertEqual(max_integer(strings), "name") + + def test_empty_string(self): + """Test an empty string.""" + with self.assertRaises(AssertionError): + max_integer("") + + +if __name__ == "__main__": + unittest.main() diff --git a/solutions/tests/test_maximum_length.py b/solutions/tests/test_maximum_length.py new file mode 100644 index 000000000..e4b7b1d94 --- /dev/null +++ b/solutions/tests/test_maximum_length.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Test module for maximum_length function. + +Test categories: + - Standard cases: list of strings that may have unique or overlapping characters + - Edge cases: empty lists, strings with identical bounds or duplicate characters, substrings with repetitive letters + - Defensive tests: invalid inputs, assertions, or `TypeError` exceptions + +Created on 2024-01-12 +Author: Kefah Albashityalshaer +""" + +import unittest + +from ..maximum_length import max_length + + +class TestMaxLengthFunction(unittest.TestCase): + # Standard test cases + def test_basic_cases(self): + self.assertEqual( + max_length(["un", "iq", "ue"]), 4 + ) # "uniq" forms a concatenated string of length 4 + self.assertEqual( + max_length(["cha", "r", "act", "ers"]), 6 + ) # The longest concatenated string is "acters" (length 6) + self.assertEqual( + max_length(["abcdefghijklmnopqrstuvwxyz"]), 26 + ) # The string contains all unique lowercase letters (length 26) + + # Edge Cases + def test_empty_list(self): + self.assertEqual( + max_length([]), 0 + ) # No strings to concatenate, so the result is 0 + + def test_single_element(self): + self.assertEqual(max_length(["a"]), 1) + self.assertEqual(max_length(["abcdef"]), 6) + + def test_no_unique_concatenation(self): + self.assertEqual(max_length(["a", "bb", "ccc"]), 1) + + def test_repeated_characters(self): + self.assertEqual(max_length(["abc", "def", "abc"]), 6) + + def test_large_input(self): + arr = ["ab", "cd", "ef", "gh", "ij", "kl", "mnop"] + self.assertEqual(max_length(arr), 16) # Longest possible combination + + # Defensive tests + def test_invalid_input(self): + with self.assertRaises( + AssertionError, + msg="Input should raise an AssertionError for non-list input.", + ): + max_length("not a list") + + def test_non_string_input(self): + with self.assertRaises(TypeError): + max_length(["abc", 123, "def"]) + + def test_empty_strings(self): + self.assertEqual(max_length(["", "abc", "de"]), 5) + + +if __name__ == "__main__": + unittest.main() diff --git a/solutions/tests/test_min_integer.py b/solutions/tests/test_min_integer.py new file mode 100644 index 000000000..0acfc4bc0 --- /dev/null +++ b/solutions/tests/test_min_integer.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Test module for min_integer function. + +Test categories: + - Standard cases: typical lists with different lengths + - Edge cases: empty lists, single elements, strings + - Defensive tests: wrong input types, assertions + +Created on 2025-01-09 +Author: Tamir Elwaleeed +""" + +import unittest +from ..min_integer import min_integer + + +class TestMinInteger(unittest.TestCase): + """Define unittests for min_integer([..]).""" + + def test_ordered_list(self): + """Test an ordered list of integers.""" + ordered = [1, 2, 3, 4] + self.assertEqual(min_integer(ordered), 1) + + def test_unordered_list(self): + """Test an unordered list of integers.""" + unordered = [1, 2, 4, 3] + self.assertEqual(min_integer(unordered), 1) + + def test_min_at_beginning(self): + """Test a list with a beginning min value.""" + min_at_beginning = [1, 4, 3, 2] + self.assertEqual(min_integer(min_at_beginning), 1) + + def test_empty_list(self): + """Test an empty list.""" + empty = [] + self.assertEqual(min_integer(empty), None) + + def test_one_element_list(self): + """Test a list with a single element.""" + one_element = [7] + self.assertEqual(min_integer(one_element), 7) + + def test_floats(self): + """Test a list of floats.""" + floats = [1.53, 6.33, -9.123, 15.2, 6.0] + self.assertEqual(min_integer(floats), -9.123) + + def test_ints_and_floats(self): + """Test a list of ints and floats.""" + ints_and_floats = [1.53, 15.5, -9, 15, 6] + self.assertEqual(min_integer(ints_and_floats), -9) + + def test_string(self): + """Test a string.""" + string = "Brennan" + with self.assertRaises(AssertionError): + min_integer(string) + + def test_list_of_strings(self): + """Test a list of strings.""" + strings = ["Brennan", "is", "my", "name"] + self.assertEqual(min_integer(strings), "Brennan") + + def test_empty_string(self): + """Test an empty string.""" + with self.assertRaises(AssertionError): + min_integer("") + + +if __name__ == "__main__": + unittest.main() diff --git a/solutions/tests/test_missing_number.py b/solutions/tests/test_missing_number.py new file mode 100644 index 000000000..f054ab8de --- /dev/null +++ b/solutions/tests/test_missing_number.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" + +Test module for missing_number function. +Checks with numbers are missed out of a sequence. + +Test categories: + - Standard cases: only one missing value. + - Edge cases: empty list and list with one number. + - Defensive tests: invalid inputs or duplicate values. + + Created on 2025-01-04 + Author: Alaa Mohamed + +""" + +import unittest + +from ..missing_number import missing_number + + +class TestMissingNumber(unittest.TestCase): + """Test case for missing_number foundation""" + + def test_only_one_missing_number(self): + """The list is [0, 1, 3] and n is 3 + Missing number should be [2]""" + self.assertEqual(missing_number([0, 1, 3], 3), [2]) + + def test_an_empty_list(self): + """The list is [] and n is 0 + Missing number should be [0]""" + self.assertEqual(missing_number([], 0), [0]) + + def test_list_with_one_number(self): + """The list is [0] and n is 1 + Missing number should be [1]""" + self.assertEqual(missing_number([0], 1), [1]) + + def test_with_two_missing_numbers(self): + """The list is [1, 3, 5] and n is 5 + Missing number should be [2, 4]""" + self.assertEqual(missing_number([1, 3, 5], 5), [0, 2, 4]) + + def test_list_with_no_missing_number(self): + """The list is [0, 1, 2] and n is 2 + Missing number should be []""" + self.assertEqual(missing_number([0, 1, 2], 2), []) + + def test_duplicate_numbers(self): + """The list is [0, 1, 2, 2, 3, 4] and n is 4 + Missing number should be []""" + self.assertEqual(missing_number([0, 1, 2, 2, 3, 4], 4), []) + + def test_invalid_input(self): + """It should raise an assertion error if the input is invalid.""" + with self.assertRaises(AssertionError): + missing_number([], 1.5) diff --git a/solutions/tests/test_missing_numbers2.py b/solutions/tests/test_missing_numbers2.py new file mode 100644 index 000000000..104512812 --- /dev/null +++ b/solutions/tests/test_missing_numbers2.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +A module for testing the missing_numbers function. + +Test cases include: + - strings with missing numbers. + - strings without missing numbers. + - strings containing letters or other non-numerical characters. + - strings containing number formats other than integers. + - strings containing different spacing sizes. + - Sorted and unsorted numbers. + - Edge cases: empty strings, single-number strings. + - Invalid inputs: non-string values (e.g., integers or floats). + +Created on 06/01/2025 +@author: Amin +""" + +import unittest + +from ..missing_numbers2 import missing_numbers2 + + +class TestMissingNumbers(unittest.TestCase): + """Test the missing_number function""" + + def test_unsorted_string(self): + """It should return a sorted list with all the missing numbers""" + self.assertEqual(missing_numbers2("3 0"), [1, 2]) + + def test_no_missing_number(self): + """It should return [] for lists without missing numbers""" + self.assertEqual(missing_numbers2("1 2"), []) + + def test_one_missing_number(self): + """It should return a list containing only the missing number""" + self.assertEqual(missing_numbers2("0 2"), [1]) + + def test_multiple_cases(self): + """It should return a sorted list with all the missing numbers""" + self.assertEqual(missing_numbers2("1 4"), [2, 3]) + + def test_different_spaces(self): + """It should function properly regardless of how many spaces are there in the string""" + self.assertEqual(missing_numbers2("1 4"), [2, 3]) + + def test_not_string(self): + """It should raise AssertionError for non-string input""" + with self.assertRaises(AssertionError): + missing_numbers2(123) + + def test_not_numbers(self): + """It should raise AssertionError for strings with letters or non-numerical characters""" + with self.assertRaises(ValueError): + missing_numbers2("1 g") + + def test_non_integer_numbers(self): + """It should raise AssertionError for strings containing numbers other than integers""" + with self.assertRaises(ValueError): + missing_numbers2("1 2.1") diff --git a/solutions/tests/test_multiplication_table.py b/solutions/tests/test_multiplication_table.py new file mode 100644 index 000000000..34b2dda93 --- /dev/null +++ b/solutions/tests/test_multiplication_table.py @@ -0,0 +1,967 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +""" " +Test module for multiplication_table function. +Contains correct tests to help identify bugs in the implementation. + +Test categories: + - Standard cases: typical integer inputs + - Edge cases: empty input , large numbers + - Defensive tests: invalid inputs + +Created on 05/01/2025 #dd/mm/yyyy +Author: Mohamed Saeed +""" + +import unittest + +from ..multiplication_table import multiplication_table + + +class TestMultiplicationTable(unittest.TestCase): + """ + Test class for the multiplication_table function. + """ + + def test_normal_case(self): + """ + Test the function with a standard input. + """ + self.assertEqual(multiplication_table(3, 5), [3, 6, 9, 12, 15]) + + def test_edge_case1(self): + """ + Test the function with an edge input smallest numbers. + """ + self.assertEqual(multiplication_table(1, 1), [1]) + + def test_none_number_input(self): + """ + Test the function with a None number input. + """ + with self.assertRaises(AssertionError): + multiplication_table(None, 5) + + def test_none_length_input(self): + """ + Test the function with a None length input. + """ + with self.assertRaises(AssertionError): + multiplication_table(3, None) + + def test_empty_input(self): + """ + Test the function with an empty input. + """ + with self.assertRaises(AssertionError): + multiplication_table("", "") + + def test_string_number_input(self): + """ + Test the function with an string number input. + """ + with self.assertRaises(AssertionError): + multiplication_table("3", 5) + + def test_string_until_input(self): + """ + Test the function with an string length input. + """ + with self.assertRaises(AssertionError): + multiplication_table(3, "5") + + def test_negative_input1(self): + """ + Test the function with a negative number input. + """ + with self.assertRaises(AssertionError): + multiplication_table(-3, 5) + + def test_negative_input2(self): + """ + Test the function with a negative length input. + """ + with self.assertRaises(AssertionError): + multiplication_table(3, -5) + + def test_large_input_number(self): + """ + Test the function with large input numbers. + """ + with self.assertRaises(ValueError): + multiplication_table(1001, 5) + + def test_large_input_until(self): + """ + Test the function with large length numbers. + """ + with self.assertRaises(ValueError): + multiplication_table(3, 1001) + + def test_large_input_both(self): + """ + Test the function with large input & length numbers. + """ + with self.assertRaises(ValueError): + multiplication_table(1001, 1001) + + def test_edge_case2(self): + """ + Test the function with an edge input very large numbers. + """ + self.assertEqual( + multiplication_table(900, 850), + [ + 900, + 1800, + 2700, + 3600, + 4500, + 5400, + 6300, + 7200, + 8100, + 9000, + 9900, + 10800, + 11700, + 12600, + 13500, + 14400, + 15300, + 16200, + 17100, + 18000, + 18900, + 19800, + 20700, + 21600, + 22500, + 23400, + 24300, + 25200, + 26100, + 27000, + 27900, + 28800, + 29700, + 30600, + 31500, + 32400, + 33300, + 34200, + 35100, + 36000, + 36900, + 37800, + 38700, + 39600, + 40500, + 41400, + 42300, + 43200, + 44100, + 45000, + 45900, + 46800, + 47700, + 48600, + 49500, + 50400, + 51300, + 52200, + 53100, + 54000, + 54900, + 55800, + 56700, + 57600, + 58500, + 59400, + 60300, + 61200, + 62100, + 63000, + 63900, + 64800, + 65700, + 66600, + 67500, + 68400, + 69300, + 70200, + 71100, + 72000, + 72900, + 73800, + 74700, + 75600, + 76500, + 77400, + 78300, + 79200, + 80100, + 81000, + 81900, + 82800, + 83700, + 84600, + 85500, + 86400, + 87300, + 88200, + 89100, + 90000, + 90900, + 91800, + 92700, + 93600, + 94500, + 95400, + 96300, + 97200, + 98100, + 99000, + 99900, + 100800, + 101700, + 102600, + 103500, + 104400, + 105300, + 106200, + 107100, + 108000, + 108900, + 109800, + 110700, + 111600, + 112500, + 113400, + 114300, + 115200, + 116100, + 117000, + 117900, + 118800, + 119700, + 120600, + 121500, + 122400, + 123300, + 124200, + 125100, + 126000, + 126900, + 127800, + 128700, + 129600, + 130500, + 131400, + 132300, + 133200, + 134100, + 135000, + 135900, + 136800, + 137700, + 138600, + 139500, + 140400, + 141300, + 142200, + 143100, + 144000, + 144900, + 145800, + 146700, + 147600, + 148500, + 149400, + 150300, + 151200, + 152100, + 153000, + 153900, + 154800, + 155700, + 156600, + 157500, + 158400, + 159300, + 160200, + 161100, + 162000, + 162900, + 163800, + 164700, + 165600, + 166500, + 167400, + 168300, + 169200, + 170100, + 171000, + 171900, + 172800, + 173700, + 174600, + 175500, + 176400, + 177300, + 178200, + 179100, + 180000, + 180900, + 181800, + 182700, + 183600, + 184500, + 185400, + 186300, + 187200, + 188100, + 189000, + 189900, + 190800, + 191700, + 192600, + 193500, + 194400, + 195300, + 196200, + 197100, + 198000, + 198900, + 199800, + 200700, + 201600, + 202500, + 203400, + 204300, + 205200, + 206100, + 207000, + 207900, + 208800, + 209700, + 210600, + 211500, + 212400, + 213300, + 214200, + 215100, + 216000, + 216900, + 217800, + 218700, + 219600, + 220500, + 221400, + 222300, + 223200, + 224100, + 225000, + 225900, + 226800, + 227700, + 228600, + 229500, + 230400, + 231300, + 232200, + 233100, + 234000, + 234900, + 235800, + 236700, + 237600, + 238500, + 239400, + 240300, + 241200, + 242100, + 243000, + 243900, + 244800, + 245700, + 246600, + 247500, + 248400, + 249300, + 250200, + 251100, + 252000, + 252900, + 253800, + 254700, + 255600, + 256500, + 257400, + 258300, + 259200, + 260100, + 261000, + 261900, + 262800, + 263700, + 264600, + 265500, + 266400, + 267300, + 268200, + 269100, + 270000, + 270900, + 271800, + 272700, + 273600, + 274500, + 275400, + 276300, + 277200, + 278100, + 279000, + 279900, + 280800, + 281700, + 282600, + 283500, + 284400, + 285300, + 286200, + 287100, + 288000, + 288900, + 289800, + 290700, + 291600, + 292500, + 293400, + 294300, + 295200, + 296100, + 297000, + 297900, + 298800, + 299700, + 300600, + 301500, + 302400, + 303300, + 304200, + 305100, + 306000, + 306900, + 307800, + 308700, + 309600, + 310500, + 311400, + 312300, + 313200, + 314100, + 315000, + 315900, + 316800, + 317700, + 318600, + 319500, + 320400, + 321300, + 322200, + 323100, + 324000, + 324900, + 325800, + 326700, + 327600, + 328500, + 329400, + 330300, + 331200, + 332100, + 333000, + 333900, + 334800, + 335700, + 336600, + 337500, + 338400, + 339300, + 340200, + 341100, + 342000, + 342900, + 343800, + 344700, + 345600, + 346500, + 347400, + 348300, + 349200, + 350100, + 351000, + 351900, + 352800, + 353700, + 354600, + 355500, + 356400, + 357300, + 358200, + 359100, + 360000, + 360900, + 361800, + 362700, + 363600, + 364500, + 365400, + 366300, + 367200, + 368100, + 369000, + 369900, + 370800, + 371700, + 372600, + 373500, + 374400, + 375300, + 376200, + 377100, + 378000, + 378900, + 379800, + 380700, + 381600, + 382500, + 383400, + 384300, + 385200, + 386100, + 387000, + 387900, + 388800, + 389700, + 390600, + 391500, + 392400, + 393300, + 394200, + 395100, + 396000, + 396900, + 397800, + 398700, + 399600, + 400500, + 401400, + 402300, + 403200, + 404100, + 405000, + 405900, + 406800, + 407700, + 408600, + 409500, + 410400, + 411300, + 412200, + 413100, + 414000, + 414900, + 415800, + 416700, + 417600, + 418500, + 419400, + 420300, + 421200, + 422100, + 423000, + 423900, + 424800, + 425700, + 426600, + 427500, + 428400, + 429300, + 430200, + 431100, + 432000, + 432900, + 433800, + 434700, + 435600, + 436500, + 437400, + 438300, + 439200, + 440100, + 441000, + 441900, + 442800, + 443700, + 444600, + 445500, + 446400, + 447300, + 448200, + 449100, + 450000, + 450900, + 451800, + 452700, + 453600, + 454500, + 455400, + 456300, + 457200, + 458100, + 459000, + 459900, + 460800, + 461700, + 462600, + 463500, + 464400, + 465300, + 466200, + 467100, + 468000, + 468900, + 469800, + 470700, + 471600, + 472500, + 473400, + 474300, + 475200, + 476100, + 477000, + 477900, + 478800, + 479700, + 480600, + 481500, + 482400, + 483300, + 484200, + 485100, + 486000, + 486900, + 487800, + 488700, + 489600, + 490500, + 491400, + 492300, + 493200, + 494100, + 495000, + 495900, + 496800, + 497700, + 498600, + 499500, + 500400, + 501300, + 502200, + 503100, + 504000, + 504900, + 505800, + 506700, + 507600, + 508500, + 509400, + 510300, + 511200, + 512100, + 513000, + 513900, + 514800, + 515700, + 516600, + 517500, + 518400, + 519300, + 520200, + 521100, + 522000, + 522900, + 523800, + 524700, + 525600, + 526500, + 527400, + 528300, + 529200, + 530100, + 531000, + 531900, + 532800, + 533700, + 534600, + 535500, + 536400, + 537300, + 538200, + 539100, + 540000, + 540900, + 541800, + 542700, + 543600, + 544500, + 545400, + 546300, + 547200, + 548100, + 549000, + 549900, + 550800, + 551700, + 552600, + 553500, + 554400, + 555300, + 556200, + 557100, + 558000, + 558900, + 559800, + 560700, + 561600, + 562500, + 563400, + 564300, + 565200, + 566100, + 567000, + 567900, + 568800, + 569700, + 570600, + 571500, + 572400, + 573300, + 574200, + 575100, + 576000, + 576900, + 577800, + 578700, + 579600, + 580500, + 581400, + 582300, + 583200, + 584100, + 585000, + 585900, + 586800, + 587700, + 588600, + 589500, + 590400, + 591300, + 592200, + 593100, + 594000, + 594900, + 595800, + 596700, + 597600, + 598500, + 599400, + 600300, + 601200, + 602100, + 603000, + 603900, + 604800, + 605700, + 606600, + 607500, + 608400, + 609300, + 610200, + 611100, + 612000, + 612900, + 613800, + 614700, + 615600, + 616500, + 617400, + 618300, + 619200, + 620100, + 621000, + 621900, + 622800, + 623700, + 624600, + 625500, + 626400, + 627300, + 628200, + 629100, + 630000, + 630900, + 631800, + 632700, + 633600, + 634500, + 635400, + 636300, + 637200, + 638100, + 639000, + 639900, + 640800, + 641700, + 642600, + 643500, + 644400, + 645300, + 646200, + 647100, + 648000, + 648900, + 649800, + 650700, + 651600, + 652500, + 653400, + 654300, + 655200, + 656100, + 657000, + 657900, + 658800, + 659700, + 660600, + 661500, + 662400, + 663300, + 664200, + 665100, + 666000, + 666900, + 667800, + 668700, + 669600, + 670500, + 671400, + 672300, + 673200, + 674100, + 675000, + 675900, + 676800, + 677700, + 678600, + 679500, + 680400, + 681300, + 682200, + 683100, + 684000, + 684900, + 685800, + 686700, + 687600, + 688500, + 689400, + 690300, + 691200, + 692100, + 693000, + 693900, + 694800, + 695700, + 696600, + 697500, + 698400, + 699300, + 700200, + 701100, + 702000, + 702900, + 703800, + 704700, + 705600, + 706500, + 707400, + 708300, + 709200, + 710100, + 711000, + 711900, + 712800, + 713700, + 714600, + 715500, + 716400, + 717300, + 718200, + 719100, + 720000, + 720900, + 721800, + 722700, + 723600, + 724500, + 725400, + 726300, + 727200, + 728100, + 729000, + 729900, + 730800, + 731700, + 732600, + 733500, + 734400, + 735300, + 736200, + 737100, + 738000, + 738900, + 739800, + 740700, + 741600, + 742500, + 743400, + 744300, + 745200, + 746100, + 747000, + 747900, + 748800, + 749700, + 750600, + 751500, + 752400, + 753300, + 754200, + 755100, + 756000, + 756900, + 757800, + 758700, + 759600, + 760500, + 761400, + 762300, + 763200, + 764100, + 765000, + ], + ) diff --git a/solutions/tests/test_prime_numbers.py b/solutions/tests/test_prime_numbers.py new file mode 100644 index 000000000..a2a0843bf --- /dev/null +++ b/solutions/tests/test_prime_numbers.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Test module for prime_numbers function. +Checks if the given number is a prime number. + +Test categories: + - Standard cases: typical integer inputs. + - Edge cases: special numbers such as 0 and 1. + - Defensive tests: invalid inputs. + +Created on 2025-01-04 +Author: Alaa Mohamed +""" + +import unittest + +from ..prime_numbers import prime_numbers + + +class TestPrimeNumbers(unittest.TestCase): + """ + + Test case for the prime_numbers function. + + """ + + +def test_not_int(self): + """It should raise AssertionError for non-integer input""" + with self.assertRaises(AssertionError): + prime_numbers(1.5) + + +def test_edge_case(self): + """Testing the function with edge inputs""" + self.assertFalse(prime_numbers(1)) + + +def test_negative_numbers(self): + """Testing the function with negative inputs""" + self.AssertFalse(prime_numbers(-5)) + + +def test_large_prime_numbers(self): + """Testing the function with large prime numbers""" + self.assertTrue(prime_numbers(7919)) + + +def test_large_non_prime_numbers(self): + """Testing the function with large non-prime numbers""" + self.assertFalse(prime_numbers(100000))