James Aspnes

176 papers A* 48A 13B 23C 5Journal 83Unranked 1
YearRankTypeTitle / Venue / Authors
2025 J jnl
CoRR
James Aspnes, Shlomi Dolev, Amit Hendin
2025 J jnl
Theor. Comput. Sci.
Talley Amir, James Aspnes
2025 J jnl
CoRR
James Aspnes
2025 J jnl
CoRR
James Aspnes
2024 J jnl
J. Comput. Syst. Sci.
James Aspnes, Othon Michail
2024 J jnl
CoRR
James Aspnes
2023 A* conf
PODC
Talley Amir, James Aspnes, Petra Berenbrink, Felix Biermeier, Christopher Hahn, Dominik Kaaser, John Lazarsfeld
2023 J jnl
CoRR
Talley Amir, James Aspnes, Petra Berenbrink, Felix Biermeier, Christopher Hahn, Dominik Kaaser, John Lazarsfeld
2023 C conf
SSS
Talley Amir, James Aspnes
2023 J jnl
CoRR
Talley Amir, James Aspnes
2023 J jnl
SIAM J. Comput.
Dan Alistarh, James Aspnes, Faith Ellen, Rati Gelashvili, Leqi Zhu
2022 ed.
SAND
James Aspnes, Othon Michail
2021 J jnl
J. Comput. Syst. Sci.
James Aspnes
2021 J jnl
IEEE/ACM Trans. Netw.
Qiao Xiang, Haitao Yu, James Aspnes, Franck Le, Chin Guok, Linghe Kong, Yang Richard Yang
2020 J jnl
CoRR
Talley Amir, James Aspnes, John Lazarsfeld
2020 B conf
OPODIS
Talley Amir, James Aspnes, John Lazarsfeld
2020 A* conf
PODC
Dan Alistarh, James Aspnes, Faith Ellen, Rati Gelashvili, Leqi Zhu
2020 A conf
DISC
Talley Amir, James Aspnes, David Doty, Mahsa Eftekhari, Eric E. Severson
2020 J jnl
CoRR
Talley Amir, James Aspnes, David Doty, Mahsa Eftekhari H., Eric E. Severson
2020 J jnl
CoRR
James Aspnes
2020 J jnl
CoRR
James Aspnes
2019 A conf
DISC
James Aspnes, Heyang Er
2019 A* conf
AAAI
Qiao Xiang, Haitao Yu, James Aspnes, Franck Le, Linghe Kong, Yang Richard Yang
2019 A* conf
STOC
Dan Alistarh, James Aspnes, Faith Ellen, Rati Gelashvili, Leqi Zhu
2018 B ed.
OPODIS
James Aspnes, Alysson Bessani, Pascal Felber, João Leitão
2018 A conf
DISC
James Aspnes, Bernhard Haeupler, Alexander Tong, Philipp Woelfel
2018 J jnl
Distributed Comput.
Dan Alistarh, James Aspnes, Valerie King, Jared Saia
2018 J jnl
J. Parallel Distributed Comput.
James Aspnes, Keren Censor-Hillel, Eitan Yaakobi
2018 J jnl
J. ACM
James Aspnes, Hagit Attiya, Keren Censor-Hillel, Faith Ellen
2018 A* conf
SODA
Dan Alistarh, James Aspnes, Rati Gelashvili
2018 A* conf
OSDI
Joshua Lockerman, Jose M. Faleiro, Juno Kim, Soham Sankaran, Daniel J. Abadi, James Aspnes, Siddhartha Sen, Mahesh Balakrishnan
2018 A* conf
INFOCOM
Christopher Leet, Xin Wang, Yang Richard Yang, James Aspnes
2018 J jnl
CoRR
Dan Alistarh, James Aspnes, Faith Ellen, Rati Gelashvili, Leqi Zhu
2017 A* conf
PODC
Yehuda Afek, James Aspnes, Edo Cohen, Danny Vainstein
2017 A* conf
PODC
James Aspnes
2017 J jnl
CoRR
Dan Alistarh, James Aspnes, Rati Gelashvili
2017 A* conf
SODA
Dan Alistarh, James Aspnes, David Eisenstat, Rati Gelashvili, Ronald L. Rivest
2016 B conf
SIROCCO
James Aspnes, Keren Censor-Hillel, Eitan Yaakobi
2016 A conf
DISC
James Aspnes, Eric Ruppert
2016 J jnl
SIAM J. Comput.
James Aspnes, Keren Censor-Hillel, Hagit Attiya, Danny Hendler
2016 J jnl
SIAM J. Comput.
James Aspnes, Yuval Ishai, Peter Bro Miltersen
2016 B conf
OPODIS
James Aspnes, Joffroy Beauquier, Janna Burman, Devan Sohier
2016 J jnl
CoRR
James Aspnes, Joffroy Beauquier, Janna Burman, Devan Sohier
2016 J jnl
CoRR
Dan Alistarh, James Aspnes, David Eisenstat, Rati Gelashvili, Ronald L. Rivest
2015 B conf
NCA
Yves Mocquard, Emmanuelle Anceaume, James Aspnes, Yann Busnel, Bruno Sericola
2015 J jnl
Distributed Comput.
James Aspnes
2015 J jnl
J. ACM
James Aspnes, Hagit Attiya, Keren Censor-Hillel, Faith Ellen
2015 J jnl
J. Comb. Optim.
Dana Angluin, James Aspnes, Lev Reyzin
2015 J jnl
J. Cryptol.
James Aspnes, Zoë Diamadi, Aleksandr Yampolskiy, Kristian Gjøsteen, René Peralta
2014 A conf
DISC
Dan Alistarh, James Aspnes, Valerie King, Jared Saia
2014 A* conf
SODA
Dan Alistarh, James Aspnes, Michael A. Bender, Rati Gelashvili, Seth Gilbert
2014 J jnl
Inf. Comput.
Dana Angluin, James Aspnes, Rida A. Bazzi, Jiang Chen, David Eisenstat, Goran Konjevod
2014 J jnl
Theory Comput. Syst.
James Aspnes, Faith Ellen
2014 J jnl
J. ACM
Dan Alistarh, James Aspnes, Keren Censor-Hillel, Seth Gilbert, Rachid Guerraoui
2013 A conf
DISC
James Aspnes, Keren Censor-Hillel
2013 J jnl
Int. J. Comput. Math.
Dana Angluin, James Aspnes, Raonne Barbosa Vargas
2013 J jnl
J. Mach. Learn. Res.
Dana Angluin, James Aspnes, Sarah Eisenstat, Aryeh Kontorovich
2013 A* conf
PODC
Dan Alistarh, James Aspnes, George Giakkoupis, Philipp Woelfel
2012 J jnl
Distributed Comput.
James Aspnes
2012 J jnl
CoRR
James Aspnes
2012 A* conf
PODC
James Aspnes
2012 A* conf
PODC
James Aspnes, Hagit Attiya, Keren Censor-Hillel, Faith Ellen
2012 J jnl
J. Parallel Distributed Comput.
James Aspnes, David Eisenstat, Yitong Yin
2012 B conf
SPAA
James Aspnes, Hagit Attiya, Keren Censor-Hillel, Danny Hendler
2012 B conf
ALT
Dana Angluin, James Aspnes, Aryeh Kontorovich
2012 J jnl
J. ACM
James Aspnes, Hagit Attiya, Keren Censor-Hillel
2012 J jnl
Inf. Process. Lett.
James Aspnes, Yitong Yin
2011 C conf
LATA
Dana Angluin, James Aspnes, Raonne Barbosa Vargas
2011 A* conf
PODC
Dan Alistarh, James Aspnes, Keren Censor-Hillel, Seth Gilbert, Morteza Zadimoghaddam
2011 A conf
DISC
James Aspnes
2011 A conf
DISC
Dan Alistarh, James Aspnes
2011 A* conf
FOCS
Dan Alistarh, James Aspnes, Seth Gilbert, Rachid Guerraoui
2011 B conf
SPAA
James Aspnes, Faith Ellen
2010 A* conf
PODC
James Aspnes
2010 J jnl
ACM Trans. Algorithms
James Aspnes, Keren Censor
2010 J jnl
J. Parallel Distributed Comput.
James Aspnes, Hagit Attiya, Keren Censor
2010 B conf
ALT
Dana Angluin, James Aspnes, Lev Reyzin
2010 B conf
SPAA
James Aspnes, David Eisenstat, Yitong Yin
2010 J jnl
Theor. Comput. Sci.
Dana Angluin, James Aspnes, Lev Reyzin
2010 J jnl
CoRR
James Aspnes
2010 C conf
SSS
Dana Angluin, James Aspnes, Rida A. Bazzi, Jiang Chen, David Eisenstat, Goran Konjevod
2010 C conf
ALGOSENSORS
James Aspnes, Eric Blais, Murat Demirbas, Ryan O'Donnell, Atri Rudra, Steve Uurtamo
2009 ch.
Middleware for Network Eccentric and Mobile Applications
James Aspnes, Eric Ruppert
2009 A* conf
SODA
James Aspnes, Keren Censor
2009 J jnl
J. Mach. Learn. Res.
Dana Angluin, James Aspnes, Jiang Chen, David Eisenstat, Lev Reyzin
2009 J jnl
J. Comput. Syst. Sci.
Dana Angluin, James Aspnes, Jiang Chen, Yinghua Wu
2009 A* conf
PODC
James Aspnes, Hagit Attiya, Keren Censor
2009 J jnl
Distributed Comput.
James Aspnes, Udi Wieder
2008 J jnl
Distributed Comput.
Dana Angluin, James Aspnes, David Eisenstat
2008 J jnl
Distributed Comput.
Dana Angluin, James Aspnes, David Eisenstat
2008 A* conf
COLT
Dana Angluin, James Aspnes, Jiang Chen, David Eisenstat, Lev Reyzin
2008 J jnl
Mach. Learn.
Dana Angluin, James Aspnes, Jiang Chen, Lev Reyzin
2008 B conf
ALT
Dana Angluin, James Aspnes, Lev Reyzin
2008 A* conf
PODC
James Aspnes, Hagit Attiya, Keren Censor
2008 A* conf
SODA
James Aspnes, Muli Safra, Yitong Yin
2008 J jnl
ACM Trans. Auton. Adapt. Syst.
Dana Angluin, James Aspnes, Michael J. Fischer, Hong Jiang
2007 A conf
DISC
Dana Angluin, James Aspnes, David Eisenstat
2007 J jnl
Bull. EATCS
James Aspnes, Eric Ruppert
2007 B ed.
DCOSS
James Aspnes, Christian Scheideler, Anish Arora, Samuel Madden
2007 J jnl
Distributed Comput.
James Aspnes
2007 A* conf
COLT
Dana Angluin, James Aspnes, Jiang Chen, Lev Reyzin
2007 B conf
OPODIS
James Aspnes, Yinghua Wu
2007 A* conf
SODA
James Aspnes, Yang Richard Yang, Yitong Yin
2007 J jnl
ACM Trans. Algorithms
James Aspnes, Gauri Shah
2007 J jnl
Distributed Comput.
Dana Angluin, James Aspnes, David Eisenstat, Eric Ruppert
2007 J jnl
Theor. Comput. Sci.
James Aspnes, Joan Feigenbaum, Aleksandr Yampolskiy, Sheng Zhong
2007 B conf
OPODIS
James Aspnes, Navin Rustagi, Jared Saia
2006 J jnl
IEEE Trans. Mob. Comput.
James Aspnes, Tolga Eren, David Kiyoshi Goldenberg, A. Stephen Morse, Walter Whiteley, Yang Richard Yang, Brian D. O. Anderson, Peter N. Belhumeur
2006 J jnl
Distributed Comput.
Dana Angluin, James Aspnes, Zoë Diamadi, Michael J. Fischer, René Peralta
2006 B ed.
DCOSS
Phillip B. Gibbons, Tarek F. Abdelzaher, James Aspnes, Ramesh R. Rao
2006 J jnl
Bull. EATCS
James Aspnes, Costas Busch, Shlomi Dolev, Panagiota Fatourou, Chryssis Georgiou, Alexander A. Shvartsman, Paul G. Spirakis, Roger Wattenhofer
2006 A conf
DISC
Dana Angluin, James Aspnes, David Eisenstat
2006 J jnl
J. Comput. Syst. Sci.
James Aspnes, Kevin L. Chang, Aleksandr Yampolskiy
2006 A* conf
STOC
Dana Angluin, James Aspnes, Jiang Chen, Yinghua Wu
2006 J jnl
CoRR
James Aspnes, Yang Richard Yang, Yitong Yin
2006 J jnl
Distributed Comput.
James Aspnes, Faith Ellen Fich, Eric Ruppert
2006 A* conf
PODC
Dana Angluin, James Aspnes, David Eisenstat
2006 J jnl
CoRR
Dana Angluin, James Aspnes, David Eisenstat, Eric Ruppert
2005 J jnl
J. Algorithms
James Aspnes, Orli Waarts
2005 ch.
Handbook on Theoretical and Algorithmic Aspects of Sensor, Ad Hoc Wireless, and Peer-to-Peer Networks
James Aspnes, Gauri Shah
2005 B conf
SPAA
Dana Angluin, James Aspnes, Jiang Chen, Yinghua Wu, Yitong Yin
2005 A* conf
SODA
James Aspnes, Kevin L. Chang, Aleksandr Yampolskiy
2005 B conf
OPODIS
Dana Angluin, James Aspnes, David Eisenstat, Eric Ruppert
2005 A* ed.
PODC
Marcos Kawazoe Aguilera, James Aspnes
2005 B conf
OPODIS
Dana Angluin, James Aspnes, Michael J. Fischer, Hong Jiang
2005 B conf
OPODIS
Ittai Abraham, James Aspnes, Jian Yuan
2005 A conf
ASIACRYPT
James Aspnes, Zoë Diamadi, Kristian Gjøsteen, René Peralta, Aleksandr Yampolskiy
2005 J jnl
IACR Cryptol. ePrint Arch.
James Aspnes, Zoë Diamadi, Kristian Gjøsteen, René Peralta, Aleksandr Yampolskiy
2005 B conf
DCOSS
Dana Angluin, James Aspnes, Melody Chan, Michael J. Fischer, Hong Jiang, René Peralta
2005 B conf
SPAA
James Aspnes, Udi Wieder
2004 A* conf
PODC
Dana Angluin, James Aspnes, Zoë Diamadi, Michael J. Fischer, René Peralta
2004 A* conf
PODC
James Aspnes, Jonathan Kirsch, Arvind Krishnamurthy
2004 C conf
ALGOSENSORS
James Aspnes, David Kiyoshi Goldenberg, Yang Richard Yang
2004 A conf
DISC
James Aspnes, Faith E. Fich, Eric Ruppert
2004 A conf
ESORICS
James Aspnes, Joan Feigenbaum, Aleksandr Yampolskiy, Sheng Zhong
2003 J jnl
CoRR
James Aspnes, Orli Waarts
2003 J jnl
CoRR
James Aspnes, Zoë Diamadi, Gauri Shah
2003 J jnl
Distributed Comput.
James Aspnes
2003 J jnl
CoRR
James Aspnes, Gauri Shah
2003 A* conf
SODA
James Aspnes, Gauri Shah
2002 J jnl
J. Comput. Biol.
James Aspnes, Julia Hartling, Ming-Yang Kao, Junhyong Kim, Gauri Shah
2002 J jnl
CoRR
James Aspnes
2002 J jnl
J. Algorithms
James Aspnes
2002 A* conf
PODC
James Aspnes, Zoë Diamadi, Gauri Shah
2002 J jnl
CoRR
James Aspnes
2002 A* conf
STOC
James Aspnes, Gauri Shah, Jatin Shah
2001 B conf
ISAAC
James Aspnes, Julia Hartling, Ming-Yang Kao, Junhyong Kim, Gauri Shah
2001 J jnl
CoRR
James Aspnes, Julia Hartling, Ming-Yang Kao, Junhyong Kim, Gauri Shah
2001 A* conf
SODA
James Aspnes, David F. Fischer, Michael J. Fischer, Ming-Yang Kao, Alok Kumar
2000 A* conf
PODC
James Aspnes
2000 J jnl
CoRR
Karhan Akcoglu, James Aspnes, Bhaskar DasGupta, Ming-Yang Kao
2000 J jnl
CoRR
James Aspnes, David F. Fischer, Michael J. Fischer, Ming-Yang Kao, Alok Kumar
1998 J jnl
J. Algorithms
Miklós Ajtai, James Aspnes, Moni Naor, Yuval Rabani, Leonard J. Schulman, Orli Waarts
1998 J jnl
J. ACM
James Aspnes
1998 J jnl
J. Algorithms
James Aspnes, William Hurwood
1997 A* conf
STOC
James Aspnes
1997 J jnl
J. ACM
James Aspnes, Yossi Azar, Amos Fiat, Serge A. Plotkin, Orli Waarts
1996 conf
Online Algorithms
James Aspnes
1996 A* conf
STOC
James Aspnes, Orli Waarts
1996 J jnl
SIAM J. Comput.
James Aspnes, Orli Waarts
1996 A* conf
PODC
James Aspnes, William Hurwood
1995 A* conf
PODC
James Aspnes, Orli Waarts
1995 A* conf
SODA
Miklós Ajtai, James Aspnes, Moni Naor, Yuval Rabani, Leonard J. Schulman, Orli Waarts
1994 A* conf
FOCS
Miklós Ajtai, James Aspnes, Cynthia Dwork, Orli Waarts
1994 A* conf
PODC
Miklós Ajtai, James Aspnes, Cynthia Dwork, Orli Waarts
1994 J jnl
J. ACM
James Aspnes, Maurice Herlihy, Nir Shavit
1994 J jnl
Comb.
James Aspnes, Richard Beigel, Merrick L. Furst, Steven Rudich
1993 A* conf
STOC
James Aspnes, Yossi Azar, Amos Fiat, Serge A. Plotkin, Orli Waarts
1993 J jnl
J. Algorithms
James Aspnes
1992 A* conf
FOCS
James Aspnes, Orli Waarts
1991 A* conf
STOC
James Aspnes, Maurice Herlihy, Nir Shavit
1991 A* conf
STOC
James Aspnes, Richard Beigel, Merrick L. Furst, Steven Rudich
1990 J jnl
J. Algorithms
James Aspnes, Maurice Herlihy
1990 A* conf
PODC
James Aspnes
1990 B conf
SPAA
James Aspnes, Maurice Herlihy
1988 A* conf
VLDB
James Aspnes, Alan D. Fekete, Nancy A. Lynch, Michael Merritt, William E. Weihl
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