Xiangyang Xu

146 papers A 5B 6C 5Misc 3Journal 108Unranked 18
YearRankTypeTitle / Venue / Authors
2026 J jnl
Expert Syst. Appl.
Malong Tan, Renchao Jin, Dun Liu, Shan Jiang, Xiangyang Xu, Enmin Song
2026 J jnl
Comput. Stat.
Xiangyu Shi, Xiangyang Xu, Ruiyuan Cao, Tianfa Xie
2026 J jnl
J. Adv. Comput. Intell. Intell. Informatics
Tianran Xu, Rui Wang, Qinglin Han, Bin Zhang, Qian Zhao, Qian Li, Jiandong Du, Xiangyang Xu
2025 J jnl
J. Circuits Syst. Comput.
Xiangyang Xu, Yu Song, Abdullah Alharbi, Amr Tolba
2025 J jnl
J. Circuits Syst. Comput.
Xiangyang Xu, Yu Song
2025 J jnl
IEEE Access
Huilan Li, Xiaolan Yu, Xiangyang Xu
2025 J jnl
Biomed. Signal Process. Control.
Malong Tan, Renchao Jin, Dun Liu, Shan Jiang, Xiangyang Xu, Enmin Song
2025 J jnl
PeerJ Comput. Sci.
Xuye Wang, Beibei Wang, Wan Yin Tew, Xiaoning Yang, Xiangyang Xu, Yifang Gao, Yongjia Chen, Mun Fei Yam
2025 J jnl
CoRR
Xiangyang Xu, Hongyang Gao
2025 J jnl
Expert Syst. Appl.
Shizheng Sun, Shuai Zheng, Xiangyang Xu, Zeyin He
2025 J jnl
IEEE Access
Huilan Li, Xunjia Zheng, Xiangyang Xu
2025 J jnl
Phys. Commun.
Xiangyang Xu, Chunlong He, Xingquan Li, Jiaming Xu
2025 J jnl
CoRR
Xiangyang Xu, Hongyang Gao
2025 J jnl
Eng. Appl. Artif. Intell.
Bingxian Li, Yanfang Liu, Junwei Zhao, Xiangyang Xu, Peng Dong, Songbo Chen, Xiaojun Wu, Xuewu Liu, Hongzhong Qi
2025 J jnl
Vis. Comput.
Kai Zou, Lianghai Jin, Xiangyang Xu
2024 J jnl
Comput. Biol. Medicine
Hong Liu, Yuzhou Zhuang, Enmin Song, Yongde Liao, Guanchao Ye, Fan Yang, Xiangyang Xu, Xvhao Xiao, Chih-Cheng Hung
2024 J jnl
J. Adv. Comput. Intell. Intell. Informatics
Renkai Hou, Xiangyang Xu, Yaping Dai, Shuai Shao, Kaoru Hirota
2024 J jnl
IEEE Trans. Intell. Transp. Syst.
Xinran Li, Xiangyang Xu, Hao Yang
2024 conf
MMAsia
Guohuan Gao, Gang Zhang, Xiangyang Xu
2024 J jnl
Sensors
Mian Zhao, Xiangyang Xu, Xiaohua Bao, Xiangsheng Chen, Hao Yang
2024 J jnl
IEEE Trans. Consumer Electron.
Xiang Li, Nianhua Zhang, Xiangyang Xu, Anh-Tu Nguyen, Kamal Al-Haddad, Hui Zhang
2024 J jnl
IEEE Trans. Intell. Veh.
Nianhua Zhang, Shima Nazari, Jicheng Chen, Xiangyang Xu, Hui Zhang
2024 J jnl
CoRR
Zhaoning Yu, Xiangyang Xu, Hongyang Gao
2024 C conf
INDIN
Haoxiang Gong, Yanfang Liu, Shumiao Zuo, Xiangyang Xu, Jiahui Du, Yongze Lang
2024 J jnl
Symmetry
Wenkai Wang, Xiangyang Xu, Hao Yang
2024 C conf
INDIN
Junqing Li, Xiangyang Xu, Wantong Zhao, Peishen Zhao, Hanning Zhang, Shuhan Wang, Peng Dong
2024 J jnl
Informatica (Slovenia)
Xiangyang Xu
2024 J jnl
Symmetry
Xianwei He, Xiangyang Xu, Hao Yang
2024 J jnl
Remote. Sens.
Yingjie Du, Xiangyang Xu, Xuhui He
2024 J jnl
Adv. Complex Syst.
Yajie Liu, Jinlong Ma, Xiangyang Xu, Yuping Li
2024 C conf
INDIN
Shuhan Wang, Hanning Zhang, Junqing Li, Peishen Zhao, Xiangyang Xu, Peng Dong
2024 J jnl
Symmetry
Qiule Li, Xiangyang Xu, Jijie Guan, Hao Yang
2023 J jnl
IEEE Access
Xiangyang Xu, Yu Song
2023 J jnl
Remote. Sens.
Zihan Wang, Xiangyang Xu, Xuhui He, Xiaojun Wei, Hao Yang
2023 J jnl
IEEE Trans. Intell. Transp. Syst.
Ruiqi Ren, Peixin Shi, Pengjiao Jia, Xiangyang Xu
2023 B conf
ICIP
Liyuan Guo, Lianghai Jin, Guangzhi Ma, Xiangyang Xu
2023 J jnl
Sensors
Xinran Li, Xiangyang Xu, Xuhui He, Xiaojun Wei, Hao Yang
2023 conf
CNIOT
Xiangyang Xu, Xinglei Xu
2023 J jnl
Knowl. Based Syst.
Bangcheng Zhan, Enmin Song, Hong Liu, Xiangyang Xu, Wencheng Li, Chih-Cheng Hung
2022 J jnl
Symmetry
Xinran Li, Wuyin Jin, Xiangyang Xu, Hao Yang
2022 J jnl
Comput. Biol. Medicine
Hong Liu, Yuzhou Zhuang, Enmin Song, Xiangyang Xu, Chih-Cheng Hung
2022 J jnl
Int. J. Distributed Sens. Networks
Ben Wu, Wei Liu, Peixin Shi, Xiangyang Xu, Yingjing Liu
2022 J jnl
IEEE J. Biomed. Health Informatics
Yuzhou Zhuang, Hong Liu, Enmin Song, Guangzhi Ma, Xiangyang Xu, Chih-Cheng Hung
2022 J jnl
Symmetry
Zihan Wang, Peixin Shi, Xunqian Xu, Xiangyang Xu, Feng Xie, Hao Yang
2022 J jnl
Neural Comput. Appl.
Zhan Gao, Qiguo Hu, Xiangyang Xu
2022 J jnl
Sensors
Xiangyang Xu, Mian Zhao, Peixin Shi, Ruiqi Ren, Xuhui He, Xiaojun Wei, Hao Yang
2022 J jnl
CoRR
Haoran Wei, Xu Liu, Shouchun Xu, Zhongjian Dai, Yaping Dai, Xiangyang Xu
2022 J jnl
Symmetry
Wei Xu, Ming Cheng, Xiangyang Xu, Cheng Chen, Wei Liu
2022 J jnl
Symmetry
Zheyuan Feng, Qi Xu, Xiangyang Xu, Qiang Tang, XueDong Li, Xin Liao
2022 J jnl
Sensors
Hua-Ping Wang, Yi-Bin Wu, Cong Chen, Hu-Yuan Zhang, Hao Jiang, Xue-Mei Zhang, Xiangyang Xu
2022 J jnl
Neurocomputing
Heshan Wang, Yuxi Liu, Peng Lu, Yong Luo, Dongshu Wang, Xiangyang Xu
2022 J jnl
Artif. Intell. Eng. Des. Anal. Manuf.
Wenjuan Li, C. Steve Suh, Xiangyang Xu, Zhenghe Song
2022 J jnl
Sensors
Mian Zhao, Peixin Shi, Xunqian Xu, Xiangyang Xu, Wei Liu, Hao Yang
2022 J jnl
Reliab. Eng. Syst. Saf.
Sajad Saraygord Afshari, Fatemeh Enayatollahi, Xiangyang Xu, Xihui Liang
2022 J jnl
IEEE Trans. Emerg. Top. Comput. Intell.
Yu Zhou, Lianghai Jin, Guangzhi Ma, Xiangyang Xu
2022 J jnl
Symmetry
Jian Yang, Chen Wang, Jichao Yi, Yuankai Du, Maocheng Sun, Sheng Huang, Wenan Zhao, Shuai Qu, Jiasheng Ni, Xiangyang Xu, Ying Shang
2022 J jnl
IEEE Trans. Instrum. Meas.
Sajad Saraygord Afshari, Shihao Cui, Xiangyang Xu, Xihui Liang
2022 J jnl
Sensors
Jianjian Dai, Xiangyang Xu, Hao Yang, Chao Su, Nan Ye
2022 J jnl
J. Adv. Comput. Intell. Intell. Informatics
Shanshan Yuan, Xiangyang Xu
2021 J jnl
Remote. Sens.
Haoran Wei, Xiangyang Xu, Ni Ou, Xinru Zhang, Yaping Dai
2021 J jnl
Symmetry
Wei Liu, Yinlong Wu, Huajing Zhao, Xiangyang Xu, Lingyi Miao
2021 J jnl
IEEE Trans. Medical Imaging
Xiaofei Wang, Lai Jiang, Liu Li, Mai Xu, Xin Deng, Lisong Dai, Xiangyang Xu, Tianyi Li, Yichen Guo, Zulin Wang, Pier Luigi Dragotti
2021 J jnl
Mob. Inf. Syst.
Jiayuan Luo, Xiangyang Xu, Peitang Wei, Chengxiang Shi, Guofeng Liu
2021 J jnl
IEEE Syst. J.
Xudong Shi, Yang Liu, Xiangyang Xu, Tao Jing
2021 J jnl
IEEE Trans. Veh. Technol.
Xiangyang Xu, Xiang Li, Peng Dong, Yue Liu, Hui Zhang
2020 J jnl
IEEE J. Biomed. Health Informatics
Haichao Cao, Hong Liu, Enmin Song, Guangzhi Ma, Xiangyang Xu, Renchao Jin, Tengying Liu, Chih-Cheng Hung
2020 J jnl
Comput. Biol. Medicine
Mengxun Li, Xiangyang Xu, Kumaradevan Punithakumar, Lawrence H. Le, Neelambar R. Kaipatur, Bin Shi
2020 J jnl
Multim. Tools Appl.
Jiaosong Long, Guangzhi Ma, Hong Liu, Enmin Song, Chih-Cheng Hung, Xiangyang Xu, Renchao Jin, Yuzhou Zhuang, DaiYang Liu
2020 J jnl
Appl. Soft Comput.
Haichao Cao, Hong Liu, Enmin Song, Chih-Cheng Hung, Guangzhi Ma, Xiangyang Xu, Renchao Jin, Jianguo Lu
2020 conf
ICCA
Xiang Li, Xiangyang Xu, Hui Zhang, Mingyue Ma
2020 J jnl
J. Digit. Imaging
Hong Liu, Haichao Cao, Enmin Song, Guangzhi Ma, Xiangyang Xu, Renchao Jin, Chuhua Liu, Chih-Cheng Hung
2020 J jnl
Sensors
Chuxuan Zhang, Xinqiang Liang, Yuanyuan Lu, Hua Li, Xiangyang Xu
2020 J jnl
Complex.
Zhan Gao, Qi-guo Hu, Xiangyang Xu
2020 J jnl
Sensors
Xiangyang Xu, Hao Yang
2019 J jnl
Signal Process.
Lianghai Jin, Zhiliang Zhu, Enmin Song, Xiangyang Xu
2019 J jnl
Int. J. Pattern Recognit. Artif. Intell.
Xiangyang Xu, Qiao Chen, Bo Li
2019 J jnl
J. Adv. Comput. Intell. Intell. Informatics
Yanyan Xu, Xiangyang Xu, Rui Yu
2019 J jnl
CoRR
Haichao Cao, Hong Liu, Enmin Song, Chih-Cheng Hung, Guangzhi Ma, Xiangyang Xu, Renchao Jin, Jianguo Lu
2019 J jnl
IEEE Access
Shuhan Wang, Xingshuai Huang, José María López, Xiangyang Xu, Peng Dong
2019 J jnl
Comput. Ind.
Renxiang Chen, Xin Huang, Lixia Yang, Xiangyang Xu, Xia Zhang, Yong Zhang
2019 J jnl
IEEE Access
Haichao Cao, Hong Liu, Enmin Song, Guangzhi Ma, Xiangyang Xu, Renchao Jin, Tengying Liu, Chih-Cheng Hung
2019 J jnl
Appl. Soft Comput.
Wenhua Zhang, Lianghai Jin, Enmin Song, Xiangyang Xu
2019 J jnl
Int. J. Distributed Sens. Networks
Xiangyang Xu, Hao Yang, Boris Kargoll
2019 J jnl
Int. J. Pattern Recognit. Artif. Intell.
Xiangyang Xu, Qiao Chen, Ruixin Xu
2019 J jnl
CoRR
Haichao Cao, Hong Liu, Enmin Song, Guangzhi Ma, Xiangyang Xu, Renchao Jin, Tengying Liu, Chih-Cheng Hung
2018 conf
MaLTeSQuE
Yuanliang Zhang, Shanshan Li, Xiangyang Xu, Xiangke Liao, Shazhou Yang, Yun Xiong
2018 A conf
ICME
Dapeng Du, Xiangyang Xu, Tongwei Ren, Gangshan Wu
2018 conf
PACIS
Xiangyang Xu, Hua Yuan, Yu Qian
2018 conf
MIPR
Yu Wang, Yang Feng, Haofu Liao, Jiebo Luo, Xiangyang Xu
2018 J jnl
Int. J. Model. Simul. Sci. Comput.
Xiangyang Xu, Tianhong Luo, Jiayuan Luo, Xia Hua, Reza Langari
2018 J jnl
J. Adv. Comput. Intell. Intell. Informatics
Rui Yu, Xiangyang Xu, Zhigang Wang
2018 J jnl
Remote. Sens.
Xin Zhao, Boris Kargoll, Mohammad Omidalizarandi, Xiangyang Xu, Hamza Alkhatib
2018 J jnl
Int. J. Distributed Sens. Networks
Xiangyang Xu, Hao Yang
2017 J jnl
Int. J. Imaging Syst. Technol.
Meng Yan, Hong Liu, Xiangyang Xu, Enmin Song, Yuejing Qian, Ning Pan, Renchao Jin, Lianghai Jin, Shaorong Cheng, Chih-Cheng Hung
2017 C conf
SEKE
Xiangyang Xu, Shanshan Li, Yong Guo, Wei Dong, Wang Li, Xiangke Liao
2017 A conf
EASE
Wang Li, Shanshan Li, Xiangke Liao, Xiangyang Xu, Shulin Zhou, Zhouyang Jia
2017 conf
PCM (2)
Dapeng Du, Na Liu, Xiangyang Xu, Gangshan Wu
2017 A conf
EASE
Shulin Zhou, Shanshan Li, Xiaodong Liu, Xiangyang Xu, Si Zheng, Xiangke Liao, Yun Xiong
2017 J jnl
IET Image Process.
Hong Liu, Meng Yan, Enmin Song, Yuejing Qian, Xiangyang Xu, Renchao Jin, Lianghai Jin, Chih-Cheng Hung
2017 J jnl
Neurocomputing
Renxiang Chen, Siyang Chen, Lixia Yang, Jiaxu Wang, Xiangyang Xu, Tianhong Luo
2017 J jnl
Pattern Recognit.
Xiangyang Xu, Yuncheng Li, Gangshan Wu, Jiebo Luo
2017 B conf
ICIP
Lianghai Jin, Min Jin, Xiangyang Xu, Enmin Song
2017 J jnl
J. Sensors
Xiangyang Xu, Xin Zhao, Hao Yang, Ingo Neumann
2017 J jnl
Int. J. Model. Simul. Sci. Comput.
Zeyin He, Tao Deng, Xiangyang Xu
2016 conf
URAI
Shaojiang Dong, Jun Wang, Baoping Tang, Xiangyang Xu, Juan Liu
2016 J jnl
Int. J. Comput. Assist. Radiol. Surg.
Yongchuan Liu, Renchao Jin, Mi Chen, Enmin Song, Xiangyang Xu, Sheng Zhang, Chih-Cheng Hung
2016 J jnl
CoRR
Yu Wang, Haofu Liao, Yang Feng, Xiangyang Xu, Jiebo Luo
2016 J jnl
J. Vis. Commun. Image Represent.
Renchao Jin, Shengrong Zhao, Xiangyang Xu, Enmin Song
2016 J jnl
J. Electronic Imaging
Renchao Jin, Shengrong Zhao, Xiangyang Xu, Enmin Song, Chih-Cheng Hung
2016
Xiangyang Xu
2016 J jnl
Signal Process.
Lianghai Jin, Zhiliang Zhu, Xiangyang Xu, Xiang Li
2015 J jnl
Multim. Tools Appl.
Mali Yu, Enmin Song, Renchao Jin, Hong Liu, Xiangyang Xu, Guangzhi Ma
2015 A conf
ICME
Xiangyang Xu, Ling Ge, Tongwei Ren, Gangshan Wu
2015 conf
MMM (1)
Wenjing Geng, Ran Ju, Xiangyang Xu, Tongwei Ren, Gangshan Wu
2014 J jnl
J. Comput.
Xiangyang Xu, Qiao Chen, Ziqi Zhao, Gang Zhang, Jiang Duan
2014 conf
ICIMCS
Xiangyang Xu, Tongwei Ren, Gangshan Wu
2014 A conf
ICME
Xiangyang Xu, Wenjing Geng, Ran Ju, Yang Yang, Tongwei Ren, Gangshan Wu
2014 J jnl
Sensors
Hao Yang, Xiangyang Xu, Ingo Neumann
2013 J jnl
J. Commun.
Zhou Zhong, Shuming Guo, Xiangyang Xu, Huiqing Bai
2013 conf
PCM
Ran Ju, Yang Yang, Xiangyang Xu, Chunrong Xia, Gangshan Wu
2013 J jnl
Medical Image Anal.
Yuan Zhou, Xinyao Cheng, Xiangyang Xu, Enmin Song
2013 J jnl
IEEE Trans. Circuits Syst. Video Technol.
Lianghai Jin, Hong Liu, Xiangyang Xu, Enmin Song
2013 conf
HPCC/EUC
Qiang Gu, Liufei Wen, Fen Dai, Hao Gong, Yongqiang Yang, Xiangyang Xu, Zexi Feng
2013 conf
PCM
Ran Ju, Xiangyang Xu, Yang Yang, Gangshan Wu
2013 J jnl
Signal Process.
Lei Li, Lianghai Jin, Xiangyang Xu, Enmin Song
2013 conf
HPCC/EUC
Huakang Li, Longbin Lai, Xiaofeng Xu, Yao Shen, Xiangyang Xu, Chunrong Xia
2012 J jnl
Pattern Recognit.
Lianghai Jin, Hong Liu, Xiangyang Xu, Enmin Song
2012 J jnl
Comput. Medical Imaging Graph.
Xiangyang Xu, Yuan Zhou, Xinyao Cheng, Enmin Song, Guokuan Li
2011 J jnl
Pattern Recognit. Lett.
Xiangyang Xu, Shengzhou Xu, Lianghai Jin, Enmin Song
2011 J jnl
Signal Process.
Lianghai Jin, Hong Liu, Xiangyang Xu, Enmin Song
2011 J jnl
J. Comput.
Li-hong Li, Xiangyang Xu, Yanfang Liu, Qianjin Guo, Xiaoli Li
2011 Misc conf
SAC
Huaifei Hu, Hong Liu, Lili Chen, Chih-Cheng Hung, Xiangyang Xu, Zhicong Lan
2010 Misc conf
ICNC
Li-hong Li, Xiangyang Xu, Fen-zhu Ji, Yanfang Liu, Xiaoli Li
2010 conf
FSKD
Pengxiang Tang, Shuhan Wang, Yanfang Liu, Xiangyang Xu
2010 J jnl
J. Electronic Imaging
Lianghai Jin, Hong Liu, Xiangyang Xu, Enmin Song
2010 conf
BIC-TA
Xiangyang Xu, Shengzhou Xu, Lianghai Jin, Shenyi Zhang
2009 J jnl
J. Am. Medical Informatics Assoc.
Jian Hu, Hao Yu, En Luo, Enmin Song, Xiangyang Xu, Hongbao Tan, Yining Wang
2009 conf
BMEI
Xiangyang Xu
2009 J jnl
Int. J. Medical Informatics
Jian Hu, En Luo, Enmin Song, Xiangyang Xu, Hongbao Tan, Yi Zhao, Yining Wang, Zhiyong Li
2008 B conf
Image Processing
Renchao Jin, Enmin Song, Lijuan Zhang, Zhifang Min, Xiangyang Xu, Chih-Cheng Huang
2007 B conf
Image Processing
Enmin Song, Renchao Jin, Yu Luo, Xiangyang Xu, Chih-Cheng Hung, Jianqiang Du
2007 conf
Computer-Aided Diagnosis
Renchao Jin, Bo Meng, Enmin Song, Xiangyang Xu, Luan Jiang
2007 Misc conf
SAC
Enmin Song, Luan Jiang, Bo Meng, Renchao Jin, Xiangyang Xu, Chih-Cheng Hung
2007 C conf
IV
Hovhannes A. Harutyunyan, Xiangyang Xu
2006 B conf
Image Processing
Renchao Jin, Lijuan Zhang, Bo Meng, Enmin Song, Xiangyang Xu, Chih-Cheng Hung
2006 B conf
SMC
Yaping Dai, Qingjie Liu, Xiangyang Xu, Zheng Liu, Fangyan Dong, Kaoru Hirota
tests/unit/test_apk_process_method.py
← Index tests/unit/test_apk_process_method.py python
"""Mock-based tests for APKCodeAnalyzer._process_method and androguard integration.

Tests the boundary between our code and androguard objects, covering:
- xref extraction (get_xref_from / get_xref_to) for both 4.x and 3.x APIs
- external method skipping
- library method filtering
- smali lookup and androguard fallback disassembly
- deduplication of content hashes
- full output population (all result dict keys)
- minimum instruction filtering
"""
from dataclasses import dataclass
from typing import List
from unittest.mock import MagicMock, Mock, patch, PropertyMock

