Olga De Troyer

129 papers A* 2A 6B 15C 11Misc 5Journal 23Unranked 60
YearRankTypeTitle / Venue / Authors
2025 J jnl
Database J. Biol. Databases Curation
Sara Sepehri, Anja Heymans, Dinja De Win, Jan Maushagen, Audrey Sanctorum, Christophe Debruyne, Robim M. Rodrigues, Joery De Kock, Vera Rogiers, Olga De Troyer, Tamara Vanhaecke
2024 conf
SEMANTiCS (Posters, Demos, Workshops & Tutorials)
Jan Maushagen, Sara Sepehri, Audrey Sanctorum, Tamara Vanhaecke, Olga De Troyer, Christophe Debruyne
2022 J jnl
Behav. Inf. Technol.
Audrey Sanctorum, Jonathan Riggio, Jan Maushagen, Sara Sepehri, Emma Arnesdotter, Mona Delagrange, Joery De Kock, Tamara Vanhaecke, Christophe Debruyne, Olga De Troyer
2022 C conf
ICBC
Kushal Soni, Olga De Troyer
2022 C conf
iiWAS
Kushal Soni, Olga De Troyer
2022 J jnl
Entertain. Comput.
Pejman Sajjadi, Ahmed Ewais, Olga De Troyer
2022 conf
FTC (2)
Kushal Soni, Olga De Troyer
2022 conf
GOODTECHS
Renny S. N. Lindberg, Beat Signer, Olga De Troyer
2021 conf
IS-EUD
Audrey Sanctorum, Jonathan Riggio, Sara Sepehri, Emma Arnesdotter, Tamara Vanhaecke, Olga De Troyer
2021 conf
RoCHI
Olga De Troyer
2021 conf
CHI Greece
Renny S. N. Lindberg, Olga De Troyer
2020 conf
ICE/ITMC
Samuli Laato, Renny S. N. Lindberg, Teemu Henrikki Laine, Phuong Bui, Boglárka Brezovszky, Lauri Koivunen, Olga De Troyer, Erno Lehtinen
2020 conf
ICSC
Christophe Debruyne, Jonathan Riggio, Emma Gustafson, Declan O'Sullivan, Mathieu Vinken, Tamara Vanhaecke, Olga De Troyer
2020 J jnl
Inf.
Olga De Troyer, Jan Maushagen, Renny S. N. Lindberg, David Breckx
2020 conf
GOODTECHS
Renny S. N. Lindberg, Olga De Troyer
2019 J jnl
Inf. Technol. Manag.
Carlos J. Torrecilla Salinas, Olga De Troyer, María José Escalona Cuaresma, Manuel Mejías
2019 B conf
ICALT
Olga De Troyer, Jan Maushagen, Renny S. N. Lindberg, Jaël Muls, Beat Signer, Koen Lombaerts
2019 conf
AVR (2)
Ahmed Ewais, Olga De Troyer, Mumen Abu Arra, Mohammed Romi
2019 B conf
RCIS
Christophe Debruyne, Jonathan Riggio, Olga De Troyer, Declan O'Sullivan
2019 C conf
iiWAS
Kushal Soni, Olga De Troyer
2019 C conf
iiWAS
Renny S. N. Lindberg, Jan Maushagen, Olga De Troyer
2019 B conf
ICALT
Olga De Troyer, Renny S. N. Lindberg, Jan Maushagen, Pejman Sajjadi
2019 J jnl
Smart Learn. Environ.
Olga De Troyer, Renny S. N. Lindberg, Pejman Sajjadi
2018 J jnl
Comput. Hum. Behav.
Ann DeSmet, Sara Bastiaensens, Katrien Van Cleemput, Karolien Poels, Heidi Vandebosch, G. Deboutte, Laura Herrewijn, Steven Malliet, Sara Pabian, Frederik Van Broeckhoven, Olga De Troyer, Gaetan Deglorie, Sofie Van Hoecke, Koen Samyn, Ilse De Bourdeaudhuij
2017 ch.
Serious Games and Edutainment Applications
Olga De Troyer, Frederik Van Broeckhoven, Joachim Vlieghe
2017 J jnl
J. Comput. High. Educ.
Olga De Troyer, Frederik Van Broeckhoven, Joachim Vlieghe
2017 C conf
SPICE
Carlos J. Torrecilla Salinas, Tatiana Guardia, Olga De Troyer, Manuel Mejías, Jorge Sedeño
2017 conf
VS-GAMES
Olga De Troyer
2016 conf
VS-GAMES
Pejman Sajjadi, Joachim Vlieghe, Olga De Troyer
2016 conf
GALA
Pejman Sajjadi, Andreas Lo-A.-Njoe, Joachim Vlieghe, Olga De Troyer
2016 conf
HCI (17)
Abdalghani Mushtaha, Olga De Troyer
2016 conf
GALA
Pejman Sajjadi, Eman El Sayed, Olga De Troyer
2016 conf
GALA
Olga De Troyer, Anas Helalouch, Christophe Debruyne
2015 conf
VS-GAMES
Frederik Van Broeckhoven, Joachim Vlieghe, Olga De Troyer
2015 conf
INT/SBG@AIIDE
Edgar Omar Cebolledo Gutierrez, Olga De Troyer
2015 Misc conf
APCCM
Pejman Sajjadi, Olga De Troyer
2015 C conf
ICIDS
Frederik Van Broeckhoven, Joachim Vlieghe, Olga De Troyer
2015 conf
JCSG
Edgar Cebolledo, Olga De Troyer
2014 conf
CSEDU (1)
Ahmed Ewais, Olga De Troyer
2014 conf
RePa
Olga De Troyer, Erik Janssens
2014 J jnl
Int. J. Virtual Pers. Learn. Environ.
Ahmed Ewais, Olga De Troyer
2014 J jnl
Comput. Games J.
Edgar Omar Cebelledo Gutierrez, Olga De Troyer
2014 conf
GameDays
Pejman Sajjadi, Frederik Van Broeckhoven, Olga De Troyer
2014 Misc conf
CHI PLAY
Pejman Sajjadi, Edgar Omar Cebolledo Gutierrez, Sandra Trullemans, Olga De Troyer
2014 C conf
FDG
Edgar Omar Cebolledo Gutierrez, Olga De Troyer
2014 C conf
FDG
Frederik Van Broeckhoven, Olga De Troyer
2014 J jnl
Int. J. Child Comput. Interact.
Olga De Troyer, Erik Janssens
2014 conf
HCI (9)
Abdalghani Mushtaha, Olga De Troyer
2013 conf
SeGAH
Frederik Van Broeckhoven, Olga De Troyer
2013 B conf
CSEDU
Ahmed Ewais, Olga De Troyer
2013 A conf
UMAP
Georgios Patsis, Hichem Sahli, Werner Verhelst, Olga De Troyer
2013 J jnl
Int. J. Virtual Pers. Learn. Environ.
Ahmed Ewais, Olga De Troyer
2012 conf
EESSMod@MoDELS
Lamia Abo Zaid, Olga De Troyer
2011 conf
HT
William Van Woensel, Sven Casteleyn, Olga De Troyer
2011 ed.
ER Workshops
Olga De Troyer, Claudia Bauzer Medeiros, Roland Billen, Pierre Hallot, Alkis Simitsis, Hans Van Mingroot
2011 conf
ANT/MobiWIS
Elien Paret, William Van Woensel, Sven Casteleyn, Beat Signer, Olga De Troyer
2011 conf
VaMoS
Lamia Abo Zaid, Frederic Kleinermann, Olga De Troyer
2011 conf
ER Workshops
Mohammed El Dammagh, Olga De Troyer
2011 J jnl
IEEE Internet Comput.
William Van Woensel, Sven Casteleyn, Elien Paret, Olga De Troyer
2011 ed.
ICSOB
Björn Regnell, Inge van de Weerd, Olga De Troyer
2011 conf
BMMDS/EMMSAD
Lamia Abo Zaid, Olga De Troyer
2011 B conf
WISE
William Van Woensel, Sven Casteleyn, Elien Paret, Olga De Troyer
2010 B conf
ICWE
William Van Woensel, Sven Casteleyn, Olga De Troyer
2010 C conf
iiWAS
Sven Casteleyn, William Van Woensel, Olga De Troyer
2010 conf
USAB
Olga De Troyer, Frederic Kleinermann, Ahmed Ewais
2010 conf
ICSOFT (1)
Lamia Abo Zaid, Frederic Kleinermann, Olga De Troyer
2010 A conf
ER
Lamia Abo Zaid, Frederic Kleinermann, Olga De Troyer
2010 C conf
iiWAS
Wael Al Sarraj, Olga De Troyer
2009 conf
OTM Workshops
William Van Woensel, Sven Casteleyn, Olga De Troyer
2009 Misc conf
SAC
Lamia Abo Zaid, Frederic Kleinermann, Olga De Troyer
2009 conf
HCI (14)
Abdalghani Mushtaha, Olga De Troyer
2009 J jnl
J. Data Semant.
Olga De Troyer, Wesley Bille, Frederic Kleinermann
2009 conf
Web3D
Haïthem Mansouri, Frederic Kleinermann, Olga De Troyer
2009 B conf
EC-TEL
Olga De Troyer, Frederic Kleinermann, Bram Pellens, Ahmed Ewais
2009 conf
Future Play
Bram Pellens, Olga De Troyer, Frederic Kleinermann
2008 J jnl
Int. J. Web Inf. Syst.
Wieland Schwinger, Werner Retschitzegger, Andrea Schauerhuber, Gerti Kappel, Manuel Wimmer, Birgit Pröll, Cristina Cachero, Sven Casteleyn, Olga De Troyer, Piero Fraternali, Irene Garrigós, Franca Garzotto, Athula Ginige, Geert-Jan Houben, Nora Koch, Nathalie Moreno, Oscar Pastor, Paolo Paolini, Vicente Pelechano, Gustavo Rossi, Daniel Schwabe, Massimo Tisi, Antonio Vallecillo, Kees van der Sluijs, Gefei Zhang
2008 conf
Web3D
Bram Pellens, Olga De Troyer, Frederic Kleinermann
2008 J jnl
Int. J. Virtual Real.
Frederic Kleinermann, Haïthem Mansouri, Olga De Troyer, Bram Pellens, Jesús Ibáñez-Martínez
2008 ch.
Web Engineering
Olga De Troyer, Sven Casteleyn, Peter Plessers
2007 conf
AEWSE
Sven Casteleyn, Florian Daniel, Peter Dolog, Maristella Matera, Geert-Jan Houben, Olga De Troyer
2007 conf
VSMM
Frederic Kleinermann, Olga De Troyer, Christophe Creelle, Bram Pellens
2007 conf
ER (Tutorials, Posters, Panels & Industrial Contributions)
Olga De Troyer, Frederic Kleinermann, Bram Pellens, Wesley Bille
2007 conf
HCI (10)
Abdalghani Mushtaha, Olga De Troyer
2007 J jnl
Virtual Real.
Olga De Troyer, Frederic Kleinermann, Haïthem Mansouri, Bram Pellens, Wesley Bille, Vladimir Fomenko
2007 ed.
AEWSE
Sven Casteleyn, Florian Daniel, Peter Dolog, Maristella Matera, Geert-Jan Houben, Olga De Troyer
2007 J jnl
J. Web Semant.
Peter Plessers, Olga De Troyer, Sven Casteleyn
2006 B conf
ICWE
Sven Casteleyn, Peter Plessers, Olga De Troyer
2006 B conf
VRST
Bram Pellens, Frederic Kleinermann, Olga De Troyer
2006 conf
VSMM
Bram Pellens, Frederic Kleinermann, Olga De Troyer, Wesley Bille
2006 J jnl
J. Web Eng.
Olga De Troyer, Abdalghani Mushtaha, H. Stengers, M. Baetens, F. Boers, Sven Casteleyn, Peter Plessers
2006 A conf
ER
Sven Casteleyn, Peter Plessers, Olga De Troyer
2006 conf
ICWE Workshops
Sven Casteleyn, Florian Daniel, Geert-Jan Houben, Maristella Matera, Peter Plessers, Olga De Troyer
2006 B conf
ESWC
Peter Plessers, Olga De Troyer
2005 A* conf
WWW
Peter Plessers, Sven Casteleyn, Yeliz Yesilada, Olga De Troyer, Robert Stevens, Simon Harper, Carole A. Goble
2005 conf
OTM Workshops
Bram Pellens, Olga De Troyer, Wesley Bille, Frederic Kleinermann, Raul Romero
2005 ch.
Encyclopedia of Information Science and Technology (I)
Olga De Troyer
2005 C conf
APWeb
Sven Casteleyn, Irene Garrigós, Olga De Troyer
2005 A conf
CAiSE
Peter Plessers, Olga De Troyer, Sven Casteleyn
2005 Misc conf
ISWC
Peter Plessers, Olga De Troyer
2005 conf
SemAnnot@ISWC
Peter Plessers, Sven Casteleyn, Olga De Troyer
2005 conf
OTM Workshops
Olga De Troyer, Sven Casteleyn, Peter Plessers
2004 B conf
ICWE
Peter Plessers, Olga De Troyer
2004 B conf
WISE
Olga De Troyer, Sven Casteleyn
2004 B conf
DASFAA
Karl Aberer, Philippe Cudré-Mauroux, Aris M. Ouksel, Tiziana Catarci, Mohand-Said Hacid, Arantza Illarramendi, Vipul Kashyap, Massimo Mecella, Eduardo Mena, Erich J. Neuhold, Olga De Troyer, Thomas Risse, Monica Scannapieco, Fèlix Saltor, Luca De Santis, Stefano Spaccapietra, Steffen Staab, Rudi Studer
2004 conf
ICSNW
Karl Aberer, Tiziana Catarci, Philippe Cudré-Mauroux, Tharam S. Dillon, Stephan Grimm, Mohand-Said Hacid, Arantza Illarramendi, Mustafa Jarrar, Vipul Kashyap, Massimo Mecella, Eduardo Mena, Erich J. Neuhold, Aris M. Ouksel, Thomas Risse, Monica Scannapieco, Fèlix Saltor, Luca De Santis, Stefano Spaccapietra, Steffen Staab, Rudi Studer, Olga De Troyer
2004 conf
IVEVA
Wesley Bille, Bram Pellens, Frederic Kleinermann, Olga De Troyer
2004 B conf
ICWE
Sven Casteleyn, Irene Garrigós, Olga De Troyer
2004 conf
ICWI
Wesley Bille, Olga De Troyer, Frederic Kleinermann, Bram Pellens, Raul Romero
2004 conf
WWW Workshop on Application Design, Development and Implementation Issues in the Semantic Web
Peter Plessers, Olga De Troyer
2003 conf
WWW (Posters)
Olga De Troyer, Peter Plessers, Sven Casteleyn
2003 Misc conf
SAC
Sven Casteleyn, Olga De Troyer, Saar Brockmans
2003 J jnl
Int. J. Web Eng. Technol.
Olga De Troyer, Sven Casteleyn
2003 B conf
MMM
Olga De Troyer, Wesley Bille, Raul Romero, Peter Stuer
2003 conf
ICWI
Olga De Troyer, Peter Plessers, Sven Casteleyn
2001 ch.
Information Modeling in the New Millennium
Olga De Troyer
2001 conf
ER (Workshops)
Sven Casteleyn, Olga De Troyer
2000 J jnl
World Wide Web
Olga De Troyer, Tom Decruyenaere
1998 A conf
ER
Olga De Troyer
1998 J jnl
Comput. Networks
Olga De Troyer, C. J. Leune
1996 J jnl
Data Knowl. Eng.
Olga De Troyer
1995 conf
OOER
Olga De Troyer, Robert Meersman
1994 conf
ORM
Olga De Troyer
1993 A* conf
ICDE
Olga De Troyer, René Janssen
1991 conf
BNCOD
M. J. Briales, Olga De Troyer
1991 A conf
CAiSE
Olga De Troyer
1989 conf
SIGMOD Conference
Olga De Troyer
1988 conf
Computerized Assistance During the Information Systems Life Cycle
Olga De Troyer, Robert Meersman, P. Verlinden
1986 conf
OODBS
Olga De Troyer, J. Keustermans, Robert Meersman
1986 conf
DS-2
Olga De Troyer
tests/unit/test_cfg_features.py
← Index tests/unit/test_cfg_features.py python
"""
Unit tests for cfg_features.py — all new CFG feature computations.

These tests use plain Python data structures (index-based adjacency lists)
and require no Binary Ninja dependency.
"""
import pytest

