Xia Wu

131 papers A* 2A 2B 3C 4Journal 81Unranked 38
YearRankTypeTitle / Venue / Authors
2026 J jnl
Pattern Recognit.
Jia Wan, Ziquan Liu, Junyu Gao, Xia Wu, Antoni B. Chan
2026 J jnl
IEEE Trans. Green Commun. Netw.
Na Lin, Xia Wu, Ammar Hawbani, Ammar Muthanna, Liang Zhao
2026 J jnl
Expert Syst. Appl.
Dong Bai, Zhonghao Chang, Zhuozhao Zheng, Xia Wu, Yicheng Li, Runze Li, Yulong Liu, Tongjun Wang
2026 J jnl
Biomed. Signal Process. Control.
Xiangcun Wang, Chuncheng Liao, Xia Wu, Jiacai Zhang
2026 J jnl
Finite Fields Their Appl.
Haojie Xu, Xia Wu, Wei Lu, Xiwang Cao
2026 J jnl
Adv. Eng. Informatics
Junfei Zhang, Fei Hui, Yiming Ye, Xia Wu, Xiangmo Zhao, Zhiwen Tong
2026 J jnl
CoRR
Yiwei Qin, Yixiu Liu, Tiantian Mi, Muhang Xie, Zhen Huang, Weiye Si, Pengrui Lu, Siyuan Feng, Xia Wu, Liming Liu, Ye Luo, Jinlong Hou, Qipeng Guo, Yu Qiao, Pengfei Liu
2025 J jnl
IEEE Internet Things J.
Jianhu Liu, Xia Wu, Ping Wang
2025 J jnl
Adv. Math. Commun.
Furong Bao, Zhengchun Zhou, Shixin Zhu, Xia Wu
2025 J jnl
Symmetry
Hangyu Hu, Liangrui Zhang, Zhaoyu Zhang, Xingmiao Yao, Xia Wu
2025 conf
ICBBS
Xia Wu
2025 A* conf
IJCAI
Xiaxin Wang, Haoyu Cai, Xiaobo Shen, Xia Wu
2025 J jnl
CoRR
Juexiao Zhou, Zhongyi Han, Mankun Xin, Xingwei He, Guotao Wang, Jiaoyan Song, Gongning Luo, Wenjia He, Xintong Li, Yuetan Chu, Juanwen Chen, Bo Wang, Xia Wu, Wenwen Duan, Zhixia Guo, Liyan Bai, Yilin Pan, Xuefei Bi, Lu Liu, Long Feng, Xiaonan He, Xin Gao
2025 J jnl
IEEE Trans. Instrum. Meas.
Xia Wu, Xu Yang, Jian Huang, Jingjing Gao, Jiarui Cui, Qing Li
2025 J jnl
NeuroImage
Chaohong Gao, Xia Wu, Liang Ma, Deying Li, Yufan Wang, Changlu Guo, Wen Li, Haiyan Wang, Congying Chu, Kristoffer Hougaard Madsen, Lingzhong Fan
2025 J jnl
CoRR
Yang Xiao, Mohan Jiang, Jie Sun, Keyu Li, Jifan Lin, Yumin Zhuang, Ji Zeng, Shijie Xia, Qishuo Hua, Xuefeng Li, Xiaojie Cai, Tongyu Wang, Yue Zhang, Liming Liu, Xia Wu, Jinlong Hou, Yuan Cheng, Wenjie Li, Xiang Wang, Dequan Wang, Pengfei Liu
2025 A conf
RecSys
Boyuan Long, Yueqi Wang, Hiloni Mehta, Mick Zomnir, Omkar Pathak, Changping Meng, Ruolin Jia, Yajun Peng, Dapeng Hong, Xia Wu, Mingyan Gao, Onkar Dalal, Ningren Han
2025 J jnl
CoRR
Boyuan Long, Yueqi Wang, Hiloni Mehta, Mick Zomnir, Omkar Pathak, Changping Meng, Ruolin Jia, Yajun Peng, Dapeng Hong, Xia Wu, Mingyan Gao, Onkar Dalal, Ningren Han
2025 J jnl
IEEE Trans. Geosci. Remote. Sens.
Mi Jiang, Xin Tian, Zhiwei Li, Xia Wu, Zhou Wu
2025 J jnl
CoRR
Jiyuan Wang, Li Zhang, Haipeng Lin, Qile Liu, Gan Huang, Ziyu Li, Zhen Liang, Xia Wu
2025 J jnl
CoRR
Boheng Liu, Ziyu Li, Xia Wu
2025 J jnl
IEEE J. Sel. Top. Appl. Earth Obs. Remote. Sens.
Xin Tian, Xia Wu, Hanwen Yu, Mi Jiang
2025 J jnl
Concurr. Comput. Pract. Exp.
Xia Wu, Zehan Li, Yong Wang, Qing Zhao, Ke Wang, Hangyu Hu
2025 conf
MICCAI (3)
Ziyu Li, Zhiyuan Zhu, Yang Bai, Qing Li, Xia Wu
2025 J jnl
Reliab. Eng. Syst. Saf.
Xia Wu, Zhiwen Liu, Lei Wang
2025 J jnl
IEEE Trans. Inf. Theory
Haojie Xu, Xia Wu, Wei Lu, Xiwang Cao
2024 C conf
IGARSS
Xin Tian, Xia Wu, Mi Jiang
2024 conf
APWeb/WAIM (2)
Xia Wu, Shaoqing Wang, Yao Zhang
2024 J jnl
Trans. Inst. Meas. Control
Yinghao Zhao, Xu Yang, Jian Huang, Xia Wu, Jiarui Cui
2024 conf
DSC
Xia Wu, Zehan Li, Zijun Hu, Qing Zhao, Hangyu Hu
2024 J jnl
NeuroImage
Xuyun Wen, Mengting Yang, Shile Qi, Xia Wu, Daoqiang Zhang
2024 conf
ICPRAI (2)
Tianyuan Jia, Chaoqiong Fan, Qixin Wang, Yuyang Han, Xia Wu
2024 conf
ASCC
Zikang Xu, Guochuan Yu, Wenying Xu, Xia Wu
2024 J jnl
Remote. Sens.
Xia Wu, Peijuan Wang, Yanduo Gong, Yuanda Zhang, Qi Wang, Yang Li, Jianping Guo, Shuxin Han
2024 conf
BICS (2)
Shanlin Xi, Ziyu Li, Xia Wu
2024 J jnl
Internet Res.
Kai Zhang, Hefu Liu, Yang Li, Xia Wu
2024 A* conf
AAAI
Qixin Wang, Chaoqiong Fan, Tianyuan Jia, Yuyang Han, Xia Wu
2024 conf
CNIOT
Xia Wu, Hua Deng, Lina Bao, Haoyi Cui, Wei Liu
2024 J jnl
J. Syst. Control. Eng.
Xia Wu, Xu Yang, Jian Huang, Kaixiang Peng
2024 J jnl
Technol. Anal. Strateg. Manag.
Xin He, Xia Wu
2024 J jnl
Comput. Electron. Agric.
Zhicheng Gu, Xiaodan Ma, Haiou Guan, Qiu Jiang, Haotian Deng, Bowen Wen, Tianyu Zhu, Xia Wu
2023 J jnl
Comput. Electron. Agric.
Tianyu Zhu, Xiaodan Ma, Haiou Guan, Xia Wu, Feiyi Wang, Chen Yang, Qiu Jiang
2023 J jnl
Knowl. Based Syst.
Guang Yang, Xia Wu, Jing Zhang
2023 J jnl
Comput. Electron. Agric.
Tianyu Zhu, Xiaodan Ma, Haiou Guan, Xia Wu, Feiyi Wang, Chen Yang, Qiu Jiang
2023 J jnl
Biomed. Signal Process. Control.
Min Hu, Xia Wu, Xiaohua Wang, Yan Xing, Ning An, Piao Shi
2023 J jnl
Ind. Manag. Data Syst.
Xia Wu, Yang Li, Zujun Zhu
2023 conf
ADMA (1)
Keke Li, Shaoqing Wang, Shun Zheng, Xia Wu, Yao Zhang, Fuzhen Sun
2023 J jnl
Neurocomputing
Chao Xu, Xia Wu, Mengmeng Wang, Feng Qiu, Yong Liu, Jun Ren
2023 J jnl
Inf. Technol. People
Tianyi Ma, Xia Wu, Yang Li
2023 J jnl
Trans. Inst. Meas. Control
Xia Wu, Shibin Luo, Caisheng Wei, Likuan Qiu
2023 J jnl
Neurocomputing
Wenqi Yang, Yansu Wang, Chang Tang, Hengjian Tong, Ao Wei, Xia Wu
2023 J jnl
Expert Syst. Appl.
Xia Wu, Yingbo Liu, Xiaoming Zhao, Jingsi Chen
2022 conf
ICSPCC
Ming-Jiu Lv, Jun Yang, Ming Zhou, Xia Wu, Jianchao Ma, Li Chen
2022 conf
CSSE
Xia Wu, Sheng Lin
2022 J jnl
J. Inf. Process. Syst.
Cunli Mao, Zhibo Man, Zhengtao Yu, Xia Wu, Haoyuan Liang
2022 J jnl
IEEE Access
Cong Wang, Jihang Zhao, Xia Wu, Wenfeng Ma, Hui Tian, Qiong Yu, Hanyi Shi, Yuanxiang Yao, Xiangyu Hao
2022 J jnl
Ind. Manag. Data Syst.
Xia Wu, Yang Li, Hefu Liu, Kai Zhang
2022 J jnl
Quantum Inf. Process.
Xia Wu, Ya-Feng Jiao, Shao-Peng Jia, Ji Zhang, Cui-Lu Zhai, Le-Man Kuang
2022 J jnl
Complex.
Yanping Bao, Chan Lyu, Xia Wu, Jun Lian
2022 J jnl
Quantum Inf. Process.
Hui-Min Chen, Heng-Yue Jia, Xia Wu, Han-Xiao Kong, Xiu-Li Wang
2022 J jnl
Quantum Inf. Process.
Yi-Han Tang, Heng-Yue Jia, Xia Wu, Hui-Min Chen, Yan-Mei Zhang
2022 J jnl
Ecol. Informatics
Bangning Fu, Jinfang Liu, Jianjun Zhang, Xia Wu, Jieyong Wang
2022 J jnl
Frontiers Comput. Sci.
Xia Wu, Jiankun Yu, Xiaoming Zhao
2021 J jnl
Sci. Program.
Hui Liu, Yang Liu, Ran Zhang, Xia Wu
2021 conf
CAA SAFEPROCESS
Yinghao Zhao, Xu Yang, Xia Wu, Jian Huang, Kaixiang Peng
2021 J jnl
Appl. Soft Comput.
Xiaochen Lai, Xia Wu, Liyong Zhang
2021 J jnl
Neurocomputing
Chao Xu, Xia Wu, Yachun Li, Yining Jin, Mengmeng Wang, Yong Liu
2021 conf
CIPAE
Xulei Yu, Yue Yang, Xia Wu
2021 conf
AIAM (IEEE)
Xia Wu
2021 A conf
ICWS
Huimin Chen, Hengyue Jia, Xia Wu, Xiuli Wang, Maoning Wang
2021 J jnl
Frontiers Neurorobotics
Hui Liu, Yang Liu, Ran Zhang, Xia Wu
2021 J jnl
Signal Image Video Process.
Shangbo Zhou, Xia Wu, Ying Qi, Shuyue Luo, Xianzhong Xie
2020 J jnl
Scientometrics
Mingliang Yue, Ruinan Li, Guiyan Ou, Xia Wu, Tingcan Ma
2020 J jnl
Symmetry
Chunlei Shi, Jiacai Zhang, Xia Wu
2020 J jnl
CoRR
Fenxi Xiao, Bo Huang, Xia Wu
2020 conf
ICMHI
Xia Wu, Yulong Qi, Fei Feng, Guanxun Cheng, Na Zhang
2020 conf
ECCV (5)
Jiangning Zhang, Chao Xu, Liang Liu, Mengmeng Wang, Xia Wu, Yong Liu, Yunliang Jiang
2020 J jnl
CoRR
Jiangning Zhang, Chao Xu, Liang Liu, Mengmeng Wang, Xia Wu, Yong Liu, Yunliang Jiang
2020 conf
HICSS
Dave T. Croasdell, Xin He, Xia Wu, Yanhai Zhai
2020 J jnl
CoRR
Cankun Qiu, Zhi Luo, Xia Wu, Huidong Yang, Bo Huang
2020 J jnl
CoRR
Fenxi Xiao, Jie Zhang, Bo Huang, Xia Wu
2020 J jnl
Quantum Inf. Process.
Xia Wu, Heng-Yue Jia, Dandan Li, Ying-Hui Yang, Fei Gao
2020 conf
RoboSoft
Xia Wu, Haiyuan Liu, Ziqi Liu, Mingdong Chen, Fang Wan, Chenglong Fu, H. Harry Asada, Zheng Wang, Chaoyang Song
2020 J jnl
CoRR
Xia Wu, Haiyuan Liu, Ziqi Liu, Mingdong Chen, Fang Wan, Chenglong Fu, H. Harry Asada, Zheng Wang, Chaoyang Song
2020 J jnl
CoRR
Yican Chen, Zhi Luo, Xia Wu, Huidong Yang, Bo Huang
2019 conf
VSIP
Xia Wu, Yaling Wang, Zheming Zhang
2019 conf
AISS
Xia Wu, Fanfei Kong, Jupeng Shi, Lina Bao, Feng Gao, Jing Li
2019 J jnl
Trans. Inst. Meas. Control
Lijun Sun, Yue Zhao, Xia Wu, Zengqiang Chen
2019 conf
ISSI
Tingcan Ma, Ruinan Li, Guiyan Ou, Xia Wu, Mingliang Yue
2019 conf
ICC
Chenming Huang, Xia Wu
2019 conf
ISNN (1)
Xiaochen Lai, Xia Wu, Liyong Zhang, Genglin Zhang
2019 J jnl
Neurocomputing
Xiaochen Lai, Xia Wu, Liyong Zhang, Wei Lu, Chongquan Zhong
2019 B conf
GLOBECOM
Chunfu Luo, Xia Wu, Lin Lin, Chao Wang, Fuqiang Liu
2019 J jnl
IMA J. Math. Control. Inf.
Xia Wu, Yi Li, Zengqiang Chen, Mingwei Sun
2019 J jnl
Environ. Model. Softw.
Xia Wu, Lucy A. Marshall, Ashish Sharma
2018 J jnl
Quantum Inf. Process.
Ying-Hui Yang, Cai-Hong Wang, Jiang-Tao Yuan, Xia Wu, Huijuan Zuo
2018 conf
SPML
Zekun Luo, Xia Wu, Qingquan Zou, Xiao Xiao
2018 J jnl
Int. J. Simul. Process. Model.
Min Huang, Hua-Zhao Li, Xia Wu
2017 conf
ICAIT
Yu Zhou, Xia Wu, Ping Wang
2017 conf
PACIS
Xi Hu, Xia Wu, Pengzhen Yin, Xiabing Zheng
2016 B conf
ICPADS
Xia Wu, Yanmin Zhu
2016 conf
ISCRAM
Yi Xiong, Weiping Si, Xia Wu
2016 conf
ISCRAM
Xia Wu, Yi Xiong
2016 conf
APWeb Workshops
Xia Wu, Lei Duan, Tinghai Pang, Jyrki Nummenmaa
2016 J jnl
J. Commun.
Yang Jiang, Yingjie Xu, Yunyan Xie, Shaokai Hong, Xia Wu
2016 J jnl
Bioinform.
Devin K. Schweppe, Chunxiang Zheng, Juan D. Chavez, Arti T. Navare, Xia Wu, Jimmy K. Eng, James E. Bruce
2016 J jnl
计算机科学
Zhihai Yao, Hongzhe Xu, Wen Li, Xia Wu
2015 C conf
APWeb
Xia Wu, Yuanyuan Zhu, Shengchao Xiong, Yuwei Peng, Zhiyong Peng
2015 J jnl
Multim. Tools Appl.
Zhiyong Peng, Mingliang Yue, Xia Wu, Yuwei Peng
2015 conf
ICIC (1)
Xia Wu, Hongzhe Xu, Xiaolin Gui, Wen Li, Zhihai Yao
2014 J jnl
Wirel. Pers. Commun.
Nan Wang, Ming Chen, Xia Wu, Jianxin Dai
2014 conf
ChinaCom
Xia Wu, Jin-Ling Xu, Ming Chen, Junbo Wang
2014 J jnl
EURASIP J. Wirel. Commun. Netw.
Xia Wu, Jin-Ling Xu, Ming Chen, Jun-Bo Wang
2014 J jnl
IEICE Trans. Fundam. Electron. Commun. Comput. Sci.
Nan Wang, Ming Chen, Jianxin Dai, Xia Wu
2014 conf
ChinaCom
Xia Wu, Jin-Ling Xu, Ming Chen, Junbo Wang
2013 J jnl
IEEE Commun. Lett.
Zhiliang Huang, Chunjuan Diao, Jianxin Dai, Chunjiang Duanmu, Xia Wu, Ming Chen
2013 conf
ICONIP (1)
Natsuki Oka, Xia Wu, Chie Fukada, Motoyuki Ozeki
2012 conf
BIBM Workshops
Xia Wu, Hui-Jin Wang, Guo-ming Chen, Wei-Heng Zhu, Shun Long
2012 J jnl
Appl. Math. Lett.
Xia Wu, Yanqiu Chen
2011 J jnl
J. Softw.
Changjun Li, Wenlong Jia, Yi Yang, Xia Wu
2011 ch.
35 Years of Fuzzy Set Theory
Xuzhu Wang, Caiping Wu, Xia Wu
2011 J jnl
J. Comput.
Changjun Li, Wenlong Jia, Xia Wu, Enbin Liu
2010 J jnl
Int. J. Model. Identif. Control.
Huaijun Wang, Xia Wu, Feng Chen, Lixin Jin, Junjie Li, Yuanbo Feng, Frederik De Keyzer, Jie Yu, Yansheng Jiang, Alfons Verbruggen, Guy Marchal, Yicheng Ni
2009 J jnl
J. Comput. Chem.
Xia Wu, Wensheng Cai, Xueguang Shao
2009 conf
ICFIE
Min Wang, Bao Qing Hu, Xia Wu, Yan Qing Niu
2007 conf
RSKT
Haihong Yu, Jigui Sun, Xia Wu, Zehai Li
2006 C conf
KSEM
Xia Wu, Jigui Sun, Kun Hou
2006 conf
IEEE ICCI
Xia Wu, Jigui Sun, Kun Hou
2006 C conf
KSEM
Shasha Feng, Jigui Sun, Xia Wu
2006 conf
RSKT
Xia Wu, Jigui Sun, Shuai Lu, Ying Li, Wei Meng, Minghao Yin
2005 B conf
Mobile Data Management
Baihua Zheng, Xia Wu, Xing Jin, Dik Lun Lee
tests/unit/test_apk_strings_ioc.py
← Index tests/unit/test_apk_strings_ioc.py python
"""Tests for APK string extraction and IOC extraction integration.

Covers:
- APKCodeAnalyzer._extract_strings() — string extraction from DEX objects
- APKCodeAnalyzer._string_entropy() — Shannon entropy computation
- DecompileAPK strings export table schema
- IOCExtractorFromResults with APK-format analysis_results
- Worker IOC wiring for APK
"""
import os
import tempfile
from dataclasses import asdict
from unittest.mock import MagicMock, patch

