Cecilia R. Aragon

85 papers A* 7A 5B 7C 5Misc 2Journal 19Unranked 39
YearRankTypeTitle / Venue / Authors
2025 conf
SIGCSE (1)
Cecilia R. Aragon
2024 J jnl
CoRR
Nina Lutz, Cecilia R. Aragon
2024 J jnl
Proc. ACM Hum. Comput. Interact.
Nina Lutz, Cecilia R. Aragon
2024 conf
CSCW Companion
Guo Freeman, Julian Frommel, Regan L. Mandryk, Jan Gugenheimer, Lingyuan Li, Daniel Johnson, Cecilia R. Aragon, Syed Ali Asif, Jakki O. Bailey, Meryem Barkallah, Braeden Burger, Sebastian Cmentowski, Jamie Hancock, Leanne Hides, Hongxin Hu, Yang Hu, Wangfan Li, Ruchi Panchanadikar, Niloofar Sayadi, Devin Tebbe, Leslie Wöhler, Xinyue (Sally) You, ZiNan Zhang, Douglas Zytko
2023 conf
HCI (40)
Sourojit Ghosh, Murtaza Ali, Anna Batra, Cheng Guo, Mohit Jain, Joseph Kang, Julia Kharchenko, Varun Suravajhela, Vincent Zhou, Cecilia R. Aragon
2023 conf
HCI (16)
Sourojit Ghosh, Niamh Froelich, Cecilia R. Aragon
2023 conf
HCI (5)
Andrea Figueroa, Sourojit Ghosh, Cecilia R. Aragon
2022 conf
ASIST
Mimi Byun, Sarah A. Evans, Bernease Herman, Cecilia R. Aragon, Diana Rojas-Ponce
2022 conf
CHI Extended Abstracts
Anissa Tanweer, Cecilia R. Aragon, Michael J. Muller, Shion Guha, Samir Passi, Gina Neff, Marina Kogan
2022 J jnl
CoRR
Felipe González-Pizarro, Andrea Figueroa, Claudia López, Cecilia R. Aragon
2022 J jnl
Comput. Support. Cooperative Work.
Felipe González-Pizarro, Andrea Figueroa, Claudia López, Cecilia R. Aragon
2021 conf
CSCW Companion
Ruoxi Shang, Zile Xiao, Jenna Frens, Cecilia R. Aragon
2021 J jnl
CoRR
Ruby Davis, Jenna Frens, Niharika Sharma, Meena Devii Muralikumar, Cecilia R. Aragon, Sarah A. Evans
2021 conf
RESPECT
Richard E. Ladner, Cecilia R. Aragon, Jerry Robinson, Jeremy A. Magruder Waisome, Rua M. Williams
2021 conf
HCI (39)
Niamh Froelich, Arthur Liu, Ruoxi Shang, Zile Xiao, Travis Neils, Jenna Frens, Cecilia R. Aragon
2021 conf
HICSS
Sungsoo Ray Hong, Rafal Kocielnik, Cecilia R. Aragon, Sarah Battersby, Juho Kim
2020 conf
ASIST
Bernease Herman, Cecilia R. Aragon, Sarah A. Evans, Lea Shanley
2019 conf
WWW (Companion Volume)
Felipe González, Yihan Yu, Andrea Figueroa, Claudia López, Cecilia R. Aragon
2019 J jnl
CoRR
Felipe González, Yihan Yu, Andrea Figueroa, Claudia López, Cecilia R. Aragon
2019 A* conf
CHI
Arpita Bhattacharya, Travis W. Windleharth, Rio Anthony Ishii, Ivy M. Acevedo, Cecilia R. Aragon, Julie A. Kientz, Jason C. Yip, Jin Ha Lee
2019 conf
HICSS
Nan-Chen Chen, Lavanya Ramakrishnan, Sarah S. Poon, Cecilia R. Aragon
2019 conf
CSCW Companion
Felipe González, Andrea Figueroa, Claudia López, Cecilia R. Aragon
2019 J jnl
CoRR
Felipe González, Andrea Figueroa, Claudia López, Cecilia R. Aragon
2019 conf
CHI Extended Abstracts
Bonnie Chinh, Himanshu Zade, Abbas Ganji, Cecilia R. Aragon
2018 A* conf
CHI
Himanshu Zade, Margaret Drouhard, Bonnie Chinh, Lu Gan, Cecilia R. Aragon
2018 conf
CSCW Companion
Cleidson R. B. de Souza, Claudia López, Francisco J. Gutierrez, Laura S. Gaytán-Lugo, Marcos R. S. Borges, Cecilia R. Aragon
2018 conf
CSCW Companion
Brianna Dym, Cecilia R. Aragon, Julia Bullard, Ruby Davis, Casey Fiesler
2018 J jnl
CoRR
John Frens, Ruby Davis, Jihyun Lee, Diana Zhang, Cecilia R. Aragon
2018 J jnl
ACM Trans. Interact. Intell. Syst.
Nan-Chen Chen, Margaret Drouhard, Rafal Kocielnik, Jina Suh, Cecilia R. Aragon
2017 B conf
PacificVis
Margaret Drouhard, Nan-Chen Chen, Jina Suh, Rafal Kocielnik, Vanessa Peña Araya, Keting Cen, Xiangyi Zheng, Cecilia R. Aragon
2017 B conf
PacificVis
Sungsoo (Ray) Hong, Rafal Kocielnik, Min-Joon Yoo, Sarah Battersby, Juho Kim, Cecilia R. Aragon
2017 J jnl
Dagstuhl Manifestos
Alice Allen, Cecilia R. Aragon, Christoph Becker, Jeffrey C. Carver, Andrei Chis, Benoît Combemale, Mike Croucher, Kevin Crowston, Daniel Garijo, Ashish Gehani, Carole A. Goble, Robert Haines, Robert Hirschfeld, James Howison, Kathryn D. Huff, Caroline Jay, Daniel S. Katz, Claude Kirchner, Katie Kuksenok, Ralf Lämmel, Oscar Nierstrasz, Matt Turk, Rob van Nieuwpoort, Matthew Vaughn, Jurgen J. Vinju
2017 conf
HICSS
Nan-Chen Chen, Michael Brooks, Rafal Kocielnik, Sungsoo (Ray) Hong, Jeff Smith, Sanny Lin, Zening Qu, Cecilia R. Aragon
2017 A conf
CSCW
Sarah A. Evans, Katie Davis, Abigail Evans, Julie Ann Campbell, David P. Randall, Kodlee Yin, Cecilia R. Aragon
2017 conf
HCI (13)
Nan-Chen Chen, Michael Brooks, Rafal Kocielnik, Sungsoo (Ray) Hong, Jeff Smith, Sanny Lin, Zening Qu, Cecilia R. Aragon
2017 J jnl
J. Assoc. Inf. Sci. Technol.
Alexis Hiniker, Sungsoo (Ray) Hong, Yea-Seul Kim, Nan-Chen Chen, Jevin D. West, Cecilia R. Aragon
2017 A* conf
CHI
Kodlee Yin, Cecilia R. Aragon, Sarah A. Evans, Katie Davis
2016 B conf
GROUP
Taylor Jackson Scott, Daniel Perry, Alison Williams, Cecilia R. Aragon
2016 A conf
CSCW
Nan-Chen Chen, Sarah S. Poon, Lavanya Ramakrishnan, Cecilia R. Aragon
2016 J jnl
CoRR
Sarah A. Evans, Katie Davis, Abigail Evans, Julie Ann Campbell, David P. Randall, Kodlee Yin, Cecilia R. Aragon
2016 A conf
CSCW
Julie Ann Campbell, Cecilia R. Aragon, Katie Davis, Sarah A. Evans, Abigail Evans, David P. Randall
2015 J jnl
CoRR
Nan-Chen Chen, Sarah S. Poon, Lavanya Ramakrishnan, Cecilia R. Aragon
2015 B conf
CogSci
Laurie Feldman, Kit Cho, Cecilia R. Aragon, Judith F. Kroll
2015 J jnl
CoRR
Julie Ann Campbell, Cecilia R. Aragon, Katie Davis, Sarah A. Evans, Abigail Evans, David P. Randall
2014 C conf
CDVE
Megan K. Torkildson, Kate Starbird, Cecilia R. Aragon
2014 C conf
CDVE
Michael Brooks, John J. Robinson, Megan K. Torkildson, Sungsoo (Ray) Hong, Cecilia R. Aragon
2014 conf
SBP
Cecilia R. Aragon, Nan-Chen Chen, Judith F. Kroll, Laurie Beth Feldman
2014 conf
IEEE VAST
Nan-Chen Chen, Laurie Beth Feldman, Judith F. Kroll, Cecilia R. Aragon
2014 J jnl
Concurr. Comput. Pract. Exp.
Daniel Perry, John J. Robinson, Stephanie Cruz, Cecilia R. Aragon, Jeanne Ting Chowning, Mette A. Peters
2014 A* conf
CHI
Sungsoo (Ray) Hong, Yea-Seul Kim, Jong-Chul Yoon, Cecilia R. Aragon
2013 conf
ChileCHI
Daniel Perry, Aaron Lynch, Asmi Joshi, Karin Hellman, John J. Robinson, Alyssa-Cyre Oyadomari, Melissa Richtarik, Cecilia R. Aragon
2013 conf
INTERACT (3)
Michael Brooks, Jevin D. West, Cecilia R. Aragon, Carl T. Bergstrom
2013 conf
XSEDE
Daniel Perry, Cecilia R. Aragon, Stephanie Cruz, Mette A. Peters, Jeanne Ting Chowning
2013 conf
ICB
Michael Brooks, Cecilia R. Aragon, Oleg V. Komogortsev
2013 A conf
CSCW
Michael Brooks, Katie Kuksenok, Megan K. Torkildson, Daniel Perry, John J. Robinson, Taylor Jackson Scott, Ona Anicello, Ariana Zukowski, Paul Harris, Cecilia R. Aragon
2012 conf
SIGDOC
Taylor Jackson Scott, Katie Kuksenok, Daniel Perry, Michael Brooks, Ona Anicello, Cecilia R. Aragon
2012 conf
ICB
Oleg V. Komogortsev, Alex Karpov, Larry R. Price, Cecilia R. Aragon
2012 conf
CSCW (Companion)
Matthew J. Bietz, Andrea Wiggins, Mark Handel, Cecilia R. Aragon
2012 conf
CSCW (Companion)
Joshua Introne, Karen Levy, Sean Munson, Sean P. Goggins, Rick Wash, Cecilia R. Aragon
2012 conf
CSCW (Companion)
Daniel Perry, Cecilia R. Aragon
2012 conf
CHI Extended Abstracts
Bill Howe, Alicia Key, Daniel Perry, Cecilia R. Aragon
2012 conf
SIGMOD Conference
Alicia Key, Bill Howe, Daniel Perry, Cecilia R. Aragon
2011 A* conf
CHI
Cecilia R. Aragon, Alison Williams
2011 conf
iConference
Daniel Perry, Cecilia R. Aragon, Alan K. Meier, Marco Pritoni
2011 conf
iConference
Cecilia R. Aragon, Sarah S. Poon
2010 B conf
ETRA
Oleg V. Komogortsev, Sampath Jayarathna, Cecilia R. Aragon, Mahmoud Mechehoul
2010 C conf
IGARSS
Randy S. Roberts, Timothy G. Trucano, Paul A. Pope, Cecilia R. Aragon, Ming Jiang, Thomas Wei, Lawrence K. Chilton, Alan Bakel
2009 B conf
Creativity & Cognition
Cecilia R. Aragon, Sarah S. Poon, Andrés Monroy-Hernández, Diana Aragon
2009 ch.
Handbook of Automation
Cecilia R. Aragon
2009 conf
CHI Extended Abstracts
Cecilia R. Aragon, Sarah S. Poon, Cláudio T. Silva
2009 J jnl
Inf. Vis.
Cecilia R. Aragon, Sarah S. Poon, Gregory S. Aldering, Rollin C. Thomas, Robert Quimby
2009 Misc conf
SAC
Cecilia R. Aragon, Karl J. Runge
2008 C conf
ICMLA
Daniela Mayumi Ushizima, Oliver Rübel, Prabhat, Gunther H. Weber, E. Wes Bethel, Cecilia R. Aragon, Cameron G. R. Geddes, Estelle Cormier-Michel, Bernd Hamann, Peter Messmer, Hans Hagen
2008 A conf
CSCW
Sarah S. Poon, Rollin C. Thomas, Cecilia R. Aragon, Brian Lee
2008 conf
IEEE VAST
Cecilia R. Aragon, Sarah S. Poon, Gregory S. Aldering, Rollin C. Thomas, Robert Quimby
2007 conf
Real-Time Image Processing
Cecilia R. Aragon, David Bradburn Aragon
2007 conf
IEEE VAST
Cecilia R. Aragon, Stephen J. Bailey, Sarah S. Poon, Karl J. Runge, Rollin C. Thomas
2006 C conf
ICMLA
Raquel A. Romano, Cecilia R. Aragon, Chris H. Q. Ding
2005 A* conf
CHI
Cecilia R. Aragon, Marti A. Hearst
2005 B conf
SMC
Cecilia R. Aragon
1998 Misc conf
CATA
David J. Korsmeyer, Joan D. Walton, Cecilia R. Aragon, Alex Shaykevich, Louise Chan
1996 J jnl
Algorithmica
Raimund Seidel, Cecilia R. Aragon
1991 J jnl
Oper. Res.
David S. Johnson, Cecilia R. Aragon, Lyle A. McGeoch, Catherine Schevon
1989 J jnl
Oper. Res.
David S. Johnson, Cecilia R. Aragon, Lyle A. McGeoch, Catherine Schevon
1989 A* conf
FOCS
Cecilia R. Aragon, Raimund Seidel
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