from redb.extractors.decompiler.bninja.analysis.cfg_features import (
    bfs_order,
    bfs_max_depth,
    count_back_edges,
    compute_topology_hash,
    compute_md_index_topdown,
    compute_md_index_bottomup,
    compute_prime_product,
    build_block_features,
    compute_cfg_feature_tlsh,
    compute_wl_minhash,
    pack_adjacency,
    LLIL_OP_CATEGORIES,
    CAT_ARITHMETIC,
    CAT_LOGIC,
    CAT_CALL,
    CAT_MEMORY,
    NUM_WL_MINHASH_PERMS,
)


# ===================================================================
# Helper: common graph topologies
# ===================================================================

def _linear_chain(n):
    """0 -> 1 -> 2 -> ... -> (n-1)"""
    return [[i + 1] if i < n - 1 else [] for i in range(n)]


def _diamond():
    """
    0 -> 1, 0 -> 2, 1 -> 3, 2 -> 3
    (classic if/else diamond)
    """
    return [[1, 2], [3], [3], []]


def _predecessors_from_successors(successors, n):
    preds = [[] for _ in range(n)]
    for src, targets in enumerate(successors):
        for tgt in targets:
            preds[tgt].append(src)
    return preds


# ===================================================================
# TestBfsOrder
# ===================================================================

