Han Liu

95 papers A* 2B 2C 2Misc 26Journal 42Unranked 16
YearRankTypeTitle / Venue / Authors
2026 J jnl
Inf. Fusion
Junyang Chen, Liang-Jie Zhang, Zhelin Huang, Han Liu, Yirui Wu, Huan Wang, Wei Liu, Victor C. M. Leung
2025 J jnl
CoRR
Zhenyu Pan, Yiting Zhang, Zhuo Liu, Yolo Yunlong Tang, Zeliang Zhang, Haozheng Luo, Yuwei Han, Jianshu Zhang, Dennis Wu, Hong-Yu Chen, Haoran Lu, Haoyang Fang, Manling Li, Chenliang Xu, Philip S. Yu, Han Liu
2025 J jnl
CoRR
Zhenyu Pan, Yiting Zhang, Yutong Zhang, Jianshu Zhang, Haozheng Luo, Yuwei Han, Dennis Wu, Hong-Yu Chen, Philip S. Yu, Manling Li, Han Liu
2025 J jnl
CoRR
Zhenyu Pan, Yutong Zhang, Jianshu Zhang, Haoran Lu, Haozheng Luo, Yuwei Han, Philip S. Yu, Manling Li, Han Liu
2025 conf
ICIC (18)
Zujie Lin, Han Liu, Yinghui Pan
2025 J jnl
Knowl. Based Syst.
Qin Zhang, Zhuoluo Liang, Alladoumbaye Ngueilbaye, Han Liu, Hong Zhou, Joshua Zhexue Huang
2025 conf
ICIC (18)
Qin Zhang, Song Zhang, Junjie Li, Hong Zhou, Xiaojun Chen, Han Liu
2025 J jnl
ACM Trans. Inf. Syst.
Qin Zhang, Mengqi Zheng, Shangsi Chen, Han Liu, Meng Fang
2025 J jnl
Inf. Sci.
Limin Hua, Han Liu, Yinghui Pan
2025 A* conf
AAAI
Han Liu, Jiaqing Zhan, Qin Zhang
2025 conf
ICIC (18)
Han Liu, Peiwei Li, Qin Zhang, Yinghui Pan
2024 J jnl
Expert Syst. Appl.
Hufsa Khan, Muhammad Tahir Rasheed, Shengli Zhang, Xizhao Wang, Han Liu
2024 J jnl
Inf. Process. Manag.
Han Liu, Qianxi Qiu, Qin Zhang
2024 J jnl
Comput. Electr. Eng.
Hufsa Khan, Muhammad Tahir Rasheed, Han Liu, Shengli Zhang
2024 conf
ICIC (2)
Hongwei Su, Han Liu, Weipeng Cao, Zhong Ming
2023 J jnl
Int. J. Syst. Sci.
Hufsa Khan, Xizhao Wang, Han Liu
2023 Misc conf
ICMLC
Zhichao Chen, Han Liu, Qin Zhang
2023 Misc conf
ICMLC
Si Cen, Han Liu, Chao Liu, Xiaoying Zou, Guoquan Dai, Xizhao Wang
2023 Misc conf
ICMLC
Peiwei Li, Han Liu
2023 Misc conf
ICMLC
Yixin Wang, Han Liu
2023 Misc conf
ICMLC
Wenliang Feng, Han Liu, Xiaogang Peng
2023 J jnl
Int. J. Mach. Learn. Cybern.
Yinfeng Fang, Huiqiao Lu, Han Liu
2023 Misc conf
ICMLC
Qianxi Qiu, Han Liu
2023 ed.
MICAD
Ruidan Su, Yudong Zhang, Han Liu, Alejandro F. Frangi
2023 Misc conf
ICMLC
Zhen-Xun Dong, Han Liu
2022 J jnl
Neurocomputing
Xinlei Zhou, Han Liu, Farhad Pourpanah, Tieyong Zeng, Xizhao Wang
2022 J jnl
Soc. Netw. Anal. Min.
Wafa Alorainy, Pete Burnap, Han Liu, Matthew L. Williams, Luca Giommoni
2022 J jnl
Int. J. Mach. Learn. Cybern.
Chengwei Li, Han Liu, Zhong Ming
2022 J jnl
Inf. Sci.
Hufsa Khan, Xizhao Wang, Han Liu
2022 J jnl
Neurocomputing
Chao Liu, Xizhao Wang, Han Liu, Xiaoying Zou, Si Cen, Guoquan Dai
2021 J jnl
CoRR
Xinlei Zhou, Han Liu, Farhad Pourpanah, Tieyong Zeng, Xizhao Wang
2021 J jnl
Inf. Sci.
Keke Huang, Haofei Wen, Han Liu, Chunhua Yang, Weihua Gui
2021 J jnl
Int. J. Mach. Learn. Cybern.
Hong Zhu, Han Liu, Ai-Min Fu
2021 J jnl
Sensors
Hailun Xie, Li Zhang, Chee Peng Lim, Yonghong Yu, Han Liu
2021 J jnl
Comput. Electr. Eng.
Hufsa Khan, Xizhao Wang, Han Liu
2021 J jnl
IEEE Access
Qiang Li, Yingjian Yang, Yingwei Guo, Wei Li, Yang Liu, Han Liu, Yan Kang
2021 ed.
MICAD
Ruidan Su, Yu-Dong Zhang, Han Liu
2021 J jnl
Appl. Soft Comput.
Patrick P. K. Chan, Juan Zheng, Han Liu, Eric C. C. Tsang, Daniel S. Yeung
2020 Misc conf
ICMLC
Fraser Young, Li Zhang, Richard Jiang, Han Liu, Conor Wall
2020 J jnl
CoRR
Fraser Young, Li Zhang, Richard Jiang, Han Liu, Conor Wall
2020 J jnl
IEEE Access
Halefom Tekle Weldegebriel, Han Liu, Anwar Ul Haq, Emmanuel Bugingo, Defu Zhang
2020 Misc conf
ICMLC
Ziwen Wang, Haiming Wu, Han Liu, Qian-Hua Cai
2020 J jnl
IEEE Access
Yanling Zhou, Yanyan Yang, Han Liu, Xiufeng Liu, Nick Savage
2020 J jnl
Inf. Sci.
Han Liu, Shyi-Ming Chen
2020 J jnl
Int. J. Mach. Learn. Cybern.
Weili Ding, Bo Hu, Han Liu, Xinming Wang, Xiangsheng Huang
2020 J jnl
Frontiers Neurorobotics
Yinfeng Fang, Haiyang Yang, Xuguang Zhang, Han Liu, Bo Tao
2020 Misc conf
ICMLC
Michael Willis, Li Zhang, Han Liu, Hailun Xie, Kamlesh Mistry
2020 ed.
MICAD
Ruidan Su, Han Liu
2020 conf
TRAC@LREC
Han Liu, Pete Burnap, Wafa Alorainy, Matthew L. Williams
2019 J jnl
ACM Trans. Web
Wafa Alorainy, Pete Burnap, Han Liu, Matthew L. Williams
2019 J jnl
IEEE Trans. Comput. Soc. Syst.
Han Liu, Pete Burnap, Wafa Alorainy, Matthew L. Williams
2019 J jnl
Expert Syst. Appl.
Han Liu, Li Zhang
2019 Misc conf
ICMLC
Liang Fan, Han Liu, Yuxuan Hou
2019 conf
UKCI
Fatima Chiroma, Mihaela Cocea, Han Liu
2019 Misc conf
ICMLC
Yun Zhang, Wenxiang Chen, Han Liu, Jinhua Liu, Hui Du
2019 A* conf
WWW
Han Liu, Pete Burnap, Wafa Alorainy, Matthew L. Williams
2019 J jnl
Inf. Sci.
Han Liu, Shyi-Ming Chen, Mihaela Cocea
2019 J jnl
Appl. Soft Comput.
Hailun Xie, Li Zhang, Chee Peng Lim, Yonghong Yu, Chengyu Liu, Han Liu, Julie Walters
2019 Misc conf
ICMLC
Ting Yuan, Hai-Hui Li, Hong-Ya Zhao, Qian-Hua Cai, Han Liu, Xiao-Hui Hu
2019 conf
ISCID (1)
Han Liu, Shyi-Ming Chen
2019 Misc conf
ICMLC
Han Liu, Shyi-Ming Chen
2019 Misc conf
ICMLC
Han Liu, Shyi-Ming Chen
2019 J jnl
Inf. Sci.
Han Liu, Shyi-Ming Chen
2019 Misc conf
ICMLC
Pengfei Guo, Han Liu, Shuangyin Liu, Longqin Xu
2019 J jnl
Inf. Sci.
Han Liu, Shyi-Ming Chen, Mihaela Cocea
2018 conf
ICCSW
Fatima Chiroma, Mihaela Cocea, Han Liu
2018 conf
ICACI
Han Liu, Mihaela Cocea
2018 conf
IberEval@SEPLN
Han Liu, Fatima Chiroma, Mihaela Cocea
2018 Misc conf
ICMLC
Alaa Mohasseb, Mohamed Bahy Bader-El-Den, Mihaela Cocea, Han Liu
2018 J jnl
Inf. Sci.
Han Liu, Mihaela Cocea
2018 Misc conf
ICMLC
Han Liu, Mihaela Cocea, Weili Ding
2018 J jnl
IEEE Access
Zhenfeng Lei, Shuangyuan Yang, Han Liu, Saba Aslam, Jinyu Liu, Halefom Tekle Weldegebriel, Emmanuel Bugingo, Defu Zhang
2018 conf
ISCID (2)
Han Liu, Shyi-Ming Chen
2018 conf
CISP-BMEI
Hui-Huang Zhao, Han Liu, Jin-Hua Zheng, Bin Fu
2018 Misc conf
ICMLC
Fatima Chiroma, Han Liu, Mihaela Cocea
2018 Misc conf
ICMLC
Wafa Alorainy, Pete Burnap, Han Liu, Amir Javed, Matthew L. Williams
2018 Misc conf
ICMLC
Fatima Chiroma, Han Liu, Mihaela Cocea
2017 Misc conf
ICMLC
Han Liu, Mihaela Cocea, Weili Ding
2017 Misc conf
ICMLC
Alaa Mohasseb, Mohamed Bader-El-Den, Han Liu, Mihaela Cocea
2017 B conf
FUZZ-IEEE
Chris Jefferson, Han Liu, Mihaela Cocea
2017 conf
ICACI
Han Liu, Mihaela Cocea
2017 J jnl
J. Artif. Intell. Soft Comput. Res.
Han Liu, Alexander E. Gegov, Mihaela Cocea
2017 conf
ICACI
Han Liu, Mihaela Cocea, Alaa Mohasseb, Mohamed Bader
2017 Misc conf
ICMLC
Ali Malik, Benjamin Aziz, Chih-Heng Ke, Han Liu, Mo Adda
2016 J jnl
J. Intell. Fuzzy Syst.
Han Liu, Alexander E. Gegov, Mihaela Cocea
2016 conf
UKCI
Han Liu, Alexander E. Gegov, Mihaela Cocea
2016 ch.
Sentiment Analysis and Ontology Engineering
Han Liu, Mihaela Cocea, Alexander E. Gegov
2016 Misc conf
ICMLC
Han Liu, Alexander E. Gegov, Mihaela Cocea
2016 conf
IEEE Conf. on Intelligent Systems
Han Liu, Alexander E. Gegov
2015 Misc conf
ICMLC
Han Liu, Alexander E. Gegov, Mihaela Cocea
2015 B conf
FUZZ-IEEE
Han Liu, Alexander E. Gegov, Mihaela Cocea
2015
Han Liu
2014 C conf
EANN
Han Liu, Alexander E. Gegov, Frederic T. Stahl
2012 J jnl
Trans. Large Scale Data Knowl. Centered Syst.
Frederic T. Stahl, Mohamed Medhat Gaber, Paul Aldridge, David May, Han Liu, Max Bramer, Philip S. Yu
2011 C conf
ISMIS
Frederic T. Stahl, Mohamed Medhat Gaber, Han Liu, Max Bramer, Philip S. Yu
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"]