Rajendra K. Raj

89 papers A 9B 4C 15Misc 5Journal 16Unranked 40
YearRankTypeTitle / Venue / Authors
2026 conf
SIGCSE (2)
Rajendra K. Raj, Rahul Simha, Helen Wright
2025 conf
World Conference on Information Security Education
Gurvirender P. S. Tejay, Tamara Bonaci, Travis Breaux, Umit Cali, Ernesto Cuadross-Vargas, Sara Foresti, Andrew D. McGettrick, Rajendra K. Raj, Kai Rannenberg, Andrew Seely
2025 conf
ITiCSE (2)
Mihaela Sabin, Matthew Barr, Tony Clear, Rajendra K. Raj
2025 conf
SIGCSE (2)
Stan Kurkovsky, Rajendra K. Raj, Mihaela Sabin, Sherif G. Aly
2025 conf
SIGCSE (2)
Rajendra K. Raj, Sherif G. Aly, Brett A. Becker, Celina Berg
2024 conf
ICHI
Lalitha Donga, Shreya Pramod, Sumita Mishra, Rajendra K. Raj
2024 Misc conf
SIGITE
Rajendra K. Raj, Sandra Gorka, Mihaela Sabin, Christian Servin
2024 conf
ITiCSE (2)
Sherif G. Aly, Brett A. Becker, Amruth N. Kumar, Rajendra K. Raj
2024 conf
SIGCSE (2)
Amruth N. Kumar, Rajendra K. Raj
2024 J jnl
Inroads
Amruth N. Kumar, Rajendra K. Raj
2024 J jnl
Commun. ACM
Rahul Simha, Amruth N. Kumar, Rajendra K. Raj
2023 Misc conf
SIGITE
David S. Bowers, Mihaela Sabin, Rajendra K. Raj
2023 C conf
FIE
Xumin Liu, Erik Golen, Rajendra K. Raj, Kimberly Fluet
2023 conf
SIGCSE (2)
Amruth N. Kumar, Rajendra K. Raj
2023 conf
ITiCSE (1)
Natalie Kiesler, Bonnie K. MacKellar, Amruth N. Kumar, Renée McCauley, Rajendra K. Raj, Mihaela Sabin, John Impagliazzo
2023 conf
CompEd (1)
Vijay Anand, Natalie A. Bolton, Prasad Calyam, Rohit Chadha, Rajendra K. Raj, Sumita Mishra
2023 conf
SIGCSE (2)
Mihaela Sabin, Natalie Kiesler, Amruth N. Kumar, Bonnie K. MacKellar, Renée McCauley, Rajendra K. Raj, John Impagliazzo
2023 conf
DataEd@SIGMOD
Xumin Liu, Erik Golen, Rajendra K. Raj, Kimberly Fluet
2023 conf
CompEd (2)
Rajendra K. Raj, Brett A. Becker, Michael Goldweber, Pankaj Jalote
2023 conf
SIGCSE (2)
Amruth N. Kumar, Renée McCauley, Bonnie K. MacKellar, Mihaela Sabin, Natalie Kiesler, Rajendra K. Raj
2023 C conf
FIE
Renée McCauley, Mihaela Sabin, Amruth N. Kumar, Natalie Kiesler, Bonnie K. MacKellar, Rajendra K. Raj, John Impagliazzo
2022 conf
IPDPS Workshops
Rajendra K. Raj
2022 conf
SIGCSE (2)
Amruth N. Kumar, Rajendra K. Raj
2022 J jnl
Inroads
Raymond Greenlaw, Rajendra K. Raj
2022 C conf
FIE
David S. Bowers, Mihaela Sabin, Rajendra K. Raj, John Impagliazzo
2022 C conf
EDUCON
David S. Bowers, Mihaela Sabin, Rajendra K. Raj, John Impagliazzo
2022 conf
SIGCSE (2)
Xumin Liu, Erik Golen, Rajendra K. Raj
2022 conf
ICHI
Lalitha Donga, Rajendra K. Raj, Sumita Mishra
2022 conf
SIGCSE (1)
Rajendra K. Raj, Amruth N. Kumar, Mihaela Sabin, John Impagliazzo
2022 conf
SIGCSE (2)
Xumin Liu, Erik Golen, Rajendra K. Raj
2022 conf
ITiCSE (2)
John Impagliazzo, Natalie Kiesler, Amruth N. Kumar, Bonnie K. MacKellar, Rajendra K. Raj, Mihaela Sabin
2022 conf
ITiCSE (2)
Rajendra K. Raj, John Impagliazzo, Sherif G. Aly, David S. Bowers, Harold S. Connamacher, Stan Kurkovsky, Bonnie K. MacKellar, Tom Prickett, Maíra Marques Samary, Krassen Stefanov
2022 J jnl
Inroads
Mikey Goldweber, Min Wei, Sherif G. Aly, Rajendra K. Raj, Mohamed F. Mokbel
2022 conf
ITiCSE-WGR
Rajendra K. Raj, John Impagliazzo, Sherif G. Aly, David S. Bowers, Harold S. Connamacher, Stan Kurkovsky, Bonnie K. MacKellar, Tom Prickett, Maíra Marques Samary
2022 J jnl
Inroads
Rajendra K. Raj, Amruth N. Kumar
2021 conf
IPDPS Workshops
Sherif G. Aly, Haidar Harmanani, Rajendra K. Raj, Sanaa Sharafeddine
2021 J jnl
CoRR
Sherif G. Aly, Haidar Harmanani, Rajendra K. Raj, Sanaa Sharafeddine
2021 A conf
SIGCSE
Jean R. S. Blair, Lawrence Jones, Paul M. Leidig, Scott Murray, Rajendra K. Raj, Carol J. Romanowski
2021 conf
ICHI
Asma Alnemari, Rajendra K. Raj, Carol J. Romanowski, Sumita Mishra
2021 conf
ITiCSE-WGR
Rajendra K. Raj, Mihaela Sabin, John Impagliazzo, David Bowers, Mats Daniels, Felienne Hermans, Natalie Kiesler, Amruth N. Kumar, Bonnie K. MacKellar, Renée McCauley, Syed Waqar Nabi, Michael Oudshoorn
2021 conf
ITiCSE (2)
Rajendra K. Raj, Mihaela Sabin, John Impagliazzo, David Bowers, Mats Daniels, Felienne Hermans, Natalie Kiesler, Amruth N. Kumar, Bonnie K. MacKellar, Renée McCauley, Syed Waqar Nabi, Michael Oudshoorn
2020 J jnl
J. Comput. Sci. Coll.
Adrienne Decker, Peter DePasquale, Rajendra K. Raj, Matt Jadud
2020 Misc conf
SIGITE
Mihaela Sabin, Stuart H. Zweben, Barry M. Lunt, Rajendra K. Raj
2020 conf
ITiCSE-WGR
Rajendra K. Raj, Carol J. Romanowski, John Impagliazzo, Sherif G. Aly, Brett A. Becker, Juan Chen, Sheikh K. Ghafoor, Nasser Giacaman, Steven I. Gordon, Cruz Izu, Shahram Rahimi, Michael P. Robson, Neena Thota
2020 B conf
ITiCSE
Jean R. S. Blair, Christa M. Chewar, Rajendra K. Raj, Edward Sobiesk
2020 B conf
ITiCSE
Rajendra K. Raj, Carol J. Romanowski, Sherif G. Aly, Brett A. Becker, Juan Chen, Sheikh K. Ghafoor, Nasser Giacaman, Steven I. Gordon, Cruz Izu, Shahram Rahimi, Michael P. Robson, Neena Thota
2019 A conf
SIGCSE
Allen Parrish, Rajendra K. Raj, Lawrence Jones
2019 conf
ITiCSE-WGR
Rajendra K. Raj, Allen Parrish, John Impagliazzo, Carol J. Romanowski, Sherif G. Aly, Casey C. Bennett, Karen C. Davis, Andrew D. McGettrick, Teresa Susana Mendes Pereira, Lovisa Sundin
2019 J jnl
Computer
Ann E. Kelley Sobel, Allen Parrish, Rajendra K. Raj
2019 A conf
SIGCSE
Rajendra K. Raj, Vijay Anand, David S. Gibson, Siddharth Kaza, Andrew Phillips
2019 B conf
ITiCSE
Rajendra K. Raj, Allen Parrish, John Impagliazzo, Carol J. Romanowski, Sherif Aly Ahmed, Casey C. Bennett, Karen C. Davis, Andrew D. McGettrick, Teresa Susana Mendes Pereira, Lovisa Sundin
2018 A conf
SIGCSE
Rajendra K. Raj, Allen Parrish
2018 conf
ITiCSE (Companion)
Allen Parrish, John Impagliazzo, Rajendra K. Raj, Henrique M. Dinis Santos, Muhammad Rizwan Asghar, Audun Jøsang, Teresa Susana Mendes Pereira, Eliana Stavrou
2018 B conf
ITiCSE
Allen Parrish, John Impagliazzo, Rajendra K. Raj, Henrique M. Dinis Santos, Muhammad Rizwan Asghar, Audun Jøsang, Teresa Susana Mendes Pereira, Vítor J. Sá, Eliana Stavrou
2018 conf
Critical Infrastructure Protection
Asma Alnemari, Suchith Arodi, Valentina Rodriguez Sosa, Soni Pandey, Carol J. Romanowski, Rajendra K. Raj, Sumita Mishra
2018 J jnl
Computer
Rajendra K. Raj, Allen Parrish
2018 A conf
SIGCSE
Michael J. Oudshoorn, Stan Thomas, Rajendra K. Raj, Allen Parrish
2017 conf
ICHI
Asma Alnemari, Carol J. Romanowski, Rajendra K. Raj
2017 C conf
FIE
Sumita Mishra, Rajendra K. Raj, Paul Tymann, Jamie Fagan, Sage Miller
2017 Misc conf
SIGITE
Joseph J. Ekstrom, Barry M. Lunt, Allen Parrish, Rajendra K. Raj, Edward Sobiesk
2017 C conf
FIE
Rajendra K. Raj, Joseph J. Ekstrom, John Impagliazzo, Steven Lingafelt, Allen Parrish, Harry Reif, Edward Sobiesk
2017 Misc conf
SIGITE
Rajendra K. Raj, Jim Leone, Allen Parrish, Mihaela Sabin
2016 conf
Critical Infrastructure Protection
Carol J. Romanowski, Rajendra K. Raj, Jennifer Schneider, Sumita Mishra, Bernard Brooks, Jessica Pardee, Bharat Bhole, Nikolaus Robalino
2016 C conf
FIE
Sumita Mishra, Trudy Howles, Rajendra K. Raj, Carol J. Romanowski, Jennifer Schneider, Alicia McNett, Daryl J. Dates
2016 conf
ICHI
Suhair Alshehri, Sumita Mishra, Rajendra K. Raj
2015 J jnl
Int. J. Crit. Infrastructure Prot.
Carol J. Romanowski, Rajendra K. Raj, Jennifer Schneider, Sumita Mishra, Vinay Shivshankar, Srikant Ayengar, Fernando Cueva
2014 A conf
SIGCSE
Xumin Liu, Rajendra K. Raj, Thomas Reichlmayr, Alex Pantaleev, Chunmei Liu
2013 C conf
FIE
Sumita Mishra, Carol J. Romanowski, Rajendra K. Raj, Trudy Howles, Jennifer Schneider
2013 C conf
FIE
Carol J. Romanowski, Rajendra K. Raj
2013 C conf
FIE
Xumin Liu, Rajendra K. Raj, Tom Reichlmayr, Chunmei Liu, Alex Pantaleev
2013 C conf
FIE
Zack Butler, Rajendra K. Raj, Minseok Kwon
2013 conf
ICHI
Suhair Alshehri, Rajendra K. Raj
2013 C conf
FIE
Xumin Liu, Rajendra K. Raj, Thomas Reichlmayr, Chunmei Liu, Alex Pantaleev
2012 conf
ICDE Workshops
Suhair Alshehri, Stanislaw P. Radziszowski, Rajendra K. Raj
2011 C conf
FIE
Reynold J. Bailey, Hans-Peter Bischof, Minseok Kwon, Tracy Miller, Rajendra K. Raj
2011 C conf
FIE
Carol J. Romanowski, Rajendra K. Raj, S. Manian Ramkumar
2011 C conf
FIE
Carol J. Romanowski, Rajendra K. Raj, Minseok Kwon
2009 conf
CSIE (4)
Priyanka Sinha, Rajendra K. Raj, Carol J. Romanowski
2008 J jnl
J. Comput. Sci. Coll.
Herbert J. Bernstein, Jennifer S. Kay, William McAllister, Rajendra K. Raj
2007 J jnl
J. Comput. Sci. Coll.
Roxanne L. Canosa, Rajendra K. Raj
2007 J jnl
J. Comput. Sci. Coll.
Rajendra K. Raj, Jennifer S. Kay, Herbert J. Bernstein, Chris Okasaki, Jeffrey Forbes, Virginia Teller
2007 J jnl
J. Comput. Sci. Coll.
Anurag Naidu, Harita Chilukuri, Gaurav Gargate, Sushil Magdum, Rajendra K. Raj
2003 conf
OTM
Rajendra K. Raj
1998 A conf
OOPSLA
Doug Lea, David W. Forslund, Tom Barry, Don Vines, Rajendra K. Raj, Ashutosh Tiwary
1995 conf
OOPSLA Addendum
Ashutosh Tiwary, Rajendra K. Raj, Doug Lea, Christopher J. Bosch
1994 A conf
SIGCSE
Paul T. Tymann, Doug Lea, Rajendra K. Raj
1991 J jnl
Softw. Pract. Exp.
Rajendra K. Raj, Ewan D. Tempero, Henry M. Levy, Andrew P. Black, Norman C. Hutchinson, Eric Jul
1989 A conf
ECOOP
Rajendra K. Raj, Henry M. Levy
1989 J jnl
Comput. J.
Rajendra K. Raj, Henry M. Levy
tests/integration/test_basicproperties.py
← Index tests/integration/test_basicproperties.py python
"""
Integration tests for the BasicPropertiesExtractor class.
"""
import pytest
import os
from unittest.mock import Mock, patch, MagicMock