import pytest

from redb.extractors.ioc_extractor.ioc_extractor import IOCExtractorFromResults
from redb.extractors.ioc_extractor.standalone_ioc_extractor import (
    IOCType,
    SourceType,
)

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


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

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
        return analyzer


def _make_mock_dex(strings):
    """Create a mock DEX object that returns the given strings."""
    dex = MagicMock()
    dex.get_strings.return_value = strings
    return dex


def _create_fake_apk_file():
    """Create a temporary file to act as a fake APK."""
    fd, path = tempfile.mkstemp(suffix=".apk")
    os.write(fd, b"PK\x03\x04fake apk content for hashing")
    os.close(fd)
    return path


# ---------------------------------------------------------------------------
# Tests: _string_entropy
# ---------------------------------------------------------------------------

class TestStringEntropy:
    """Tests for Shannon entropy computation."""

    def test_empty_string(self):
        analyzer = _make_analyzer()
        assert analyzer._string_entropy("") == 0.0

    def test_single_char(self):
        analyzer = _make_analyzer()
        assert analyzer._string_entropy("a") == 0.0

    def test_repeated_char(self):
        analyzer = _make_analyzer()
        assert analyzer._string_entropy("aaaa") == 0.0

    def test_two_equal_chars(self):
        analyzer = _make_analyzer()
        # "ab" -> entropy = 1.0
        assert abs(analyzer._string_entropy("ab") - 1.0) < 0.01

    def test_higher_entropy(self):
        analyzer = _make_analyzer()
        # More variety = higher entropy
        low = analyzer._string_entropy("aabb")
        high = analyzer._string_entropy("abcd")
        assert high > low

    def test_url_string_entropy(self):
        analyzer = _make_analyzer()
        entropy = analyzer._string_entropy("https://evil.com/payload")
        assert entropy > 2.0  # URLs have moderate entropy


