Raffaele Sperandeo

43 papers Journal 1Unranked 32
YearRankTypeTitle / Venue / Authors
2025 J jnl
Informatics
Valeria Cioffi, Ottavio Ragozzino, Lucia Luciana Mosca, Enrico Moretto, Enrica Tortora, Annamaria Acocella, Claudia Montanari, Antonio Ferrara, Stefano Crispino, Elena Gigante, Alexander Lommatzsch, Mariano Pizzimenti, Efisio Temporin, Valentina Barlacchi, Claudio Billi, Giovanni Salonia, Raffaele Sperandeo
2023 conf
WIRN
Nelson Mauro Maldonato, Benedetta Muzii, Raffaele Sperandeo, Natascia De Lucia, Gianluigi Califano, Cristiano Scandurra, Vincenzo Bochicchio, Francesco Mangiapia, Stefania Sivero, Fabio Carraturo, Anna Esposito
2023 conf
CogInfoCom
Valeria Cioffi, Lucia Luciana Mosca, Enrico Moretto, Roberta Stanzione, Ottavio Ragozzino, Giovanni Salonia, Claudia Montanari, Oliviero Rossi, Claudio Billi, Paolo Quattrini, Alexander Lommatzsch, Antonio Ferrara, Stefano Crispino, Elena Gigante, Mariano Pizzimenti, Roberta Melis, Efisio Temporin, Nelson Mauro Maldonato, Raffaele Sperandeo
2023 conf
WIRN
Benedetta Muzii, Francesco Mangiapia, Anna Esposito, Raffaele Sperandeo, Gianluigi Califano, Natascia De Lucia, Cristiano Scandurra, Fabio Carraturo, Nelson Mauro Maldonato
2022 conf
CogInfoCom
Tiziana Di Perna, Fabio Carraturo, Viviana Giannicola, Marco Alfonso Nacchia, Marco Pepe, Benedetta Muzii, Mario Bottone, Raffaele Sperandeo, Nelson Mauro Maldonato, Cristiano Scandurra
2022 conf
CogInfoCom
Giuseppe Vertola, Antonella Marcello, Mario Bottone, Raffaele Sperandeo, Benedetta Muzii, Cristiano Scandurra, Nelson Mauro Maldonato
2022 conf
CogInfoCom
Antonella Tafuro, Giorgia Masi, Marco Terracciano, Nelson Mauro Maldonato, Mario Bottone, Raffaele Sperandeo, Cristiano Scandurra, Benedetta Muzii
2020 ch.
Neural Approaches to Dynamics of Signal Exchanges
Silvia Dell'Orco, Raffaele Sperandeo, Ciro Punzo, Mario Bottone, Anna Esposito, Antonietta Maria Esposito, Vincenzo Bochicchio, Mauro N. Maldonato
2020 conf
CogInfoCom
Lucia Luciana Mosca, Raffaele Sperandeo, Valeria Cioffi, Daniela Cantone, Enrico Moretto, Teresa Longobardi, Yari Mirko Alfano, Grazia Isabella Continisio, Benedetta Muzii, Mario Bottone, Nelson Mauro Maldonato
2020 ch.
Neural Approaches to Dynamics of Signal Exchanges
Mauro N. Maldonato, Raffaele Sperandeo, Anna Esposito, Ciro Punzo, Silvia Dell'Orco
2020 ch.
Neural Approaches to Dynamics of Signal Exchanges
Daniela Iennaco, Raffaele Sperandeo, Lucia Luciana Mosca, Martina Messina, Enrico Moretto, Valeria Cioffi, Silvia Dell'Orco, Mauro N. Maldonato
2020 conf
CogInfoCom
Nelson Mauro Maldonato, Alessandro Chiodi, Donatella di Corrado, Antonietta Maria Esposito, Salvatore de Lucia, Raffaele Sperandeo, Benedetta Muzii
2020 conf
CogInfoCom
Nelson Mauro Maldonato, Raffaele Sperandeo, Marinella Coco, Valeria Cioffi, Salvatore de Lucia, Lucia Luciana Mosca, Anna Esposito
2020 conf
CogInfoCom
Raffaele Sperandeo, Teresa Longobardi, Lucia Luciana Mosca, Valeria Cioffi, Enrico Moretto, Yari Mirko Alfano, Benedetta Muzii, Nelson Mauro Maldonato
2020 conf
CogInfoCom
Valeria Cioffi, Daniela Cantone, Carmela Guerriera, Marco Architravo, Lucia Luciana Mosca, Raffaele Sperandeo, Enrico Moretto, Teresa Longobardi, Yari Mirko Alfano, Grazia Isabella Continisio, Benedetta Muzii, Nelson Mauro Maldonato
2020 ch.
Neural Approaches to Dynamics of Signal Exchanges
Mauro N. Maldonato, Paolo Valerio, Raffaele Sperandeo, Antonietta Maria Esposito, Roberto Vitelli, Cristiano Scandurra, Benedetta Muzii, Silvia Dell'Orco
2020 ch.
Neural Approaches to Dynamics of Signal Exchanges
Alfonso Davide Di Sarno, Raffaele Sperandeo, Giuseppina Di Leva, Irene Fabbricino, Enrico Moretto, Silvia Dell'Orco, Mauro N. Maldonato
2019 conf
CogInfoCom
Raffaele Sperandeo, Lucia Luciana Mosca, Yari Mirko Alfano, Valeria Cioffi, Alfonso Davide Di Sarno, Anastasiya Galchenko, Daniela Iennaco, Teresa Longobardi, Enrico Moretto, Silvia Dell'Orco, Benedetta Muzii, Nelson Mauro Maldonato
2019 ch.
Quantifying and Processing Biomedical and Behavioral Signals
Nelson Mauro Maldonato, Luigi Maria Sicca, Antonietta Maria Esposito, Raffaele Sperandeo
2019 ch.
Cognitive Infocommunications, Theory and Applications
Raffaele Sperandeo, Mauro Maldonato, Enrico Moretto, Silvia Dell'Orco
2019 conf
MindCare
Claudia Repetto, Silvia Serino, Mauro N. Maldonato, Teresa Longobardi, Raffaele Sperandeo, Daniela Iennaco, Giuseppe Riva
2019 ch.
Quantifying and Processing Biomedical and Behavioral Signals
Vincenzo Monda, Raffaele Sperandeo, Nelson Mauro Maldonato, Enrico Moretto, Silvia Dell'Orco, Elena Gigante, Gennaro Iorio, Giovanni Messina
2019 conf
CogInfoCom
Raffaele Sperandeo, Lucia Luciana Mosca, Yari Mirko Alfano, Valeria Cioffi, Alfonso Davide Di Sarno, Anastasiya Galchenko, Daniela Iennaco, Teresa Longobardi, Enrico Moretto, Silvia Dell'Orco, Benedetta Muzii, Nelson Mauro Maldonato
2019 conf
CogInfoCom
Nelson Mauro Maldonato, Mario Bottone, Raffaele Sperandeo, Cristiano Scandurra, Vincenzo Bochicchio, Massimiliano Lorenzo Cappuccio, Antonietta Maria Esposito, Benedetta Muzii
2019 conf
CogInfoCom
Nelson Mauro Maldonato, Benedetta Muzii, Donatella di Corrado, Raffaele Sperandeo, Mario Bottone, Massimiliano Lorenzo Cappuccio, Marinella Coco, Anna Esposito
2019 conf
PSYCHOBIT
Raffaele Sperandeo, Alfonso Davide Di Sarno, Teresa Longobardi, Daniela Iennaco, Lucia Luciana Mosca, Nelson Mauro Maldonato
2018 conf
CogInfoCom
Lucia Luciana Mosca, Nelson Mauro Maldonado, Alfonso Davide Di Sarno, Marzia Duval, Valeria Cioffi, Silvia Dell'Orco, Raffaele Sperandeo, Enrico Moretto, Giuseppina di Ronza
2018 conf
CogInfoCom
Vania Costa, Martina Messina, Mario Bottone, Raffaele Sperandeo, Anna Esposito, Nelson Mauro Maldonato, Valeria Cioffi, Giuseppina di Ronza, Daniela Iennaco, Pasquale Dolce, Enrico Moretto
2018 conf
CogInfoCom
Martina Messina, Alfonso Davide Di Sarno, Yari Mirko Alfano, Maria Guastaferro, Nadia Nugnes, Daniela Iennaco, Nelson Mauro Maldonado, Raffaele Sperandeo, Nicole Nascivera
2018 conf
CogInfoCom
Teresa Longobardi, Raffaele Sperandeo, Francesca Albano, Yuri Tedesco, Enrico Moretto, Alfonso Davide Di Sarno, Silvia Dell'Orco, Nelson Mauro Maldonato
2018 conf
CogInfoCom
Alfonso Davide Di Sarno, Maria Luigia Fusco, Silvia Dell'Orco, Valeria Cioffi, Raffaele Sperandeo, Enrico Moretto, Gennaro Iorio, Teresa Longobardi, Nelson Mauro Maldonado, Gaetano Buonocore
2018 conf
CogInfoCom
Daniela Iennaco, Martina Messina, Enrico Moretto, Silvia Dell'Orco, Vania Costa, Raffaele Sperandeo, Valeria Cioffi, Anna Esposito, Nelson Mauro Maldonato, Pasquale Dolce, Gaetano Buonocore
2018 conf
CogInfoCom
Enrico Moretto, Alfonso Davide Di Sarno, Vania Costa, Silvia Dell'Orco, Raffaele Sperandeo, Mariavittoria Lerro, Nelson Mauro Maldonado, Marzia Duval, Teresa Longobardi
2018 conf
CogInfoCom
Raffaele Sperandeo, Enrico Moretto, Daniela Iennaco, Nelson Mauro Maldonato
2018 conf
CogInfoCom
Nicole Nascivera, Yari Mirko Alfano, Tilde Annunziato, Martina Messina, Vittoria Silviana Iorio, Valeria Cioffi, Raffaele Sperandeo, Margherita Rosato, Teresa Longobardi, Nelson Mauro Maldonato
2018 ch.
Multidisciplinary Approaches to Neural Computing
Mauro N. Maldonato, Silvia Dell'Orco, Raffaele Sperandeo
2017 conf
CogInfoCom
Raffaele Sperandeo, Enrico Moretto, Gesualda Baldo, Silvia Dell'Orco, Mauro Maldonato
2017 conf
IIH-MSP (1)
Nelson Mauro Maldonato, Mario Bottone, Benedetta Muzii, Donatella di Corrado, Raffaele Sperandeo, Simone D'Andrea, Anna Esposito
2017 conf
IIH-MSP (1)
Nelson Mauro Maldonato, Paolo Valerio, Mario Bottone, Raffaele Sperandeo, Cristiano Scandurra, Ciro Punzo, Benedetta Muzii, Simone D'Andrea, Anna Esposito
2017 conf
IIH-MSP (1)
Raffaele Sperandeo, Lucia Luciana Mosca, Anastasiya Galchenko, Enrico Moretto, Alfonso Davide Di Sarno, Teresa Longobardi, Daniela Iennaco, Valeria Cioffi, Anna Esposito, Nelson Mauro Maldonato
2017 conf
IIH-MSP (1)
Alfonso Davide Di Sarno, Teresa Longobardi, Enrico Moretto, Giuseppina Di Leva, Irene Fabbricino, Lucia Luciana Mosca, Valeria Cioffi, Raffaele Sperandeo
2016 ch.
Advances in Neural Networks
Raffaele Sperandeo, Anna Esposito, Mauro Maldonato, Silvia Dell'Orco
2016 conf
CogInfoCom
Raffaele Sperandeo, Mauro Maldonato, Gesualda Baldo, Silvia Dell'Orco
tests/unit/test_apk_dataclasses.py
← Index tests/unit/test_apk_dataclasses.py python
"""
Unit tests for APK dataclasses in redb/models/dataclasses.py.
"""
import pytest
from dataclasses import asdict, fields

