James McLaughlin

65 papers B 1C 1Misc 1Journal 14Unranked 48
YearRankTypeTitle / Venue / Authors
2024 J jnl
J. Sens. Actuator Networks
Tahereh Shah Mansouri, Gennady Lubarsky, Dewar D. Finlay, James McLaughlin
2023 J jnl
Sensors
Idongesit Ekerete, Matias Garcia-Constantino, Christopher Nugent, Paul J. McCullagh, James McLaughlin
2023 J jnl
Expert Syst. Appl.
Niamh McCallan, Scot Davidson, Kok Yew Ng, Pardis Biglarbeigi, Dewar D. Finlay, Boon Leong Lan, James McLaughlin
2023 J jnl
IEEE Access
Ghalib Muhammad Waqas Janjua, Dewar D. Finlay, Daniel Guldenring, Atta Ul Haq, James McLaughlin
2023 conf
CinC
Daniel Guldenring, Dewar D. Finlay, Raymond R. Bond, Alan Kennedy, Peter Doggart, Ghalib Janjua, James McLaughlin
2023 conf
EMBC
Min Jing, Kathryn Owen, Brian Mac Namee, Iab B. A. Menown, James McLaughlin
2023 Misc conf
CISS
Niamh McCallan, Scot Davidson, Kok Yew Ng, Pardis Biglarbeigi, Dewar D. Finlay, Boon Leong Lan, James McLaughlin
2022 conf
CinC
Alan Kennedy, Dewar D. Finlay, Raymond R. Bond, Daniel Guldenring, James McLaughlin, Chris Crockford
2022 conf
EMBC
Xushuo Zhang, Sam Jeffery Fishlock, Peter Sharpe, James McLaughlin
2022 conf
EMBC
Srinivasu Valagerahally Puttaswamy, Gourav Bhattacharya, Shasidran Raj, Nikhil Bhalla, Chengkuo Lee, James McLaughlin
2022 conf
CinC
Mohammad L. Karim, Antonio M. Bosnjak, James McLaughlin, Paul Crawford, David J. McEneaney, Omar J. Escalona
2022 conf
CinC
Daniel Guldenring, Ali Rababah, Dewar D. Finlay, Raymond R. Bond, Alan Kennedy, Peter Doggart, James McLaughlin
2022 J jnl
Sensors
Mohammad L. Karim, Antonio M. Bosnjak, James McLaughlin, Paul Crawford, David J. McEneaney, Omar J. Escalona
2021 conf
HCI (39)
Susan Quinn, Raymond R. Bond, Mark P. Donnelly, Shirley Davey, James McLaughlin, Dewar D. Finlay
2021 J jnl
J. Biomed. Informatics
Min Jing, Kok Yew Ng, Brian Mac Namee, Pardis Biglarbeigi, Rob Brisk, Raymond R. Bond, Dewar D. Finlay, James McLaughlin
2021 J jnl
Comput. Methods Programs Biomed.
Michael R. Jennings, Colin Turner, Raymond R. Bond, Alan Kennedy, Ranul Deelaka Thantilage, Mohand Tahar Kechadi, Nhien-An Le-Khac, James McLaughlin, Dewar D. Finlay
2021 conf
CinC
Michael R. Jennings, Ali S. Rababah, Daniel Güldenring, James McLaughlin, Dewar D. Finlay
2021 conf
CinC
Daniel Guldenring, Ali Rababah, Dewar D. Finlay, Raymond R. Bond, Alan Kennedy, Michael Jennings, Khaled Rjoob, James McLaughlin
2021 J jnl
Sensors
Idongesit Ekerete, Matias Garcia-Constantino, Yohanca Diaz-Skeete, Chris D. Nugent, James McLaughlin
2021 conf
IEEE SENSORS
Weiran Song, Hui Wang, Enayetur Rahman, Judit Barabas, Jiandong Huang, Ultan F. Power, Hugh J. Byrne, James McLaughlin, Chris D. Nugent, Paul Maguire
2021 J jnl
CoRR
Scot Davidson, Niamh McCallan, Kok Yew Ng, Pardis Biglarbeigi, Dewar D. Finlay, Boon Leong Lan, James McLaughlin
2021 conf
APSIPA ASC
Niamh McCallan, Scot Davidson, Kok Yew Ng, Pardis Biglarbeigi, Dewar D. Finlay, Boon Leong Lan, James McLaughlin
2021 J jnl
Comput. Biol. Medicine
Ali S. Rababah, Laura R. Bear, Yesim Serinagaoglu Dogrusoz, Wilson Good, Jake Bergquist, Job Stoks, Rob S. MacLeod, Khaled Rjoob, Michael Jennings, James McLaughlin, Dewar D. Finlay
2020 J jnl
IEEE Access
César Navarro, Sam Jeffery Fishlock, David Steele, Srinivasu Valagerahally Puttaswamy, Gennady Lubarsky, Shasidran Raj, James McLaughlin
2020 conf
CinC
Michael R. Jennings, Ali S. Rababah, Pardis Biglarbeigi, Rob Brisk, Daniel Güldenring, Raymond R. Bond, James McLaughlin, Dewar D. Finlay
2020 conf
BIOIMAGING
Min Jing, Donal McLaughlin, David Steele, Sara McNamee, Brian MacNamee, Patrick Cullen, Dewar D. Finlay, James McLaughlin
2020 B conf
ICIP
Min Jing, Brian Mac Namee, Donal McLaughlin, David Steele, Sara McNamee, Patrick Cullen, Dewar D. Finlay, James McLaughlin
2020 conf
CinC
Michael R. Jennings, Pardis Biglarbeigi, Raymond R. Bond, Rob Brisk, Daniel Güldenring, Alan Kennedy, James McLaughlin, Dewar D. Finlay
2020 J jnl
IEEE Intell. Transp. Syst. Mag.
Philip A. Catherwood, Michael J. Little, Dewar D. Finlay, James McLaughlin
2020 conf
CinC
Daniel Guldenring, Ali Rababah, Dewar D. Finlay, Raymond R. Bond, Alan Kennedy, Michael Jennings, Khaled Rjoob, James McLaughlin
2019 J jnl
IEEE Access
Ghalib Muhammad Waqas Janjua, Dewar D. Finlay, Daniel Guldenring, Atta Ul Haq, James McLaughlin
2019 conf
CinC
César Navarro, Mary Jo Kurth, Mark Ruddock, Sam Jeffery Fishlock, James McLaughlin
2019 conf
CinC
Pardis Biglarbeigi, Donal McLaughlin, Khaled Rjoob, Abdullah Abdullah, Niamh McCallan, Alicja Jasinska-Piadlo, Raymond R. Bond, Dewar D. Finlay, Mark Kok Yew Ng, Alan Kennedy, James McLaughlin
2019 conf
EMBC
Srinivasu Valagerahally Puttaswamy, Qiongfeng Shi, David Steele, Sam Jeffery Fishlock, Chengkuo Lee, James McLaughlin
2019 conf
FIMH
Ali Rababah, Dewar D. Finlay, Laura Bear, Raymond R. Bond, Khaled Rjoob, James McLaughlin
2019 conf
CinC
Michael R. Jennings, Daniel Guldenring, Raymond R. Bond, Ali Rababah, James McLaughlin, Dewar D. Finlay
2019 conf
CinC
Daniel Guldenring, Dewar D. Finlay, Alan Kennedy, Raymond R. Bond, Michael R. Jennings, James McLaughlin
2019 conf
CinC
Niamh McCallan, Dewar D. Finlay, Pardis Biglarbeigi, Gilberto Perpiñan, Michael R. Jennings, Kok Yew Ng, James McLaughlin, Omar Escalona
2018 conf
CinC
Ali Rababah, Dewar D. Finlay, Daniel Guldenring, Raymond R. Bond, James McLaughlin
2017 conf
CinC
Paul F. Brennan, Dewar D. Finlay, Mark S. Spence, Agnes Awuah, James McLaughlin, Johnny Moore, Andrew Nesbit, Emanuele Trucco, Ruixuan Wang, Tara Moore
2017 conf
CinC
Antonio M. Bosnjak, Pedro Linares, James McLaughlin, Omar Escalona
2017 conf
CinC
Rohit Hadia, Daniel Guldenring, Dewar D. Finlay, Alan Kennedy, Ghalib Janjua, Raymond R. Bond, James McLaughlin
2017 conf
CinC
Ghalib Muhammad Waqas Janjua, Dewar D. Finlay, Daniel Guldenring, Rohit Hadia, James McLaughlin
2017 conf
EMBC
Antonio M. Bosnjak, Alan Kennedy, Pedro Linares, Maira Borges, James McLaughlin, Omar J. Escalona
2017 conf
CinC
Daniel Guldenring, Dewar D. Finlay, Alan Kennedy, Raymond R. Bond, James McLaughlin
2017 conf
EMBC
Ghalib Janjua, Daniel Guldenring, Dewar D. Finlay, James McLaughlin
2017 conf
CinC
Omar Escalona, Louise McFrederick, Maira Borges, Pedro Linares, Ricardo Villegas, Gilberto Perpiñan, James McLaughlin, David J. McEneaney
2016 conf
CinC
Cesar Oswaldo Navarro Paredes, Mary Jo Kurth, David J. McEneaney, James McLaughlin
2016 conf
CinC
Ronald Cloughley, Raymond R. Bond, Dewar D. Finlay, Daniel Guldenring, James McLaughlin
2016 J jnl
IEEE Trans. Biomed. Eng.
Alan Kennedy, Dewar D. Finlay, Daniel Guldenring, Raymond R. Bond, James McLaughlin
2016 conf
CinC
Alan Kennedy, Dewar D. Finlay, Daniel Guldenring, Raymond R. Bond, James McLaughlin, Keiran Moran
2016 conf
CinC
Daniel Guldenring, Dewar D. Finlay, Raymond R. Bond, Alan Kennedy, James McLaughlin, Kieran Moran
2016 conf
CinC
Raymond R. Bond, Peter O'Hare, Hannah Torney, Laura Davis, Bruno Delafont, Hannah McReynolds, Anna McLister, Ben McCartney, Rebecca Di Maio, Dewar D. Finlay, Daniel Guldenring, James McLaughlin, David J. McEneaney
2015 conf
EMBC
Nicola Donnelly, Roy Harper, David Branagh, Jonathan Francey, H. Easlea, Virginia Faro-Maza, Thomas Hunniford, Andrew Mooney, James McLaughlin
2015 conf
AmIHEALTH
Jonathan Synnott, Stephen McComb, Chris D. Nugent, James McLaughlin
2015 conf
CinC
Daniel Guldenring, Dewar D. Finlay, Raymond R. Bond, Alan Kennedy, James McLaughlin
2015 C conf
ISTAS
Philip A. Catherwood, Dewar D. Finlay, James McLaughlin
2015 conf
CinC
Alan Kennedy, Dewar D. Finlay, Daniel Guldenring, Raymond R. Bond, James McLaughlin
2015 conf
CinC
Dewar D. Finlay, Raymond R. Bond, Alan Kennedy, Daniel Guldenring, Kieran Moran, James McLaughlin
2014 conf
CinC
Alan Kennedy, Dewar D. Finlay, Daniel Guldenring, James McLaughlin
2014 conf
CinC
Daniel Guldenring, Dewar D. Finlay, Raymond R. Bond, Alan Kennedy, James McLaughlin
2013 conf
EMBC
Nicola Donnelly, T. Hunniford, Richard Harper, Aiden Flynn, Alan Kennedy, David Branagh, James McLaughlin
2012 conf
ISSPA
Paolo Zicari, Abbes Amira, Georg Fischer, James McLaughlin
2012 conf
EMBC
Nicola Donnelly, Richard Harper, John McCAnderson, David Branagh, Alan Kennedy, Michael Caulfield, James McLaughlin
2012 conf
pHealth
Eric McAdams, Claudine Géhin, Bertrand Massot, James McLaughlin
tests/integration/test_pe_extractors.py
← Index tests/integration/test_pe_extractors.py python
"""
Integration tests for PE-specific extractors.
"""
import pytest
from unittest.mock import Mock, patch, MagicMock