# ---------------------------------------------------------------------------
# Tests: _extract_strings
# ---------------------------------------------------------------------------

class TestExtractStrings:
    """Tests for DEX string extraction."""

    def test_basic_extraction(self):
        analyzer = _make_analyzer()
        dex = _make_mock_dex(["hello", "world"])
        result = analyzer._extract_strings([dex])

        assert len(result) == 2
        assert result[0]["string"] == "hello"
        assert result[1]["string"] == "world"

    def test_string_fields_present(self):
        analyzer = _make_analyzer()
        dex = _make_mock_dex(["test_string"])
        result = analyzer._extract_strings([dex])

        entry = result[0]
        assert "string" in entry
        assert "string_encoding" in entry
        assert "string_offset" in entry
        assert "string_length" in entry
        assert "string_entropy" in entry
        assert entry["string_encoding"] == "UTF8"
        assert entry["string_length"] == len("test_string")

    def test_deduplication_across_dex(self):
        """Same string in multiple DEX files is only extracted once."""
        analyzer = _make_analyzer()
        dex1 = _make_mock_dex(["shared", "unique1"])
        dex2 = _make_mock_dex(["shared", "unique2"])
        result = analyzer._extract_strings([dex1, dex2])

        string_values = [s["string"] for s in result]
        assert string_values.count("shared") == 1
        assert "unique1" in string_values
        assert "unique2" in string_values
        assert len(result) == 3

    def test_empty_strings_filtered(self):
        analyzer = _make_analyzer()
        dex = _make_mock_dex(["", "valid", None, "also_valid"])
        result = analyzer._extract_strings([dex])

        string_values = [s["string"] for s in result]
        assert "" not in string_values
        assert None not in string_values
        assert "valid" in string_values
        assert "also_valid" in string_values

    def test_no_dex_files(self):
        analyzer = _make_analyzer()
        result = analyzer._extract_strings([])
        assert result == []

    def test_dex_get_strings_returns_none(self):
        analyzer = _make_analyzer()
        dex = MagicMock()
        dex.get_strings.return_value = None
        result = analyzer._extract_strings([dex])
        assert result == []

    def test_dex_get_strings_exception(self):
        analyzer = _make_analyzer()
        dex = MagicMock()
        dex.get_strings.side_effect = RuntimeError("corrupt DEX")
        result = analyzer._extract_strings([dex])
        assert result == []

    def test_entropy_computed(self):
        analyzer = _make_analyzer()
        dex = _make_mock_dex(["abcdefgh"])
        result = analyzer._extract_strings([dex])
        assert result[0]["string_entropy"] > 0.0

    def test_incremental_offsets(self):
        """String offsets are incremented sequentially."""
        analyzer = _make_analyzer()
        dex = _make_mock_dex(["a", "b", "c"])
        result = analyzer._extract_strings([dex])

        offsets = [s["string_offset"] for s in result]
        assert offsets == [0, 1, 2]

    def test_url_strings_preserved(self):
        """URL strings are extracted without modification."""
        analyzer = _make_analyzer()
        dex = _make_mock_dex([
            "https://evil.com/payload",
            "http://c2.malware.org/gate",
        ])
        result = analyzer._extract_strings([dex])
        strings = [s["string"] for s in result]
        assert "https://evil.com/payload" in strings
        assert "http://c2.malware.org/gate" in strings


