Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
70cb55a
Implement string reversal function
labrocadabro Apr 22, 2025
f40e945
Add comprehensive tests for string reversal function
labrocadabro Apr 22, 2025
136e364
Add pytest dependency
labrocadabro Apr 22, 2025
1db32b9
Implement string reversal without slicing or reverse()
labrocadabro Apr 22, 2025
33d6490
Update tests for string reversal implementation
labrocadabro Apr 22, 2025
0e4e1d4
Fix syntax error in test file
labrocadabro Apr 22, 2025
519572d
Implement array flattening function with recursive approach
laura-abro Apr 22, 2025
99fa175
Add comprehensive tests for array flattening function
laura-abro Apr 22, 2025
1b9cd95
Implement binary search function with comprehensive error handling
labrocadabro Apr 22, 2025
6b19ee3
Add comprehensive tests for binary search function
labrocadabro Apr 22, 2025
c07d50f
Implement URL parser function with comprehensive parsing
laura-abro Apr 22, 2025
dcd6082
Add comprehensive tests for URL parser function
laura-abro Apr 22, 2025
78ce04a
Add pytest to requirements
laura-abro Apr 22, 2025
26a42f3
Update URL parser to handle more edge cases
laura-abro Apr 22, 2025
6bc4d71
Further refine URL parser to handle more edge cases
laura-abro Apr 22, 2025
9a1efb0
Final refinement of URL parser to pass all tests
laura-abro Apr 22, 2025
c58f240
Final implementation of URL parser to handle all test cases
laura-abro Apr 22, 2025
694cd4b
Add RGB to Hex converter function
labrocadabro Apr 22, 2025
e9d45b0
Add comprehensive tests for RGB to Hex converter
labrocadabro Apr 22, 2025
ed62dff
Merged branch pr-256-momstrosity-builder-test for PR https://github.c…
momstrosity Apr 22, 2025
c597afb
Merged branch pr-257-momstrosity-builder-test for PR https://github.c…
momstrosity Apr 22, 2025
09caeda
Merged branch pr-258-momstrosity-builder-test for PR https://github.c…
momstrosity Apr 22, 2025
5495993
Merged branch pr-259-momstrosity-builder-test for PR https://github.c…
momstrosity Apr 22, 2025
5912d41
Merged branch pr-260-momstrosity-builder-test for PR https://github.c…
momstrosity Apr 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pytest
39 changes: 39 additions & 0 deletions src/array_flattener.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from typing import List, Union

def flatten_array(arr: List[Union[int, List]]) -> List[int]:
"""
Recursively flatten a nested list 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 containing all integers from the input.

Raises:
TypeError: If the input is not a list or contains non-integer/non-list elements.

Examples:
>>> flatten_array([1, [2, 3], 4])
[1, 2, 3, 4]
>>> flatten_array([1, [2, [3, 4]], 5])
[1, 2, 3, 4, 5]
"""
# Validate input is a list
if not isinstance(arr, list):
raise TypeError("Input must be a list")

flattened = []

for item in arr:
# If item is a list, recursively flatten
if isinstance(item, list):
flattened.extend(flatten_array(item))
# If item is an integer, append to result
elif isinstance(item, int):
flattened.append(item)
# Raise error for invalid item types
else:
raise TypeError(f"List can only contain integers or nested lists, found {type(item)}")

return flattened
46 changes: 46 additions & 0 deletions src/binary_search.py
Original file line number Diff line number Diff line change
@@ -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 input 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")

# Edge case: empty list
if not arr:
return -1

# Binary search implementation
left, right = 0, len(arr) - 1

while left <= right:
# Prevent potential integer overflow
mid = left + (right - left) // 2

# Check if target is found
if arr[mid] == target:
return mid

# Decide which half to search
if arr[mid] < target:
left = mid + 1
else:
right = mid - 1

# Target not found
return -1
24 changes: 24 additions & 0 deletions src/rgb_to_hex.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
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 (e.g., '#FF0000')

