Xianbin Yu

61 papers C 1Misc 1Journal 24Unranked 35
YearRankTypeTitle / Venue / Authors
2025 conf
ECOC
Zhidong Lyu, Zhecheng Dai, Tianyu Jiang, Richard Schatz, Yan-Ting Sun, Dan Li, Zhijian Shen, Mathieu Carras, Vjaceslavs Bobrovs, Lu Zhang, Oskars Ozolins, Xianbin Yu, Baile Chen, Xiaodan Pang
2025 conf
ECOC
Armands Ostrovskis, Toms Salgals, Darja Cirjulina, Said El-Busaidy, Michael Koenigsmann, Benjamin Krüger, Fabio Pittalà, Lu Zhang, Xianbin Yu, Hadrien Louchet, Robert Jahn, Kazuo Yamaguchi, Markus Gruen, Vjaceslavs Bobrovs, Marcel Zeiler, Xiaodan Pang, Oskars Ozolins
2025 J jnl
IEEE Commun. Lett.
Yuqi Chen, Xiaowen Xiong, Shilie Zheng, Zelin Zhu, Bingchen Pan, Bincai Wu, Xiaonan Hui, Xianbin Yu, Xianmin Zhang
2025 J jnl
CoRR
Jiahao Zhang, Lu Zhang, Xiaodan Pang, Oskars Ozolins, Qun Zhang, Xianbin Yu
2025 conf
OFC
Armands Ostrovskis, Said El-Busaidy, Toms Salgals, Michael Koenigsmann, Kristaps Rubuls, Benjamin Krüger, Arvids Sedulis, Darja Cirjulina, Fabio Pittalà, Lu Zhang, Xianbin Yu, Rafael Puerta, Sandis Spolitis, Richard Schatz, Katia Gallo, Hadrien Louchet, Robert Jahn, Kazuo Yamaguchi, Markus Gruen, Vjaceslavs Bobrovs, Marcel Zeiler, Xiaodan Pang, Oskars Ozolins
2025 conf
OFC
Zhidong Lyu, Lu Zhang, Mingzheng Lei, Qiuzhuo Deng, Zuomin Yang, Xing Fang, Oskars Ozolins, Guangyi Liu, Min Zhu, Xiaodan Pang, Xianbin Yu
2025 conf
OFC
Lu Zhang, Zhidong Lyu, Oskars Ozolins, Xiaodan Pang, Xianbin Yu
2025 J jnl
IEEE Trans. Commun.
Jiahao Zhang, Lu Zhang, Xianbin Yu, Zhanhong Wang, Oskars Ozolins, Xiaodan Pang, Maïté Brandt-Pearce, Qun Zhang
2025 conf
ECOC
Xing Fang, Lu Zhang, Tianyu Li, Zuomin Yang, Zhidong Lyu, Oskars Ozolins, Xiaodan Pang, Xianbin Yu
2025 conf
OFC
Armands Ostrovskis, Darja Cirjulina, Toms Salgals, Minkyu Kim, Michael Koenigsmann, Benjamin Krüger, Fabio Pittalà, Lu Zhang, Xianbin Yu, Richard Schatz, Markus Gruen, Hadrien Louchet, Robert Jahn, Kazuo Yamaguchi, Vjaceslavs Bobrovs, Peter De Heyn, Xiaodan Pang, Oskars Ozolins
2024 conf
OFC
Mahdieh Joharifar, Hamza Dely, Lauréline Durupt, Armands Ostrovskis, Richard Schatz, Rafael Puerta, Thomas Bonazzi, Grégory Maisons, Djamal Gacemi, Lu Zhang, Sandis Spolitis, Yan-Ting Sun, Vjaceslavs Bobrovs, Xianbin Yu, Angela Vasanelli, Oskars Ozolins, Carlo Sirtori, Xiaodan Pang
2024 conf
OFC
Hongqi Zhang, Zuomin Yang, Zhidong Lyu, Hang Yang, Lu Zhang, Oskars Ozolins, Xiaodan Pang, Xianmin Zhang, Xianbin Yu
2024 J jnl
Digit. Signal Process.
Yuanyuan Dong, Hua Wang, Zhaohui Yang, Nan Hao, Changming Zhang, Xianbin Yu
2024 J jnl
IEEE Trans. Circuits Syst. II Express Briefs
Maolin Sun, Kuiwen Xu, Yang Yang, Shichang Chen, Tao Wang, Dingwang Yu, Xianbin Yu, Gaofeng Wang
2024 conf
OFC
Xiaodan Pang, Richard Schatz, Mahdieh Joharifar, Hamza Dely, Lauréline Durupt, Grégory Maisons, Djamal Gacemi, Rafael Puerta, Thomas Bonazzi, Lu Zhang, Sandis Spolitis, Yan-Ting Sun, Vjaceslavs Bobrovs, Xianbin Yu, Angela Vasanelli, Carlo Sirtori, Oskars Ozolins
2024 J jnl
Phys. Commun.
Yuqian He, Lu Zhang, Hang Yang, Hongqi Zhang, Xianbin Yu
2024 J jnl
IEEE Internet Things J.
Kai Zhang, Changming Zhang, Hua Wang, Zhaohui Yang, Xianbin Yu, Yongjun Li
2024 J jnl
IEEE Trans. Wirel. Commun.
Yuqi Chen, Xiaowen Xiong, Shilie Zheng, Zhaohui Yang, Zelin Zhu, Bingchen Pan, Bincai Wu, Xiaonan Hui, Xiaofeng Jin, Xianbin Yu, Xianmin Zhang
2024 conf
ICTON
Armands Ostrovskis, Toms Salgals, Michael Koenigsmann, Azra Farid, Aleksandrs Marinins, Benjamin Krüger, Fabio Pittalà, Ryan P. Scott, Hansjoerg Haisch, Lu Zhang, Xianbin Yu, Rafael Puerta, Sandis Spolitis, Richard Schatz, Katia Gallo, Markus Gruen, Hadrien Louchet, Kazuo Yamaguchi, Vjaceslavs Bobrovs, Xiaodan Pang, Oskars Ozolins
2023 conf
OFC
Oskars Ozolins, Armands Ostrovskis, Toms Salgals, Benjamin Krüger, Fabio Pittalà, Mahdieh Joharifar, Richard Schatz, Di Che, Yasuhiro Matsui, Thomas Dippon, Yuchuan Fan, Aleksejs Udalcovs, Marek Chacinski, Urban Westergren, Lu Zhang, Haïk Mardoyan, Xianbin Yu, Sandis Spolitis, Sergei Popov, Markus Gruen, Vjaceslavs Bobrovs, Hadrien Louchet, Xiaodan Pang
2023 conf
OFC
Mahdieh Joharifar, Mengyao Han, Richard Schatz, Rafael Puerta, Yan-Ting Sun, Yuchuan Fan, Grégory Maisons, Johan Abautret, Roland Teissier, Lu Zhang, Sandis Spolitis, Muguang Wang, Vjaceslavs Bobrovs, Sebastian Lourdudoss, Xianbin Yu, Sergei Popov, Oskars Ozolins, Xiaodan Pang
2023 J jnl
Comput. Networks
Hua Wang, Adrián Pérez Aguilar, Almudena Díaz-Zayas, Germán Corrales Madueño, Changming Zhang, Nan Hao, Xianbin Yu
2023 J jnl
IEEE Commun. Lett.
Chao Wei, Zhaohui Yang, Jian Dang, Pei Li, Haiquan Wang, Xianbin Yu
2023 conf
OFC
Mengyao Han, Muguang Wang, Yuchuan Fan, Toms Salgals, Hadrien Louchet, Richard Schatz, Markus Gruen, Fabio Pittalà, Benjamin Krüger, Thomas Dippon, Lu Zhang, Xianbin Yu, Sandis Spolitis, Vjaceslavs Bobrovs, Sergei Popov, Xiaodan Pang, Oskars Ozolins
2023 Misc conf
SoftCOM
Oskars Ozolins, Armands Ostrovskis, Toms Salgals, Benjamin Krüger, Fabio Pittalà, Mahdieh Joharifar, Richard Schatz, Michael Koenigsmann, Yuchuan Fan, Urban Westergren, Haïk Mardoyan, Lu Zhang, Sandis Spolitis, Xianbin Yu, Markus Gruen, Vjaceslavs Bobrovs, Hadrien Louchet, Xiaodan Pang
2023 conf
ICTON
Oskars Ozolins, Armands Ostrovskis, Michael Koenigsmann, Toms Salgals, Benjamin Krüger, Fabio Pittalà, Ryan P. Scott, Hansjoerg Haisch, Hadrien Louchet, Aleksandrs Marinins, Sandis Spolitis, Jurgis Porins, Lu Zhang, Richard Schatz, Xianbin Yu, Vjaceslavs Bobrovs, Markus Gruen, Xiaodan Pang
2023 conf
OFC
Rafael Puerta, Mengyao Han, Mahdieh Joharifar, Richard Schatz, Yan-Ting Sun, Yuchuan Fan, Anders Djupsjöbacka, Grégory Maisons, Johan Abautret, Roland Teissier, Lu Zhang, Sandis Spolitis, Muguang Wang, Vjaceslavs Bobrovs, Sebastian Lourdudoss, Xianbin Yu, Sergei Popov, Oskars Ozolins, Xiaodan Pang
2023 conf
OFC
Oskars Ozolins, Armands Ostrovskis, Toms Salgals, Benjamin Krüger, Fabio Pittalà, Mahdieh Joharifar, Richard Schatz, Di Che, Yasuhiro Matsui, Thomas Dippon, Michael Koenigsmann, Yuchuan Fan, Marek Chacinski, Urban Westergren, Lu Zhang, Haïk Mardoyan, Sandis Spolitis, Sergei Popov, Xianbin Yu, Markus Gruen, Vjaceslavs Bobrovs, Hadrien Louchet, Xiaodan Pang
2023 conf
OFC
Xianbin Yu, Hongqi Zhang, Zuomin Yang, Zhidong Lyu, Hang Yang, Yuqian He, Siqi Liu, Nan Li, Oskars Ozolins, Xiaodan Pang, Lu Zhang, Xianmin Zhang
2023 conf
OFC
Qiuzhuo Deng, Lu Zhang, Hongqi Zhang, Zuomin Yang, Xiaodan Pang, Vjaceslavs Bobrovs, Sergei Popov, Yixin Wu, Xiongbin Yu, Oskars Ozolins, Xianbin Yu
2023 C conf
ICCC
Kai Zhang, Hua Wang, Changming Zhang, Xianbin Yu, Yuanyuan Dong
2023 conf
ICC
Kai Zhang, Hua Wang, Changming Zhang, Xianbin Yu, Yuanyuan Dong
2022 conf
OFC
Xiaodan Pang, Hamza Dely, Richard Schatz, Djamal Gacemi, Mahdieh Joharifar, Toms Salgals, Aleksejs Udalcovs, Yan-Ting Sun, Yuchuan Fan, Lu Zhang, Etienne Rodriguez, Sandis Spolitis, Vjaceslavs Bobrovs, Xianbin Yu, Sebastian Lourdudoss, Sergei Popov, Oskars Ozolins, Angela Vasanelli, Carlo Sirtori
2022 J jnl
IEEE Access
Zelin Zhu, Shilie Zheng, Xiaowen Xiong, Yuqi Chen, Xiaonan Hui, Xiaofeng Jin, Xianbin Yu, Xianmin Zhang
2022 conf
ICCT
Siqi Liu, Hongqi Zhang, Yuqian He, Lu Zhang, Xianbin Yu
2022 J jnl
Sensors
Kai Zhang, Guoxin Zheng, Hua Wang, Changming Zhang, Xianbin Yu
2022 J jnl
IEEE Commun. Lett.
Yuqi Chen, Shilie Zheng, Xiaowen Xiong, Zelin Zhu, Bingchen Pan, Cheng Ren, Xiaonan Hui, Xiaofeng Jin, Xianbin Yu, Xianmin Zhang
2022 conf
OECC/PSC
Oskars Ozolins, Toms Salgals, Hadrien Louchet, Mahdieh Joharifar, Richard Schatz, Di Che, Yasuhiro Matsui, Markus Gruen, Thomas Dippon, Fabio Pittalà, Benjamin Krüger, Yuchuan Fan, Aleksejs Udalcovs, Urban Westergren, Lu Zhang, Xianbin Yu, Sandis Spolitis, Vjaceslavs Bobrovs, Sergei Popov, Xiaodan Pang
2022 J jnl
J. Commun. Inf. Networks
Nazar Muhammad Idrees, Zijie Lu, Muhammad Saqlain, Hongqi Zhang, Shiwei Wang, Lu Zhang, Xianbin Yu
2022 conf
OFC
Oskars Ozolins, Toms Salgals, Hadrien Louchet, Mahdieh Joharifar, Richard Schatz, Markus Gruen, Thomas Dippon, Benjamin Krüger, Di Che, Yasuhiro Matsui, Yuchuan Fan, Aleksejs Udalcovs, Lu Zhang, Xianbin Yu, Sandis Spolitis, Vjaceslavs Bobrovs, Sergei Popov, Xiaodan Pang
2022 conf
GLOBECOM (Workshops)
Changming Zhang, Shengnan Dai, Xuemin Li, Kai Zhang, Hua Wang, Xianbin Yu
2022 conf
OECC/PSC
Zijie Lu, Hongqi Zhang, Zuomin Yang, Xianmin Zhang, Lu Zhang, Xianbin Yu
2021 conf
ECOC
Xiaodan Pang, Oskars Ozolins, Shi Jia, Lu Zhang, Richard Schatz, Aleksejs Udalcovs, Vjaceslavs Bobrovs, Hao Hu, Toshio Morioka, Yan-Ting Sun, Jiajia Chen, Sebastian Lourdudoss, Leif K. Oxenløwe, Sergei Popov, Xianbin Yu
2021 J jnl
IEEE Access
Jichen Qiu, Zhiwei Li, Xiaofeng Jin, Xianbin Yu, Shilie Zheng, Xianmin Zhang
2021 conf
ECOC
Xiaodan Pang, Richard Schatz, Mahdieh Joharifar, Aleksejs Udalcovs, Vjaceslavs Bobrovs, Lu Zhang, Xianbin Yu, Yan-Ting Sun, Sergei Popov, Sebastian Lourdudoss, Oskars Ozolins
2020 J jnl
IEEE Commun. Mag.
Lu Zhang, Xiaodan Pang, Shi Jia, Shiwei Wang, Xianbin Yu
2020 J jnl
IEEE Commun. Lett.
Xiaowen Xiong, Shilie Zheng, Zelin Zhu, Zhixia Wang, Yuqi Chen, Xianbin Yu, Xianmin Zhang
2020 J jnl
IEEE Commun. Lett.
Xiaowen Xiong, Shilie Zheng, Zelin Zhu, Xianbin Yu, Xiaofeng Jin, Xianmin Zhang
2020 J jnl
IEEE Access
Zhixia Wang, Shilie Zheng, Xiaowen Xiong, Zelin Zhu, Yuqi Chen, Xianbin Yu, Xiaofeng Jin, Xianmin Zhang
2019 J jnl
J. Commun. Inf. Networks
Xinyue Wang, Shilie Zheng, Xianbin Yu, Xiaofeng Jin, Xianmin Zhang
2019 conf
OFC
Shi Jia, Mu-Chieh Lo, Lu Zhang, Oskars Ozolins, Aleksejs Udalcovs, Deming Kong, Xiaodan Pang, Xianbin Yu, Shilin Xiao, Sergei Popov, Jiajia Chen, Guillermo Carpintero, Toshio Morioka, Hao Hu, Leif K. Oxenløwe
2019 J jnl
IEEE Access
Jialiang Zhou, Shilie Zheng, Xianbin Yu, Xiaofeng Jin, Xianmin Zhang
2019 J jnl
Phys. Commun.
Nazar Muhammad Idrees, Xianbin Yu, Andreas Springer
2017 conf
ICTON
Xianbin Yu, Shi Jia, Xiaodan Pang, Toshio Morioka, Leif K. Oxenløwe
2017 J jnl
IEEE Access
Shilie Zheng, Ruofan Dong, Zhuofan Zhang, Xianbin Yu, Xiaofeng Jin, Hao Chi, Zhi Ning Chen, Xianmin Zhang
2017 conf
OFC
Xiaodan Pang, Shi Jia, Oskars Ozolins, Xianbin Yu, Hao Hu, Leonardo Marcon, Pengyu Guan, Francesco Da Ros, Sergei Popov, Gunnar Jacobsen, Michael Galili, Toshio Morioka, Darko Zibar, Leif Katsuo Oxenløwe
2015 conf
ICTON
Xianbin Yu, Michael Galili, Toshio Morioka, Peter Uhd Jepsen, Leif K. Oxenløwe
2014 conf
ICTON
Xianbin Yu, Ying Chen, Michael Galili, Toshio Morioka, Peter Uhd Jepsen, Leif K. Oxenløwe
2013 conf
OFC/NFOEC
Lei Deng, Xiaodan Pang, Xu Zhang, Xianbin Yu, Deming Liu, Idelfonso Tafur Monroy
2012 conf
ICUMT
Alexander Lebedev, Roberto Rodes, Xianbin Yu, Juan Jose Vegas Olmos, Idelfonso Tafur Monroy, Søren Forchhammer
2011 J jnl
IEEE J. Sel. Areas Commun.
Marta Beltrán, Jesper Bevensee Jensen, Xianbin Yu, Roberto Llorente, Roberto Rodes, Markus Ortsiefer, Christian Neumeyr, Idelfonso Tafur Monroy
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 == {}