Xiantao Hu

30 papers A* 4C 1Journal 21Unranked 4
YearRankTypeTitle / Venue / Authors
2026 A* conf
AAAI
Hao Li, Yuhao Wang, Xiantao Hu, Wenning Hao, Pingping Zhang, Dong Wang, Huchuan Lu
2026 J jnl
Pattern Recognit.
Xiantao Hu, Fansheng Zeng, Bineng Zhong, Zhangyong Tang, Wenxuan Fang, Jun Li, Ying Tai, Jian Yang
2026 J jnl
CoRR
Jiahao Zeng, Zhenkui Shi, Chunpei Li, Mengkai Yan, Hongliang Zhang, Sihan Chen, Xiantao Hu, Xianxian Li
2026 J jnl
Inf. Fusion
Enhao Ning, Libin Wu, Sheng Xie, Jie Yang, Xiantao Hu, Zhipeng Hu, Huang Zhang, Hemant Ghayvat, Xin Ning
2026 J jnl
IEEE Trans. Inf. Forensics Secur.
Songping Wang, Hanqing Liu, Yueming Lyu, Xiantao Hu, Ziwen He, Wei Wang, Caifeng Shan, Liang Wang
2026 J jnl
Pattern Recognit.
Xu Zhao, Chen Zhao, Xiantao Hu, Hongliang Zhang, Ying Tai, Jian Yang
2026 A* conf
AAAI
Hongtao Yang, Bineng Zhong, Qihua Liang, Xiantao Hu, Yufei Tan, Haiying Xia, Shuxiang Song
2025 J jnl
CoRR
Xiantao Hu, Bineng Zhong, Qihua Liang, Zhiyi Mo, Liangtao Shi, Ying Tai, Jian Yang
2025 J jnl
IEEE Trans. Artif. Intell.
Xiantao Hu, Bineng Zhong, Qihua Liang, Liangtao Shi, Zhiyi Mo, Ying Tai, Jian Yang
2025 J jnl
CoRR
Songping Wang, Xiantao Hu, Yueming Lyu, Caifeng Shan
2025 J jnl
CoRR
Hao Li, Yuhao Wang, Xiantao Hu, Wenning Hao, Pingping Zhang, Dong Wang, Huchuan Lu
2025 A* conf
ACM Multimedia
Fansheng Zeng, Bineng Zhong, Haiying Xia, Yufei Tan, Xiantao Hu, Liangtao Shi, Shuxiang Song
2025 J jnl
CoRR
Fansheng Zeng, Bineng Zhong, Haiying Xia, Yufei Tan, Xiantao Hu, Liangtao Shi, Shuxiang Song
2025 A* conf
AAAI
Xiantao Hu, Ying Tai, Xu Zhao, Chen Zhao, Zhenyu Zhang, Jun Li, Bineng Zhong, Jian Yang
2025 J jnl
CoRR
Xu Zhao, Chen Zhao, Xiantao Hu, Hongliang Zhang, Ying Tai, Jian Yang
2025 J jnl
IEEE Trans. Circuits Syst. Video Technol.
Liangtao Shi, Bineng Zhong, Qihua Liang, Xiantao Hu, Zhiyi Mo, Shuxiang Song
2025 J jnl
IEEE Trans. Multim.
Liangtao Shi, Ting Liu, Xiantao Hu, Yue Hu, Quanjun Yin, Richang Hong
2025 J jnl
CoRR
Liangtao Shi, Ting Liu, Xiantao Hu, Yue Hu, Quanjun Yin, Richang Hong
2025 conf
ICCVW
Matei Kristan, Jirí Matas, Pavel Tokmakov, Alan Lukezic, Michael Felsberg, Luka Cehovin Zajc, Khanh-Tung Tran, Xuan-Son Vu, Johanna Björklund, Michal Neoral, Hyung Jin Chang, Gustavo Fernández, Minasadat Attari, Matteo Dunnhofer, Wei Feng, Zhenhua Feng, Jin Gao, Yameng Gu, Ruize Han, Jiawei He, Zhenyu He, Junhui Hou, Weiming Hu, Xiantao Hu, Xingsen Huang, Yuqing Huang, Gleb Kirichenko, Josef Kittler, Yutong Kou, Simiao Lai, Bing Li, Xin Li, Shubo Lin, Huchuan Lu, Deshui Miao, Christian Micheloni, Juan David Mogollon, Moritz Nottebaum, Kannappan Palaniappan, Ziqi Pang, Zekun Qian, Gani Rahmon, Aleksandr Romanov, Liangtao Shi, Roman A. Solovyev, Elham Soltani Kazemi, Imad Eddine Toubal, Jovana Videnovic, Dong Wang, Yaowei Wang, Yu-Xiong Wang, Zhixiang Wang, Xiaojun Wu, Jinxia Xie, Tianyang Xu, Chaocan Xue, Yuanliang Xue, Ming-Hsuan Yang, Dmitriy Yurtov, Chunui Zhang, Xiangqun Zhang, Yunfei Zhang, Qingfang Zheng, Bineng Zhong, Fuan Zhong, Jinglin Zhou, Jingmeng Zhou, Junbao Zhou, Yong Zhou, Xuefeng Zhu
2025 J jnl
CoRR
Wenxuan Fang, Jili Fan, Chao Wang, Xiantao Hu, Jiangwei Weng, Ying Tai, Jian Yang, Jun Li
2024 conf
ICPR (Workshops and Challenges, 4)
Songping Wang, Haoxiang Rao, Xiantao Hu, Yueming Lyu, Caifeng Shan
2024 J jnl
CoRR
Xiantao Hu, Ying Tai, Xu Zhao, Chen Zhao, Zhenyu Zhang, Jun Li, Bineng Zhong, Jian Yang
2024 C conf
CSCWD
Wolong Xing, Zhenkui Shi, Hongyan Peng, Xiantao Hu, Yaozong Zheng, Xianxian Li
2024 J jnl
CoRR
Wolong Xing, Zhenkui Shi, Hongyan Peng, Xiantao Hu, Xianxian Li
2024 conf
ECCV Workshops (7)
Matej Kristan, Jirí Matas, Pavel Tokmakov, Michael Felsberg, Luka Cehovin Zajc, Alan Lukezic, Khanh-Tung Tran, Xuan-Son Vu, Johanna Björklund, Hyung Jin Chang, Gustavo Fernández, Minasadat Attari, Antoni B. Chan, Liang Chen, Xin Chen, Jaired Collins, Yutao Cui, Ganesh Sai Manas Devarapu, Yinglong Du, Heng Fan, Wan-Cyuan Fan, Zhenhua Feng, Mingqi Gao, Rama Krishna Sai S. Gorthi, Raghav Goyal, Jungong Han, Bijaya Kumar Hatuwal, Zhenyu He, Xiantao Hu, Xingsen Huang, Yuqing Huang, Dongmei Jiang, Ben Kang, Kannappan Palaniappan, Josef Kittler, Simiao Lai, Ning Li, Xiaohai Li, Xin Li, Cheng Liang, Liting Lin, Haibin Ling, Ting Liu, Ziquan Liu, Huchuan Lu, Yifei Luo, Deshui Miao, Juan David Mogollon, Ziqi Pang, Jaswanth Reddy Pochimireddy, Viktor Prutyanov, Gani Rahmon, Aleksandr Romanov, Liangtao Shi, Mennatullah Siam, Leonid Sigal, Arun Kumar Sivapuram, Roman A. Solovyev, Elham Soltani Kazemi, Imad Eddine Toubal, Jia Wan, Limin Wang, Xinying Wang, Yaowei Wang, Yu-Xiong Wang, Zhiquan Wang, Gangshan Wu, Qiangqiang Wu, Xiaojun Wu, Zihao Xia, Jinxia Xie, Chenlong Xu, Tianyang Xu, Yong Xu, Chaocan Xue, Chao Yang, Jinyu Yang, Ming-Hsuan Yang, Chenyang Yu, Ke Yu, Chunhui Zhang, Jiaming Zhang, Zhipeng Zhang, Feng Zheng, Yaozong Zheng, Bineng Zhong, Jinglin Zhou, Junbao Zhou, Yong Zhou, Zikun Zhou, Guibo Zhu, Jiawen Zhu, Xuefeng Zhu, Vladimir V. Zunin
2024 J jnl
IEEE Trans. Circuits Syst. Video Technol.
Xiantao Hu, Bineng Zhong, Qihua Liang, Shengping Zhang, Ning Li, Xianxian Li
2024 J jnl
IEEE Trans. Circuits Syst. Video Technol.
Xiantao Hu, Bineng Zhong, Qihua Liang, Shengping Zhang, Ning Li, Xianxian Li, Rongrong Ji
2023 conf
ICCV (Workshops)
Matej Kristan, Jirí Matas, Martin Danelljan, Michael Felsberg, Hyung Jin Chang, Luka Cehovin Zajc, Alan Lukezic, Ondrej Drbohlav, Zhongqun Zhang, Khanh-Tung Tran, Xuan-Son Vu, Johanna Björklund, Christoph Mayer, Yushan Zhang, Lei Ke, Jie Zhao, Gustavo Fernández, Noor Al-Shakarji, Dong An, Michael Arens, Stefan Becker, Goutam Bhat, Sebastian Bullinger, Antoni B. Chan, Shijie Chang, Hanyuan Chen, Xin Chen, Yan Chen, Zhenyu Chen, Yangming Cheng, Yutao Cui, Chunyuan Deng, Jiahua Dong, Matteo Dunnhofer, Wei Feng, Jianlong Fu, Jie Gao, Ruize Han, Zeqi Hao, Jun-Yan He, Keji He, Zhenyu He, Xiantao Hu, Kaer Huang, Yuqing Huang, Yi Jiang, Ben Kang, Jin-Peng Lan, Hyungjun Lee, Chenyang Li, Jiahao Li, Ning Li, Wangkai Li, Xiaodi Li, Xin Li, Pengyu Liu, Yue Liu, Huchuan Lu, Bin Luo, Ping Luo, Yinchao Ma, Deshui Miao, Christian Micheloni, Kannappan Palaniappan, Hancheol Park, Matthieu Paul, Houwen Peng, Zekun Qian, Gani Rahmon, Norbert Scherer-Negenborn, Pengcheng Shao, Wooksu Shin, Elham Soltani Kazemi, Tianhui Song, Rainer Stiefelhagen, Rui Sun, Chuanming Tang, Zhangyong Tang, Imad Eddine Toubal, Jack Valmadre, Joost van de Weijer, Luc Van Gool, Jash Vira, Stéphane Vujasinovic, Cheng Wan, Jia Wan, Dong Wang, Fei Wang, Feifan Wang, He Wang, Limin Wang, Song Wang, Yaowei Wang, Zhepeng Wang, Gangshan Wu, Jiannan Wu, Qiangqiang Wu, Xiaojun Wu, Anqi Xiao, Jinxia Xie, Chenlong Xu, Min Xu, Tianyang Xu, Yuanyou Xu, Bin Yan, Dawei Yang, Ming-Hsuan Yang, Tianyu Yang, Yi Yang, Zongxin Yang, Xuanwu Yin, Fisher Yu, Hongyuan Yu, Qianjin Yu, Weichen Yu, Yongsheng Yuan, Zehuan Yuan, Jianlin Zhang, Lu Zhang, Tianzhu Zhang, Guodongfang Zhao, Shaochuan Zhao, Yaozong Zheng, Bineng Zhong, Jiawen Zhu, Xuefeng Zhu, Yueting Zhuang, ChengAo Zong, Kunlong Zuo
2015 J jnl
Neurocomputing
Liuwei Zhou, Zhijie Wang, Xiantao Hu, Bo Chu, Wuneng Zhou
2015 J jnl
J. Frankl. Inst.
Xianghui Zhou, Wuneng Zhou, Jun Yang, Xiantao Hu
tests/integration/test_basicproperties.py
← Index tests/integration/test_basicproperties.py python
"""
Integration tests for the BasicPropertiesExtractor class.
"""
import pytest
import os
from unittest.mock import Mock, patch, MagicMock