pytestmark = [pytest.mark.integration]


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

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

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

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

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

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

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

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

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

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

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

            assert extractor.parent_sha256 == parent_hash

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

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

            assert "-basic_properties" in extractor.elastic_index


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

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

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

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


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

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

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

            result = extractor.extract()

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

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

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

            result = extractor.extract()

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

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

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

            result = extractor.extract()

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

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

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

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


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

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

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

            result = extractor.extract()

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

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

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

            result = extractor.extract()

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

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

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

            result = extractor.extract()

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


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

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

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

            result = extractor.extract()

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

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

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

            result = extractor.extract()

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


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

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

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

            result = extractor.extract()

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

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

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

            result = extractor.extract()

            assert result.filesize == len(elf_binary_content)


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

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

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

            result = extractor.prepare_export_data("ElasticsearchExporter")

            assert result is extractor.basic_properties

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

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

            result = extractor.prepare_export_data("ClickHouseExporter")

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

            data, column_names, column_type_names = result

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

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

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

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

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

            row = data[0]

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

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

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


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

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

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

            assert extractor.get_clickhouse_table() == "redb_basic_properties"


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

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

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

            result = extractor.export_data()

            assert result is True

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

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

            result = extractor.export_data()

            # Should succeed with no exporters
            assert result is True


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

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

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

            result = extractor.extract()

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

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

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

            result = extractor.extract()

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


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

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

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

            result = extractor.extract()

            assert result is not None
            assert result.is_fat is True

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

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

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

            result = extractor.extract()

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

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

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

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

            result = extractor.extract()

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

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

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

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

            result = extractor.extract()

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            result = extractor.extract()

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


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

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

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

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

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

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

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

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