Karthik Sankaranarayanan

96 papers A* 11A 6B 5C 3Misc 2Journal 44Unranked 25
YearRankTypeTitle / Venue / Authors
2023 conf
IEEM
Rajinder Khurmi, Karthik Sankaranarayanan, Glenn Harvel
2022 conf
NAACL-HLT (Industry Papers)
Yannis Katsis, Saneem A. Chemmengath, Vishwajeet Kumar, Samarth Bharadwaj, Mustafa Canim, Michael R. Glass, Alfio Gliozzo, Feifei Pan, Jaydeep Sen, Karthik Sankaranarayanan, Soumen Chakrabarti
2021 J jnl
CoRR
Yannis Katsis, Saneem A. Chemmengath, Vishwajeet Kumar, Samarth Bharadwaj, Mustafa Canim, Michael R. Glass, Alfio Gliozzo, Feifei Pan, Jaydeep Sen, Karthik Sankaranarayanan, Soumen Chakrabarti
2021 conf
ICCVW
Saneem A. Chemmengath, Soumava Paul, Samarth Bharadwaj, Suranjana Samanta, Karthik Sankaranarayanan
2021 conf
COMAD/CODS
Ashish R. Mittal, Diptikalyan Saha, Parag Jain, Jaydeep Sen, Manasa Jammi, Karthik Sankaranarayanan
2021 conf
IEEM
Rajinder Khurmi, Karthik Sankaranarayanan, Glenn Harvel
2021 J jnl
J. Chem. Inf. Model.
Esther Heid, Samuel Goldman, Karthik Sankaranarayanan, Connor W. Coley, Christoph Flamm, William H. Green Jr.
2021 A conf
Interspeech
Anuj Diwan, Rakesh Vaideeswaran, Sanket Shah, Ankita Singh, Srinivasa Raghavan K. M., Shreya Khare, Vinit Unni, Saurabh Vyas, Akash Rajpuria, Chiranjeevi Yarra, Ashish R. Mittal, Prasanta Kumar Ghosh, Preethi Jyothi, Kalika Bali, Vivek Seshadri, Sunayana Sitaram, Samarth Bharadwaj, Jai Nanavati, Raoul Nanavati, Karthik Sankaranarayanan
2021 J jnl
CoRR
Anuj Diwan, Rakesh Vaideeswaran, Sanket Shah, Ankita Singh, Srinivasa Raghavan K. M., Shreya Khare, Vinit Unni, Saurabh Vyas, Akash Rajpuria, Chiranjeevi Yarra, Ashish R. Mittal, Prasanta Kumar Ghosh, Preethi Jyothi, Kalika Bali, Vivek Seshadri, Sunayana Sitaram, Samarth Bharadwaj, Jai Nanavati, Raoul Nanavati, Karthik Sankaranarayanan, Tejaswi Seeram, Basil Abraham
2021 conf
COMAD/CODS
Jaydeep Sen, Diptikalyan Saha, Ashish R. Mittal, Karthik Sankaranarayanan
2021 J jnl
CoRR
Ashish R. Mittal, Samarth Bharadwaj, Shreya Khare, Saneem A. Chemmengath, Karthik Sankaranarayanan, Brian Kingsbury
2021 conf
EMNLP (1)
Tejas I. Dhamecha, V. Rudra Murthy, Samarth Bharadwaj, Karthik Sankaranarayanan, Pushpak Bhattacharyya
2021 J jnl
CoRR
Tejas Indulal Dhamecha, V. Rudra Murthy, Samarth Bharadwaj, Karthik Sankaranarayanan, Pushpak Bhattacharyya
2021 conf
EMNLP (1)
Saneem A. Chemmengath, Vishwajeet Kumar, Samarth Bharadwaj, Jaydeep Sen, Mustafa Canim, Soumen Chakrabarti, Alfio Gliozzo, Karthik Sankaranarayanan
2021 J jnl
CoRR
Saneem Ahmed Chemmengath, Vishwajeet Kumar, Samarth Bharadwaj, Jaydeep Sen, Mustafa Canim, Soumen Chakrabarti, Alfio Gliozzo, Karthik Sankaranarayanan
2020 J jnl
J. Database Manag.
Brandon Laughlin, Karthik Sankaranarayanan, Khalil El-Khatib
2020 J jnl
Proc. VLDB Endow.
Jaydeep Sen, Chuan Lei, Abdul Quamar, Fatma Özcan, Vasilis Efthymiou, Ayushi Dalmia, Greg Stager, Ashish R. Mittal, Diptikalyan Saha, Karthik Sankaranarayanan
2020 J jnl
CoRR
Saneem Ahmed Chemmengath, Samarth Bharadwaj, Soumava Paul, Suranjana Samanta, Karthik Sankaranarayanan
2020 J jnl
CoRR
Karthik Sankaranarayanan, Chit-Kwan Lin, Gautham N. Chinya
2020 A conf
INTERSPEECH
Ashish R. Mittal, Samarth Bharadwaj, Shreya Khare, Saneem A. Chemmengath, Karthik Sankaranarayanan, Brian Kingsbury
2020 B conf
COLING
Jaydeep Sen, Tanaya Babtiwale, Kanishk Saxena, Yash Butala, Sumit Bhatia, Karthik Sankaranarayanan
2020 J jnl
CoRR
Abhijit Mishra, Md. Faisal Mahbub Chowdhury, Sagar Manohar, Dan Gutfreund, Karthik Sankaranarayanan
2019 conf
EMNLP/IJCNLP (1)
Abhijit Mishra, Tarun Tater, Karthik Sankaranarayanan
2019 C conf
VizSEC
Brandon Laughlin, Christopher Collins, Karthik Sankaranarayanan, Khalil El-Khatib
2019 J jnl
CoRR
Brandon Laughlin, Christopher Collins, Karthik Sankaranarayanan, Khalil El-Khatib
2019 J jnl
Trans. Assoc. Comput. Linguistics
Amrita Saha, Ghulam Ahmed Ansari, Abhishek Laddha, Karthik Sankaranarayanan, Soumen Chakrabarti
2019 conf
SIGMOD Conference
Jaydeep Sen, Fatma Ozcan, Abdul Quamar, Greg Stager, Ashish R. Mittal, Manasa Jammi, Chuan Lei, Diptikalyan Saha, Karthik Sankaranarayanan
2019 A* conf
IJCAI
Ghulam Ahmed Ansari, Amrita Saha, Vishwajeet Kumar, Mohan Bhambhani, Karthik Sankaranarayanan, Soumen Chakrabarti
2019 A* conf
ISCA
Stephen J. Tarsa, Rangeen Basu Roy Chowdhury, Julien Sebot, Gautham N. Chinya, Jayesh Gaur, Karthik Sankaranarayanan, Chit-Kwan Lin, Robert Chappell, Ronak Singhal, Hong Wang
2019 J jnl
Comput. Linguistics
Anirban Laha, Parag Jain, Abhijit Mishra, Karthik Sankaranarayanan
2019 conf
ACL (4)
Abhijit Mishra, Anirban Laha, Karthik Sankaranarayanan, Parag Jain, Saravanan Krishnan
2019 conf
ICCSE
Ralph Laite, Miguel Lozano Gonzalez, Karthik Sankaranarayanan
2019 conf
ACL (1)
Priyanka Agrawal, Ayushi Dalmia, Parag Jain, Abhishek Bansal, Ashish R. Mittal, Karthik Sankaranarayanan
2019 J jnl
CoRR
Priyanka Agrawal, Parag Jain, Ayushi Dalmia, Abhishek Bansal, Ashish R. Mittal, Karthik Sankaranarayanan
2019 A* conf
AAAI
Parag Jain, Abhijit Mishra, Amar Prakash Azad, Karthik Sankaranarayanan
2019 conf
ACL (1)
Sai Surya, Abhijit Mishra, Anirban Laha, Parag Jain, Karthik Sankaranarayanan
2019 J jnl
IBM J. Res. Dev.
S. Agrawal, Anush Sankaran, Anirban Laha, Saneem A. Chemmengath, Disha Shrivastava, Karthik Sankaranarayanan
2018 conf
NAACL-HLT (2)
Parag Jain, Anirban Laha, Karthik Sankaranarayanan, Preksha Nema, Mitesh M. Khapra, Shreyas Shetty
2018 J jnl
CoRR
Parag Jain, Anirban Laha, Karthik Sankaranarayanan, Preksha Nema, Mitesh M. Khapra, Shreyas Shetty
2018 conf
SIGMOD Conference
Ashish R. Mittal, Jaydeep Sen, Diptikalyan Saha, Karthik Sankaranarayanan
2018 A* conf
AAAI
Amrita Saha, Vardaan Pahuja, Mitesh M. Khapra, Karthik Sankaranarayanan, Sarath Chandar
2018 J jnl
CoRR
Amrita Saha, Vardaan Pahuja, Mitesh M. Khapra, Karthik Sankaranarayanan, Sarath Chandar
2018 conf
ACL (1)
Amrita Saha, Rahul Aralikatte, Mitesh M. Khapra, Karthik Sankaranarayanan
2018 J jnl
CoRR
Amrita Saha, Rahul Aralikatte, Mitesh M. Khapra, Karthik Sankaranarayanan
2018 conf
iThings/GreenCom/CPSCom/SmartData
Sultan Basudan, Abdulrahman Alamer, Xiaodong Lin, Karthik Sankaranarayanan
2018 A* conf
IJCAI
Jaydeep Sen, Ashish R. Mittal, Diptikalyan Saha, Karthik Sankaranarayanan
2018 conf
NAACL-HLT
Preksha Nema, Shreyas Shetty, Parag Jain, Anirban Laha, Karthik Sankaranarayanan, Mitesh M. Khapra
2018 J jnl
CoRR
Preksha Nema, Shreyas Shetty, Parag Jain, Anirban Laha, Karthik Sankaranarayanan, Mitesh M. Khapra
2018 J jnl
CoRR
Disha Shrivastava, Abhijit Mishra, Karthik Sankaranarayanan
2018 A* conf
NeurIPS
Anirban Laha, Saneem Ahmed Chemmengath, Priyanka Agrawal, Mitesh M. Khapra, Karthik Sankaranarayanan, Harish G. Ramaswamy
2018 J jnl
CoRR
Anirban Laha, Saneem A. Chemmengath, Priyanka Agrawal, Mitesh M. Khapra, Karthik Sankaranarayanan, Harish G. Ramaswamy
2018 J jnl
IEEE Data Eng. Bull.
Chuan Lei, Fatma Özcan, Abdul Quamar, Ashish R. Mittal, Jaydeep Sen, Diptikalyan Saha, Karthik Sankaranarayanan
2018 J jnl
CoRR
Anirban Laha, Parag Jain, Abhijit Mishra, Karthik Sankaranarayanan
2018 J jnl
Proc. VLDB Endow.
Manasa Jammi, Jaydeep Sen, Ashish R. Mittal, Sagar Verma, Vardaan Pahuja, Rema Ananthanarayanan, Pranay Lohia, Hima Karanam, Diptikalyan Saha, Karthik Sankaranarayanan
2018 A* conf
AAAI
Amrita Saha, Mitesh M. Khapra, Karthik Sankaranarayanan
2018 J jnl
CoRR
Parag Jain, Abhijit Mishra, Amar Prakash Azad, Karthik Sankaranarayanan
2018 J jnl
CoRR
Sai Surya, Abhijit Mishra, Anirban Laha, Parag Jain, Karthik Sankaranarayanan
2017 J jnl
CoRR
Disha Shrivastava, C. G. Saneem Ahmed, Anirban Laha, Karthik Sankaranarayanan
2017 J jnl
IEEE Internet Things J.
Sultan Basudan, Xiaodong Lin, Karthik Sankaranarayanan
2017 B conf
GLOBECOM
Sultan Basudan, Xiaodong Lin, Karthik Sankaranarayanan
2017 J jnl
Proc. VLDB Endow.
Shreyas Bharadwaj, Laura Chiticariu, Marina Danilevsky, Samarth Dhingra, Samved Divekar, Arnaldo Carreno-Fuentes, Himanshu Gupta, Nitin Gupta, Sang-Don Han, Mauricio A. Hernández, Howard Ho, Parag Jain, Salil Joshi, Hima Karanam, Saravanan Krishnan, Rajasekar Krishnamurthy, Yunyao Li, Satishkumaar Manivannan, Ashish R. Mittal, Fatma Ozcan, Abdul Quamar, Poornima Raman, Diptikalyan Saha, Karthik Sankaranarayanan, Jaydeep Sen, Prithviraj Sen, Shivakumar Vaithyanathan, Mitesh Vasa, Hao Wang, Huaiyu Zhu
2017 J jnl
CoRR
Amrita Saha, Mitesh M. Khapra, Karthik Sankaranarayanan
2017 conf
HCI (17)
Cameron Chodan, Pejman Mirza-Babaei, Karthik Sankaranarayanan
2017 J jnl
CoRR
Parag Jain, Priyanka Agrawal, Abhijit Mishra, Mohak Sukhwani, Anirban Laha, Karthik Sankaranarayanan
2016 J jnl
Proc. VLDB Endow.
Diptikalyan Saha, Avrilia Floratou, Karthik Sankaranarayanan, Umar Farooq Minhas, Ashish R. Mittal, Fatma Özcan
2016 Misc conf
WSC
Ralph Laite, Nataliya Portman, Karthik Sankaranarayanan
2015 J jnl
Mach. Learn.
Amit Dhurandhar, Karthik Sankaranarayanan
2015 conf
GEM
Karthik Sankaranarayanan, Pejman Mirza-Babaei, Frederico Da Rocha Tomé Filho
2014 conf
SIGSOFT FSE
Senthil Mani, Karthik Sankaranarayanan, Vibha Singhal Sinha, Premkumar T. Devanbu
2014 J jnl
J. Simulation
Karthik Sankaranarayanan, Carlos Arturo Delgado Alvarez, Ann van Ackere, Erik Reimer Larsen
2013 J jnl
Integr.
Karthik Sankaranarayanan, Brett H. Meyer, Wei Huang, Robert J. Ribando, Hossein Haj-Hariri, Mircea R. Stan, Kevin Skadron
2013 A conf
CIKM
Karthik Sankaranarayanan, Amit Dhurandhar
2012 conf
ACCV (3)
Karthik Sankaranarayanan, James W. Davis
2012 B conf
ICPR
Karthik Sankaranarayanan, James W. Davis
2012 C conf
ICORES
Karthik Sankaranarayanan, Carlos Arturo Delgado Alvarez, Erik Reimer Larsen, Ann van Ackere
2011 C conf
ECMS
Carlos Arturo Delgado Alvarez, Ann van Ackere, Karthik Sankaranarayanan, Erik Reimer Larsen
2011 A* conf
CVPR
Karthik Sankaranarayanan, James W. Davis
2011 J jnl
Sustain. Comput. Informatics Syst.
Karthik Sankaranarayanan, Brett H. Meyer, Mircea R. Stan, Kevin Skadron
2011 A conf
WACV
Karthik Sankaranarayanan, Ming-Ching Chang, Nils Krahnstoever
2010 conf
ISVC (1)
Karthik Sankaranarayanan, James W. Davis
2010 B conf
AVSS
Karthik Sankaranarayanan, James W. Davis
2010 conf
ACCV (2)
Karthik Sankaranarayanan, James W. Davis
2008 B conf
AVSS
Karthik Sankaranarayanan, James W. Davis
2008 J jnl
IEEE Trans. Computers
Wei Huang, Karthik Sankaranarayanan, Kevin Skadron, Robert J. Ribando, Mircea R. Stan
2008 A conf
WACV
Karthik Sankaranarayanan, James W. Davis
2008 A* conf
DAC
Wei Huang, Mircea R. Stan, Karthik Sankaranarayanan, Robert J. Ribando, Kevin Skadron
2006 J jnl
IEEE Trans. Very Large Scale Integr. Syst.
Wei Huang, Shougata Ghosh, Sivakumar Velusamy, Karthik Sankaranarayanan, Kevin Skadron, Mircea R. Stan
2005 J jnl
J. Instr. Level Parallelism
Karthik Sankaranarayanan, Sivakumar Velusamy, Mircea R. Stan, Kevin Skadron
2004 A* conf
DAC
Wei Huang, Mircea R. Stan, Kevin Skadron, Karthik Sankaranarayanan, Shougata Ghosh, Sivakumar Velusamy
2004 J jnl
ACM Trans. Archit. Code Optim.
Karthik Sankaranarayanan, Kevin Skadron
2004 A conf
DATE
Yingmin Li, Dharmesh Parikh, Yan Zhang, Karthik Sankaranarayanan, Mircea R. Stan, Kevin Skadron
2004 J jnl
ACM Trans. Archit. Code Optim.
Kevin Skadron, Mircea R. Stan, Karthik Sankaranarayanan, Wei Huang, Sivakumar Velusamy, David Tarjan
2003 J jnl
Microelectron. J.
Mircea R. Stan, Kevin Skadron, Marco Barcella, Wei Huang, Karthik Sankaranarayanan, Sivakumar Velusamy
2003 J jnl
IEEE Micro
Kevin Skadron, Mircea R. Stan, Wei Huang, Sivakumar Velusamy, Karthik Sankaranarayanan, David Tarjan
2003 A* conf
ISCA
Kevin Skadron, Mircea R. Stan, Wei Huang, Sivakumar Velusamy, Karthik Sankaranarayanan, David Tarjan
2001 Misc conf
FCCM
Ranjani Parthasarathi, Easwaran Raman, Karthik Sankaranarayanan, Lakshmi N. Chakrapani
tests/unit/test_apk_decompile_extractor.py
← Index tests/unit/test_apk_decompile_extractor.py python
"""
Unit tests for DecompileAPK extractor, export data, and ClickHouse schemas.

Tests the main DecompileAPK extractor class following the DecompileBinja test pattern.
All analysis is mocked — no JADX/apktool/Java installation required.
"""
import hashlib
import os
import tempfile
import zipfile