pytestmark = [pytest.mark.unit, pytest.mark.dataclass, pytest.mark.apk]


# ============================================================================
# APKFeatures
# ============================================================================

class TestAPKFeaturesDataclass:
    """Tests for APKFeatures dataclass."""

    def test_named_fields(self):
        from redb.models.dataclasses import APKFeatures

        f = APKFeatures(
            package_name="com.example.app",
            app_name="Example App",
            version_code=1,
            version_name="1.0.0",
        )
        assert f.package_name == "com.example.app"
        assert f.app_name == "Example App"
        assert f.version_code == 1
        assert f.version_name == "1.0.0"

    def test_all_fields_default_none_or_safe(self):
        from redb.models.dataclasses import APKFeatures

        f = APKFeatures()
        # Nullable fields default to None
        assert f.package_name is None
        assert f.app_name is None
        assert f.version_code is None
        assert f.version_name is None
        assert f.min_sdk_version is None
        assert f.target_sdk_version is None
        assert f.compile_sdk_version is None
        assert f.main_activity is None
        # Non-nullable fields have safe defaults
        assert f.is_debuggable is False
        assert f.allow_backup is True
        assert f.uses_cleartext_traffic is False
        assert f.supported_abis == []
        assert f.dex_count == 0
        assert f.total_dex_size == 0
        assert f.total_file_count == 0
        assert f.has_native_code is False
        assert f.has_assets is False
        assert f.uses_libraries == []
        assert f.earliest_content_modification is None
        assert f.latest_content_modification is None
        assert f.contains_embedded_apk is False

    def test_all_fields_populated(self):
        from redb.models.dataclasses import APKFeatures

        f = APKFeatures(
            package_name="com.malware.test",
            app_name="Malware",
            version_code=42,
            version_name="6.6.6",
            min_sdk_version=21,
            target_sdk_version=33,
            compile_sdk_version=33,
            main_activity="com.malware.test.MainActivity",
            is_debuggable=True,
            allow_backup=False,
            uses_cleartext_traffic=True,
            supported_abis=["armeabi-v7a", "arm64-v8a", "x86"],
            dex_count=3,
            total_dex_size=5000000,
            total_file_count=200,
            has_native_code=True,
            has_assets=True,
            uses_libraries=["com.google.android.maps"],
            earliest_content_modification="2024-01-01T00:00:00Z",
            latest_content_modification="2024-06-15T12:00:00Z",
            contains_embedded_apk=True,
        )
        assert f.is_debuggable is True
        assert f.dex_count == 3
        assert len(f.supported_abis) == 3
        assert f.contains_embedded_apk is True

    def test_asdict_roundtrip(self):
        from redb.models.dataclasses import APKFeatures

        f = APKFeatures(
            package_name="com.test",
            app_name="Test",
            version_code=1,
            version_name="1.0",
        )
        d = asdict(f)
        assert d["package_name"] == "com.test"
        assert d["is_debuggable"] is False
        assert d["supported_abis"] == []

    def test_partial_extraction(self):
        """Verify that APKFeatures can be created with only some fields populated,
        simulating a partial extraction where some fields failed."""
        from redb.models.dataclasses import APKFeatures

        f = APKFeatures(
            package_name="com.example.app",
            # app_name failed to extract — left as None
            version_code=10,
            # version_name failed to extract — left as None
            is_debuggable=True,
            dex_count=2,
        )
        assert f.package_name == "com.example.app"
        assert f.app_name is None
        assert f.version_code == 10
        assert f.version_name is None
        assert f.is_debuggable is True
        assert f.dex_count == 2


