Nan Feng

95 papers A* 1A 1B 2C 3Misc 1Journal 76Unranked 11
YearRankTypeTitle / Venue / Authors
2026 J jnl
IEEE Trans. Engineering Management
Nan Feng, Jiaqi Li, Hongke Zhao, Longjun Zhao, Minqiang Li
2026 J jnl
Decis. Support Syst.
Wenfan Zhao, Haiyang Feng, Nan Feng, Minqiang Li
2026 J jnl
Inf. Syst. Frontiers
Jingjing Li, Haiyang Feng, Nan Feng, Nan Yuan
2025 J jnl
IEEE Geosci. Remote. Sens. Lett.
Lingxia Mu, Yichi Yang, Youmin Zhang, Xianghong Xue, Nan Feng
2025 J jnl
Inf. Syst. Res.
Haiyang Feng, Nan Feng, Ling Zhang, Zhengrui Jiang, Minqiang Li
2025 J jnl
Comput. Chem. Eng.
Peilin Cao, Ying Geng, Nan Feng, Xiang Zhang, Zhiwen Qi, Zhen Song, Rafiqul Gani
2025 J jnl
IEEE Trans. Instrum. Meas.
Lingxia Mu, Nan Feng, Zhenhua Zhang, Youmin Zhang, Jian Zhang
2025 J jnl
Energy Inform.
Nan Feng, Conglin Ran
2025 J jnl
IEEE J. Sel. Top. Appl. Earth Obs. Remote. Sens.
Lingxia Mu, Yichi Yang, Ban Wang, Youmin Zhang, Nan Feng, Xuesong Xie
2025 J jnl
Ind. Manag. Data Syst.
Nan Feng, Xin Liu, Yi Wu, Chenxing Jia, Changqing Dong
2025 J jnl
CoRR
Nan Feng, Guodong Zhang, Kapil Khandelwal
2025 J jnl
Decis. Support Syst.
Yi Wu, Leping Xiao, Zhongtao Hu, Na Liu, Nan Feng
2025 J jnl
IEEE Trans. Cogn. Dev. Syst.
Nan Feng, Xiong Guo, Xinbo Yu, Shuang Zhang, Wei He
2025 A* conf
AAAI
Zipeng Liu, Likang Wu, Ming He, Zhong Guan, Hongke Zhao, Nan Feng
2025 J jnl
Neurocomputing
Pengxin Yang, Shuang Zhang, Xinbo Yu, Nan Feng, Yi Xing, Wei He
2025 J jnl
Inf. Syst. Res.
Jianqing Chen, Nan Feng, Zhiling Guo, Wenyi Zhang
2025 J jnl
IEEE Trans. Engineering Management
Wenshuo Zhang, Minqiang Li, Haiyang Feng, Nan Feng
2025 J jnl
Decis. Support Syst.
Jiahe Wang, Nan Feng, Haiyang Feng, Minqiang Li
2025 J jnl
Inf. Manag.
Haiyang Feng, Muzi Li, Wenfan Zhao, Nan Feng
2025 J jnl
CoRR
Peilin Cao, Ying Geng, Nan Feng, Xiang Zhang, Zhiwen Qi, Zhen Song, Rafiqul Gani
2025 conf
PACIS
Ruomeng Hu, Dan Ma, Nan Feng
2025 conf
PACIS
Aihui Chen, Yini Zhang, Nan Feng
2025 J jnl
Behav. Inf. Technol.
Aihui Chen, Yini Zhang, Nan Feng
2025 J jnl
J. Assoc. Inf. Syst.
Danyu Liang, Haiyang Feng, Xinxue (Shawn) Qu, Nan Feng, Minqiang Li
2024 J jnl
IEEE Trans. Instrum. Meas.
Lingxia Mu, Jian Zhang, Nan Feng, Yongze Jin, Youmin Zhang, Hongxin Wang, Shihai Wu, Lu Tian
2024 J jnl
IEEE Trans. Smart Grid
Nan Feng, Yaping Du, Yuxuan Ding
2024 B conf
TrustCom
Weidong Zhou, Chunhe Xia, Nan Feng, Xinyi Pan, Tianbo Wang, Xiaojian Li
2024 J jnl
Inf. Syst. Frontiers
Nan Feng, Yanan Shi, Yadi Li, Dahui Li, Jie Zhang, Minqiang Li
2024 J jnl
IEEE Trans. Syst. Man Cybern. Syst.
Chuang Zhao, Hongke Zhao, Hengshu Zhu, Zhenya Huang, Nan Feng, Enhong Chen, Hui Xiong
2024 J jnl
Comput. Ind. Eng.
Nan Feng, Shixin Tu, Feng Guo
2024 J jnl
CoRR
Zipeng Liu, Likang Wu, Ming He, Zhong Guan, Hongke Zhao, Nan Feng
2024 J jnl
IEEE Access
Nan Feng, Yuyao Feng, Yun Su, Yajun Zhang, Tao Niu
2024 J jnl
J. Opt. Commun. Netw.
Qiuyan Yao, Daqing Meng, Hui Yang, Nan Feng, Jie Zhang
2024 J jnl
IEEE Trans. Instrum. Meas.
Yongze Jin, Xin Ye, Nan Feng, Zirong Wang, Xinhong Hei, Junqi Liu, Lingxia Mu, Yankai Li
2024 J jnl
Phys. Commun.
Nan Feng, Kunkun Li, Zishan Huang, Zhongcheng Wei, Wei Wang, Jijun Zhao
2024 J jnl
J. Assoc. Inf. Syst.
Nan Feng, Tianlu Zhou, Haiyang Feng, Minqiang Li
2024 J jnl
Ind. Manag. Data Syst.
Ling Zhang, Nan Feng, Haiyang Feng, Minqiang Li
2024 J jnl
Ind. Manag. Data Syst.
Nan Feng, Lei Zhang, Xin Liu, Jing Xie
2024 J jnl
IEEE Trans. Engineering Management
Chongkai Wang, Minqiang Li, Haiyang Feng, Nan Feng
2023 C conf
ICIS
Tianlu Zhou, Dan Ma, Nan Feng
2023 J jnl
J. Assoc. Inf. Syst.
Nan Feng, Zhongtao Hu, Yi Wu, Ben Choi
2023 J jnl
Future Internet
Siyu Gao, Yuchen Wang, Nan Feng, Zhongcheng Wei, Jijun Zhao
2023 J jnl
Comput. Ind. Eng.
Nan Feng, Yubo Zhang, Binbin Ren, Runliang Dou, Minqiang Li
2023 conf
ICDL
Gaochen Min, Yifan Wu, Nan Feng, Xinbo Yu, Guang Li, Wei He
2023 conf
PACIS
Wanying Chen, Haiyang Feng, Nan Feng, Yi Wu
2023 conf
ICPS
Lingxia Mu, Wenzhe Sun, Youmin Zhang, Nan Feng
2023 J jnl
IEEE Trans. Circuits Syst. II Express Briefs
Yongze Jin, Lingxia Mu, Nan Feng, Xinhong Hei, Yankai Li, Guo Xie, Xin Ye, Jiajie Li
2023 C conf
iSPEC
Nan Feng, Yun Su, Yuyao Feng, Yufan Zhang, Ren Zhang, Haoming Liu
2023 J jnl
Qual. Reliab. Eng. Int.
Anqi Shangguan, Nan Feng, Lingxia Mu, Rong Fei, Xinhong Hei, Guo Xie
2023 J jnl
J. Database Manag.
Nan Feng, Yuguang Wang, Zhiguo Chen, Tingting Song
2023 conf
PACIS
Tianlu Zhou, Dan Ma, Nan Feng
2023 J jnl
Int. J. Electron. Commer.
Chongkai Wang, Minqiang Li, Haiyang Feng, Nan Feng
2022 J jnl
Inf. Manag.
Nan Feng, Jia Su, Haiyang Feng, Minqiang Li
2022 J jnl
J. Assoc. Inf. Syst.
Nan Yuan, Haiyang Feng, Minqiang Li, Nan Feng
2021 J jnl
Electron. Commer. Res. Appl.
Nan Feng, Shiyue Zhang, Minqiang Li, Dahui Li
2021 J jnl
CoRR
Nan Feng, Guodong Zhang, Kapil Khandelwal
2021 J jnl
Inf. Syst. Frontiers
Chenglong Zhang, Nan Feng, JianJian Chen, Dahui Li, Minqiang Li
2021 J jnl
Decis. Support Syst.
Nan Feng, JianJian Chen, Haiyang Feng, Minqiang Li
2021 J jnl
Electron. Commer. Res. Appl.
Charlie Wang, Minqiang Li, Haiyang Feng, Nan Feng
2020 J jnl
CoRR
Guodong Zhang, Nan Feng, Kapil Khandelwal
2020 J jnl
MIS Q.
Haiyang Feng, Zhengrui Jiang, Minqiang Li, Nan Feng
2020 J jnl
Decis. Support Syst.
Nan Feng, Huanhuan Feng, Dahui Li, Minqiang Li
2020 J jnl
Int. J. Electron. Commer.
Yu Wang, Minqiang Li, Haiyang Feng, Nan Feng
2020 J jnl
Electron. Commer. Res. Appl.
Nan Feng, JianJian Chen, Haiyang Feng, Minqiang Li
2020 J jnl
Inf. Manag.
Nan Feng, Yufan Chen, Haiyang Feng, Dahui Li, Minqiang Li
2019 C conf
ICIS
Nan Feng, Zhongtao Hu, Yi Wu
2019 A conf
AISTATS
Pengkai Zhu, Durmus Alp Emre Acar, Nan Feng, Prateek Jain, Venkatesh Saligrama
2019 J jnl
Electron. Commer. Res. Appl.
Nan Feng, Meiyun Wang, Minqiang Li, Dahui Li
2019 conf
PACIS
Nan Feng, Zhongtao Hu, Yi Wu
2019 J jnl
Inf. Technol. Manag.
Yu Wang, Minqiang Li, Haiyang Feng, Nan Feng
2018 J jnl
Inf. Manag.
Nan Feng, Zhenjing Su, Dahui Li, Chundong Zheng, Minqiang Li
2018 conf
ITSC
Nan Feng, Siyu Lin, Gang Zhu, Shichao Li, Huimin Zhang
2018 conf
CONF-IRM
Nan Feng, Haiyang Feng, Jie Zhang, Yufan Chen, Minqiang Li
2017 J jnl
Comput. Ind. Eng.
Xiaoxiao Luo, Minqiang Li, Haiyang Feng, Nan Feng
2017 J jnl
Asia Pac. J. Oper. Res.
Xiaoxiao Luo, Minqiang Li, Nan Feng, Fuzan Chen
2017 conf
ITSC
Nan Feng, Jianwen Ding, Gang Zhu, Siyu Lin, Jiaying Song, Shichao Li, Xiaobing Guo
2016 J jnl
Int. J. Adv. Media Commun.
Nan Feng, Sijing Cai, Li Yang
2016 J jnl
IEEE Trans. Neural Networks Learn. Syst.
Jin Tian, Minqiang Li, Fuzan Chen, Nan Feng
2016 J jnl
Enterp. Inf. Syst.
Nan Feng, Harris Wu, Minqiang Li, Desheng Wu, Fuzan Chen, Jin Tian
2016 J jnl
J. Sensors
Nan Feng, Zhiqi Hao, Sibo Yang, Harris Wu
2015 J jnl
J. Intell. Fuzzy Syst.
Nan Feng, Xue Yu, Runliang Dou, Bingning Pan
2014 J jnl
Inf. Sci.
Nan Feng, Harry Jiannan Wang, Minqiang Li
2014 J jnl
Int. J. Comput. Intell. Syst.
Jin Tian, Nan Feng
2014 conf
DMS
Zan Wang, Xue Yu, Nan Feng, Zhenhua Wang
2014 J jnl
J. Vis. Lang. Comput.
Zan Wang, Xue Yu, Nan Feng, Zhenhua Wang
2014 J jnl
JOCN
Jijun Zhao, Nan Feng, Xin Liu, Wei Bai, Martin Maier
2012 J jnl
J. Comput.
Nan Feng, Xue Yu
2012 J jnl
J. Networks
Nan Feng, Jing Xie
2011 J jnl
Appl. Math. Comput.
Tie Zhang, Nan Feng
2011 J jnl
Appl. Soft Comput.
Nan Feng, Minqiang Li
2010 Misc conf
ITA
Hon Fah Chong, Mehul Motani, Nan Feng
2009 J jnl
Scientometrics
Ling-Li Li, Guohua Ding, Nan Feng, Ming-Huang Wang, Yuh-Shan Ho
2005 J jnl
IEEE Trans. Commun.
Nan Feng, Siun-Chuon Mau, Narayan B. Mandayam
2004 J jnl
IEEE Trans. Commun.
Nan Feng, Siun-Chuon Mau, Narayan B. Mandayam
2004 B conf
GLOBECOM
Tingfang Ji, H. Jonathan Chao, Nan Feng
tests/integration/test_hashes.py
← Index tests/integration/test_hashes.py python
"""
Integration tests for the HashExtractor class.
"""
import pytest
import hashlib
from unittest.mock import Mock, patch, MagicMock

