Kari Stadius

90 papers C 20Journal 24Unranked 46
YearRankTypeTitle / Venue / Authors
2025 J jnl
IEEE Access
Saeed Naghavi, Kari Stadius, Anu Lehtovuori, Ville Viikari, Jussi Ryynänen
2024 J jnl
IEEE Trans. Very Large Scale Integr. Syst.
Kimi Jokiniemi, Kaisa Ryynänen, Joni Vähä, Elmo Kankkunen, Kari Stadius, Jussi Ryynänen
2024 C conf
ISCAS
Santeri Porrasmaa, Okko Järvinen, Ilia Kempi, Kari Stadius, Marko Kosunen, Jussi Ryynänen
2024 C conf
ISCAS
Kimi Jokiniemi, Kaisa Ryynänen, Joni Vähä, Kari Stadius, Jussi Ryynänen
2024 J jnl
IEEE Trans. Very Large Scale Integr. Syst.
Agnimesh Ghosh, Andrei Spelman, Tze Hin Cheung, Dhanashree Boopathy, Kari Stadius, Manil Dev Gomony, Mikko Valkama, Jussi Ryynänen, Marko Kosunen, Vishnu Unnikrishnan
2024 conf
NewCAS
Tze Hin Cheung, Agnimesh Ghosh, Andrei Spelman, Dhanashree Boopathy, Vishnu Unnikrishnan, Lauri Anttila, Mikko Valkama, Marko Kosunen, Kari Stadius, Jussi Ryynänen
2023 conf
NorCAS
Kimi Jokiniemi, Kaisa Ryynänen, Joni Vähä, Elmo Kankkunen, Kari Stadius, Jussi Ryynänen
2023 conf
NorCAS
Kaisa Ryynänen, Veeti Lahtinen, Santeri Porrasmaa, Kari Stadius, Marko Kosunen, Jussi Ryynänen
2023 conf
NEWCAS
Dhanashree Boopathy, Tze Hin Cheung, Andrei Spelman, Agnimesh Ghosh, Vesa Lampu, Lauri Anttila, Kari Stadius, Marko Kosunen, Jussi Ryynänen, Vishnu Unnikrishnan
2022 conf
ICECS 2022
Kalle Spoof, Miikka Tenhunen, Vishnu Unnikrishnan, Kari Stadius, Marko Kosunen, Jussi Ryynänen
2022 C conf
ISCAS
Ilia Kempi, Okko Järvinen, Marko Kosunen, Vishnu Unnikrishnan, Kari Stadius, Jussi Ryynänen
2022 conf
NEWCAS
Miikka Tenhunen, Kalle Spoof, Vishnu Unnikrishnan, Kari Stadius, Marko Kosunen, Jussi Ryynänen
2022 conf
ICECS 2022
Ali Raza Saleem, Saeed Naghavi, Mahwish Zahra, Kari Stadius, Marko Kosunen, Lauri Anttila, Mikko Valkama, Jussi Ryynänen
2022 C conf
ISCAS
Okko Järvinen, Vishnu Unnikrishnan, Ilia Kempi, Kari Stadius, Marko Kosunen, Jussi Ryynänen
2022 J jnl
IEEE Trans. Circuits Syst. II Express Briefs
Okko Järvinen, Vishnu Unnikrishnan, Ilia Kempi, Santeri Porrasmaa, Kari Stadius, Marko Kosunen, Jussi Ryynänen
2022 conf
NorCAS
Agnimesh Ghosh, Andrei Spelman, Tze Hin Cheung, Dhanashree Boopathy, Vishnu Unnikrishnan, Vesa Lampu, Guixian Xu, Lauri Anttila, Kari Stadius, Marko Kosunen, Jussi Ryynänen
2022 J jnl
IEEE Access
Kalle Spoof, Miikka Tenhunen, Vishnu Unnikrishnan, Kari Stadius, Marko Kosunen, Jussi Ryynänen
2021 J jnl
IEEE Access
Okko Järvinen, Vishnu Unnikrishnan, Waqas Siddiqui, Teuvo Korhonen, Kimmo Koli, Kari Stadius, Marko Kosunen, Jussi Ryynänen
2021 conf
ESSCIRC
Rehman Akbar, Rana Azhar Shaheen, Timo Rahkonen, Tze Hin Cheung, Kari Stadius, Aarno Pärssinen
2021 C conf
ISCAS
Tze Hin Cheung, Jussi Ryynänen, Aarno Pärssinen, Kari Stadius
2021 C conf
ISCAS
Kaisa Ryynänen, Kari Stadius, Andreas Hammer, Mikko Varonen, Henrik Forsten, Tero Kiuru, Ville Viikari, Jussi Ryynänen
2021 conf
MWSCAS
Ali Raza Saleem, Kari Stadius, Jari-Matti Hannula, Anu Lehtovuori, Marko Kosunen, Ville Viikari, Jussi Ryynänen
2021 J jnl
IEEE Trans. Very Large Scale Integr. Syst.
Vishnu Unnikrishnan, Okko Järvinen, Waqas Siddiqui, Kari Stadius, Marko Kosunen, Jussi Ryynänen
2021 J jnl
IEEE Wirel. Commun. Lett.
Guixian Xu, Vesa Lampu, Marko Kosunen, Kari Stadius, Jussi Ryynänen, Mikko Valkama, Lauri Anttila
2020 C conf
ISCAS
Tze Hin Cheung, Mikko Martelius, Yury Antonov, Rehman Akbar, Jussi Ryynänen, Aarno Pärssinen, Kari Stadius
2020 conf
ICECS
Ali Raza Saleem, Kari Stadius, Marko Kosunen, Lauri Anttila, Mikko Valkama, Jussi Ryynänen
2020 conf
6G SUMMIT
Henri Hurskainen, Rehman Akbar, Kari Stadius, Aarno Pärssinen
2020 C conf
ISCAS
Vishnu Unnikrishnan, Okko Järvinen, Kari Stadius, Marko Kosunen, Jussi Ryynänen
2020 C conf
ISCAS
Andreas Hammer, Ilia Kempi, Olaitan Olabode, Kari Stadius, Jussi Ryynänen, Marko Kosunen
2020 J jnl
IEEE Trans. Circuits Syst.
Kalle Spoof, Vishnu Unnikrishnan, Mahwish Zahra, Kari Stadius, Marko Kosunen, Jussi Ryynänen
2019 J jnl
IEEE J. Solid State Circuits
Jerry Lemberg, Mikko Martelius, Enrico Roverato, Yury Antonov, Tero Nieminen, Kari Stadius, Lauri Anttila, Mikko Valkama, Marko Kosunen, Jussi Ryynänen
2019 conf
ESSCIRC
Yury Antonov, Mikko Valkama, Marko Kosunen, Jussi Ryynänen, Mahwish Zahra, Kari Stadius, Zahra Khonsari, Ilia Kempi, Toni Miilunpalo, Juha Inkinen, Vishnu Unnikrishnan, Lauri Anttila
2019 conf
ESSCIRC
Rehman Akbar, Eric A. M. Klumperink, Nuutti Tervo, Muhammad Yasir Javed, Kari Stadius, Timo Rahkonen, Aarno Pärssinen
2019 J jnl
Int. J. Circuit Theory Appl.
Faizan Ul Haq, Mikko Englund, Kim B. Östman, Kari Stadius, Marko Kosunen, Kimmo Koli, Jussi Ryynänen
2018 conf
NGCAS
Yury Antonov, Markus Törmänen, Jussi Ryynänen, Aarno Pärssinen, Kari Stadius
2018 conf
NEWCAS
Yury Antonov, Mahwish Zahra, Kari Stadius, Zahra Khonsari, Nouman Ahmed, Ilia Kempi, Juha Inkinen, Vishnu Unnikrishnan, Jussi Ryynänen
2018 J jnl
IEEE Trans. Circuits Syst. II Express Briefs
Enrico Roverato, Marko Kosunen, Jerry Lemberg, Mikko Martelius, Kari Stadius, Lauri Anttila, Mikko Valkama, Jussi Ryynänen
2018 J jnl
IEEE Trans. Circuits Syst. I Regul. Pap.
Mikko Englund, Faizan Ul Haq, Kari Stadius, Marko Kosunen, Kim B. Ostman, Kimmo Koli, Jussi Ryynänen
2018 J jnl
Int. J. Circuit Theory Appl.
Faizan Ul Haq, Kim B. Ostman, Mikko Englund, Kari Stadius, Marko Kosunen, Kimmo Koli, Jussi Ryynänen
2018 C conf
ISCAS
Jerry Lemberg, Marko Kosunen, Tero Nieminen, Enrico Roverato, Mikko Martelius, Kari Stadius, Jussi Ryynänen, Lauri Anttila, Mikko Valkama
2018 C conf
ISCAS
Faizan Ul Haq, Mikko Englund, Yury Antonov, Kari Stadius, Marko Kosunen, Jussi Ryynänen, Kim B. Östman, Kimmo Koli
2018 C conf
ISCAS
Mikko Martelius, Kari Stadius, Jerry Lemberg, Enrico Roverato, Marko Kosunen, Jussi Ryynänen, Lauri Anttila, Mikko Valkama
2018 J jnl
IEEE Trans. Circuits Syst. I Regul. Pap.
Jerry Lemberg, Mikko Martelius, Marko Kosunen, Enrico Roverato, Kari Stadius, Lauri Anttila, Mikko Valkama, Jussi Ryynänen
2017 conf
ISSCC
Marko Kosunen, Jerry Lemberg, Mikko Martelius, Enrico Roverato, Tero Nieminen, Mikko Englund, Kari Stadius, Lauri Anttila, Jorma Pallonen, Mikko Valkama, Jussi Ryynänen
2017 C conf
ISCAS
Yury Antonov, Kari Stadius, Jussi Ryynänen
2017 C conf
ISCAS
Faizan Ul Haq, Mikko Englund, Kari Stadius, Marko Kosunen, Jussi Ryynänen, Kimmo Koli, Kim B. Ostman
2017 conf
ECCTD
Yury Antonov, Kari Stadius, Marko Kosunen, Jussi Ryynänen
2016 conf
NORCAS
Faizan Ul Haq, Mikko Englund, Kari Stadius, Marko Kosunen, Jussi Ryynänen, Kimmo Koli, Kim B. Ostman
2016 C conf
ISCAS
Mikko Martelius, Kari Stadius, Jerry Lemberg, Tero Nieminen, Enrico Roverato, Marko Kosunen, Jussi Ryynänen, Lauri Anttila, Mikko Valkama
2016 J jnl
IEEE Trans. Circuits Syst. I Regul. Pap.
Jerry Lemberg, Marko Kosunen, Enrico Roverato, Mikko Martelius, Kari Stadius, Lauri Anttila, Mikko Valkama, Jussi Ryynänen
2016 conf
GlobalSIP
Jaakko Marttila, Markus Allén, Marko Kosunen, Kari Stadius, Jussi Ryynänen, Mikko Valkama
2015 conf
ESSCIRC
Tero Tikka, Kari Stadius, Jussi Ryynänen, Mikko Kaltiokallio
2015 J jnl
IEEE J. Solid State Circuits
Mikko Englund, Kim B. Ostman, Olli Viitala, Mikko Kaltiokallio, Kari Stadius, Kimmo Koli, Jussi Ryynänen
2015 conf
ECCTD
Yury Antonov, Tero Tikka, Kari Stadius, Jussi Ryynänen
2015 J jnl
IEEE Trans. Circuits Syst. I Regul. Pap.
Kim B. Ostman, Mikko Englund, Olli Viitala, Mikko Kaltiokallio, Kari Stadius, Kimmo Koli, Jussi Ryynänen
2015 J jnl
IEEE J. Emerg. Sel. Topics Circuits Syst.
Kim B. Ostman, Mikko Englund, Olli Viitala, Kari Stadius, Kimmo Koli, Jussi Ryynänen
2014 conf
ISSCC
Mikko Englund, Kim B. Östman, Olli Viitala, Mikko Kaltiokallio, Kari Stadius, Kimmo Koli, Jussi Ryynänen
2014 C conf
ISCAS
Tero Tikka, Kari Stadius, Jussi Ryynänen, Martti Voutilainen
2014 conf
ESSCIRC
Mikko Englund, Kim B. Ostman, Olli Viitala, Mikko Kaltiokallio, Kari Stadius, Jussi Ryynänen, Kimmo Koli
2014 J jnl
IEEE Trans. Circuits Syst. II Express Briefs
Kim B. Ostman, Mikko Englund, Olli Viitala, Kari Stadius, Kimmo Koli, Jussi Ryynänen
2014 J jnl
IEEE Trans. Circuits Syst. I Regul. Pap.
Enrico Roverato, Marko Kosunen, Jerry Lemberg, Kari Stadius, Jussi Ryynänen
2013 conf
ESSCIRC
Tapio Rapinoja, Kari Stadius, Jussi Ryynänen
2013 conf
ECCTD
Enrico Roverato, Marko Kosunen, Jerry Lemberg, Tero Nieminen, Kari Stadius, Jussi Ryynänen, Petri Eloranta, Risto Kaunisto, Aarno Pärssinen
2013 conf
NEWCAS
Enrico Roverato, Marko Kosunen, Jerry Lemberg, Kari Stadius, Jussi Ryynänen, Petri Eloranta, Risto Kaunisto, Aarno Pärssinen
2013 conf
ECCTD
Kim B. Ostman, Mikko Englund, Olli Viitala, Kari Stadius, Jussi Ryynänen, Kimmo Koli
2012 J jnl
IEEE Trans. Circuits Syst. I Regul. Pap.
Liangge Xu, Kari Stadius, Jussi Ryynänen
2011 C conf
ISCAS
Kari Stadius, Mikko Kaltiokallio, Jussi Ollikainen, Tuomas Parnanen, Ville Saari, Jussi Ryynänen
2011 conf
NORCHIP
Johanna Anteroinen, Wonjae Kim, Kari Stadius, Juha Riikonen, Harri Lipsanen, Jussi Ryynänen
2011 C conf
ISCAS
Tapio Rapinoja, Liangge Xu, Kari Stadius, Jussi Ryynänen
2010 J jnl
IEEE J. Solid State Circuits
Liangge Xu, Saska Lindfors, Kari Stadius, Jussi Ryynänen
2010 C conf
ISCAS
Liangge Xu, Kari Stadius, Jussi Ryynänen
2009 conf
CICC
Liangge Xu, Saska Lindfors, Kari Stadius, Jussi Ryynänen
2009 conf
ESSCIRC
Liangge Xu, Kari Stadius, Jussi Ryynänen
2009 conf
ECCTD
Liangge Xu, Kari Stadius, Tapio Rapinoja, Jussi Ryynänen
2009 conf
ICECS
Tapio Rapinoja, Kari Stadius, Jussi Ryynänen
2008 conf
ESSCIRC
Mikko Kaltiokallio, Ville Saari, Tapio Rapinoja, Kari Stadius, Jussi Ryynänen, Saska Lindfors, Kari Halonen
2008 J jnl
IEEE Trans. Circuits Syst. I Regul. Pap.
Jouni Kaukovuori, Kari Stadius, Jussi Ryynänen, Kari Halonen
2005 conf
ISCAS (3)
Kari Stadius, Kari Halonen
2004 conf
ISCAS (4)
Arto Malinen, Kari Stadius, Kari Halonen
2003 conf
ISCAS (2)
Kari Stadius, Arto Malinen, Petteri Paatsila, Kari Halonen
2003 conf
ESSCIRC
Kari Stadius, Arto Malinen, Petri Järviö, Kari Halonen, Petteri Paatsila
2001 conf
ICECS
Kari Stadius, Petri Järviö, Kari Halonen
2001 conf
ISCAS (4)
Kari Stadius, Petri Järviö, Petteri Paatsila, Kari Halonen
2001 conf
ISCAS (1)
Kari Stadius, Risto Kaunisto, Veikko Porra
1999 conf
ICECS
Rami Ahola, Kari Stadius, Kari Halonen
1999 conf
ISCAS (2)
Rami Ahola, Kari Stadius, Kari Halonen
1999 conf
ICECS
Kari Stadius, Risto Kaunisto, Veikko Porra
1998 conf
ICECS
Risto Kaunisto, Kari Stadius, Veikko Porra
1998 conf
ICECS
Kari Stadius, Risto Kaunisto, Veikko Porra
1994 C conf
ISCAS
Risto Kaunisto, Petteri Alinikula, Kari Stadius
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"