# ============================================================================
# APKManifestComponent
# ============================================================================

class TestAPKManifestComponentDataclass:

    def test_creation(self):
        from redb.models.dataclasses import APKManifestComponent

        c = APKManifestComponent(
            component_type="activity",
            class_name="com.example.MainActivity",
            is_exported=True,
            intent_actions=["android.intent.action.MAIN"],
            intent_categories=["android.intent.category.LAUNCHER"],
        )
        assert c.component_type == "activity"
        assert c.class_name == "com.example.MainActivity"
        assert c.is_exported is True
        assert len(c.intent_actions) == 1
        assert len(c.intent_categories) == 1

    def test_defaults(self):
        from redb.models.dataclasses import APKManifestComponent

        c = APKManifestComponent(
            component_type="service",
            class_name="com.example.MyService",
            is_exported=False,
        )
        assert c.intent_actions == []
        assert c.intent_categories == []


# ============================================================================
# APKManifest
# ============================================================================

class TestAPKManifestDataclass:

    def test_required_fields(self):
        from redb.models.dataclasses import APKManifest

        m = APKManifest(
            activity_count=5,
            service_count=2,
            receiver_count=3,
            provider_count=1,
        )
        assert m.activity_count == 5
        assert m.service_count == 2
        assert m.receiver_count == 3
        assert m.provider_count == 1

    def test_optional_list_defaults(self):
        from redb.models.dataclasses import APKManifest

        m = APKManifest(
            activity_count=0,
            service_count=0,
            receiver_count=0,
            provider_count=0,
        )
        assert m.activities == []
        assert m.services == []
        assert m.receivers == []
        assert m.providers == []
        assert m.exported_components == []
        assert m.intent_filters_by_action == []
        assert m.intent_filters_by_category == []
        assert m.uses_features == []
        assert m.meta_data is None
        assert m.manifest_xml is None

    def test_fully_populated(self):
        from redb.models.dataclasses import APKManifest

        m = APKManifest(
            activity_count=2,
            service_count=1,
            receiver_count=1,
            provider_count=0,
            activities=["MainActivity", "SettingsActivity"],
            services=["SyncService"],
            receivers=["BootReceiver"],
            providers=[],
            exported_components=["MainActivity", "BootReceiver"],
            intent_filters_by_action=["android.intent.action.MAIN"],
            uses_features=["android.hardware.camera"],
            manifest_xml="<manifest>...</manifest>",
        )
        assert len(m.activities) == 2
        assert len(m.exported_components) == 2
        assert m.manifest_xml is not None


