Ramakrishna R. Nemani

75 papers A* 6A 1B 3C 4Misc 2Journal 52Unranked 7
YearRankTypeTitle / Venue / Authors
2023 J jnl
IEEE Trans. Neural Networks Learn. Syst.
Kate Duffy, Thomas J. Vandal, Weile Wang, Ramakrishna R. Nemani, Auroop R. Ganguly
2023 J jnl
IEEE Trans. Neural Networks Learn. Syst.
Thomas J. Vandal, Ramakrishna R. Nemani
2022 J jnl
Remote. Sens.
Weile Wang, Yujie Wang, Alexei I. Lyapustin, Hirofumi Hashimoto, Taejin Park, Andrew R. Michaelis, Ramakrishna R. Nemani
2022 A* conf
KDD
Thomas J. Vandal, Kate Duffy, Will McCarty, Akira Sewnath, Ramakrishna R. Nemani
2022 conf
GECCO Companion
Subodh Kalia, Chilukuri K. Mohan, Ramakrishna R. Nemani
2022 J jnl
IEEE Access
Kate Duffy, Thomas J. Vandal, Ramakrishna R. Nemani
2022 J jnl
IEEE Trans. Geosci. Remote. Sens.
Thomas Vandal, Daniel McDuff, Weile Wang, Kate Duffy, Andrew R. Michaelis, Ramakrishna R. Nemani
2021 J jnl
IEEE J. Sel. Top. Appl. Earth Obs. Remote. Sens.
Yepei Chen, Kaimin Sun, Wenzhuo Li, Chi Chen, Pengfei Li, Ting Bai, Taejin Park, Weile Wang, Ramakrishna R. Nemani, Ranga B. Myneni
2020 J jnl
Remote. Sens.
Weile Wang, Shuang Li, Hirofumi Hashimoto, Hideaki Takenaka, Atsushi Higuchi, Satya Kalluri, Ramakrishna R. Nemani
2020 J jnl
Remote. Sens.
Vesta Afzali Gorooh, Subodh Kalia, Phu Nguyen, Kuo-lin Hsu, Soroosh Sorooshian, Sangram Ganguly, Ramakrishna R. Nemani
2020 C conf
IGARSS
Ramakrishna R. Nemani, Weile Wang, Hirofumi Hashimoto, Andrew R. Michaelis, Thomas Vandal, Alexei I. Lyapustin, Jia Zhang, Tsengdar J. Lee, Satya Kalluri, Hideaki Takenaka, Atsushi Higuchi, Kazuhito Ichii, Shuang Li, Jong-Min Yeom
2020 A* conf
KDD
Nicholas Gao, Max Wilson, Thomas Vandal, Walter Vinci, Ramakrishna R. Nemani, Eleanor Gilbert Rieffel
2020 J jnl
CoRR
Nicholas Gao, Max Wilson, Thomas Vandal, Walter Vinci, Ramakrishna R. Nemani, Eleanor Gilbert Rieffel
2020 C conf
IGARSS
Hirofumi Hashimoto, Weile Wang, Andrew R. Michaelis, Hideaki Takenaka, Atsushi Higuchi, Ramakrishna R. Nemani
2020 J jnl
CoRR
Thomas Vandal, Daniel McDuff, Weile Wang, Andrew R. Michaelis, Ramakrishna R. Nemani
2019 J jnl
Remote. Sens.
Negin Hayatbini, Bailey Kong, Kuo-lin Hsu, Phu Nguyen, Soroosh Sorooshian, Graeme Stephens, Charless C. Fowlkes, Ramakrishna R. Nemani
2019 J jnl
CoRR
Kate Duffy, Thomas Vandal, Weile Wang, Ramakrishna R. Nemani, Auroop R. Ganguly
2019 J jnl
Frontiers Big Data
Kate Duffy, Thomas Vandal, Shuang Li, Sangram Ganguly, Ramakrishna R. Nemani, Auroop R. Ganguly
2019 J jnl
CoRR
Qun Liu, Saikat Basu, Sangram Ganguly, Supratik Mukhopadhyay, Robert DiBiano, Manohar Karki, Ramakrishna R. Nemani
2019 A* conf
KDD
Ramakrishna R. Nemani
2019 J jnl
Remote. Sens.
Shuang Li, Weile Wang, Hirofumi Hashimoto, Jun Xiong, Thomas Vandal, Jing Yao, Lexiang Qian, Kazuhito Ichii, Alexei I. Lyapustin, Yujie Wang, Ramakrishna R. Nemani
2019 J jnl
Remote. Sens.
Yepei Chen, Kaimin Sun, Chi Chen, Ting Bai, Taejin Park, Weile Wang, Ramakrishna R. Nemani, Ranga B. Myneni
2019 J jnl
Remote. Sens.
Dawn Emil Sebastian, Sangram Ganguly, Jagdish Krishnaswamy, Kate Duffy, Ramakrishna R. Nemani, Subimal Ghosh
2019 J jnl
CoRR
Thomas Vandal, Ramakrishna R. Nemani
2019 J jnl
CoRR
Edward Collier, Kate Duffy, Sangram Ganguly, Geri Madanguit, Subodh Kalia, Shreekant Gayaka, Ramakrishna R. Nemani, Andrew R. Michaelis, Shuang Li, Auroop R. Ganguly, Supratik Mukhopadhyay
2018 J jnl
Remote. Sens.
Weile Wang, Ramakrishna R. Nemani, Hirofumi Hashimoto, Sangram Ganguly, Dong Huang, Yuri Knyazikhin, Ranga B. Myneni, Govindasamy Bala
2018 J jnl
Neural Networks
Saikat Basu, Supratik Mukhopadhyay, Manohar Karki, Robert DiBiano, Sangram Ganguly, Ramakrishna R. Nemani, Shreekant Gayaka
2018 A* conf
IJCAI
Thomas Vandal, Evan Kodra, Sangram Ganguly, Andrew R. Michaelis, Ramakrishna R. Nemani, Auroop R. Ganguly
2018 J jnl
Remote. Sens.
Varun Mithal, Guruprasad Nayak, Ankush Khandelwal, Vipin Kumar, Ramakrishna R. Nemani, Nikunj C. Oza
2018 conf
ICDM Workshops
Edward Collier, Kate Duffy, Sangram Ganguly, Geri Madanguit, Subodh Kalia, Shreekant Gayaka, Ramakrishna R. Nemani, Andrew R. Michaelis, Shuang Li, Auroop R. Ganguly, Supratik Mukhopadhyay
2018 A* conf
KDD
Thomas Vandal, Evan Kodra, Jennifer G. Dy, Sangram Ganguly, Ramakrishna R. Nemani, Auroop R. Ganguly
2018 J jnl
CoRR
Thomas Vandal, Evan Kodra, Jennifer G. Dy, Sangram Ganguly, Ramakrishna R. Nemani, Auroop R. Ganguly
2018 A conf
ICSOC
Jia Zhang, Maryam Pourreza, Seungwon Lee, Ramakrishna R. Nemani, Tsengdar J. Lee
2017 A* conf
KDD
Thomas Vandal, Evan Kodra, Sangram Ganguly, Andrew R. Michaelis, Ramakrishna R. Nemani, Auroop R. Ganguly
2017 J jnl
CoRR
Thomas Vandal, Evan Kodra, Sangram Ganguly, Andrew R. Michaelis, Ramakrishna R. Nemani, Auroop R. Ganguly
2017 J jnl
Remote. Sens.
Uttam Kumar, Sangram Ganguly, Ramakrishna R. Nemani, S. Kumar Raja, Cristina Milesi, Ruchita Sinha, Andrew R. Michaelis, Petr Votava, Hirofumi Hashimoto, Shuang Li, Weile Wang, Subodh Kalia, Shreekant Gayaka
2017 J jnl
Neural Process. Lett.
Saikat Basu, Manohar Karki, Sangram Ganguly, Robert DiBiano, Supratik Mukhopadhyay, Shreekant Gayaka, Rajgopal Kannan, Ramakrishna R. Nemani
2017 J jnl
IEEE Trans. Knowl. Data Eng.
Varun Mithal, Guruprasad Nayak, Ankush Khandelwal, Vipin Kumar, Nikunj C. Oza, Ramakrishna R. Nemani
2016 J jnl
CoRR
Saikat Basu, Manohar Karki, Robert DiBiano, Supratik Mukhopadhyay, Sangram Ganguly, Ramakrishna R. Nemani, Shreekant Gayaka
2016 B conf
IJCNN
Saikat Basu, Manohar Karki, Supratik Mukhopadhyay, Sangram Ganguly, Ramakrishna R. Nemani, Robert DiBiano, Shreekant Gayaka
2016 J jnl
Remote. Sens.
Kai Yan, Taejin Park, Guangjian Yan, Chi Chen, Bin Yang, Zhao Liu, Ramakrishna R. Nemani, Yuri Knyazikhin, Ranga B. Myneni
2016 J jnl
Remote. Sens.
Kai Yan, Taejin Park, Guangjian Yan, Zhao Liu, Bin Yang, Chi Chen, Ramakrishna R. Nemani, Yuri Knyazikhin, Ranga B. Myneni
2015 J jnl
IEEE Trans. Geosci. Remote. Sens.
Saikat Basu, Sangram Ganguly, Ramakrishna R. Nemani, Supratik Mukhopadhyay, Gong Zhang, Cristina Milesi, Andrew R. Michaelis, Petr Votava, Ralph Dubayah, Laura Duncanson, Bruce D. Cook, Yifan Yu, Sassan Saatchi, Robert DiBiano, Manohar Karki, Edward Boyda, Uttam Kumar, Shuang Li
2015 J jnl
Int. J. Web Serv. Res.
Jia Zhang, Chris Lee, Petr Votava, Tsengdar J. Lee, Shuai Wang, Venkatesh Sriram, Neeraj Saini, Pujita Rao, Ramakrishna R. Nemani
2015 J jnl
Int. J. Bus. Process. Integr. Manag.
Jia Zhang, Chris Lee, Petr Votava, Tsengdar J. Lee, Ramakrishna R. Nemani, Ian T. Foster
2015 J jnl
CoRR
Saikat Basu, Sangram Ganguly, Supratik Mukhopadhyay, Robert DiBiano, Manohar Karki, Ramakrishna R. Nemani
2015 conf
SIGSPATIAL/GIS
Saikat Basu, Sangram Ganguly, Supratik Mukhopadhyay, Robert DiBiano, Manohar Karki, Ramakrishna R. Nemani
2015 B conf
ESANN
Saikat Basu, Manohar Karki, Sangram Ganguly, Robert DiBiano, Supratik Mukhopadhyay, Ramakrishna R. Nemani
2015 J jnl
CoRR
Saikat Basu, Manohar Karki, Sangram Ganguly, Robert DiBiano, Supratik Mukhopadhyay, Ramakrishna R. Nemani
2015 Misc conf
IRI
Uttam Kumar, Cristina Milesi, Sangram Ganguly, S. Kumar Raja, Ramakrishna R. Nemani
2015 Misc conf
IRI
Uttam Kumar, Cristina Milesi, S. Kumar Raja, Sangram Ganguly, Ramakrishna R. Nemani
2014 conf
SOSE
Jia Zhang, Chris Lee, Sean Xiao, Petr Votava, Tsengdar J. Lee, Ramakrishna R. Nemani, Ian T. Foster
2013 conf
IEEE SCC
Jia Zhang, Petr Votava, Tsengdar J. Lee, Shrikant Adhikarla, Isaraporn Cherry Kulkumjon, Matthew Schlau, Divya Natesan, Ramakrishna R. Nemani
2013 J jnl
Remote. Sens.
Yuli Shi, Sungho Choi, Xiliang Ni, Sangram Ganguly, Gong Zhang, Hieu V. Duong, Michael A. Lefsky, Marc Simard, Sassan S. Saatchi, Shihyan Lee, Wenge Ni-Meister, Shilong Piao, Chunxiang Cao, Ramakrishna R. Nemani, Ranga B. Myneni
2013 J jnl
Remote. Sens.
Sungho Choi, Xiliang Ni, Yuli Shi, Sangram Ganguly, Gong Zhang, Hieu V. Duong, Michael A. Lefsky, Marc Simard, Sassan S. Saatchi, Shihyan Lee, Wenge Ni-Meister, Shilong Piao, Chunxiang Cao, Ramakrishna R. Nemani, Ranga B. Myneni
2013 B conf
SERVICES
Jia Zhang, Petr Votava, Tsengdar J. Lee, Owen Chu, Clyde Li, David Liu, Kate Liu, Norman Xin, Ramakrishna R. Nemani
2013 J jnl
Remote. Sens.
Zaichun Zhu, Jian Bi, Yaozhong Pan, Sangram Ganguly, Alessandro Anav, Liang Xu, Arindam Samanta, Shilong Piao, Ramakrishna R. Nemani, Ranga B. Myneni
2013 J jnl
Remote. Sens.
Hirofumi Hashimoto, Weile Wang, Cristina Milesi, Jun Xiong, Sangram Ganguly, Zaichun Zhu, Ramakrishna R. Nemani
2013 J jnl
IEEE Trans. Geosci. Remote. Sens.
Jianjun Zhao, Yeqiao Wang, Hirofumi Hashimoto, Forrest S. Melton, Samuel H. Hiatt, Hongyan Zhang, Ramakrishna R. Nemani
2012 J jnl
Remote. Sens.
Hirofumi Hashimoto, Weile Wang, Cristina Milesi, Michael A. White, Sangram Ganguly, Minoru Gamo, Ryuichi Hirata, Ranga B. Myneni, Ramakrishna R. Nemani
2012 J jnl
IEEE J. Sel. Top. Appl. Earth Obs. Remote. Sens.
Eric M. Danner, Forrest S. Melton, Andrew Pike, Hirofumi Hashimoto, Andrew R. Michaelis, Balaji Rajagopalan, Jason Caldwell, Lynn DeWitt, Steven Lindley, Ramakrishna R. Nemani
2012 J jnl
IEEE J. Sel. Top. Appl. Earth Obs. Remote. Sens.
Forrest S. Melton, Lee F. Johnson, Christopher P. Lund, Lars L. Pierce, Andrew R. Michaelis, Samuel H. Hiatt, Alberto Guzman, Diganta D. Adhikari, Adam J. Purdy, Carolyn Rosevelt, Petr Votava, Thomas J. Trout, Bekele Temesgen, Kent Frame, Edwin J. Sheffner, Ramakrishna R. Nemani
2010 conf
WHISPERS
Sangram Ganguly, Ramakrishna R. Nemani, Yuri Knyazikhin, Weile Wang, Hirofumi Hashimoto, Petr Votava, Andrew R. Michaelis, Cristina Milesi, Jennifer L. Dungan, Forrest S. Melton, Ranga B. Myneni
2010 J jnl
Remote. Sens.
Cristina Milesi, Arindam Samanta, Hirofumi Hashimoto, K. Krishna Kumar, Sangram Ganguly, Prasad S. Thenkabail, Ashok N. Srivastava, Ramakrishna R. Nemani, Ranga B. Myneni
2010 C conf
IGARSS
Yeqiao Wang, Ramakrishna R. Nemani, Fred Dieffenbach, Kenneth Stolte, Glenn Holcomb, Matt Robinson, C. Casey Reese, Marcia McNiff, Roland Duhaime, Geri Tierney, Brian Mitche, Peter August, Peter Paton, Charles LaBash
2006 J jnl
IEEE Trans. Geosci. Remote. Sens.
Wenze Yang, Dong Huang, Bin Tan, Julienne C. Stroeve, Nikolay V. Shabanov, Yuri Knyazikhin, Ramakrishna R. Nemani, Ranga B. Myneni
2006 J jnl
IEEE Trans. Geosci. Remote. Sens.
Faith Ann Heinsch, Maosheng Zhao, Steven W. Running, John S. Kimball, Ramakrishna R. Nemani, Kenneth J. Davis, Paul V. Bolstad, Bruce D. Cook, Ankur R. Desai, Daniel M. Ricciuto, Beverly E. Law, Walt C. Oechel, Hyojung Kwon, Hongyan Luo, Steven C. Wofsy, Allison L. Dunn, J. William Munger, Dennis D. Baldocchi, Liukang Xu, David Y. Hollinger, Andrew D. Richardson, Paul C. Stoy, Mario B. S. Siqueira, Russell K. Monson, Sean P. Burns, Lawrence B. Flanagan
2006 J jnl
IEEE Trans. Geosci. Remote. Sens.
Wenze Yang, Bin Tan, Dong Huang, Miina Rautiainen, Nikolay V. Shabanov, Yujie Wang, Jeffrey L. Privette, Karl Fred Huemmrich, Rasmus Fensholt, Inge Sandholt, Marie Weiss, Douglas E. Ahl, Stith T. Gower, Ramakrishna R. Nemani, Yuri Knyazikhin, Ranga B. Myneni
2006 J jnl
IEEE Trans. Geosci. Remote. Sens.
Feihua Yang, Michael A. White, Andrew R. Michaelis, Kazuhito Ichii, Hirofumi Hashimoto, Petr Votava, A-Xing Zhu, Ramakrishna R. Nemani
2005 J jnl
Environ. Model. Softw.
William Matt Jolly, Jonathan M. Graham, Andrew R. Michaelis, Ramakrishna R. Nemani, Steven W. Running
2005 C conf
IGARSS
Smadar Shiffman, Ramakrishna R. Nemani
2003 J jnl
IEEE Trans. Geosci. Remote. Sens.
Kenlo Nishida, Ramakrishna R. Nemani, Joseph Glassy, Steven W. Running
2003 conf
ScanGIS
Petr Votava, Ramakrishna R. Nemani, Keith Golden, Daniel E. Cooke, Hector Hernandez, Changming Ma
1998 J jnl
IEEE Trans. Geosci. Remote. Sens.
Christopher Justice, Eric F. Vermote, John R. Townshend, Ruth S. DeFries, David P. Roy, Dorothy K. Hall, Vincent V. Salomonson, Jeffrey L. Privette, George A. Riggs, Alan H. Strahler, Wolfgang Lucht, Ranga B. Myneni, Yuri Knyazikhin, Steven W. Running, Ramakrishna R. Nemani, Zhengming Wan, Alfredo R. Huete, Wim van Leeuwen, Robert E. Wolfe, Louis Giglio, Jan-Peter Muller, Philip Lewis, Michael J. Barnsley
1997 J jnl
IEEE Trans. Geosci. Remote. Sens.
Ranga B. Myneni, Ramakrishna Ramakrishna, Ramakrishna R. Nemani, Steven W. Running
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