Haiyang Sun

88 papers A* 6A 1B 2C 1Misc 1Journal 65Unranked 12
YearRankTypeTitle / Venue / Authors
2026 J jnl
Expert Syst. Appl.
Lingwei Xu, Haiyang Sun, Kai Wang, Gaofeng Nie, Zhe Chen, T. Aaron Gulliver
2026 A* conf
AAAI
Gangwei Xu, Haotong Lin, Zhaoxing Zhang, Hongcheng Luo, Haiyang Sun, Xin Yang
2026 J jnl
IEEE Internet Things J.
Xuezhe Yan, Ning Chen, Zhichen Ni, Huansheng Xue, Haiyang Sun, Honglong Chen
2026 J jnl
IEEE Trans. Veh. Technol.
Haiyang Sun, Honglong Chen, Zhichen Ni, Xinglong Fan, Guoxin Li, Feng Xia
2026 A* conf
AAAI
Enhui Ma, Lijun Zhou, Tao Tang, Jiahuan Zhang, Junpeng Jiang, Zhan Zhang, Dong Han, Kun Zhan, Xueyang Zhang, Xianpeng Lang, Haiyang Sun, Xia Zhou, Di Lin, Kaicheng Yu
2026 J jnl
Inf. Fusion
Chen Sun, Haiyang Sun, Zhiqing Guo, Yunfeng Diao, Liejun Wang, Dan Ma, Gaobo Yang, Keqin Li
2026 J jnl
CoRR
Yong Ren, Jingbei Li, Haiyang Sun, Yujie Chen, Cheng Yi, Yechang Huang, Hao Gu, Ye Bai, Xuerui Yang
2026 J jnl
CoRR
Yiheng Liu, Junhao Ning, Sichen Xia, Haiyang Sun, Yang Yang, Hanyang Chi, Xiaohui Gao, Ning Qiang, Bao Ge, Junwei Han, Xintao Hu
2026 J jnl
IEEE Trans. Mob. Comput.
Haiyang Sun, Honglong Chen, Xinglong Fan, Zhichen Ni, Liantao Wu, Peng Sun, Weifeng Liu
2026 J jnl
CoRR
Xiaobao Wei, Zhangjie Ye, Yuxiang Gu, Zunjie Zhu, Yunfei Guo, Yingying Shen, Shan Zhao, Ming Lu, Haiyang Sun, Bing Wang, Guang Chen, Rongfeng Lu, Hangjun Ye
2026 J jnl
CoRR
Gangwei Xu, Haotong Lin, Hongcheng Luo, Haiyang Sun, Bing Wang, Guang Chen, Sida Peng, Hangjun Ye, Xin Yang
2026 J jnl
Comput. Commun.
Aoran Li, Honglong Chen, Zhishuai Li, Ning Chen, Zhichen Ni, Haiyang Sun
2026 J jnl
IEEE Trans. Pattern Anal. Mach. Intell.
Sida Peng, Yushi Long, Yunzhi Yan, Haotong Lin, Chenxu Zhou, Haiyang Sun, Kun Zhan, Xianpeng Lang, Hujun Bao, Xiaowei Zhou
2026 J jnl
CoRR
Jiawei Zhou, Zhenxin Zhu, Lingyi Du, Linye Lyu, Lijun Zhou, Zhanqian Wu, Hongcheng Luo, Zhuotao Tian, Bing Wang, Guang Chen, Hangjun Ye, Haiyang Sun, Yu Li
2026 J jnl
IEEE Trans. Veh. Technol.
Xuezhe Yan, Zhishuai Li, Zhichen Ni, Haiyang Sun, Ning Chen, Jiguo Yu, Honglong Chen
2026 J jnl
CoRR
Kaiyuan Tan, Yingying Shen, Mingfei Tu, Haohui Zhu, Bing Wang, Guang Chen, Hangjun Ye, Haiyang Sun
2026 A* conf
AAAI
Lixin Jia, Haiyang Sun, Zhiqing Guo, Yunfeng Diao, Dan Ma, Gaobo Yang
2025 J jnl
IEEE Internet Things J.
Wenzhe Fu, Haiyang Sun, Yong Fu, Lingwei Xu, T. Aaron Gulliver
2025 B conf
SMC
Boyuan Gu, Jiahao Tang, Yunhan Tang, Haiyang Sun, Changting Xie
2025 J jnl
Neurocomputing
Qi Yu, Danyang Song, Jinzhu Yang, Zhitao Zhang, Song Sun, Haiyang Sun, Yangyang Li, Yao Liu, Yiqiu Qi, Mei Wei, Yiming Liu
2025 J jnl
CoRR
Gangwei Xu, Haotong Lin, Zhaoxing Zhang, Hongcheng Luo, Haiyang Sun, Xin Yang
2025 A* conf
AAAI
Tao Tang, Dafeng Wei, Zhengyu Jia, Tian Gao, Changwei Cai, Chengkai Hou, Peng Jia, Kun Zhan, Haiyang Sun, Jingchen Fan, Yixing Zhao, Xiaodan Liang, Xianpeng Lang, Yang Wang
2025 J jnl
CoRR
Yiheng Liu, Xiaohui Gao, Haiyang Sun, Bao Ge, Tianming Liu, Junwei Han, Xintao Hu
2025 J jnl
CoRR
Zhuojie Wu, Heming Du, Shuyun Wang, Ming Lu, Haiyang Sun, Yandong Guo, Xin Yu
2025 J jnl
CoRR
Yishen Ji, Ziyue Zhu, Zhenxin Zhu, Kaixin Xiong, Ming Lu, Zhiqi Li, Lijun Zhou, Haiyang Sun, Bing Wang, Tong Lu
2025 J jnl
CoRR
Enhui Ma, Lijun Zhou, Tao Tang, Jiahuan Zhang, Junpeng Jiang, Zhan Zhang, Dong Han, Kun Zhan, Xueyang Zhang, Xianpeng Lang, Haiyang Sun, Xia Zhou, Di Lin, Kaicheng Yu
2025 J jnl
CoRR
Xiaoxue Chen, Ziyi Xiong, Yuantao Chen, Gen Li, Nan Wang, Hongcheng Luo, Long Chen, Haiyang Sun, Bing Wang, Guang Chen, Hangjun Ye, Hongyang Li, Ya-Qin Zhang, Hao Zhao
2025 J jnl
CoRR
Chen Sun, Haiyang Sun, Zhiqing Guo, Yunfeng Diao, Liejun Wang, Dan Ma, Gaobo Yang, Keqin Li
2025 J jnl
IEEE Robotics Autom. Lett.
Xiaobiao Du, Haiyang Sun, Ming Lu, Tianqing Zhu, Xin Yu
2025 J jnl
CoRR
Tianze Xia, Yongkang Li, Lijun Zhou, Jingfeng Yao, Kaixin Xiong, Haiyang Sun, Bing Wang, Kun Ma, Guang Chen, Hangjun Ye, Wenyu Liu, Xinggang Wang
2025 J jnl
CoRR
Zhiyi Hou, Enhui Ma, Fang Li, Zhiyi Lai, Kalok Ho, Zhanqian Wu, Lijun Zhou, Long Chen, Chitian Sun, Haiyang Sun, Bing Wang, Guang Chen, Hangjun Ye, Kaicheng Yu
2025 J jnl
CoRR
Kaiyuan Tan, Yingying Shen, Haohui Zhu, Zhiwei Zhan, Shan Zhao, Mingfei Tu, Hongcheng Luo, Haiyang Sun, Bing Wang, Guang Chen, Hangjun Ye
2025 C conf
FUSION
Haiyang Sun, Lin Gao, Giorgio Battistelli, Luigi Chisci, Ping Wei
2025 J jnl
CoRR
Xiangyu Guo, Zhanqian Wu, Kaixin Xiong, Ziyang Xu, Lijun Zhou, Gangwei Xu, Shaoqing Xu, Haiyang Sun, Bing Wang, Guang Chen, Hangjun Ye, Wenyu Liu, Xinggang Wang
2025 J jnl
IEEE Trans. Mob. Comput.
Xuejian Chi, Honglong Chen, Zhichen Ni, Haiyang Sun, Peng Sun, Dongxiao Yu
2025 J jnl
Signal Image Video Process.
Haiyang Sun, Rongfen Gong, Maoxiang Chu, Yaobang Wang
2025 B conf
SMC
Boyuan Gu, Yanhui Yang, Siyu You, Haiyang Sun, Jiahui Sun, Shisheng Guo
2025 J jnl
CoRR
Yayue Deng, Guoqiang Hu, Haiyang Sun, Xiangyu Zhang, Haoyang Zhang, Fei Tian, Xuerui Yang, Gang Yu, Eng Siong Chng
2025 J jnl
CoRR
Xiaoshuai Hao, Lei Zhou, Zhijian Huang, Zhiwen Hou, Yingbo Tang, Lingfeng Zhang, Guang Li, Zheng Lu, Shuhuai Ren, Xianhui Meng, Yuchen Zhang, Jing Wu, Jinghui Lu, Chenxu Dang, Jiayi Guan, Jianhua Wu, Zhiyi Hou, Hanbing Li, Shumeng Xia, Mingliang Zhou, Yinan Zheng, Zihao Yue, Shuhao Gu, Hao Tian, Yuannan Shen, Jianwei Cui, Wen Zhang, Shaoqing Xu, Bing Wang, Haiyang Sun, Zeyu Zhu, Yuncheng Jiang, Zibin Guo, Chuhong Gong, Chaofan Zhang, Wenbo Ding, Kun Ma, Guang Chen, Rui Cai, Diyun Xiang, Heng Qu, Fuli Luo, Hangjun Ye, Long Chen
2025 J jnl
CoRR
Shuyun Wang, Haiyang Sun, Bin Wang, Hangjun Ye, Xin Yu
2025 J jnl
CoRR
Gangwei Xu, Haotong Lin, Hongcheng Luo, Xianqi Wang, Jingfeng Yao, Lianghui Zhu, Yuechuan Pu, Cheng Chi, Haiyang Sun, Bing Wang, Guang Chen, Hangjun Ye, Sida Peng, Xin Yang
2025 A conf
IROS
Bu Jin, Weize Li, Baihan Yang, Zhenxin Zhu, Junpeng Jiang, Huan-ang Gao, Haiyang Sun, Kun Zhan, Hengtong Hu, Xueyang Zhang, Peng Jia, Hao Zhao
2025 J jnl
CoRR
Bu Jin, Weize Li, Baihan Yang, Zhenxin Zhu, Junpeng Jiang, Huan-ang Gao, Haiyang Sun, Kun Zhan, Hengtong Hu, Xueyang Zhang, Peng Jia, Hao Zhao
2025 J jnl
CoRR
Yongkang Li, Kaixin Xiong, Xiangyu Guo, Fang Li, Sixu Yan, Gangwei Xu, Lijun Zhou, Long Chen, Haiyang Sun, Bing Wang, Guang Chen, Hangjun Ye, Wenyu Liu, Xinggang Wang
2025 J jnl
CoRR
Kai Zeng, Zhanqian Wu, Kaixin Xiong, Xiaobao Wei, Xiangyu Guo, Zhenxin Zhu, Kalok Ho, Lijun Zhou, Bohan Zeng, Ming Lu, Haiyang Sun, Bing Wang, Guang Chen, Hangjun Ye, Wentao Zhang
2025 A* conf
ICML
Tao Tang, Lijun Zhou, Pengkun Hao, Zihang He, Kalok Ho, Shuo Gu, Zhihui Hao, Haiyang Sun, Kun Zhan, Peng Jia, Xianpeng Lang, Xiaodan Liang
2025 J jnl
CoRR
Xia Wang, Haiyang Sun, Tiantian Cao, Yueying Sun, Min Feng
2025 J jnl
CoRR
Lixin Jia, Haiyang Sun, Zhiqing Guo, Yunfeng Diao, Dan Ma, Gaobo Yang
2025 J jnl
CoRR
Zikang Yuan, Yuechuan Pu, Hongcheng Luo, Fengtian Lang, Cheng Chi, Teng Li, Yingying Shen, Haiyang Sun, Bing Wang, Xin Yang
2025 J jnl
CoRR
Kaiyuan Tan, Yingying Shen, Haiyang Sun, Bing Wang, Guang Chen, Hangjun Ye
2025 J jnl
CoRR
Ziyue Zhu, Zhanqian Wu, Zhenxin Zhu, Lijun Zhou, Haiyang Sun, Bing Wan, Kun Ma, Guang Chen, Hangjun Ye, Jin Xie, Jian Yang
2024 J jnl
CoRR
Xiaobiao Du, Haiyang Sun, Shuyun Wang, Zhuojie Wu, Hongwei Sheng, Jiaying Ying, Ming Lu, Tianqing Zhu, Kun Zhan, Xin Yu
2024 J jnl
CoRR
Haiyang Sun, Lin Zhao, Zihao Wu, Xiaohui Gao, Yutao Hu, Mengfei Zuo, Wei Zhang, Junwei Han, Tianming Liu, Xintao Hu
2024 J jnl
CoRR
Junpeng Jiang, Gangyi Hong, Lijun Zhou, Enhui Ma, Hengtong Hu, Xia Zhou, Jie Xiang, Fan Liu, Kaicheng Yu, Haiyang Sun, Kun Zhan, Peng Jia, Miao Zhang
2024 J jnl
CoRR
Xin Shen, Lei Shen, Shaozu Yuan, Heming Du, Haiyang Sun, Xin Yu
2024 J jnl
CoRR
Xiaobiao Du, Haiyang Sun, Ming Lu, Tianqing Zhu, Xin Yu
2024 J jnl
CoRR
Xiaohui Gao, Yue Cheng, Peiyang Li, Yijie Niu, Yifan Ren, Yiheng Liu, Haiyang Sun, Zhuoyi Li, Weiwei Xing, Xintao Hu
2024 J jnl
IEEE Trans. Veh. Technol.
Xinglong Fan, Honglong Chen, Zhichen Ni, Guoxin Li, Haiyang Sun, Jiguo Yu
2024 conf
ECCV (84)
Hu Zhang, Jianhua Xu, Tao Tang, Haiyang Sun, Xin Yu, Zi Huang, Kaicheng Yu
2024 J jnl
CoRR
Tianyang Zhong, Zhenyuan Yang, Zhengliang Liu, Ruidong Zhang, Yiheng Liu, Haiyang Sun, Yi Pan, Yiwei Li, Yifan Zhou, Hanqi Jiang, Junhao Chen, Tianming Liu
2024 conf
ICCEIC
Jiahao Wang, Haiyang Sun, Shufan Cao, Rongyang Liao
2024 J jnl
CoRR
Yunzhi Yan, Haotong Lin, Chenxu Zhou, Weijie Wang, Haiyang Sun, Kun Zhan, Xianpeng Lang, Xiaowei Zhou, Sida Peng
2024 conf
ECCV (73)
Yunzhi Yan, Haotong Lin, Chenxu Zhou, Weijie Wang, Haiyang Sun, Kun Zhan, Xianpeng Lang, Xiaowei Zhou, Sida Peng
2024 conf
ECCV (18)
Bu Jin, Yupeng Zheng, Pengfei Li, Weize Li, Yuhang Zheng, Sujie Hu, Xinyu Liu, Jinwei Zhu, Zhijie Yan, Haiyang Sun, Kun Zhan, Peng Jia, Xiaoxiao Long, Yilun Chen, Hao Zhao
2024 J jnl
CoRR
Bu Jin, Yupeng Zheng, Pengfei Li, Weize Li, Yuhang Zheng, Sujie Hu, Xinyu Liu, Jinwei Zhu, Zhijie Yan, Haiyang Sun, Kun Zhan, Peng Jia, Xiaoxiao Long, Yilun Chen, Hao Zhao
2024 J jnl
CoRR
Lijun Zhou, Tao Tang, Pengkun Hao, Zihang He, Kalok Ho, Shuo Gu, Wenbo Hou, Zhihui Hao, Haiyang Sun, Kun Zhan, Peng Jia, Xianpeng Lang, Xiaodan Liang
2024 J jnl
CoRR
Enhui Ma, Lijun Zhou, Tao Tang, Zhan Zhang, Dong Han, Junpeng Jiang, Kun Zhan, Peng Jia, Xianpeng Lang, Haiyang Sun, Di Lin, Kaicheng Yu
2023 J jnl
Remote. Sens.
Haiyang Sun, Xupu Geng, Lingsheng Meng, Xiao-Hai Yan
2023 J jnl
CoRR
Hu Zhang, Jianhua Xu, Tao Tang, Haiyang Sun, Xin Yu, Zi Huang, Kaicheng Yu
2022 J jnl
Sensors
Zhexue Ge, Xiaolei Shen, Quanqin Gao, Haiyang Sun, Xiaoan Tang, Qingyu Cai
2022 conf
CNIOT
Xiaolei Shen, Zhexue Ge, Quanqin Gao, Haiyang Sun, Xiaoan Tang, Qingyu Cai
2022 J jnl
CoRR
Kaicheng Yu, Tao Tang, Hongwei Xie, Zhiwei Lin, Zhongwei Wu, Zhongyu Xia, Tingting Liang, Haiyang Sun, Jiong Deng, Dayang Hao, Yongtao Wang, Xiaodan Liang, Bing Wang
2021 conf
ICVISP
Xiaokui Luo, Haiyang Sun, Ning Zhang, Zhijun Han, Jingjian Bi
2021 J jnl
IEEE Trans. Ind. Electron.
Zhangqi Liu, Kai Wang, Haiyang Sun, Jian Li, Bo Zhou
2021 conf
ICVISP
Zhitao Yan, Qiang Wang, Haining Liu, Shouxing Kang, Liping Zhang, Haiyang Sun
2021 conf
ICAIIS
Shulin He, Yong Liu, Haiyang Sun, Kaiwen Zheng, Yandi Zhang
2021 conf
ICVISP
Haiyang Sun, Fujun Zhai, Ning Zhang, Jingjian Bi, Zhijun Han
2020 J jnl
IEEE Trans. Veh. Technol.
Kai Wang, Feng Li, Haiyang Sun, Xiaodong Sun
2020 J jnl
IEEE Access
Enbin Liu, Yong Peng, Shanbi Peng, Haiyang Sun, Weibiao Qiao, Mohammadamin Azimi
2019 Misc conf
AMIA
Hongru Yu, Haiyang Sun, Danyi Wu, Tsung-Ting Kuo
2019 J jnl
IEEE Trans. Ind. Electron.
Haiyang Sun, Kai Wang
2019 A* conf
IJCAI
Jonathan Chase, Duc Thien Nguyen, Haiyang Sun, Hoong Chuin Lau
2019 J jnl
IEEE Access
Feng Li, Kai Wang, Haiyang Sun, Jinwang Kong
2019 J jnl
IEEE Trans. Ind. Electron.
Lufeng Zhang, Kai Wang, Haiyang Sun, Shushu Zhu
2019 J jnl
IEEE Access
Haiyang Sun, Kai Wang
2018 conf
ICIC (2)
Haiyang Sun, Zhenyu Yue, Le Zhao, Junfeng Xia, Yannan Bin, Di Zhang
2016 conf
AsiaSim/SCS AutumnSim (1)
Liren Xu, Jun Cai, Runqiang Chen, Kun Li, Haiyang Sun, Xingtao Su
2016 conf
HCI (11)
Youxin Wu, Yin Liang, Haiyang Sun, Jingxian Chen, Yi Liu, Jian Lin, Binbin Li
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