Nan Hua

107 papers A* 6A 1B 3C 2Misc 1Journal 44Unranked 49
YearRankTypeTitle / Venue / Authors
2025 J jnl
J. Opt. Commun. Netw.
Yuanjian Zhang, Yongli Zhao, Dedong Zhang, Xiaodan Yan, Wei Wang, Yinji Jing, Nan Hua, Jie Zhang
2025 A* conf
EMNLP
Jin Peng Zhou, Sébastien M. R. Arnold, Nan Ding, Kilian Q. Weinberger, Nan Hua, Fei Sha
2025 J jnl
CoRR
Jin Peng Zhou, Sébastien M. R. Arnold, Nan Ding, Kilian Q. Weinberger, Nan Hua, Fei Sha
2025 conf
OFC
Kangqi Zhu, Nan Hua, Xiaoping Zheng
2024 J jnl
CoRR
Zi Yang, Nan Hua
2024 J jnl
Univers. Access Inf. Soc.
Bin Li, Jeffrey Weinland, Tingting Zhang, Nan Hua
2024 J jnl
CoRR
Chenghao Yang, Zi Yang, Nan Hua
2024 conf
ACL (Findings)
Vincent Perot, Kai Kang, Florian Luisier, Guolong Su, Xiaoyu Sun, Ramya Sree Boppana, Zilong Wang, Zifeng Wang, Jiaqi Mu, Hao Zhang, Chen-Yu Lee, Nan Hua
2023 J jnl
Quantum Eng.
Nan Hua, Han-Yang Liu, Xiao-Yun Xiong, Jin-Long Wang, Jun-Qing Liang
2023 conf
ACL (1)
Chen-Yu Lee, Chun-Liang Li, Hao Zhang, Timothy Dozat, Vincent Perot, Guolong Su, Xiang Zhang, Kihyuk Sohn, Nikolay Glushnev, Renshen Wang, Joshua Ainslie, Shangbang Long, Siyang Qin, Yasuhisa Fujii, Nan Hua, Tomas Pfister
2023 J jnl
CoRR
Chen-Yu Lee, Chun-Liang Li, Hao Zhang, Timothy Dozat, Vincent Perot, Guolong Su, Xiang Zhang, Kihyuk Sohn, Nikolai Glushnev, Renshen Wang, Joshua Ainslie, Shangbang Long, Siyang Qin, Yasuhisa Fujii, Nan Hua, Tomas Pfister
2023 J jnl
CoRR
Vincent Perot, Kai Kang, Florian Luisier, Guolong Su, Xiaoyu Sun, Ramya Sree Boppana, Zilong Wang, Jiaqi Mu, Hao Zhang, Nan Hua
2023 A* conf
USENIX Security Symposium
Shuai Li, Zhemin Yang, Guangliang Yang, Hange Zhang, Nan Hua, Yurui Huang, Min Yang
2022 conf
OECC/PSC
Chen Zhao, Nan Hua, Guanqin Pan, Jipu Li, Yanhe Li, Xiaoping Zheng
2022 A* conf
CCS
Shuai Li, Zhemin Yang, Nan Hua, Peng Liu, Xiaohan Zhang, Guangliang Yang, Min Yang
2022 conf
OFC
Jipu Li, Nan Hua, Yanhe Li, Xiaoping Zheng
2022 conf
ACL (1)
Chen-Yu Lee, Chun-Liang Li, Timothy Dozat, Vincent Perot, Guolong Su, Nan Hua, Joshua Ainslie, Renshen Wang, Yasuhisa Fujii, Tomas Pfister
2022 J jnl
CoRR
Chen-Yu Lee, Chun-Liang Li, Timothy Dozat, Vincent Perot, Guolong Su, Nan Hua, Joshua Ainslie, Renshen Wang, Yasuhisa Fujii, Tomas Pfister
2022 J jnl
JOCN
Jialong Li, Nan Hua, Kangqi Zhu, Chen Zhao, Guanqin Pan, Yanhe Li, Xiaoping Zheng, Bingkun Zhou
2022 conf
PAKDD (1)
Ashkan Farhangi, Ning Sui, Nan Hua, Haiyan Bai, Arthur Huang, Zhishan Guo
2022 J jnl
CoRR
Ashkan Farhangi, Ning Sui, Nan Hua, Haiyan Bai, Arthur Huang, Zhishan Guo
2022 conf
OECC/PSC
Kangqi Zhu, Nan Hua, Jinghan Yu, Guanqin Pan, Bofan Yang, Xiaoping Zheng, Bingkun Zhou
2021 conf
OFC
Chen Zhao, Nan Hua, Kangqi Zhu, Jipu Li, Bofan Yang, Xiaoping Zheng
2020 J jnl
Sensors
Yuanchao Wang, Yongming Yang, Haipeng Kuang, Dongming Yuan, Chunfeng Yu, Juan Chen, Nan Hua, Han Hou
2020 conf
EMNLP (Findings)
Zi Lin, Jeremiah Z. Liu, Zi Yang, Nan Hua, Dan Roth
2020 J jnl
CoRR
Zi Lin, Jeremiah Zhe Liu, Zi Yang, Nan Hua, Dan Roth
2019 conf
OFC
Ruijie Luo, Yufang Yu, Nan Hua, Zhizhen Zhong, Jialong Li, Xiaoping Zheng, Bingkun Zhou
2019 conf
OECC/PSC
Yanlong Li, Nan Hua, Kai Tian, Xiaoxiao Xue, Jiading Li, Xiaoping Zheng
2019 J jnl
JOCN
Jialong Li, Nan Hua, Zhizhen Zhong, Yufang Yu, Xiaoping Zheng, Bingkun Zhou
2019 J jnl
JOCN
Ruijie Luo, Nan Hua, Xiaoping Zheng, Bingkun Zhou
2019 J jnl
IEEE/ACM Trans. Netw.
Zhizhen Zhong, Nan Hua, Massimo Tornatore, Jialong Li, Yanhe Li, Xiaoping Zheng, Biswanath Mukherjee
2019 conf
OFC
Yanlong Li, Nan Hua, Chen Zhao, Haotao Wang, Ruijie Luo, Xiaoping Zheng
2019 conf
OFC
Zhizhen Zhong, Nan Hua, Zhigang Yuan, Yanhe Li, Xiaoping Zheng
2019 J jnl
IEEE Access
Zelin Zheng, Nan Hua, Zhizhen Zhong, Jialong Li, Yanhe Li, Xiaoping Zheng
2018 conf
OFC
Jialong Li, Nan Hua, Yufang Yu, Zhizhen Zhong, Xiaoping Zheng, Bingkun Zhou
2018 conf
OFC
Ruijie Luo, Nan Hua, Xiaoping Zheng, Bingkun Zhou
2018 Misc conf
NSDI
Michael Dalton, David Schultz, Jacob Adriaens, Ahsan Arefin, Anshuman Gupta, Brian Fahs, Dima Rubinstein, Enrique Cauich Zermeno, Erik Rubow, James Alexander Docauer, Jesse Alpert, Jing Ai, Jon Olson, Kevin DeCabooter, Marc de Kruijf, Nan Hua, Nathan Lewis, Nikhil Kasinadhuni, Riccardo Crepaldi, Srinivas Krishnan, Subbaiah Venkata, Yossi Richter, Uday Naik, Amin Vahdat
2018 J jnl
JOCN
Yinqiu Jia, Nan Hua, Yanhe Li, Xiaoping Zheng
2018 J jnl
JOCN
Ruijie Luo, Nan Hua, Xiaoping Zheng, Bingkun Zhou
2018 conf
OFC
Ruijie Luo, Nan Hua, Yufang Yu, Zhizhen Zhong, Zhongying Wu, Juhao Li, Xiaoping Zheng, Bingkun Zhou
2018 J jnl
IEEE Commun. Lett.
Yanlong Li, Nan Hua, Yufang Yu, Qingsong Luo, Xiaoping Zheng
2018 conf
OFC
Zhizhen Zhong, Nan Hua, Yufang Yu, Zhongying Wu, Juhao Li, Haozhe Yan, Shangyuan Li, Ruijie Luo, Jialong Li, Yanhe Li, Xiaoping Zheng
2018 conf
EMNLP (Demonstration)
Daniel Cer, Yinfei Yang, Sheng-yi Kong, Nan Hua, Nicole Limtiaco, Rhomni St. John, Noah Constant, Mario Guajardo-Cespedes, Steve Yuan, Chris Tar, Brian Strope, Ray Kurzweil
2018 J jnl
CoRR
Daniel Cer, Yinfei Yang, Sheng-yi Kong, Nan Hua, Nicole Limtiaco, Rhomni St. John, Noah Constant, Mario Guajardo-Cespedes, Steve Yuan, Chris Tar, Yun-Hsuan Sung, Brian Strope, Ray Kurzweil
2017 conf
OFC
Yao Li, Nan Hua, Xiaoping Zheng
2017 J jnl
IEEE Commun. Lett.
Jialong Li, Zhizhen Zhong, Nan Hua, Xiaoping Zheng, Bingkun Zhou
2017 conf
ONDM
Nan Hua, Zhizhen Zhong, Xiaoping Zheng
2017 J jnl
CoRR
Zhizhen Zhong, Nan Hua, Zhu Liu, Wenjing Li, Yanhe Li, Xiaoping Zheng
2017 conf
OFC
Yinqiu Jia, Nan Hua, Yufang Yu, Yanhe Li, Xiaoping Zheng
2017 conf
OFC
Ruijie Luo, Nan Hua, Yao Li, Xiaoping Zheng, Bingkun Zhou
2017 conf
OFC
Liuyan Han, Xintian Hu, Han Li, Lei Wang, Nan Hua
2017 conf
OFC
Yanlong Li, Shuangyi Yan, Nan Hua, Yanni Ou, Fengchen Qian, Reza Nejabati, Dimitra Simeonidou, Xiaoping Zheng
2017 J jnl
Photonic Netw. Commun.
Yinqiu Jia, Nan Hua, Yanhe Li, Xiaoping Zheng
2017 J jnl
CoRR
Zhizhen Zhong, Nan Hua, Yufang Yu, Zhongying Wu, Juhao Li, Haozhe Yan, Shangyuan Li, Ruijie Luo, Jialong Li, Yanhe Li, Xiaoping Zheng
2016 conf
OFC
Haijiao Liu, Nan Hua, Yao Li, Yanhe Li, Xiaoping Zheng
2016 J jnl
Photonic Netw. Commun.
Yao Li, Nan Hua, Xiaoping Zheng
2016 J jnl
JOCN
Zhizhen Zhong, Nan Hua, Massimo Tornatore, Yao Li, Haijiao Liu, Chen Ma, Yanhe Li, Xiaoping Zheng, Biswanath Mukherjee
2016 J jnl
IEEE Commun. Lett.
Yao Li, Nan Hua, Yiqiao Song, Shangyuan Li, Xiaoping Zheng
2016 conf
OFC
Yao Li, Nan Hua, Xiaoping Zheng
2016 conf
OFC
Haijiao Liu, Nan Hua, Yao Li, Yanhe Li, Xiaoping Zheng
2016 conf
OFC
Yao Li, Nan Hua, Xiaoping Zheng, Guifang Li
2016 B conf
GLOBECOM
Zhizhen Zhong, Jipu Li, Nan Hua, Gustavo B. Figueiredo, Yanhe Li, Xiaoping Zheng, Biswanath Mukherjee
2016 J jnl
CoRR
Zhizhen Zhong, Jipu Li, Nan Hua, Gustavo B. Figueiredo, Yanhe Li, Xiaoping Zheng, Biswanath Mukherjee
2016 conf
OFC
Yanlong Li, Yao Li, Nan Hua, Xiaoping Zheng
2015 conf
OFC
Yao Li, Nan Hua, Xiaoping Zheng, Guifang Li
2015 conf
OFC
Wangyang Liu, Nan Hua, Xiaoping Zheng, Bingkun Zhou, Xiaohui Chen
2015 J jnl
JOCN
Wangyang Liu, Nan Hua, Xiaoping Zheng, Bingkun Zhou
2014 conf
ECOC
Wangyang Liu, Xiaohui Chen, Nan Hua, Xiaoping Zheng, Bingkun Zhou
2014 conf
OFC
Nan Hua, Xiaoping Zheng
2014 conf
OFC
Liuyan Han, Han Li, Lei Wang, Nan Hua
2013 J jnl
IEEE Commun. Lett.
Liuyan Han, Nan Hua
2013 conf
OFC/NFOEC
Yanwei Li, Wenda Ni, Heng Zhang, Nan Hua, Yanhe Li, Xiaoping Zheng
2013 J jnl
JOCN
Rui Lu, Xiaoping Zheng, Nan Hua
2013 J jnl
Photonic Netw. Commun.
Yue Chen, Nan Hua, Xin Wan, Hanyi Zhang, Xiaoping Zheng
2013 J jnl
Photonic Netw. Commun.
Haijiao Liu, Nan Hua, Lei Wang, Xiaoping Zheng, Zhigang Liu
2012 A* conf
INFOCOM
Nan Hua, Ashwin Lall, Baochun Li, Jun (Jim) Xu
2012 J jnl
JOCN
Xin Wan, Nan Hua, Xiaoping Zheng
2012 conf
CHINACOM
Nan Hua, Yang Liu, Xin Wan, Xiaoping Zheng, Zhigang Liu
2012 conf
CHINACOM
Wangyang Liu, Qingshan Li, Rui Lu, Xin Wan, Nan Hua, Xiaoping Zheng, Bingkun Zhou, Xiaohui Chen, Pi Wang
2012 C conf
ICCC
Yao Li, Nan Hua, Hanyi Zhang, Xiaoping Zheng
2012 conf
CHINACOM
Congyuan Yang, Nan Hua, Xiaoping Zheng
2012
Nan Hua
2012 J jnl
Photonic Netw. Commun.
Xin Wan, Nan Hua, Hanyi Zhang, Xiaoping Zheng
2012 A* conf
SIGMETRICS
Nan Hua, Ashwin Lall, Baochun Li, Jun (Jim) Xu
2011 J jnl
Opt. Switch. Netw.
Shengfeng Shang, Nan Hua, Lei Wang, Rui Lu, Xiaoping Zheng, Hanyi Zhang
2011 J jnl
IEEE/ACM Trans. Netw.
Nan Hua, Jun (Jim) Xu, Bill Lin, Haiquan (Chuck) Zhao
2011 conf
ANCS
Nan Hua, Eric Norige, Sailesh Kumar, Bill Lynch
2011 C conf
NPC
Haiquan (Chuck) Zhao, Nan Hua, Ashwin Lall, Ping Li, Jia Wang, Jun (Jim) Xu
2010 J jnl
Inf. Sci.
Yi Guo, Zhiqing Shao, Nan Hua
2010 J jnl
Inf. Sci.
Yi Guo, Zhiqing Shao, Nan Hua
2010 conf
FSKD
Xueping Zhang, YanXia Zhu, Nan Hua
2010 conf
Wireless Health
Nan Hua, Ashwin Lall, Justin K. Romberg, Jun (Jim) Xu, Mustafa al'Absi, Emre Ertin, Santosh Kumar, Shikhar Suri
2009 conf
WKDD
Yi Guo, Zhiqing Shao, Nan Hua
2009 J jnl
SIGMETRICS Perform. Evaluation Rev.
Bill Lin, Jun (Jim) Xu, Nan Hua, Hao Wang, Haiquan (Chuck) Zhao
2009 conf
ISCID (2)
Xueping Zhang, YanXia Zhu, Nan Hua
2009 conf
ISPAN
Nan Hua, Ning Yu, Yi Guo
2009 A* conf
INFOCOM
Nan Hua, Haoyu Song, T. V. Lakshman
2008 J jnl
Photonic Netw. Commun.
Nan Hua, Xiaoping Zheng, Hanyi Zhang, Bingkun Zhou
2008 conf
ANCS
Nan Hua, Bill Lin, Jun (Jim) Xu, Haiquan (Chuck) Zhao
2008 conf
ISCSCT (1)
Yi Guo, Zhiqing Shao, Nan Hua
2008 A conf
CoNEXT
Tongqing Qiu, Jian Ni, Hao Wang, Nan Hua, Yang Richard Yang, Jun (Jim) Xu
2008 J jnl
Photonic Netw. Commun.
Nan Hua, Xiaoping Zheng, Hanyi Zhang, Bingkun Zhou
2008 B conf
ICNP
Nan Hua, Haiquan (Chuck) Zhao, Bill Lin, Jun (Jim) Xu
2007 conf
ICC
Nan Hua, Peng Wang, Depeng Jin, Lieguang Zeng, Bin Liu, Gang Feng
2006 B conf
GLOBECOM
Nan Hua, Yang Xu, Peng Wang, Depeng Jin, Lieguang Zeng
2006 J jnl
IEICE Trans. Electron.
Peng Wang, Chao Zhang, Nan Hua, Depeng Jin, Lieguang Zeng
2003 conf
IICAI
Yi Guo, Nan Hua
tests/unit/test_decompile_medium_level.py
← Index tests/unit/test_decompile_medium_level.py python
# tests/unit/test_decompile_medium_level.py
"""Unit tests (mocked BN) for bninja/analysis/medium_level.py
   and bninja/analysis/medium_level_normalization.py."""
