Wang Miao

98 papers A* 2B 5C 4Misc 2Journal 54Unranked 26
YearRankTypeTitle / Venue / Authors
2026 J jnl
IEEE Trans. Mob. Comput.
Haojun Huang, Jieling Lei, Bang Wu, Geyong Min, Wang Miao
2026 J jnl
CoRR
Yuanhao Li, Haozhe Wang, Geyong Min, Nektarios Georgalas, Wang Miao
2026 J jnl
IEEE Robotics Autom. Lett.
Cai Luo, Lijun Wang, Jiucai Jin, Zhenpeng Du, Wang Miao
2025 J jnl
IEEE Trans. Mob. Comput.
Haojun Huang, Qifan Wang, Weimin Wu, Wang Miao, Geyong Min
2025 J jnl
IEEE Trans. Image Process.
Wenqi Han, Wen Jiang, Jie Geng, Wang Miao
2025 J jnl
IEEE Trans. Mob. Comput.
Haojun Huang, Junhao Zhang, Bang Wang, Wang Miao, Geyong Min
2025 J jnl
IEEE Trans. Commun.
Zhaowei Zhang, Shuai Du, Lin Liu, Hui Liu, Jiakuo Zuo, Wang Miao, Haitao Zhao
2025 J jnl
IEEE Trans. Mob. Comput.
Haojun Huang, Qifan Wang, Geyong Min, Wang Miao, Dapeng Oliver Wu
2025 J jnl
CoRR
Peili Mao, Joseph Billingsley, Wang Miao, Geyong Min, Ke Li
2025 J jnl
IEEE Trans. Serv. Comput.
Haojun Huang, Hao Sun, Weimin Wu, Chen Wang, Wuwu Liu, Wang Miao, Geyong Min
2024 A* conf
ICML
Feng Xie, Zhengming Chen, Shanshan Luo, Wang Miao, Ruichu Cai, Zhi Geng
2024 J jnl
CoRR
Feng Xie, Zhengming Chen, Shanshan Luo, Wang Miao, Ruichu Cai, Zhi Geng
2024 J jnl
IEEE Trans. Geosci. Remote. Sens.
Wenqi Han, Wang Miao, Jie Geng, Wen Jiang
2024 J jnl
Future Gener. Comput. Syst.
Zheyi Chen, Junjie Zhang, Zhiqin Huang, Pengfei Wang, Zhengxin Yu, Wang Miao
2024 J jnl
IEEE J. Sel. Top. Appl. Earth Obs. Remote. Sens.
Wang Miao, Zihao Zhao, Jie Geng, Wen Jiang
2024 J jnl
IEEE Trans. Geosci. Remote. Sens.
Wang Miao, Wenqi Han, Jie Geng, Wen Jiang
2024 J jnl
IEEE Trans. Mob. Comput.
Wang Miao, Geyong Min, Zhengxin Yu, Xu Zhang
2024 J jnl
Appl. Intell.
Wang Miao, Kai Huang, Zhe Xu, Jianting Zhang, Jie Geng, Wen Jiang
2024 C conf
IGARSS
Wang Miao, Wen Jiang, Jie Geng
2024 J jnl
Eng. Appl. Artif. Intell.
Ronghao Yang, Wang Miao, Zhenxin Zhang, Zhenlong Liu, Mubai Li, Bin Lin
2024 A* conf
INFOCOM
Luying Zhong, Yueyang Pi, Zheyi Chen, Zhengxin Yu, Wang Miao, Xing Chen, Geyong Min
2024 J jnl
CoRR
Luying Zhong, Yueyang Pi, Zheyi Chen, Zhengxin Yu, Wang Miao, Xing Chen, Geyong Min
2023 J jnl
IEEE/ACM Trans. Netw.
Haojun Huang, Zhaoxi Li, Jialin Tian, Geyong Min, Wang Miao, Dapeng Oliver Wu
2023 J jnl
IEEE Trans. Geosci. Remote. Sens.
Wang Miao, Zhe Xu, Jie Geng, Wen Jiang
2023 J jnl
IEEE Trans. Computers
Luwei Fu, Zhiwei Zhao, Geyong Min, Wang Miao, Liang Zhao, Wenjie Huang
2023 conf
ICC
Zhanghui Liu, Lixian Chen, Zheyi Chen, Yifan Huang, Jie Liang, Zhengxin Yu, Wang Miao
2023 J jnl
IEEE Trans. Geosci. Remote. Sens.
Wang Miao, Jie Geng, Wen Jiang
2023 J jnl
CoRR
Zhenrong Wang, Bin Li, Weifeng Li, Shuanlong Niu, Wang Miao, Tongzhi Niu
2023 J jnl
IEEE Trans. Mob. Comput.
Wang Miao, Geyong Min, Xu Zhang, Zhiwei Zhao, Jia Hu
2023 J jnl
IEEE Trans. Serv. Comput.
Haojun Huang, Jialin Tian, Hao Yin, Geyong Min, Dapeng Oliver Wu, Wang Miao
2022 J jnl
IEEE Trans. Ind. Informatics
Haozhe Wang, Yulei Wu, Geyong Min, Wang Miao
2022 J jnl
Eng. Appl. Artif. Intell.
Zhuo Zhang, Hongfei Wang, Jie Geng, Wen Jiang, Xinyang Deng, Wang Miao
2022 J jnl
IEEE Trans. Parallel Distributed Syst.
Xu Zhang, Zhengnan Qi, Geyong Min, Wang Miao, Qilin Fan, Zhan Ma
2022 J jnl
IEEE Trans. Ind. Informatics
Haojun Huang, Wang Miao, Zhaoxi Li, Jialin Tian, Chen Wang, Geyong Min
2022 J jnl
ACM Trans. Sens. Networks
Xu Zhang, Yangchao Zhao, Geyong Min, Wang Miao, Haojun Huang, Zhan Ma
2022 J jnl
Neurocomputing
Wenqing Cheng, Ruxue Wen, Haojun Huang, Wang Miao, Chen Wang
2022 J jnl
IEEE Internet Things J.
Zhengxin Yu, Jia Hu, Geyong Min, Zi Wang, Wang Miao, Shancang Li
2022 J jnl
IEEE Trans. Geosci. Remote. Sens.
Wang Miao, Jie Geng, Wen Jiang
2022 J jnl
IEEE Trans. Serv. Comput.
Haojun Huang, Li Li, Geyong Min, Wang Miao, Yingying Zhu, Yangming Zhao
2022 J jnl
Biomed. Signal Process. Control.
Ziyi Cao, Yaxiang Wang, Wenfeng Zheng, Lirong Yin, Yushan Tang, Wang Miao, Shan Liu, Bo Yang
2021 C conf
IGARSS
Wang Miao, Jie Geng, Xinyang Deng, Wen Jiang
2021 J jnl
CoRR
Joseph Billingsley, Ke Li, Wang Miao, Geyong Min, Nektarios Georgalas
2021 J jnl
IEEE Internet Things J.
Wang Miao, Chunbo Luo, Geyong Min, Yang Mi, Zhengxin Yu
2021 J jnl
IEEE Trans. Intell. Transp. Syst.
Zhengxin Yu, Jia Hu, Geyong Min, Zhiwei Zhao, Wang Miao, M. Shamim Hossain
2021 J jnl
IEEE Trans. Ind. Informatics
Haojun Huang, Wang Miao, Geyong Min, Jialin Tian, Atif Alamri
2021 C conf
EMO
Joseph Billingsley, Ke Li, Wang Miao, Geyong Min, Nektarios Georgalas
2021 J jnl
Entropy
Shubo Yang, Yang Luo, Wang Miao, Changhao Ge, Wenjian Sun, Chunbo Luo
2021 J jnl
IEEE J. Sel. Areas Commun.
Haojun Huang, Cheng Zeng, Yangming Zhao, Geyong Min, Yingying Zhu, Wang Miao, Jia Hu
2021 J jnl
IEEE Wirel. Commun.
Junbao Zhang, Haojun Huang, Geyong Min, Wang Miao, Dapeng Wu
2021 J jnl
IEEE Trans. Netw. Sci. Eng.
Wang Miao, Chunbo Luo, Geyong Min, Yang Mi, Haozhe Wang
2020 ch.
Blockchains for Network Security
Haojun Huang, Geyong Min, Wang Miao, Haozhe Wang
2020 ch.
Blockchains for Network Security
Wang Miao, Geyong Min, Haojun Huang, Haozhe Wang
2020 ed.
ISPA/BDCloud/SocialCom/SustainCom
Jia Hu, Geyong Min, Nektarios Georgalas, Zhiwei Zhao, Fei Hao, Wang Miao
2020 ch.
Blockchains for Network Security
Haojun Huang, Jialin Tian, Geyong Min, Wang Miao
2020 J jnl
IEEE Trans. Broadcast.
Wang Miao, Chunbo Luo, Geyong Min, Zhiwei Zhao
2020 B conf
GLOBECOM
Joseph Billingsley, Wang Miao, Ke Li, Geyong Min, Nektarios Georgalas
2020 conf
ISPA/BDCloud/SocialCom/SustainCom
Ruxue Wen, Wenqing Cheng, Haojun Huang, Wang Miao, Chen Wang
2020 J jnl
IEEE/ACM Trans. Netw.
Haojun Huang, Wang Miao, Geyong Min, Chengqiang Huang, Xu Zhang, Chen Wang
2020 B conf
CEC
Joseph Billingsley, Ke Li, Wang Miao, Geyong Min, Nektarios Georgalas
2020 J jnl
CoRR
Joseph Billingsley, Ke Li, Wang Miao, Geyong Min, Nektarios Georgalas
2019 C conf
EMO
Joseph Billingsley, Ke Li, Wang Miao, Geyong Min, Nektarios Georgalas
2019 conf
ICC
Wang Miao, Chunbo Luo, Geyong Min, Liang Wu, Tianxiao Zhao, Yang Mi
2019 Misc conf
ICASSP
Yang Mi, Chunbo Luo, Geyong Min, Wang Miao, Liang Wu, Tianxiao Zhao
2019 J jnl
IEEE J. Sel. Areas Commun.
Wang Miao, Geyong Min, Yulei Wu, Haojun Huang, Zhiwei Zhao, Haozhe Wang, Chunbo Luo
2018 J jnl
JOCN
Koteswararao Kondepu, Chris Jackson, Yanni Ou, Arash Beldachi, Albert Pagès, Fernando Agraz, Francesca Moscatelli, Wang Miao, Valerija Kamchevska, Nicola Calabretta, Giada Landi, Salvatore Spadaro, Shuangyi Yan, Dimitra Simeonidou, Reza Nejabati
2018 J jnl
Future Gener. Comput. Syst.
Hugo Meyer, José Carlos Sancho, Milica Mrdakovic, Wang Miao, Nicola Calabretta
2017 conf
ECOC
Chris Jackson, Koteswararao Kondepu, Yanni Ou, Arash Beldachi, Albert Pagès Cruz, Fernando Agraz, Francesca Moscatelli, Wang Miao, Valerija Kamchevska, Nicola Calabretta, Giada Landi, Salvatore Spadaro, Reza Nejabati, Dimitra Simeonidou
2017 B conf
GLOBECOM
Haozhe Wang, Jia Hu, Geyong Min, Wang Miao, Nektarios Georgalas
2017 conf
OFC
Nicola Calabretta, Wang Miao, Ketemaw Addis Mekonnen, Kristif Prifti, Kevin A. Williams
2017 J jnl
JOCN
Fulong Yan, Wang Miao, Oded Raz, Nicola Calabretta
2017 conf
ICTON
Nicola Calabretta, Fulong Yan, Wang Miao
2017 conf
ISPAN-FCST-ISCC
Noushin Najjari, Geyong Min, Jia Hu, Wang Miao
2017
Wang Miao
2016 conf
ICTON
Nicola Calabretta, Wang Miao, Huug de Waardt
2016 conf
ICTON
Nicola Calabretta, Wang Miao, Kevin A. Williams
2016 conf
OFC
Wang Miao, Fulong Yan, Oded Raz, Nicola Calabretta
2016 conf
OFC
Wang Miao, Huug de Waardt, Nicola Calabretta
2016 conf
OFC
Oded Raz, Gonzalo Guelbenzu, Teng Li, Chenhui Li, Wang Miao, Fulong Yan, Harm J. S. Dorren, Patty Stabile, Nicola Calabretta
2016 conf
SOSE
Haozhe Wang, Geyong Min, Jia Hu, Wang Miao, Nektarios Georgalas
2016 J jnl
ACM Trans. Multim. Comput. Commun. Appl.
Wang Miao, Geyong Min, Yulei Wu, Haozhe Wang, Jia Hu
2016 Misc conf
ICDCN
Hugo Meyer, José Carlos Sancho, Milica Mrdakovic, Shuping Peng, Dimitra Simeonidou, Wang Miao, Nicola Calabretta
2015 conf
OFC
Wang Miao, Fernando Agraz, Huug de Waardt, Salvatore Spadaro, Harm J. S. Dorren, Nicola Calabretta
2015 conf
ICTON
Nicola Calabretta, Wang Miao, Harm J. S. Dorren
2015 J jnl
Ad Hoc Networks
Tao Hu, Minghui Zheng, Jianjun Tan, Li Zhu, Wang Miao
2015 conf
ECOC
George M. Saridis, Shuping Peng, Yan Yan, Alejandro Aguado, Bingli Guo, Murat Arslan, Chris Jackson, Wang Miao, Nicola Calabretta, Fernando Agraz, Salvatore Spadaro, Giacomo Bernini, Nicola Ciulli, Georgios Zervas, Reza Nejabati, Dimitra Simeonidou
2015 conf
SmartCity
Wang Miao, Geyong Min, Yulei Wu, Haozhe Wang
2015 conf
HPCS
Hugo Meyer, José Carlos Sancho, Wang Miao, Harm J. S. Dorren, Nicola Calabretta, Montse Farreras
2015 conf
ECOC
Wang Miao, Fulong Yan, Harm J. S. Dorren, Nicola Calabretta
2015 J jnl
JOCN
Wang Miao, Fernando Agraz, Shuping Peng, Salvatore Spadaro, Giacomo Bernini, Jordi Perelló, Georgios Zervas, Reza Nejabati, Nicola Ciulli, Dimitra Simeonidou, Harm J. S. Dorren, Nicola Calabretta
2015 conf
OFC
Bingli Guo, Shuping Peng, Chris Jackson, Yan Yan, Y. Shu, Wang Miao, Harm J. S. Dorren, Nicola Calabretta, Fernando Agraz, Jordi Perelló, Salvatore Spadaro, Giacomo Bernini, R. Monno, Nicola Ciulli, Reza Nejabati, Georgios Zervas, Dimitra Simeonidou
2014 conf
EuCNC
Shuping Peng, Dimitra Simeonidou, George Zervas, Reza Nejabati, Yan Yan, Yi Shu, Salvatore Spadaro, Jordi Perelló, Fernando Agraz, Davide Careglio, Harm J. S. Dorren, Wang Miao, Nicola Calabretta, Giacomo Bernini, Nicola Ciulli, José Carlos Sancho, Steluta Iordache, Yolanda Becerra, Montse Farreras, Matteo Biancani, Alessandro Predieri, Roberto Proietti, Zheng Cao, Lei Liu, S. J. Ben Yoo
2014 B conf
WCNC
Haozhe Wang, Geyong Min, Jia Hu, Hao Yin, Wang Miao
2014 conf
ECOC
Wang Miao, Shuping Peng, Salvatore Spadaro, Giacomo Bernini, Fernando Agraz, A. Ferrer, Jordi Perelló, Georgios Zervas, Reza Nejabati, Nicola Ciulli, Dimitra Simeonidou, Harm J. S. Dorren, Nicola Calabretta
2014 conf
ICTON
Nicola Calabretta, Wang Miao, Jun Luo, Stefano Di Lucente, Harm J. S. Dorren
2014 conf
ECOC
Fernando Agraz, Wang Miao, A. Ferrer, Giacomo Bernini, Harm J. S. Dorren, Nicola Calabretta, Nicola Ciulli, Jordi Perelló, Shuping Peng, Georgios Zervas, Dimitra Simeonidou, Gabriel Junyent, Salvatore Spadaro
2014 conf
ECOC
Wang Miao, Xin Yin, Johan Bauwelinck, Harm J. S. Dorren, Nicola Calabretta
2014 B conf
WCNC
Wang Miao, Geyong Min, Yuming Jiang, Xiaolong Jin, Haozhe Wang
2011 conf
ISCIT
Yan Li, Jianhua Ge, Cheng Shen, Jing Li, Wang Miao
tests/unit/test_decompile_binja_extractor.py
← Index tests/unit/test_decompile_binja_extractor.py python
"""Unit tests for DecompileBinja (top-level extractor) and prepare_export_data."""
import hashlib
import json
import os
import sys
import pytest
from unittest.mock import MagicMock, patch, PropertyMock
from datetime import datetime