pytestmark = [pytest.mark.integration]


class TestHashExtractorInitialization:
    """Tests for HashExtractor initialization."""

    def test_initialization_elf(self, elf_binary_path, mock_logger):
        """Test initialization with ELF file."""
        from redb.extractors.hashes import HashExtractor

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

            assert extractor.filepath == elf_binary_path
            assert extractor.hashes is None
            assert extractor.filetype == "elf"
            assert extractor.macho is None

    def test_initialization_with_macho_object(self, elf_binary_path, mock_logger):
        """Test initialization with pre-parsed macho object."""
        from redb.extractors.hashes import HashExtractor

        mock_macho = MagicMock()
        mock_macho.get_architectures.return_value = ["x86_64"]

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

            assert extractor.macho is mock_macho

    def test_initialization_pe(self, pe_binary_path, mock_logger):
        """Test initialization with PE file."""
        from redb.extractors.hashes import HashExtractor

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

            assert extractor.filepath == pe_binary_path
            assert extractor.filetype == "pebin"
            # PE object should be created
            assert extractor.pe is not None

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

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

            assert "-hashes" in extractor.elastic_index


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

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

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

            assert extractor.tag() == Tag.HASH.value
            assert extractor.tag() == "hash"


class TestHashExtractorBasicHashes:
    """Tests for basic hash extraction."""

    def test_extract_md5(self, elf_binary_path, mock_logger, known_hashes):
        """Test MD5 hash extraction."""
        from redb.extractors.hashes import HashExtractor

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

            result = extractor.extract()

            assert result is not None
            assert result.md5 == known_hashes['md5']

    def test_extract_sha1(self, elf_binary_path, mock_logger, known_hashes):
        """Test SHA1 hash extraction."""
        from redb.extractors.hashes import HashExtractor

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

            result = extractor.extract()

            assert result is not None
            assert result.sha1 == known_hashes['sha1']

    def test_extract_sha256(self, elf_binary_path, mock_logger, known_hashes):
        """Test SHA256 hash extraction."""
        from redb.extractors.hashes import HashExtractor

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

            result = extractor.extract()

            assert result is not None
            assert result.sha256 == known_hashes['sha256']

    def test_extract_ssdeep(self, elf_binary_path, mock_logger):
        """Test ssdeep hash extraction."""
        from redb.extractors.hashes import HashExtractor

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

            result = extractor.extract()

            assert result is not None
            # ssdeep should be a string
            assert isinstance(result.ssdeep_hash, str)

    def test_extract_tlsh(self, elf_binary_path, mock_logger):
        """Test TLSH hash extraction."""
        from redb.extractors.hashes import HashExtractor

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

            result = extractor.extract()

            assert result is not None
            # TLSH should be a string
            assert isinstance(result.tlsh_hash, str)