# ---------------------------------------------------------------------------
# Tests: strings in extract() integration
# ---------------------------------------------------------------------------

class TestExtractStringsIntegration:
    """Tests that strings are included in extract() results."""

    @patch("redb.extractors.decompiler.apk.analyzer.APKCodeAnalyzer._run_androguard")
    @patch("redb.extractors.decompiler.apk.analyzer.ApktoolDisassembler")
    @patch("redb.extractors.decompiler.apk.analyzer.JADXDecompiler")
    def test_extract_includes_strings(self, mock_jadx, mock_apktool, mock_androguard):
        from redb.extractors.decompiler.apk.analyzer import APKCodeAnalyzer

        mock_dex = _make_mock_dex(["hello", "world"])
        mock_analysis = MagicMock()
        mock_analysis.get_methods.return_value = []
        mock_androguard.return_value = (MagicMock(), [mock_dex], mock_analysis)

        analyzer = APKCodeAnalyzer("/fake/path.apk", log=MagicMock())
        results = analyzer.extract()

        assert "strings" in results
        assert len(results["strings"]) == 2
        assert results["strings"][0]["string"] == "hello"
        analyzer.cleanup()

    @patch("redb.extractors.decompiler.apk.analyzer.APKCodeAnalyzer._run_androguard")
    @patch("redb.extractors.decompiler.apk.analyzer.ApktoolDisassembler")
    @patch("redb.extractors.decompiler.apk.analyzer.JADXDecompiler")
    def test_extract_strings_error_is_non_fatal(self, mock_jadx, mock_apktool, mock_androguard):
        from redb.extractors.decompiler.apk.analyzer import APKCodeAnalyzer

        # Return a bad dex list that will cause _extract_strings to fail
        mock_analysis = MagicMock()
        mock_analysis.get_methods.return_value = []
        # dexs is not iterable — triggers the except block
        mock_androguard.return_value = (MagicMock(), 42, mock_analysis)

        analyzer = APKCodeAnalyzer("/fake/path.apk", log=MagicMock())
        results = analyzer.extract()

        # Should not crash, strings should be empty, error recorded
        assert results["strings"] == []
        assert any(
            e.get("error_location") == "strings"
            for e in results["analysis_errors"]
        )
        analyzer.cleanup()