# Install binaryninja stubs
from tests.unit.conftest_binja_stubs import install_binja_stubs
install_binja_stubs()

from redb.extractors.enum import Tag


# ============================================================================
# 7a. DecompileBinja — methods that don't require a live Binary Ninja session
# ============================================================================


class TestDecompileBinjaCalculateMD5:
    def test_calculate_md5(self):
        """calculate_md5("test") returns expected MD5."""
        with patch("redb.extractors.decompiler.DecompileBinja.Extractor.__init__", return_value=None):
            from redb.extractors.decompiler.DecompileBinja import DecompileBinja
            obj = object.__new__(DecompileBinja)
            obj.log = MagicMock()
            result = obj.calculate_md5("test")
            expected = hashlib.md5(b"test").hexdigest()
            assert result == expected


class TestDecompileBinjaTimeouts:
    def _make_extractor(self, env_vars=None):
        """Create a DecompileBinja with mocked Extractor.__init__."""
        with patch("redb.extractors.decompiler.DecompileBinja.Extractor.__init__", return_value=None):
            from redb.extractors.decompiler.DecompileBinja import DecompileBinja
            if env_vars:
                with patch.dict(os.environ, env_vars, clear=False):
                    obj = DecompileBinja.__new__(DecompileBinja)
                    obj.log = MagicMock()
                    obj.analysis_results = None
                    obj.binja_decompiler = None
                    obj.filetype = None
                    obj.goresym_data = None
                    obj.goresym_output_path = None
                    # Re-run timeout logic
                    try:
                        obj.BINJA_TIMEOUT = int(os.getenv("BINJA_TIMEOUT", "1200"))
                    except ValueError:
                        obj.BINJA_TIMEOUT = 1200
                    try:
                        obj.DECOMPILE_EXTRACTOR_TIMEOUT = int(
                            os.getenv("DECOMPILE_EXTRACTOR_TIMEOUT", "2580")
                        )
                    except ValueError:
                        obj.DECOMPILE_EXTRACTOR_TIMEOUT = 2580
                    return obj
            else:
                obj = DecompileBinja.__new__(DecompileBinja)
                obj.log = MagicMock()
                obj.analysis_results = None
                obj.binja_decompiler = None
                obj.filetype = None
                obj.goresym_data = None
                obj.goresym_output_path = None
                obj.BINJA_TIMEOUT = 1200
                obj.DECOMPILE_EXTRACTOR_TIMEOUT = 2580
                return obj

    def test_timeout_defaults(self):
        obj = self._make_extractor()
        assert obj.BINJA_TIMEOUT == 1200
        assert obj.DECOMPILE_EXTRACTOR_TIMEOUT == 2580

    def test_timeout_from_env(self):
        obj = self._make_extractor(env_vars={"BINJA_TIMEOUT": "600"})
        assert obj.BINJA_TIMEOUT == 600

    def test_timeout_invalid_env(self):
        obj = self._make_extractor(env_vars={"BINJA_TIMEOUT": "not_a_number"})
        assert obj.BINJA_TIMEOUT == 1200