# ============================================================================
# APKPermission / APKPermissions
# ============================================================================

class TestAPKPermissionDataclass:

    def test_creation(self):
        from redb.models.dataclasses import APKPermission

        p = APKPermission(
            permission_name="android.permission.CAMERA",
            protection_level="dangerous",
        )
        assert p.permission_name == "android.permission.CAMERA"
        assert p.protection_level == "dangerous"
        assert p.is_custom is False

    def test_custom_permission(self):
        from redb.models.dataclasses import APKPermission

        p = APKPermission(
            permission_name="com.example.CUSTOM_PERM",
            protection_level="signature",
            is_custom=True,
        )
        assert p.is_custom is True


class TestAPKPermissionsDataclass:

    def test_required_fields(self):
        from redb.models.dataclasses import APKPermissions

        p = APKPermissions(
            total_permission_count=10,
            dangerous_permission_count=3,
        )
        assert p.total_permission_count == 10
        assert p.dangerous_permission_count == 3

    def test_defaults(self):
        from redb.models.dataclasses import APKPermissions

        p = APKPermissions(
            total_permission_count=0,
            dangerous_permission_count=0,
        )
        assert p.permissions == []
        assert p.dangerous_permissions == []
        assert p.custom_permissions == []
        assert p.permission_details == []
        assert p.permhash is None

    def test_with_permission_details(self):
        from redb.models.dataclasses import APKPermission, APKPermissions

        details = [
            APKPermission("android.permission.INTERNET", "normal"),
            APKPermission("android.permission.CAMERA", "dangerous"),
        ]
        p = APKPermissions(
            total_permission_count=2,
            dangerous_permission_count=1,
            permissions=["android.permission.INTERNET", "android.permission.CAMERA"],
            dangerous_permissions=["android.permission.CAMERA"],
            permission_details=details,
            permhash="abc123def456",
        )
        assert len(p.permission_details) == 2
        assert p.permhash == "abc123def456"