pytestmark = [pytest.mark.integration]


class TestBasicPropertiesExtractorInitialization:
    """Tests for BasicPropertiesExtractor initialization."""

    def test_initialization(self, elf_binary_path, mock_logger):
        """Test basic initialization."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(elf_binary_path, mock_logger)

            assert extractor.filepath == elf_binary_path
            assert extractor.basic_properties is None
            assert extractor.is_packed is None
            assert extractor.is_fat is None
            assert extractor.parent_sha256 is None
            assert extractor.child_sha256 is None
            assert extractor.child_architecture is None
            assert extractor.child_filetype is None

    def test_initialization_with_fat_params(self, elf_binary_path, mock_logger):
        """Test initialization with FAT Mach-O parameters."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            child_hashes = ["abc123", "def456"]
            child_archs = ["x86_64", "arm64"]
            child_types = ["macho", "macho"]

            extractor = BasicPropertiesExtractor(
                elf_binary_path,
                mock_logger,
                is_fat=True,
                child_sha256=child_hashes,
                child_architecture=child_archs,
                child_filetype=child_types
            )

            assert extractor.is_fat is True
            assert extractor.child_sha256 == child_hashes
            assert extractor.child_architecture == child_archs
            assert extractor.child_filetype == child_types

    def test_initialization_with_parent_sha256(self, elf_binary_path, mock_logger):
        """Test initialization with parent_sha256 for slice binaries."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            parent_hash = "parent_sha256_hash_here"

            extractor = BasicPropertiesExtractor(
                elf_binary_path,
                mock_logger,
                parent_sha256=parent_hash
            )

            assert extractor.parent_sha256 == parent_hash

    def test_elastic_index_suffix(self, elf_binary_path, mock_logger):
        """Test that elastic_index has correct suffix."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(elf_binary_path, mock_logger)

            assert "-basic_properties" in extractor.elastic_index