import pytest

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


# ---------------------------------------------------------------------------
# Helpers: build mock androguard objects
# ---------------------------------------------------------------------------

SAMPLE_SMALI_BODY = """\
.locals 2
const/4 v0, 0x0
invoke-virtual {p0, v0}, Lcom/example/Foo;->bar(I)V
iget-object v1, p0, Lcom/example/Foo;->name:Ljava/lang/String;
add-int v0, v0, v1
return-void
"""

SAMPLE_JAVA_SOURCE = """\
public void doStuff() {
    int x = 0;
    bar(x);
    String n = this.name;
    x = x + n;
}
"""


def _make_encoded_method(
    class_name="Lcom/example/Foo;",
    method_name="doStuff",
    descriptor="()V",
    code=None,
):
    """Create a mock EncodedMethod."""
    enc = MagicMock()
    enc.get_class_name.return_value = class_name
    enc.get_name.return_value = method_name
    enc.get_descriptor.return_value = descriptor
    enc.get_code.return_value = code
    return enc


def _make_xref_entry_4x(class_name, method_name, offset=0):
    """Create a mock xref tuple in androguard 4.x format.

    4.x: (ClassAnalysis, MethodAnalysis, offset)
    MethodAnalysis has .get_method() returning the EncodedMethod.
    """
    ref_class = MagicMock()
    ref_method = MagicMock()
    inner_enc = MagicMock()
    inner_enc.get_class_name.return_value = class_name
    inner_enc.get_name.return_value = method_name
    ref_method.get_method.return_value = inner_enc
    # Remove direct get_class_name/get_name to simulate 4.x behavior
    del ref_method.get_class_name
    del ref_method.get_name
    return (ref_class, ref_method, offset)