Raises:
ValueError: If any color value is outside the valid range of 0-255
"""
# Validate input values
for color, name in [(r, 'Red'), (g, 'Green'), (b, 'Blue')]:
if not isinstance(color, int):
raise TypeError(f"{name} value must be an integer")
if color < 0 or color > 255:
raise ValueError(f"{name} value must be between 0 and 255")

# Convert RGB to hex, ensuring two-digit representation
return f'#{r:02X}{g:02X}{b:02X}'
31 changes: 31 additions & 0 deletions src/string_reversal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
def reverse_string(s: str) -> str:
"""
Reverse the given string manually without using slicing or reverse().

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")

# Convert string to list of characters
chars = list(s)

# Manually reverse the list of characters
left, right = 0, len(chars) - 1
while left < right:
# Swap characters
chars[left], chars[right] = chars[right], chars[left]
# Move towards the center
left += 1
right -= 1

# Convert back to string and return
return ''.join(chars)
74 changes: 74 additions & 0 deletions src/url_parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
from urllib.parse import urlparse, parse_qs
from typing import Dict, Any

def parse_url(url: str) -> Dict[str, Any]:
"""
Parse a given URL into its component parts.

Args:
url (str): The URL to be parsed.

Returns:
Dict[str, Any]: A dictionary containing parsed URL components:
- protocol: The URL scheme (e.g., 'http', 'https')
- domain: The domain name
- port: The port number (or None if not specified)
- path: The path component of the URL
- query_params: A dictionary of query parameters
- fragment: The fragment identifier (or None if not present)

Raises:
ValueError: If the input is not a valid URL string.
"""
# Validate input
if not isinstance(url, str):
raise ValueError("Input must be a string")

# Handle empty or whitespace-only strings
if not url.strip():
raise ValueError("URL cannot be empty")

try:
# Validate basic structure of the URL
if not any(char in url for char in ['/', '.', ':']):
raise ValueError(f"Invalid URL: {url}")

# Try parsing with potential manual protocol handling
if '://' not in url:
# If the URL contains path, treat it as a potential http URL
if '/' in url:
# If there's a path, try http://
parsed_url = urlparse('http://' + url)
protocol = None
else:
# If just a domain, try http://
parsed_url = urlparse('http://' + url)
protocol = None
else:
# If protocol is present, use as-is
parsed_url = urlparse(url)
protocol = parsed_url.scheme

# Extract query parameters
query_params = parse_qs(parsed_url.query)
# Convert query params to their single values if possible
query_params = {k: v[0] if len(v) == 1 else v for k, v in query_params.items()}

# Determine path
path = parsed_url.path if parsed_url.path and parsed_url.path != '/' else None

# Ensure path starts with '/' if present
if path and not path.startswith('/'):
path = '/' + path

# Construct the result dictionary
return {
'protocol': protocol,
'domain': parsed_url.hostname,
'port': parsed_url.port,
'path': path,
'query_params': query_params,
'fragment': parsed_url.fragment or None
}
except Exception:
raise ValueError(f"Invalid URL: {url}")
46 changes: 46 additions & 0 deletions tests/test_array_flattener.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import pytest
from src.array_flattener import flatten_array

def test_flatten_simple_list():
"""Test flattening a simple list with no nested lists"""
assert flatten_array([1, 2, 3]) == [1, 2, 3]

def test_flatten_single_nested_list():
"""Test flattening a list with one level of nesting"""
assert flatten_array([1, [2, 3], 4]) == [1, 2, 3, 4]

def test_flatten_multiple_nested_lists():
"""Test flattening a list with multiple levels of nesting"""
assert flatten_array([1, [2, [3, 4]], 5]) == [1, 2, 3, 4, 5]

def test_flatten_deeply_nested_list():
"""Test flattening a deeply nested list"""
assert flatten_array([1, [2, [3, [4, [5]]]], 6]) == [1, 2, 3, 4, 5, 6]

def test_flatten_empty_list():
"""Test flattening an empty list"""
assert flatten_array([]) == []

def test_flatten_nested_empty_lists():
"""Test flattening a list with nested empty lists"""
assert flatten_array([1, [], [2, []], 3]) == [1, 2, 3]