class TestDecompileBinjaDotnet:
    def _make_extractor(self, filetype=None):
        with patch("redb.extractors.decompiler.DecompileBinja.Extractor.__init__", return_value=None):
            from redb.extractors.decompiler.DecompileBinja import DecompileBinja
            obj = DecompileBinja.__new__(DecompileBinja)
            obj.log = MagicMock()
            obj.filetype = filetype
            obj.filepath = "/tmp/fake.bin"
            obj.binary = b"\x00" * 100
            obj.hash = MagicMock()
            obj.hash.sha256 = "a" * 64
            return obj

    def test_is_dotnet_non_pe(self):
        obj = self._make_extractor(filetype="elf")
        assert obj.is_dotnet() is False

    def test_is_dotnet_pe_without_com(self):
        """PE without .NET COM descriptor -> False."""
        obj = self._make_extractor(filetype="pebin")
        # Mock magic to not have .Net
        with patch("redb.extractors.decompiler.DecompileBinja.magic") as mock_magic:
            mock_magic.from_buffer.return_value = "PE32 executable"
            with patch("redb.extractors.decompiler.DecompileBinja.pefile") as mock_pefile:
                mock_pe = MagicMock()
                entry = MagicMock()
                entry.name = "IMAGE_DIRECTORY_ENTRY_IMPORT"
                entry.Size = 100
                mock_pe.OPTIONAL_HEADER.DATA_DIRECTORY = [entry]
                mock_pefile.PE.return_value = mock_pe
                assert obj.is_dotnet() is False

    def test_is_dotnet_pe_with_com_descriptor(self):
        """PE with COM descriptor -> True."""
        obj = self._make_extractor(filetype="pebin")
        with patch("redb.extractors.decompiler.DecompileBinja.magic") as mock_magic:
            mock_magic.from_buffer.return_value = "PE32 executable"
            with patch("redb.extractors.decompiler.DecompileBinja.pefile") as mock_pefile:
                mock_pe = MagicMock()
                entry = MagicMock()
                entry.name = "IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR"
                entry.Size = 72
                mock_pe.OPTIONAL_HEADER.DATA_DIRECTORY = [entry]
                mock_pefile.PE.return_value = mock_pe
                assert obj.is_dotnet() is True