# ============================================================================
# APKCertificate / APKCodeSigningInfo
# ============================================================================

class TestAPKCertificateDataclass:

    def test_required_fields(self):
        from redb.models.dataclasses import APKCertificate

        c = APKCertificate(
            subject="CN=Android Debug",
            issuer="CN=Android Debug",
            serial_number="1234567890",
            valid_from="2024-01-01",
            valid_to="2054-01-01",
            thumbprint_sha1="aabbccdd" * 5,
            thumbprint_sha256="aabbccdd" * 8,
        )
        assert c.subject == "CN=Android Debug"
        assert c.issuer == "CN=Android Debug"
        assert c.is_self_signed is False

    def test_optional_fields(self):
        from redb.models.dataclasses import APKCertificate

        c = APKCertificate(
            subject="CN=Test",
            issuer="CN=CA",
            serial_number="1",
            valid_from="2024-01-01",
            valid_to="2025-01-01",
            thumbprint_sha1="aa" * 20,
            thumbprint_sha256="bb" * 32,
            algorithm="SHA256withRSA",
            key_size=2048,
            is_self_signed=True,
        )
        assert c.algorithm == "SHA256withRSA"
        assert c.key_size == 2048
        assert c.is_self_signed is True


class TestAPKCodeSigningInfoDataclass:

    def test_required_fields(self):
        from redb.models.dataclasses import APKCodeSigningInfo

        info = APKCodeSigningInfo(
            _id="abcdef1234567890" * 4,
            is_signed=True,
        )
        assert info.is_signed is True
        assert info.signature_scheme_versions == []
        assert info.number_of_certificates == 0
        assert info.x509_certificates is None
        assert info.apk_signer_subject is None
        assert info.apk_signer_issuer is None

    def test_fully_populated(self):
        from redb.models.dataclasses import APKCertificate, APKCodeSigningInfo

        cert = APKCertificate(
            subject="CN=Test",
            issuer="CN=Test",
            serial_number="1",
            valid_from="2024-01-01",
            valid_to="2025-01-01",
            thumbprint_sha1="aa" * 20,
            thumbprint_sha256="bb" * 32,
        )
        info = APKCodeSigningInfo(
            _id="cc" * 32,
            is_signed=True,
            signature_scheme_versions=[1, 2, 3],
            number_of_certificates=1,
            x509_certificates=[cert],
            apk_signer_subject="CN=Test",
            apk_signer_issuer="CN=Test",
        )
        assert len(info.signature_scheme_versions) == 3
        assert info.number_of_certificates == 1
        assert len(info.x509_certificates) == 1