class TestHashExtractorPEHashes:
    """Tests for PE-specific hash extraction."""

    def test_extract_imphash(self, pe_binary_path, mock_logger):
        """Test imphash extraction for PE file."""
        from redb.extractors.hashes import HashExtractor

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

            result = extractor.extract()

            assert result is not None
            # Imphash should be set for PE files
            if extractor.pe is not None:
                assert result.imphash is not None or result.imphash is None  # May or may not have imports

    def test_extract_authentihash(self, pe_binary_path, mock_logger):
        """Test authentihash extraction for PE file."""
        from redb.extractors.hashes import HashExtractor

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

            result = extractor.extract()

            assert result is not None
            # Authentihash should be set for PE files
            if extractor.pe is not None:
                assert result.authentihash is not None

    def test_pe_hashes_not_set_for_elf(self, elf_binary_path, mock_logger):
        """Test that PE-specific hashes are not set for ELF files."""
        from redb.extractors.hashes import HashExtractor

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

            result = extractor.extract()

            assert result is not None
            # PE-specific hashes should be None for ELF
            assert result.imphash is None
            assert result.authentihash is None
            assert result.richhash is None


class TestHashExtractorRichHeaderHashes:
    """Tests for Rich header hash extraction."""

    def test_compute_richhash(self, pe_binary_path, mock_logger):
        """Test Rich header hash computation."""
        from redb.extractors.hashes import HashExtractor

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

            result = extractor.extract()

            assert result is not None
            # Rich hash may or may not be present depending on the PE
            if result.richhash is not None:
                assert isinstance(result.richhash, str)
                assert len(result.richhash) == 32  # MD5 hex length

    def test_compute_richpe_hash(self, pe_binary_path, mock_logger):
        """Test RichPE hash computation."""
        from redb.extractors.hashes import HashExtractor

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

            result = extractor.extract()

            assert result is not None
            # RichPE hash may or may not be present
            if result.richpe_hash is not None:
                assert isinstance(result.richpe_hash, str)
                assert len(result.richpe_hash) == 32  # MD5 hex length

    def test_compute_richpv_hash(self, pe_binary_path, mock_logger):
        """Test RichPV hash computation."""
        from redb.extractors.hashes import HashExtractor

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

            result = extractor.extract()

            assert result is not None
            # RichPV hashes may or may not be present
            if result.richpv_hash is not None:
                assert isinstance(result.richpv_hash, str)
            if result.richpv_hash_sorted is not None:
                assert isinstance(result.richpv_hash_sorted, str)


