Inseok Hwang

86 papers A* 7A 21B 3Misc 12Journal 21Unranked 22
YearRankTypeTitle / Venue / Authors
2025 B conf
VRST
Jaewoong Jang, Sungjae Cho, Yeseul Shin, Inseok Hwang
2025 J jnl
CoRR
Jungeun Lee, Kyungah Lee, Inseok Hwang, Sohyun Park, Young-Ho Kim
2025 conf
NAACL (Long Papers)
Jaechang Kim, Jinmin Goh, Inseok Hwang, Jaewoong Cho, Jungseul Ok
2025 conf
UIST Adjunct
Seungwon Yang, Suwon Yoon, Jeongwon Choi, Inseok Hwang
2025 J jnl
CoRR
Seungwon Yang, Suwon Yoon, Jeongwon Choi, Inseok Hwang
2025 J jnl
CoRR
Suwon Yoon, Seungwon Yang, Jeongwon Choi, Wonjeong Park, Inseok Hwang
2025 A* conf
CHI
Hyojin Ju, Jungeun Lee, Seungwon Yang, Jungseul Ok, Inseok Hwang
2024 J jnl
GetMobile Mob. Comput. Commun.
Jonghyuk Yun, Kyoosik Lee, Kichang Lee, Bangjie Sun, Jaeho Jeon, JeongGil Ko, Inseok Hwang, Jun Han
2024 J jnl
CoRR
Jaechang Kim, Jinmin Goh, Inseok Hwang, Jaewoong Cho, Jungseul Ok
2024 J jnl
ACM Trans. Internet Things
Darshana Rathnayake, Meera Radhakrishnan, Inseok Hwang, Archan Misra
2024 A* conf
CHI
Jungeun Lee, Suwon Yoon, Kyoosik Lee, Eunae Jeong, Jae-Eun Cho, Wonjeong Park, Dongsun Yim, Inseok Hwang
2024 A conf
MobiSys
Jonghyuk Yun, Kyoosik Lee, Kichang Lee, Bangjie Sun, Jaeho Jeon, JeongGil Ko, Inseok Hwang, Jun Han
2024 A conf
MobiSys
Jonghyuk Yun, Kyoosik Lee, Kichang Lee, Bangjie Sun, Jaeho Jeon, JeongGil Ko, Inseok Hwang, Jun Han
2023 J jnl
IEEE Pervasive Comput.
Bumsoo Kang, Seungwoo Kang, Inseok Hwang
2023 J jnl
Proc. ACM Interact. Mob. Wearable Ubiquitous Technol.
Sungjae Cho, Yoonsu Kim, Jaewoong Jang, Inseok Hwang
2023 Misc conf
SenSys
Darshana Rathnayake, Dulanga Weerakoon, Meera Radhakrishnan, Vigneshwaran Subbaraju, Inseok Hwang, Archan Misra
2023 conf
UbiComp/ISWC Adjunct
Sungjae Cho, Jaewoong Jang, Yoonsu Kim, Inseok Hwang
2023 conf
UbiComp/ISWC Adjunct
Jiha Kim, Younho Nam, Jungeun Lee, Young-Joo Suh, Inseok Hwang
2023 conf
UbiComp/ISWC Adjunct
Jungeun Lee, Inseok Hwang
2023 conf
IoTDI
Darshana Rathnayake, Meeralakshmi Radhakrishnan, Inseok Hwang, Archan Misra
2023 J jnl
Proc. ACM Interact. Mob. Wearable Ubiquitous Technol.
Jiha Kim, Younho Nam, Jungeun Lee, Young-Joo Suh, Inseok Hwang
2023 conf
UbiComp/ISWC Adjunct
Mingyeol Kim, Inseok Hwang
2023 conf
UbiComp/ISWC Adjunct
Jeongwon Choi, Inseok Hwang
2022 B conf
MobiHoc
Wonjung Kim, Seungchul Lee, Youngjae Chang, Taegyeong Lee, Seongwoong Kang, Inseok Hwang, Junehwa Song
2022 A* conf
UIST
Jungeun Lee, Sungnam Kim, Minki Cheon, Hyojin Ju, Jaeeun Lee, Inseok Hwang
2022 conf
UIST (Adjunct Volume)
Sungjae Cho, Jungeun Lee, Inseok Hwang
2021 A conf
MobiSys
Wonjung Kim, Seungchul Lee, Youngjae Chang, Taegyeong Lee, Inseok Hwang, Junehwa Song
2021 A conf
MobiSys
Wonjung Kim, Seungchul Lee, Youngjae Chang, Taegyeong Lee, Inseok Hwang, Junehwa Song
2021 A* conf
CHI
Bumsoo Kang, Seungwoo Kang, Inseok Hwang
2020 conf
UbiComp/ISWC Adjunct
Wonjung Kim, Seungchul Lee, Seonghoon Kim, Sungbin Jo, Chungkuk Yoo, Inseok Hwang, Seungwoo Kang, Junehwa Song
2020 J jnl
Proc. ACM Interact. Mob. Wearable Ubiquitous Technol.
Wonjung Kim, Seungchul Lee, Seonghoon Kim, Sungbin Jo, Chungkuk Yoo, Inseok Hwang, Seungwoo Kang, Junehwa Song
2020 Misc conf
SenSys
Meera Radhakrishnan, Darshana Rathnayake, Ong Koon Han, Inseok Hwang, Archan Misra
2020 A* conf
DAC
Jinho Lee, Inseok Hwang, Soham Shah, Minsik Cho
2020 J jnl
IEEE Trans. Mob. Comput.
Chulhong Min, Youngki Lee, Chungkuk Yoo, Inseok Hwang, Younghyun Ju, Junehwa Song, Seungwoo Kang
2020 J jnl
CoRR
Inseok Hwang, Jinho Lee, Frank Liu, Minsik Cho
2019 J jnl
IEEE Pervasive Comput.
Jinho Lee, Inseok Hwang, Thomas Hubregtsen, Anne E. Gattiker, Christopher M. Durham
2019 conf
MCSS@MobiSys
Chungkuk Yoo, Seungwoo Kang, Inseok Hwang, Chulhong Min, Seonghoon Kim, Wonjung Kim, Junehwa Song
2019 A conf
MobiSys
Inseok Hwang, Eric Rozner, Chungkuk Yoo
2019 J jnl
IEEE Pervasive Comput.
Inseok Hwang, Youngki Lee, Chungkuk Yoo, Chulhong Min, Dongsun Yim, John Kim
2019 A conf
MobiSys
Bumsoo Kang, Inseok Hwang, Jinho Lee, Seungchul Lee, Taegyeong Lee, Youngjae Chang, Min Kyung Lee
2019 conf
ICCV Workshops
Mayoore Jaiswal, H. Peter Hofstee, Valerie Chen, Suvadip Paul, Rogério Feris, Frank Liu, Anupama Jagannathan, Anne Gattiker, Inseok Hwang, Jinho Lee, Matthew Tong, Sahil Dureja, Soham Shah
2018 A conf
MobiSys
Bumsoo Kang, Inseok Hwang, Jinho Lee, Seungchul Lee, Taegyeong Lee, Youngjae Chang, Min Kyung Lee
2018 A conf
MobiSys
Bumsoo Kang, Inseok Hwang, Jinho Lee, Seungchul Lee, Taegyeong Lee, Youngjae Chang, Min Kyung Lee
2017 J jnl
GetMobile Mob. Comput. Commun.
Chungkuk Yoo, Inseok Hwang, Seungwoo Kang, Myung-Chul Kim, Seonghoon Kim, Daeyoung Won, Yu Gu, Junehwa Song
2017 A conf
MobiSys
Chungkuk Yoo, Inseok Hwang, Seungwoo Kang, Myung-Chul Kim, Seonghoon Kim, Daeyoung Won, Yu Gu, Junehwa Song
2017 A conf
MobiSys
Chungkuk Yoo, Inseok Hwang, Seungwoo Kang, Myung-Chul Kim, Seonghoon Kim, Daeyoung Won, Yu Gu, Junehwa Song
2017 B conf
MDM
Jinho Lee, Inseok Hwang, Thomas Hubregtsen, Anne E. Gattiker, Christopher M. Durham
2017 conf
CSCW Companion
Bumsoo Kang, Wonjung Kim, Inseok Hwang, Chunjong Park, Seungchul Lee, Chulhong Min, Sung-Ju Lee, Junehwa Song
2017 A conf
CSCW
Bumsoo Kang, Chulhong Min, Wonjung Kim, Inseok Hwang, Chunjong Park, Seungchul Lee, Sung-Ju Lee, Junehwa Song
2016 J jnl
IEEE Trans. Mob. Comput.
Youngki Lee, Seungwoo Kang, Chulhong Min, Younghyun Ju, Inseok Hwang, Junehwa Song
2016 conf
MobiSys (Companion Volume)
Chungkuk Yoo, Inseok Hwang, Eric Rozner, Yu Gu, Robert F. Dickerson
2016 J jnl
ACM Trans. Sens. Networks
WooHyeok Choi, Jeungmin Oh, Taiwoo Park, Seongjun Kang, Miri Moon, Uichin Lee, Inseok Hwang, Darren Edge, Junehwa Song
2016 J jnl
GetMobile Mob. Comput. Commun.
Chulhong Min, Youngki Lee, Chungkuk Yoo, Seungwoo Kang, Inseok Hwang, Junehwa Song
2016 A* conf
CHI
Chungkuk Yoo, Inseok Hwang, Eric Rozner, Yu Gu, Robert F. Dickerson
2015 conf
UbiComp/ISWC Adjunct
Youngki Lee, Inseok Hwang
2015 Misc conf
SenSys
Chulhong Min, Chungkuk Yoo, Sangwon Choi, Pillsoon Park, Seungchul Lee, Changhun Lee, Seungpyo Choi, Seungwoo Kang, Youngki Lee, Inseok Hwang, Younghyun Ju, Junehwa Song
2015 Misc conf
SenSys
Chulhong Min, Youngki Lee, Chungkuk Yoo, Seungwoo Kang, Sangwon Choi, Pillsoon Park, Inseok Hwang, Younghyun Ju, Seungpyo Choi, Junehwa Song
2015 Misc conf
UbiComp
Chulhong Min, Chungkuk Yoo, Inseok Hwang, Seungwoo Kang, Youngki Lee, Seungchul Lee, Pillsoon Park, Changhun Lee, Seungpyo Choi, Junehwa Song
2015 A conf
CSCW
Bumsoo Kang, Sujin Lee, Alice Oh, Seungwoo Kang, Inseok Hwang, Junehwa Song
2014 Misc conf
UbiComp
Yuhwan Kim, Seungchul Lee, Inseok Hwang, Hyunho Ro, Youngki Lee, Miri Moon, Junehwa Song
2014 A* conf
CHI
Taiwoo Park, Uichin Lee, I. Scott MacKenzie, Miri Moon, Inseok Hwang, Junehwa Song
2014 Misc conf
SenSys
WooHyeok Choi, Jeungmin Oh, Taiwoo Park, Seongjun Kang, Miri Moon, Uichin Lee, Inseok Hwang, Junehwa Song
2014 A conf
CSCW
Inseok Hwang, Chungkuk Yoo, Chanyou Hwang, Dongsun Yim, Youngki Lee, Chulhong Min, John Kim, Junehwa Song
2014 conf
UbiComp Adjunct
Chulhong Min, Youngki Lee, Saumay Pushp, Seungwoo Kang, Seungchul Lee, Junehwa Song, Inseok Hwang
2013 J jnl
ACM SIGMOBILE Mob. Comput. Commun. Rev.
Chulhong Min, Chanyou Hwang, Taiwoo Park, Yuhwan Kim, Uichin Lee, Inseok Hwang, Chungkuk Yoo, Changhoon Lee, Younghyun Ju, Junehwa Song, Jaeung Lee, Miri Moon, Haechan Lee, Youngki Lee
2013 conf
UbiComp (Adjunct Publication)
Haechan Lee, Miri Moon, Taiwoo Park, Inseok Hwang, Uichin Lee, Junehwa Song
2013 conf
UbiComp (Adjunct Publication)
Chungkuk Yoo, Jaemyung Shin, Inseok Hwang, Junehwa Song
2013 A conf
MobiSys
Youngki Lee, Chulhong Min, Chanyou Hwang, Jaeung Lee, Inseok Hwang, Younghyun Ju, Chungkuk Yoo, Miri Moon, Uichin Lee, Junehwa Song
2013 A conf
MobiSys
Youngki Lee, Chulhong Min, Chanyou Hwang, Jaeung Lee, Inseok Hwang, Younghyun Ju, Chungkuk Yoo, Miri Moon, Uichin Lee, Junehwa Song
2012 A conf
MobiSys
Youngki Lee, Younghyun Ju, Chulhong Min, Seungwoo Kang, Inseok Hwang, Junehwa Song
2012 A conf
MobiSys
Taiwoo Park, Inseok Hwang, Uichin Lee, Sunghoon Ivan Lee, Chungkuk Yoo, Youngki Lee, Hyukjae Jang, Sungwon Peter Choe, Souneil Park, Junehwa Song
2012 A conf
MobiSys
Youngki Lee, Younghyun Ju, Chulhong Min, Seungwoo Kang, Inseok Hwang, Junehwa Song
2012 A conf
MobiSys
Taiwoo Park, Inseok Hwang, Uichin Lee, Sunghoon Ivan Lee, Chungkuk Yoo, Youngki Lee, Hyukjae Jang, Sungwon Peter Choe, Souneil Park, Junehwa Song
2012 conf
Pervasive
Inseok Hwang, Hyukjae Jang, Taiwoo Park, Aram Choi, Youngki Lee, Chanyou Hwang, Yanggui Choi, Lama Nachman, Junehwa Song
2012 A conf
MobiSys
Chulhong Min, Wookhyun Han, Inseok Hwang, SangJeong Lee, Youngki Lee, Insik Shin, Junehwa Song
2012 Misc conf
UbiComp
Hyukjae Jang, Sungwon Peter Choe, Inseok Hwang, Chanyou Hwang, Lama Nachman, Junehwa Song
2012 conf
MobiGames@SIGCOMM
Inseok Hwang, Youngki Lee, Taiwoo Park, Junehwa Song
2011 A conf
MobiSys
Taiwoo Park, Jinwon Lee, Inseok Hwang, Chungkuk Yoo, Lama Nachman, Junehwa Song
2011 Misc conf
SenSys
Taiwoo Park, Jinwon Lee, Inseok Hwang, Chungkuk Yoo, Lama Nachman, Junehwa Song
2011 J jnl
J. Syst. Softw.
Byoungjip Kim, SangJeong Lee, Youngki Lee, Inseok Hwang, Yunseok Rhee, Junehwa Song
2011 Misc conf
UbiComp
Inseok Hwang, Hyukjae Jang, Taiwoo Park, Aram Choi, Chanyou Hwang, Yanggui Choi, Lama Nachman, Junehwa Song
2010 Misc conf
UbiComp
Inseok Hwang, Hyukjae Jang, Lama Nachman, Junehwa Song
2009 conf
Advances in Computer Entertainment Technology
Miru Ahn, Sungjun Kwon, Byunglim Park, Kyungmin Cho, Sungwon Peter Choe, Inseok Hwang, Hyukjae Jang, Jaesang Park, Yunseok Rhee, Junehwa Song
2008 J jnl
IEEE Netw.
Kyungmin Cho, Inseok Hwang, Seungwoo Kang, Byoungjip Kim, Jinwon Lee, SangJeong Lee, Souneil Park, Junehwa Song, Yunseok Rhee
2005 conf
PerCom Workshops
Inseok Hwang, Qi Han, Archan Misra
2003 Misc conf
SAC
Su Myeon Kim, Kyungmin Cho, Inseok Hwang, Seungwoo Kang, Heung-Kyu Lee
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