pytestmark = [pytest.mark.integration, pytest.mark.pe]


# ============================================================================
# PEFeaturesExtractor Tests
# ============================================================================

class TestPEFeaturesExtractor:
    """Tests for PEFeaturesExtractor class."""

    def test_extract_valid_pe(self, pe_binary_path, mock_logger):
        """Test extracting features from valid PE file."""
        from redb.extractors.pe_extractors.pe_features import PEFeaturesExtractor
        from redb.models.dataclasses import PE

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.extract()

            assert result is not None
            assert isinstance(result, PE)

    def test_extract_pe_type(self, pe_binary_path, mock_logger):
        """Test PE type detection (DLL, EXE, DRIVER)."""
        from redb.extractors.pe_extractors.pe_features import PEFeaturesExtractor

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.extract()

            assert result.type in ["DLL", "EXE", "DRIVER"]

    def test_extract_architecture(self, pe_binary_path, mock_logger):
        """Test architecture detection."""
        from redb.extractors.pe_extractors.pe_features import PEFeaturesExtractor

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.extract()

            # Architecture should be detected
            assert result.architecture is not None

    def test_extract_entry_point(self, pe_binary_path, mock_logger):
        """Test entry point extraction."""
        from redb.extractors.pe_extractors.pe_features import PEFeaturesExtractor

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.extract()

            # Entry point should be a hex string
            assert result.entry_point.startswith("0x")

    def test_extract_compilation_time(self, pe_binary_path, mock_logger):
        """Test compilation time extraction."""
        from redb.extractors.pe_extractors.pe_features import PEFeaturesExtractor

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.extract()

            # Compilation time should be an integer timestamp
            assert isinstance(result.compilation_time, int)
            assert result.compilation_time_utc is not None

    def test_extract_dotnet_detection(self, pe_binary_path, mock_logger):
        """Test .NET detection."""
        from redb.extractors.pe_extractors.pe_features import PEFeaturesExtractor

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.extract()

            # Should be True for the test .NET binary
            assert isinstance(result.is_dotnet, bool)
            assert result.is_dotnet is True  # Test file is .NET

    def test_extract_headers(self, pe_binary_path, mock_logger):
        """Test header extraction."""
        from redb.extractors.pe_extractors.pe_features import PEFeaturesExtractor

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.extract()

            assert result.dos_header is not None
            assert result.nt_header is not None
            assert result.file_header is not None
            assert result.optional_header is not None

    def test_extract_counts(self, pe_binary_path, mock_logger):
        """Test section/import/export counts."""
        from redb.extractors.pe_extractors.pe_features import PEFeaturesExtractor

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.extract()

            assert isinstance(result.number_of_sections, int)
            assert isinstance(result.number_of_imports, int)
            assert isinstance(result.number_of_exports, int)
            assert isinstance(result.number_of_resources, int)

    def test_extract_rich_header(self, pe_binary_path, mock_logger):
        """Test Rich header extraction."""
        from redb.extractors.pe_extractors.pe_features import PEFeaturesExtractor

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.extract()

            # Rich header may or may not be present
            # If present, should be JSON string
            if result.rich_header_dump is not None:
                assert isinstance(result.rich_header_dump, str)

    def test_extract_version_info(self, pe_binary_path, mock_logger):
        """Test version info extraction."""
        from redb.extractors.pe_extractors.pe_features import PEFeaturesExtractor

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.extract()

            # Version info may or may not be present
            if result.version_info is not None:
                assert isinstance(result.version_info, list)