class TestBfsOrder:
    def test_empty_graph(self):
        assert bfs_order([], 0) == []

    def test_single_node(self):
        assert bfs_order([[]], 1) == [0]

    def test_linear_chain(self):
        succs = _linear_chain(4)
        assert bfs_order(succs, 4) == [0, 1, 2, 3]

    def test_diamond(self):
        succs = _diamond()
        order = bfs_order(succs, 4)
        assert order[0] == 0
        assert order[-1] == 3
        assert set(order) == {0, 1, 2, 3}

    def test_unreachable_nodes(self):
        # 0 -> 1, node 2 is unreachable
        succs = [[1], [], []]
        order = bfs_order(succs, 3)
        assert order[:2] == [0, 1]
        assert 2 in order  # unreachable appended

    def test_all_nodes_visited(self):
        succs = _diamond()
        order = bfs_order(succs, 4)
        assert len(order) == 4


# ===================================================================
# TestBfsMaxDepth
# ===================================================================

class TestBfsMaxDepth:
    def test_empty_graph(self):
        assert bfs_max_depth([], 0) == 0

    def test_single_block(self):
        assert bfs_max_depth([[]], 1) == 0

    def test_linear_chain(self):
        succs = _linear_chain(5)
        assert bfs_max_depth(succs, 5) == 4

    def test_diamond(self):
        succs = _diamond()
        assert bfs_max_depth(succs, 4) == 2

    def test_wide_graph(self):
        # 0 -> 1, 0 -> 2, 0 -> 3 (all at depth 1)
        succs = [[1, 2, 3], [], [], []]
        assert bfs_max_depth(succs, 4) == 1