class TestBasicPropertiesExtractorTag:
    """Tests for tag method."""

    def test_tag_value(self, elf_binary_path, mock_logger):
        """Test that tag returns correct value."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor
        from redb.extractors.enum import Tag

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(elf_binary_path, mock_logger)

            assert extractor.tag() == Tag.BASIC_PROPERTIES.value
            assert extractor.tag() == "basic_properties"


class TestBasicPropertiesExtract:
    """Tests for extract method."""

    def test_extract_elf_binary(self, elf_binary_path, mock_logger):
        """Test extracting properties from ELF binary."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor
        from redb.models.dataclasses import BasicProperties

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(elf_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            assert isinstance(result, BasicProperties)
            assert result.sample_name == os.path.basename(elf_binary_path)
            assert result.filesize > 0
            assert result.file_entropy >= 0
            assert result.filetype is not None
            assert result.filetype_mime is not None
            assert result.filetype_magika is not None

    def test_extract_pe_binary(self, pe_binary_path, mock_logger):
        """Test extracting properties from PE binary."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor
        from redb.models.dataclasses import BasicProperties

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(pe_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            assert isinstance(result, BasicProperties)
            assert result.filesize > 0
            # PE file should be detected
            assert "PE" in result.filetype or "executable" in result.filetype.lower()

    def test_extract_text_file(self, temp_text_file, mock_logger):
        """Test extracting properties from text file."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(temp_text_file, mock_logger)

            result = extractor.extract()

            assert result is not None
            assert "text" in result.filetype.lower() or "ASCII" in result.filetype
            assert result.file_entropy >= 0

    def test_extract_stores_in_basic_properties(self, elf_binary_path, mock_logger):
        """Test that extract stores result in basic_properties attribute."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(elf_binary_path, mock_logger)

            assert extractor.basic_properties is None
            result = extractor.extract()
            assert extractor.basic_properties is result


class TestBasicPropertiesFiletype:
    """Tests for file type detection."""

    def test_elf_filetype(self, elf_binary_path, mock_logger):
        """Test ELF file type detection."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(elf_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            # Should detect as ELF
            assert "ELF" in result.filetype

    def test_pe_filetype_mime(self, pe_binary_path, mock_logger):
        """Test PE file type MIME detection."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(pe_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            # PE MIME types (varies by libmagic version)
            assert "dosexec" in result.filetype_mime or "x-msdownload" in result.filetype_mime or "portable-executable" in result.filetype_mime

    def test_text_filetype_mime(self, temp_text_file, mock_logger):
        """Test text file type MIME detection."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(temp_text_file, mock_logger)

            result = extractor.extract()

            assert result is not None
            # Text MIME types
            assert "text" in result.filetype_mime


class TestBasicPropertiesEntropy:
    """Tests for entropy calculation in BasicPropertiesExtractor."""

    def test_entropy_reasonable_range(self, elf_binary_path, mock_logger):
        """Test that entropy is within reasonable range (0-8)."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(elf_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            assert 0 <= result.file_entropy <= 8

    def test_entropy_rounded(self, elf_binary_path, mock_logger):
        """Test that entropy is rounded to 3 decimal places."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(elf_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            # Check rounding to 3 decimal places
            entropy_str = str(result.file_entropy)
            if '.' in entropy_str:
                decimal_places = len(entropy_str.split('.')[1])
                assert decimal_places <= 3


class TestBasicPropertiesFilesize:
    """Tests for file size calculation."""

    def test_filesize_matches_actual(self, elf_binary_path, mock_logger):
        """Test that filesize matches actual file size."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(elf_binary_path, mock_logger)

            result = extractor.extract()

            actual_size = os.path.getsize(elf_binary_path)
            assert result.filesize == actual_size

    def test_filesize_matches_binary_length(self, elf_binary_path, mock_logger, elf_binary_content):
        """Test that filesize matches binary content length."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(elf_binary_path, mock_logger)

            result = extractor.extract()

            assert result.filesize == len(elf_binary_content)


class TestBasicPropertiesPrepareExportData:
    """Tests for prepare_export_data method."""

    def test_prepare_export_elasticsearch(self, elf_binary_path, mock_logger):
        """Test prepare_export_data for Elasticsearch."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(elf_binary_path, mock_logger)
            extractor.extract()

            result = extractor.prepare_export_data("ElasticsearchExporter")

            assert result is extractor.basic_properties

    def test_prepare_export_clickhouse(self, elf_binary_path, mock_logger):
        """Test prepare_export_data for ClickHouse."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(elf_binary_path, mock_logger)
            extractor.extract()

            result = extractor.prepare_export_data("ClickHouseExporter")

            # Should return tuple of (data, column_names, column_type_names)
            assert isinstance(result, tuple)
            assert len(result) == 3

            data, column_names, column_type_names = result

            assert isinstance(data, list)
            assert len(data) == 1  # One row
            assert isinstance(column_names, list)
            assert isinstance(column_type_names, list)

            # Check expected columns
            assert 'sha256' in column_names
            assert 'md5' in column_names
            assert 'sha1' in column_names
            assert 'filesize' in column_names
            assert 'file_entropy' in column_names
            assert 'filetype' in column_names
            assert 'filetype_mime' in column_names
            assert 'filetype_magika' in column_names
            # New FAT/child columns
            assert 'parent_sha256' in column_names
            assert 'child_sha256' in column_names
            assert 'child_architecture' in column_names
            assert 'child_filetype' in column_names
            assert 'is_fat' in column_names

    def test_prepare_export_clickhouse_data_types(self, elf_binary_path, mock_logger):
        """Test that ClickHouse export data has correct types."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(elf_binary_path, mock_logger)
            extractor.extract()

            data, column_names, column_type_names = extractor.prepare_export_data("ClickHouseExporter")

            row = data[0]

            # Check that sha256 is a string with correct length
            sha256_idx = column_names.index('sha256')
            assert isinstance(row[sha256_idx], str)
            assert len(row[sha256_idx]) == 64

            # Check that filesize is an integer
            filesize_idx = column_names.index('filesize')
            assert isinstance(row[filesize_idx], int)

            # Check that file_entropy is a float
            entropy_idx = column_names.index('file_entropy')
            assert isinstance(row[entropy_idx], float)


class TestBasicPropertiesClickHouseTable:
    """Tests for get_clickhouse_table method."""

    def test_clickhouse_table_name(self, elf_binary_path, mock_logger):
        """Test correct ClickHouse table name."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(elf_binary_path, mock_logger)

            assert extractor.get_clickhouse_table() == "redb_basic_properties"


class TestBasicPropertiesExportData:
    """Tests for export_data method."""

    def test_export_data_with_print_exporter(self, elf_binary_path, mock_logger, mock_print_exporter, capsys):
        """Test export_data with PrintExporter."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(
                elf_binary_path,
                mock_logger,
                exporters=[mock_print_exporter]
            )

            result = extractor.export_data()

            assert result is True

    def test_export_data_empty_exporters(self, elf_binary_path, mock_logger):
        """Test export_data with no exporters."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(
                elf_binary_path,
                mock_logger,
                exporters=[]
            )

            result = extractor.export_data()

            # Should succeed with no exporters
            assert result is True


