Osamu Takahashi

78 papers A* 1A 3B 8C 10Misc 1Journal 29Unranked 26
YearRankTypeTitle / Venue / Authors
2023 J jnl
Adv. Data Anal. Classif.
Kuniyoshi Hayashi, Eri Hoshino, Mitsuyoshi Suzuki, Kotomi Sakai, Masayuki Obatake, Osamu Takahashi
2019 Misc conf
ICNC
Yoshitaka Nakamura, Tomohiro Kaneta, Osamu Takahashi
2018 conf
NTMS
Yoshitaka Nakamura, Shihori Kanazawa, Hiroshi Inamura, Osamu Takahashi
2018 J jnl
Ad Hoc Networks
Wu Wang, Bin Yang, Osamu Takahashi, Xiaohong Jiang, Shikai Shen
2017 conf
ICMU
Kazuki Iwata, Yoshitaka Nakamura, Hiroshi Inamura, Osamu Takahashi
2017 B conf
WCNC
Yang Xu, Jia Liu, Osamu Takahashi, Norio Shiratori, Xiaohong Jiang
2016 C conf
MobiQuitous
Masanori Ooi, Yoshitaka Nakamura, Hiroshi Inamura, Osamu Takahashi
2016 conf
NaNA
Wu Wang, Bin Yang, Osamu Takahashi, Xiaohong Jiang, Shikai Shen
2015 conf
ICMU
Yuta Watanabe, Yoshitaka Nakamura, Osamu Takahashi
2015 conf
CANDAR
Wu Wang, Bin Yang, Osamu Takahashi, Xiaohong Jiang
2015 J jnl
Ad Hoc Sens. Wirel. Networks
Juntao Gao, Yulong Shen, Xiaohong Jiang, Osamu Takahashi, Norio Shiratori
2015 conf
ICMU
JinXiao Zhu, Yin Chen, Yoshitaka Nakamura, Xiaohong Jiang, Osamu Takahashi, Norio Shiratori
2014 conf
ICCE-TW
Yoshitaka Nakamura, Masashi Sekiya, Kazuaki Honda, Osamu Takahashi
2014 J jnl
IEICE Trans. Commun.
JinXiao Zhu, Yulong Shen, Xiaohong Jiang, Osamu Takahashi, Norio Shiratori
2014 J jnl
CoRR
JinXiao Zhu, Yin Chen, Yulong Shen, Osamu Takahashi, Xiaohong Jiang, Norio Shiratori
2014 J jnl
Ad Hoc Networks
JinXiao Zhu, Yin Chen, Yulong Shen, Osamu Takahashi, Xiaohong Jiang, Norio Shiratori
2013 conf
CICC
Ming-Zhang Kuo, Osamu Takahashi, Ping-Lin Yang, Cheng-Chung Lin, Min-Jer Wang, Ping-Wei Wang, Sang H. Dhong
2013 J jnl
Inf. Media Technol.
JinXiao Zhu, Xiaohong Jiang, Osamu Takahashi, Norio Shiratori
2013 J jnl
J. Inf. Process.
JinXiao Zhu, Xiaohong Jiang, Osamu Takahashi, Norio Shiratori
2013 J jnl
CoRR
Juntao Gao, Yulong Shen, Xiaohong Jiang, Osamu Takahashi, Norio Shiratori
2013 J jnl
BMC Medical Informatics Decis. Mak.
Daiki Kobayashi, Osamu Takahashi, Takuya Ueda, Gautam A. Deshpande, Hiroko Arioka, Tsuguya Fukui
2013 J jnl
IEICE Trans. Commun.
Juntao Gao, Jiajia Liu, Xiaohong Jiang, Osamu Takahashi, Norio Shiratori
2013 J jnl
Ad Hoc Networks
Yin Chen, Jiajia Liu, Xiaohong Jiang, Osamu Takahashi
2012 C conf
ICCC
Juntao Gao, Jiajia Liu, Xiaohong Jiang, Osamu Takahashi, Norio Shiratori
2012 C conf
APCC
Yin Chen, Jiajia Liu, Xiaohong Jiang, Osamu Takahashi, Norio Shiratori
2012 C conf
APSCC
JinXiao Zhu, Xiaohong Jiang, Yuezhi Zhou, Yaoxue Zhang, Osamu Takahashi, Norio Shiratori
2012 C conf
APCC
JinXiao Zhu, Xiaohong Jiang, Osamu Takahashi, Norio Shiratori
2010 conf
3PGCIC
Yoh Shiraishi, Osamu Takahashi, Ryo Miki
2010 conf
SAINT
Feelhwan Park, Yoh Shiraishi, Osamu Takahashi
2010 conf
KES (3)
Takashi Mishina, Yoh Shiraishi, Osamu Takahashi
2009 conf
CICC
Osamu Takahashi, Michael Seningen
2008 B conf
ARES
Kyosuke Osaka, Shuang Chang, Tsuyoshi Takagi, Kenichi Yamazaki, Osamu Takahashi
2008 conf
KES (3)
Tomonori Kagi, Osamu Takahashi
2008 J jnl
IEEE J. Solid State Circuits
Juergen Pille, Chad Adams, Todd Christensen, Scott R. Cottier, Sebastian Ehrenreich, Fumihiro Kono, Daniel Nelson, Osamu Takahashi, Shunsako Tokito, Otto A. Torreiter, Otto Wagner, Dieter F. Wendel
2008 conf
ISSCC
Osamu Takahashi, Chad Adams, D. Ault, Erwin Behnen, O. Chiang, Scott R. Cottier, Paula K. Coulman, James Culp, Gilles Gervais, M. S. Gray, Y. Itaka, C. J. Johnson, Fumihiro Kono, L. Maurice, Kevin W. McCullen, Lam Nguyen, Y. Nishino, Hiromi Noro, Jürgen Pille, Mack W. Riley, M. Shen, Chiaki Takano, Shunsako Tokito, Tina Wagner, Hiroshi Yoshihara
2008 conf
KES (3)
Akira Otaka, Tsuyoshi Takagi, Osamu Takahashi
2007 conf
CICC
Osamu Takahashi, Erwin Behnen, Scott R. Cottier, Paula K. Coulman, Sang H. Dhong, Brian K. Flachs, H. Peter Hofstee, C. J. Johnson, Stephen D. Posluszny
2007 conf
CICC
Mack W. Riley, Brian K. Flachs, Sang H. Dhong, Gilles Gervais, Steve Weitzel, Michael Wang, David Boerstler, Mark Bolliger, John M. Keaty, Jürgen Pille, R. Berry, Osamu Takahashi, Y. Nishino, T. Uchino
2007 conf
ISSCC
Jürgen Pille, Chad Adams, Todd Christensen, Scott R. Cottier, Sebastian Ehrenreich, Fumihiro Kono, Daniel Nelson, Osamu Takahashi, Shunsako Tokito, Otto A. Torreiter, Otto Wagner, Dieter F. Wendel
2007 J jnl
IBM J. Res. Dev.
Brian K. Flachs, Shigehiro Asano, Sang H. Dhong, H. Peter Hofstee, Gilles Gervais, Roy Kim, Tien Le, Peichun Liu, Jens Leenstra, John S. Liberty, Brad W. Michael, Hwa-Joon Oh, Silvia M. Müller, Osamu Takahashi, Koji Hirairi, Atsushi Kawasumi, Hiroaki Murakami, Hiromi Noro, Shoji Onishi, Juergen Pille, Joel Silberman, Suksoon Yong, Akiyuki Hatakeyama, Yukio Watanabe, Naoka Yano, Daniel A. Brokenshire, Mohammad Peyravian, Vandung To, Eiji Iwata
2007 conf
KES (3)
Norio Yamaguchi, Makoto Okita, Masahiro Itou, Takayuki Shigematsu, Osamu Takahashi, Eiichi Miyamoto
2006 C conf
CIS
Kyosuke Osaka, Tsuyoshi Takagi, Kenichi Yamazaki, Osamu Takahashi
2006 J jnl
IEEE J. Solid State Circuits
James D. Warnock, Dieter F. Wendel, Tony Aipperspach, Erwin Behnen, Robert A. Cordes, Sang H. Dhong, Koji Hirairi, Hiroaki Murakami, Shohji Onishi, Dac C. Pham, Jürgen Pille, Stephen D. Posluszny, Osamu Takahashi, Huajun Wen
2006 B conf
MDM
Shin Yokoyama, Yoshikazu Nakane, Osamu Takahashi, Eiichi Miyamoto
2006 J jnl
IEEE J. Solid State Circuits
Dac C. Pham, Tony Aipperspach, David Boerstler, Mark Bolliger, Rajat Chaudhry, Dennis Cox, Paul E. Harvey, H. Peter Hofstee, Charles R. Johns, Jim Kahle, Atsushi Kameyama, John M. Keaty, Yoshio Masubuchi, Mydung Pham, Jürgen Pille, Stephen D. Posluszny, Mack W. Riley, Daniel L. Stasiak, Masakazu Suzuoki, Osamu Takahashi, James D. Warnock, Stephen Weitzel, Dieter F. Wendel, Kazuaki Yazawa
2006 J jnl
Inf. Media Technol.
Motoharu Miyake, Hiroshi Inamura, Osamu Takahashi
2006 J jnl
IEEE J. Solid State Circuits
Brian K. Flachs, Shigehiro Asano, Sang H. Dhong, H. Peter Hofstee, Gilles Gervais, Roy Kim, Tien Le, Peichun Liu, Jens Leenstra, John S. Liberty, Brad W. Michael, Hwa-Joon Oh, Silvia Melitta Müller, Osamu Takahashi, A. Hatakeyama, Yukio Watanabe, Naoka Yano, Daniel A. Brokenshire, Mohammad Peyravian, Vandung To, Eiji Iwata
2005 J jnl
IEICE Trans. Commun.
Hidetoshi Ueno, Hideharu Suzuki, Norihiro Ishikawa, Osamu Takahashi
2005 B conf
IJCNN
Yuuki Nakamiya, Mitsunaga Kinjo, Osamu Takahashi, Shigeo Sato, Koji Nakajima
2005 J jnl
IEEE Micro
Toru Asano, Joel Silberman, Sang H. Dhong, Osamu Takahashi, Michael White, Scott R. Cottier, Takaaki Nakazato, Atsushi Kawasumi, Hiroshi Yoshihara
2005 J jnl
Clust. Comput.
Hidetoshi Ueno, Norihiro Ishikawa, Hideharu Suzuki, Hiromitsu Sumino, Osamu Takahashi
2005 J jnl
IEEE Micro
Osamu Takahashi, Scott R. Cottier, Sang H. Dhong, Brian K. Flachs, Joel Silberman
2005 A conf
ICCAD
Osamu Takahashi, Russ Cook, Scott R. Cottier, Sang H. Dhong, Brian K. Flachs, Koji Hirairi, Atsushi Kawasumi, Hiroaki Murakami, Hiromi Noro, Hwa-Joon Oh, S. Onish, Juergen Pille, Joel Silberman
2004 B conf
IJCNN
Shigeo Sato, Mitsunaga Kinjo, Osamu Takahashi, Yuuki Nakamiya, Koji Nakajima
2004 B conf
IEEE Congress on Evolutionary Computation
Osamu Takahashi, Shigenobu Kobayashi
2004 conf
AINA (1)
Hiroshi Inamura, Osamu Takahashi, Taro Ishikawa, Hiroshi Shigeno, Ken-ichi Okada
2004 J jnl
Telecommun. Syst.
Norihiro Ishikawa, Hironori Fujiwara, Hidetoshi Ueno, Hideharu Suzuki, Osamu Takahashi
2004 A conf
ICDCS
Hiroshi Inamura, Osamu Takahashi, Hirotaka Nakano, Taro Ishikawa, Hiroshi Shigeno
2003 J jnl
J. Comput. Chem.
Osamu Takahashi, Masanori Joyabu, Masaki Mitani, Ko Saito, Suehiro Iwata
2002 B conf
NETWORKING
Hidetoshi Ueno, Norihiro Ishikawa, Hideharu Suzuki, Hiromitsu Sumino, Osamu Takahashi
2001 B conf
SMC
Osamu Takahashi, Shigenobu Kobayashi
2000 A* conf
DAC
Stephen D. Posluszny, Naoaki Aoki, David Boerstler, Paula K. Coulman, Sang H. Dhong, Brian K. Flachs, H. Peter Hofstee, Nobuo Kojima, Ohsang Kwon, Kyung T. Lee, David Meltzer, Kevin J. Nowka, J. Park, J. Peter, Joel Silberman, Osamu Takahashi, Paul Villarrubia
2000 J jnl
IEEE J. Solid State Circuits
Osamu Takahashi, Sang H. Dhong, Manabu Ohkubo, Shohji Onishi, Robert H. Dennard, Robert Hannon, Scott Crowder, Subramanian S. Iyer, Matthew R. Wordeman, Bijan Davari, William B. Weinberger, Naoaki Aoki
2000 A conf
GECCO
Osamu Takahashi, Hajime Kita, Shigenobu Kobayashi
1999 J jnl
IEEE J. Solid State Circuits
Osamu Takahashi, Naoaki Aoki, Joel Silberman, Sang H. Dhong
1998 J jnl
IEEE J. Solid State Circuits
Joel Silberman, Naoaki Aoki, David Boerstler, Jeffrey L. Burns, Sang H. Dhong, Axel Essbaum, Uttam Ghoshal, David F. Heidel, H. Peter Hofstee, Kyung T. Lee, David Meltzer, Hung C. Ngo, Kevin J. Nowka, Stephen D. Posluszny, Osamu Takahashi, Ivan Vo, Brian A. Zoric
1998 C conf
ICCD
Osamu Takahashi, Joel Silberman, Sang H. Dhong, H. Peter Hofstee, Naoaki Aoki
1998 C conf
ICCD
Stephen D. Posluszny, Naoaki Aoki, David Boerstler, Jeffrey L. Burns, Sang H. Dhong, Uttam Ghoshal, H. Peter Hofstee, David P. LaPotin, Kyung T. Lee, David Meltzer, Hung C. Ngo, Kevin J. Nowka, Joel Silberman, Osamu Takahashi, Ivan Vo
1998 J jnl
IEEE Micro
H. Peter Hofstee, Sang H. Dhong, David Meltzer, Kevin J. Nowka, Joel Silberman, Jeffrey L. Burns, Stephen D. Posluszny, Osamu Takahashi
1997 conf
SIGDOC
Teruji Shiroshita, Osamu Takahashi, Shizuo Shiokawa
1996 conf
IFIP World Conference on IT Tools
Osamu Takahashi, Teruji Shiroshita, Takeshi Sano, Masahide Yamashita, Yukihiro Nakamura, Mina Maruyama
1996 conf
Protocols for High-Speed Networks
Teruji Shiroshita, Takeshi Sano, Osamu Takahashi, Masahide Yamashita, N. Yamanouchi, T. Kushida
1996 conf
PDIS
Teruji Shiroshita, Osamu Takahashi, Masahide Yamashita
1989 J jnl
IEEE Trans. Robotics Autom.
Osamu Takahashi, Robert J. Schilling
1988 C conf
ICCC
Osamu Takahashi, Shizuo Yoshitake, Shigekazu Kawano
1986 C conf
ICCC
Shoichiro Asano, Naohiko Hayashi, Tetsuo Ono, Osamu Takahashi, Shizuo Yoshitake
1983 conf
AFIPS National Computer Conference
Takatoshi Minami, Kenjiro Yano, Takashi Touge, Hisashi Morikawa, Osamu Takahashi
1980 conf
IFIP Congress
Kazuyoshi Morino, Osamu Takahashi
tests/unit/test_apk_strings_ioc.py
← Index tests/unit/test_apk_strings_ioc.py python
"""Tests for APK string extraction and IOC extraction integration.

Covers:
- APKCodeAnalyzer._extract_strings() — string extraction from DEX objects
- APKCodeAnalyzer._string_entropy() — Shannon entropy computation
- DecompileAPK strings export table schema
- IOCExtractorFromResults with APK-format analysis_results
- Worker IOC wiring for APK
"""
import os
import tempfile
from dataclasses import asdict
from unittest.mock import MagicMock, patch