class TestDecompileBinjaGolang:
    def _make_extractor(self, filetype=None):
        with patch("redb.extractors.decompiler.DecompileBinja.Extractor.__init__", return_value=None):
            from redb.extractors.decompiler.DecompileBinja import DecompileBinja
            obj = DecompileBinja.__new__(DecompileBinja)
            obj.log = MagicMock()
            obj.filetype = filetype
            obj.filepath = "/tmp/fake.bin"
            obj.hash = MagicMock()
            obj.hash.sha256 = "a" * 64
            return obj

    def test_is_golang_non_elf_pe(self):
        obj = self._make_extractor(filetype=None)
        assert obj.is_golang() is False

    def test_is_golang_elf_with_go_sections(self):
        """ELF with .gopclntab section -> True."""
        obj = self._make_extractor(filetype="elf")
        with patch("builtins.open", MagicMock()):
            with patch("redb.extractors.decompiler.DecompileBinja.ELFFile") as mock_elf_cls:
                mock_elf = MagicMock()
                sec1 = MagicMock()
                sec1.name = ".text"
                sec1.__getitem__ = lambda self, k: 0x2 if k == "sh_flags" else 0
                sec1.data.return_value = b""
                sec2 = MagicMock()
                sec2.name = ".gopclntab"
                sec2.__getitem__ = lambda self, k: 0x2 if k == "sh_flags" else 0
                sec2.data.return_value = b""
                mock_elf.iter_sections.return_value = [sec1, sec2]
                mock_elf_cls.return_value = mock_elf
                assert obj.is_golang() is True

    def test_is_golang_elf_without_go(self):
        obj = self._make_extractor(filetype="elf")
        with patch("builtins.open", MagicMock()):
            with patch("redb.extractors.decompiler.DecompileBinja.ELFFile") as mock_elf_cls:
                mock_elf = MagicMock()
                sec = MagicMock()
                sec.name = ".text"
                sec.__getitem__ = lambda self, k: 0x2 if k == "sh_flags" else 0
                sec.data.return_value = b"no go signatures here"
                mock_elf.iter_sections.return_value = [sec]
                mock_elf_cls.return_value = mock_elf
                assert obj.is_golang() is False


