File size: 6,444 Bytes
0fd441a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# tests/test_main_ui.py
# run with pytest tests/.

import pytest
from unittest.mock import patch, MagicMock
from pathlib import Path

from main import build_interface  # Wait, main imports from ui, but test main logic
from ui.gradio_ui import convert_batch, build_interface, accumulate_files, clear_state, pdf_files_wrap
from utils.logger import get_logger

logger = get_logger("test_main_ui")

@pytest.fixture
def mock_gradio():
    with patch('gradio.Blocks') as mock_blocks, \
         patch('gradio.Markdown') as mock_md, \
         patch('gradio.Accordion') as mock_accordion, \
         patch('gradio.Dropdown') as mock_dropdown, \
         patch('gradio.Textbox') as mock_textbox, \
         patch('gradio.Slider') as mock_slider, \
         patch('gradio.Checkbox') as mock_checkbox, \
         patch('gradio.Button') as mock_button, \
         patch('gradio.File') as mock_file, \
         patch('gradio.UploadButton') as mock_upload, \
         patch('gradio.State') as mock_state, \
         patch('gradio.Tab') as mock_tab, \
         patch('gradio.JSON') as mock_json, \
         patch('gradio.Files') as mock_files, \
         patch('gradio.Gallery') as mock_gallery:
        yield {
            'Blocks': mock_blocks, 'Markdown': mock_md, 'Accordion': mock_accordion,
            'Dropdown': mock_dropdown, 'Textbox': mock_textbox, 'Slider': mock_slider,
            'Checkbox': mock_checkbox, 'Button': mock_button, 'File': mock_file,
            'UploadButton': mock_upload, 'State': mock_state, 'Tab': mock_tab,
            'JSON': mock_json, 'Files': mock_files, 'Gallery': mock_gallery
        }

def test_build_interface(mock_gradio):
    demo = build_interface()
    assert demo is not None
    # Verify UI components are created
    mock_gradio['Blocks'].assert_called_once_with(title="parserPDF", css=MagicMock())
    mock_gradio['Markdown'].assert_called()  # Title markdown
    mock_gradio['Accordion'].assert_any_call("βš™οΈ LLM Model Settings", open=False)
    mock_gradio['Tab'].assert_any_call(" πŸ“„ PDF & HTML ➜ Markdown")

def test_convert_batch_no_files():
    result = convert_batch([], 0, "huggingface", "test-model", "fireworks-ai", "", "model-id", 
                          "system", 1024, 0.0, 0.1, False, "token", 
                          "https://router.huggingface.co/v1", "webp", 4, 2, "markdown", 
                          "output_dir", False, None)
    assert "No files uploaded" in result[0]

@patch('ui.gradio_ui.login_huggingface')
@patch('ui.gradio_ui.ProcessPoolExecutor')
@patch('ui.gradio_ui.pdf2md_converter.convert_files')
def test_convert_batch_success(mock_convert, mock_pool, mock_login):
    mock_result = MagicMock()
    mock_convert.return_value = {"filepath": Path("test.md"), "image_path": ["img.jpg"], "markdown": "content"}
    mock_pool.return_value.__enter__.return_value.map.return_value = [mock_result]
    mock_login.return_value = None
    
    pdf_files = [MagicMock(name="test.pdf")]
    result = convert_batch(pdf_files, 1, "huggingface", "test-model", "fireworks-ai", "", "model-id", 
                          "system", 1024, 0.0, 0.1, False, "token", 
                          "https://router.huggingface.co/v1", "webp", 4, 2, "markdown", 
                          "output_dir", False, None)
    
    assert len(result) == 3
    assert "test.md" in result[0]
    assert "img.jpg" in result[2][0]
    mock_pool.assert_called_once()
    mock_convert.assert_called_once_with("test.pdf")

@patch('ui.gradio_ui.ProcessPoolExecutor')
def test_convert_batch_pool_error(mock_pool):
    mock_pool.side_effect = Exception("Pool error")
    pdf_files = [MagicMock(name="test.pdf")]
    result = convert_batch(pdf_files, 1, "huggingface", "test-model", "fireworks-ai", "", "model-id", 
                          "system", 1024, 0.0, 0.1, False, "token", 
                          "https://router.huggingface.co/v1", "webp", 4, 2, "markdown", 
                          "output_dir", False, None)
    assert "Error during ProcessPoolExecutor" in result[0]

def test_accumulate_files():
    # Test initial accumulation
    new_files = [MagicMock(name="/tmp/file1.pdf"), MagicMock(name="/tmp/file2.html")]
    state = []
    updated_state, message = accumulate_files(new_files, state)
    assert len(updated_state) == 2
    assert "/tmp/file1.pdf" in updated_state
    assert "Accumulated 2 file(s)" in message
    
    # Test adding to existing state
    new_files2 = [MagicMock(name="/tmp/file3.pdf")]
    updated_state2, message2 = accumulate_files(new_files2, updated_state)
    assert len(updated_state2) == 3
    assert "Accumulated 3 file(s)" in message2
    
    # Test no new files
    _, message3 = accumulate_files([], updated_state2)
    assert "No new files uploaded" in message3

def test_clear_state():
    result = clear_state()
    assert len(result) == 4
    assert result[0] == []  # cleared file list
    assert result[1] == "Files list cleared."  # message
    assert result[2] == []  # cleared file btn
    assert result[3] == []  # cleared dir btn

def test_pdf_files_wrap():
    # Single file
    single_file = "single.pdf"
    wrapped = pdf_files_wrap(single_file)
    assert isinstance(wrapped, list)
    assert len(wrapped) == 1
    assert wrapped[0] == single_file
    
    # List of files
    files_list = ["file1.pdf", "file2.html"]
    wrapped_list = pdf_files_wrap(files_list)
    assert wrapped_list == files_list
    
    # None input
    assert pdf_files_wrap(None) == [None]

@patch('ui.gradio_ui.os.chdir')
@patch('ui.gradio_ui.Path')
def test_main_launch(mock_path, mock_chdir):
    mock_script_dir = MagicMock()
    mock_path.return_value.resolve.return_value.parent = mock_script_dir
    mock_chdir.return_value = None
    
    # Test main execution path
    with patch('builtins.__name__', '__main__'):
        from main import main  # Assuming main has a main function, or test the if __name__ logic indirectly
        # Since main.py is simple, test the key parts
        demo = MagicMock()
        with patch('ui.gradio_ui.build_interface', return_value=demo):
            with patch('gradio.Interface.launch') as mock_launch:
                # Execute main logic
                import main
                main.main()  # If it has main(), or just import runs it
                
                mock_chdir.assert_called_once_with(mock_script_dir)
                mock_launch.assert_called_once_with(debug=True, show_error=True)