Kaiwen Zhang

115 papers A 16B 3C 4Misc 5Journal 26Unranked 49
YearRankTypeTitle / Venue / Authors
2026 J jnl
IEEE Trans. Very Large Scale Integr. Syst.
Lemayian Joel Poncha, Ghyslain Gagnon, Kaiwen Zhang, Pascal Giard
2025 J jnl
Distributed Ledger Technol. Res. Pract.
Syed Muhammad Danish, Muhammad Muneem Shabir, Kaiwen Zhang, Hans-Arno Jacobsen, Syed Ali Hassan
2025 J jnl
IEEE Trans. Veh. Technol.
Syed Muhammad Danish, Aroosa Hameed, Ali Ranjha, Gautam Srivastava, Kaiwen Zhang
2025 conf
DEBS
Reza Nourmohammadi, Kaiwen Zhang, Chamseddine Talhi
2025 B conf
COMPSAC
Lemayian Joel Poncha, Hachem Bensalem, Ghyslain Gagnon, Kaiwen Zhang, Pascal Giard
2025 J jnl
CoRR
Lemayian Joel Poncha, Ghyslain Gagnon, Kaiwen Zhang, Pascal Giard
2025 J jnl
IET Blockchain
Lemayian Joel Poncha, Ghyslain Gagnon, Kaiwen Zhang, Pascal Giard
2025 J jnl
Clust. Comput.
Muhammad Muneem Shabir, Kaiwen Zhang, Bertrand Reulet, Ghyslain Gagnon
2025 conf
BRAINS
Shahin Zakizadeh, Kaiwen Zhang, Syed Muhammad Danish
2025 conf
BCCA
Reza Nourmohammadi, Kaiwen Zhang
2024 conf
BPM (Blockchain and RPA Forum)
Sion Israel Sion, Kaiwen Zhang, Alain April, Thomas Maketa Lutete, Charlaine Bouchard
2024 conf
Blockchain
Muhammad Muneem Shabir, Syed Muhammad Danish, Kaiwen Zhang
2024 conf
BRAINS
Reza Nourmohammadi, Mohammad Reza Sabramooz, Kaiwen Zhang, Chamseddine Talhi
2024 J jnl
IEEE Trans. Sustain. Comput.
Syed Muhammad Danish, Kaiwen Zhang, Fatima Amara, Juan Carlos Oviedo-Cepeda, Luis Fernando Rueda Vasquez, Tom Marynowski
2024 B conf
IEEE Big Data
Rodrigue Tonga Naha, Kaiwen Zhang
2024 conf
BCCA
Oumayma Dekhil, Rodrigue Tonga Naha, Mikaeil Mayeli-Feridani, Fatma Najjar, Kaiwen Zhang
2024 C conf
ICMLA
Muhammad KaleemUllah Khan, Kaiwen Zhang, Chamseddine Talhi
2024 J jnl
CoRR
Zeinab Alipanahloo, Abdelhakim Senhaji Hafid, Kaiwen Zhang
2024 J jnl
IEEE Access
Zeinab Alipanahloo, Abdelhakim Senhaji Hafid, Kaiwen Zhang
2024 Misc conf
SAC
Michael Duchesne, Kaiwen Zhang, Chamseddine Talhi
2024 J jnl
CoRR
Michael Duchesne, Kaiwen Zhang, Chamseddine Talhi
2024 J jnl
CoRR
Lemayian Joel Poncha, Ghyslain Gagnon, Kaiwen Zhang, Pascal Giard
2023 conf
DAPPS
Zahra Batool, Sion Israel Sion, Rodrigue Tonga Naha, Kaiwen Zhang
2023 J jnl
IEEE Trans. Mob. Comput.
Syed Muhammad Danish, Kaiwen Zhang, Hans-Arno Jacobsen
2023 J jnl
Distributed Ledger Technol. Res. Pract.
Muhammad Muneem Shabir, Syed Muhammad Danish, Kaiwen Zhang
2023 J jnl
CoRR
Helmi Trabelsi, Kaiwen Zhang
2023 conf
BCCA
Muhammad Muneem Shabir, Kaiwen Zhang
2023 conf
BCCA
Mahtab Norouzi, Mounir Elgharabawy, Kaiwen Zhang
2023 conf
BCCA
Sion Israel Sion, Kaiwen Zhang, Alain April
2022 J jnl
IEEE Trans. Engineering Management
Yahya Shahsavari, Kaiwen Zhang, Chamseddine Talhi
2022 J jnl
IEEE Access
Reza Nourmohammadi, Kaiwen Zhang
2022 conf
ICACT
Samin Sadri, Aamir Shahzad, Kaiwen Zhang
2022 J jnl
Sensors
Aamir Shahzad, Abdelouahed Gherbi, Kaiwen Zhang
2022 Misc conf
SAC
Zahra Batool, Kaiwen Zhang, Matthew Toews
2022 A ed.
Middleware
Paolo Bellavista, Kaiwen Zhang, Abdelouahed Gherbi, Saurabh Bagchi, Marta Patiño, Giuseppe Di Modica, Julien Gascon-Samson
2022 conf
BCCA
Reza Nourmohammadi, Kaiwen Zhang
2022 conf
BCCA
Yahya Shahsavari, Kaiwen Zhang, Chamseddine Talhi
2022 ed.
Middleware Demos/Posters
Kaiwen Zhang, Abdelouahed Gherbi, Paolo Bellavista
2022 ed.
Middleware Industry
Kaiwen Zhang, Abdelouahed Gherbi, Paolo Bellavista
2022 ed.
DICG@Middleware
Kaiwen Zhang, Abdelouahed Gherbi, Paolo Bellavista
2022 ed.
WOC@Middleware
Kaiwen Zhang, Abdelouahed Gherbi, Paolo Bellavista
2022 ed.
WoSC@Middleware
Kaiwen Zhang, Abdelouahed Gherbi, Paolo Bellavista
2022 conf
BPM (Blockchain and RPA Forum)
Rodrigue Tonga Naha, Kaiwen Zhang
2022 J jnl
Frontiers Blockchain
Yahya Shahsavari, Kaiwen Zhang, Chamseddine Talhi
2022 conf
BCCA
Subhasish Goswami, Syed Muhammad Danish, Kaiwen Zhang
2022 C conf
ICBC
Mario Felipe Munoz, Kaiwen Zhang, Fatima Amara
2022 J jnl
CoRR
Mario Felipe Munoz, Kaiwen Zhang, Fatima Amara
2021 C conf
MMSP
Sardar Basiri, Kaiwen Zhang, Stéphane Coulombe
2021 J jnl
IEEE Trans. Intell. Transp. Syst.
Syed Muhammad Danish, Kaiwen Zhang, Hans-Arno Jacobsen, Nouman Ashraf, Hassaan Khaliq Qureshi
2021 conf
ICACT
Samin Sadri, Aamir Shahzad, Kaiwen Zhang
2021 conf
IEEE ICBC
Mario Felipe Munoz, Kaiwen Zhang, Aamir Shahzad, Mustapha Ouhimmou
2021 A ed.
Middleware
Kaiwen Zhang, Abdelouahed Gherbi, Nalini Venkatasubramanian, Luís Veiga
2021 ed.
Middleware Demos/Posters
Kaiwen Zhang, Abdelouahed Gherbi, Nalini Venkatasubramanian, Luís Veiga
2021 ed.
Middleware Extended Abstracts
Kaiwen Zhang, Abdelouahed Gherbi, Nalini Venkatasubramanian, Luís Veiga
2021 ed.
Middleware Industry
Kaiwen Zhang, Abdelouahed Gherbi, Nalini Venkatasubramanian, Luís Veiga
2021 ed.
Middleware Doctoral Symposium
Kaiwen Zhang, Abdelouahed Gherbi, Nalini Venkatasubramanian, Luís Veiga
2021 Misc conf
SAC
Aamir Shahzad, Kaiwen Zhang, Abdelouahed Gherbi
2020 ed.
DEBS
Julien Gascon-Samson, Kaiwen Zhang, Khuzaima Daudjee, Bettina Kemme
2020 conf
IEEE ICBC
Syed Muhammad Danish, Kaiwen Zhang, Hans-Arno Jacobsen
2020 conf
IEEE ICBC
Shiquan Zhang, Kaiwen Zhang, Bettina Kemme
2020 J jnl
CoRR
Narasimha Raghavan Veeraragavan, Kaiwen Zhang
2020 J jnl
Int. J. Distributed Sens. Networks
Aamir Shahzad, Kaiwen Zhang, René Landry Jr., Neal N. Xiong, Young-Gab Kim
2020 conf
Blockchain
Shiquan Zhang, Kaiwen Zhang, Bettina Kemme
2020 conf
DAPPS
Syed Muhammad Danish, Kaiwen Zhang, Hans-Arno Jacobsen
2020 J jnl
Sensors
Aamir Shahzad, Kaiwen Zhang, Abdelouahed Gherbi
2020 conf
IEEE ICBC
Wiem Badreddine, Kaiwen Zhang, Chamseddine Talhi
2020 A conf
Middleware
Pooya Salehi, Kaiwen Zhang, Hans-Arno Jacobsen
2020 J jnl
Clust. Comput.
Syed Muhammad Danish, Marios Lestas, Hassaan Khaliq Qureshi, Kaiwen Zhang, Waqar Asif, Muttukrishnan Rajarajan
2020 C conf
WEBIST
Sonia Slimani, Kaiwen Zhang
2019 J jnl
IEEE Access
Yahya Shahsavari, Hadishahriar Shahhoseini, Kaiwen Zhang, Halima Elbiaze
2019 conf
Blockchain
Yahya Shahsavari, Kaiwen Zhang, Chamseddine Talhi
2019 Misc conf
SEC
Shweta Khare, Hongyang Sun, Julien Gascon-Samson, Kaiwen Zhang, Aniruddha Gokhale, Yogesh D. Barve, Anirban Bhattacharjee, Xenofon D. Koutsoukos
2019 conf
DAPPCON
Yahya Shahsavari, Kaiwen Zhang, Chamseddine Talhi
2019 ch.
Encyclopedia of Big Data Technologies
Kaiwen Zhang
2018 conf
Middleware (Tutorials)
Hans-Arno Jacobsen, Mohammad Sadoghi, Mohammad Hossein Tabatabaei, Roman Vitenberg, Kaiwen Zhang
2018 conf
DEBS
Kaiwen Zhang, Roman Vitenberg, Hans-Arno Jacobsen
2018 conf
DEBS
Jelena Pajic, José Rivera, Kaiwen Zhang, Hans-Arno Jacobsen
2018 A conf
ICDCS
Martin Jergler, Kaiwen Zhang, Hans-Arno Jacobsen
2018 conf
IoTDI
Shweta Khare, Hongyang Sun, Kaiwen Zhang, Julien Gascon-Samson, Aniruddha S. Gokhale, Xenofon D. Koutsoukos
2018 Misc conf
SEC
Shweta Khare, Hongyang Sun, Kaiwen Zhang, Julien Gascon-Samson, Aniruddha S. Gokhale, Xenofon D. Koutsoukos, Hamzah Abdelaziz
2018 A conf
ICDCS
Kaiwen Zhang, Hans-Arno Jacobsen
2018 conf
SERIAL@Middleware
Daniel Sel, Kaiwen Zhang, Hans-Arno Jacobsen
2017 conf
Middleware Posters and Demos
Jing-Yi Wang, Kaiwen Zhang, Hans-Arno Jacobsen
2017 A conf
Middleware
Kaiwen Zhang, Mohammad Sadoghi, Vinod Muthusamy, Hans-Arno Jacobsen
2017 A conf
ICDCS
Mohammadreza Najafi, Kaiwen Zhang, Mohammad Sadoghi, Hans-Arno Jacobsen
2017 conf
Middleware Posters and Demos
Nejc Zupan, Kaiwen Zhang, Hans-Arno Jacobsen
2017 A conf
ICDCS
Pooya Salehi, Kaiwen Zhang, Hans-Arno Jacobsen
2017 conf
DEBS
Pooya Salehi, Kaiwen Zhang, Hans-Arno Jacobsen
2017 A conf
ICDCS
César Cañas, Kaiwen Zhang, Bettina Kemme, Jörg Kienzle, Hans-Arno Jacobsen
2017 A conf
ICDCS
Kaiwen Zhang, Vinod Muthusamy, Mohammad Sadoghi, Hans-Arno Jacobsen
2017 conf
Middleware Posters and Demos
Lyubomir Stoykov, Kaiwen Zhang, Hans-Arno Jacobsen
2016 A conf
ICDCS
Kaiwen Zhang, Mohammad Sadoghi, Hans-Arno Jacobsen
2016 conf
Middleware Posters and Demos
Christoph Doblander, Simon Zimmermann, Kaiwen Zhang, Hans-Arno Jacobsen
2016 conf
DEBS
César Cañas, Kaiwen Zhang, Bettina Kemme, Jörg Kienzle, Hans-Arno Jacobsen
2016
Kaiwen Zhang
2016 conf
CASCON
César Cañas, Kaiwen Zhang, Bettina Kemme, Jörg Kienzle, Hans-Arno Jacobsen
2016 A conf
ICDCS
Christoph Doblander, Kaiwen Zhang, Hans-Arno Jacobsen
2016 conf
DEBS
Christoph Doblander, Tanuj Ghinaiya, Kaiwen Zhang, Hans-Arno Jacobsen
2015 conf
DEBS
Dantong Song, Kaiwen Zhang, Tilmann Rabl, Prashanth Menon, Hans-Arno Jacobsen
2015 A conf
ICDCS
Navneet Kumar Pandey, Kaiwen Zhang, Stéphane Weiss, Hans-Arno Jacobsen, Roman Vitenberg
2014 conf
Middleware (Posters & Demos)
César Cañas, Kaiwen Zhang, Bettina Kemme, Jörg Kienzle, Hans-Arno Jacobsen
2014 conf
DEBS
Navneet Kumar Pandey, Kaiwen Zhang, Stéphane Weiss, Hans-Arno Jacobsen, Roman Vitenberg
2014 conf
Middleware (Posters & Demos)
Kaiwen Zhang, Tilmann Rabl, Yi Ping Sun, Rushab Kumar, Nayeem Zen, Hans-Arno Jacobsen
2014 conf
Middleware (Posters & Demos)
Nischay Bodapati, Kaiwen Zhang, Hans-Arno Jacobsen
2014 A conf
Middleware
César Cañas, Kaiwen Zhang, Bettina Kemme, Jörg Kienzle, Hans-Arno Jacobsen
2013 A conf
ICDCS
Kaiwen Zhang, Mohammad Sadoghi, Vinod Muthusamy, Hans-Arno Jacobsen
2013 conf
DEBS
Hans-Arno Jacobsen, Kianoosh Mokhtarian, Tilmann Rabl, Mohammad Sadoghi, Reza Sherafat Kazemzadeh, Young Yoon, Kaiwen Zhang
2013 conf
DEBS
Tilmann Rabl, Mohammad Sadoghi, Kaiwen Zhang, Hans-Arno Jacobsen
2013 J jnl
CoRR
Kaiwen Zhang, Hans-Arno Jacobsen
2013 conf
Middleware Demo & Poster Track
Yingqi Yue, Kaiwen Zhang, Hans-Arno Jacobsen
2012 conf
Middleware Doctoral Symposium
Kaiwen Zhang
2012 conf
DEBS
Tilmann Rabl, Kaiwen Zhang, Mohammad Sadoghi, Navneet Kumar Pandey, Aakash Nigam, Chen Wang, Hans-Arno Jacobsen
2012 A conf
ICDCS
Kaiwen Zhang, Vinod Muthusamy, Hans-Arno Jacobsen
2011 B conf
SRDS
Kaiwen Zhang, Bettina Kemme
2008 conf
NETGAMES
Kaiwen Zhang, Bettina Kemme, Alexandre Denault
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