def _make_xref_entry_3x(class_name, method_name, offset=0):
    """Create a mock xref tuple in androguard 3.x format.

    3.x: (ClassAnalysis, EncodedMethod, offset)
    EncodedMethod has .get_class_name() and .get_name() directly.
    """
    ref_class = MagicMock()
    ref_method = MagicMock(spec=[
        "get_class_name", "get_name",
    ])
    ref_method.get_class_name.return_value = class_name
    ref_method.get_name.return_value = method_name
    return (ref_class, ref_method, offset)


def _make_method_analysis(
    encoded=None,
    is_external=False,
    xref_from=None,
    xref_to=None,
):
    """Create a mock MethodAnalysis."""
    method = MagicMock()
    method.is_external.return_value = is_external
    method.get_method.return_value = encoded or _make_encoded_method()
    method.get_xref_from.return_value = xref_from or []
    method.get_xref_to.return_value = xref_to or []
    return method


def _make_analyzer(min_instructions=1):
    """Create an APKCodeAnalyzer with mocked dependencies."""
    with patch(
        "redb.extractors.decompiler.apk.analyzer.JADXDecompiler"
    ), patch(
        "redb.extractors.decompiler.apk.analyzer.ApktoolDisassembler"
    ):
        from redb.extractors.decompiler.apk.analyzer import APKCodeAnalyzer
        analyzer = APKCodeAnalyzer("/fake/path.apk")
        analyzer.min_instructions = min_instructions
        analyzer.library_filter = MagicMock()
        analyzer.library_filter.is_library.return_value = False
        return analyzer


