Rabab Kreidieh Ward

115 papers A 2B 17C 6Misc 11Journal 46Unranked 33
YearRankTypeTitle / Venue / Authors
2023 J jnl
IEEE Signal Process. Mag.
Athina P. Petropulu, José M. F. Moura, Rabab Kreidieh Ward, Theresa Argiropoulos
2023 J jnl
IEEE Signal Process. Mag.
Rabab Kreidieh Ward
2021 J jnl
IEEE Trans. Geosci. Remote. Sens.
Jianzhe Lin, Tianze Yu, Lichao Mou, Xiaoxiang Zhu, Rabab Kreidieh Ward, Z. Jane Wang
2018 J jnl
Multim. Tools Appl.
Sima Valizadeh, Panos Nasiopoulos, Rabab Kreidieh Ward
2017 J jnl
Signal Process.
Hamid Palangi, Rabab Kreidieh Ward, Li Deng
2017 conf
GlobalSIP
Ramy Hussein, Mohamed Elgendi, Rabab Kreidieh Ward, Amr Mohamed
2017 B conf
IJCNN
Angshul Majumdar, Rabab Kreidieh Ward
2017 J jnl
IEEE Trans. Biomed. Eng.
Anupriya Gogna, Angshul Majumdar, Rabab Kreidieh Ward
2016 conf
CCECE
Hesham Mahrous, Rabab Kreidieh Ward
2016 B conf
IJCNN
Prerna Khurana, Angshul Majumdar, Rabab Kreidieh Ward
2016 Misc conf
ICASSP
Hamid Palangi, Rabab Kreidieh Ward, Li Deng
2016 conf
GlobalSIP
Ramy Hussein, Z. Jane Wang, Rabab Kreidieh Ward
2016 J jnl
IEEE Signal Process. Mag.
Rabab Kreidieh Ward
2016 C conf
ICCE
Sima Valizadeh, Panos Nasiopoulos, Rabab Kreidieh Ward
2016 B conf
IJCNN
Angshul Majumdar, Rabab Kreidieh Ward
2016 conf
GlobalSIP
Hamid Palangi, Rabab Kreidieh Ward, Li Deng
2016 Misc conf
ICASSP
Angshul Majumdar, Rabab Kreidieh Ward
2015 B conf
ICIP
Angshul Majumdar, Rabab Kreidieh Ward
2015 conf
GlobalSIP
Mushfiqur Rouf, Rabab Kreidieh Ward
2013 J jnl
IEEE Trans. Multim.
Xun Chen, Xiang Chen, Rabab Kreidieh Ward, Z. Jane Wang
2013 J jnl
IEEE Trans. Multim.
Zicong Mai, Hassan Mansour, Panos Nasiopoulos, Rabab Kreidieh Ward
2012 J jnl
IEEE Trans. Pattern Anal. Mach. Intell.
Mani Malek Esmaeili, Rabab Kreidieh Ward, Mehrdad Fatourechi
2012 B conf
ICIP
Angshul Majumdar, Rabab Kreidieh Ward, Tyseer Aboulnasr
2012 Misc conf
ICASSP
Tanaya Guha, Rabab Kreidieh Ward
2012 conf
ISBI
Mehrnoush Khojasteh, Rabab Kreidieh Ward, Calum MacAulay
2012 J jnl
IEEE J. Sel. Top. Signal Process.
Zicong Mai, Colin Doutre, Panos Nasiopoulos, Rabab Kreidieh Ward
2012 Misc conf
ICASSP
Angshul Majumdar, Rabab Kreidieh Ward
2011 J jnl
IEEE Trans. Inf. Forensics Secur.
Mani Malek Esmaeili, Mehrdad Fatourechi, Rabab Kreidieh Ward
2011 J jnl
IEEE Trans. Image Process.
Zicong Mai, Hassan Mansour, Rafal Mantiuk, Panos Nasiopoulos, Rabab Kreidieh Ward, Wolfgang Heidrich
2011 J jnl
IEEE Trans. Inf. Forensics Secur.
Ehsan Nezhadarya, Z. Jane Wang, Rabab Kreidieh Ward
2011 J jnl
Signal Process.
Angshul Majumdar, Rabab Kreidieh Ward
2010 B conf
DCC
Angshul Majumdar, Rabab Kreidieh Ward
2010 Misc conf
ICASSP
Ehsan Nezhadarya, Rabab Kreidieh Ward
2010 Misc conf
ICASSP
Hassan Mansour, Rayan Saab, Panos Nasiopoulos, Rabab Kreidieh Ward
2010 B conf
ICIP
Angshul Majumdar, Rabab Kreidieh Ward
2010 Misc conf
ICASSP
Tanaya Guha, Rabab Kreidieh Ward
2010 C conf
ISCAS
Qiang Tang, Panos Nasiopoulos, Rabab Kreidieh Ward
2010 B conf
ICIP
Ning Sun, Hassan Mansour, Rabab Kreidieh Ward
2010 Misc conf
ICASSP
Angshul Majumdar, Rabab Kreidieh Ward
2010 C conf
ISCAS
Zicong Mai, Hassan Mansour, Rafal Mantiuk, Panos Nasiopoulos, Rabab Kreidieh Ward, Wolfgang Heidrich
2010 J jnl
IEEE Trans. Geosci. Remote. Sens.
Kaan Ersahin, Ian G. Cumming, Rabab Kreidieh Ward
2010 B conf
ICIP
Zicong Mai, Hassan Mansour, Panos Nasiopoulos, Rabab Kreidieh Ward
2010 B conf
ICIP
Ehsan Nezhadarya, Z. Jane Wang, Rabab Kreidieh Ward
2009 B conf
MMM
Mahsa T. Pourazad, Panos Nasiopoulos, Rabab Kreidieh Ward
2009 conf
CCECE
Angshul Majumdar, Rabab Kreidieh Ward
2009 B conf
ICIP
Qiang Tang, Panos Nasiopoulos, Rabab Kreidieh Ward
2009 A conf
GECCO
Tarundeep Singh, Nawwaf Kharma, Mohmmad Daoud, Rabab Kreidieh Ward
2009 J jnl
IEEE Trans. Syst. Man Cybern. Part B
Shan Du, Rabab Kreidieh Ward
2009 conf
SoCC
Sohaib Majzoub, Resve A. Saleh, Steven J. E. Wilton, Rabab Kreidieh Ward
2008 conf
ISWPC
Qiang Tang, Hassan Mansour, Panos Nasiopoulos, Rabab Kreidieh Ward
2008 J jnl
IEEE Trans. Circuits Syst. Video Technol.
Qiang Tang, Panos Nasiopoulos, Rabab Kreidieh Ward
2008 conf
EUSIPCO
Maha Shadaydeh, Yegui Xiao, Rabab Kreidieh Ward
2008 C conf
ISCAS
Yegui Xiao, Maha Shadaydeh, Rabab Kreidieh Ward
2007 J jnl
IEEE Trans. Image Process.
Qing Wang, Rabab Kreidieh Ward
2007 conf
ICIP (1)
Shan Du, Rabab Kreidieh Ward
2007 conf
ICDIM
Lino Coria-Mendoza, Panos Nasiopoulos, Rabab Kreidieh Ward, Mark R. Pickering
2007 J jnl
Signal Process.
Yegui Xiao, Liying Ma, Rabab Kreidieh Ward
2006 conf
Digital Rights Management Workshop
Lino Coria-Mendoza, Panos Nasiopoulos, Rabab Kreidieh Ward
2006 conf
EUSIPCO
Mahsa T. Pourazad, Panos Nasiopoulos, Rabab Kreidieh Ward
2006 J jnl
IEEE Trans. Multim.
Mehran Azimi, Panos Nasiopoulos, Rabab Kreidieh Ward
2005 C conf
Communication Systems and Applications
Jiancheng Zou, Wenqi Zhong, Rabab Kreidieh Ward
2005 J jnl
IEEE Trans. Circuits Syst. I Regul. Pap.
Yegui Xiao, Rabab Kreidieh Ward, Liying Ma, Akira Ikuta
2005 conf
ICIP (1)
Lino Coria-Mendoza, Panos Nasiopoulos, Rabab Kreidieh Ward
2005 J jnl
BMC Bioinform.
Mehrnoush Khojasteh, Wan L. Lam, Rabab Kreidieh Ward, Calum MacAulay
2005 conf
ICIP (2)
Qing Wang, Rabab Kreidieh Ward, Jiancheng Zou
2005 J jnl
IEEE Trans. Signal Process.
Mehran Azimi, Panos Nasiopoulos, Rabab Kreidieh Ward
2005 conf
ICIP (2)
Shan Du, Rabab Kreidieh Ward
2004 conf
ISCAS (3)
Jiancheng Zou, Rabab Kreidieh Ward, Dongxu Qi
2004 B conf
ICIP
Liying Ma, Yegui Xiao, Khashayar Khorasani, Rabab Kreidieh Ward
2004 conf
ISCAS (3)
Yegui Xiao, Liying Ma, Rabab Kreidieh Ward, Li Xu
2004 conf
ISCAS (3)
Alireza Nasiri Avanaki, Babak Hamidzadeh, Faouzi Kossentini, Rabab Kreidieh Ward
2004 J jnl
J. Intell. Fuzzy Syst.
Hongjian Shi, Nawwaf Kharma, Rabab Kreidieh Ward
2004 J jnl
Math. Comput. Simul.
Maher Ahmed, Rabab Kreidieh Ward, Nawwaf Kharma
2004 J jnl
IEEE Trans. Circuits Syst. I Regul. Pap.
Yegui Xiao, Akira Ikuta, Liying Ma, Li Xu, Rabab Kreidieh Ward
2003 conf
ICIP (3)
Qing Wang, Rabab Kreidieh Ward
2003 conf
ISCAS (4)
Yegui Xiao, Rabab Kreidieh Ward, Li Xu
2003 A conf
INTERSPEECH
Huiqun Deng, Michael P. Beddoes, Rabab Kreidieh Ward, Murray Hodgson
2003 J jnl
IEEE Trans. Signal Process.
Yegui Xiao, Rabab Kreidieh Ward, Akira Ikuta
2003 J jnl
IEEE Trans. Image Process.
Ying Luo, Rabab Kreidieh Ward
2003 conf
ISCAS (4)
Yegui Xiao, Rabab Kreidieh Ward, Akira Ikuta
2003 J jnl
IEEE Trans. Signal Process.
Michael D. Adams, Rabab Kreidieh Ward
2002 J jnl
IEEE Trans. Pattern Anal. Mach. Intell.
Maher Ahmed, Rabab Kreidieh Ward
2002 conf
ICIP (3)
Mehran Azimi, Panos Nasiopoulos, Rabab Kreidieh Ward
2002 J jnl
IEEE Trans. Broadcast.
Panos Nasiopoulos, Rabab Kreidieh Ward
2002 J jnl
IEEE Trans. Biomed. Eng.
Parvin Mousavi, Rabab Kreidieh Ward, Sidney S. Fels, Mohammad Sameti, Peter M. Lansdorp
2002 conf
ICIP (3)
Qing Wang, Rabab Kreidieh Ward, Hongjian Shi
2002 Misc conf
ICASSP
Michael D. Adams, Rabab Kreidieh Ward
2001 conf
ICIP (3)
Qing Wang, Rabab Kreidieh Ward
2001 conf
ICIP (2)
Parvin Mousavi, Sidney S. Fels, Rabab Kreidieh Ward, Peter M. Lansdorp
2001 conf
ICIP (1)
Mehran Azimi, Panos Nasiopoulos, Rabab Kreidieh Ward
2000 J jnl
IEEE J. Sel. Areas Commun.
Shahram Shirani, Faouzi Kossentini, Rabab Kreidieh Ward
2000 B conf
ICIP
Ismaeil R. Ismaeil, Shahram Shirani, Faouzi Kossentini, Rabab Kreidieh Ward
2000 J jnl
Pattern Recognit.
Maher Ahmed, Rabab Kreidieh Ward
2000 Misc conf
ICASSP
Ismaeil R. Ismaeil, Alen Docef, Faouzi Kossentini, Rabab Kreidieh Ward
2000 B conf
ICIP
Katerina Pronina, Rabab Kreidieh Ward, Panos Nasiopoulos
2000 B conf
ICIP
Parvin Mousavi, Rabab Kreidieh Ward, Peter M. Lansdorp, Sidney S. Fels
2000 J jnl
IEEE Trans. Image Process.
Shahram Shirani, Faouzi Kossentini, Rabab Kreidieh Ward
1999 conf
ICIP (3)
Shahram Shirani, Ali Jerbi, Faouzi Kossentini, Rabab Kreidieh Ward, Q. M. Jonathan Wu
1999 conf
ICIP (1)
Ismaeil R. Ismaeil, Alen Docef, Faouzi Kossentini, Rabab Kreidieh Ward
1999 B conf
Data Compression Conference
Ismaeil R. Ismaeil, Alen Docef, Faouzi Kossentini, Rabab Kreidieh Ward
1998 J jnl
J. Electronic Imaging
Maher Ahmed, Rabab Kreidieh Ward
1998 conf
ICIP (3)
Shahram Shirani, Faouzi Kossentini, Rabab Kreidieh Ward
1997 conf
ICIP (2)
Yuen-Wen Lee, Faouzi Kossentini, Rabab Kreidieh Ward
1997 J jnl
IEEE J. Sel. Areas Commun.
Faouzi Kossentini, Yuen-Wen Lee, Mark J. T. Smith, Rabab Kreidieh Ward
1997 J jnl
Signal Process. Image Commun.
Yuen-Wen Lee, Faouzi Kossentini, Rabab Kreidieh Ward, Mark J. T. Smith
1996 Misc conf
ICASSP
Yuen-Wen Lee, Faouzi Kossentini, Rabab Kreidieh Ward
1996 J jnl
IEEE Trans. Image Process.
Farzin Aghdasi, Rabab Kreidieh Ward
1996 conf
ICIP (1)
Yuen-Wen Lee, Rabab Kreidieh Ward, Faouzi Kossentini, Mark J. T. Smith
1995 C conf
ISCAS
Panos Nasiopoulos, Rabab Kreidieh Ward
1994 J jnl
IEEE Trans. Broadcast.
Panos Nasiopoulos, Rabab Kreidieh Ward
1993 J jnl
IEEE Trans. Image Process.
Rabab Kreidieh Ward
1992 J jnl
IEEE Trans. Image Process.
Ling Guan, Rabab Kreidieh Ward
1989 J jnl
IEEE Trans. Acoust. Speech Signal Process.
Claudio Rey, Rabab Kreidieh Ward
1987 J jnl
IEEE Trans. Acoust. Speech Signal Process.
Rabab Kreidieh Ward, Bahaa E. A. Saleh
1984 J jnl
IEEE Trans. Syst. Man Cybern.
Rabab Kreidieh Ward
tests/unit/test_smali_normalization.py
← Index tests/unit/test_smali_normalization.py python
"""Unit tests for smali semantic normalization.

Tests the three normalization levels (category, opcode, opcode_api),
opcode categorization, ACFG feature index mapping, and integration
with MinHash computation.
"""
import pytest