# tests/unit/test_decompile_medium_level.py
import sys
from unittest.mock import MagicMock, patch

# Installa gli stubs BN
from tests.unit.conftest_binja_stubs import install_binja_stubs
install_binja_stubs()

# ── Definisci MockMLILInstruction PRIMA di importare il modulo ──
class MockMLILInstruction:
    def __init__(self, operation, address=0, operands=None):
        self.operation = operation
        self.address = address
        self.operands = operands or []

# ── Patcha il modulo BN in modo che isinstance() funzioni ──
sys.modules["binaryninja"].MediumLevelILInstruction = MockMLILInstruction
sys.modules["binaryninja"].SSAVariable = type("SSAVariable", (), {})
sys.modules["binaryninja"].Variable = type("Variable", (), {})
sys.modules["binaryninja"].ILIntrinsic = type("ILIntrinsic", (), {})

# Ora importa il modulo — vede già i tipi corretti
from redb.extractors.decompiler.bninja.analysis.medium_level_normalization import (
    MediumLevelNormalization,
)	

class MockMLILFunction:
    def __init__(self, instructions):
        self._instructions = instructions

    @property
    def instructions(self):
        return iter(self._instructions)

    @property
    def basic_blocks(self):
        # one block containing all instructions, good enough for MinHasher
        block = MagicMock()
        block.__iter__ = lambda self_: iter([])  # not used by MediumLevelAnalysis
        return [block]


