Back to Repositories

Testing FileExplorer Component Security and Configuration in Gradio

This test suite validates the FileExplorer component in the Gradio framework, focusing on file handling, path validation, and configuration management. The tests ensure proper functionality of single and multiple file selection modes while maintaining security against path traversal attacks.

Test Coverage Overview

The test suite provides comprehensive coverage of the FileExplorer component functionality.

Key areas tested include:
  • Single and multiple file selection modes
  • File preprocessing and configuration validation
  • File glob pattern filtering
  • Directory structure handling
  • Security measures against path traversal

Implementation Analysis

The testing approach utilizes pytest fixtures and class-based organization for structured test cases. The implementation leverages PathLib for file system operations and combines both functional and security testing patterns. Specific test methods verify component configuration, data preprocessing, and file system interactions.

Technical Details

Testing tools and setup:
  • pytest as the primary testing framework
  • tmpdir fixture for temporary directory creation
  • PathLib for cross-platform file path handling
  • Custom FileExplorerData class for input simulation
  • Mock directory structures for file system testing

Best Practices Demonstrated

The test suite exemplifies several testing best practices including isolation of test cases, proper exception handling, and security-focused validation. Notable practices include:
  • Separate test methods for distinct functionality
  • Thorough validation of component configuration
  • Security testing for path traversal prevention
  • Use of fixtures for test data management

gradio-app/gradio

test/components/test_file_explorer.py

            
from pathlib import Path

import pytest

import gradio as gr
from gradio.components.file_explorer import FileExplorerData
from gradio.exceptions import InvalidPathError


class TestFileExplorer:
    def test_component_functions(self):
        """
        Preprocess, get_config
        """
        file_explorer = gr.FileExplorer(file_count="single")

        config = file_explorer.get_config()
        assert config["glob"] == "**/*"
        assert config["value"] is None
        assert config["file_count"] == "single"
        assert config["server_fns"] == ["ls"]

        input_data = FileExplorerData(root=[["test/test_files/bus.png"]])
        preprocessed_data = file_explorer.preprocess(input_data)
        assert isinstance(preprocessed_data, str)
        assert Path(preprocessed_data).name == "bus.png"

        input_data = FileExplorerData(root=[])
        preprocessed_data = file_explorer.preprocess(input_data)
        assert preprocessed_data is None

        file_explorer = gr.FileExplorer(file_count="multiple")

        config = file_explorer.get_config()
        assert config["glob"] == "**/*"
        assert config["value"] is None
        assert config["file_count"] == "multiple"
        assert config["server_fns"] == ["ls"]

        input_data = FileExplorerData(root=[["test/test_files/bus.png"]])
        preprocessed_data = file_explorer.preprocess(input_data)
        assert isinstance(preprocessed_data, list)
        assert Path(preprocessed_data[0]).name == "bus.png"

        input_data = FileExplorerData(root=[])
        preprocessed_data = file_explorer.preprocess(input_data)
        assert preprocessed_data == []

    def test_file_explorer_txt_only_glob(self, tmpdir):
        tmpdir.mkdir("foo")
        (Path(tmpdir) / "foo" / "bar").mkdir()
        (Path(tmpdir) / "foo" / "file.txt").touch()
        (Path(tmpdir) / "foo" / "file2.txt").touch()
        (Path(tmpdir) / "foo" / "file3.log").touch()
        (Path(tmpdir) / "foo" / "img.png").touch()
        (Path(tmpdir) / "foo" / "bar" / "bar.txt").touch()

        file_explorer = gr.FileExplorer(glob="*.txt", root_dir=Path(tmpdir))
        tree = file_explorer.ls(["foo"])

        answer = [
            {"name": "bar", "type": "folder", "valid": False},
            {"name": "file.txt", "type": "file", "valid": True},
            {"name": "file2.txt", "type": "file", "valid": True},
        ]
        assert tree == answer

    def test_file_explorer_prevents_path_traversal(self, tmpdir):
        file_explorer = gr.FileExplorer(glob="*.txt", root_dir=Path(tmpdir))

        with pytest.raises(InvalidPathError):
            file_explorer.ls(["../file.txt"])