class TestBasicPropertiesMagika:
    """Tests for Magika file type detection."""

    def test_magika_elf_detection(self, elf_binary_path, mock_logger):
        """Test Magika detection of ELF files."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(elf_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            # Magika should detect ELF
            assert result.filetype_magika == "elf" or "elf" in result.filetype_magika.lower()

    def test_magika_pe_detection(self, pe_binary_path, mock_logger):
        """Test Magika detection of PE files."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(pe_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            # Magika should detect PE
            assert "pe" in result.filetype_magika.lower() or "exe" in result.filetype_magika.lower()


class TestBasicPropertiesFATSupport:
    """Tests for FAT Mach-O and child file support."""

    def test_extract_with_fat_flag(self, elf_binary_path, mock_logger):
        """Test extraction with is_fat flag set."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(
                elf_binary_path,
                mock_logger,
                is_fat=True
            )

            result = extractor.extract()

            assert result is not None
            assert result.is_fat is True

    def test_extract_with_child_hashes(self, elf_binary_path, mock_logger):
        """Test extraction with child_sha256 provided."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            child_hashes = ["abc123def456", "789ghi012jkl"]

            extractor = BasicPropertiesExtractor(
                elf_binary_path,
                mock_logger,
                child_sha256=child_hashes
            )

            result = extractor.extract()

            assert result is not None
            assert result.child_sha256 == child_hashes

    def test_extract_with_child_architecture(self, elf_binary_path, mock_logger):
        """Test extraction with child_architecture provided."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            child_archs = ["x86_64", "arm64"]

            extractor = BasicPropertiesExtractor(
                elf_binary_path,
                mock_logger,
                child_architecture=child_archs
            )

            result = extractor.extract()

            assert result is not None
            assert result.child_architecture == child_archs

    def test_extract_with_child_filetype(self, elf_binary_path, mock_logger):
        """Test extraction with child_filetype provided."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            child_types = ["macho", "macho"]

            extractor = BasicPropertiesExtractor(
                elf_binary_path,
                mock_logger,
                child_filetype=child_types
            )

            result = extractor.extract()

            assert result is not None
            assert result.child_filetype == child_types

    def test_clickhouse_export_with_fat_data(self, elf_binary_path, mock_logger):
        """Test ClickHouse export includes FAT-related fields correctly."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            child_hashes = ["abc123", "def456"]
            child_archs = ["x86_64", "arm64"]
            child_types = ["macho", "macho"]

            extractor = BasicPropertiesExtractor(
                elf_binary_path,
                mock_logger,
                is_fat=True,
                child_sha256=child_hashes,
                child_architecture=child_archs,
                child_filetype=child_types,
                parent_sha256=None  # FAT container has no parent
            )
            extractor.extract()

            data, column_names, column_type_names = extractor.prepare_export_data("ClickHouseExporter")
            row = data[0]

            # Check FAT fields
            is_fat_idx = column_names.index('is_fat')
            assert row[is_fat_idx] is True

            child_sha256_idx = column_names.index('child_sha256')
            assert row[child_sha256_idx] == child_hashes

            child_arch_idx = column_names.index('child_architecture')
            assert row[child_arch_idx] == child_archs

            child_type_idx = column_names.index('child_filetype')
            assert row[child_type_idx] == child_types

    def test_clickhouse_export_for_slice(self, elf_binary_path, mock_logger):
        """Test ClickHouse export for a slice binary with parent_sha256."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            parent_hash = "parent_container_sha256_hash"

            extractor = BasicPropertiesExtractor(
                elf_binary_path,
                mock_logger,
                parent_sha256=parent_hash
            )
            extractor.extract()

            data, column_names, column_type_names = extractor.prepare_export_data("ClickHouseExporter")
            row = data[0]

            parent_idx = column_names.index('parent_sha256')
            assert row[parent_idx] == parent_hash

    def test_default_fat_fields_are_none_or_empty(self, elf_binary_path, mock_logger):
        """Test that FAT-related fields default to None/empty for non-FAT binaries."""
        from redb.extractors.basicproperties import BasicPropertiesExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = BasicPropertiesExtractor(elf_binary_path, mock_logger)

            result = extractor.extract()

            assert result is not None
            assert result.is_fat is None
            assert result.child_sha256 is None
            assert result.child_architecture is None
            assert result.child_filetype is None