def _empty_results():
    """Create a fresh empty results dict."""
    return {
        "decompiled_content": [],
        "decompiled_refs": [],
        "smali_content": [],
        "smali_refs": [],
        "similarity_metrics": [],
        "cfg": [],
        "analysis_errors": [],
    }


def _make_smali_method(body=SAMPLE_SMALI_BODY, instruction_count=5):
    """Create a mock SmaliMethod."""
    m = MagicMock()
    m.body = body
    m.instruction_count = instruction_count
    m.register_count = 2
    return m


# ---------------------------------------------------------------------------
# Tests: xref extraction
# ---------------------------------------------------------------------------

class TestXrefExtraction:
    """Tests that xrefs are correctly extracted from androguard objects."""

    def test_xref_from_androguard_4x(self):
        """4.x: ref_method.get_method().get_class_name() path."""
        analyzer = _make_analyzer()
        results = _empty_results()
        method_key = "Lcom/example/Foo;->doStuff()V"

        xref_from = [
            _make_xref_entry_4x("Lcom/example/Caller;", "init", 42),
            _make_xref_entry_4x("Lcom/example/Other;", "run", 100),
        ]
        method = _make_method_analysis(xref_from=xref_from)

        smali_methods = {method_key: _make_smali_method()}
        java_methods = {"com.example.Foo.doStuff": SAMPLE_JAVA_SOURCE}

        analyzer._process_method(
            method, smali_methods, java_methods,
            results, set(), set(),
        )

        assert len(results["decompiled_refs"]) == 1
        ref = results["decompiled_refs"][0]
        assert ref["functions_caller"] == [
            "Lcom/example/Caller;->init",
            "Lcom/example/Other;->run",
        ]

    def test_xref_to_androguard_4x(self):
        """4.x: callees extracted via get_method() unwrap."""
        analyzer = _make_analyzer()
        results = _empty_results()
        method_key = "Lcom/example/Foo;->doStuff()V"

        xref_to = [
            _make_xref_entry_4x("Lcom/example/Dep;", "calculate", 10),
        ]
        method = _make_method_analysis(xref_to=xref_to)

        smali_methods = {method_key: _make_smali_method()}
        java_methods = {"com.example.Foo.doStuff": SAMPLE_JAVA_SOURCE}

        analyzer._process_method(
            method, smali_methods, java_methods,
            results, set(), set(),
        )

        ref = results["decompiled_refs"][0]
        assert ref["functions_call"] == ["Lcom/example/Dep;->calculate"]

    def test_xref_from_androguard_3x_fallback(self):
        """3.x: ref_method.get_class_name() direct access fallback."""
        analyzer = _make_analyzer()
        results = _empty_results()
        method_key = "Lcom/example/Foo;->doStuff()V"

        xref_from = [
            _make_xref_entry_3x("Lcom/example/OldCaller;", "legacy"),
        ]
        method = _make_method_analysis(xref_from=xref_from)

        smali_methods = {method_key: _make_smali_method()}
        java_methods = {"com.example.Foo.doStuff": SAMPLE_JAVA_SOURCE}

        analyzer._process_method(
            method, smali_methods, java_methods,
            results, set(), set(),
        )

        ref = results["decompiled_refs"][0]
        assert ref["functions_caller"] == ["Lcom/example/OldCaller;->legacy"]

    def test_xref_to_androguard_3x_fallback(self):
        """3.x: callees via direct access fallback."""
        analyzer = _make_analyzer()
        results = _empty_results()
        method_key = "Lcom/example/Foo;->doStuff()V"

        xref_to = [
            _make_xref_entry_3x("Lcom/example/OldDep;", "compute"),
        ]
        method = _make_method_analysis(xref_to=xref_to)

        smali_methods = {method_key: _make_smali_method()}
        java_methods = {"com.example.Foo.doStuff": SAMPLE_JAVA_SOURCE}

        analyzer._process_method(
            method, smali_methods, java_methods,
            results, set(), set(),
        )

        ref = results["decompiled_refs"][0]
        assert ref["functions_call"] == ["Lcom/example/OldDep;->compute"]

    def test_empty_xrefs(self):
        """No xrefs produces empty lists, not None."""
        analyzer = _make_analyzer()
        results = _empty_results()
        method_key = "Lcom/example/Foo;->doStuff()V"

        method = _make_method_analysis()
        smali_methods = {method_key: _make_smali_method()}
        java_methods = {"com.example.Foo.doStuff": SAMPLE_JAVA_SOURCE}

        analyzer._process_method(
            method, smali_methods, java_methods,
            results, set(), set(),
        )

        ref = results["decompiled_refs"][0]
        assert ref["functions_caller"] == []
        assert ref["functions_call"] == []

    def test_xref_exception_does_not_crash(self):
        """If get_xref_from() itself throws, method still processes."""
        analyzer = _make_analyzer()
        results = _empty_results()
        method_key = "Lcom/example/Foo;->doStuff()V"

        method = _make_method_analysis()
        method.get_xref_from.side_effect = RuntimeError("xref table corrupt")
        method.get_xref_to.side_effect = RuntimeError("xref table corrupt")

        smali_methods = {method_key: _make_smali_method()}
        java_methods = {"com.example.Foo.doStuff": SAMPLE_JAVA_SOURCE}

        analyzer._process_method(
            method, smali_methods, java_methods,
            results, set(), set(),
        )

        # Method should still be processed with empty xrefs
        assert len(results["smali_refs"]) == 1
        ref = results["decompiled_refs"][0]
        assert ref["functions_caller"] == []
        assert ref["functions_call"] == []

    def test_multiple_xrefs(self):
        """Multiple callers and callees are all captured."""
        analyzer = _make_analyzer()
        results = _empty_results()
        method_key = "Lcom/example/Foo;->doStuff()V"

        xref_from = [
            _make_xref_entry_4x("Lcom/A;", "a1"),
            _make_xref_entry_4x("Lcom/B;", "b1"),
            _make_xref_entry_4x("Lcom/C;", "c1"),
        ]
        xref_to = [
            _make_xref_entry_4x("Lcom/D;", "d1"),
            _make_xref_entry_4x("Lcom/E;", "e1"),
        ]
        method = _make_method_analysis(xref_from=xref_from, xref_to=xref_to)

        smali_methods = {method_key: _make_smali_method()}
        java_methods = {"com.example.Foo.doStuff": SAMPLE_JAVA_SOURCE}

        analyzer._process_method(
            method, smali_methods, java_methods,
            results, set(), set(),
        )

        ref = results["decompiled_refs"][0]
        assert len(ref["functions_caller"]) == 3
        assert len(ref["functions_call"]) == 2