# ===================================================================
# TestCountBackEdges
# ===================================================================

class TestCountBackEdges:
    def test_empty_graph(self):
        assert count_back_edges([], 0) == 0

    def test_no_loops(self):
        succs = _linear_chain(3)
        assert count_back_edges(succs, 3) == 0

    def test_single_loop(self):
        # 0 -> 1 -> 2 -> 0 (one back edge: 2->0)
        succs = [[1], [2], [0]]
        assert count_back_edges(succs, 3) == 1

    def test_nested_loops(self):
        # 0 -> 1 -> 2 -> 1 (inner), 2 -> 3 -> 0 (outer)
        succs = [[1], [2], [1, 3], [0]]
        assert count_back_edges(succs, 4) == 2

    def test_self_loop(self):
        # 0 -> 0 (self-loop)
        succs = [[0]]
        assert count_back_edges(succs, 1) == 1

    def test_diamond_no_loops(self):
        succs = _diamond()
        assert count_back_edges(succs, 4) == 0

    def test_single_node_no_loop(self):
        succs = [[]]
        assert count_back_edges(succs, 1) == 0


# ===================================================================
# TestTopologyHash
# ===================================================================

class TestTopologyHash:
    def test_same_graph_same_hash(self):
        succs = _diamond()
        bfs = bfs_order(succs, 4)
        h1 = compute_topology_hash(succs, bfs, 4)
        h2 = compute_topology_hash(succs, bfs, 4)
        assert h1 == h2

    def test_different_graphs_different_hash(self):
        succs1 = _linear_chain(3)
        bfs1 = bfs_order(succs1, 3)
        h1 = compute_topology_hash(succs1, bfs1, 3)

        succs2 = _diamond()
        bfs2 = bfs_order(succs2, 4)
        h2 = compute_topology_hash(succs2, bfs2, 4)

        assert h1 != h2

    def test_returns_16_bytes(self):
        succs = _diamond()
        bfs = bfs_order(succs, 4)
        h = compute_topology_hash(succs, bfs, 4)
        assert isinstance(h, bytes)
        assert len(h) == 16

    def test_isomorphic_graphs_same_hash(self):
        # Graph A: 0->1, 0->2, 1->3, 2->3 (diamond with successors [1,2])
        succs_a = [[1, 2], [3], [3], []]
        # Graph B: same structure but successors listed as [2,1]
        # BFS from 0 will visit them in different order, but after remapping
        # the canonical form should be identical for isomorphic graphs
        succs_b = [[2, 1], [3], [3], []]

        bfs_a = bfs_order(succs_a, 4)
        bfs_b = bfs_order(succs_b, 4)

        h_a = compute_topology_hash(succs_a, bfs_a, 4)
        h_b = compute_topology_hash(succs_b, bfs_b, 4)
        assert h_a == h_b

    def test_empty_graph(self):
        h = compute_topology_hash([], [], 0)
        assert h == b'\x00' * 16

    def test_single_node(self):
        succs = [[]]
        bfs = bfs_order(succs, 1)
        h = compute_topology_hash(succs, bfs, 1)
        assert isinstance(h, bytes)
        assert len(h) == 16