import pytest

from redb.extractors.ioc_extractor.ioc_extractor import IOCExtractorFromResults
from redb.extractors.ioc_extractor.standalone_ioc_extractor import (
    IOCType,
    SourceType,
)

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


# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

def _make_analyzer(min_instructions=1):
    """Create an APKCodeAnalyzer with mocked dependencies."""
    with patch(
        "redb.extractors.decompiler.apk.analyzer.JADXDecompiler"
    ), patch(
        "redb.extractors.decompiler.apk.analyzer.ApktoolDisassembler"
    ):
        from redb.extractors.decompiler.apk.analyzer import APKCodeAnalyzer
        analyzer = APKCodeAnalyzer("/fake/path.apk")
        analyzer.min_instructions = min_instructions
        return analyzer


def _make_mock_dex(strings):
    """Create a mock DEX object that returns the given strings."""
    dex = MagicMock()
    dex.get_strings.return_value = strings
    return dex


def _create_fake_apk_file():
    """Create a temporary file to act as a fake APK."""
    fd, path = tempfile.mkstemp(suffix=".apk")
    os.write(fd, b"PK\x03\x04fake apk content for hashing")
    os.close(fd)
    return path


# ---------------------------------------------------------------------------
# Tests: _string_entropy
# ---------------------------------------------------------------------------