class MockFunction:
    def __init__(self, name="func", start=0x1000, mlil=None):
        self.name = name
        self.start = start
        self.mlil = mlil



class TestMediumLevelNormalization:
    def setup_method(self):
        from redb.extractors.decompiler.bninja.analysis.medium_level_normalization import (
            MediumLevelNormalization,
        )
        self.norm = MediumLevelNormalization()

    def test_normalize_skeleton_single_instruction(self):
        il = MockMLILInstruction(operation=42, operands=[])
        result = self.norm.normalize_instruction_all_levels(il)
        assert result == [42]

    def test_normalize_skeleton_nested(self):
        inner = MockMLILInstruction(operation=7, operands=[])
        outer = MockMLILInstruction(operation=1, operands=[inner])
        result = self.norm.normalize_instruction_all_levels(outer)
        assert result == [1, 7]

    def test_normalize_skeleton_with_list_operand(self):
        inner_a = MockMLILInstruction(operation=10, operands=[])
        inner_b = MockMLILInstruction(operation=11, operands=[])
        outer = MockMLILInstruction(operation=2, operands=[[inner_a, inner_b]])
        result = self.norm.normalize_instruction_all_levels(outer)
        assert result == [2, 10, 11]

    def test_normalize_skeleton_none(self):
        result = self.norm.normalize_instruction_all_levels(None)
        # collect on None should leave ops empty
        assert result == []

    def test_normalize_typed_appends_leaf_types(self):
        # operand is a plain int -> "CONST"
        il = MockMLILInstruction(operation=3, operands=[42])
        result = self.norm.normalize_instr_with_operands(il)
        assert result == [3, "CONST"]

    def test_normalize_typed_bool_before_int(self):
        # bool must be detected before int (since bool is an int subclass)
        il = MockMLILInstruction(operation=4, operands=[True])
        result = self.norm.normalize_instr_with_operands(il)
        assert result == [4, "BOOL"]

    def test_normalize_typed_float(self):
        il = MockMLILInstruction(operation=5, operands=[1.5])
        result = self.norm.normalize_instr_with_operands(il)
        assert result == [5, "FLOAT_CONST"]

    def test_normalize_typed_str(self):
        il = MockMLILInstruction(operation=6, operands=["hello"])
        result = self.norm.normalize_instr_with_operands(il)
        assert result == [6, "STR"]

    def test_normalize_typed_unknown_falls_back_to_typename(self):
        class Weird:
            pass
        il = MockMLILInstruction(operation=8, operands=[Weird()])
        result = self.norm.normalize_instr_with_operands(il)
        assert result == [8, "WEIRD"]

    def test_normalize_typed_nested_mlil(self):
        inner = MockMLILInstruction(operation=99, operands=[7])
        outer = MockMLILInstruction(operation=1, operands=[inner])
        result = self.norm.normalize_instr_with_operands(outer)
        assert result == [1, 99, "CONST"]

    def test_normalize_typed_list_mixed(self):
        inner = MockMLILInstruction(operation=50, operands=[])
        il = MockMLILInstruction(operation=2, operands=[[inner, 99]])
        result = self.norm.normalize_instr_with_operands(il)
        assert result == [2, 50, "CONST"]