pytestmark = [pytest.mark.unit, pytest.mark.apk, pytest.mark.decompile]


class TestCategorizeOpcode:
    """Tests for opcode -> semantic category mapping."""

    def test_arithmetic(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("add-int") == "ALU"
        assert categorize_opcode("mul-long/2addr") == "ALU"
        assert categorize_opcode("neg-int") == "ALU"

    def test_data_movement(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("move-result") == "MOV"
        assert categorize_opcode("const/4") == "CONST"
        assert categorize_opcode("const-string") == "CONST"

    def test_memory_access(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("iget-object") == "LOAD"
        assert categorize_opcode("sput-wide") == "STORE"
        assert categorize_opcode("aget-byte") == "LOAD"

    def test_invocation(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("invoke-virtual") == "CALL"
        assert categorize_opcode("invoke-static") == "CALL"
        assert categorize_opcode("invoke-direct") == "CALL"

    def test_control_flow(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("if-eqz") == "BRANCH"
        assert categorize_opcode("goto") == "JMP"
        assert categorize_opcode("goto/16") == "JMP"
        assert categorize_opcode("return-void") == "RET"

    def test_comparison(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("cmp-long") == "CMP"
        assert categorize_opcode("cmpl-float") == "CMP"
        assert categorize_opcode("cmpg-double") == "CMP"

    def test_conversion(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("int-to-long") == "CONV"
        assert categorize_opcode("float-to-int") == "CONV"

    def test_object_type(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("new-instance") == "ALLOC"
        assert categorize_opcode("check-cast") == "TYPE"
        assert categorize_opcode("instance-of") == "TYPE"

    def test_exception_sync(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("throw") == "EXC"
        assert categorize_opcode("monitor-enter") == "SYNC"

    def test_unknown(self):
        from redb.extractors.decompiler.apk.smali_normalization import categorize_opcode
        assert categorize_opcode("nop") == "OTHER"


class TestNormalizeInstruction:
    """Tests for single instruction normalization at various levels."""

    def test_category_level(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        assert normalize_instruction("add-int v0, v1, v2", "category") == "ALU"
        assert normalize_instruction("invoke-virtual {p0}, Lcom/Foo;->bar()V", "category") == "CALL"
        assert normalize_instruction("return-void", "category") == "RET"

    def test_opcode_level_strips_width(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        # Width variants collapse to same base
        assert normalize_instruction("add-int v0, v1, v2", "opcode") == "add"
        assert normalize_instruction("add-long v0, v2, v4", "opcode") == "add"
        assert normalize_instruction("add-float v0, v1, v2", "opcode") == "add"
        # Addressing modes collapse too
        assert normalize_instruction("add-int/2addr v0, v1", "opcode") == "add"

    def test_opcode_api_invoke(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        result = normalize_instruction(
            "invoke-virtual {p0, v0}, Lcom/example/Foo;->bar(I)V"
        )
        assert result == "CALL Lcom/example/Foo;->bar(I)V"

    def test_opcode_api_invoke_no_ref(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        # If somehow no method ref is found, fallback to CALL
        assert normalize_instruction("invoke-virtual {v0}") == "CALL"

    def test_opcode_api_field_load(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        result = normalize_instruction(
            "iget-object v0, p0, Lcom/Foo;->mField:Ljava/lang/String;"
        )
        assert result == "LOAD Lcom/Foo;->mField:Ljava/lang/String;"

    def test_opcode_api_field_store(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        result = normalize_instruction(
            "iput-object v0, p0, Lcom/Foo;->mField:Ljava/lang/String;"
        )
        assert result == "STORE Lcom/Foo;->mField:Ljava/lang/String;"

    def test_opcode_api_androguard_field_format(self):
        """androguard uses space instead of colon in field references."""
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        result = normalize_instruction(
            "iget-object v0, p0, Lcom/Foo;->mField Ljava/lang/String;"
        )
        assert result.startswith("LOAD")
        assert "Lcom/Foo;->mField" in result

    def test_opcode_api_new_instance(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        result = normalize_instruction(
            "new-instance v0, Lcom/example/MyClass;"
        )
        assert result == "ALLOC Lcom/example/MyClass;"

    def test_opcode_api_const_string(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        result = normalize_instruction(
            'const-string v0, "hello world"'
        )
        assert result == 'CONST_STR "hello world"'

    def test_opcode_api_const_string_jumbo(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        result = normalize_instruction(
            'const-string/jumbo v0, "large string"'
        )
        assert result == 'CONST_STR "large string"'

    def test_opcode_api_fallback_to_category(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        # Non-special instructions fall back to category
        assert normalize_instruction("add-int v0, v1, v2") == "ALU"
        assert normalize_instruction("return-void") == "RET"
        assert normalize_instruction("nop") == "OTHER"

    def test_empty_input(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_instruction
        assert normalize_instruction("") == ""
        assert normalize_instruction("   ") == ""


class TestNormalizeMethodBody:
    """Tests for full method body normalization."""

    def test_filters_directives_labels_comments(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_method_body
        body = """\
.locals 2
# comment
:label_0
add-int v0, v1, v2
.line 42
invoke-virtual {p0}, Lcom/Foo;->bar()V
return-void
"""
        result = normalize_method_body(body, "category")
        assert result == ["ALU", "CALL", "RET"]

    def test_opcode_api_preserves_api_refs(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_method_body
        body = """\
const/4 v0, 0x0
invoke-virtual {p0, v0}, Lcom/Foo;->setX(I)V
iget-object v1, p0, Lcom/Foo;->name:Ljava/lang/String;
return-void
"""
        result = normalize_method_body(body, "opcode_api")
        assert result[0] == "CONST"
        assert result[1] == "CALL Lcom/Foo;->setX(I)V"
        assert result[2] == "LOAD Lcom/Foo;->name:Ljava/lang/String;"
        assert result[3] == "RET"

    def test_empty_body(self):
        from redb.extractors.decompiler.apk.smali_normalization import normalize_method_body
        assert normalize_method_body("") == []
        assert normalize_method_body("\n\n") == []


class TestNormalizationWithMinHash:
    """Integration tests: normalization + MinHash computation."""

    def test_minhash_returns_signature(self):
        from redb.extractors.decompiler.apk.method_extractor import compute_minhash
        body = """\
const/4 v0, 0x0
invoke-virtual {p0, v0}, Lcom/Foo;->bar(I)V
iget-object v1, p0, Lcom/Foo;->name:Ljava/lang/String;
add-int v2, v0, v1
return-void
"""
        sig = compute_minhash(body)
        assert sig is not None
        assert len(sig) == 64
        assert all(0 <= v < 256 for v in sig)

    def test_minhash_register_invariance(self):
        """Same operations with different registers should produce identical signatures."""
        from redb.extractors.decompiler.apk.method_extractor import compute_minhash
        body_a = """\
const/4 v0, 0x0
invoke-virtual {p0, v0}, Lcom/Foo;->bar(I)V
iget-object v1, p0, Lcom/Foo;->name:Ljava/lang/String;
add-int v2, v0, v1
return-void
"""
        body_b = """\
const/4 v3, 0x0
invoke-virtual {p1, v3}, Lcom/Foo;->bar(I)V
iget-object v4, p1, Lcom/Foo;->name:Ljava/lang/String;
add-int v5, v3, v4
return-void
"""
        sig_a = compute_minhash(body_a)
        sig_b = compute_minhash(body_b)
        assert sig_a == sig_b

    def test_minhash_width_invariance(self):
        """Width variants of same operations should produce identical signatures."""
        from redb.extractors.decompiler.apk.method_extractor import compute_minhash
        body_int = """\
add-int v0, v1, v2
sub-int v3, v0, v1
mul-int v4, v0, v3
return v4
"""
        body_long = """\
add-long v0, v2, v4
sub-long v6, v0, v2
mul-long v8, v0, v6
return-wide v8
"""
        sig_int = compute_minhash(body_int)
        sig_long = compute_minhash(body_long)
        # Both normalize to ALU, ALU, ALU, RET -> identical
        assert sig_int == sig_long

    def test_minhash_different_apis_differ(self):
        """Methods calling different APIs should produce different signatures."""
        from redb.extractors.decompiler.apk.method_extractor import compute_minhash
        body_a = """\
const/4 v0, 0x0
invoke-virtual {p0, v0}, Lcom/crypto/AES;->encrypt([B)[B
invoke-virtual {v0}, Ljava/io/OutputStream;->write([B)V
return-void
"""
        body_b = """\
const/4 v0, 0x0
invoke-virtual {p0, v0}, Ljava/lang/String;->length()I
invoke-virtual {v0}, Ljava/io/PrintStream;->println(I)V
return-void
"""
        sig_a = compute_minhash(body_a)
        sig_b = compute_minhash(body_b)
        assert sig_a != sig_b

    def test_minhash_too_few_instructions(self):
        from redb.extractors.decompiler.apk.method_extractor import compute_minhash
        assert compute_minhash("return-void\nnop") is None


class TestACFGBlockFeatures:
    """Tests for per-block ACFG feature extraction via smali_cfg."""

    def test_simple_linear_method(self):
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        body = """\
add-int v0, v1, v2
invoke-virtual {p0}, Lcom/Foo;->bar()V
return-void
"""
        metrics = compute_cfg_metrics(body)
        assert metrics.block_count >= 1
        assert len(metrics.block_features) == metrics.block_count
        # Each feature vector has 8 elements
        for feat in metrics.block_features:
            assert len(feat) == 8

    def test_branching_method_has_multiple_blocks(self):
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        body = """\
const/4 v0, 0x0
if-eqz v0, :cond_0
invoke-virtual {p0}, Lcom/Foo;->a()V
goto :goto_0
:cond_0
invoke-virtual {p0}, Lcom/Foo;->b()V
:goto_0
return-void
"""
        metrics = compute_cfg_metrics(body)
        assert metrics.block_count >= 3
        assert len(metrics.block_features) == metrics.block_count

    def test_feature_vector_arithmetic_count(self):
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        body = """\
add-int v0, v1, v2
sub-int v3, v0, v1
mul-int v4, v0, v3
return v4
"""
        metrics = compute_cfg_metrics(body)
        assert len(metrics.block_features) == 1
        feat = metrics.block_features[0]
        # feat[0] = instr_count (4), feat[1] = arithmetic (3)
        assert feat[0] == 4
        assert feat[1] >= 3  # 3 ALU ops

    def test_feature_vector_call_count(self):
        from redb.extractors.decompiler.apk.smali_cfg import compute_cfg_metrics
        body = """\
invoke-virtual {p0}, Lcom/A;->a()V
invoke-static {v0}, Lcom/B;->b()V
return-void
"""
        metrics = compute_cfg_metrics(body)
        feat = metrics.block_features[0]
        # feat[4] = call count
        assert feat[4] == 2