class TestHashExtractorELFHashes:
    """Tests for ELF-specific hash extraction."""

    def test_extract_elf_import_hash(self, elf_binary_path, mock_logger):
        """Test ELF import hash extraction."""
        from redb.extractors.hashes import HashExtractor

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

            result = extractor.extract()

            assert result is not None
            # Import hash may or may not be present
            if result.import_hash is not None:
                assert isinstance(result.import_hash, str)
                assert len(result.import_hash) == 32

    def test_extract_elf_export_hash(self, elf_binary_path, mock_logger):
        """Test ELF export hash extraction."""
        from redb.extractors.hashes import HashExtractor

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

            result = extractor.extract()

            assert result is not None
            # Export hash may or may not be present
            if result.export_hash is not None:
                assert isinstance(result.export_hash, str)

    def test_extract_elf_section_hash(self, elf_binary_path, mock_logger):
        """Test ELF section hash extraction."""
        from redb.extractors.hashes import HashExtractor

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

            result = extractor.extract()

            assert result is not None
            # Section hash should be present for valid ELF
            if result.section_hash is not None:
                assert isinstance(result.section_hash, str)

    def test_extract_elf_symbol_hash(self, elf_binary_path, mock_logger):
        """Test ELF symbol hash extraction."""
        from redb.extractors.hashes import HashExtractor

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

            result = extractor.extract()

            assert result is not None
            # Symbol hash (symhash) may or may not be present
            if result.symbol_hash is not None:
                assert isinstance(result.symbol_hash, str)

    def test_extract_elf_dynamic_hash(self, elf_binary_path, mock_logger):
        """Test ELF dynamic hash extraction."""
        from redb.extractors.hashes import HashExtractor

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

            result = extractor.extract()

            assert result is not None
            # Dynamic hash may or may not be present
            if result.dynamic_hash is not None:
                assert isinstance(result.dynamic_hash, str)