class TestDecompileBinjaTag:
    def test_tag_returns_decompiled(self):
        with patch("redb.extractors.decompiler.DecompileBinja.Extractor.__init__", return_value=None):
            from redb.extractors.decompiler.DecompileBinja import DecompileBinja
            obj = DecompileBinja.__new__(DecompileBinja)
            obj.log = MagicMock()
            assert obj.tag() == Tag.DECOMPILED.value


class TestDecompileBinjaContextManager:
    def test_context_manager_protocol(self):
        with patch("redb.extractors.decompiler.DecompileBinja.Extractor.__init__", return_value=None):
            from redb.extractors.decompiler.DecompileBinja import DecompileBinja
            obj = DecompileBinja.__new__(DecompileBinja)
            obj.log = MagicMock()
            obj.binja_decompiler = None
            obj.goresym_output_path = None
            assert obj.__enter__() is obj
            # __exit__ calls cleanup_run
            obj.__exit__(None, None, None)

    def test_cleanup_run_clears_state(self):
        with patch("redb.extractors.decompiler.DecompileBinja.Extractor.__init__", return_value=None):
            from redb.extractors.decompiler.DecompileBinja import DecompileBinja
            obj = DecompileBinja.__new__(DecompileBinja)
            obj.log = MagicMock()
            obj.binja_decompiler = MagicMock()
            obj.goresym_output_path = None
            obj.cleanup_run()
            assert obj.binja_decompiler is None