class TestMediumLevelAnalysis:
    def _make_analysis(self, instructions=None, mlil=True, start=0x1000):
        from redb.extractors.decompiler.bninja.analysis.medium_level import (
            MediumLevelAnalysis,
        )
        mlil_func = MockMLILFunction(instructions or []) if mlil else None
        func = MockFunction(name="testfunc", start=start, mlil=mlil_func)
        bv = MagicMock()
        return MediumLevelAnalysis(func, bv, MagicMock())

    def test_collect_returns_empty_when_no_mlil(self):
        a = self._make_analysis(mlil=False)
        sk, sk_addr, ty, ty_addr = a._collect_mlil_skeleton_and_typed()
        assert sk == [] and sk_addr == [] and ty == [] and ty_addr == []

    def test_collect_skeleton_and_typed_basic(self):
        instrs = [
            MockMLILInstruction(operation=1, address=0x1000, operands=[]),
            MockMLILInstruction(operation=2, address=0x1004, operands=[42]),
        ]
        a = self._make_analysis(instructions=instrs, start=0x1000)
        sk, sk_addr, ty, ty_addr = a._collect_mlil_skeleton_and_typed()

        assert sk == [[1], [2]]
        assert ty == [[1], [2, "CONST"]]
        assert sk_addr == [(0, [1]), (4, [2])]
        assert ty_addr == [(0, [1]), (4, [2, "CONST"])]

    def test_collect_negative_offset_clamped_to_zero(self):
        instrs = [
            MockMLILInstruction(operation=1, address=0x900, operands=[]),
        ]
        a = self._make_analysis(instructions=instrs, start=0x1000)
        _, sk_addr, _, ty_addr = a._collect_mlil_skeleton_and_typed()
        assert sk_addr[0][0] == 0
        assert ty_addr[0][0] == 0

    def test_log_error_records_entry(self):
        a = self._make_analysis()
        a.log_error("boom", "fname", 0x1234, ValueError("x"), "loc")
        assert len(a.errors) == 1
        err = a.errors[0]
        assert err["function_name"] == "fname"
        assert err["function_address"] == "4660"  # hex 0x1234
        assert err["error_location"] == "loc"
        assert err["error_message"] == "boom"
        assert err["error_type"] == "ValueError"
        assert "timestamp" in err

    @patch(
        "redb.extractors.decompiler.bninja.analysis.medium_level.MinHasher"
    )
    def test_analyze_returns_expected_keys(self, mock_minhasher):
        mock_minhasher.return_value.calculateMinHash.return_value = [1, 2, 3]

        instrs = [
            MockMLILInstruction(operation=1, address=0x1000, operands=[]),
            MockMLILInstruction(operation=2, address=0x1004, operands=[42]),
            MockMLILInstruction(operation=3, address=0x1008, operands=[]),
        ]
        a = self._make_analysis(instructions=instrs, start=0x1000)
        result, errors = a.analyze()

        expected_keys = {
            "function_address",
            "body_mlil_skeleton_vector",
            "sha256_mlil_skeleton",
            "tlsh_mlil_skeleton",
            "minhash_mlil_skeleton",
            "body_mlil_typed_vector",
            "sha256_mlil_typed",
            "tlsh_mlil_typed",
            "minhash_mlil_typed",
        }
        assert set(result.keys()) == expected_keys
        assert result["function_address"] == 0x1000
        assert result["minhash_mlil_skeleton"] == [1, 2, 3]
        assert result["minhash_mlil_typed"] == [1, 2, 3]
        assert errors == []

    @patch(
        "redb.extractors.decompiler.bninja.analysis.medium_level.MinHasher"
    )
    def test_analyze_empty_mlil(self, mock_minhasher):
        mock_minhasher.return_value.calculateMinHash.return_value = []
        a = self._make_analysis(mlil=False)
        result, errors = a.analyze()
        assert result["body_mlil_skeleton_vector"] == []
        assert result["body_mlil_typed_vector"] == []
        assert errors == []

    @patch(
        "redb.extractors.decompiler.bninja.analysis.medium_level.MinHasher"
    )
    def test_analyze_sha256_differs_skeleton_vs_typed(self, mock_minhasher):
        mock_minhasher.return_value.calculateMinHash.return_value = []

        instrs = [
            MockMLILInstruction(operation=1, address=0x1000, operands=[42]),
            MockMLILInstruction(operation=2, address=0x1004, operands=["foo"]),
            MockMLILInstruction(operation=3, address=0x1008, operands=[True]),
        ]
        a = self._make_analysis(instructions=instrs)
        result, _ = a.analyze()
        # skeleton ignores operand leaves, typed includes them -> different hashes
        assert result["sha256_mlil_skeleton"] != result["sha256_mlil_typed"]