import pytest
from unittest.mock import MagicMock, patch, PropertyMock
from dataclasses import asdict

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


def _create_fake_apk_file():
    """Create a minimal APK file for testing and return its path."""
    tmpdir = tempfile.mkdtemp()
    apk_path = os.path.join(tmpdir, "test.apk")
    with zipfile.ZipFile(apk_path, "w") as zf:
        zf.writestr("AndroidManifest.xml", b"<manifest/>")
        zf.writestr("classes.dex", b"dex\n035\x00" + b"\x00" * 100)
    return apk_path


# ============================================================================
# DecompileAPK Extractor Tests
# ============================================================================

class TestDecompileAPK:
    """Tests for the DecompileAPK extractor class."""

    def test_tag(self):
        from redb.extractors.decompiler.DecompileAPK import DecompileAPK
        apk_path = _create_fake_apk_file()
        try:
            ext = DecompileAPK(apk_path, MagicMock())
            assert ext.tag() == "apk_decompiled"
        finally:
            os.unlink(apk_path)

    def test_get_clickhouse_table(self):
        from redb.extractors.decompiler.DecompileAPK import DecompileAPK
        apk_path = _create_fake_apk_file()
        try:
            ext = DecompileAPK(apk_path, MagicMock())
            assert ext.get_clickhouse_table() is None
        finally:
            os.unlink(apk_path)

    def test_timeout_default(self):
        from redb.extractors.decompiler.DecompileAPK import DecompileAPK
        apk_path = _create_fake_apk_file()
        try:
            ext = DecompileAPK(apk_path, MagicMock())
            assert ext.APK_DECOMPILE_TIMEOUT == 600
        finally:
            os.unlink(apk_path)

    def test_timeout_from_env(self):
        from redb.extractors.decompiler.DecompileAPK import DecompileAPK
        apk_path = _create_fake_apk_file()
        try:
            with patch.dict(os.environ, {"APK_DECOMPILE_TIMEOUT": "900"}):
                ext = DecompileAPK(apk_path, MagicMock())
                assert ext.APK_DECOMPILE_TIMEOUT == 900
        finally:
            os.unlink(apk_path)

    def test_timeout_invalid_env(self):
        from redb.extractors.decompiler.DecompileAPK import DecompileAPK
        apk_path = _create_fake_apk_file()
        try:
            with patch.dict(os.environ, {"APK_DECOMPILE_TIMEOUT": "not_a_number"}):
                ext = DecompileAPK(apk_path, MagicMock())
                assert ext.APK_DECOMPILE_TIMEOUT == 600
        finally:
            os.unlink(apk_path)

    def test_calculate_md5(self):
        from redb.extractors.decompiler.DecompileAPK import DecompileAPK
        apk_path = _create_fake_apk_file()
        try:
            ext = DecompileAPK(apk_path, MagicMock())
            result = ext.calculate_md5("test_string")
            assert len(result) == 32
            assert result == hashlib.md5(b"test_string").hexdigest()
        finally:
            os.unlink(apk_path)

    def test_context_manager(self):
        from redb.extractors.decompiler.DecompileAPK import DecompileAPK
        apk_path = _create_fake_apk_file()
        try:
            with DecompileAPK(apk_path, MagicMock()) as ext:
                assert ext is not None
        finally:
            os.unlink(apk_path)

    def test_cleanup_run(self):
        from redb.extractors.decompiler.DecompileAPK import DecompileAPK
        apk_path = _create_fake_apk_file()
        try:
            ext = DecompileAPK(apk_path, MagicMock())
            ext.analyzer = MagicMock()
            ext.cleanup_run()
            assert ext.analyzer is None
        finally:
            os.unlink(apk_path)