class TestDecompileBinjaExtract:
    def test_extract_timeout_handling(self):
        """Thread timeout -> returns None and calls cleanup."""
        with patch("redb.extractors.decompiler.DecompileBinja.Extractor.__init__", return_value=None):
            from redb.extractors.decompiler.DecompileBinja import DecompileBinja
            obj = DecompileBinja.__new__(DecompileBinja)
            obj.log = MagicMock()
            obj.analysis_results = None
            obj.binja_decompiler = None
            obj.goresym_output_path = None
            obj.DECOMPILE_EXTRACTOR_TIMEOUT = 0  # Immediate timeout
            obj.sha256 = "a" * 64
            obj.sha1 = "b" * 40
            obj.md5 = "c" * 32
            # Mock analyze_binary to block
            import threading
            obj.analyze_binary = lambda: None
            result = obj.extract()
            assert result is None

    def test_analyze_binary_skips_dotnet(self):
        """Dotnet binary -> analyze_binary returns None."""
        with patch("redb.extractors.decompiler.DecompileBinja.Extractor.__init__", return_value=None):
            from redb.extractors.decompiler.DecompileBinja import DecompileBinja
            obj = DecompileBinja.__new__(DecompileBinja)
            obj.log = MagicMock()
            obj.filetype = "pebin"
            obj.filepath = "/fake"
            obj.hash = MagicMock()
            obj.hash.sha256 = "a" * 64
            obj.binja_decompiler = None
            obj.goresym_output_path = None
            obj.goresym_data = None
            obj.BINJA_TIMEOUT = 60
            obj.exporters = []
            obj.index_prefix = None
            with patch.object(obj, "is_dotnet", return_value=True):
                result = obj.analyze_binary()
                assert result is None


# ============================================================================
# 7b. prepare_export_data (ClickHouse schema)
# ============================================================================


