Narayan Prasad

122 papers A* 2A 1B 32C 1Misc 17Journal 49Unranked 20
YearRankTypeTitle / Venue / Authors
2024 conf
ICC Workshops
Narayan Prasad, Yu-Chin Ou, Tao Luo, M. Ali Tassoudji, Junyi Li, Peter Gaal
2024 J jnl
IEEE Wirel. Commun. Lett.
Narayan Prasad, Yavuz Yapici, Tao Luo, Junyi Li, Peter Gaal
2023 B conf
PIMRC
Narayan Prasad, Yavuz Yapici, Tao Luo, Junyi Li, Peter Gaal
2022 J jnl
Digit. Commun. Networks
Miguel Dajer, Zhengxiang Ma, Leonard Piazzi, Narayan Prasad, Xiao-Feng Qi, Baoling Sheen, Jin Yang, Guosen Yue
2021 Misc conf
COMSNETS
Narayan Prasad, Md Moin Uddin Chowdhury, Xiao-Feng Qi
2021 conf
VTC Fall
Narayan Prasad, Md Moin Uddin Chowdhury, Xiao-Feng Qi
2021 conf
ICC
Divyakumar Badheka, Narayan Prasad, Zhengxiang Ma, Leonard Piazzi, Xiao-Feng Qi
2020 Misc conf
COMSNETS
Narayan Prasad, Xiao-Feng Qi
2020 J jnl
IEEE Trans. Commun.
Jinseok Choi, Junmo Sung, Narayan Prasad, Xiao-Feng Qi, Brian L. Evans, Alan Gatherer
2020 J jnl
IEEE Access
Arkady Molev-Shteiman, Xiao-Feng Qi, Laurence Mailaender, Narayan Prasad, Bertrand M. Hochwald
2020 A* conf
INFOCOM
Narayan Prasad, Xiao-Feng Qi, Arkady Molev-Shteiman
2020 J jnl
CoRR
Miguel Dajer, Zhengxiang Ma, Leonard Piazzi, Narayan Prasad, Xiao-Feng Qi, Baoling Sheen, Jin Yang, Guosen Yue
2019 J jnl
CoRR
Jinseok Choi, Junmo Sung, Narayan Prasad, Xiao-Feng Qi, Brian L. Evans, Alan Gatherer
2019 B conf
WiOpt
Narayan Prasad, Qian Zhang, Xiao-Feng Qi
2019 J jnl
CoRR
Arkady Molev-Shteiman, Xiao-Feng Qi, Laurence Mailaender, Narayan Prasad, Bertrand M. Hochwald
2019 Misc conf
ICNC
Narayan Prasad, Xiao-Feng Qi, Alan Gatherer
2018 B conf
WiOpt
Narayan Prasad, Xiao-Feng Qi
2018 J jnl
CoRR
Narayan Prasad, Xiao-Feng Qi, Alan Gatherer
2017 J jnl
CoRR
Narayan Prasad, Sampath Rangarajan
2017 B conf
WiOpt
Narayan Prasad, Sampath Rangarajan
2017 conf
ICC
Yasaman Ghasempour, Narayan Prasad, Mohammad Ali Amir Khojastepour, Sampath Rangarajan
2017 Misc conf
ACSSC
Yasaman Ghasempour, Narayan Prasad, Mohammad Ali Amir Khojastepour, Sampath Rangarajan
2017 conf
WONS
Yasaman Ghasempour, Narayan Prasad, Mohammad Ali Amir Khojastepour, Sampath Rangarajan
2017 J jnl
IEEE Trans. Green Commun. Netw.
Hajar Mahdavi-Doost, Narayan Prasad, Sampath Rangarajan
2016 Misc conf
ACSSC
Rob Arnott, Kengo Oketani, Narayan Prasad, Sampath Rangarajan, Patricia Wells
2016 Misc conf
COMSNETS
Hajar Mahdavi-Doost, Narayan Prasad, Sampath Rangarajan
2016 B conf
ISIT
Hajar Mahdavi-Doost, Narayan Prasad, Sampath Rangarajan
2015 Misc conf
ACSSC
Narayan Prasad, Vaibhav Singh, Sampath Rangarajan
2015 J jnl
CoRR
Vaibhav Singh, Narayan Prasad, Mustafa Y. Arslan, Sampath Rangarajan
2015 B conf
WiOpt
Vaibhav Singh, Narayan Prasad, Mustafa Y. Arslan, Sampath Rangarajan
2015 B conf
WiOpt
Rob Arnott, A. Gurung, C. Liang, Y. Maruta, D. Pham, Narayan Prasad, Sampath Rangarajan, Patricia Wells
2014 Misc conf
COMSNETS
Narayan Prasad, Mustafa Y. Arslan, Sampath Rangarajan
2014 B conf
ISIT
Narayan Prasad, Mustafa Y. Arslan, Sampath Rangarajan
2014 conf
OFC
Neda Cvijetic, Ezra Ip, Narayan Prasad, Ming-Jun Li, Ting Wang
2014 J jnl
IEEE Trans. Commun.
Narayan Prasad, Mustafa Y. Arslan, Sampath Rangarajan
2014 conf
ICC
Narayan Prasad, Mustafa Y. Arslan, Sampath Rangarajan
2014 J jnl
IEEE Trans. Mob. Comput.
Narayan Prasad, Honghai Zhang, Hao Zhu, Sampath Rangarajan
2014 conf
ICC
Yi Xu, Guosen Yue, Narayan Prasad, Sampath Rangarajan, Shiwen Mao
2013 B conf
GLOBECOM
Narayan Prasad, Guosen Yue, Sampath Rangarajan
2013 J jnl
CoRR
Wenzhuo Ouyang, Narayan Prasad, Sampath Rangarajan
2013 B conf
WiOpt
Wenzhuo Ouyang, Narayan Prasad, Sampath Rangarajan
2013 Misc conf
ACSSC
Guosen Yue, Narayan Prasad, Sampath Rangarajan
2013 J jnl
IEEE Trans. Wirel. Commun.
Narayan Prasad, Honghai Zhang, Hao Zhu, Sampath Rangarajan
2013 Misc conf
ACSSC
Narayan Prasad, Honghai Zhang, Hao Zhu, Sampath Rangarajan
2013 Misc conf
CISS
Guosen Yue, Narayan Prasad, Meilong Jiang, Mohammad Ali Khojastepour, Sampath Rangarajan
2012 conf
ACSCC
Narayan Prasad, Ali Tajer, Xiaodong Wang
2012 conf
ICC
Guosen Yue, Narayan Prasad, Sampath Rangarajan
2012 conf
VTC Spring
Meilong Jiang, Guosen Yue, Narayan Prasad, Sampath Rangarajan
2012 A* conf
INFOCOM
Honghai Zhang, Narayan Prasad, Sampath Rangarajan
2012 J jnl
CoRR
Narayan Prasad, Honghai Zhang, Hao Zhu, Sampath Rangarajan
2012 B conf
WiOpt
Narayan Prasad, Honghai Zhang, Hao Zhu, Sampath Rangarajan
2012 J jnl
IEEE Trans. Signal Process.
Hao Zhu, Narayan Prasad, Sampath Rangarajan
2012 conf
ICC
Hao Zhu, Narayan Prasad, Sampath Rangarajan
2012 B conf
GLOBECOM
Hao Zhu, Narayan Prasad, Sampath Rangarajan
2012 conf
ICC
Honghai Zhang, Narayan Prasad, Sampath Rangarajan, Sherif Mekhail, Said Said, Rob Arnott
2011 J jnl
IEEE Trans. Commun.
Kai Yang, Narayan Prasad, Xiaodong Wang
2011 J jnl
EURASIP J. Wirel. Commun. Netw.
Ke Dong, Narayan Prasad, Xiaodong Wang, Shihua Zhu
2011 conf
ICC
Meilong Jiang, Narayan Prasad, Guosen Yue, Sampath Rangarajan
2011 J jnl
IET Commun.
Narayan Prasad, Xiaodong Wang
2011 B conf
GLOBECOM
Narayan Prasad, Guosen Yue, Meilong Jiang, Mohammad Ali Khojastepour, Sampath Rangarajan
2011 B conf
PIMRC
Guosen Yue, Narayan Prasad, Meilong Jiang, Mohammad Ali Khojastepour, Sampath Rangarajan
2011 Misc conf
CISS
Meilong Jiang, Guosen Yue, Narayan Prasad, Sampath Rangarajan
2011 J jnl
CoRR
Narayan Prasad, Honghai Zhang, Hao Zhu, Sampath Rangarajan
2011 conf
ICC
Jubin Jose, Narayan Prasad, Mohammad Ali Khojastepour, Sampath Rangarajan
2011 J jnl
IEEE J. Sel. Top. Signal Process.
Narayan Prasad, Khalid Kalbat, Xiaodong Wang
2011 J jnl
CoRR
Hao Zhu, Narayan Prasad, Sampath Rangarajan
2011 B conf
GLOBECOM
Narayan Prasad, Honghai Zhang, Meilong Jiang, Guosen Yue, Sampath Rangarajan
2011 conf
ACSCC
Narayan Prasad, Honghai Zhang, Luca Venturino, Jubin Jose, Mohammad Ali Khojastepour, Sampath Rangarajan
2011 J jnl
IEEE Trans. Signal Process.
Ali Tajer, Narayan Prasad, Xiaodong Wang
2011 J jnl
IEEE J. Sel. Areas Commun.
Honghai Zhang, Luca Venturino, Narayan Prasad, Peilong Li, Sampath Rangarajan, Xiaodong Wang
2010 J jnl
IEEE Trans. Signal Process.
Ali Tajer, Narayan Prasad, Xiaodong Wang
2010 J jnl
IEEE Trans. Wirel. Commun.
Luca Venturino, Narayan Prasad, Xiaodong Wang
2010 J jnl
IEEE Trans. Inf. Theory
Narayan Prasad, Luca Venturino, Xiaodong Wang
2010 B conf
ISIT
Ali Tajer, Narayan Prasad, Xiaodong Wang
2010 J jnl
IEEE Trans. Wirel. Commun.
Narayan Prasad, Mahesh K. Varanasi
2010 J jnl
EURASIP J. Wirel. Commun. Netw.
Young-June Choi, Narayan Prasad, Sampath Rangarajan
2010 B conf
GLOBECOM
Narayan Prasad, Khalid Kalbat, Xiaodong Wang
2010 J jnl
CoRR
Ali Tajer, Narayan Prasad, Xiaodong Wang
2010 conf
ICC
Ali Tajer, Narayan Prasad, Xiaodong Wang
2010 B conf
ISIT
Ali Tajer, Narayan Prasad, Xiaodong Wang
2009 J jnl
IEEE Trans. Signal Process.
Kai Yang, Narayan Prasad, Xiaodong Wang
2009 J jnl
CoRR
Ali Tajer, Narayan Prasad, Xiaodong Wang
2009 J jnl
IEEE Trans. Veh. Technol.
Luca Venturino, Narayan Prasad, Xiaodong Wang
2009 Misc conf
CISS
Meilong Jiang, Narayan Prasad, Xiaodong Wang
2009 conf
ICC
Ali Tajer, Narayan Prasad, Xiaodong Wang
2009 B conf
GLOBECOM
Narayan Prasad, Meilong Jiang, Xiaodong Wang
2009 J jnl
IEEE Trans. Wirel. Commun.
Narayan Prasad, Shuangquan Wang, Xiaodong Wang
2009 J jnl
IEEE Trans. Signal Process.
Narayan Prasad, Kai Li, Xiaodong Wang
2009 J jnl
IEICE Trans. Commun.
Meilong Jiang, Narayan Prasad, Yan Xin, Guosen Yue, Amir Khojastepour, Le Liu, Takamichi Inoue, Kenji Koyanagi, Yoshikazu Kakura
2009 C conf
QSHINE
Young-June Choi, Narayan Prasad, Sampath Rangarajan
2009 J jnl
IEEE Trans. Inf. Theory
Narayan Prasad, Xiaodong Wang
2008 Misc conf
CISS
Luca Venturino, Narayan Prasad, Xiaodong Wang
2008 J jnl
IEEE Trans. Inf. Theory
Narayan Prasad, Mahesh K. Varanasi, Luca Venturino, Xiaodong Wang
2008 B conf
GLOBECOM
Kai Yang, Narayan Prasad, Xiaodong Wang
2008 J jnl
IEEE Trans. Wirel. Commun.
Narayan Prasad, Mahesh K. Varanasi
2008 J jnl
IEEE Trans. Inf. Theory
Narayan Prasad, Mahesh K. Varanasi
2008 conf
ACSCC
Luca Venturino, Narayan Prasad, Xiaodong Wang
2008 J jnl
IEEE Trans. Inf. Theory
Narayan Prasad, Inaki Berenguer, Xiaodong Wang
2008 J jnl
IEEE J. Sel. Areas Commun.
Narayan Prasad, Xiaodong Wang
2008 J jnl
IEEE Trans. Inf. Theory
Narayan Prasad, Guosen Yue, Xiaodong Wang, Mahesh K. Varanasi
2008 B conf
GLOBECOM
Narayan Prasad, Xiaodong Wang
2008 B conf
ISIT
Narayan Prasad, Xiaodong Wang
2008 J jnl
IEEE J. Sel. Areas Commun.
Mohammad Ali Khojastepour, Narayan Prasad, Shuangquan Wang, Xiaodong Wang, Mohammad Madihian
2008 Misc conf
CISS
Mohammad Ali Khojastepour, Narayan Prasad, Shuangquan Wang, Xiaodong Wang, Mohammad Madihian
2007 J jnl
IEEE Trans. Signal Process.
Pradeep Aggarwal, Narayan Prasad, Xiaodong Wang
2007 B conf
ISIT
Narayan Prasad, Luca Venturino, Xiaodong Wang, Mohammad Madihian
2007 J jnl
J. Sel. Topics Signal Processing
Luca Venturino, Narayan Prasad, Xiaodong Wang, Mohammad Madihian
2007 B conf
GLOBECOM
Narayan Prasad, Luca Venturino, Xiaodong Wang, Mohammad Madihian
2007 conf
ICC
Luca Venturino, Narayan Prasad, Xiaodong Wang, Mohammad Madihian
2006 Misc conf
CISS
Pradeep Aggarwal, Narayan Prasad, Xiaodong Wang
2006 B conf
ISIT
Narayan Prasad, Inaki Berenguer, Xiaodong Wang, Mohammad Madihian
2006 B conf
GLOBECOM
Narayan Prasad, Mahesh K. Varanasi
2006 Misc conf
CISS
Narayan Prasad, Guosen Yue, Mohammad Amir Khojastepour, Xiaodong Wang, Mohammad Madihian
2006 J jnl
IEEE Trans. Inf. Theory
Narayan Prasad, Mahesh K. Varanasi
2006 B conf
ISIT
Narayan Prasad, Mahesh K. Varanasi
2005 B conf
GLOBECOM
Inaki Berenguer, Xiaodong Wang, Narayan Prasad, Jibing Wang, Mohammad Madihian
2005 B conf
ISIT
Narayan Prasad, Mahesh K. Varanasi
2004 J jnl
IEEE Trans. Inf. Theory
Narayan Prasad, Mahesh K. Varanasi
2004 B conf
ISIT
Narayan Prasad, Mahesh K. Varanasi
2004 B conf
ITW
Narayan Prasad, Mahesh K. Varanasi
2003 B conf
GLOBECOM
Narayan Prasad, Mahesh K. Varanasi
2000 A conf
ITC
Jais Abraham, Narayan Prasad, Srinivasa Chakravarthy B. S., Ameet Bagwe, Rubin A. Parekhji
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"