| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251 |
- """
- Tests for the Drag-and-Drop Upload Zone component (Story 7.14).
- """
- import pytest
- from pathlib import Path
- import tempfile
- from PyQt6.QtWidgets import QApplication
- from PyQt6.QtCore import QMimeData, QUrl
- from src.ui.drop_zone import (
- DropState,
- DroppedFiles,
- DropZoneWidget,
- FileDropArea,
- )
- @pytest.fixture
- def app(qtbot):
- """Create QApplication for tests."""
- return QApplication.instance() or QApplication([])
- @pytest.fixture
- def temp_files(tmp_path):
- """Create temporary test files."""
- files = []
- for ext in [".txt", ".md", ".html", ".jpg"]:
- file_path = tmp_path / f"test{ext}"
- file_path.write_text(f"Test content {ext}")
- files.append(file_path)
- return files
- class TestDropState:
- """Tests for DropState enum."""
- def test_state_values(self):
- """Test DropState enum values."""
- assert DropState.IDLE.value == "idle"
- assert DropState.HOVER.value == "hover"
- assert DropState.PROCESSING.value == "processing"
- assert DropState.ERROR.value == "error"
- class TestDroppedFiles:
- """Tests for DroppedFiles."""
- def test_creation(self):
- """Test creating DroppedFiles."""
- files = [Path("file1.txt"), Path("file2.md")]
- folders = [Path("folder1")]
- invalid = ["file.exe"]
- dropped = DroppedFiles(
- files=files,
- folders=folders,
- invalid=invalid
- )
- assert len(dropped.files) == 2
- assert len(dropped.folders) == 1
- assert len(dropped.invalid) == 1
- class TestDropZoneWidget:
- """Tests for DropZoneWidget."""
- def test_initialization(self, qtbot):
- """Test widget initialization."""
- widget = DropZoneWidget()
- qtbot.addWidget(widget)
- assert widget._state == DropState.IDLE
- assert widget._drag_active is False
- def test_supported_extensions(self):
- """Test supported file extensions."""
- expected = [".txt", ".md", ".html", ".htm"]
- assert DropZoneWidget.SUPPORTED_EXTENSIONS == expected
- def test_is_valid_file(self, qtbot):
- """Test file validation."""
- widget = DropZoneWidget()
- qtbot.addWidget(widget)
- # Valid files
- assert widget._is_valid_file(Path("test.txt")) is True
- assert widget._is_valid_file(Path("test.md")) is True
- assert widget._is_valid_file(Path("test.html")) is True
- # Invalid files
- assert widget._is_valid_file(Path("test.jpg")) is False
- assert widget._is_valid_file(Path("test.exe")) is False
- assert widget._is_valid_file(Path("test")) is False
- def test_set_state_idle(self, qtbot):
- """Test setting IDLE state."""
- widget = DropZoneWidget()
- qtbot.addWidget(widget)
- widget._set_state(DropState.IDLE)
- assert widget._state == DropState.IDLE
- def test_set_state_hover(self, qtbot):
- """Test setting HOVER state."""
- widget = DropZoneWidget()
- qtbot.addWidget(widget)
- widget._set_state(DropState.HOVER)
- assert widget._state == DropState.HOVER
- def test_set_state_error(self, qtbot):
- """Test setting ERROR state."""
- widget = DropZoneWidget()
- qtbot.addWidget(widget)
- widget._set_state(DropState.ERROR)
- assert widget._state == DropState.ERROR
- def test_set_state_processing(self, qtbot):
- """Test setting PROCESSING state."""
- widget = DropZoneWidget()
- qtbot.addWidget(widget)
- widget._set_state(DropState.PROCESSING)
- assert widget._state == DropState.PROCESSING
- assert widget._progress_bar.isVisible() is True
- def test_get_valid_files_from_mime(self, qtbot, temp_files):
- """Test extracting valid files from mime data."""
- widget = DropZoneWidget()
- qtbot.addWidget(widget)
- # Create mime data with URLs
- mime_data = QMimeData()
- urls = [QUrl.fromLocalFile(str(f)) for f in temp_files]
- mime_data.setUrls(urls)
- valid_urls = widget._get_valid_files(mime_data)
- # Should have 3 valid files (txt, md, html)
- assert len(valid_urls) == 3
- def test_process_mime_data(self, qtbot, temp_files):
- """Test processing mime data."""
- widget = DropZoneWidget()
- qtbot.addWidget(widget)
- # Create mime data with valid and invalid files
- mime_data = QMimeData()
- urls = [QUrl.fromLocalFile(str(f)) for f in temp_files]
- mime_data.setUrls(urls)
- dropped = widget._process_mime_data(mime_data)
- assert len(dropped.files) == 3 # txt, md, html
- assert len(dropped.invalid) == 1 # jpg
- assert len(dropped.folders) == 0
- class TestFileDropArea:
- """Tests for FileDropArea."""
- def test_initialization(self, qtbot):
- """Test area initialization."""
- area = FileDropArea()
- qtbot.addWidget(area)
- assert area.file_count == 0
- assert area.files == []
- def test_on_files_dropped(self, qtbot, tmp_path):
- """Test handling dropped files."""
- area = FileDropArea()
- qtbot.addWidget(area)
- # Create dropped files
- files = [tmp_path / "test1.txt", tmp_path / "test2.md"]
- for f in files:
- f.write_text("content")
- dropped = DroppedFiles(files=files, folders=[], invalid=[])
- # Mock signal emission
- area._on_files_dropped(dropped)
- assert area.file_count == 2
- assert len(area.files) == 2
- def test_clear(self, qtbot, tmp_path):
- """Test clearing files."""
- area = FileDropArea()
- qtbot.addWidget(area)
- # Add some files
- files = [tmp_path / "test1.txt", tmp_path / "test2.md"]
- for f in files:
- f.write_text("content")
- dropped = DroppedFiles(files=files, folders=[], invalid=[])
- area._on_files_dropped(dropped)
- assert area.file_count == 2
- # Clear
- area.clear()
- assert area.file_count == 0
- assert area.files == []
- def test_on_clear(self, qtbot, tmp_path):
- """Test clear button handler."""
- area = FileDropArea()
- qtbot.addWidget(area)
- # Add files
- files = [tmp_path / "test.txt"]
- files[0].write_text("content")
- dropped = DroppedFiles(files=files, folders=[], invalid=[])
- area._on_files_dropped(dropped)
- assert area.file_count == 1
- # Click clear
- area._on_clear()
- assert area.file_count == 0
- def test_update_display(self, qtbot, tmp_path):
- """Test display update."""
- area = FileDropArea()
- qtbot.addWidget(area)
- # Add files
- for i in range(5):
- f = tmp_path / f"test{i}.txt"
- f.write_text(f"content {i}")
- area._dropped_files.append(f)
- area._update_display()
- assert area._file_list_widget.isVisible() is True
- assert "5 个文件" in area._count_label.text()
|