class TestMinHasherMLILKinds:
    def _make_func(self, instrs):
        # MinHasher iterates basic_blocks then over each block
        block = MagicMock()
        block.__iter__ = lambda self_: iter(instrs)
        f = MagicMock()
        f.basic_blocks = [block]
        return f

    def test_mlil_skeleton_uses_medium_normalizer(self):
        from redb.extractors.decompiler.bninja.similarity.minhasher import (
            MinHasher, TokenKind,
        )
        instrs = [
            MockMLILInstruction(operation=i, operands=[]) for i in range(5)
        ]
        func = self._make_func(instrs)
        hasher = MinHasher(seed=42, il_function=func, kind=TokenKind.MLIL)
        result = hasher.calculateMinHash()
        # 5 instructions -> 3 trigrams -> non-empty signature
        assert result != []

    def test_typed_mlil_differs_from_skeleton(self):
        from redb.extractors.decompiler.bninja.similarity.minhasher import (
            MinHasher, TokenKind,
        )
        instrs = [
            MockMLILInstruction(operation=1, operands=[42]),
            MockMLILInstruction(operation=2, operands=["s"]),
            MockMLILInstruction(operation=3, operands=[True]),
            MockMLILInstruction(operation=4, operands=[1.5]),
        ]
        func = self._make_func(instrs)
        skel = MinHasher(seed=42, il_function=func, kind=TokenKind.MLIL).calculateMinHash()
        typed = MinHasher(seed=42, il_function=func, kind=TokenKind.TYPED_MLIL).calculateMinHash()
        # Same seed, same instructions, but typed has extra leaf tokens
        # -> hashes should generally differ
        assert skel != typed

    def test_mlil_too_few_instructions(self):
        from redb.extractors.decompiler.bninja.similarity.minhasher import (
            MinHasher, TokenKind,
        )
        instrs = [MockMLILInstruction(operation=1, operands=[])] * 2
        func = self._make_func(instrs)
        hasher = MinHasher(seed=42, il_function=func, kind=TokenKind.MLIL)
        assert hasher.calculateMinHash() == []

    def test_unsupported_kind_raises(self):
        from redb.extractors.decompiler.bninja.similarity.minhasher import MinHasher
        func = self._make_func([])
        hasher = MinHasher(seed=42, il_function=func, kind="bogus")
        with pytest.raises(ValueError):
            hasher.calculateMinHash()