class TestStringEntropy:
    """Tests for Shannon entropy computation."""

    def test_empty_string(self):
        analyzer = _make_analyzer()
        assert analyzer._string_entropy("") == 0.0

    def test_single_char(self):
        analyzer = _make_analyzer()
        assert analyzer._string_entropy("a") == 0.0

    def test_repeated_char(self):
        analyzer = _make_analyzer()
        assert analyzer._string_entropy("aaaa") == 0.0

    def test_two_equal_chars(self):
        analyzer = _make_analyzer()
        # "ab" -> entropy = 1.0
        assert abs(analyzer._string_entropy("ab") - 1.0) < 0.01

    def test_higher_entropy(self):
        analyzer = _make_analyzer()
        # More variety = higher entropy
        low = analyzer._string_entropy("aabb")
        high = analyzer._string_entropy("abcd")
        assert high > low

    def test_url_string_entropy(self):
        analyzer = _make_analyzer()
        entropy = analyzer._string_entropy("https://evil.com/payload")
        assert entropy > 2.0  # URLs have moderate entropy


# ---------------------------------------------------------------------------
# Tests: _extract_strings
# ---------------------------------------------------------------------------

class TestExtractStrings:
    """Tests for DEX string extraction."""

    def test_basic_extraction(self):
        analyzer = _make_analyzer()
        dex = _make_mock_dex(["hello", "world"])
        result = analyzer._extract_strings([dex])

        assert len(result) == 2
        assert result[0]["string"] == "hello"
        assert result[1]["string"] == "world"

    def test_string_fields_present(self):
        analyzer = _make_analyzer()
        dex = _make_mock_dex(["test_string"])
        result = analyzer._extract_strings([dex])

        entry = result[0]
        assert "string" in entry
        assert "string_encoding" in entry
        assert "string_offset" in entry
        assert "string_length" in entry
        assert "string_entropy" in entry
        assert entry["string_encoding"] == "UTF8"
        assert entry["string_length"] == len("test_string")

    def test_deduplication_across_dex(self):
        """Same string in multiple DEX files is only extracted once."""
        analyzer = _make_analyzer()
        dex1 = _make_mock_dex(["shared", "unique1"])
        dex2 = _make_mock_dex(["shared", "unique2"])
        result = analyzer._extract_strings([dex1, dex2])

        string_values = [s["string"] for s in result]
        assert string_values.count("shared") == 1
        assert "unique1" in string_values
        assert "unique2" in string_values
        assert len(result) == 3

    def test_empty_strings_filtered(self):
        analyzer = _make_analyzer()
        dex = _make_mock_dex(["", "valid", None, "also_valid"])
        result = analyzer._extract_strings([dex])

        string_values = [s["string"] for s in result]
        assert "" not in string_values
        assert None not in string_values
        assert "valid" in string_values
        assert "also_valid" in string_values

    def test_no_dex_files(self):
        analyzer = _make_analyzer()
        result = analyzer._extract_strings([])
        assert result == []

    def test_dex_get_strings_returns_none(self):
        analyzer = _make_analyzer()
        dex = MagicMock()
        dex.get_strings.return_value = None
        result = analyzer._extract_strings([dex])
        assert result == []

    def test_dex_get_strings_exception(self):
        analyzer = _make_analyzer()
        dex = MagicMock()
        dex.get_strings.side_effect = RuntimeError("corrupt DEX")
        result = analyzer._extract_strings([dex])
        assert result == []

    def test_entropy_computed(self):
        analyzer = _make_analyzer()
        dex = _make_mock_dex(["abcdefgh"])
        result = analyzer._extract_strings([dex])
        assert result[0]["string_entropy"] > 0.0

    def test_incremental_offsets(self):
        """String offsets are incremented sequentially."""
        analyzer = _make_analyzer()
        dex = _make_mock_dex(["a", "b", "c"])
        result = analyzer._extract_strings([dex])

        offsets = [s["string_offset"] for s in result]
        assert offsets == [0, 1, 2]

    def test_url_strings_preserved(self):
        """URL strings are extracted without modification."""
        analyzer = _make_analyzer()
        dex = _make_mock_dex([
            "https://evil.com/payload",
            "http://c2.malware.org/gate",
        ])
        result = analyzer._extract_strings([dex])
        strings = [s["string"] for s in result]
        assert "https://evil.com/payload" in strings
        assert "http://c2.malware.org/gate" in strings