# ============================================================================
# PEImportExtractor Tests
# ============================================================================

class TestPEImportExtractor:
    """Tests for PEImportExtractor class."""

    def test_extract_imports(self, pe_binary_path, mock_logger):
        """Test import extraction."""
        from redb.extractors.pe_extractors.pe_imports import PEImportExtractor
        from redb.models.dataclasses import PEImport

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.extract()

            if result is not None:
                assert isinstance(result, PEImport)
                assert isinstance(result.pe_imports_total, int)

    def test_extract_import_libraries(self, pe_binary_path, mock_logger):
        """Test import library extraction."""
        from redb.extractors.pe_extractors.pe_imports import PEImportExtractor

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.extract()

            if result is not None and result.pe_import_libraryName is not None:
                assert isinstance(result.pe_import_libraryName, list)

    def test_extract_import_functions(self, pe_binary_path, mock_logger):
        """Test import function extraction."""
        from redb.extractors.pe_extractors.pe_imports import PEImportExtractor

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.extract()

            if result is not None and result.pe_import_functions is not None:
                assert isinstance(result.pe_import_functions, list)

    def test_prepare_export_clickhouse(self, pe_binary_path, mock_logger):
        """Test ClickHouse export preparation."""
        from redb.extractors.pe_extractors.pe_imports import PEImportExtractor

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.prepare_export_data("ClickHouseExporter")

            if result is not None:
                data, column_names, column_type_names = result
                assert 'library_name' in column_names
                assert 'function_name' in column_names