class TestHashExtractorPrepareExportData:
    """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.hashes import HashExtractor

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

            result = extractor.prepare_export_data("ElasticsearchExporter")

            assert result is extractor.hashes

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

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(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 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 'ssdeep_hash' in column_names
            assert 'tlsh_hash' in column_names

    def test_prepare_export_clickhouse_pe(self, pe_binary_path, mock_logger):
        """Test prepare_export_data for ClickHouse with PE file."""
        from redb.extractors.hashes import HashExtractor

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

            result = extractor.prepare_export_data("ClickHouseExporter")

            data, column_names, column_type_names = result

            # PE-specific columns should be present
            assert 'authentihash' in column_names
            assert 'imphash' in column_names
            assert 'richhash' in column_names

    def test_prepare_export_clickhouse_has_macho_columns(self, elf_binary_path, mock_logger):
        """Test prepare_export_data for ClickHouse includes Mach-O hash columns."""
        from redb.extractors.hashes import HashExtractor

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

            result = extractor.prepare_export_data("ClickHouseExporter")

            data, column_names, column_type_names = result

            # Mach-O hash columns should be present
            assert 'macho_dylib_hash' in column_names
            assert 'macho_import_hash' in column_names
            assert 'macho_export_hash' in column_names
            assert 'macho_entitlement_hash' in column_names
            assert 'macho_symhash' in column_names


class TestHashExtractorClickHouseTable:
    """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.hashes import HashExtractor

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

            assert extractor.get_clickhouse_table() == "redb_hashes"