# ---------------------------------------------------------------------------
# Tests: strings in extract() integration
# ---------------------------------------------------------------------------

class TestExtractStringsIntegration:
    """Tests that strings are included in extract() results."""

    @patch("redb.extractors.decompiler.apk.analyzer.APKCodeAnalyzer._run_androguard")
    @patch("redb.extractors.decompiler.apk.analyzer.ApktoolDisassembler")
    @patch("redb.extractors.decompiler.apk.analyzer.JADXDecompiler")
    def test_extract_includes_strings(self, mock_jadx, mock_apktool, mock_androguard):
        from redb.extractors.decompiler.apk.analyzer import APKCodeAnalyzer

        mock_dex = _make_mock_dex(["hello", "world"])
        mock_analysis = MagicMock()
        mock_analysis.get_methods.return_value = []
        mock_androguard.return_value = (MagicMock(), [mock_dex], mock_analysis)

        analyzer = APKCodeAnalyzer("/fake/path.apk", log=MagicMock())
        results = analyzer.extract()

        assert "strings" in results
        assert len(results["strings"]) == 2
        assert results["strings"][0]["string"] == "hello"
        analyzer.cleanup()

    @patch("redb.extractors.decompiler.apk.analyzer.APKCodeAnalyzer._run_androguard")
    @patch("redb.extractors.decompiler.apk.analyzer.ApktoolDisassembler")
    @patch("redb.extractors.decompiler.apk.analyzer.JADXDecompiler")
    def test_extract_strings_error_is_non_fatal(self, mock_jadx, mock_apktool, mock_androguard):
        from redb.extractors.decompiler.apk.analyzer import APKCodeAnalyzer

        # Return a bad dex list that will cause _extract_strings to fail
        mock_analysis = MagicMock()
        mock_analysis.get_methods.return_value = []
        # dexs is not iterable — triggers the except block
        mock_androguard.return_value = (MagicMock(), 42, mock_analysis)

        analyzer = APKCodeAnalyzer("/fake/path.apk", log=MagicMock())
        results = analyzer.extract()

        # Should not crash, strings should be empty, error recorded
        assert results["strings"] == []
        assert any(
            e.get("error_location") == "strings"
            for e in results["analysis_errors"]
        )
        analyzer.cleanup()