class TestPrepareExportData:
    def _make_extractor_with_results(self, goresym_data=None):
        with patch("redb.extractors.decompiler.DecompileBinja.Extractor.__init__", return_value=None):
            from redb.extractors.decompiler.DecompileBinja import DecompileBinja
            obj = DecompileBinja.__new__(DecompileBinja)
            obj.log = MagicMock()
            obj.goresym_data = goresym_data
            obj.analysis_results = {
                "sha256": "a" * 64,
                "sha1": "b" * 40,
                "md5": "c" * 32,
                "decompiled": [
                    {
                        "decompiled_function_hash": "h" * 64,
                        "decompiled_function": "void test() {}",
                        "decompiled_function_name": "test",
                        "decompiled_function_prototype": "void test()",
                        "decompiled_function_address": 0x1000,
                        "function_type": "USER",
                        "functions_caller": [],
                        "functions_call": [],
                        "disassembled_function_hash": "d" * 64,
                        "flattened_score": 0.0,
                        "mba_score": 0.0,
                    }
                ],
                "disassembled": [
                    {
                        "disassembled_function_hash": "d" * 64,
                        "disassembled_function": "0x1000: push rbp",
                        "disassembled_function_no_addresses": "push rbp",
                        "disassembled_function_name": "test",
                        "disassembled_function_address": 0x1000,
                        "function_type": "USER",
                        "instructions_count": 5,
                        "instructions_types": ["DATA_MOVEMENT"],
                        "control_flow_count": 1,
                        "memory_access_pattern": ["MEM_STACK"],
                        "register_usage": ["GPR"],
                        "data_references_count": 0,
                        "max_block_size": 5,
                        "num_calls": 1,
                        "stack_size": -8,
                        "decompiled_function_hash": "h" * 64,
                        "tlsh_disassembly": None,
                        "tlsh_llil": None,
                        "minhash": [1, 2, 3],
                        "cyclomatic_complexity": 2,
                    }
                ],
                "cfg": [
                    {
                        "function_address": 0x1000,
                        "disassembled_function_hash": "d" * 64,
                        "cfg_topology_hash": b'\x00' * 16,
                        "block_count": 3,
                        "edge_count": 4,
                        "llil_total_operations": 20,
                        "call_count": 1,
                        "cyclomatic_complexity": 3,
                        "loop_count": 1,
                        "max_depth": 2,
                        "max_fan_out": 2,
                        "md_index_topdown": 12345,
                        "md_index_bottomup": 67890,
                        "prime_product_llil": 99999,
                        "cfg_feature_tlsh": None,
                        "wl_minhash": [0] * 128,
                        "bb_features": [[5, 1, 0, 2, 0, 1, 1, 2]] * 3,
                        "cfg_adjacency": [(0 << 16) | 1, (0 << 16) | 2, (1 << 16) | 2],
                    }
                ],
                "llil": [
                    {
                        "sha256_llil": "l" * 64,
                        "function_type": "USER",
                        "instructions_types_llil": [],
                        "control_flow_count_llil": 0,
                        "memory_access_pattern_llil": [],
                        "register_usage": {},
                        "total_reg_reads": 0,
                        "total_reg_written": 0,
                        "data_references_count": 0,
                        "max_block_size": 5,
                        "num_calls": 0,
                        "stack_size": -8,
                        "body_llil_vector": [],
                        "function_address": 0x1000,
                        "disassembled_function_hash": "d" * 64,
                        "tlsh_disassembly": None,
                        "tlsh_llil": None,
                    }
                ],
                "errors": [],
                "strings": [
                    {
                        "string": "Hello",
                        "string_raw": "Hello",
                        "string_encoding": "Utf8String",
                        "string_offset": 0,
                        "string_length": 5,
                        "string_raw_length": 5,
                        "string_entropy": 2.32,
                    }
                ],
            }
            return obj

    def test_prepare_export_returns_none_no_results(self):
        with patch("redb.extractors.decompiler.DecompileBinja.Extractor.__init__", return_value=None):
            from redb.extractors.decompiler.DecompileBinja import DecompileBinja
            obj = DecompileBinja.__new__(DecompileBinja)
            obj.log = MagicMock()
            obj.analysis_results = None
            result = obj.prepare_export_data("ClickHouseExporter")
            assert result is None

    def test_prepare_export_multi_table_flag(self):
        obj = self._make_extractor_with_results()
        result = obj.prepare_export_data("ClickHouseExporter")
        assert result["multi_table"] is True

    def test_prepare_export_all_tables_present(self):
        obj = self._make_extractor_with_results()
        result = obj.prepare_export_data("ClickHouseExporter")
        expected_tables = [
            "decompiled_content",
            "decompiled_refs",
            "disassembled_content",
            "disassembled_refs",
            "llil_content",
            "llil_refs",
            "cfg_functions",
            "function_similarity_metrics",
            "strings_raw",
        ]
        for table in expected_tables:
            assert table in result, f"Missing table: {table}"

    def test_prepare_export_decompiled_content_schema(self):
        obj = self._make_extractor_with_results()
        result = obj.prepare_export_data("ClickHouseExporter")
        table = result["decompiled_content"]
        assert len(table["column_names"]) == len(table["column_type_names"])
        assert "decompiled_function_hash" in table["column_names"]

    def test_prepare_export_decompiled_refs_schema(self):
        obj = self._make_extractor_with_results()
        result = obj.prepare_export_data("ClickHouseExporter")
        table = result["decompiled_refs"]
        assert len(table["column_names"]) == len(table["column_type_names"])
        assert "sha256" in table["column_names"]

    def test_prepare_export_disassembled_content_schema(self):
        obj = self._make_extractor_with_results()
        result = obj.prepare_export_data("ClickHouseExporter")
        table = result["disassembled_content"]
        assert len(table["column_names"]) == len(table["column_type_names"])

    def test_prepare_export_disassembled_refs_schema(self):
        obj = self._make_extractor_with_results()
        result = obj.prepare_export_data("ClickHouseExporter")
        table = result["disassembled_refs"]
        assert len(table["column_names"]) == len(table["column_type_names"])

    def test_prepare_export_llil_content_schema(self):
        obj = self._make_extractor_with_results()
        result = obj.prepare_export_data("ClickHouseExporter")
        table = result["llil_content"]
        assert len(table["column_names"]) == len(table["column_type_names"])

    def test_prepare_export_llil_refs_schema(self):
        obj = self._make_extractor_with_results()
        result = obj.prepare_export_data("ClickHouseExporter")
        table = result["llil_refs"]
        assert len(table["column_names"]) == len(table["column_type_names"])

    def test_prepare_export_cfg_functions_schema(self):
        obj = self._make_extractor_with_results()
        result = obj.prepare_export_data("ClickHouseExporter")
        table = result["cfg_functions"]
        assert len(table["column_names"]) == len(table["column_type_names"])
        assert table["table"] == "code_binja_cfg_functions"
        assert "cfg_topology_hash" in table["column_names"]
        assert "wl_minhash" in table["column_names"]
        assert "bb_features" in table["column_names"]

    def test_prepare_export_function_similarity_schema(self):
        obj = self._make_extractor_with_results()
        result = obj.prepare_export_data("ClickHouseExporter")
        table = result["function_similarity_metrics"]
        assert len(table["column_names"]) == len(table["column_type_names"])

    def test_prepare_export_strings_raw_schema(self):
        obj = self._make_extractor_with_results()
        result = obj.prepare_export_data("ClickHouseExporter")
        table = result["strings_raw"]
        assert len(table["column_names"]) == len(table["column_type_names"])

    def test_prepare_export_errors_schema(self):
        obj = self._make_extractor_with_results()
        result = obj.prepare_export_data("ClickHouseExporter")
        table = result["function_analysis_errors"]
        assert len(table["column_names"]) == len(table["column_type_names"])

    def test_prepare_export_golang_metadata_present(self):
        obj = self._make_extractor_with_results(goresym_data={"UserFunctions": []})
        result = obj.prepare_export_data("ClickHouseExporter")
        assert "golang_metadata" in result

    def test_prepare_export_golang_metadata_absent(self):
        obj = self._make_extractor_with_results(goresym_data=None)
        result = obj.prepare_export_data("ClickHouseExporter")
        assert "golang_metadata" not in result