# ============================================================================
# Export Data Tests
# ============================================================================

class TestPrepareExportData:
    """Tests for DecompileAPK.prepare_export_data() ClickHouse schemas."""

    def _make_extractor_with_results(self):
        from redb.extractors.decompiler.DecompileAPK import DecompileAPK
        apk_path = _create_fake_apk_file()
        ext = DecompileAPK(apk_path, MagicMock())
        ext.analysis_results = {
            "sha256": "a" * 64,
            "sha1": "b" * 40,
            "md5": "c" * 32,
            "decompiled_content": [
                {
                    "decompiled_method_hash": "d" * 64,
                    "decompiled_method": "public void foo() {}",
                    "decompiled_method_type": "USER",
                    "decompiled_has_string_encryption": False,
                    "decompiled_has_reflection_calls": False,
                    "decompiled_excessive_goto_count": False,
                }
            ],
            "decompiled_refs": [
                {
                    "decompiled_method_hash": "d" * 64,
                    "smali_method_hash": "e" * 64,
                    "decompiled_class_name": "com.example.Foo",
                    "decompiled_method_name": "foo",
                    "decompiled_method_signature": "()V",
                    "decompiled_method_prototype": "void foo()",
                    "functions_caller": ["bar"],
                    "functions_call": ["baz"],
                }
            ],
            "smali_content": [
                {
                    "smali_method_hash": "e" * 64,
                    "smali_method": "invoke-virtual {p0}, Lfoo;->bar()V\nreturn-void",
                    "smali_method_type": "USER",
                    "smali_instructions_count": 10,
                    "smali_register_count": 3,
                    "smali_has_string_encryption": False,
                    "smali_has_reflection_calls": False,
                    "smali_excessive_goto_count": False,
                    "smali_flattened_score": 0.0,
                    "smali_mba_score": 0.0,
                }
            ],
            "smali_refs": [
                {
                    "smali_method_hash": "e" * 64,
                    "decompiled_method_hash": "d" * 64,
                    "smali_class_name": "com.example.Foo",
                    "smali_method_name": "foo",
                    "smali_method_signature": "()V",
                    "ssdeep_smali": None,
                    "tlsh_smali": None,
                }
            ],
            "similarity_metrics": [
                {
                    "smali_method_hash": "e" * 64,
                    "cyclomatic_complexity": 2,
                    "ssdeep_smali": None,
                    "tlsh_smali": None,
                    "ssdeep_smali_normalized": None,
                    "tlsh_smali_normalized": None,
                    "minhash": [],
                }
            ],
            "cfg": [
                {
                    "smali_method_hash": "e" * 64,
                    "cfg_topology_hash": b'\x01' * 16,
                    "block_count": 3,
                    "edge_count": 3,
                    "cfg_instructions_count": 10,
                    "call_count": 1,
                    "cyclomatic_complexity": 2,
                    "loop_count": 0,
                    "max_depth": 2,
                    "max_fan_out": 2,
                    "md_index_topdown": 12345,
                    "md_index_bottomup": 67890,
                    "prime_product_smali": 999,
                    "cfg_feature_tlsh": None,
                    "wl_minhash": [0] * 128,
                    "bb_features": [[5, 1, 0, 1, 1, 0, 0, 2]] * 3,
                    "cfg_adjacency": [0x00000001, 0x00000002],
                }
            ],
            "strings": [
                {
                    "string": "https://evil.example.com/payload",
                    "string_encoding": "UTF8",
                    "string_offset": 0,
                    "string_length": 31,
                    "string_entropy": 3.95,
                }
            ],
            "analysis_errors": [
                {
                    "class_name": "com.example.Foo",
                    "method_name": "bar",
                    "error_location": "jadx",
                    "error_message": "timeout",
                    "error_type": "TimeoutError",
                }
            ],
        }
        return ext, apk_path

    def test_returns_none_when_no_results(self):
        from redb.extractors.decompiler.DecompileAPK import DecompileAPK
        apk_path = _create_fake_apk_file()
        try:
            ext = DecompileAPK(apk_path, MagicMock())
            assert ext.prepare_export_data("ClickHouseExporter") is None
        finally:
            os.unlink(apk_path)

    def test_multi_table_flag(self):
        ext, apk_path = self._make_extractor_with_results()
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            assert export["multi_table"] is True
        finally:
            os.unlink(apk_path)

    def test_all_table_keys_present(self):
        ext, apk_path = self._make_extractor_with_results()
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            assert "decompiled_content" in export
            assert "decompiled_refs" in export
            assert "smali_content" in export
            assert "smali_refs" in export
            assert "method_similarity_metrics" in export
            assert "strings_raw" in export
            assert "analysis_errors" in export
        finally:
            os.unlink(apk_path)

    def test_decompiled_content_schema(self):
        ext, apk_path = self._make_extractor_with_results()
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            dc = export["decompiled_content"]
            assert dc["table"] == "code_apk_decompiled_methods_content"
            assert len(dc["column_names"]) == 7
            assert len(dc["column_type_names"]) == 7
            assert "decompiled_method_hash" in dc["column_names"]
            assert "decompiled_method" in dc["column_names"]
            assert "analysis_date" in dc["column_names"]
            assert len(dc["data"]) == 1
            assert len(dc["data"][0]) == 7
        finally:
            os.unlink(apk_path)

    def test_decompiled_refs_schema(self):
        ext, apk_path = self._make_extractor_with_results()
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            dr = export["decompiled_refs"]
            assert dr["table"] == "code_apk_decompiled_methods_references"
            assert len(dr["column_names"]) == 10
            assert len(dr["column_type_names"]) == 10
            assert "sha256" in dr["column_names"]
            assert "sha1" not in dr["column_names"]
            assert "md5" not in dr["column_names"]
            assert "functions_caller" in dr["column_names"]
            assert "functions_call" in dr["column_names"]
        finally:
            os.unlink(apk_path)

    def test_smali_content_schema(self):
        ext, apk_path = self._make_extractor_with_results()
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            sc = export["smali_content"]
            assert sc["table"] == "code_apk_smali_methods_content"
            assert len(sc["column_names"]) == 11
            assert len(sc["column_type_names"]) == 11
            assert "smali_instructions_count" in sc["column_names"]
            assert "smali_register_count" in sc["column_names"]
            assert "smali_flattened_score" in sc["column_names"]
            assert "smali_mba_score" in sc["column_names"]
        finally:
            os.unlink(apk_path)

    def test_smali_refs_schema(self):
        ext, apk_path = self._make_extractor_with_results()
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            sr = export["smali_refs"]
            assert sr["table"] == "code_apk_smali_methods_references"
            assert len(sr["column_names"]) == 7
            assert len(sr["column_type_names"]) == 7
            assert "sha1" not in sr["column_names"]
            assert "md5" not in sr["column_names"]
            assert "ssdeep_smali" not in sr["column_names"]
            assert "tlsh_smali" not in sr["column_names"]
        finally:
            os.unlink(apk_path)

    def test_similarity_metrics_schema(self):
        ext, apk_path = self._make_extractor_with_results()
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            sm = export["method_similarity_metrics"]
            assert sm["table"] == "code_apk_method_similarity_metrics"
            assert len(sm["column_names"]) == 7
            assert "minhash" in sm["column_names"]
            assert "ssdeep_smali_normalized" in sm["column_names"]
            assert "tlsh_smali_normalized" in sm["column_names"]
            # cyclomatic_complexity moved to cfg table
            assert "cyclomatic_complexity" not in sm["column_names"]
            assert "block_count" not in sm["column_names"]
            assert "loop_count" not in sm["column_names"]
        finally:
            os.unlink(apk_path)

    def test_analysis_errors_schema(self):
        ext, apk_path = self._make_extractor_with_results()
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            ae = export["analysis_errors"]
            assert ae["table"] == "code_apk_analysis_errors"
            assert len(ae["column_names"]) == 9
            assert "error_hash" in ae["column_names"]
            assert "status" in ae["column_names"]
        finally:
            os.unlink(apk_path)

    def test_sha256_propagated_to_refs(self):
        ext, apk_path = self._make_extractor_with_results()
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            # Check that sha256 from analysis_results appears in ref rows
            dr_row = export["decompiled_refs"]["data"][0]
            assert dr_row[0] == "a" * 64  # sha256
            # sha1 and md5 no longer included in refs
            assert "sha1" not in export["decompiled_refs"]["column_names"]
            assert "md5" not in export["decompiled_refs"]["column_names"]
        finally:
            os.unlink(apk_path)

    def test_empty_tables_not_included(self):
        from redb.extractors.decompiler.DecompileAPK import DecompileAPK
        apk_path = _create_fake_apk_file()
        try:
            ext = DecompileAPK(apk_path, MagicMock())
            ext.analysis_results = {
                "sha256": "a" * 64,
                "sha1": "b" * 40,
                "md5": "c" * 32,
                "decompiled_content": [],
                "decompiled_refs": [],
                "smali_content": [],
                "smali_refs": [],
                "similarity_metrics": [],
                "cfg": [],
                "strings": [],
                "analysis_errors": [],
            }
            export = ext.prepare_export_data("ClickHouseExporter")
            assert export == {"multi_table": True}
        finally:
            os.unlink(apk_path)

    def test_non_clickhouse_exporter_returns_none(self):
        ext, apk_path = self._make_extractor_with_results()
        try:
            result = ext.prepare_export_data("ElasticsearchExporter")
            assert result is None
        finally:
            os.unlink(apk_path)