# ===================================================================
# TestMdIndex
# ===================================================================

class TestMdIndex:
    def test_single_block_topdown(self):
        succs = [[]]
        preds = [[]]
        bfs = [0]
        result = compute_md_index_topdown(succs, preds, bfs)
        assert isinstance(result, int)
        assert result > 0

    def test_single_block_bottomup(self):
        succs = [[]]
        preds = [[]]
        result = compute_md_index_bottomup(succs, preds, 1)
        assert isinstance(result, int)
        assert result > 0

    def test_linear_chain_topdown_vs_bottomup(self):
        succs = _linear_chain(4)
        preds = _predecessors_from_successors(succs, 4)
        bfs = bfs_order(succs, 4)
        td = compute_md_index_topdown(succs, preds, bfs)
        bu = compute_md_index_bottomup(succs, preds, 4)
        # Top-down and bottom-up should be different for a linear chain
        # (entry has in_deg=0, exit has out_deg=0, so the sequences differ)
        assert td != bu

    def test_deterministic(self):
        succs = _diamond()
        preds = _predecessors_from_successors(succs, 4)
        bfs = bfs_order(succs, 4)
        td1 = compute_md_index_topdown(succs, preds, bfs)
        td2 = compute_md_index_topdown(succs, preds, bfs)
        assert td1 == td2

    def test_different_graphs_different_index(self):
        succs1 = _linear_chain(3)
        preds1 = _predecessors_from_successors(succs1, 3)
        bfs1 = bfs_order(succs1, 3)
        td1 = compute_md_index_topdown(succs1, preds1, bfs1)

        succs2 = _diamond()
        preds2 = _predecessors_from_successors(succs2, 4)
        bfs2 = bfs_order(succs2, 4)
        td2 = compute_md_index_topdown(succs2, preds2, bfs2)

        assert td1 != td2

    def test_topdown_empty(self):
        assert compute_md_index_topdown([], [], []) == 0

    def test_bottomup_empty(self):
        assert compute_md_index_bottomup([], [], 0) == 0


