Maggie X. Cheng

44 papers B 10C 1Journal 10Unranked 22
YearRankTypeTitle / Venue / Authors
2024 conf
ICPR (4)
Huiyuan Yu, Maggie X. Cheng
2024 J jnl
CoRR
Huiyuan Yu, Jia He, Maggie X. Cheng
2024 conf
ICPR (32)
Huiyuan Yu, Jia He, Maggie X. Cheng
2021 conf
ICC
Shuya Feng, Jia He, Maggie X. Cheng
2021 J jnl
Frontiers Big Data
Jia He, Maggie X. Cheng
2020 B conf
ICPR
Huiyuan Yu, Maggie X. Cheng, Yingdong Lu
2020 B conf
ICPR
Jia He, Maggie X. Cheng
2019 conf
AMCIS
Xinhui Zhan, Fiona Nah, Keng Siau, Richard H. Hall, Maggie X. Cheng
2018 conf
LOD
Jia He, Maggie X. Cheng, Yixin Fang, Mariesa L. Crow
2018 conf
HCI (23)
Xinhui Zhan, Fiona Fui-Hoon Nah, Maggie X. Cheng
2018 conf
ICC
Maggie X. Cheng, Yi Ling, Wei Biao Wu
2017 J jnl
Theor. Comput. Sci.
Maggie X. Cheng, Yi Ling, Brian M. Sadler
2017 B conf
GLOBECOM
Maggie X. Cheng, Yi Ling, Wei Biao Wu
2016 J jnl
IEEE Internet Things J.
Wei Biao Wu, Maggie X. Cheng, Bei Gou
2016 conf
ICC
Maggie X. Cheng, Wei Biao Wu
2016 J jnl
IEEE Internet Things J.
Maggie X. Cheng, Wei Biao Wu
2016 conf
ICC
Maggie X. Cheng, Yi Ling, Wei Biao Wu
2016 conf
ICC
Maggie X. Cheng, Quanmin Ye, Xiaochun Cheng, Lin Cai
2016 conf
HCI (20)
Samuel N. Smith, Fiona Fui-Hoon Nah, Maggie X. Cheng
2015 conf
ICC
Maggie X. Cheng, Quanmin Ye, Xiaochun Cheng, Robert F. Erbacher
2015 conf
ICC
Maggie X. Cheng, Yi Ling, Brian M. Sadler
2014 conf
IEEE SCC
Kenneth K. Fletcher, Xiaoqing (Frank) Liu, Maggie X. Cheng
2014 B conf
GLOBECOM
Maggie X. Cheng, Quanmin Ye, Lin Cai
2014 B conf
GLOBECOM
Maggie X. Cheng, Yi Ling, Brian M. Sadler
2013 conf
ICC
Maggie X. Cheng, Quanmin Ye, Robert F. Erbacher
2013 conf
ICC
Maggie X. Cheng, Quanmin Ye, Xiaochun Cheng
2013 conf
CSIIRW
Maggie X. Cheng, Quanmin Ye, Robert F. Erbacher
2013 conf
CSIIRW
Maggie X. Cheng, Mariesa L. Crow, Robert F. Erbacher
2011 J jnl
IEEE Trans. Veh. Technol.
Maggie X. Cheng, Xuan Gong, Lin Cai, Xiaohua Jia
2011 B conf
GLOBECOM
Maggie X. Cheng, Xuan Gong, Yibo Xu, Lin Cai
2011 J jnl
J. Glob. Optim.
Maggie X. Cheng, Xuan Gong
2011 conf
WASA
Maggie X. Cheng, Xuan Gong, Peng-Jun Wan
2011 J jnl
Discret. Math. Algorithms Appl.
Xuan Gong, Maggie X. Cheng, Yibo Xu
2011 C conf
COCOA
Maggie X. Cheng, Quanmin Ye
2010 B conf
GLOBECOM
Maggie X. Cheng, Xuan Gong
2009 B conf
SMC
Raghavendra V. Kulkarni, Ganesh K. Venayagamoorthy, Maggie X. Cheng
2009 conf
ICC
Maggie X. Cheng, Xuan Gong, Scott C.-H. Huang
2009 ed.
NanoNet
Maggie X. Cheng
2008 J jnl
Int. J. Sens. Networks
Maggie X. Cheng, Li Yin
2008 B conf
GLOBECOM
Maggie X. Cheng, Xuan Gong, Lin Cai
2008 conf
WASA
Maggie X. Cheng, Xuan Gong, Lin Cai, Ahmad Ali Abdullah
2007 conf
ICC
Maggie X. Cheng, Li Yin
2006 B conf
GLOBECOM
Maggie X. Cheng, Yadi Ma, Yi Wang
2004 J jnl
J. Aerosp. Comput. Inf. Commun.
Maggie X. Cheng, Yiyuan J. Zhao
tests/unit/test_decompile_similarity.py
← Index tests/unit/test_decompile_similarity.py python
"""Unit tests for similarity modules:
- bninja/similarity/minhashcustom.py
- bninja/similarity/minhasher.py
"""
import numpy as np
import pytest