# ============================================================================
# PESectionExtractor Tests
# ============================================================================

class TestPESectionExtractor:
    """Tests for PESectionExtractor class."""

    def test_extract_sections(self, pe_binary_path, mock_logger):
        """Test section extraction."""
        from redb.extractors.pe_extractors.pe_sections import PESectionExtractor
        from redb.models.dataclasses import PESection

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.extract()

            assert result is not None
            assert isinstance(result, list)
            assert len(result) > 0
            assert isinstance(result[0], PESection)

    def test_section_properties(self, pe_binary_path, mock_logger):
        """Test section property extraction."""
        from redb.extractors.pe_extractors.pe_sections import PESectionExtractor

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.extract()

            if result is not None and len(result) > 0:
                section = result[0]
                assert section.section_name is not None
                assert section.section_entropy >= 0
                assert section.section_sha256 is not None
                assert section.section_md5 is not None
                assert section.section_size >= 0

    def test_section_entropy_range(self, pe_binary_path, mock_logger):
        """Test that section entropy is in valid range."""
        from redb.extractors.pe_extractors.pe_sections import PESectionExtractor

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.extract()

            if result is not None:
                for section in result:
                    assert 0 <= section.section_entropy <= 8

    def test_prepare_export_clickhouse(self, pe_binary_path, mock_logger):
        """Test ClickHouse export preparation."""
        from redb.extractors.pe_extractors.pe_sections import PESectionExtractor

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.prepare_export_data("ClickHouseExporter")

            if result is not None:
                data, column_names, column_type_names = result
                assert 'section_name' in column_names
                assert 'section_entropy' in column_names
                assert 'section_sha256' in column_names