# ===================================================================
# TestPrimeProduct
# ===================================================================

class TestPrimeProduct:
    def test_empty(self):
        assert compute_prime_product([]) == 0

    def test_known_sequence(self):
        # Use actual LLIL enum values from conftest_binja_stubs:
        # LLIL_NOP=0 -> prime 1, LLIL_LOAD=4 -> prime 5
        from redb.extractors.decompiler.bninja.analysis.cfg_features import LLIL_OP_PRIMES
        nop_val = 0   # LLIL_NOP
        load_val = 4  # LLIL_LOAD
        expected = LLIL_OP_PRIMES.get(nop_val, 1) * LLIL_OP_PRIMES.get(load_val, 1)
        result = compute_prime_product([nop_val, load_val])
        assert result == expected

    def test_order_independence(self):
        # LLIL_LOAD=4, LLIL_STORE=5, LLIL_ADD=13
        ops_a = [4, 5, 13]
        ops_b = [13, 4, 5]
        assert compute_prime_product(ops_a) == compute_prime_product(ops_b)

    def test_unknown_ops_map_to_1(self):
        # Unknown ops get prime 1, so they don't change the product
        result_known = compute_prime_product([4])  # LLIL_LOAD -> 5
        result_with_unknown = compute_prime_product([4, 9999])  # LOAD * unknown(1)
        assert result_known == result_with_unknown

    def test_mod_2_64(self):
        # Product should be mod 2^64
        result = compute_prime_product([4] * 1000)  # LLIL_LOAD
        assert 0 <= result < 2**64

    def test_single_op(self):
        # LLIL_STORE=5 -> prime 7
        assert compute_prime_product([5]) == 7