# ============================================================================
# APKDexFile
# ============================================================================

class TestAPKDexFileDataclass:

    def test_required_fields(self):
        from redb.models.dataclasses import APKDexFile

        d = APKDexFile(
            filename="classes.dex",
            sha256="aa" * 32,
            class_count=100,
            method_count=500,
            string_count=1000,
        )
        assert d.filename == "classes.dex"
        assert d.class_count == 100
        assert d.method_count == 500
        assert d.string_count == 1000

    def test_optional_fields_defaults(self):
        from redb.models.dataclasses import APKDexFile

        d = APKDexFile(
            filename="classes2.dex",
            sha256="bb" * 32,
            class_count=0,
            method_count=0,
            string_count=0,
        )
        assert d.tlsh is None
        assert d.top_packages is None
        assert d.api_usage is None
        assert d.obfuscation_indicators is None

    def test_tlsh_populated(self):
        from redb.models.dataclasses import APKDexFile

        tlsh_value = "T1" + "A" * 68
        d = APKDexFile(
            filename="classes.dex",
            sha256="aa" * 32,
            class_count=100,
            method_count=500,
            string_count=1000,
            tlsh=tlsh_value,
        )
        assert d.tlsh == tlsh_value

    def test_with_api_usage(self):
        from redb.models.dataclasses import APKDexFile

        d = APKDexFile(
            filename="classes.dex",
            sha256="cc" * 32,
            class_count=50,
            method_count=200,
            string_count=300,
            top_packages=[{"name": "com.example", "class_count": 30}],
            api_usage={
                "crypto": ["Ljavax/crypto/Cipher;->getInstance"],
                "reflection": ["Ljava/lang/Class;->forName"],
            },
            obfuscation_indicators={"short_class_names_ratio": 0.8, "single_char_methods_ratio": 0.5},
        )
        assert len(d.api_usage) == 2
        assert d.obfuscation_indicators["short_class_names_ratio"] == 0.8


# ============================================================================
# APKResource
# ============================================================================

class TestAPKResourceDataclass:

    def test_creation(self):
        from redb.models.dataclasses import APKResource

        r = APKResource(
            path="res/drawable/icon.png",
            size=1024,
            sha256="dd" * 32,
            filetype_magika="png",
        )
        assert r.path == "res/drawable/icon.png"
        assert r.size == 1024
        assert r.is_suspicious is False

    def test_suspicious_resource(self):
        from redb.models.dataclasses import APKResource

        r = APKResource(
            path="assets/payload.dex",
            size=50000,
            sha256="ee" * 32,
            filetype_magika="dex",
            is_suspicious=True,
        )
        assert r.is_suspicious is True


# ============================================================================
# APKNativeLib
# ============================================================================