from redb.extractors.decompiler.bninja.similarity.minhashcustom import MinHashCustom
from redb.extractors.decompiler.bninja.analysis.low_level_normalization import LowLevelNormalization


# ============================================================================
# 2a. MinHashCustom
# ============================================================================

class TestMinHashCustomInit:
    def test_init_empty(self):
        mh = MinHashCustom()
        assert not mh.hasMinHash()
        assert mh.minhash == b""
        assert mh.minhash_int == []

    def test_init_from_signature(self):
        sig = [10, 20, 30, 40]
        mh = MinHashCustom(minhash_signature=sig)
        assert mh.hasMinHash()
        assert mh.minhash_int == sig

    def test_init_from_bytes_uint32(self):
        """Verify round-trip: ints -> bytes -> MinHashCustom -> ints."""
        sig = [100, 200, 300]
        packed = np.array(sig, dtype=np.uint32).tobytes()
        # np.frombuffer returns numpy scalars; setMinHash does % 2**32 which
        # overflows numpy uint32, so verify the raw bytes round-trip instead.
        raw_arr = np.frombuffer(packed, dtype=np.uint32)
        assert list(raw_arr) == sig

    def test_init_from_bytes_uint8(self):
        """Verify round-trip: ints -> bytes -> back."""
        sig = [10, 20, 30]
        packed = np.array(sig, dtype=np.uint8).tobytes()
        raw_arr = np.frombuffer(packed, dtype=np.uint8)
        assert list(raw_arr) == sig

    def test_init_both_raises(self):
        sig = [1, 2, 3]
        packed = np.array(sig, dtype=np.uint32).tobytes()
        with pytest.raises(ValueError, match="only one"):
            MinHashCustom(minhash_bytes=packed, minhash_signature=sig)


class TestMinHashCustomSetGet:
    def test_set_and_get_minhash(self):
        mh = MinHashCustom()
        sig = [5, 10, 15]
        mh.setMinHash(sig)
        raw = mh.getMinHash()
        assert raw == np.array(sig, dtype=np.uint32).tobytes()
        assert mh.getMinHashInt() == sig

    def test_minhash_int_truncation(self):
        mh = MinHashCustom(minhash_bits=8)
        # Values > 256 should be truncated mod 2^8
        mh.setMinHash([300, 500, 256])
        for val in mh.minhash_int:
            assert 0 <= val < 256


class TestMinHashCustomHashData:
    def test_hash_data_string(self):
        result = MinHashCustom.hashData("hello", 42)
        assert isinstance(result, int)
        assert 0 <= result <= 0xFFFFFFFF

    def test_hash_data_bytes(self):
        result = MinHashCustom.hashData(b"bytes", 42)
        assert isinstance(result, int)
        assert 0 <= result <= 0xFFFFFFFF

    def test_hash_data_list(self):
        result = MinHashCustom.hashData([1, 2, 3], 42)
        assert isinstance(result, int)
        assert 0 <= result <= 0xFFFFFFFF

    def test_hash_data_unsupported_type(self):
        with pytest.raises(NotImplementedError, match="Type not supported"):
            MinHashCustom.hashData(123, 42)

    def test_hash_data_deterministic(self):
        assert MinHashCustom.hashData("test", 7) == MinHashCustom.hashData("test", 7)


class TestMinHashCustomScore:
    def test_score_identical(self):
        sig = [1, 2, 3, 4, 5]
        mh1 = MinHashCustom(minhash_signature=sig)
        mh2 = MinHashCustom(minhash_signature=sig)
        score = MinHashCustom.calculateMinHashScore(
            mh1.getMinHash(), mh2.getMinHash()
        )
        assert score == 100.0

    def test_score_different(self):
        mh1 = MinHashCustom(minhash_signature=[1, 2, 3, 4, 5])
        mh2 = MinHashCustom(minhash_signature=[6, 7, 8, 9, 10])
        score = MinHashCustom.calculateMinHashScore(
            mh1.getMinHash(), mh2.getMinHash()
        )
        assert score < 100.0

    def test_score_against(self):
        sig1 = [1, 2, 3, 4, 5]
        sig2 = [1, 2, 99, 4, 5]
        mh1 = MinHashCustom(minhash_signature=sig1)
        mh2 = MinHashCustom(minhash_signature=sig2)
        instance_score = mh1.scoreAgainst(mh2)
        static_score = MinHashCustom.calculateMinHashScore(
            mh1.getMinHash(), mh2.getMinHash()
        )
        assert instance_score == static_score