# ===================================================================
# TestBuildBlockFeatures
# ===================================================================

class TestBuildBlockFeatures:
    def test_empty_llil(self):
        succs = [[1], []]
        features = build_block_features([[], []], succs, 2)
        assert len(features) == 2
        # All zeros except successor_count
        assert features[0] == [0, 0, 0, 0, 0, 0, 0, 1]  # 1 successor
        assert features[1] == [0, 0, 0, 0, 0, 0, 0, 0]  # 0 successors

    def test_correct_categorization(self):
        # Set up categories for testing
        import redb.extractors.decompiler.bninja.analysis.cfg_features as cf
        old_cats = cf.LLIL_OP_CATEGORIES.copy()
        cf.LLIL_OP_CATEGORIES.update({
            100: CAT_ARITHMETIC,
            101: CAT_ARITHMETIC,
            200: CAT_LOGIC,
            300: CAT_CALL,
            400: CAT_MEMORY,
        })
        try:
            block_ops = [[100, 101, 200, 300, 400]]
            succs = [[]]
            features = build_block_features(block_ops, succs, 1)
            assert features[0][0] == 5   # instr_count
            assert features[0][1] == 2   # arithmetic
            assert features[0][2] == 1   # logic
            assert features[0][4] == 1   # call
            assert features[0][6] == 1   # memory
        finally:
            cf.LLIL_OP_CATEGORIES.clear()
            cf.LLIL_OP_CATEGORIES.update(old_cats)

    def test_cap_at_65535(self):
        # More than 65535 ops in one block
        huge_ops = [0] * 70000  # NOP x 70000
        succs = [[]]
        features = build_block_features([huge_ops], succs, 1)
        assert features[0][0] == 65535  # capped

    def test_missing_block_ops(self):
        # block_llil_ops shorter than n
        succs = [[1], [2], []]
        features = build_block_features([[1, 2]], succs, 3)
        assert len(features) == 3
        # Block 1 and 2 get empty ops since block_llil_ops only has 1 entry
        assert features[1] == [0, 0, 0, 0, 0, 0, 0, 1]
        assert features[2] == [0, 0, 0, 0, 0, 0, 0, 0]


# ===================================================================
# TestCfgFeatureTlsh
# ===================================================================

class TestCfgFeatureTlsh:
    def test_too_few_blocks_returns_none(self):
        # 5 blocks = 5 * 9 bytes = 45 < 50
        bb_features = [[10, 1, 0, 2, 0, 1, 1, 2]] * 5
        bfs = list(range(5))
        result = compute_cfg_feature_tlsh(bb_features, bfs)
        assert result is None

    def test_uniform_data_returns_none(self):
        # 7 identical blocks — TLSH returns TNULL for low-entropy input
        bb_features = [[10, 1, 0, 2, 0, 1, 1, 2]] * 7
        bfs = list(range(7))
        result = compute_cfg_feature_tlsh(bb_features, bfs)
        assert result is None

    def test_varied_data_returns_string(self):
        # 20 blocks with varied features — enough entropy for TLSH
        bb_features = [
            [i * 7 + 3, (i * 13) % 50, (i * 17) % 30, (i * 23) % 40,
             (i * 11) % 20, (i * 7) % 25, (i * 19) % 35, (i * 3) % 10]
            for i in range(20)
        ]
        bfs = list(range(20))
        result = compute_cfg_feature_tlsh(bb_features, bfs)
        assert isinstance(result, str)
        assert len(result) > 0
        assert result.startswith("T1")