# ============================================================================
# Dataclass Tests
# ============================================================================

class TestAPKCodeAnalysisDataclasses:
    """Tests for the new APK code analysis dataclasses."""

    def test_decompiled_method_content(self):
        from redb.models.dataclasses import APKDecompiledMethodContent
        dc = APKDecompiledMethodContent(
            decompiled_method_hash="a" * 64,
            decompiled_method="public void foo() {}",
            decompiled_method_type="USER",
        )
        assert dc.decompiled_has_string_encryption is False
        assert dc.decompiled_has_reflection_calls is False
        assert dc.decompiled_excessive_goto_count is False

    def test_decompiled_method_content_populated(self):
        from redb.models.dataclasses import APKDecompiledMethodContent
        dc = APKDecompiledMethodContent(
            decompiled_method_hash="a" * 64,
            decompiled_method="public void foo() {}",
            decompiled_method_type="USER",
            decompiled_has_string_encryption=True,
            decompiled_has_reflection_calls=True,
            decompiled_excessive_goto_count=True,
        )
        assert dc.decompiled_has_string_encryption is True
        d = asdict(dc)
        assert d["decompiled_method_hash"] == "a" * 64

    def test_decompiled_method_reference(self):
        from redb.models.dataclasses import APKDecompiledMethodReference
        dr = APKDecompiledMethodReference(
            sha256="a" * 64,
            sha1="b" * 40,
            md5="c" * 32,
            decompiled_method_hash="d" * 64,
        )
        assert dr.functions_caller == []
        assert dr.functions_call == []
        assert dr.smali_method_hash is None

    def test_smali_method_content(self):
        from redb.models.dataclasses import APKSmaliMethodContent
        sc = APKSmaliMethodContent(
            smali_method_hash="e" * 64,
            smali_method="invoke-virtual {p0}, Lfoo;->bar()V",
            smali_method_type="USER",
            smali_instructions_count=5,
            smali_register_count=3,
        )
        assert sc.smali_instructions_count == 5
        assert sc.smali_register_count == 3

    def test_smali_method_reference(self):
        from redb.models.dataclasses import APKSmaliMethodReference
        sr = APKSmaliMethodReference(
            sha256="a" * 64,
            sha1="b" * 40,
            md5="c" * 32,
            smali_method_hash="e" * 64,
        )
        assert sr.decompiled_method_hash is None
        assert sr.ssdeep_smali is None
        assert sr.tlsh_smali is None

    def test_method_similarity_metrics(self):
        from redb.models.dataclasses import APKMethodSimilarityMetrics
        ms = APKMethodSimilarityMetrics(smali_method_hash="e" * 64)
        assert ms.cyclomatic_complexity is None
        assert ms.ssdeep_smali_normalized is None
        assert ms.tlsh_smali_normalized is None
        assert ms.minhash == []

    def test_code_analysis_error(self):
        from redb.models.dataclasses import APKCodeAnalysisError
        err = APKCodeAnalysisError(
            sha256="a" * 64,
            error_location="jadx",
            error_message="timeout",
        )
        assert err.class_name is None
        assert err.method_name is None
        assert err.error_type is None


# ============================================================================
# Tag Enum Tests
# ============================================================================

class TestAPKDecompiledTag:
    """Tests for the APK_DECOMPILED tag enum."""

    def test_tag_exists(self):
        from redb.extractors.enum import Tag
        assert hasattr(Tag, "APK_DECOMPILED")

    def test_tag_value(self):
        from redb.extractors.enum import Tag
        assert Tag.APK_DECOMPILED.value == "apk_decompiled"


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

class TestAPKWorkerDecompileIntegration:
    """Tests that DecompileAPK is registered in workers.py."""

    def test_module_registered(self):
        """Verify DecompileAPK is discoverable via the extractor registry."""
        from redb.extractor_registry import get_extractor_class
        cls = get_extractor_class("DecompileAPK")
        assert cls is not None, "DecompileAPK not found in extractor registry"
        assert cls.__name__ == "DecompileAPK"

    def test_worker_apk_dispatch_includes_decompile(self):
        import inspect
        import redb.workers as workers
        source = inspect.getsource(workers.process_binary_file)
        assert "DecompileAPK" in source