# ============================================================================
# PEResourceExtractor Tests
# ============================================================================

class TestPEResourceExtractor:
    """Tests for PEResourceExtractor class."""

    def test_extract_resources(self, pe_binary_path, mock_logger):
        """Test resource extraction."""
        from redb.extractors.pe_extractors.pe_resources import PEResourceExtractor

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.extract()

            # May be None if no resources
            if result is not None:
                assert isinstance(result, list)

    def test_resource_properties(self, pe_binary_path, mock_logger):
        """Test resource property extraction."""
        from redb.extractors.pe_extractors.pe_resources import PEResourceExtractor
        from redb.models.dataclasses import PEResource

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.extract()

            if result is not None and len(result) > 0:
                resource = result[0]
                assert isinstance(resource, PEResource)
                assert resource.resource_type is not None


# ============================================================================
# PEOverlayExtractor Tests
# ============================================================================

class TestPEOverlayExtractor:
    """Tests for PEOverlayExtractor class."""

    def test_extract_overlay(self, pe_binary_path, mock_logger):
        """Test overlay extraction."""
        from redb.extractors.pe_extractors.pe_overlay import PEOverlayExtractor

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.extract()

            # May be None if no overlay
            # If present, should have overlay properties
            if result is not None:
                assert hasattr(result, 'overlay_size')

    def test_has_overlay_check(self, pe_binary_path, mock_logger):
        """Test overlay detection."""
        from redb.extractors.pe_extractors.pe_overlay import PEOverlayExtractor

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            has_overlay = extractor._has_overlay()
            assert isinstance(has_overlay, bool)


# ============================================================================
# PESignatureExtractor Tests
# ============================================================================

class TestPESignatureExtractor:
    """Tests for PESignatureExtractor class."""

    def test_extract_signature(self, pe_binary_path, mock_logger):
        """Test signature extraction."""
        from redb.extractors.pe_extractors.pe_signature import PESignatureExtractor

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.extract()

            # May be None if not signed
            # Result type depends on implementation

    def test_is_signed_check(self, pe_binary_path, mock_logger):
        """Test signature detection."""
        from redb.extractors.pe_extractors.pe_signature import PESignatureExtractor

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            is_signed = extractor._is_signed()
            assert isinstance(is_signed, bool)