# ---------------------------------------------------------------------------
# Tests: DecompileAPK strings export table
# ---------------------------------------------------------------------------

class TestDecompileAPKStringsExport:
    """Tests for strings table in DecompileAPK.prepare_export_data()."""

    def _make_extractor_with_strings(self, strings_data):
        from redb.extractors.decompiler.DecompileAPK import DecompileAPK
        apk_path = _create_fake_apk_file()
        ext = DecompileAPK(apk_path, MagicMock())
        ext.analysis_results = {
            "sha256": "a" * 64,
            "sha1": "b" * 40,
            "md5": "c" * 32,
            "decompiled_content": [],
            "decompiled_refs": [],
            "smali_content": [],
            "smali_refs": [],
            "similarity_metrics": [],
            "strings": strings_data,
            "analysis_errors": [],
        }
        return ext, apk_path

    def test_strings_table_present(self):
        ext, path = self._make_extractor_with_strings([
            {"string": "hello", "string_encoding": "UTF8",
             "string_offset": 0, "string_length": 5, "string_entropy": 2.32}
        ])
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            assert "strings_raw" in export
        finally:
            os.unlink(path)

    def test_strings_table_schema(self):
        ext, path = self._make_extractor_with_strings([
            {"string": "hello", "string_encoding": "UTF8",
             "string_offset": 0, "string_length": 5, "string_entropy": 2.32}
        ])
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            sr = export["strings_raw"]
            assert sr["table"] == "code_binja_strings_raw"
            assert len(sr["column_names"]) == 8
            assert len(sr["column_type_names"]) == 8
            assert "sha256" in sr["column_names"]
            assert "string" in sr["column_names"]
            assert "string_raw" in sr["column_names"]
            assert "string_encoding" in sr["column_names"]
            assert "string_offset" in sr["column_names"]
            assert "string_length" in sr["column_names"]
            assert "string_raw_length" in sr["column_names"]
            assert "string_entropy" in sr["column_names"]
            assert len(sr["data"]) == 1
            assert len(sr["data"][0]) == 8
        finally:
            os.unlink(path)

    def test_strings_sha256_propagated(self):
        ext, path = self._make_extractor_with_strings([
            {"string": "test", "string_encoding": "UTF8",
             "string_offset": 0, "string_length": 4, "string_entropy": 2.0}
        ])
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            row = export["strings_raw"]["data"][0]
            assert row[0] == "a" * 64  # sha256 is first column
        finally:
            os.unlink(path)

    def test_empty_strings_not_exported(self):
        ext, path = self._make_extractor_with_strings([])
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            assert "strings_raw" not in export
        finally:
            os.unlink(path)