class TestPrepareHelperFunctions:
    """Test the helper functions inside prepare_export_data."""

    def test_prepare_array_field_none(self):
        # The prepare_array_field function converts None -> []
        with patch("redb.extractors.decompiler.DecompileBinja.Extractor.__init__", return_value=None):
            from redb.extractors.decompiler.DecompileBinja import DecompileBinja
            obj = DecompileBinja.__new__(DecompileBinja)
            obj.log = MagicMock()
            obj.goresym_data = None
            obj.analysis_results = {
                "sha256": "a" * 64, "sha1": "b" * 40, "md5": "c" * 32,
                "decompiled": [], "disassembled": [], "cfg": [], "llil": [],
                "errors": [], "strings": [],
            }
            result = obj.prepare_export_data("ClickHouseExporter")
            # Verify the export succeeds (function works even with empty lists)
            assert result is not None

    def test_prepare_array_field_list(self):
        """List values pass through."""
        # Verified through the export data containing arrays
        pass

    def test_prepare_register_usage_map(self):
        """Dict converted to {reg: (reads, writes)} tuples."""
        with patch("redb.extractors.decompiler.DecompileBinja.Extractor.__init__", return_value=None):
            from redb.extractors.decompiler.DecompileBinja import DecompileBinja
            obj = DecompileBinja.__new__(DecompileBinja)
            obj.log = MagicMock()
            obj.goresym_data = None
            obj.analysis_results = {
                "sha256": "a" * 64, "sha1": "b" * 40, "md5": "c" * 32,
                "decompiled": [], "disassembled": [],
                "cfg": [],
                "llil": [{
                    "sha256_llil": "l" * 64, "function_type": "USER",
                    "instructions_types_llil": [], "control_flow_count_llil": 0,
                    "memory_access_pattern_llil": [],
                    "register_usage": {"rbx": {"reads": 3, "writes": 1}},
                    "total_reg_reads": 3, "total_reg_written": 1,
                    "data_references_count": 0, "max_block_size": 5,
                    "num_calls": 0, "stack_size": 0,
                    "body_llil_vector": [],
                    "function_address": 0x1000,
                    "disassembled_function_hash": "d" * 64,
                    "tlsh_disassembly": None,
                    "tlsh_llil": None,
                }],
                "errors": [], "strings": [],
            }
            result = obj.prepare_export_data("ClickHouseExporter")
            # The LLIL content data should have register_usage_llil as a map
            llil_data = result["llil_content"]["data"]
            assert len(llil_data) == 1
            # Column index 5 is register_usage_llil
            reg_map = llil_data[0][5]
            assert reg_map == {"rbx": (3, 1)}

    def test_prepare_register_usage_map_empty(self):
        """Empty/None register usage -> {}."""
        with patch("redb.extractors.decompiler.DecompileBinja.Extractor.__init__", return_value=None):
            from redb.extractors.decompiler.DecompileBinja import DecompileBinja
            obj = DecompileBinja.__new__(DecompileBinja)
            obj.log = MagicMock()
            obj.goresym_data = None
            obj.analysis_results = {
                "sha256": "a" * 64, "sha1": "b" * 40, "md5": "c" * 32,
                "decompiled": [], "disassembled": [],
                "cfg": [],
                "llil": [{
                    "sha256_llil": "l" * 64, "function_type": "USER",
                    "instructions_types_llil": [], "control_flow_count_llil": 0,
                    "memory_access_pattern_llil": [],
                    "register_usage": None,
                    "total_reg_reads": 0, "total_reg_written": 0,
                    "data_references_count": 0, "max_block_size": 0,
                    "num_calls": 0, "stack_size": 0,
                    "body_llil_vector": [],
                    "function_address": 0x1000,
                    "disassembled_function_hash": "d" * 64,
                    "tlsh_disassembly": None,
                    "tlsh_llil": None,
                }],
                "errors": [], "strings": [],
            }
            result = obj.prepare_export_data("ClickHouseExporter")
            llil_data = result["llil_content"]["data"]
            reg_map = llil_data[0][5]
            assert reg_map == {}