# ---------------------------------------------------------------------------
# Tests: method filtering and skipping
# ---------------------------------------------------------------------------

class TestMethodFiltering:
    """Tests for external/library/min-instruction filtering."""

    def test_external_method_skipped(self):
        """External methods (no code body) produce no output."""
        analyzer = _make_analyzer()
        results = _empty_results()

        method = _make_method_analysis(is_external=True)

        analyzer._process_method(
            method, {}, {}, results, set(), set(),
        )

        assert all(len(v) == 0 for v in results.values())

    def test_library_method_skipped(self):
        """Library methods produce no output."""
        analyzer = _make_analyzer()
        analyzer.library_filter.is_library.return_value = True
        results = _empty_results()

        method = _make_method_analysis()

        analyzer._process_method(
            method, {}, {}, results, set(), set(),
        )

        assert all(len(v) == 0 for v in results.values())

    def test_min_instruction_filter(self):
        """Methods below min_instructions threshold are skipped."""
        analyzer = _make_analyzer(min_instructions=10)
        results = _empty_results()
        method_key = "Lcom/example/Foo;->doStuff()V"

        method = _make_method_analysis()
        # Only 3 instructions — below threshold of 10
        smali_methods = {method_key: _make_smali_method(instruction_count=3)}

        analyzer._process_method(
            method, smali_methods, {}, results, set(), set(),
        )

        assert all(len(v) == 0 for v in results.values())

    def test_method_above_min_instructions_processed(self):
        """Methods at or above threshold are processed."""
        analyzer = _make_analyzer(min_instructions=5)
        results = _empty_results()
        method_key = "Lcom/example/Foo;->doStuff()V"

        method = _make_method_analysis()
        smali_methods = {method_key: _make_smali_method(instruction_count=5)}

        analyzer._process_method(
            method, smali_methods, {}, results, set(), set(),
        )

        assert len(results["smali_content"]) == 1
        assert len(results["smali_refs"]) == 1


