Xiangjun Zhao

18 papers Misc 1Journal 10Unranked 7
YearRankTypeTitle / Venue / Authors
2026 J jnl
Adv. Eng. Informatics
Jie Sun, Zhilin Sun, Zhongshan Chen, Yiling Xie, Yikai Zhang, Zheng Wang, Lingling Zheng, Hao Zheng, Xiangjun Zhao
2026 J jnl
Neural Networks
Jie Sun, Zhilin Sun, Zhongshan Chen, Mengyang Dong, Xiaozheng Wang, Changwei Chen, Hao Zheng, Xiangjun Zhao
2024 J jnl
IEEE Trans Autom. Sci. Eng.
Jie Sun, Zhilin Sun, Hao Zheng, Xiangjun Zhao
2023 J jnl
Comput. Electron. Agric.
Jie Sun, Hui Chen, Zhilin Sun, Xiaozheng Wang, Yan Shi, Xiangjun Zhao, Hao Zheng
2023 conf
CGI (3)
Zhenlong Du, Yu Feng, Xiaoli Li, Dong Chen, Xiangjun Zhao
2023 J jnl
Comput. Electr. Eng.
Xiangjun Zhao, Zhenlong Du
2021 conf
PRCV (2)
Linmao Zhou, Hong Chang, Nan Kang, Xiangjun Zhao, Bingpeng Ma
2018 Misc conf
ICASSP
Nana Wang, Xiangjun Zhao
2018 conf
ECOC
Shuang Yin, Liang B. Du, Claudio DaSanti, Xiangjun Zhao, Tao Zhang, Adam Barratt, Joy Jiang, Cedric F. Lam
2018 conf
OFC
Liang B. Du, Shuang Yin, Xiangjun Zhao, Tao Zhang, Adam Barratt, Joy Jiang, Daoyi Wang, Cedric F. Lam
2017 conf
ECOC
Xiangjun Zhao, Liang B. Du, Shuang Yin, Tao Zhang, Adam Barratt, Joy Jiang, Daoyi Wang, Cedric F. Lam
2016 J jnl
Soft Comput.
Gai-Ge Wang, Amir Hossein Gandomi, Xiangjun Zhao, Hai Cheng Eric Chu
2016 J jnl
计算机科学
Ming Du, Xiangjun Zhao
2015 J jnl
Int. J. Digit. Crime Forensics
Nana Wang, Xiangjun Zhao, Han Zhang
2015 J jnl
计算机科学
Yali Liu, Xiaolin Qin, Xiangjun Zhao, Guosheng Hao, Yongquan Dong
2013 J jnl
J. Softw.
Xiangjun Zhao, Mei Lu
2012 conf
AICI
Xiangjun Zhao, Jianghua Gong
2011 conf
WISM (2)
Yongquan Dong, Xiangjun Zhao, Gongjie Zhang
tests/unit/test_apk_apktool_wrapper.py
← Index tests/unit/test_apk_apktool_wrapper.py python
"""
Unit tests for apktool wrapper subprocess management and smali directory detection.

All subprocess calls are mocked — no apktool/Java installation required.
"""
import os
import tempfile

import pytest
from unittest.mock import MagicMock, patch

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


class TestApktoolDisassembler:
    """Tests for ApktoolDisassembler subprocess wrapper."""

    @patch.dict(os.environ, {}, clear=False)
    def test_init_defaults(self):
        os.environ.pop("APKTOOL_PATH", None)
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        a = ApktoolDisassembler()
        assert a.apktool_path == "apktool"
        assert a.timeout == 120

    def test_init_custom(self):
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        a = ApktoolDisassembler(apktool_path="/opt/apktool", timeout=120)
        assert a.apktool_path == "/opt/apktool"
        assert a.timeout == 120

    def test_init_from_env(self):
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        with patch.dict(os.environ, {"APKTOOL_PATH": "/usr/bin/apktool", "APKTOOL_TIMEOUT": "90"}):
            a = ApktoolDisassembler()
            assert a.apktool_path == "/usr/bin/apktool"
            assert a.timeout == 90

    @patch("subprocess.Popen")
    def test_disassemble_success(self, mock_popen):
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        mock_proc = MagicMock()
        mock_proc.communicate.return_value = ("output", "")
        mock_proc.returncode = 0
        mock_popen.return_value = mock_proc

        a = ApktoolDisassembler()
        result = a.disassemble("/test.apk", "/output")
        assert result is True

    @patch("subprocess.Popen")
    def test_disassemble_failure(self, mock_popen):
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        mock_proc = MagicMock()
        mock_proc.communicate.return_value = ("", "error")
        mock_proc.returncode = 1
        mock_popen.return_value = mock_proc

        a = ApktoolDisassembler(log=MagicMock())
        result = a.disassemble("/test.apk", "/output")
        assert result is False

    @patch("subprocess.Popen")
    def test_disassemble_timeout(self, mock_popen):
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        import subprocess
        mock_proc = MagicMock()
        mock_proc.communicate.side_effect = subprocess.TimeoutExpired(cmd="apktool", timeout=10)
        mock_proc.pid = 12345
        mock_popen.return_value = mock_proc

        with patch("os.getpgid", return_value=12345), \
             patch("os.killpg"):
            a = ApktoolDisassembler(timeout=10, log=MagicMock())
            result = a.disassemble("/test.apk", "/output")
            assert result is False

    @patch("subprocess.Popen", side_effect=FileNotFoundError)
    def test_disassemble_not_found(self, mock_popen):
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        a = ApktoolDisassembler(log=MagicMock())
        result = a.disassemble("/test.apk", "/output")
        assert result is False

    @patch("subprocess.Popen")
    def test_disassemble_command_args(self, mock_popen):
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        mock_proc = MagicMock()
        mock_proc.communicate.return_value = ("", "")
        mock_proc.returncode = 0
        mock_popen.return_value = mock_proc

        a = ApktoolDisassembler(apktool_path="/opt/apktool")
        a.disassemble("/test.apk", "/output")

        cmd = mock_popen.call_args[0][0]
        assert cmd[0] == "/opt/apktool"
        assert "d" in cmd
        assert "--no-res" in cmd
        assert "--force" in cmd
        assert "/test.apk" in cmd

    def test_get_smali_directories_single_dex(self):
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        with tempfile.TemporaryDirectory() as tmpdir:
            os.makedirs(os.path.join(tmpdir, "smali"))
            a = ApktoolDisassembler()
            dirs = a.get_smali_directories(tmpdir)
            assert len(dirs) == 1
            assert dirs[0].endswith("smali")

    def test_get_smali_directories_multi_dex(self):
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        with tempfile.TemporaryDirectory() as tmpdir:
            os.makedirs(os.path.join(tmpdir, "smali"))
            os.makedirs(os.path.join(tmpdir, "smali_classes2"))
            os.makedirs(os.path.join(tmpdir, "smali_classes3"))
            # Should not be included
            os.makedirs(os.path.join(tmpdir, "res"))
            os.makedirs(os.path.join(tmpdir, "original"))

            a = ApktoolDisassembler()
            dirs = a.get_smali_directories(tmpdir)
            assert len(dirs) == 3

    def test_get_smali_directories_empty(self):
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        with tempfile.TemporaryDirectory() as tmpdir:
            a = ApktoolDisassembler()
            dirs = a.get_smali_directories(tmpdir)
            assert dirs == []

    def test_get_smali_directories_nonexistent(self):
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        a = ApktoolDisassembler()
        dirs = a.get_smali_directories("/nonexistent/path")
        assert dirs == []