class TestMinHashCustomBitModes:
    def test_8bit_mode(self):
        mh = MinHashCustom(minhash_bits=8)
        mh.setMinHash([10, 20, 30])
        raw = mh.getMinHash()
        arr = np.frombuffer(raw, dtype=np.uint8)
        assert list(arr) == [10, 20, 30]

    def test_32bit_mode(self):
        mh = MinHashCustom(minhash_bits=32)
        mh.setMinHash([10, 20, 30])
        raw = mh.getMinHash()
        arr = np.frombuffer(raw, dtype=np.uint32)
        assert list(arr) == [10, 20, 30]


# ============================================================================
# 2b. MinHasher
# ============================================================================


class MockILNode:
    """Mock IL node with operation and operands for normalization."""
    def __init__(self, operation, operands=None):
        self.operation = operation
        self.operands = operands or []


class MockLLILBasicBlock:
    """Mock LLIL basic block that yields IL instructions."""
    def __init__(self, instructions):
        self._instructions = instructions

    def __iter__(self):
        return iter(self._instructions)


class MockLLILFunction:
    """Mock LLIL function with basic blocks."""
    def __init__(self, basic_blocks):
        self.basic_blocks = basic_blocks


# Import MinHasher after we know the module can handle the import
from redb.extractors.decompiler.bninja.similarity.minhasher import (
    MinHasher,
    MINHASH_SIGNATURE_LENGTH,
    MINHASH_SIGNATURE_BITS,
)


class TestMinHasherMakeNgrams:
    def setup_method(self):
        # Create a minimal minhasher with a mock LLIL function
        empty_func = MockLLILFunction([])
        self.hasher = MinHasher(seed=42, il_function=empty_func)

    def test_make_ngrams_basic(self):
        result = self.hasher.make_ngrams(["a", "b", "c", "d"], n=3)
        assert result == [("a", "b", "c"), ("b", "c", "d")]

    def test_make_ngrams_short_input(self):
        result = self.hasher.make_ngrams(["a", "b"], n=3)
        assert result == []

    def test_make_ngrams_exact_n(self):
        result = self.hasher.make_ngrams(["a", "b", "c"], n=3)
        assert result == [("a", "b", "c")]


class TestMinHasherCalculate:
    def _make_llil_function(self, num_instructions=10):
        """Create a mock LLIL function with enough instructions."""
        instructions = [
            MockILNode(operation=i % 20) for i in range(num_instructions)
        ]
        bb = MockLLILBasicBlock(instructions)
        return MockLLILFunction([bb])

    def test_calculate_minhash_empty_function(self):
        # Function with < 3 LLIL instructions -> empty list
        func = self._make_llil_function(num_instructions=2)
        hasher = MinHasher(seed=42, il_function=func)
        result = hasher.calculateMinHash()
        assert result == []

    def test_calculate_minhash_deterministic(self):
        func = self._make_llil_function(num_instructions=20)
        h1 = MinHasher(seed=42, il_function=func)
        h2 = MinHasher(seed=42, il_function=func)
        assert h1.calculateMinHash() == h2.calculateMinHash()

    def test_calculate_minhash_length(self):
        func = self._make_llil_function(num_instructions=20)
        hasher = MinHasher(seed=42, il_function=func)
        result = hasher.calculateMinHash()
        assert len(result) == MINHASH_SIGNATURE_LENGTH

    def test_calculate_minhash_value_range(self):
        func = self._make_llil_function(num_instructions=20)
        hasher = MinHasher(seed=42, il_function=func)
        result = hasher.calculateMinHash()
        for val in result:
            assert 0 <= val < 2 ** MINHASH_SIGNATURE_BITS

    def test_shingle_hash_deterministic(self):
        func = self._make_llil_function(num_instructions=5)
        hasher = MinHasher(seed=42, il_function=func)
        shingle = ([1, 2], [3, 4], [5, 6])
        assert hasher.shingle_hash(shingle, 99) == hasher.shingle_hash(shingle, 99)

    def test_seed_reproducibility(self):
        func = self._make_llil_function(num_instructions=20)
        h1 = MinHasher(seed=1, il_function=func)
        h2 = MinHasher(seed=2, il_function=func)
        r1 = h1.calculateMinHash()
        r2 = h2.calculateMinHash()
        # Different seeds should (very likely) produce different results
        assert r1 != r2