# ===================================================================
# TestWlMinhash
# ===================================================================

class TestWlMinhash:
    def test_empty_function(self):
        result = compute_wl_minhash([], [], [], 0)
        assert result == [255] * NUM_WL_MINHASH_PERMS

    def test_returns_128_elements(self):
        succs = _diamond()
        preds = _predecessors_from_successors(succs, 4)
        bb_feats = [[5, 1, 0, 2, 0, 1, 1, 2]] * 4
        result = compute_wl_minhash(succs, preds, bb_feats, 4)
        assert len(result) == 128

    def test_all_uint8(self):
        succs = _linear_chain(3)
        preds = _predecessors_from_successors(succs, 3)
        bb_feats = [[3, 1, 0, 1, 0, 0, 1, 1]] * 3
        result = compute_wl_minhash(succs, preds, bb_feats, 3)
        assert all(0 <= v <= 255 for v in result)

    def test_identical_graphs_same_signature(self):
        succs = _diamond()
        preds = _predecessors_from_successors(succs, 4)
        bb_feats = [[5, 1, 0, 2, 0, 1, 1, 2]] * 4
        sig1 = compute_wl_minhash(succs, preds, bb_feats, 4)
        sig2 = compute_wl_minhash(succs, preds, bb_feats, 4)
        assert sig1 == sig2

    def test_different_graphs_different_signatures(self):
        # Graph 1: linear chain
        succs1 = _linear_chain(4)
        preds1 = _predecessors_from_successors(succs1, 4)
        bb_feats1 = [[5, 1, 0, 2, 0, 1, 1, i] for i in range(4)]
        sig1 = compute_wl_minhash(succs1, preds1, bb_feats1, 4)

        # Graph 2: diamond
        succs2 = _diamond()
        preds2 = _predecessors_from_successors(succs2, 4)
        bb_feats2 = [[10, 3, 2, 1, 0, 0, 0, i] for i in range(4)]
        sig2 = compute_wl_minhash(succs2, preds2, bb_feats2, 4)

        assert sig1 != sig2

    def test_single_node(self):
        succs = [[]]
        preds = [[]]
        bb_feats = [[1, 0, 0, 0, 0, 0, 0, 0]]
        result = compute_wl_minhash(succs, preds, bb_feats, 1)
        assert len(result) == 128


# ===================================================================
# TestPackAdjacency
# ===================================================================

class TestPackAdjacency:
    def test_empty(self):
        assert pack_adjacency([]) == []

    def test_single_edge(self):
        succs = [[1], []]
        edges = pack_adjacency(succs)
        assert len(edges) == 1
        assert edges[0] == (0 << 16) | 1

    def test_correct_packing(self):
        succs = _diamond()
        edges = pack_adjacency(succs)
        assert len(edges) == 4
        # 0->1, 0->2, 1->3, 2->3
        expected = {
            (0 << 16) | 1,
            (0 << 16) | 2,
            (1 << 16) | 3,
            (2 << 16) | 3,
        }
        assert set(edges) == expected

    def test_roundtrip(self):
        """Unpack edges and verify source/target pairs."""
        succs = [[1, 2], [3], [3], []]
        edges = pack_adjacency(succs)
        unpacked = [(e >> 16, e & 0xFFFF) for e in edges]
        expected = [(0, 1), (0, 2), (1, 3), (2, 3)]
        assert sorted(unpacked) == sorted(expected)

    def test_large_index_filtered(self):
        # Create a successor list where index >= 65536
        succs = [[] for _ in range(65537)]
        succs[0] = [65536]  # target is exactly 65536 — should be filtered
        edges = pack_adjacency(succs)
        assert len(edges) == 0

    def test_max_valid_index(self):
        # Index 65535 is the maximum valid
        succs = [[] for _ in range(65536)]
        succs[0] = [65535]
        edges = pack_adjacency(succs)
        assert len(edges) == 1
        assert edges[0] == (0 << 16) | 65535