# ---------------------------------------------------------------------------
# Tests: smali body lookup and androguard fallback
# ---------------------------------------------------------------------------

class TestSmaliLookup:
    """Tests for smali body lookup from apktool and androguard fallback."""

    def test_apktool_smali_used_when_available(self):
        """When apktool smali is available, it's used."""
        analyzer = _make_analyzer()
        results = _empty_results()
        method_key = "Lcom/example/Foo;->doStuff()V"

        method = _make_method_analysis()
        smali_methods = {method_key: _make_smali_method()}

        analyzer._process_method(
            method, smali_methods, {}, results, set(), set(),
        )

        assert len(results["smali_content"]) == 1
        assert results["smali_content"][0]["smali_method"] == SAMPLE_SMALI_BODY

    def test_androguard_fallback_when_no_apktool(self):
        """When apktool smali is missing, _disassemble_with_androguard is used."""
        analyzer = _make_analyzer()
        results = _empty_results()

        # Create encoded method with code
        instruction1 = MagicMock()
        instruction1.get_name.return_value = "const/4"
        instruction1.get_output.return_value = "v0, 0x0"
        instruction2 = MagicMock()
        instruction2.get_name.return_value = "invoke-virtual"
        instruction2.get_output.return_value = "v0, Lcom/Foo;->bar()V"
        instruction3 = MagicMock()
        instruction3.get_name.return_value = "add-int"
        instruction3.get_output.return_value = "v0, v1, v2"
        instruction4 = MagicMock()
        instruction4.get_name.return_value = "sub-int"
        instruction4.get_output.return_value = "v3, v0, v1"
        instruction5 = MagicMock()
        instruction5.get_name.return_value = "return-void"
        instruction5.get_output.return_value = ""

        code = MagicMock()
        code.get_registers_size.return_value = 4
        bytecode = MagicMock()
        bytecode.get_instructions.return_value = [
            instruction1, instruction2, instruction3, instruction4, instruction5,
        ]
        code.get_bc.return_value = bytecode

        encoded = _make_encoded_method(code=code)
        method = _make_method_analysis(encoded=encoded)

        # Empty smali_methods — forces androguard fallback
        analyzer._process_method(
            method, {}, {}, results, set(), set(),
        )

        assert len(results["smali_content"]) == 1
        body = results["smali_content"][0]["smali_method"]
        assert "const/4" in body
        assert "return-void" in body

    def test_androguard_fallback_no_code(self):
        """When encoded method has no code, method is skipped."""
        analyzer = _make_analyzer()
        results = _empty_results()

        encoded = _make_encoded_method(code=None)
        method = _make_method_analysis(encoded=encoded)

        analyzer._process_method(
            method, {}, {}, results, set(), set(),
        )

        assert all(len(v) == 0 for v in results.values())

    def test_androguard_fallback_bytecode_exception(self):
        """When bytecode iteration throws, method is skipped gracefully."""
        analyzer = _make_analyzer()
        results = _empty_results()

        code = MagicMock()
        code.get_registers_size.return_value = 2
        bytecode = MagicMock()
        bytecode.get_instructions.side_effect = RuntimeError("bad bytecode")
        code.get_bc.return_value = bytecode

        encoded = _make_encoded_method(code=code)
        method = _make_method_analysis(encoded=encoded)

        analyzer._process_method(
            method, {}, {}, results, set(), set(),
        )

        # Should not crash, but no content produced
        assert len(results["smali_content"]) == 0


