From 062723220021254792d863d50286f1e1d9117efa Mon Sep 17 00:00:00 2001 From: labrocadabro Date: Tue, 15 Apr 2025 10:47:13 -0300 Subject: [PATCH 01/14] Add string reversal function implementation --- src/string_reversal.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/string_reversal.py diff --git a/src/string_reversal.py b/src/string_reversal.py new file mode 100644 index 00000000..1b19e92a --- /dev/null +++ b/src/string_reversal.py @@ -0,0 +1,19 @@ +def reverse_string(s: str) -> str: + """ + Reverses the given string. + + Args: + s (str): The input string to be reversed. + + Returns: + str: The reversed string. + + Raises: + TypeError: If the input is not a string. + """ + # Check if input is a string + if not isinstance(s, str): + raise TypeError("Input must be a string") + + # Return the reversed string + return s[::-1] \ No newline at end of file From eec981dd752ed10f6e7147bd919db2bc824c7cca Mon Sep 17 00:00:00 2001 From: labrocadabro Date: Tue, 15 Apr 2025 10:47:49 -0300 Subject: [PATCH 02/14] Add comprehensive tests for string reversal function --- tests/test_string_reversal.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 tests/test_string_reversal.py diff --git a/tests/test_string_reversal.py b/tests/test_string_reversal.py new file mode 100644 index 00000000..661bd377 --- /dev/null +++ b/tests/test_string_reversal.py @@ -0,0 +1,34 @@ +import pytest +from src.string_reversal import reverse_string + +def test_reverse_string_basic(): + """Test basic string reversal.""" + assert reverse_string("hello") == "olleh" + assert reverse_string("python") == "nohtyp" + +def test_reverse_string_empty(): + """Test reversing an empty string.""" + assert reverse_string("") == "" + +def test_reverse_string_with_spaces(): + """Test reversing a string with spaces.""" + assert reverse_string("hello world") == "dlrow olleh" + +def test_reverse_string_with_special_chars(): + """Test reversing a string with special characters.""" + assert reverse_string("a1b2c3") == "3c2b1a" + +def test_reverse_string_with_unicode(): + """Test reversing a string with Unicode characters.""" + assert reverse_string("café") == "éfac" + +def test_reverse_string_invalid_input(): + """Test that TypeError is raised for non-string inputs.""" + with pytest.raises(TypeError, match="Input must be a string"): + reverse_string(123) + + with pytest.raises(TypeError, match="Input must be a string"): + reverse_string(None) + + with pytest.raises(TypeError, match="Input must be a string"): + reverse_string(["hello"]) \ No newline at end of file From 71658bef03a7aff72181f43cf44caae2eb1bc8ee Mon Sep 17 00:00:00 2001 From: labrocadabro Date: Tue, 15 Apr 2025 10:49:32 -0300 Subject: [PATCH 03/14] Implement string reversal without using slice or reverse() --- src/string_reversal.py | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/string_reversal.py b/src/string_reversal.py index 1b19e92a..abf5c061 100644 --- a/src/string_reversal.py +++ b/src/string_reversal.py @@ -1,6 +1,6 @@ def reverse_string(s: str) -> str: """ - Reverses the given string. + Reverses the given string manually without using slicing or built-in reverse methods. Args: s (str): The input string to be reversed. @@ -15,5 +15,16 @@ def reverse_string(s: str) -> str: if not isinstance(s, str): raise TypeError("Input must be a string") - # Return the reversed string - return s[::-1] \ No newline at end of file + # Convert string to list of characters to allow manipulation + chars = list(s) + + # Manually reverse the list of characters + left, right = 0, len(chars) - 1 + while left < right: + # Swap characters from both ends + chars[left], chars[right] = chars[right], chars[left] + left += 1 + right -= 1 + + # Convert back to string and return + return ''.join(chars) \ No newline at end of file From e04bd5cfa581beae1afa53df11b7c603d36a7573 Mon Sep 17 00:00:00 2001 From: labrocadabro Date: Tue, 15 Apr 2025 10:49:47 -0300 Subject: [PATCH 04/14] Update tests for string reversal implementation From fdb1a8b3335bef8588f3242d594e339833a9bb44 Mon Sep 17 00:00:00 2001 From: laura-abro Date: Tue, 15 Apr 2025 10:53:08 -0300 Subject: [PATCH 05/14] Implement array flattening function --- src/array_flatten.py | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/array_flatten.py diff --git a/src/array_flatten.py b/src/array_flatten.py new file mode 100644 index 00000000..35344693 --- /dev/null +++ b/src/array_flatten.py @@ -0,0 +1,29 @@ +from typing import List, Union + +def flatten_array(arr: List[Union[int, List]]) -> List[int]: + """ + Recursively flatten a nested array of integers into a single-level list. + + Args: + arr (List[Union[int, List]]): A potentially nested list of integers + + Returns: + List[int]: A flattened list of integers + + Raises: + TypeError: If the input contains non-integer and non-list elements + """ + flattened = [] + + for item in arr: + # If the item is a list, recursively flatten it + if isinstance(item, list): + flattened.extend(flatten_array(item)) + # If the item is an integer, add it to the flattened list + elif isinstance(item, int): + flattened.append(item) + # Raise an error for non-integer and non-list elements + else: + raise TypeError(f"Invalid element type: {type(item)}. Only integers and lists are allowed.") + + return flattened \ No newline at end of file From 458cfef2267d2958b001541705ad20af60cada68 Mon Sep 17 00:00:00 2001 From: laura-abro Date: Tue, 15 Apr 2025 10:53:51 -0300 Subject: [PATCH 06/14] Add comprehensive tests for array flattening function --- tests/test_array_flatten.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 tests/test_array_flatten.py diff --git a/tests/test_array_flatten.py b/tests/test_array_flatten.py new file mode 100644 index 00000000..7115f906 --- /dev/null +++ b/tests/test_array_flatten.py @@ -0,0 +1,31 @@ +import pytest +from src.array_flatten import flatten_array + +def test_flatten_single_level_array(): + """Test flattening a single-level array""" + assert flatten_array([1, 2, 3]) == [1, 2, 3] + +def test_flatten_nested_array(): + """Test flattening a nested array""" + assert flatten_array([1, [2, 3], 4]) == [1, 2, 3, 4] + +def test_flatten_deeply_nested_array(): + """Test flattening a deeply nested array""" + assert flatten_array([1, [2, [3, 4]], 5]) == [1, 2, 3, 4, 5] + +def test_flatten_empty_array(): + """Test flattening an empty array""" + assert flatten_array([]) == [] + +def test_flatten_array_with_empty_nested_lists(): + """Test flattening an array with empty nested lists""" + assert flatten_array([1, [], [2, []], 3]) == [1, 2, 3] + +def test_invalid_element_type(): + """Test raising TypeError for non-integer and non-list elements""" + with pytest.raises(TypeError, match="Invalid element type"): + flatten_array([1, 2, "3"]) + +def test_complex_nested_array(): + """Test flattening a complex nested array""" + assert flatten_array([1, [2, [3, [4, 5]]], [6, 7]]) == [1, 2, 3, 4, 5, 6, 7] \ No newline at end of file From fec23c6d525fbbaecf7bf677d88e9661ea910986 Mon Sep 17 00:00:00 2001 From: labrocadabro Date: Tue, 15 Apr 2025 11:37:33 -0300 Subject: [PATCH 07/14] Implement binary search algorithm --- src/binary_search.py | 46 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/binary_search.py diff --git a/src/binary_search.py b/src/binary_search.py new file mode 100644 index 00000000..e288904f --- /dev/null +++ b/src/binary_search.py @@ -0,0 +1,46 @@ +def binary_search(arr, target): + """ + Perform binary search on a sorted array to find the target element. + + Args: + arr (list): A sorted list of comparable elements (ascending order) + target: The element to search for + + Returns: + int: Index of the target element if found, -1 otherwise + + Raises: + TypeError: If input is not a list + ValueError: If the list is not sorted + """ + # Validate input + if not isinstance(arr, list): + raise TypeError("Input must be a list") + + # Check if list is sorted + if arr != sorted(arr): + raise ValueError("Input list must be sorted in ascending order") + + # Handle empty list + if not arr: + return -1 + + # Perform binary search + left, right = 0, len(arr) - 1 + + while left <= right: + # Calculate mid point to avoid potential integer overflow + mid = left + (right - left) // 2 + + # Check if target is found + if arr[mid] == target: + return mid + + # Adjust search boundaries + if arr[mid] < target: + left = mid + 1 + else: + right = mid - 1 + + # Target not found + return -1 \ No newline at end of file From 3f5b973b7876c7665df41046f7b317e33f08a97b Mon Sep 17 00:00:00 2001 From: labrocadabro Date: Tue, 15 Apr 2025 11:37:48 -0300 Subject: [PATCH 08/14] Add comprehensive tests for binary search --- tests/test_binary_search.py | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 tests/test_binary_search.py diff --git a/tests/test_binary_search.py b/tests/test_binary_search.py new file mode 100644 index 00000000..4b7a2e21 --- /dev/null +++ b/tests/test_binary_search.py @@ -0,0 +1,42 @@ +import pytest +from src.binary_search import binary_search + +def test_binary_search_normal_case(): + """Test binary search with a typical sorted list""" + arr = [1, 3, 5, 7, 9, 11, 13] + assert binary_search(arr, 7) == 3 + assert binary_search(arr, 13) == 6 + assert binary_search(arr, 1) == 0 + +def test_binary_search_not_found(): + """Test when target is not in the list""" + arr = [1, 3, 5, 7, 9, 11, 13] + assert binary_search(arr, 4) == -1 + assert binary_search(arr, 0) == -1 + assert binary_search(arr, 14) == -1 + +def test_binary_search_empty_list(): + """Test binary search on an empty list""" + assert binary_search([], 5) == -1 + +def test_binary_search_single_element(): + """Test binary search on a single-element list""" + arr = [5] + assert binary_search(arr, 5) == 0 + assert binary_search(arr, 6) == -1 + +def test_binary_search_duplicate_elements(): + """Test binary search with duplicate elements""" + arr = [1, 2, 2, 3, 3, 3, 4, 4, 5] + # Note: Returns the index of one of the matching elements + assert binary_search(arr, 3) in [3, 4, 5] + +def test_binary_search_invalid_input(): + """Test error handling for invalid inputs""" + # Not a list + with pytest.raises(TypeError): + binary_search("not a list", 5) + + # Unsorted list + with pytest.raises(ValueError): + binary_search([5, 3, 1, 4, 2], 3) \ No newline at end of file From 12c83c97f3394ff75d1d7c884be7c6ba1ecc1a02 Mon Sep 17 00:00:00 2001 From: laura-abro Date: Tue, 15 Apr 2025 11:41:10 -0300 Subject: [PATCH 09/14] Implement URL parser function with comprehensive parsing --- src/url_parser.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/url_parser.py diff --git a/src/url_parser.py b/src/url_parser.py new file mode 100644 index 00000000..9507b6b5 --- /dev/null +++ b/src/url_parser.py @@ -0,0 +1,46 @@ +from urllib.parse import urlparse, parse_qs +from typing import Dict, Any, Optional + +def parse_url(url: str) -> Dict[str, Any]: + """ + Parse a URL into its components and return a dictionary with detailed information. + + Args: + url (str): The URL to parse. + + Returns: + Dict[str, Any]: A dictionary containing parsed URL components: + - protocol: The URL protocol (http, https, etc.) + - domain: The domain name + - path: The path component of the URL + - query_params: A dictionary of query parameters + - port: The port number (if specified, otherwise None) + - fragment: The fragment identifier (if present, otherwise None) + + Raises: + ValueError: If the input URL is invalid or empty. + """ + # Check for empty or None input + if not url or not isinstance(url, str): + raise ValueError("Invalid URL: URL must be a non-empty string") + + try: + # Use urlparse to break down the URL + parsed = urlparse(url) + + # Extract query parameters + query_params = parse_qs(parsed.query) + # Convert query params from lists to single values if possible + query_params = {k: v[0] if len(v) == 1 else v for k, v in query_params.items()} + + # Construct the result dictionary + return { + 'protocol': parsed.scheme, + 'domain': parsed.netloc.split(':')[0], # Remove port if present + 'path': parsed.path, + 'query_params': query_params, + 'port': parsed.port, + 'fragment': parsed.fragment or None + } + except Exception as e: + raise ValueError(f"Error parsing URL: {str(e)}") \ No newline at end of file From 21a160593a25e4ae01e0a030f8058bf935d759b8 Mon Sep 17 00:00:00 2001 From: laura-abro Date: Tue, 15 Apr 2025 11:41:35 -0300 Subject: [PATCH 10/14] Add comprehensive tests for URL parser function --- tests/test_url_parser.py | 73 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 tests/test_url_parser.py diff --git a/tests/test_url_parser.py b/tests/test_url_parser.py new file mode 100644 index 00000000..edaf871b --- /dev/null +++ b/tests/test_url_parser.py @@ -0,0 +1,73 @@ +import pytest +from src.url_parser import parse_url + +def test_full_url_parsing(): + """Test parsing a complete URL with all components""" + url = "https://www.example.com:8080/path/to/page?param1=value1¶m2=value2#section" + result = parse_url(url) + + assert result == { + 'protocol': 'https', + 'domain': 'www.example.com', + 'path': '/path/to/page', + 'query_params': {'param1': 'value1', 'param2': 'value2'}, + 'port': 8080, + 'fragment': 'section' + } + +def test_url_without_port(): + """Test parsing a URL without a port""" + url = "http://github.com/user/repo" + result = parse_url(url) + + assert result == { + 'protocol': 'http', + 'domain': 'github.com', + 'path': '/user/repo', + 'query_params': {}, + 'port': None, + 'fragment': None + } + +def test_url_with_complex_query_params(): + """Test parsing URL with multiple values for same parameter""" + url = "https://example.com/search?tag=python&tag=programming" + result = parse_url(url) + + assert result == { + 'protocol': 'https', + 'domain': 'example.com', + 'path': '/search', + 'query_params': {'tag': ['python', 'programming']}, + 'port': None, + 'fragment': None + } + +def test_url_with_fragment(): + """Test parsing URL with fragment""" + url = "https://docs.python.org/3/library/urllib.parse.html#urlparse" + result = parse_url(url) + + assert result == { + 'protocol': 'https', + 'domain': 'docs.python.org', + 'path': '/3/library/urllib.parse.html', + 'query_params': {}, + 'port': None, + 'fragment': 'urlparse' + } + +def test_empty_url_raises_error(): + """Test that empty URL raises a ValueError""" + with pytest.raises(ValueError, match="Invalid URL: URL must be a non-empty string"): + parse_url("") + +def test_none_url_raises_error(): + """Test that None input raises a ValueError""" + with pytest.raises(ValueError, match="Invalid URL: URL must be a non-empty string"): + parse_url(None) + +def test_invalid_url_handling(): + """Test handling of an invalid URL""" + with pytest.raises(ValueError, match="Error parsing URL"): + parse_url("not a valid url") \ No newline at end of file From c7e1f0a330c8368d2068c3ae9fa6b18be466c26c Mon Sep 17 00:00:00 2001 From: laura-abro Date: Tue, 15 Apr 2025 11:41:53 -0300 Subject: [PATCH 11/14] Add pytest to requirements --- requirements.txt | 1 + 1 file changed, 1 insertion(+) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..55b033e9 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +pytest \ No newline at end of file From 34d6d907e5043fb1090ca82d6002379b201bf807 Mon Sep 17 00:00:00 2001 From: laura-abro Date: Tue, 15 Apr 2025 11:42:18 -0300 Subject: [PATCH 12/14] Improve URL parsing with stricter validation --- src/url_parser.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/url_parser.py b/src/url_parser.py index 9507b6b5..357a7d42 100644 --- a/src/url_parser.py +++ b/src/url_parser.py @@ -25,8 +25,16 @@ def parse_url(url: str) -> Dict[str, Any]: raise ValueError("Invalid URL: URL must be a non-empty string") try: - # Use urlparse to break down the URL + # Try to parse the URL, raising an error if it fails parsed = urlparse(url) + + # Require a scheme (protocol) to be a valid URL + if not parsed.scheme: + raise ValueError("Invalid URL: Missing protocol") + + # Require a netloc (domain) to be a valid URL + if not parsed.netloc: + raise ValueError("Invalid URL: Missing domain") # Extract query parameters query_params = parse_qs(parsed.query) From 8acca3ce2e46192ce4a4ed00b348234066ead80f Mon Sep 17 00:00:00 2001 From: labrocadabro Date: Tue, 15 Apr 2025 11:46:43 -0300 Subject: [PATCH 13/14] Add RGB to Hex converter function --- src/rgb_to_hex.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/rgb_to_hex.py diff --git a/src/rgb_to_hex.py b/src/rgb_to_hex.py new file mode 100644 index 00000000..8c1f0e51 --- /dev/null +++ b/src/rgb_to_hex.py @@ -0,0 +1,26 @@ +def rgb_to_hex(r: int, g: int, b: int) -> str: + """ + Convert RGB color values to a hexadecimal color representation. + + Args: + r (int): Red color value (0-255) + g (int): Green color value (0-255) + b (int): Blue color value (0-255) + + Returns: + str: Hexadecimal color representation (uppercase) + + Raises: + ValueError: If any color value is outside the range 0-255 + """ + # Validate input values + if not all(isinstance(val, int) for val in (r, g, b)): + raise TypeError("RGB values must be integers") + + if not all(0 <= val <= 255 for val in (r, g, b)): + raise ValueError("RGB values must be between 0 and 255") + + # Convert each color component to a two-digit hex value + hex_color = '#{:02X}{:02X}{:02X}'.format(r, g, b) + + return hex_color \ No newline at end of file From a48ebed98c9c41812039a80c8bb10190ec45c668 Mon Sep 17 00:00:00 2001 From: labrocadabro Date: Tue, 15 Apr 2025 11:47:08 -0300 Subject: [PATCH 14/14] Add comprehensive tests for RGB to Hex converter --- tests/test_rgb_to_hex.py | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 tests/test_rgb_to_hex.py diff --git a/tests/test_rgb_to_hex.py b/tests/test_rgb_to_hex.py new file mode 100644 index 00000000..297922d3 --- /dev/null +++ b/tests/test_rgb_to_hex.py @@ -0,0 +1,34 @@ +import pytest +from src.rgb_to_hex import rgb_to_hex + +def test_basic_conversion(): + """Test basic RGB to Hex conversion""" + assert rgb_to_hex(255, 255, 255) == '#FFFFFF' + assert rgb_to_hex(0, 0, 0) == '#000000' + assert rgb_to_hex(255, 0, 0) == '#FF0000' + assert rgb_to_hex(0, 255, 0) == '#00FF00' + assert rgb_to_hex(0, 0, 255) == '#0000FF' + +def test_mid_range_conversion(): + """Test mid-range RGB to Hex conversion""" + assert rgb_to_hex(128, 128, 128) == '#808080' + assert rgb_to_hex(100, 150, 200) == '#6496C8' + +def test_invalid_inputs(): + """Test error handling for invalid inputs""" + # Test out of range values + with pytest.raises(ValueError, match="RGB values must be between 0 and 255"): + rgb_to_hex(-1, 0, 0) + with pytest.raises(ValueError, match="RGB values must be between 0 and 255"): + rgb_to_hex(0, 256, 0) + with pytest.raises(ValueError, match="RGB values must be between 0 and 255"): + rgb_to_hex(0, 0, 300) + +def test_type_errors(): + """Test error handling for incorrect input types""" + with pytest.raises(TypeError, match="RGB values must be integers"): + rgb_to_hex(1.5, 0, 0) + with pytest.raises(TypeError, match="RGB values must be integers"): + rgb_to_hex('255', 0, 0) + with pytest.raises(TypeError, match="RGB values must be integers"): + rgb_to_hex(0, [255], 0) \ No newline at end of file