Kai Riemer

160 papers B 1C 14Journal 65Unranked 79
YearRankTypeTitle / Venue / Authors
2026 J jnl
CoRR
Su Yan, Clara Rodrigo Gonzalez, Vincent C. H. Leung, Herman Verinaz-Jadan, Jiakang Chen, Matthieu Toulemonde, Kai Riemer, Jipeng Yan, Clotilde Vié, Qingyuan Tan, Peter D. Weinberg, Pier Luigi Dragotti, Kevin G. Murphy, Meng-Xing Tang
2026 J jnl
Inf. Syst. J.
Kai Riemer, Sandra Peter, Gerhard Schwabe, Sutirtha Chatterjee, Martin Adam, Robert M. Davison
2026 conf
HICSS
Kai Riemer, Sandra Peter
2026 conf
HICSS
Sandra Peter, Kai Riemer, Jevin West
2025 conf
HICSS
Kai Riemer, Sandra Peter
2025 J jnl
Inf. Syst. Res.
Ram D. Gopal, Jingjing Li, Kai Riemer, Suprateek Sarker, Param Vir Singh, Anjana Susarla, Martin Bichler, Jason Bennett Thatcher
2025 J jnl
Inf. Syst. Res.
Mike Seymour, Lingyao (Ivy) Yuan, Kai Riemer, Alan R. Dennis
2025 conf
ACIS
Stefanie Knippschild, Kai Riemer, Sebastian K. Boell, Sandra Peter
2025 J jnl
Commun. Assoc. Inf. Syst.
Mike Seymour, Lorenn P. Ruster, Kai Riemer, Sandra Peter, Karlheinz Kautz
2024 J jnl
Int. J. Inf. Manag.
Kai Riemer, Sandra Peter
2024 conf
HICSS
Sandra Peter, Kai Riemer
2024 conf
ACIS
Kai Riemer, Sandra Peter
2024 conf
AMCIS
Stefanie Knippschild, Sebastian K. Boell, Kai Riemer, Sandra Peter
2024 conf
ACIS
Stefanie Knippschild, Sebastian K. Boell, Kai Riemer, Sandra Peter
2024 J jnl
Inf. Organ.
Rick Sullivan, Alex Veen, Kai Riemer
2024 conf
HICSS
Kai Riemer, Mike Seymour, Lingyao Yuan
2024 J jnl
IEEE Trans. Biomed. Eng.
Qingyuan Tan, Kai Riemer, Joseph Hansen-Shearer, Jipeng Yan, Matthieu Toulemonde, Laura Taylor, Su Yan, Christopher Dunsby, Peter D. Weinberg, Meng-Xing Tang
2024 J jnl
IEEE Trans. Medical Imaging
Marcelo Lerendegui, Kai Riemer, Georgios Papageorgiou, Bingxue Wang, Lachlan Arthur, Arthur Chavignon, Tao Zhang, Olivier Couture, Pingtong Huang, Md Ashikuzzaman, Stefanie Dencks, Christopher Dunsby, Brandon Helfield, Jørgen Arendt Jensen, Thomas Lisson, Matthew R. Lowerison, Hassan Rivaz, Anthony E. Samir, Georg Schmitz, Scott J. Schoen, Ruud van Sloun, Pengfei Song, Tristan S. W. Stevens, Jipeng Yan, Vassilis Sboros, Meng-Xing Tang
2024 conf
ACIS
Stefanie Knippschild, Sebastian K. Boell, Kai Riemer, Sandra Peter
2023 J jnl
Commun. ACM
Michael Seymour, Kai Riemer, Lingyao Yuan, Alan R. Dennis
2023 C conf
ICIS
Bayu Nuswantoro, Alexander Richter, Kai Riemer
2023 conf
ACIS
Stefanie Knippschild, Sebastian K. Boell, Sandra Peter, Kai Riemer
2023 J jnl
IEEE Trans. Biomed. Eng.
Jipeng Yan, Bingxue Wang, Kai Riemer, Joseph Hansen-Shearer, Marcelo Lerendegui, Matthieu Toulemonde, Christopher J. Rowlands, Peter D. Weinberg, Meng-Xing Tang
2023 J jnl
IEEE Trans. Medical Imaging
Kai Riemer, Matthieu Toulemonde, Jipeng Yan, Marcelo Lerendegui, Eleanor Stride, Peter D. Weinberg, Christopher Dunsby, Meng-Xing Tang
2023 conf
ACIS
Belinda Yichen Wang, Sebastian K. Boell, Kai Riemer, Sandra Peter
2023 conf
HICSS
Lingyao Yuan, Kai Riemer, Mike Seymour
2023 J jnl
CoRR
Kai Riemer, Marcelo Lerendegui, Matthieu Toulemonde, Jiaqi Zhu, Christopher Dunsby, Peter D. Weinberg, Meng-Xing Tang
2023 conf
ACIS
Kai Riemer, Sandra Peter
2022 conf
HICSS
Mike Seymour, Lingyao (Ivy) Yuan, Alan R. Dennis, Kai Riemer
2022 conf
HICSS
Mike Seymour, Kai Riemer, Lingyao (Ivy) Yuan
2021 J jnl
J. Inf. Technol.
Kai Riemer, Sandra Peter
2021 conf
HICSS
Mike Seymour, Kai Riemer, Lingyao (Ivy) Yuan, Alan R. Dennis
2021 J jnl
J. Assoc. Inf. Syst.
Mike Seymour, Lingyao (Ivy) Yuan, Alan R. Dennis, Kai Riemer
2021 J jnl
Bus. Inf. Syst. Eng.
Janine Hacker, Kai Riemer
2021 J jnl
Eur. J. Inf. Syst.
Ella Hafermalz, Kai Riemer
2021 conf
HICSS
Kai Riemer, Mike Seymour
2020 conf
ECIS
Sandra Peter, Kai Riemer, Dirk Hovorka
2020 J jnl
Inf. Syst. J.
Ella Hafermalz, Robert Bruce Johnston, Dirk S. Hovorka, Kai Riemer
2020 J jnl
Eur. J. Inf. Syst.
Kai Riemer, Raffaele Ciriello, Sandra Peter, Daniel Schlagwein
2020 conf
HICSS
Mike Seymour, Lingyao (Ivy) Yuan, Alan R. Dennis, Kai Riemer
2020 J jnl
Australas. J. Inf. Syst.
Kai Riemer, Laurence Lock Lee, Cai Kjaer, Annika Haeffner
2020 J jnl
J. Inf. Technol.
Kai Riemer, Sandra Peter
2019 conf
HICSS
Michael Seymour, Lingyao (Ivy) Yuan, Alan R. Dennis, Kai Riemer
2019 J jnl
J. Inf. Technol.
Kai Riemer, Robert B. Johnston
2019 conf
HICSS
Michael Seymour, Kai Riemer, Judy Kay
2019 J jnl
Australas. J. Inf. Syst.
Marta Indulska, Virpi Kristiina Tuunainen, Kai Riemer
2019 conf
ACIS
Ali Eshraghi, Robert Bruce Johnston, Kai Riemer
2019 C conf
ICIS
Kai Riemer, Robert Bruce Johnston
2018 J jnl
Commun. Assoc. Inf. Syst.
Uri Gal, Kai Riemer, Friedrich Chasin
2018 J jnl
J. Assoc. Inf. Syst.
Mike Seymour, Kai Riemer, Judy Kay
2018 conf
ACIS
Natalie Hardwicke, Kai Riemer
2018 conf
IS&O
Margunn Aanestad, Magnus Mähring, Carsten S. Østerlund, Kai Riemer, Ulrike Schultze
2018 ed.
IS&O
Ulrike Schultze, Margunn Aanestad, Magnus Mähring, Carsten S. Østerlund, Kai Riemer
2018 conf
ACIS
Kai Riemer, Laurence Lock Lee, Cai Kjaer, Annika Haeffner
2018 C conf
ICIS
Kai Riemer, Ella Hafermalz
2018 conf
ACIS
Natalie Hardwicke, Tim Mahlberg, Kai Riemer
2017 J jnl
MIS Q.
Kai Riemer, Robert Bruce Johnston
2017 conf
HICSS
Michael Seymour, Kai Riemer, Judy Kay
2016 J jnl
CoRR
Janine Viol, Rebecca Bernsmann, Kai Riemer
2016 conf
IS&O
Ella Hafermalz, Kai Riemer, Sebastian K. Boell
2016 J jnl
Int. J. Inf. Manag.
Matti Mäntymäki, Kai Riemer
2016 conf
ACIS
Kai Riemer, Robert Bruce Johnston
2016 C conf
ICIS
Ella Hafermalz, Kai Riemer
2016 J jnl
CoRR
Ella Hafermalz, Dirk S. Hovorka, Kai Riemer
2016 conf
ACIS
Steve Elliot, Ella Hafermalz, Dirk Hovorka, Sebastian K. Boell, Kai Riemer, Olivera Marjanovic
2016 conf
ECIS
Ella Hafermalz, Kai Riemer
2015 conf
ACIS
Janine Viol, Rebecca Bernsmann, Kai Riemer
2015 C conf
ICIS
Kai Riemer, Jan Finke, Dirk S. Hovorka
2015 J jnl
Bus. Inf. Syst. Eng.
Kai Riemer, Stefan Stieglitz, Christian Meske
2015 conf
ECIS
Jo Orsatti, Kai Riemer
2015 conf
ACIS
Ella Hafermalz, Dirk S. Hovorka, Kai Riemer
2015 J jnl
Commun. Assoc. Inf. Syst.
Jan vom Brocke, Alexander Simons, Kai Riemer, Björn Niehaves, Ralf Plattfaut, Anne Cleven
2015 conf
ECIS
Ella Hafermalz, Kai Riemer
2014 J jnl
Int. J. Inf. Manag.
Matti Mäntymäki, Kai Riemer
2014 conf
ECIS
Stefan Stieglitz, Kai Riemer, Christian Meske
2014 J jnl
Commun. Assoc. Inf. Syst.
Robert Bruce Johnston, Kai Riemer
2014 J jnl
Eur. J. Inf. Syst.
Kai Riemer, Robert Bruce Johnston
2014 J jnl
Wirtschaftsinf.
Torsten Eymann, Dennis Kundisch, Jan Recker, Abraham Bernstein, Judith Gebauer, Oliver Günther, Wolfgang Ketter, Michael zur Mühlen, Kai Riemer
2014 J jnl
Bus. Inf. Syst. Eng.
Torsten Eymann, Dennis Kundisch, Jan Recker, Abraham Bernstein, Judith Gebauer, Oliver Günther, Wolfgang Ketter, Michael zur Mühlen, Kai Riemer
2013 C conf
ICIS
Kai Riemer, Robert Bruce Johnston, Dirk S. Hovorka, Marta Indulska
2013 J jnl
Inf. Syst. E Bus. Manag.
Kai Riemer, Stefan Seidel
2013 conf
HICSS
Daniel Richter, Alexander Richter, Jakob Hamann, Kai Riemer, Nadine Vehring
2013 J jnl
Bus. Inf. Syst. Eng.
Alexander Richter, Kai Riemer
2013 J jnl
Wirtschaftsinf.
Alexander Richter, Kai Riemer
2013 conf
ECIS
Alexander Richter, Kai Riemer
2013 conf
ACIS
Friedrich Chasin, Uri Gal, Kai Riemer
2012 C conf
ICIS
Matti Mäntymäki, Kai Riemer
2012 J jnl
it Inf. Technol.
Alexander Stocker, Alexander Richter, Kai Riemer
2012 conf
ECIS
Nadine Vehring, Kai Riemer
2012 conf
ECIS
Kai Riemer, Philipp Overfeld, Paul Scifleet, Alexander Richter
2012 J jnl
Wirtschaftsinformatik Manag.
Jan vom Brocke, Daniel Richter, Kai Riemer
2012 conf
ACIS
Kai Riemer, Paul Scifleet
2012 conf
ACIS
Jo Orsatti, Kai Riemer
2012 conf
ACIS
Denise Vandeweijer, Alexander Richter, Michael Koch, Kai Riemer
2012 C conf
ICIS
Kai Riemer, Robert Bruce Johnston
2012 J jnl
Electron. Mark.
Kai Riemer, Nadine Vehring
2011 C conf
ICIS
Nadine Vehring, Kai Riemer, Stefan Klein
2011 conf
ACIS
Matti Mäntymäki, Kai Riemer
2011 C conf
ICIS
Kai Riemer, Robert Bruce Johnston
2011 conf
ECIS
Kai Riemer, Justus Holler, Marta Indulska
2011 J jnl
Bus. Inf. Syst. Eng.
Kai Riemer, Alexander Richter, Martin Böhringer
2011 J jnl
Wirtschaftsinf.
Kai Riemer, Alexander Richter, Martin Böhringer
2011 conf
PACIS
Matti Mäntymäki, Kai Riemer
2011 J jnl
Bus. Inf. Syst. Eng.
Daniel Richter, Kai Riemer, Jan vom Brocke
2011 J jnl
Wirtschaftsinf.
Daniel Richter, Kai Riemer, Jan vom Brocke
2011 conf
PACIS
Kai Riemer, Stephan Diederich, Alexander Richter, Paul Scifleet
2011 C conf
ICIS
Russell P. Haines, Kai Riemer
2011 conf
ECIS
Kai Riemer, Alexander Altenhofen, Alexander Richter
2010 C conf
ICIS
Kai Riemer, Deborah Bunker
2010 J jnl
Bus. Inf. Syst. Eng.
Kai Riemer, Alexander Richter, Martin Böhringer
2010 J jnl
Wirtschaftsinf.
Kai Riemer, Alexander Richter, Martin Böhringer
2010 conf
AMCIS
Kai Riemer, Alexander Richter, Philip Seltsikas
2010 C conf
ICIS
Kai Riemer, Nadine Vehring
2010 J jnl
Wirtschaftsinformatik Manag.
Alexander Richter, Kai Riemer, Michael Koch
2010 conf
ACIS
Kai Riemer, Alexander Richter
2010 conf
Bled eConference
Daniel Richter, Kai Riemer, Jan vom Brocke
2010 J jnl
Commun. Assoc. Inf. Syst.
Kai Riemer
2010 conf
Bled eConference
Kai Riemer, Alexander Richter
2009 J jnl
Int. J. Electron. Commer.
Kai Riemer, Christoph Lehrke
2009 J jnl
Bus. Inf. Syst. Eng.
Kai Riemer, Stefanie Filius
2009 conf
ACIS
Alexander Richter, Kai Riemer
2009 J jnl
Int. J. e Collab.
Kai Riemer
2009 conf
ECIS
Daniel Richter, Kai Riemer, Jan vom Brocke, Stefan Große Böckmann
2009 J jnl
Wirtschaftsinf.
Kai Riemer, Stefanie Filius
2009 J jnl
Bus. Process. Manag. J.
Kai Wehmeyer, Alexander Kipp, Kai Riemer
2009 conf
Bled eConference
Jan vom Brocke, Daniel Richter, Kai Riemer
2009 conf
Wirtschaftsinformatik (1)
Kai Riemer, Stefan Klein
2009 conf
ECIS
Jan vom Brocke, Alexander Simons, Björn Niehaves, Kai Riemer, Ralf Plattfaut, Anne Cleven
2009 J jnl
Bus. Inf. Syst. Eng.
Kai Riemer, Stefan Taing
2009 J jnl
Wirtschaftsinf.
Kai Riemer, Stefan Taing
2009 J jnl
Electron. Mark.
Kai Riemer, Charles Steinfield, Doug Vogel
2009 J jnl
HMD Prax. Wirtsch.
Kai Riemer
2008 conf
ECIS
Kai Riemer, Nadine Vehring, Stefan Klein
2008 conf
ECIS
Kai Riemer, Christoph Lehrke
2008 conf
ECIS
Kai Riemer, Jan vom Brocke, Daniel Richter, Stefan Große Böckmann
2008 conf
AMCIS
Kai Riemer, Nadine Vehring
2008 conf
HEALTHINF (2)
Stefan Schellhammer, Kai Riemer, Stefan Klein
2008 conf
ECIS
Alexander Kipp, Kai Riemer, Sebastian Wiemann
2008 J jnl
J. Inf. Technol.
Kai Riemer, Stefan Klein
2008 J jnl
HMD Prax. Wirtsch.
Kai Riemer
2008 conf
MobIS Workshops
Stefan Große Böckmann, Jan vom Brocke, Kai Riemer, Daniel Richter
2008 conf
Bled eConference
Kai Riemer, Nadine Vehring
2008 conf
Bled eConference
Kai Riemer
2008 conf
Multikonferenz Wirtschaftsinformatik
Jan vom Brocke, Kai Riemer, Daniel Richter
2007 conf
Wirtschaftsinformatik (2)
Kai Riemer, Dorothee Korn
2007 J jnl
Commun. Assoc. Inf. Syst.
Kai Riemer, Frank Frößler
2007 conf
Bled eConference
Kai Wehmeyer, Alexander Kipp, Kai Riemer
2007 J jnl
Wirtschaftsinf.
Kai Riemer, Fabian Brüggemann
2007 conf
Wirtschaftsinformatik (1)
Kai Riemer
2007 conf
ECIS
Kai Riemer, Frank Frößler, Stefan Klein
2007 conf
ECIS
Kai Riemer
2007 C conf
ICIS
Frank Frößler, Stefan Klein, Kai Riemer
2006 conf
Bled eConference
Kai Riemer, Fabian Brüggemann
2006 conf
Bled eConference
Kai Riemer, Frank Frößler
2005 J jnl
HMD Prax. Wirtsch.
Kai Riemer, Stefan Klein
2004 conf
Bled eConference
Kai Riemer
2003 conf
ACIS
Kai Riemer, Stefan Klein
2002 J jnl
HMD Prax. Wirtsch.
Kai Riemer, Stefan Klein
2001 conf
Wirtschaftsinformatik
Kai Riemer, Frederik Ahlemann
1998 B conf
EDOC
Kai Riemer
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()