class TestAPKNativeLibDataclass:

    def test_creation(self):
        from redb.models.dataclasses import APKNativeLib

        lib = APKNativeLib(
            abi="arm64-v8a",
            filename="libnative.so",
            size=200000,
            sha256="ff" * 32,
        )
        assert lib.abi == "arm64-v8a"
        assert lib.filename == "libnative.so"
        assert lib.is_known_packer is False

    def test_known_packer(self):
        from redb.models.dataclasses import APKNativeLib

        lib = APKNativeLib(
            abi="armeabi-v7a",
            filename="libjiagu.so",
            size=100000,
            sha256="aa" * 32,
            is_known_packer=True,
        )
        assert lib.is_known_packer is True


# ============================================================================
# APKInconsistencyTests
# ============================================================================

class TestAPKInconsistencyTestsDataclass:

    def test_all_defaults_none(self):
        from redb.models.dataclasses import APKInconsistencyTests

        t = APKInconsistencyTests()
        assert t.test_zip_bomb is None
        assert t.test_zip_duplicate_entries is None
        assert t.test_zip_path_traversal is None
        assert t.test_zip_suspicious_timestamps is None
        assert t.test_hidden_dex_files is None
        assert t.test_manifest_component_mismatch is None
        assert t.test_debuggable_release is None
        assert t.test_emulator_detection_strings is None
        assert t.test_debugger_detection is None
        assert t.test_root_detection is None

    def test_all_fields_populated(self):
        from redb.models.dataclasses import APKInconsistencyTests

        t = APKInconsistencyTests(
            test_zip_bomb=True,
            test_zip_duplicate_entries=False,
            test_zip_path_traversal=True,
            test_zip_suspicious_timestamps=False,
            test_hidden_dex_files=True,
            test_manifest_component_mismatch=False,
            test_debuggable_release=True,
            test_emulator_detection_strings=True,
            test_debugger_detection=False,
            test_root_detection=True,
        )
        assert t.test_zip_bomb is True
        assert t.test_debuggable_release is True
        # Count true values
        d = asdict(t)
        true_count = sum(1 for v in d.values() if v is True)
        assert true_count == 6

    def test_field_count(self):
        from redb.models.dataclasses import APKInconsistencyTests

        # Exactly 10 inconsistency tests per PDD specification
        assert len(fields(APKInconsistencyTests)) == 10


# ============================================================================
# Hashes dataclass — APK permhash field
# ============================================================================

class TestHashesAPKField:

    def test_permhash_default_none(self):
        from redb.models.dataclasses import Hashes

        h = Hashes(md5="a", sha1="b", sha256="c", ssdeep_hash="d", tlsh_hash="e")
        assert h.permhash is None

    def test_permhash_populated(self):
        from redb.models.dataclasses import Hashes

        h = Hashes(
            md5="a", sha1="b", sha256="c", ssdeep_hash="d", tlsh_hash="e",
            permhash="abc123" * 10 + "abcd",
        )
        assert h.permhash is not None
        assert len(h.permhash) == 64


# ============================================================================
# Tag enum — APK entries
# ============================================================================

class TestAPKTagEnum:

    def test_all_apk_tags_exist(self):
        from redb.extractors.enum import Tag

        expected_tags = [
            "APK_FEATURES", "APK_MANIFEST", "APK_PERMISSIONS", "APK_SIGNATURE",
            "APK_DEX", "APK_RESOURCES", "APK_NATIVE_LIBS", "APK_INCONSISTENCY_TESTS",
        ]
        for name in expected_tags:
            assert hasattr(Tag, name), f"Tag.{name} missing"

    def test_apk_tag_values(self):
        from redb.extractors.enum import Tag

        assert Tag.APK_FEATURES.value == "apk_features"
        assert Tag.APK_MANIFEST.value == "apk_manifest"
        assert Tag.APK_PERMISSIONS.value == "apk_permissions"
        assert Tag.APK_SIGNATURE.value == "apk_signature"
        assert Tag.APK_DEX.value == "apk_dex"
        assert Tag.APK_RESOURCES.value == "apk_resources"
        assert Tag.APK_NATIVE_LIBS.value == "apk_native_libs"
        assert Tag.APK_INCONSISTENCY_TESTS.value == "apk_inconsistency_tests"