# ---------------------------------------------------------------------------
# Tests: output population and deduplication
# ---------------------------------------------------------------------------

class TestOutputPopulation:
    """Tests that all result dict keys are correctly populated."""

    def _process_standard_method(self, with_java=True):
        """Helper: process a standard method and return results."""
        analyzer = _make_analyzer()
        results = _empty_results()
        method_key = "Lcom/example/Foo;->doStuff()V"

        xref_from = [_make_xref_entry_4x("Lcom/Caller;", "call")]
        xref_to = [_make_xref_entry_4x("Lcom/Dep;", "dep")]
        method = _make_method_analysis(
            xref_from=xref_from, xref_to=xref_to
        )

        smali_methods = {method_key: _make_smali_method()}
        java_methods = {}
        if with_java:
            java_methods = {"com.example.Foo.doStuff": SAMPLE_JAVA_SOURCE}

        analyzer._process_method(
            method, smali_methods, java_methods,
            results, set(), set(),
        )
        return results

    def test_smali_content_populated(self):
        results = self._process_standard_method()
        assert len(results["smali_content"]) == 1
        entry = results["smali_content"][0]
        assert "smali_method_hash" in entry
        assert entry["smali_method"] == SAMPLE_SMALI_BODY
        assert entry["smali_method_type"] == "USER"
        assert entry["smali_instructions_count"] == 5
        assert isinstance(entry["smali_has_string_encryption"], bool)
        assert isinstance(entry["smali_has_reflection_calls"], bool)
        assert isinstance(entry["smali_excessive_goto_count"], bool)

    def test_smali_refs_populated(self):
        results = self._process_standard_method()
        assert len(results["smali_refs"]) == 1
        ref = results["smali_refs"][0]
        assert "smali_method_hash" in ref
        assert ref["smali_class_name"] == "com.example.Foo"
        assert ref["smali_method_name"] == "doStuff"
        assert ref["smali_method_signature"] == "()V"

    def test_decompiled_content_populated_with_java(self):
        results = self._process_standard_method(with_java=True)
        assert len(results["decompiled_content"]) == 1
        entry = results["decompiled_content"][0]
        assert "decompiled_method_hash" in entry
        assert entry["decompiled_method"] == SAMPLE_JAVA_SOURCE

    def test_decompiled_refs_populated_with_java(self):
        results = self._process_standard_method(with_java=True)
        assert len(results["decompiled_refs"]) == 1
        ref = results["decompiled_refs"][0]
        assert "decompiled_method_hash" in ref
        assert "smali_method_hash" in ref
        assert ref["decompiled_class_name"] == "com.example.Foo"
        assert ref["decompiled_method_name"] == "doStuff"
        assert "decompiled_method_prototype" in ref
        assert ref["functions_caller"] == ["Lcom/Caller;->call"]
        assert ref["functions_call"] == ["Lcom/Dep;->dep"]

    def test_no_decompiled_without_java(self):
        results = self._process_standard_method(with_java=False)
        assert len(results["decompiled_content"]) == 0
        assert len(results["decompiled_refs"]) == 0
        # Smali should still be there
        assert len(results["smali_content"]) == 1

    def test_similarity_metrics_populated(self):
        results = self._process_standard_method()
        assert len(results["similarity_metrics"]) == 1
        sim = results["similarity_metrics"][0]
        assert "smali_method_hash" in sim
        assert "cyclomatic_complexity" in sim
        assert "minhash" in sim
        assert isinstance(sim["minhash"], list)
        # block_count moved to cfg table
        assert "block_count" not in sim

    def test_cfg_entry_populated(self):
        results = self._process_standard_method()
        assert len(results["cfg"]) == 1
        cfg = results["cfg"][0]
        assert "smali_method_hash" in cfg
        assert "block_count" in cfg
        assert "cfg_topology_hash" in cfg
        assert "prime_product_smali" in cfg
        assert "wl_minhash" in cfg
        assert "bb_features" in cfg
        assert isinstance(cfg["bb_features"], list)
        for feat in cfg["bb_features"]:
            assert len(feat) == 8

    def test_smali_deduplication(self):
        """Same smali body processed twice produces one content entry."""
        analyzer = _make_analyzer()
        results = _empty_results()
        method_key = "Lcom/example/Foo;->doStuff()V"
        seen_smali = set()

        method = _make_method_analysis()
        smali_methods = {method_key: _make_smali_method()}

        # Process same method twice
        analyzer._process_method(
            method, smali_methods, {}, results, set(), seen_smali,
        )
        analyzer._process_method(
            method, smali_methods, {}, results, set(), seen_smali,
        )

        # Content deduplicated, but refs are per-call
        assert len(results["smali_content"]) == 1
        assert len(results["smali_refs"]) == 2

    def test_decompiled_deduplication(self):
        """Same Java source processed twice produces one content entry."""
        analyzer = _make_analyzer()
        results = _empty_results()
        method_key = "Lcom/example/Foo;->doStuff()V"
        seen_decompiled = set()
        seen_smali = set()

        method = _make_method_analysis()
        smali_methods = {method_key: _make_smali_method()}
        java_methods = {"com.example.Foo.doStuff": SAMPLE_JAVA_SOURCE}

        analyzer._process_method(
            method, smali_methods, java_methods,
            results, seen_decompiled, seen_smali,
        )
        analyzer._process_method(
            method, smali_methods, java_methods,
            results, seen_decompiled, seen_smali,
        )

        assert len(results["decompiled_content"]) == 1
        assert len(results["decompiled_refs"]) == 2