# ---------------------------------------------------------------------------
# Tests: DecompileAPK strings export table
# ---------------------------------------------------------------------------

class TestDecompileAPKStringsExport:
    """Tests for strings table in DecompileAPK.prepare_export_data()."""

    def _make_extractor_with_strings(self, strings_data):
        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_refs": [],
            "smali_content": [],
            "smali_refs": [],
            "similarity_metrics": [],
            "strings": strings_data,
            "analysis_errors": [],
        }
        return ext, apk_path

    def test_strings_table_present(self):
        ext, path = self._make_extractor_with_strings([
            {"string": "hello", "string_encoding": "UTF8",
             "string_offset": 0, "string_length": 5, "string_entropy": 2.32}
        ])
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            assert "strings_raw" in export
        finally:
            os.unlink(path)

    def test_strings_table_schema(self):
        ext, path = self._make_extractor_with_strings([
            {"string": "hello", "string_encoding": "UTF8",
             "string_offset": 0, "string_length": 5, "string_entropy": 2.32}
        ])
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            sr = export["strings_raw"]
            assert sr["table"] == "code_binja_strings_raw"
            assert len(sr["column_names"]) == 8
            assert len(sr["column_type_names"]) == 8
            assert "sha256" in sr["column_names"]
            assert "string" in sr["column_names"]
            assert "string_raw" in sr["column_names"]
            assert "string_encoding" in sr["column_names"]
            assert "string_offset" in sr["column_names"]
            assert "string_length" in sr["column_names"]
            assert "string_raw_length" in sr["column_names"]
            assert "string_entropy" in sr["column_names"]
            assert len(sr["data"]) == 1
            assert len(sr["data"][0]) == 8
        finally:
            os.unlink(path)

    def test_strings_sha256_propagated(self):
        ext, path = self._make_extractor_with_strings([
            {"string": "test", "string_encoding": "UTF8",
             "string_offset": 0, "string_length": 4, "string_entropy": 2.0}
        ])
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            row = export["strings_raw"]["data"][0]
            assert row[0] == "a" * 64  # sha256 is first column
        finally:
            os.unlink(path)

    def test_empty_strings_not_exported(self):
        ext, path = self._make_extractor_with_strings([])
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            assert "strings_raw" not in export
        finally:
            os.unlink(path)