def test_invalid_input_non_list():
"""Test that a TypeError is raised for non-list input"""
with pytest.raises(TypeError, match="Input must be a list"):
flatten_array(123)

def test_invalid_input_non_integer_element():
"""Test that a TypeError is raised for non-integer/non-list elements"""
with pytest.raises(TypeError):
flatten_array([1, 2, "3"])
with pytest.raises(TypeError):
flatten_array([1, [2, 3.14], 4])

def test_flatten_single_element_list():
"""Test flattening a list with a single element"""
assert flatten_array([42]) == [42]

def test_flatten_list_with_single_nested_list():
"""Test flattening a list containing a single nested list"""
assert flatten_array([[1]]) == [1]
49 changes: 49 additions & 0 deletions tests/test_binary_search.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
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."""
arr = []
assert binary_search(arr, 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_invalid_input():
"""Test error handling for invalid inputs."""
with pytest.raises(TypeError):
binary_search("not a list", 5)

with pytest.raises(ValueError):
binary_search([5, 3, 1], 3) # Unsorted list

def test_binary_search_duplicate_elements():
"""Test binary search with duplicate elements."""
arr = [1, 2, 2, 3, 3, 3, 4, 4, 5]
# Note: This returns the index of one of the duplicate elements
assert binary_search(arr, 3) in [4, 5, 6]
assert binary_search(arr, 2) in [1, 2]

def test_binary_search_large_list():
"""Test binary search on a larger sorted list."""
arr = list(range(1000))
assert binary_search(arr, 500) == 500
assert binary_search(arr, 999) == 999
assert binary_search(arr, 1000) == -1
53 changes: 53 additions & 0 deletions tests/test_rgb_to_hex.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import pytest
from src.rgb_to_hex import rgb_to_hex

def test_rgb_to_hex_basic():
"""Test basic color conversion"""
assert rgb_to_hex(255, 0, 0) == '#FF0000' # Red
assert rgb_to_hex(0, 255, 0) == '#00FF00' # Green
assert rgb_to_hex(0, 0, 255) == '#0000FF' # Blue
assert rgb_to_hex(255, 255, 255) == '#FFFFFF' # White
assert rgb_to_hex(0, 0, 0) == '#000000' # Black

def test_rgb_to_hex_mixed_colors():
"""Test mixed color conversions"""
assert rgb_to_hex(128, 128, 128) == '#808080' # Gray
assert rgb_to_hex(255, 165, 0) == '#FFA500' # Orange

def test_rgb_to_hex_boundary_values():
"""Test boundary values"""
assert rgb_to_hex(0, 0, 0) == '#000000'
assert rgb_to_hex(255, 255, 255) == '#FFFFFF'

def test_rgb_to_hex_invalid_inputs():
"""Test error handling for invalid inputs"""
# Test negative values
with pytest.raises(ValueError, match="Red value must be between 0 and 255"):
rgb_to_hex(-1, 0, 0)

with pytest.raises(ValueError, match="Green value must be between 0 and 255"):
rgb_to_hex(0, -1, 0)

with pytest.raises(ValueError, match="Blue value must be between 0 and 255"):
rgb_to_hex(0, 0, -1)

# Test values over 255
with pytest.raises(ValueError, match="Red value must be between 0 and 255"):
rgb_to_hex(256, 0, 0)

with pytest.raises(ValueError, match="Green value must be between 0 and 255"):
rgb_to_hex(0, 256, 0)

with pytest.raises(ValueError, match="Blue value must be between 0 and 255"):
rgb_to_hex(0, 0, 256)

def test_rgb_to_hex_type_errors():
"""Test type checking"""
with pytest.raises(TypeError, match="Red value must be an integer"):
rgb_to_hex('255', 0, 0)

with pytest.raises(TypeError, match="Green value must be an integer"):
rgb_to_hex(0, '255', 0)

with pytest.raises(TypeError, match="Blue value must be an integer"):
rgb_to_hex(0, 0, '255')
Loading