# ---------------------------------------------------------------------------
# Tests: _disassemble_with_androguard
# ---------------------------------------------------------------------------

class TestDisassembleWithAndroguard:
    """Tests for the androguard bytecode disassembly fallback."""

    def test_no_code_returns_none(self):
        from redb.extractors.decompiler.apk.analyzer import APKCodeAnalyzer
        encoded = _make_encoded_method(code=None)
        body, count, regs = APKCodeAnalyzer._disassemble_with_androguard(encoded)
        assert body is None
        assert count == 0
        assert regs == 0

    def test_no_bytecode_returns_none(self):
        from redb.extractors.decompiler.apk.analyzer import APKCodeAnalyzer
        code = MagicMock()
        code.get_registers_size.return_value = 3
        code.get_bc.return_value = None
        encoded = _make_encoded_method(code=code)

        body, count, regs = APKCodeAnalyzer._disassemble_with_androguard(encoded)
        assert body is None
        assert count == 0
        assert regs == 3

    def test_basic_disassembly(self):
        from redb.extractors.decompiler.apk.analyzer import APKCodeAnalyzer

        instructions = []
        for name, output in [
            ("const/4", "v0, 0x0"),
            ("invoke-virtual", "v0, Lcom/Foo;->bar()V"),
            ("return-void", ""),
        ]:
            instr = MagicMock()
            instr.get_name.return_value = name
            instr.get_output.return_value = output
            instructions.append(instr)

        code = MagicMock()
        code.get_registers_size.return_value = 2
        bytecode = MagicMock()
        bytecode.get_instructions.return_value = instructions
        code.get_bc.return_value = bytecode

        encoded = _make_encoded_method(code=code)
        body, count, regs = APKCodeAnalyzer._disassemble_with_androguard(encoded)

        assert body is not None
        assert count == 3
        assert regs == 2
        assert "const/4" in body
        assert "return-void" in body

    def test_invoke_operands_normalized(self):
        """Androguard invoke output gets braces added around registers."""
        from redb.extractors.decompiler.apk.analyzer import APKCodeAnalyzer

        instr = MagicMock()
        instr.get_name.return_value = "invoke-virtual"
        # Androguard format: no braces
        instr.get_output.return_value = "v0, v1, Lcom/Foo;->bar(I)V"

        code = MagicMock()
        code.get_registers_size.return_value = 2
        bytecode = MagicMock()
        bytecode.get_instructions.return_value = [instr]
        code.get_bc.return_value = bytecode

        encoded = _make_encoded_method(code=code)
        body, count, regs = APKCodeAnalyzer._disassemble_with_androguard(encoded)

        # Should be normalized to apktool format with braces
        assert "{v0, v1}" in body

    def test_bytecode_exception_returns_none(self):
        from redb.extractors.decompiler.apk.analyzer import APKCodeAnalyzer

        code = MagicMock()
        code.get_registers_size.return_value = 2
        bytecode = MagicMock()
        bytecode.get_instructions.side_effect = RuntimeError("corrupt")
        code.get_bc.return_value = bytecode

        encoded = _make_encoded_method(code=code)
        body, count, regs = APKCodeAnalyzer._disassemble_with_androguard(encoded)

        assert body is None
        assert regs == 2