@pytest.mark.unit
@pytest.mark.dataclass
class TestHashExtractorHashesDataclass:
    """Tests for Hashes dataclass structure."""

    def test_hashes_dataclass_structure(self, elf_binary_path, mock_logger):
        """Test that Hashes dataclass has expected structure."""
        from redb.extractors.hashes import HashExtractor
        from redb.models.dataclasses import Hashes

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

            result = extractor.extract()

            assert isinstance(result, Hashes)
            # Required fields
            assert hasattr(result, 'md5')
            assert hasattr(result, 'sha1')
            assert hasattr(result, 'sha256')
            assert hasattr(result, 'ssdeep_hash')
            assert hasattr(result, 'tlsh_hash')
            # Optional fields
            assert hasattr(result, 'authentihash')
            assert hasattr(result, 'imphash')
            assert hasattr(result, 'richhash')

    def test_hashes_dataclass_has_macho_fields(self):
        """Test that Hashes dataclass has Mach-O hash fields."""
        from redb.models.dataclasses import Hashes

        # Create instance with default values
        hashes = Hashes(
            md5="d41d8cd98f00b204e9800998ecf8427e",
            sha1="da39a3ee5e6b4b0d3255bfef95601890afd80709",
            sha256="e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
            ssdeep_hash="",
            tlsh_hash=""
        )

        # Verify Mach-O hash fields exist and default to None
        assert hasattr(hashes, 'macho_dylib_hash')
        assert hasattr(hashes, 'macho_import_hash')
        assert hasattr(hashes, 'macho_export_hash')
        assert hasattr(hashes, 'macho_entitlement_hash')
        assert hasattr(hashes, 'macho_symhash')

        assert hashes.macho_dylib_hash is None
        assert hashes.macho_import_hash is None
        assert hashes.macho_export_hash is None
        assert hashes.macho_entitlement_hash is None
        assert hashes.macho_symhash is None

    def test_hashes_dataclass_with_macho_values(self):
        """Test that Hashes dataclass can be created with Mach-O hash values."""
        from redb.models.dataclasses import Hashes

        hashes = Hashes(
            md5="d41d8cd98f00b204e9800998ecf8427e",
            sha1="da39a3ee5e6b4b0d3255bfef95601890afd80709",
            sha256="e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
            ssdeep_hash="",
            tlsh_hash="",
            macho_dylib_hash="abc123def456789012345678901234567",
            macho_import_hash="def456abc123789012345678901234567",
            macho_export_hash="789012abc123def456345678901234567",
            macho_entitlement_hash="345678abc123def456789012901234567",
            macho_symhash="901234abc123def456789012345678567"
        )

        assert hashes.macho_dylib_hash == "abc123def456789012345678901234567"
        assert hashes.macho_import_hash == "def456abc123789012345678901234567"
        assert hashes.macho_export_hash == "789012abc123def456345678901234567"
        assert hashes.macho_entitlement_hash == "345678abc123def456789012901234567"
        assert hashes.macho_symhash == "901234abc123def456789012345678567"