# ============================================================================
# PEDotNetExtractor Tests
# ============================================================================

class TestPEDotNetExtractor:
    """Tests for PEDotNetExtractor class."""

    def test_extract_dotnet(self, pe_binary_path, mock_logger):
        """Test .NET metadata extraction."""
        from redb.extractors.pe_extractors.pe_dotnet import PEDotNetExtractor

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.extract()

            # The test file is a .NET binary
            if extractor._check_dotnet():
                assert result is not None

    def test_check_dotnet(self, pe_binary_path, mock_logger):
        """Test .NET detection."""
        from redb.extractors.pe_extractors.pe_dotnet import PEDotNetExtractor

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            is_dotnet = extractor._check_dotnet()
            assert isinstance(is_dotnet, bool)
            # Test file should be .NET
            assert is_dotnet is True


# ============================================================================
# PEInconsistencyTestsExtractor Tests
# ============================================================================

class TestPEInconsistencyTestsExtractor:
    """Tests for PEInconsistencyTestsExtractor class."""

    def test_extract_inconsistency_tests(self, pe_binary_path, mock_logger):
        """Test inconsistency tests extraction."""
        from redb.extractors.pe_extractors.pe_inconsistency_tests import PEInconstistencyTestsExtractor as PEInconsistencyTestsExtractor

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.extract()

            # extract() returns True if tests were performed, False otherwise
            # The actual test results are stored in extractor.pe_inconsistency_tests
            # and extractor.dotnet_inconsistency_tests
            assert result in (True, False)

            if result:
                # Check that test results were stored
                assert extractor.pe_inconsistency_tests is not None or extractor.dotnet_inconsistency_tests is not None


# ============================================================================
# PEExtraFindings Tests
# ============================================================================

class TestPEExtraFindings:
    """Tests for PEExtraFindings class."""

    def test_extract_extra_findings(self, pe_binary_path, mock_logger):
        """Test extra findings extraction."""
        from redb.extractors.pe_extractors.pe_extra_findings import PEExtraFindings

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

            if extractor.pe is None:
                pytest.skip("PE parsing failed")

            result = extractor.extract()

            # May return None or list of findings
            if result is not None:
                assert isinstance(result, list)


# ============================================================================
# Integration Tests
# ============================================================================

class TestPEExtractorIntegration:
    """Integration tests for PE extractors."""

    def test_all_extractors_same_pe_object(self, pe_binary_path, mock_logger, pe_object):
        """Test that extractors can share the same PE object."""
        from redb.extractors.pe_extractors.pe_features import PEFeaturesExtractor
        from redb.extractors.pe_extractors.pe_imports import PEImportExtractor
        from redb.extractors.pe_extractors.pe_sections import PESectionExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            # Create extractors sharing the same PE object
            features_ext = PEFeaturesExtractor(pe_binary_path, mock_logger, pe=pe_object)
            imports_ext = PEImportExtractor(pe_binary_path, mock_logger, pe=pe_object)
            sections_ext = PESectionExtractor(pe_binary_path, mock_logger, pe=pe_object)

            # All should use the same PE object
            assert features_ext.pe is pe_object
            assert imports_ext.pe is pe_object
            assert sections_ext.pe is pe_object

            # All should extract successfully
            features_result = features_ext.extract()
            imports_result = imports_ext.extract()
            sections_result = sections_ext.extract()

            assert features_result is not None
            # imports and sections may be None if not present

    def test_hash_consistency_across_extractors(self, pe_binary_path, mock_logger):
        """Test that hashes are consistent across all extractors."""
        from redb.extractors.pe_extractors.pe_features import PEFeaturesExtractor
        from redb.extractors.pe_extractors.pe_imports import PEImportExtractor

        with patch('redb.settings.ELASTIC_BINARIES_COLLECTION', 'test'):
            features_ext = PEFeaturesExtractor(pe_binary_path, mock_logger)
            imports_ext = PEImportExtractor(pe_binary_path, mock_logger)

            # Hashes should be the same
            assert features_ext.sha256 == imports_ext.sha256
            assert features_ext.md5 == imports_ext.md5
            assert features_ext.sha1 == imports_ext.sha1