# ---------------------------------------------------------------------------
# Tests: IOCExtractorFromResults with APK format
# ---------------------------------------------------------------------------

class TestIOCExtractorAPKFormat:
    """Tests that IOCExtractorFromResults handles APK analysis_results."""

    def setup_method(self):
        self.log = MagicMock()

    def test_extract_iocs_from_apk_strings(self):
        """IOCs extracted from APK strings (same format as Binja)."""
        results = {
            "strings": [
                {"string": "https://evil.com/payload", "string_offset": 0},
                {"string": "Contact [email protected]", "string_offset": 1},
            ],
            "decompiled": [],
            "decompiled_content": [],
        }
        extractor = IOCExtractorFromResults(results, sha256="a" * 64, log=self.log)
        iocs = extractor.extract()

        url_iocs = [i for i in iocs if i.ioc_type == IOCType.URL]
        assert len(url_iocs) >= 1
        assert any("evil.com" in i.ioc_value for i in url_iocs)

    def test_extract_iocs_from_apk_decompiled_content(self):
        """IOCs extracted from APK's decompiled_content key."""
        results = {
            "strings": [],
            "decompiled": [],  # Binja format — empty
            "decompiled_content": [  # APK format
                {
                    "decompiled_method": "connect('https://c2.malware.org/gate');",
                    "decompiled_method_hash": "hash123",
                    "method_type": "USER",
                }
            ],
        }
        extractor = IOCExtractorFromResults(results, sha256="a" * 64, log=self.log)
        iocs = extractor.extract()

        url_iocs = [i for i in iocs if i.ioc_type == IOCType.URL]
        assert len(url_iocs) >= 1

    def test_apk_library_methods_skipped(self):
        """LIBRARY methods in decompiled_content are skipped."""
        results = {
            "strings": [],
            "decompiled": [],
            "decompiled_content": [
                {
                    "decompiled_method": "https://should-skip.com",
                    "decompiled_method_hash": "lib_hash",
                    "method_type": "LIBRARY",
                }
            ],
        }
        extractor = IOCExtractorFromResults(results, sha256="a" * 64, log=self.log)
        iocs = extractor.extract()
        assert len(iocs) == 0

    def test_combined_binja_and_apk_sources(self):
        """Both Binja and APK format decompiled entries are processed."""
        results = {
            "strings": [],
            "decompiled": [
                {
                    "decompiled_function": "call('https://binja.example.com');",
                    "decompiled_function_hash": "binja_hash",
                    "function_type": "USER",
                }
            ],
            "decompiled_content": [
                {
                    "decompiled_method": "send('https://apk.example.com');",
                    "decompiled_method_hash": "apk_hash",
                    "method_type": "USER",
                }
            ],
        }
        extractor = IOCExtractorFromResults(results, sha256="a" * 64, log=self.log)
        iocs = extractor.extract()

        url_iocs = [i for i in iocs if i.ioc_type == IOCType.URL]
        urls = [i.ioc_value for i in url_iocs]
        assert any("binja.example.com" in u for u in urls)
        assert any("apk.example.com" in u for u in urls)

    def test_apk_results_only(self):
        """Works when only APK keys are present (no 'decompiled' key)."""
        results = {
            "strings": [
                {"string": "https://evil.com", "string_offset": 0},
            ],
            "decompiled_content": [
                {
                    "decompiled_method": "x = 1",
                    "decompiled_method_hash": "h",
                    "method_type": "USER",
                }
            ],
        }
        extractor = IOCExtractorFromResults(results, sha256="a" * 64, log=self.log)
        iocs = extractor.extract()
        # Should not crash, and should find URL from strings
        url_iocs = [i for i in iocs if i.ioc_type == IOCType.URL]
        assert len(url_iocs) >= 1

    def test_source_type_is_string_for_strings(self):
        results = {
            "strings": [
                {"string": "https://evil.com/test", "string_offset": 42},
            ],
            "decompiled_content": [],
        }
        extractor = IOCExtractorFromResults(results, sha256="a" * 64, log=self.log)
        iocs = extractor.extract()
        url_iocs = [i for i in iocs if i.ioc_type == IOCType.URL]
        assert url_iocs[0].source_type == SourceType.STRING
        assert url_iocs[0].source_identifier == "42"

    def test_source_type_is_decompiled_for_methods(self):
        results = {
            "strings": [],
            "decompiled_content": [
                {
                    "decompiled_method": "https://evil.com/method",
                    "decompiled_method_hash": "myhash",
                    "method_type": "USER",
                }
            ],
        }
        extractor = IOCExtractorFromResults(results, sha256="a" * 64, log=self.log)
        iocs = extractor.extract()
        url_iocs = [i for i in iocs if i.ioc_type == IOCType.URL]
        assert url_iocs[0].source_type == SourceType.DECOMPILED_FUNCTION
        assert url_iocs[0].source_identifier == "myhash"


# ---------------------------------------------------------------------------
# Tests: Worker IOC wiring for APK
# ---------------------------------------------------------------------------

class TestWorkerAPKIOCWiring:
    """Tests that workers.py wires IOC extraction for APK."""

    def test_worker_source_contains_ioc_for_apk(self):
        """Verify workers.py source has IOC extraction in APK branch."""
        import inspect
        from redb import workers
        source = inspect.getsource(workers)
        # APK branch should import IOCExtractorFromResults
        assert "IOCExtractorFromResults" in source
        # Should be in the APK section (near DecompileAPK)
        apk_section = source[source.index("DecompileAPK("):]
        ioc_pos = apk_section.find("IOCExtractorFromResults")
        assert ioc_pos != -1, "IOCExtractorFromResults not found after DecompileAPK"