class TestHashExtractorErrorHandling:
    """Tests for error handling in HashExtractor."""

    def test_extract_handles_hash_errors(self, elf_binary_path, mock_logger):
        """Test that extract handles hash computation errors gracefully."""
        from redb.extractors.hashes import HashExtractor

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

            # Even if some hashes fail, we should get a result
            result = extractor.extract()

            assert result is not None

    def test_extract_with_invalid_pe(self, elf_binary_path, mock_logger):
        """Test extraction when PE parsing fails."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            # Force filetype to be 'pebin' but use ELF file
            with patch.object(HashExtractor, '__init__', lambda self, *args, **kwargs: None):
                extractor = HashExtractor.__new__(HashExtractor)
                extractor.filepath = elf_binary_path
                extractor.log = mock_logger
                extractor.hashes = None
                extractor.pe = None
                extractor.filetype = 'pebin'

                with open(elf_binary_path, 'rb') as f:
                    extractor.binary = f.read()

                # Should not crash
                result = extractor._extract_hashes()
                assert result is not None


class TestHashExtractorMachoHashes:
    """Tests for Mach-O specific hash extraction."""

    def test_macho_hashes_not_set_for_elf(self, elf_binary_path, mock_logger):
        """Test that Mach-O hashes are not set for ELF files."""
        from redb.extractors.hashes import HashExtractor

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

            result = extractor.extract()

            assert result is not None
            assert result.macho_dylib_hash is None
            assert result.macho_import_hash is None
            assert result.macho_export_hash is None
            assert result.macho_entitlement_hash is None
            assert result.macho_symhash is None

    def test_macho_hashes_not_set_for_pe(self, pe_binary_path, mock_logger):
        """Test that Mach-O hashes are not set for PE files."""
        from redb.extractors.hashes import HashExtractor

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

            result = extractor.extract()

            assert result is not None
            assert result.macho_dylib_hash is None
            assert result.macho_import_hash is None
            assert result.macho_export_hash is None
            assert result.macho_entitlement_hash is None
            assert result.macho_symhash is None

    def test_extract_macho_hashes_with_mock(self, elf_binary_path, mock_logger):
        """Test Mach-O hash extraction with mocked macho object."""
        from redb.extractors.hashes import HashExtractor

        # Create mock macho object
        mock_macho = MagicMock()
        mock_macho.get_architectures.return_value = ["x86_64"]
        mock_macho.get_similarity_hashes.return_value = {
            'dylib_hash': 'abc123def456789012345678901234ab',
            'import_hash': 'def456abc789012345678901234567cd',
            'export_hash': '789012abc456def345678901234567ef',
            'entitlement_hash': '345678abc123def789012901234567gh',
            'symhash': '901234abc123def456789012345678ij'
        }

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger, macho=mock_macho)
            # Override filetype to trigger macho hash extraction
            extractor.filetype = 'macho'

            result = extractor.extract()

            assert result is not None
            assert result.macho_dylib_hash == 'abc123def456789012345678901234ab'
            assert result.macho_import_hash == 'def456abc789012345678901234567cd'
            assert result.macho_export_hash == '789012abc456def345678901234567ef'
            assert result.macho_entitlement_hash == '345678abc123def789012901234567gh'
            assert result.macho_symhash == '901234abc123def456789012345678ij'

    def test_extract_macho_hashes_fat_binary_mock(self, elf_binary_path, mock_logger):
        """Test Mach-O hash extraction for FAT binary with mocked macho object."""
        from redb.extractors.hashes import HashExtractor

        # Create mock macho object for FAT binary
        mock_macho = MagicMock()
        mock_macho.get_architectures.return_value = ["x86_64", "arm64"]  # Multiple archs = FAT
        mock_macho.get_similarity_hashes.return_value = {
            'fat': {
                'dylib_hash': 'fat_dylib_hash_12345678901234567',
                'import_hash': 'fat_import_hash_12345678901234567',
            },
            'combined': {
                'dylib_hash': 'combined_dylib_hash_1234567890123',
            }
        }

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger, macho=mock_macho)
            extractor.filetype = 'macho'

            result = extractor.extract()

            assert result is not None
            # Should use 'fat' key for FAT binaries
            assert result.macho_dylib_hash == 'fat_dylib_hash_12345678901234567'
            assert result.macho_import_hash == 'fat_import_hash_12345678901234567'

    def test_extract_macho_hashes_handles_empty(self, elf_binary_path, mock_logger):
        """Test Mach-O hash extraction handles empty hash dict."""
        from redb.extractors.hashes import HashExtractor

        mock_macho = MagicMock()
        mock_macho.get_architectures.return_value = ["x86_64"]
        mock_macho.get_similarity_hashes.return_value = {}

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger, macho=mock_macho)
            extractor.filetype = 'macho'

            result = extractor.extract()

            # Should not crash, hashes should be None
            assert result is not None
            assert result.macho_dylib_hash is None

    def test_extract_macho_hashes_handles_none(self, elf_binary_path, mock_logger):
        """Test Mach-O hash extraction handles None return."""
        from redb.extractors.hashes import HashExtractor

        mock_macho = MagicMock()
        mock_macho.get_architectures.return_value = ["x86_64"]
        mock_macho.get_similarity_hashes.return_value = None

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor = HashExtractor(elf_binary_path, mock_logger, macho=mock_macho)
            extractor.filetype = 'macho'

            result = extractor.extract()

            # Should not crash
            assert result is not None


class TestHashExtractorConsistency:
    """Tests for hash consistency."""

    def test_hash_consistency_across_extractions(self, elf_binary_path, mock_logger):
        """Test that hashes are consistent across multiple extractions."""
        from redb.extractors.hashes import HashExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            extractor1 = HashExtractor(elf_binary_path, mock_logger)
            result1 = extractor1.extract()

            extractor2 = HashExtractor(elf_binary_path, mock_logger)
            result2 = extractor2.extract()

            assert result1.md5 == result2.md5
            assert result1.sha1 == result2.sha1
            assert result1.sha256 == result2.sha256

    def test_hash_values_are_lowercase(self, elf_binary_path, mock_logger):
        """Test that hash values are lowercase hex strings."""
        from redb.extractors.hashes import HashExtractor

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

            result = extractor.extract()

            assert result.md5 == result.md5.lower()
            assert result.sha1 == result.sha1.lower()
            assert result.sha256 == result.sha256.lower()

    def test_hash_lengths_correct(self, elf_binary_path, mock_logger):
        """Test that hash lengths are correct."""
        from redb.extractors.hashes import HashExtractor

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

            result = extractor.extract()

            assert len(result.md5) == 32  # MD5 = 128 bits = 32 hex chars
            assert len(result.sha1) == 40  # SHA1 = 160 bits = 40 hex chars
            assert len(result.sha256) == 64  # SHA256 = 256 bits = 64 hex chars