@pytest.mark.unit
@pytest.mark.dataclass
class TestBasicPropertiesDataclass:
    """Tests for BasicProperties dataclass structure."""

    def test_dataclass_has_all_expected_fields(self):
        """Test that BasicProperties dataclass has all expected fields."""
        from redb.models.dataclasses import BasicProperties

        # Create a sample instance
        bp = BasicProperties(
            filename="test.exe",
            sample_name="test.exe",
            filesize=1024,
            filetype="PE32",
            filetype_mime="application/x-dosexec",
            filetype_magika="pebin",
            file_entropy=6.5
        )

        # Check required fields
        assert bp.filename == "test.exe"
        assert bp.sample_name == "test.exe"
        assert bp.filesize == 1024
        assert bp.filetype == "PE32"
        assert bp.filetype_mime == "application/x-dosexec"
        assert bp.filetype_magika == "pebin"
        assert bp.file_entropy == 6.5

        # Check optional fields default to None
        assert bp.is_packed is None
        assert bp.is_fat is None
        assert bp.child_sha256 is None
        assert bp.child_architecture is None
        assert bp.child_filetype is None

    def test_dataclass_with_optional_fat_fields(self):
        """Test BasicProperties dataclass with FAT-related optional fields."""
        from redb.models.dataclasses import BasicProperties

        bp = BasicProperties(
            filename="universal.app",
            sample_name="universal.app",
            filesize=2048,
            filetype="Mach-O universal",
            filetype_mime="application/x-mach-binary",
            filetype_magika="macho",
            file_entropy=7.2,
            is_fat=True,
            child_sha256=["hash1", "hash2"],
            child_architecture=["x86_64", "arm64"],
            child_filetype=["macho", "macho"]
        )

        assert bp.is_fat is True
        assert bp.child_sha256 == ["hash1", "hash2"]
        assert bp.child_architecture == ["x86_64", "arm64"]
        assert bp.child_filetype == ["macho", "macho"]