Kai Xu

76 papers A* 3A 2B 2C 8Misc 1Journal 32Unranked 26
YearRankTypeTitle / Venue / Authors
2026 J jnl
CoRR
Jun-Peng Zhu, Qizhi Wang, Yulong Zhai, Yishen Sun, Sen Chen, Kai Xu, Peng Cai, Hongming Zhang, Heng Long, Liu Tang, Qi Liu
2026 J jnl
IEEE Trans. Vis. Comput. Graph.
Jun-Hsiang Yao, Jielin Feng, Xinfang Tian, Kai Xu, Gulshat Amirkhanova, Siming Chen
2026 J jnl
CoRR
Yi Shan, Yixuan He, Zekai Shao, Kai Xu, Siming Chen
2026 J jnl
CoRR
Jun-Peng Zhu, Boyan Niu, Peng Cai, Zheming Ni, Kai Xu, Jiajun Huang, Shengbo Ma, Bing Wang, Xuan Zhou, Guanglei Bao, Donghui Zhang, Liu Tang, Qi Liu
2025 J jnl
CoRR
Shayan Monadjemi, Yuhan Guo, Kai Xu, Alex Endert, Anamaria Crisan
2025 J jnl
CoRR
Jun-Hsiang Yao, Jielin Feng, Xinfang Tian, Kai Xu, Gulshat Amirkhanova, Siming Chen
2025 J jnl
IEEE Trans. Vis. Comput. Graph.
Yuhan Guo, Hanning Shao, Can Liu, Kai Xu, Xiaoru Yuan
2025 J jnl
CoRR
Yuhan Guo, Xingyou Liu, Xiaoru Yuan, Kai Xu
2025 A* conf
ICDE
Jun-Peng Zhu, Zhiwei Ye, Xiaolong He, Peng Cai, Xuan Zhou, Aoying Zhou, Dunbo Cai, Ling Qian, Kai Xu, Liu Tang, Qi Liu
2025 J jnl
Proc. VLDB Endow.
Jun-Peng Zhu, Boyan Niu, Peng Cai, Zheming Ni, Jianwei Wan, Kai Xu, Jiajun Huang, Shengbo Ma, Bing Wang, Xuan Zhou, Guanglei Bao, Donghui Zhang, Liu Tang, Qi Liu
2025 conf
SIGMOD Conference Companion
Jun-Peng Zhu, Peng Cai, Kai Xu, Li Li, Yishen Sun, Shuai Zhou, Haihuang Su, Liu Tang, Qi Liu
2024 J jnl
Vis. Informatics
Qiru Wang, Kai Xu, Robert S. Laramee
2024 J jnl
CoRR
Yuhan Guo, Hanning Shao, Can Liu, Kai Xu, Xiaoru Yuan
2024 conf
VAST Challenge@VIS
Yuhan Guo, Yuchu Luo, Xinyue Chen, Hanning Shao, Xiaoru Yuan, Kai Xu
2023 J jnl
Dagstuhl Reports
Anamaria Crisan, Lars Kotthoff, Marc Streit, Kai Xu
2023 J jnl
IEEE Trans. Vis. Comput. Graph.
Conny Walchshofer, Andreas P. Hinterreiter, Kai Xu, Holger Stitz, Marc Streit
2022 J jnl
Comput. Graph. Forum
Max Sondag, Cagatay Turkay, Kai Xu, Louise Matthews, Sibylle Mohr, Daniel Archambault
2022 J jnl
CoRR
Jason Dykes, Alfie Abdul-Rahman, Daniel Archambault, Benjamin Bach, Rita Borgo, Min Chen, Jessica A. Enright, Hui Fang, Elif E. Firat, Euan Freeman, Tuna Gonen, Claire Harris, Radu Jianu, Nigel W. John, Saiful Khan, Andrew Lahiff, Robert S. Laramee, Louise Matthews, Sibylle Mohr, Phong Hai Nguyen, Alma A. M. Rahat, Richard E. Reeve, Panagiotis D. Ritsos, Jonathan C. Roberts, Aidan Slingsby, Ben Swallow, Thomas Torsney-Weir, Cagatay Turkay, Robert Turner, Franck P. Vidal, Qiru Wang, Jo Wood, Kai Xu
2020 ed.
CGVC
Panagiotis D. Ritsos, Kai Xu
2020 J jnl
IEEE Computer Graphics and Applications
John E. Wenskovitch, Michelle X. Zhou, Christopher Collins, Remco Chang, Michelle Dowling, Alex Endert, Kai Xu, Theresa-Marie Rhyne
2020 J jnl
CoRR
Min Chen, Alfie Abdul-Rahman, Daniel Archambault, Jason Dykes, Aidan Slingsby, Panagiotis D. Ritsos, Thomas Torsney-Weir, Cagatay Turkay, Benjamin Bach, A. Brett, Hui Fang, Radu Jianu, Saiful Khan, Robert S. Laramee, Phong Hai Nguyen, Richard E. Reeve, Jonathan C. Roberts, Franck Vidal, Q. Wang, Jo Wood, Kai Xu
2020 J jnl
Comput. Graph. Forum
Kai Xu, Alvitta Ottley, Conny Walchshofer, Marc Streit, Remco Chang, John E. Wenskovitch
2020 J jnl
IEEE Computer Graphics and Applications
Kai Xu, Saminu Salisu, Phong H. Nguyen, Rick Walker, B. L. William Wong, Adrian Wagstaff, Graham Phillips, Mike Biggs, Mike Potel
2019 conf
LegalAIIA@ICAIL
Simon Attfield, Bob Fields, David Windridge, Kai Xu
2019 J jnl
IEEE Computer Graphics and Applications
Jean-Daniel Fekete, T. J. Jankun-Kelly, Melanie Tory, Kai Xu
2018 J jnl
Dagstuhl Reports
Jean-Daniel Fekete, T. J. Jankun-Kelly, Melanie Tory, Kai Xu
2018 conf
EuroRV³@EuroVis
Md. Junayed Islam, Kai Xu, B. L. William Wong
2017 J jnl
Multimodal Technol. Interact.
Kai Xu, Leishi Zhang, Daniel Pérez, Phong H. Nguyen, Adam Ogilvie-Smith
2016 conf
VAST
Phong Hai Nguyen, Kai Xu, Andy Bardill, Betul Salman, Kate Herd, B. L. William Wong
2016 J jnl
IEEE Trans. Vis. Comput. Graph.
Phong Hai Nguyen, Kai Xu, Ashley Wheat, B. L. William Wong, Simon Attfield, Bob Fields
2016 conf
CGVC
Saminu Salisu, Kai Xu, Adrian Wagstaff, Mike Biggs, Graham Phillips
2016 J jnl
Inf. Vis.
Phong Hai Nguyen, Kai Xu, Rick Walker, B. L. William Wong
2016 conf
CGVC
Junayed Islam, Craig Anslow, Kai Xu, B. L. William Wong, Leishi Zhang
2015 J jnl
IEEE Computer Graphics and Applications
Kai Xu, Simon Attfield, T. J. Jankun-Kelly, Ashley Wheat, Phong Hai Nguyen, Nallini Selvaraj
2014 J jnl
Inf. Vis.
Neesha Kodagoda, Simon Attfield, Tinni Choudhury, Chris Rooney, Glenford E. Mapp, Phong Hai Nguyen, Louis Slabbert, B. L. William Wong, Mahdi Aiash, Yongjun Zheng, Kai Xu, Aboubaker Lasebae
2014 conf
EKAW (Satellite Events)
Valentina Ivanova, Tomi Kauppinen, Steffen Lohmann, Suvodeep Mazumdar, Catia Pesquita, Kai Xu
2014 conf
JISIC
Neesha Kodagoda, Simon Attfield, Phong Hai Nguyen, Leishi Zhang, Kai Xu, B. L. William Wong, Adrian Wagstaff, Graham Phillips, James Bullock, John Marshall, Stewart Bertram
2014 ed.
VISUAL@EKAW
Valentina Ivanova, Tomi Kauppinen, Steffen Lohmann, Suvodeep Mazumdar, Catia Pesquita, Kai Xu
2014 C conf
IV
Phong Hai Nguyen, Kai Xu, Rick Walker, B. L. William Wong
2014 conf
IEEE VAST
Kai Xu, Phong Hai Nguyen, Bob Fields
2013 J jnl
IEEE Trans. Vis. Comput. Graph.
Rick Walker, Aidan Slingsby, Jason Dykes, Kai Xu, Jo Wood, Phong Hai Nguyen, Derek Stephens, B. L. William Wong, Yongjun Zheng
2013 conf
Multivariate Network Visualization
T. J. Jankun-Kelly, Tim Dwyer, Danny Holten, Christophe Hurter, Martin Nöllenburg, Chris E. Weaver, Kai Xu
2012 C conf
Diagrams
Kai Xu, Chris Rooney, Peter J. Passmore, Dong-Han Ham
2012 J jnl
IEEE Trans. Vis. Comput. Graph.
Kai Xu, Chris Rooney, Peter J. Passmore, Dong-Han Ham, Phong Hai Nguyen
2012 conf
IEEE VAST
Sharmin (Tinni) Choudhury, Neesha Kodagoda, Phong Hai Nguyen, Chris Rooney, Simon Attfield, Kai Xu, Yongjun Zheng, B. L. William Wong, Raymond Chen, Glenford E. Mapp, Louis Slabbert, Mahdi Aiash, Aboubaker Lasebae
2011 conf
ICDKE
Qing Liu, Ji Zhang, James Forbes, Kai Xu, Dinesh Nair
2011 B conf
TPDL
B. L. William Wong, Sharmin (Tinni) Choudhury, Chris Rooney, Raymond Chen, Kai Xu
2011 conf
CHI Extended Abstracts
B. L. William Wong, Raymond Chen, Neesha Kodagoda, Chris Rooney, Kai Xu
2011 conf
USAB
B. L. William Wong, Kai Xu, Andreas Holzinger
2011 J jnl
Serv. Oriented Comput. Appl.
Kai Xu, Qi Yu, Qing Liu, Ji Zhang, Athman Bouguettaya
2010 B conf
AVI
Andrew Cunningham, Kai Xu, Bruce H. Thomas
2009 C conf
DEXA
Ji Zhang, Qigang Gao, Hai H. Wang, Qing Liu, Kai Xu
2009 Misc conf
AusDM
Ji Zhang, Qing Liu, Kai Xu
2009 conf
ICCS (1)
Ji Zhang, Qing Liu, Kai Xu
2009 A conf
GD
Kai Xu, Rohan Williams, Seok-Hee Hong, Qing Liu, Ji Zhang
2009 conf
SERVICES I
Xuan Zhou, Shiping Chen, Athman Bouguettaya, Kai Xu
2009 C conf
VINCI
Adel Ahmed, Xiaoyan Fu, Seok-Hee Hong, Quan Hoang Nguyen, Kai Xu
2009 C conf
IV
David Cho Yau Fung, Seok-Hee Hong, Dirk Koschützki, Falk Schreiber, Kai Xu
2009 conf
DASFAA Workshops
Shazia Sadiq, Ke Deng, Xiaofang Zhou, Xiaochun Yang, Walid G. Aref, Alex Delis, Qing Liu, Kai Xu
2008 J jnl
J. Integr. Bioinform.
David Cho Yau Fung, Seok-Hee Hong, Dirk Koschützki, Falk Schreiber, Kai Xu
2008 J jnl
VLDB J.
Ke Deng, Xiaofang Zhou, Heng Tao Shen, Qing Liu, Kai Xu, Xuemin Lin
2008 conf
eScience
Athman Bouguettaya, Mark Hepburn, Qing Liu, Kai Xu, Ji Zhang
2007 conf
APVIS
Kai Xu, Andrew Cunningham, Seok-Hee Hong, Bruce H. Thomas
2007 conf
IEEE VAST
Adel Ahmed, Xiaoyan Fu, Seok-Hee Hong, Quan Hoang Nguyen, Kai Xu
2007 conf
APVIS
Xiaoyan Fu, Seok-Hee Hong, Nikola S. Nikolov, Xiaobin Shen, Yingxin Wu, Kai Xu
2006 J jnl
IEEE Trans. Knowl. Data Eng.
Kai Xu, Xiaofang Zhou, Xuemin Lin, Heng Tao Shen, Ke Deng
2006 conf
Human-Centered Visualization Environments
Mircea Lungu, Kai Xu
2006 conf
CGIV
Joshua Wing Kei Ho, Tristan Manwaring, Seok-Hee Hong, Uwe Röhm, David Cho Yau Fung, Kai Xu, Tim Kraska, David Hart
2006 A* conf
ICDE
Ke Deng, Xiaofang Zhou, Heng Tao Shen, Kai Xu, Xuemin Lin
2006 conf
Human-Centered Visualization Environments
Carsten Görg, Mathias Pohl, Ermir Qeli, Kai Xu
2006 conf
APVIS
Tim Dwyer, Seok-Hee Hong, Dirk Koschützki, Falk Schreiber, Kai Xu
2006 C conf
APWeb
Kai Xu
2005 A conf
GD
Adel Ahmed, Tim Dwyer, Michael Forster, Xiaoyan Fu, Joshua Wing Kei Ho, Seok-Hee Hong, Dirk Koschützki, Colin Murray, Nikola S. Nikolov, Ronnie Taib, Alexandre Tarassov, Kai Xu
2005 C conf
APWeb
Kai Xu, Xiaofang Zhou
2004 A* conf
ICDE
Kai Xu, Xiaofang Zhou, Xuemin Lin
2004 C conf
APWeb
Xiaofang Zhou, Sham Prasher, Sai Sun, Kai Xu
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