# ---------------------------------------------------------------------------
# Tests: IOCExtractorFromResults with APK format
# ---------------------------------------------------------------------------

class TestIOCExtractorAPKFormat:
    """Tests that IOCExtractorFromResults handles APK analysis_results."""

    def setup_method(self):
        self.log = MagicMock()

    def test_extract_iocs_from_apk_strings(self):
        """IOCs extracted from APK strings (same format as Binja)."""
        results = {
            "strings": [
                {"string": "https://evil.com/payload", "string_offset": 0},
                {"string": "Contact [email protected]", "string_offset": 1},
            ],
            "decompiled": [],
            "decompiled_content": [],
        }
        extractor = IOCExtractorFromResults(results, sha256="a" * 64, log=self.log)
        iocs = extractor.extract()

        url_iocs = [i for i in iocs if i.ioc_type == IOCType.URL]
        assert len(url_iocs) >= 1
        assert any("evil.com" in i.ioc_value for i in url_iocs)

    def test_extract_iocs_from_apk_decompiled_content(self):
        """IOCs extracted from APK's decompiled_content key."""
        results = {
            "strings": [],
            "decompiled": [],  # Binja format — empty
            "decompiled_content": [  # APK format
                {
                    "decompiled_method": "connect('https://c2.malware.org/gate');",
                    "decompiled_method_hash": "hash123",
                    "method_type": "USER",
                }
            ],
        }
        extractor = IOCExtractorFromResults(results, sha256="a" * 64, log=self.log)
        iocs = extractor.extract()

        url_iocs = [i for i in iocs if i.ioc_type == IOCType.URL]
        assert len(url_iocs) >= 1

    def test_apk_library_methods_skipped(self):
        """LIBRARY methods in decompiled_content are skipped."""
        results = {
            "strings": [],
            "decompiled": [],
            "decompiled_content": [
                {
                    "decompiled_method": "https://should-skip.com",
                    "decompiled_method_hash": "lib_hash",
                    "method_type": "LIBRARY",
                }
            ],
        }
        extractor = IOCExtractorFromResults(results, sha256="a" * 64, log=self.log)
        iocs = extractor.extract()
        assert len(iocs) == 0

    def test_combined_binja_and_apk_sources(self):
        """Both Binja and APK format decompiled entries are processed."""
        results = {
            "strings": [],
            "decompiled": [
                {
                    "decompiled_function": "call('https://binja.example.com');",
                    "decompiled_function_hash": "binja_hash",
                    "function_type": "USER",
                }
            ],
            "decompiled_content": [
                {
                    "decompiled_method": "send('https://apk.example.com');",
                    "decompiled_method_hash": "apk_hash",
                    "method_type": "USER",
                }
            ],
        }
        extractor = IOCExtractorFromResults(results, sha256="a" * 64, log=self.log)
        iocs = extractor.extract()

        url_iocs = [i for i in iocs if i.ioc_type == IOCType.URL]
        urls = [i.ioc_value for i in url_iocs]
        assert any("binja.example.com" in u for u in urls)
        assert any("apk.example.com" in u for u in urls)

    def test_apk_results_only(self):
        """Works when only APK keys are present (no 'decompiled' key)."""
        results = {
            "strings": [
                {"string": "https://evil.com", "string_offset": 0},
            ],
            "decompiled_content": [
                {
                    "decompiled_method": "x = 1",
                    "decompiled_method_hash": "h",
                    "method_type": "USER",
                }
            ],
        }
        extractor = IOCExtractorFromResults(results, sha256="a" * 64, log=self.log)
        iocs = extractor.extract()
        # Should not crash, and should find URL from strings
        url_iocs = [i for i in iocs if i.ioc_type == IOCType.URL]
        assert len(url_iocs) >= 1

    def test_source_type_is_string_for_strings(self):
        results = {
            "strings": [
                {"string": "https://evil.com/test", "string_offset": 42},
            ],
            "decompiled_content": [],
        }
        extractor = IOCExtractorFromResults(results, sha256="a" * 64, log=self.log)
        iocs = extractor.extract()
        url_iocs = [i for i in iocs if i.ioc_type == IOCType.URL]
        assert url_iocs[0].source_type == SourceType.STRING
        assert url_iocs[0].source_identifier == "42"

    def test_source_type_is_decompiled_for_methods(self):
        results = {
            "strings": [],
            "decompiled_content": [
                {
                    "decompiled_method": "https://evil.com/method",
                    "decompiled_method_hash": "myhash",
                    "method_type": "USER",
                }
            ],
        }
        extractor = IOCExtractorFromResults(results, sha256="a" * 64, log=self.log)
        iocs = extractor.extract()
        url_iocs = [i for i in iocs if i.ioc_type == IOCType.URL]
        assert url_iocs[0].source_type == SourceType.DECOMPILED_FUNCTION
        assert url_iocs[0].source_identifier == "myhash"


# ---------------------------------------------------------------------------
# Tests: Worker IOC wiring for APK
# ---------------------------------------------------------------------------

class TestWorkerAPKIOCWiring:
    """Tests that workers.py wires IOC extraction for APK."""

    def test_worker_source_contains_ioc_for_apk(self):
        """Verify workers.py source has IOC extraction in APK branch."""
        import inspect
        from redb import workers
        source = inspect.getsource(workers)
        # APK branch should import IOCExtractorFromResults
        assert "IOCExtractorFromResults" in source
        # Should be in the APK section (near DecompileAPK)
        apk_section = source[source.index("DecompileAPK("):]
        ioc_pos = apk_section.find("IOCExtractorFromResults")
        assert ioc_pos != -1, "IOCExtractorFromResults not found after DecompileAPK"