mirror of
https://github.com/varun-r-mallya/py-libp2p.git
synced 2025-12-31 20:36:24 +00:00
Merge branch 'main' into fix_expose_timeout_muxer_multistream
This commit is contained in:
@ -1,4 +1,8 @@
|
||||
import random
|
||||
from unittest.mock import (
|
||||
AsyncMock,
|
||||
MagicMock,
|
||||
)
|
||||
|
||||
import pytest
|
||||
import trio
|
||||
@ -7,6 +11,9 @@ from libp2p.pubsub.gossipsub import (
|
||||
PROTOCOL_ID,
|
||||
GossipSub,
|
||||
)
|
||||
from libp2p.pubsub.pb import (
|
||||
rpc_pb2,
|
||||
)
|
||||
from libp2p.tools.utils import (
|
||||
connect,
|
||||
)
|
||||
@ -754,3 +761,173 @@ async def test_single_host():
|
||||
assert connected_peers == 0, (
|
||||
f"Single host has {connected_peers} connections, expected 0"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.trio
|
||||
async def test_handle_ihave(monkeypatch):
|
||||
async with PubsubFactory.create_batch_with_gossipsub(2) as pubsubs_gsub:
|
||||
gossipsub_routers = []
|
||||
for pubsub in pubsubs_gsub:
|
||||
if isinstance(pubsub.router, GossipSub):
|
||||
gossipsub_routers.append(pubsub.router)
|
||||
gossipsubs = tuple(gossipsub_routers)
|
||||
|
||||
index_alice = 0
|
||||
index_bob = 1
|
||||
id_bob = pubsubs_gsub[index_bob].my_id
|
||||
|
||||
# Connect Alice and Bob
|
||||
await connect(pubsubs_gsub[index_alice].host, pubsubs_gsub[index_bob].host)
|
||||
await trio.sleep(0.1) # Allow connections to establish
|
||||
|
||||
# Mock emit_iwant to capture calls
|
||||
mock_emit_iwant = AsyncMock()
|
||||
monkeypatch.setattr(gossipsubs[index_alice], "emit_iwant", mock_emit_iwant)
|
||||
|
||||
# Create a test message ID as a string representation of a (seqno, from) tuple
|
||||
test_seqno = b"1234"
|
||||
test_from = id_bob.to_bytes()
|
||||
test_msg_id = f"(b'{test_seqno.hex()}', b'{test_from.hex()}')"
|
||||
ihave_msg = rpc_pb2.ControlIHave(messageIDs=[test_msg_id])
|
||||
|
||||
# Mock seen_messages.cache to avoid false positives
|
||||
monkeypatch.setattr(pubsubs_gsub[index_alice].seen_messages, "cache", {})
|
||||
|
||||
# Simulate Bob sending IHAVE to Alice
|
||||
await gossipsubs[index_alice].handle_ihave(ihave_msg, id_bob)
|
||||
|
||||
# Check if emit_iwant was called with the correct message ID
|
||||
mock_emit_iwant.assert_called_once()
|
||||
called_args = mock_emit_iwant.call_args[0]
|
||||
assert called_args[0] == [test_msg_id] # Expected message IDs
|
||||
assert called_args[1] == id_bob # Sender peer ID
|
||||
|
||||
|
||||
@pytest.mark.trio
|
||||
async def test_handle_iwant(monkeypatch):
|
||||
async with PubsubFactory.create_batch_with_gossipsub(2) as pubsubs_gsub:
|
||||
gossipsub_routers = []
|
||||
for pubsub in pubsubs_gsub:
|
||||
if isinstance(pubsub.router, GossipSub):
|
||||
gossipsub_routers.append(pubsub.router)
|
||||
gossipsubs = tuple(gossipsub_routers)
|
||||
|
||||
index_alice = 0
|
||||
index_bob = 1
|
||||
id_alice = pubsubs_gsub[index_alice].my_id
|
||||
|
||||
# Connect Alice and Bob
|
||||
await connect(pubsubs_gsub[index_alice].host, pubsubs_gsub[index_bob].host)
|
||||
await trio.sleep(0.1) # Allow connections to establish
|
||||
|
||||
# Mock mcache.get to return a message
|
||||
test_message = rpc_pb2.Message(data=b"test_data")
|
||||
test_seqno = b"1234"
|
||||
test_from = id_alice.to_bytes()
|
||||
|
||||
# ✅ Correct: use raw tuple and str() to serialize, no hex()
|
||||
test_msg_id = str((test_seqno, test_from))
|
||||
|
||||
mock_mcache_get = MagicMock(return_value=test_message)
|
||||
monkeypatch.setattr(gossipsubs[index_bob].mcache, "get", mock_mcache_get)
|
||||
|
||||
# Mock write_msg to capture the sent packet
|
||||
mock_write_msg = AsyncMock()
|
||||
monkeypatch.setattr(gossipsubs[index_bob].pubsub, "write_msg", mock_write_msg)
|
||||
|
||||
# Simulate Alice sending IWANT to Bob
|
||||
iwant_msg = rpc_pb2.ControlIWant(messageIDs=[test_msg_id])
|
||||
await gossipsubs[index_bob].handle_iwant(iwant_msg, id_alice)
|
||||
|
||||
# Check if write_msg was called with the correct packet
|
||||
mock_write_msg.assert_called_once()
|
||||
packet = mock_write_msg.call_args[0][1]
|
||||
assert isinstance(packet, rpc_pb2.RPC)
|
||||
assert len(packet.publish) == 1
|
||||
assert packet.publish[0] == test_message
|
||||
|
||||
# Verify that mcache.get was called with the correct parsed message ID
|
||||
mock_mcache_get.assert_called_once()
|
||||
called_msg_id = mock_mcache_get.call_args[0][0]
|
||||
assert isinstance(called_msg_id, tuple)
|
||||
assert called_msg_id == (test_seqno, test_from)
|
||||
|
||||
|
||||
@pytest.mark.trio
|
||||
async def test_handle_iwant_invalid_msg_id(monkeypatch):
|
||||
"""
|
||||
Test that handle_iwant raises ValueError for malformed message IDs.
|
||||
"""
|
||||
async with PubsubFactory.create_batch_with_gossipsub(2) as pubsubs_gsub:
|
||||
gossipsub_routers = []
|
||||
for pubsub in pubsubs_gsub:
|
||||
if isinstance(pubsub.router, GossipSub):
|
||||
gossipsub_routers.append(pubsub.router)
|
||||
gossipsubs = tuple(gossipsub_routers)
|
||||
|
||||
index_alice = 0
|
||||
index_bob = 1
|
||||
id_alice = pubsubs_gsub[index_alice].my_id
|
||||
|
||||
await connect(pubsubs_gsub[index_alice].host, pubsubs_gsub[index_bob].host)
|
||||
await trio.sleep(0.1)
|
||||
|
||||
# Malformed message ID (not a tuple string)
|
||||
malformed_msg_id = "not_a_valid_msg_id"
|
||||
iwant_msg = rpc_pb2.ControlIWant(messageIDs=[malformed_msg_id])
|
||||
|
||||
# Mock mcache.get and write_msg to ensure they are not called
|
||||
mock_mcache_get = MagicMock()
|
||||
monkeypatch.setattr(gossipsubs[index_bob].mcache, "get", mock_mcache_get)
|
||||
mock_write_msg = AsyncMock()
|
||||
monkeypatch.setattr(gossipsubs[index_bob].pubsub, "write_msg", mock_write_msg)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
await gossipsubs[index_bob].handle_iwant(iwant_msg, id_alice)
|
||||
mock_mcache_get.assert_not_called()
|
||||
mock_write_msg.assert_not_called()
|
||||
|
||||
# Message ID that's a tuple string but not (bytes, bytes)
|
||||
invalid_tuple_msg_id = "('abc', 123)"
|
||||
iwant_msg = rpc_pb2.ControlIWant(messageIDs=[invalid_tuple_msg_id])
|
||||
with pytest.raises(ValueError):
|
||||
await gossipsubs[index_bob].handle_iwant(iwant_msg, id_alice)
|
||||
mock_mcache_get.assert_not_called()
|
||||
mock_write_msg.assert_not_called()
|
||||
|
||||
|
||||
@pytest.mark.trio
|
||||
async def test_handle_ihave_empty_message_ids(monkeypatch):
|
||||
"""
|
||||
Test that handle_ihave with an empty messageIDs list does not call emit_iwant.
|
||||
"""
|
||||
async with PubsubFactory.create_batch_with_gossipsub(2) as pubsubs_gsub:
|
||||
gossipsub_routers = []
|
||||
for pubsub in pubsubs_gsub:
|
||||
if isinstance(pubsub.router, GossipSub):
|
||||
gossipsub_routers.append(pubsub.router)
|
||||
gossipsubs = tuple(gossipsub_routers)
|
||||
|
||||
index_alice = 0
|
||||
index_bob = 1
|
||||
id_bob = pubsubs_gsub[index_bob].my_id
|
||||
|
||||
# Connect Alice and Bob
|
||||
await connect(pubsubs_gsub[index_alice].host, pubsubs_gsub[index_bob].host)
|
||||
await trio.sleep(0.1) # Allow connections to establish
|
||||
|
||||
# Mock emit_iwant to capture calls
|
||||
mock_emit_iwant = AsyncMock()
|
||||
monkeypatch.setattr(gossipsubs[index_alice], "emit_iwant", mock_emit_iwant)
|
||||
|
||||
# Empty messageIDs list
|
||||
ihave_msg = rpc_pb2.ControlIHave(messageIDs=[])
|
||||
|
||||
# Mock seen_messages.cache to avoid false positives
|
||||
monkeypatch.setattr(pubsubs_gsub[index_alice].seen_messages, "cache", {})
|
||||
|
||||
# Simulate Bob sending IHAVE to Alice
|
||||
await gossipsubs[index_alice].handle_ihave(ihave_msg, id_bob)
|
||||
|
||||
# emit_iwant should not be called since there are no message IDs
|
||||
mock_emit_iwant.assert_not_called()
|
||||
|
||||
@ -15,6 +15,7 @@ import pytest
|
||||
import trio
|
||||
|
||||
from libp2p.utils.logging import (
|
||||
_current_handlers,
|
||||
_current_listener,
|
||||
_listener_ready,
|
||||
log_queue,
|
||||
@ -24,13 +25,19 @@ from libp2p.utils.logging import (
|
||||
|
||||
def _reset_logging():
|
||||
"""Reset all logging state."""
|
||||
global _current_listener, _listener_ready
|
||||
global _current_listener, _listener_ready, _current_handlers
|
||||
|
||||
# Stop existing listener if any
|
||||
if _current_listener is not None:
|
||||
_current_listener.stop()
|
||||
_current_listener = None
|
||||
|
||||
# Close all file handlers to ensure proper cleanup on Windows
|
||||
for handler in _current_handlers:
|
||||
if isinstance(handler, logging.FileHandler):
|
||||
handler.close()
|
||||
_current_handlers.clear()
|
||||
|
||||
# Reset the event
|
||||
_listener_ready = threading.Event()
|
||||
|
||||
@ -174,6 +181,15 @@ async def test_custom_log_file(clean_env):
|
||||
if _current_listener is not None:
|
||||
_current_listener.stop()
|
||||
|
||||
# Give a moment for the listener to fully stop
|
||||
await trio.sleep(0.05)
|
||||
|
||||
# Close all file handlers to release the file
|
||||
for handler in _current_handlers:
|
||||
if isinstance(handler, logging.FileHandler):
|
||||
handler.flush() # Ensure all writes are flushed
|
||||
handler.close()
|
||||
|
||||
# Check if the file exists and contains our message
|
||||
assert log_file.exists()
|
||||
content = log_file.read_text()
|
||||
@ -185,16 +201,15 @@ async def test_default_log_file(clean_env):
|
||||
"""Test logging to the default file path."""
|
||||
os.environ["LIBP2P_DEBUG"] = "INFO"
|
||||
|
||||
with patch("libp2p.utils.logging.datetime") as mock_datetime:
|
||||
# Mock the timestamp to have a predictable filename
|
||||
mock_datetime.now.return_value.strftime.return_value = "20240101_120000"
|
||||
with patch("libp2p.utils.paths.create_temp_file") as mock_create_temp:
|
||||
# Mock the temp file creation to return a predictable path
|
||||
mock_temp_file = (
|
||||
Path(tempfile.gettempdir()) / "test_py-libp2p_20240101_120000.log"
|
||||
)
|
||||
mock_create_temp.return_value = mock_temp_file
|
||||
|
||||
# Remove the log file if it exists
|
||||
if os.name == "nt": # Windows
|
||||
log_file = Path("C:/Windows/Temp/20240101_120000_py-libp2p.log")
|
||||
else: # Unix-like
|
||||
log_file = Path("/tmp/20240101_120000_py-libp2p.log")
|
||||
log_file.unlink(missing_ok=True)
|
||||
mock_temp_file.unlink(missing_ok=True)
|
||||
|
||||
setup_logging()
|
||||
|
||||
@ -211,9 +226,18 @@ async def test_default_log_file(clean_env):
|
||||
if _current_listener is not None:
|
||||
_current_listener.stop()
|
||||
|
||||
# Check the default log file
|
||||
if log_file.exists(): # Only check content if we have write permission
|
||||
content = log_file.read_text()
|
||||
# Give a moment for the listener to fully stop
|
||||
await trio.sleep(0.05)
|
||||
|
||||
# Close all file handlers to release the file
|
||||
for handler in _current_handlers:
|
||||
if isinstance(handler, logging.FileHandler):
|
||||
handler.flush() # Ensure all writes are flushed
|
||||
handler.close()
|
||||
|
||||
# Check the mocked temp file
|
||||
if mock_temp_file.exists():
|
||||
content = mock_temp_file.read_text()
|
||||
assert "Test message" in content
|
||||
|
||||
|
||||
|
||||
290
tests/utils/test_paths.py
Normal file
290
tests/utils/test_paths.py
Normal file
@ -0,0 +1,290 @@
|
||||
"""
|
||||
Tests for cross-platform path utilities.
|
||||
"""
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
|
||||
import pytest
|
||||
|
||||
from libp2p.utils.paths import (
|
||||
create_temp_file,
|
||||
ensure_dir_exists,
|
||||
find_executable,
|
||||
get_binary_path,
|
||||
get_config_dir,
|
||||
get_project_root,
|
||||
get_python_executable,
|
||||
get_script_binary_path,
|
||||
get_script_dir,
|
||||
get_temp_dir,
|
||||
get_venv_path,
|
||||
join_paths,
|
||||
normalize_path,
|
||||
resolve_relative_path,
|
||||
)
|
||||
|
||||
|
||||
class TestPathUtilities:
|
||||
"""Test cross-platform path utilities."""
|
||||
|
||||
def test_get_temp_dir(self):
|
||||
"""Test that temp directory is accessible and exists."""
|
||||
temp_dir = get_temp_dir()
|
||||
assert isinstance(temp_dir, Path)
|
||||
assert temp_dir.exists()
|
||||
assert temp_dir.is_dir()
|
||||
# Should match system temp directory
|
||||
assert temp_dir == Path(tempfile.gettempdir())
|
||||
|
||||
def test_get_project_root(self):
|
||||
"""Test that project root is correctly determined."""
|
||||
project_root = get_project_root()
|
||||
assert isinstance(project_root, Path)
|
||||
assert project_root.exists()
|
||||
# Should contain pyproject.toml
|
||||
assert (project_root / "pyproject.toml").exists()
|
||||
# Should contain libp2p directory
|
||||
assert (project_root / "libp2p").exists()
|
||||
|
||||
def test_join_paths(self):
|
||||
"""Test cross-platform path joining."""
|
||||
# Test with strings
|
||||
result = join_paths("a", "b", "c")
|
||||
expected = Path("a") / "b" / "c"
|
||||
assert result == expected
|
||||
|
||||
# Test with mixed types
|
||||
result = join_paths("a", Path("b"), "c")
|
||||
expected = Path("a") / "b" / "c"
|
||||
assert result == expected
|
||||
|
||||
# Test with absolute path
|
||||
result = join_paths("/absolute", "path")
|
||||
expected = Path("/absolute") / "path"
|
||||
assert result == expected
|
||||
|
||||
def test_ensure_dir_exists(self, tmp_path):
|
||||
"""Test directory creation and existence checking."""
|
||||
# Test creating new directory
|
||||
new_dir = tmp_path / "new_dir"
|
||||
result = ensure_dir_exists(new_dir)
|
||||
assert result == new_dir
|
||||
assert new_dir.exists()
|
||||
assert new_dir.is_dir()
|
||||
|
||||
# Test creating nested directory
|
||||
nested_dir = tmp_path / "parent" / "child" / "grandchild"
|
||||
result = ensure_dir_exists(nested_dir)
|
||||
assert result == nested_dir
|
||||
assert nested_dir.exists()
|
||||
assert nested_dir.is_dir()
|
||||
|
||||
# Test with existing directory
|
||||
result = ensure_dir_exists(new_dir)
|
||||
assert result == new_dir
|
||||
assert new_dir.exists()
|
||||
|
||||
def test_get_config_dir(self):
|
||||
"""Test platform-specific config directory."""
|
||||
config_dir = get_config_dir()
|
||||
assert isinstance(config_dir, Path)
|
||||
|
||||
if os.name == "nt": # Windows
|
||||
# Should be in AppData/Roaming or user home
|
||||
assert "AppData" in str(config_dir) or "py-libp2p" in str(config_dir)
|
||||
else: # Unix-like
|
||||
# Should be in ~/.config
|
||||
assert ".config" in str(config_dir)
|
||||
assert "py-libp2p" in str(config_dir)
|
||||
|
||||
def test_get_script_dir(self):
|
||||
"""Test script directory detection."""
|
||||
# Test with current file
|
||||
script_dir = get_script_dir(__file__)
|
||||
assert isinstance(script_dir, Path)
|
||||
assert script_dir.exists()
|
||||
assert script_dir.is_dir()
|
||||
# Should contain this test file
|
||||
assert (script_dir / "test_paths.py").exists()
|
||||
|
||||
def test_create_temp_file(self):
|
||||
"""Test temporary file creation."""
|
||||
temp_file = create_temp_file()
|
||||
assert isinstance(temp_file, Path)
|
||||
assert temp_file.parent == get_temp_dir()
|
||||
assert temp_file.name.startswith("py-libp2p_")
|
||||
assert temp_file.name.endswith(".log")
|
||||
|
||||
# Test with custom prefix and suffix
|
||||
temp_file = create_temp_file(prefix="test_", suffix=".txt")
|
||||
assert temp_file.name.startswith("test_")
|
||||
assert temp_file.name.endswith(".txt")
|
||||
|
||||
def test_resolve_relative_path(self, tmp_path):
|
||||
"""Test relative path resolution."""
|
||||
base_path = tmp_path / "base"
|
||||
base_path.mkdir()
|
||||
|
||||
# Test relative path
|
||||
relative_path = "subdir/file.txt"
|
||||
result = resolve_relative_path(base_path, relative_path)
|
||||
expected = (base_path / "subdir" / "file.txt").resolve()
|
||||
assert result == expected
|
||||
|
||||
# Test absolute path (platform-agnostic)
|
||||
if os.name == "nt": # Windows
|
||||
absolute_path = "C:\\absolute\\path"
|
||||
else: # Unix-like
|
||||
absolute_path = "/absolute/path"
|
||||
result = resolve_relative_path(base_path, absolute_path)
|
||||
assert result == Path(absolute_path)
|
||||
|
||||
def test_normalize_path(self, tmp_path):
|
||||
"""Test path normalization."""
|
||||
# Test with relative path
|
||||
relative_path = tmp_path / ".." / "normalize_test"
|
||||
result = normalize_path(relative_path)
|
||||
assert result.is_absolute()
|
||||
assert "normalize_test" in str(result)
|
||||
|
||||
# Test with absolute path
|
||||
absolute_path = tmp_path / "test_file"
|
||||
result = normalize_path(absolute_path)
|
||||
assert result.is_absolute()
|
||||
assert result == absolute_path.resolve()
|
||||
|
||||
def test_get_venv_path(self, monkeypatch):
|
||||
"""Test virtual environment path detection."""
|
||||
# Test when no virtual environment is active
|
||||
# Temporarily clear VIRTUAL_ENV to test the "no venv" case
|
||||
monkeypatch.delenv("VIRTUAL_ENV", raising=False)
|
||||
result = get_venv_path()
|
||||
assert result is None
|
||||
|
||||
# Test when virtual environment is active
|
||||
test_venv_path = "/path/to/venv"
|
||||
monkeypatch.setenv("VIRTUAL_ENV", test_venv_path)
|
||||
result = get_venv_path()
|
||||
assert result == Path(test_venv_path)
|
||||
|
||||
def test_get_python_executable(self):
|
||||
"""Test Python executable path detection."""
|
||||
result = get_python_executable()
|
||||
assert isinstance(result, Path)
|
||||
assert result.exists()
|
||||
assert result.name.startswith("python")
|
||||
|
||||
def test_find_executable(self):
|
||||
"""Test executable finding in PATH."""
|
||||
# Test with non-existent executable
|
||||
result = find_executable("nonexistent_executable")
|
||||
assert result is None
|
||||
|
||||
# Test with existing executable (python should be available)
|
||||
result = find_executable("python")
|
||||
if result:
|
||||
assert isinstance(result, Path)
|
||||
assert result.exists()
|
||||
|
||||
def test_get_script_binary_path(self):
|
||||
"""Test script binary path detection."""
|
||||
result = get_script_binary_path()
|
||||
assert isinstance(result, Path)
|
||||
assert result.exists()
|
||||
assert result.is_dir()
|
||||
|
||||
def test_get_binary_path(self, monkeypatch):
|
||||
"""Test binary path resolution with virtual environment."""
|
||||
# Test when no virtual environment is active
|
||||
result = get_binary_path("python")
|
||||
if result:
|
||||
assert isinstance(result, Path)
|
||||
assert result.exists()
|
||||
|
||||
# Test when virtual environment is active
|
||||
test_venv_path = "/path/to/venv"
|
||||
monkeypatch.setenv("VIRTUAL_ENV", test_venv_path)
|
||||
# This test is more complex as it depends on the actual venv structure
|
||||
# We'll just verify the function doesn't crash
|
||||
result = get_binary_path("python")
|
||||
# Result can be None if binary not found in venv
|
||||
if result:
|
||||
assert isinstance(result, Path)
|
||||
|
||||
|
||||
class TestCrossPlatformCompatibility:
|
||||
"""Test cross-platform compatibility."""
|
||||
|
||||
def test_config_dir_platform_specific_windows(self, monkeypatch):
|
||||
"""Test config directory respects Windows conventions."""
|
||||
import platform
|
||||
|
||||
# Only run this test on Windows systems
|
||||
if platform.system() != "Windows":
|
||||
pytest.skip("This test only runs on Windows systems")
|
||||
|
||||
monkeypatch.setattr("os.name", "nt")
|
||||
monkeypatch.setenv("APPDATA", "C:\\Users\\Test\\AppData\\Roaming")
|
||||
config_dir = get_config_dir()
|
||||
assert "AppData" in str(config_dir)
|
||||
assert "py-libp2p" in str(config_dir)
|
||||
|
||||
def test_path_separators_consistent(self):
|
||||
"""Test that path separators are handled consistently."""
|
||||
# Test that join_paths uses platform-appropriate separators
|
||||
result = join_paths("dir1", "dir2", "file.txt")
|
||||
expected = Path("dir1") / "dir2" / "file.txt"
|
||||
assert result == expected
|
||||
|
||||
# Test that the result uses correct separators for the platform
|
||||
if os.name == "nt": # Windows
|
||||
assert "\\" in str(result) or "/" in str(result)
|
||||
else: # Unix-like
|
||||
assert "/" in str(result)
|
||||
|
||||
def test_temp_file_uniqueness(self):
|
||||
"""Test that temporary files have unique names."""
|
||||
files = set()
|
||||
for _ in range(10):
|
||||
temp_file = create_temp_file()
|
||||
assert temp_file not in files
|
||||
files.add(temp_file)
|
||||
|
||||
|
||||
class TestBackwardCompatibility:
|
||||
"""Test backward compatibility with existing code patterns."""
|
||||
|
||||
def test_path_operations_equivalent(self):
|
||||
"""Test that new path operations are equivalent to old os.path operations."""
|
||||
# Test join_paths vs os.path.join
|
||||
parts = ["a", "b", "c"]
|
||||
new_result = join_paths(*parts)
|
||||
old_result = Path(os.path.join(*parts))
|
||||
assert new_result == old_result
|
||||
|
||||
# Test get_script_dir vs os.path.dirname(os.path.abspath(__file__))
|
||||
new_script_dir = get_script_dir(__file__)
|
||||
old_script_dir = Path(os.path.dirname(os.path.abspath(__file__)))
|
||||
assert new_script_dir == old_script_dir
|
||||
|
||||
def test_existing_functionality_preserved(self):
|
||||
"""Ensure no existing functionality is broken."""
|
||||
# Test that all functions return Path objects
|
||||
assert isinstance(get_temp_dir(), Path)
|
||||
assert isinstance(get_project_root(), Path)
|
||||
assert isinstance(join_paths("a", "b"), Path)
|
||||
assert isinstance(ensure_dir_exists(tempfile.gettempdir()), Path)
|
||||
assert isinstance(get_config_dir(), Path)
|
||||
assert isinstance(get_script_dir(__file__), Path)
|
||||
assert isinstance(create_temp_file(), Path)
|
||||
assert isinstance(resolve_relative_path(".", "test"), Path)
|
||||
assert isinstance(normalize_path("."), Path)
|
||||
assert isinstance(get_python_executable(), Path)
|
||||
assert isinstance(get_script_binary_path(), Path)
|
||||
|
||||
# Test optional return types
|
||||
venv_path = get_venv_path()
|
||||
if venv_path is not None:
|
||||
assert isinstance(venv_path, Path)
|
||||
Reference in New Issue
Block a user