Karsten Klein

134 papers A* 2A 24B 4C 8Journal 71Unranked 16
YearRankTypeTitle / Venue / Authors
2026 J jnl
CoRR
Wilhelm Kerle-Malcharek, Giulio Biondi, Karsten Klein, Ulf Hailer, Steffen Diefenbach, Fabrizio Grosso, Marco Legittimo, Paola Venuti, Carla Binucci, Giuseppe Liotta, Falk Schreiber
2025 J jnl
IEEE Trans. Vis. Comput. Graph.
Michael Aichem, Karsten Klein, Stephen G. Kobourov, Falk Schreiber
2025 A conf
GD
Raissa dos Santos Vieira, Hugo A. D. do Nascimento, Joelma de Moura Ferreira, Les R. Foulds, Karsten Klein, Falk Schreiber
2025 J jnl
IEEE Trans. Vis. Comput. Graph.
Niklas Gröne, Peter Eades, Karsten Klein, Patrick Eades, Leo Schreiber, Ulf Hailer, Hugo A. D. do Nascimento, Falk Schreiber
2025 A conf
GD
Ying Zhang, Niklas Gröne, Giuseppe Liotta, Falk Schreiber, Karsten Klein
2025 J jnl
CoRR
Ying Zhang, Niklas Gröne, Karsten Klein, Giuseppe Liotta, Falk Schreiber
2025 J jnl
CoRR
Wilhelm Kerle-Malcharek, Karsten Klein, Martin Wikelski, Falk Schreiber, Timm A. Wild
2025 A conf
GD
Lucas Joos, Gavin J. Mooney, Maximilian T. Fischer, Daniel A. Keim, Falk Schreiber, Helen C. Purchase, Karsten Klein
2025 J jnl
CoRR
Lucas Joos, Gavin J. Mooney, Maximilian T. Fischer, Daniel A. Keim, Falk Schreiber, Helen C. Purchase, Karsten Klein
2025 J jnl
J. Integr. Bioinform.
Falk Schreiber, Tobias Czauderna, Dimitar Garkov, Niklas Gröne, Karsten Klein, Matthias Lange, Uwe Scholz, Björn Sommer
2025 J jnl
CoRR
Wilhelm Kerle-Malcharek, Niklas Hann-von-Weyhern, Ulf Hailer, Steffen Diefenbach, Stefan P. Feyer, Karsten Klein, Falk Schreiber
2025 A conf
GD
Lin Zhang, Yao Wang, Ying Zhang, Wilhelm Kerle-Malcharek, Karsten Klein, Falk Schreiber, Andreas Bulling
2025 J jnl
CoRR
Lucas Joos, Maximilian T. Fischer, Julius Rauscher, Daniel A. Keim, Tim Dwyer, Falk Schreiber, Karsten Klein
2025 C conf
IV
Rika Tarumi, Asahi Hentona, Karsten Klein, Takayuki Itoh
2024 J jnl
IEEE Trans. Vis. Comput. Graph.
Stefan P. Feyer, Bruno Pinaud, Stephen G. Kobourov, Nicolas Brich, Michael Krone, Andreas Kerren, Michael Behrisch, Falk Schreiber, Karsten Klein
2024 A ed.
GD
Stefan Felsner, Karsten Klein
2024 J jnl
CoRR
Dimitar Garkov, Tommaso Piselli, Emilio Di Giacomo, Karsten Klein, Giuseppe Liotta, Fabrizio Montecchiani, Falk Schreiber
2024 J jnl
J. Integr. Bioinform.
Stefan Paul Feyer, Bruno Pinaud, Karsten Klein, Etienne Lein, Falk Schreiber
2024 A conf
GD
Stefan P. Feyer, Wilhelm Kerle-Malcharek, Ying Zhang, Falk Schreiber, Karsten Klein
2024 J jnl
J. Integr. Bioinform.
Niklas Gröne, Benjamin Grüneisen, Karsten Klein, Bernard de Bono, Tobias Czauderna, Falk Schreiber
2024 J jnl
Bioinform.
Philipp Eberhard, Martin Kern, Michael Aichem, Hanna Borlinghaus, Karsten Klein, Johannes Delp, Ilinca Suciu, Benjamin Moser, Daniel Dietrich, Marcel Leist, Falk Schreiber
2024 B conf
ETRA
Yao Wang, Qi Dai, Mihai Bâce, Karsten Klein, Andreas Bulling
2024 J jnl
J. Cheminformatics
Sabrina Jaeger-Honz, Karsten Klein, Falk Schreiber
2024 J jnl
PLoS Comput. Biol.
Nicolai Kraus, Michael Aichem, Karsten Klein, Etienne Lein, Alex Jordan, Falk Schreiber
2024 conf
EuroVA@EuroVis
Ying Zhang, Hannah Williams, Falk Schreiber, Karsten Klein
2024 J jnl
CoRR
Kathryn Gray, Brian Bell, Diana Sieper, Stephen G. Kobourov, Falk Schreiber, Karsten Klein, Seokhee Hong
2023 J jnl
CoRR
Stefan P. Feyer, Bruno Pinaud, Stephen G. Kobourov, Nicolas Brich, Michael Krone, Andreas Kerren, Michael Behrisch, Falk Schreiber, Karsten Klein
2023 J jnl
Vis. Comput. Ind. Biomed. Art
Ying Zhang, Karsten Klein, Falk Schreiber, Kamran Safi
2023 conf
GD (1)
Peter Eades, Niklas Gröne, Karsten Klein, Patrick Eades, Leo Schreiber, Ulf Hailer, Falk Schreiber
2023 J jnl
CoRR
Peter Eades, Niklas Gröne, Karsten Klein, Patrick Eades, Leo Schreiber, Ulf Hailer, Falk Schreiber
2023 J jnl
IEEE Computer Graphics and Applications
Hsiang-Yun Wu, Karsten Klein, Da Yan
2023 A* conf
ISMAR
Lucas Joos, Karsten Klein, Maximilian T. Fischer, Frederik L. Dennig, Daniel A. Keim, Michael Krone
2023 conf
ICAT-EGVE
Wilhelm Kerle-Malcharek, Stefan Paul Feyer, Falk Schreiber, Karsten Klein
2023 J jnl
Dagstuhl Reports
Karsten Klein, Stephen G. Kobourov, Bernice E. Rogowitz, Danielle Szafir, Jacob Miller
2022 J jnl
Dagstuhl Reports
Karsten Klein, Juan F. Sequeda, Hsiang-Yun Wu, Da Yan
2022 J jnl
Comput. Graph. Forum
Matthias Kraus, Johannes Fuchs, Björn Sommer, Karsten Klein, Ulrich Engelke, Daniel A. Keim, Falk Schreiber
2022 J jnl
it Inf. Technol.
Karsten Klein, Michael Sedlmair, Falk Schreiber
2022 J jnl
J. Graph Algorithms Appl.
Michael A. Bekos, Carla Binucci, Giuseppe Di Battista, Walter Didimo, Martin Gronemann, Karsten Klein, Maurizio Patrignani, Ignaz Rutter
2022 J jnl
it Inf. Technol.
Ying Zhang, Karsten Klein, Oliver Deussen, Theodor Gutschlag, Sabine Storandt
2022 J jnl
Vis. Comput. Ind. Biomed. Art
Denis Bienroth, Hieu T. Nim, Dimitar Garkov, Karsten Klein, Sabrina Jaeger-Honz, Mirana Ramialison, Falk Schreiber
2022 J jnl
J. Integr. Bioinform.
Michael Aichem, Karsten Klein, Tobias Czauderna, Dimitar Garkov, Jinxin Zhao, Jian Li, Falk Schreiber
2022 J jnl
IEEE Trans. Vis. Comput. Graph.
Lucas Joos, Sabrina Jaeger-Honz, Falk Schreiber, Daniel A. Keim, Karsten Klein
2021 J jnl
Database J. Biol. Databases Curation
Karsten Klein, Dimitar Garkov, Sina Rütschlin, Thomas Böttcher, Falk Schreiber
2021 J jnl
Database J. Biol. Databases Curation
Karsten Klein, Dimitar Garkov, Sina Rütschlin, Thomas Böttcher, Falk Schreiber
2021 J jnl
J. Vis.
Karsten Klein, Michael Aichem, Ying Zhang, Stefan Erk, Björn Sommer, Falk Schreiber
2021 J jnl
IEEE Computer Graphics and Applications
Matthias Kraus, Karsten Klein, Johannes Fuchs, Daniel A. Keim, Falk Schreiber, Michael Sedlmair, Theresa-Marie Rhyne
2021 C ed.
VINCI
Karsten Klein, Michael Burch, Daniel Limberger, Matthias Trapp
2021 J jnl
J. Vis.
Karsten Klein, Sabrina Jaeger, Jörg Melzheimer, Bettina Wachter, Heribert Hofer, Artur Baltabayev, Falk Schreiber
2021 J jnl
Bioinform.
Michael Aichem, Tobias Czauderna, Yan Zhu, Jinxin Zhao, Matthias Klapperstück, Karsten Klein, Jian Li, Falk Schreiber
2021 J jnl
Dagstuhl Reports
Karsten Klein, Georgeta Elisabeta Marai, Kay Katja Nieselt, Blaz Zupan
2020 B conf
PacificVis
Joseph Kotlarek, Oh-Hyun Kwon, Kwan-Liu Ma, Peter Eades, Andreas Kerren, Karsten Klein, Falk Schreiber
2020 J jnl
CoRR
Joseph Kotlarek, Oh-Hyun Kwon, Kwan-Liu Ma, Peter Eades, Andreas Kerren, Karsten Klein, Falk Schreiber
2020 J jnl
J. Comput. Lang.
Karsten Klein, Yi-Na Li, Andreas Kerren
2020 J jnl
Algorithms
Patrizio Angelini, Peter Eades, Seok-Hee Hong, Karsten Klein, Stephen G. Kobourov, Giuseppe Liotta, Alfredo Navarra, Alessandra Tappini
2020 A conf
GD
Michael A. Bekos, Carla Binucci, Giuseppe Di Battista, Walter Didimo, Martin Gronemann, Karsten Klein, Maurizio Patrignani, Ignaz Rutter
2020 J jnl
CoRR
Michael A. Bekos, Carla Binucci, Giuseppe Di Battista, Walter Didimo, Martin Gronemann, Karsten Klein, Maurizio Patrignani, Ignaz Rutter
2019 J jnl
Int. J. Found. Comput. Sci.
Markus Chimani, Giuseppe Di Battista, Fabrizio Frati, Karsten Klein
2019 J jnl
Neuroinformatics
Michael de Ridder, Karsten Klein, Jean Yee Hwa Yang, Pengyi Yang, Jim Lagopoulos, Ian B. Hickie, Max Bennett, Jinman Kim
2019 conf
ERVR
Bjorn Sommer, Stefan P. Feyer, Daniel Klinkhammer, Karsten Klein, Jonathan Wieland, Daniel Fink, Wolfgang Fiedler, Andrea Flack, Máté Nagy, Martin Wikelski, Harald Reiterer, Falk Schreiber
2019 B conf
PacificVis
Sabrina Jaeger, Karsten Klein, Lucas Joos, Johannes Zagermann, Michael de Ridder, Jinman Kim, Jean Yee Hwa Yang, Ulrike Pfeil, Harald Reiterer, Falk Schreiber
2019 J jnl
J. Integr. Bioinform.
Dimitar Garkov, Karsten Klein, Christian Klukas, Falk Schreiber
2019 C conf
VINCI
Karsten Klein, Michael Aichem, Björn Sommer, Stefan Erk, Ying Zhang, Falk Schreiber
2019 conf
SD&A
Björn Sommer, Alexandra Diehl, Michael Aichem, Philipp Meschenmoser, Kim Rehberg, David Weber, Ying Zhang, Karsten Klein, Daniel A. Keim, Falk Schreiber
2019 C conf
VINCI
Karsten Klein, Sabrina Jaeger, Jörg Melzheimer, Bettina Wachter, Heribert Hofer, Artur Baltabayev, Falk Schreiber
2018 C conf
VINCI
Mehmood Ghaffar, Niklas Biere, Daniel Jäger, Karsten Klein, Falk Schreiber, Olaf Kruse, Björn Sommer
2018 J jnl
Brain Informatics
Michael de Ridder, Karsten Klein, Jinman Kim
2018 conf
EMBC
Michael de Ridder, Karsten Klein, Jinman Kim
2018 J jnl
CoRR
Vahan Yoghourdjian, Daniel Archambault, Stephan Diehl, Tim Dwyer, Karsten Klein, Helen C. Purchase, Hsiang-Yun Wu
2018 J jnl
Vis. Informatics
Vahan Yoghourdjian, Daniel Archambault, Stephan Diehl, Tim Dwyer, Karsten Klein, Helen C. Purchase, Hsiang-Yun Wu
2018 J jnl
IEEE Trans. Vis. Comput. Graph.
Vahan Yoghourdjian, Tim Dwyer, Karsten Klein, Kim Marriott, Michael Wybrow
2018 ch.
Graph Data Management
Peter Eades, Karsten Klein
2018 book
Kim Marriott, Falk Schreiber, Tim Dwyer, Karsten Klein, Nathalie Henry Riche, Takayuki Itoh, Wolfgang Stuerzlinger, Bruce H. Thomas
2018 ch.
Immersive Analytics
Tobias Czauderna, Jason Haga, Jinman Kim, Matthias Klapperstück, Karsten Klein, Torsten W. Kuhlen, Steffen Oeltze-Jafra, Björn Sommer, Falk Schreiber
2018 ch.
Immersive Analytics
Tim Dwyer, Kim Marriott, Tobias Isenberg, Karsten Klein, Nathalie Henry Riche, Falk Schreiber, Wolfgang Stuerzlinger, Bruce H. Thomas
2018 C ed.
VINCI
Andreas Kerren, Karsten Klein, Yi-Na Li
2018 J jnl
NII Shonan Meet. Rep.
Daniel Archambault, Karsten Klein, Kazuo Misue
2018 A conf
GD
Patrizio Angelini, Peter Eades, Seok-Hee Hong, Karsten Klein, Stephen G. Kobourov, Giuseppe Liotta, Alfredo Navarra, Alessandra Tappini
2018 J jnl
CoRR
Patrizio Angelini, Peter Eades, Seok-Hee Hong, Karsten Klein, Stephen G. Kobourov, Giuseppe Liotta, Alfredo Navarra, Alessandra Tappini
2018 conf
ERVR
Artur Baltabayev, Alexej Gluschkow, Johannes Blank, Gero Birkhölzer, Jean Büsche, Martin Kern, Fabian Klopfer, Lisa-Maria Mayer, Gabriel Scheibler, Karsten Klein, Falk Schreiber, Björn Sommer
2017 conf
SD&A
Björn Sommer, David G. Barnes, Sarah E. Boyd, Tom Chandler, Maxime Cordeil, Tobias Czauderna, Matthias Klapperstück, Karsten Klein, Toàn D. Nguyên, Hieu T. Nim, Kingsley Stephens, Dany Vohl, Stephen Jia Wang, Elliott Wilson, Yan Zhu, Jian Li, Jon McCormack, Kim Marriott, Falk Schreiber
2017 J jnl
J. Graph Algorithms Appl.
Carla Binucci, Markus Chimani, Walter Didimo, Martin Gronemann, Karsten Klein, Jan Kratochvíl, Fabrizio Montecchiani, Ioannis G. Tollis
2017 conf
VCBM
Hieu T. Nim, Björn Sommer, Karsten Klein, Andrea Flack, Kamran Safi, Máté Nagy, Wolfgang Fiedler, Martin Wikelski, Falk Schreiber
2017 J jnl
J. Vis. Lang. Comput.
Takayuki Itoh, Ashnil Kumar, Karsten Klein, Jinman Kim
2017 J jnl
IEEE Trans. Vis. Comput. Graph.
Maxime Cordeil, Tim Dwyer, Karsten Klein, Bireswar Laha, Kim Marriott, Bruce H. Thomas
2017 J jnl
J. Cheminformatics
Till Schäfer, Nils M. Kriege, Lina Humbeck, Karsten Klein, Oliver Koch, Petra Mutzel
2017 J jnl
J. Graph Algorithms Appl.
Peter Eades, Seok-Hee Hong, An Nguyen, Karsten Klein
2017 J jnl
J. Vis. Lang. Comput.
Quang Vinh Nguyen, Karsten Klein, Ulrich Engelke, Tomasz Bednarz, Julian Heinrich
2017 C conf
CGI
Michael de Ridder, Karsten Klein, Jinman Kim
2017 J jnl
J. Vis.
Andrew Kennedy, Karsten Klein, An Nguyen, Florence Ying Wang
2016 A conf
GD
Markus Chimani, Karsten Klein, Tilo Wiedera
2016 J jnl
CoRR
Markus Chimani, Karsten Klein, Tilo Wiedera
2016 J jnl
NII Shonan Meet. Rep.
Takayuki Itoh, Karsten Klein, Giuseppe Liotta
2016 J jnl
CoRR
Takayuki Itoh, Ashnil Kumar, Karsten Klein, Jinman Kim
2016 J jnl
IEEE Trans. Vis. Comput. Graph.
Vahan Yoghourdjian, Tim Dwyer, Graeme Gange, Steve Kieffer, Karsten Klein, Kim Marriott
2016 J jnl
Dagstuhl Reports
Tim Dwyer, Nathalie Henry Riche, Karsten Klein, Wolfgang Stuerzlinger, Bruce H. Thomas
2015 A conf
GD
Carla Binucci, Markus Chimani, Walter Didimo, Martin Gronemann, Karsten Klein, Jan Kratochvíl, Fabrizio Montecchiani, Ioannis G. Tollis
2015 J jnl
IEEE J. Biomed. Health Informatics
Ashnil Kumar, Falk Nette, Karsten Klein, Michael J. Fulham, Jinman Kim
2015 J jnl
NII Shonan Meet. Rep.
Takayuki Itoh, Karsten Klein, Giuseppe Liotta
2015 conf
IVAPP
Michael de Ridder, Karsten Klein, Jinman Kim
2015 conf
BDVA
Tom Chandler, Maxime Cordeil, Tobias Czauderna, Tim Dwyer, Jaroslaw Glowacki, Cagatay Goncu, Matthias Klapperstück, Karsten Klein, Kim Marriott, Falk Schreiber, Elliott Wilson
2015 J jnl
IEEE Computer Graphics and Applications
Takayuki Itoh, Karsten Klein
2015 B conf
PacificVis
Florence Ying Wang, Arnaud Sallaberry, Karsten Klein, Masahiro Takatsuka, Mathieu Roche
2015 A conf
GD
Peter Eades, Seok-Hee Hong, Karsten Klein, An Nguyen
2015 C conf
VINCI
Andrew Kennedy, Karsten Klein, An Nguyen
2014 A conf
GD
Markus Chimani, Giuseppe Di Battista, Fabrizio Frati, Karsten Klein
2014 J jnl
CoRR
Markus Chimani, Giuseppe Di Battista, Fabrizio Frati, Karsten Klein
2014 A conf
GD
Michael R. Marner, Ross T. Smith, Bruce H. Thomas, Karsten Klein, Peter Eades, Seok-Hee Hong
2014 ed.
ED/GViP@Diagrams
Jim Burton, Gem Stapleton, Karsten Klein
2014 J jnl
J. Cheminformatics
Karsten Klein, Oliver Koch, Nils M. Kriege, Petra Mutzel, Till Schäfer
2014 conf
3DVis@IEEE VIS
Bruce H. Thomas, Michael R. Marner, Ross T. Smith, Neven Abdelaziz Mohamed ElSayed, G. Stewart Von Itzstein, Karsten Klein, Matt Adcock, Peter Eades, Andrew Irlitti, Joanne E. Zucco, Timothy M. Simon, James Baumeister, Timothy Suthers
2013 ch.
Handbook of Graph Drawing and Visualization
Markus Chimani, Carsten Gutwenger, Michael Jünger, Gunnar W. Klau, Karsten Klein, Petra Mutzel
2012 conf
GRAPP/IVAPP
Karsten Klein, Nils M. Kriege, Petra Mutzel
2012 conf
VISIGRAPP (Selected Papers)
Karsten Klein, Nils M. Kriege, Petra Mutzel
2012 A conf
GD
Markus Chimani, Karsten Klein
2012 A conf
GD
Tim Dwyer, Fabrizio Frati, Seok-Hee Hong, Karsten Klein
2011 A* conf
ICDE
Karsten Klein, Nils M. Kriege, Petra Mutzel
2011
Karsten Klein
2011 J jnl
CoRR
Christian Bachmaier, Franz-Josef Brandenburg, Philip Effinger, Carsten Gutwenger, Jyrki Katajainen, Karsten Klein, Miro Spönemann, Matthias Stegmaier, Michael Wybrow
2011 A conf
GD
Christian Bachmaier, Franz-Josef Brandenburg, Philip Effinger, Carsten Gutwenger, Jyrki Katajainen, Karsten Klein, Miro Spönemann, Matthias Stegmaier, Michael Wybrow
2010 ch.
Experimental Methods for the Analysis of Optimization Algorithms
Markus Chimani, Karsten Klein
2010 A conf
GD
Gereon Bartel, Carsten Gutwenger, Karsten Klein, Petra Mutzel
2009 A conf
GD
Mario Albrecht, Andreas Kerren, Karsten Klein, Oliver Kohlbacher, Petra Mutzel, Wolfgang Paul, Falk Schreiber, Michael Wybrow
2009 A conf
GD
Karsten Klein, Nils M. Kriege, Petra Mutzel, Herbert Waldmann, Stefan Wetzel
2008 conf
Graph Drawing with Applications to Bioinformatics and Social Sciences
Mario Albrecht, Alejandro Estrella-Balderrama, Markus Geyer, Carsten Gutwenger, Karsten Klein, Oliver Kohlbacher, Michael Schulz
2008 A conf
GD
Markus Chimani, Carsten Gutwenger, Mathias Jansen, Karsten Klein, Petra Mutzel
2008 J jnl
J. Integr. Bioinform.
Dorothea Emig, Melissa S. Cline, Karsten Klein, Anne Kunert, Petra Mutzel, Thomas Lengauer, Mario Albrecht
2008 J jnl
J. Graph Algorithms Appl.
Carsten Gutwenger, Karsten Klein, Petra Mutzel
2006 A conf
GD
Carsten Gutwenger, Karsten Klein, Petra Mutzel
2004 ch.
Graph Drawing Software
Carsten Gutwenger, Michael Jünger, Karsten Klein, Joachim Kupke, Sebastian Leipert, Petra Mutzel
2004 J jnl
Inf. Vis.
Markus Eiglsperger, Carsten Gutwenger, Michael Kaufmann, Joachim Kupke, Michael Jünger, Sebastian Leipert, Karsten Klein, Petra Mutzel, Martin Siebenhaller
2003 conf
SOFTVIS
Carsten Gutwenger, Michael Jünger, Karsten Klein, Joachim Kupke, Sebastian Leipert, Petra Mutzel
2003 A conf
GD
Carsten Gutwenger, Joachim Kupke, Karsten Klein, Sebastian Leipert
2001 A conf
GD
Carsten Gutwenger, Michael Jünger, Karsten Klein, Joachim Kupke, Sebastian Leipert, Petra Mutzel
2000 A conf
GD
Gunnar W. Klau, Karsten Klein, Petra Mutzel
tests/unit/test_apk_decompile_extractor.py
← Index tests/unit/test_apk_decompile_extractor.py python
"""
Unit tests for DecompileAPK extractor, export data, and ClickHouse schemas.

Tests the main DecompileAPK extractor class following the DecompileBinja test pattern.
All analysis is mocked — no JADX/apktool/Java installation required.
"""
import hashlib
import os
import tempfile
import zipfile

import pytest
from unittest.mock import MagicMock, patch, PropertyMock
from dataclasses import asdict

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


def _create_fake_apk_file():
    """Create a minimal APK file for testing and return its path."""
    tmpdir = tempfile.mkdtemp()
    apk_path = os.path.join(tmpdir, "test.apk")
    with zipfile.ZipFile(apk_path, "w") as zf:
        zf.writestr("AndroidManifest.xml", b"<manifest/>")
        zf.writestr("classes.dex", b"dex\n035\x00" + b"\x00" * 100)
    return apk_path


# ============================================================================
# DecompileAPK Extractor Tests
# ============================================================================

class TestDecompileAPK:
    """Tests for the DecompileAPK extractor class."""

    def test_tag(self):
        from redb.extractors.decompiler.DecompileAPK import DecompileAPK
        apk_path = _create_fake_apk_file()
        try:
            ext = DecompileAPK(apk_path, MagicMock())
            assert ext.tag() == "apk_decompiled"
        finally:
            os.unlink(apk_path)

    def test_get_clickhouse_table(self):
        from redb.extractors.decompiler.DecompileAPK import DecompileAPK
        apk_path = _create_fake_apk_file()
        try:
            ext = DecompileAPK(apk_path, MagicMock())
            assert ext.get_clickhouse_table() is None
        finally:
            os.unlink(apk_path)

    def test_timeout_default(self):
        from redb.extractors.decompiler.DecompileAPK import DecompileAPK
        apk_path = _create_fake_apk_file()
        try:
            ext = DecompileAPK(apk_path, MagicMock())
            assert ext.APK_DECOMPILE_TIMEOUT == 600
        finally:
            os.unlink(apk_path)

    def test_timeout_from_env(self):
        from redb.extractors.decompiler.DecompileAPK import DecompileAPK
        apk_path = _create_fake_apk_file()
        try:
            with patch.dict(os.environ, {"APK_DECOMPILE_TIMEOUT": "900"}):
                ext = DecompileAPK(apk_path, MagicMock())
                assert ext.APK_DECOMPILE_TIMEOUT == 900
        finally:
            os.unlink(apk_path)

    def test_timeout_invalid_env(self):
        from redb.extractors.decompiler.DecompileAPK import DecompileAPK
        apk_path = _create_fake_apk_file()
        try:
            with patch.dict(os.environ, {"APK_DECOMPILE_TIMEOUT": "not_a_number"}):
                ext = DecompileAPK(apk_path, MagicMock())
                assert ext.APK_DECOMPILE_TIMEOUT == 600
        finally:
            os.unlink(apk_path)

    def test_calculate_md5(self):
        from redb.extractors.decompiler.DecompileAPK import DecompileAPK
        apk_path = _create_fake_apk_file()
        try:
            ext = DecompileAPK(apk_path, MagicMock())
            result = ext.calculate_md5("test_string")
            assert len(result) == 32
            assert result == hashlib.md5(b"test_string").hexdigest()
        finally:
            os.unlink(apk_path)

    def test_context_manager(self):
        from redb.extractors.decompiler.DecompileAPK import DecompileAPK
        apk_path = _create_fake_apk_file()
        try:
            with DecompileAPK(apk_path, MagicMock()) as ext:
                assert ext is not None
        finally:
            os.unlink(apk_path)

    def test_cleanup_run(self):
        from redb.extractors.decompiler.DecompileAPK import DecompileAPK
        apk_path = _create_fake_apk_file()
        try:
            ext = DecompileAPK(apk_path, MagicMock())
            ext.analyzer = MagicMock()
            ext.cleanup_run()
            assert ext.analyzer is None
        finally:
            os.unlink(apk_path)


# ============================================================================
# Export Data Tests
# ============================================================================

class TestPrepareExportData:
    """Tests for DecompileAPK.prepare_export_data() ClickHouse schemas."""

    def _make_extractor_with_results(self):
        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_method_hash": "d" * 64,
                    "decompiled_method": "public void foo() {}",
                    "decompiled_method_type": "USER",
                    "decompiled_has_string_encryption": False,
                    "decompiled_has_reflection_calls": False,
                    "decompiled_excessive_goto_count": False,
                }
            ],
            "decompiled_refs": [
                {
                    "decompiled_method_hash": "d" * 64,
                    "smali_method_hash": "e" * 64,
                    "decompiled_class_name": "com.example.Foo",
                    "decompiled_method_name": "foo",
                    "decompiled_method_signature": "()V",
                    "decompiled_method_prototype": "void foo()",
                    "functions_caller": ["bar"],
                    "functions_call": ["baz"],
                }
            ],
            "smali_content": [
                {
                    "smali_method_hash": "e" * 64,
                    "smali_method": "invoke-virtual {p0}, Lfoo;->bar()V\nreturn-void",
                    "smali_method_type": "USER",
                    "smali_instructions_count": 10,
                    "smali_register_count": 3,
                    "smali_has_string_encryption": False,
                    "smali_has_reflection_calls": False,
                    "smali_excessive_goto_count": False,
                    "smali_flattened_score": 0.0,
                    "smali_mba_score": 0.0,
                }
            ],
            "smali_refs": [
                {
                    "smali_method_hash": "e" * 64,
                    "decompiled_method_hash": "d" * 64,
                    "smali_class_name": "com.example.Foo",
                    "smali_method_name": "foo",
                    "smali_method_signature": "()V",
                    "ssdeep_smali": None,
                    "tlsh_smali": None,
                }
            ],
            "similarity_metrics": [
                {
                    "smali_method_hash": "e" * 64,
                    "cyclomatic_complexity": 2,
                    "ssdeep_smali": None,
                    "tlsh_smali": None,
                    "ssdeep_smali_normalized": None,
                    "tlsh_smali_normalized": None,
                    "minhash": [],
                }
            ],
            "cfg": [
                {
                    "smali_method_hash": "e" * 64,
                    "cfg_topology_hash": b'\x01' * 16,
                    "block_count": 3,
                    "edge_count": 3,
                    "cfg_instructions_count": 10,
                    "call_count": 1,
                    "cyclomatic_complexity": 2,
                    "loop_count": 0,
                    "max_depth": 2,
                    "max_fan_out": 2,
                    "md_index_topdown": 12345,
                    "md_index_bottomup": 67890,
                    "prime_product_smali": 999,
                    "cfg_feature_tlsh": None,
                    "wl_minhash": [0] * 128,
                    "bb_features": [[5, 1, 0, 1, 1, 0, 0, 2]] * 3,
                    "cfg_adjacency": [0x00000001, 0x00000002],
                }
            ],
            "strings": [
                {
                    "string": "https://evil.example.com/payload",
                    "string_encoding": "UTF8",
                    "string_offset": 0,
                    "string_length": 31,
                    "string_entropy": 3.95,
                }
            ],
            "analysis_errors": [
                {
                    "class_name": "com.example.Foo",
                    "method_name": "bar",
                    "error_location": "jadx",
                    "error_message": "timeout",
                    "error_type": "TimeoutError",
                }
            ],
        }
        return ext, apk_path

    def test_returns_none_when_no_results(self):
        from redb.extractors.decompiler.DecompileAPK import DecompileAPK
        apk_path = _create_fake_apk_file()
        try:
            ext = DecompileAPK(apk_path, MagicMock())
            assert ext.prepare_export_data("ClickHouseExporter") is None
        finally:
            os.unlink(apk_path)

    def test_multi_table_flag(self):
        ext, apk_path = self._make_extractor_with_results()
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            assert export["multi_table"] is True
        finally:
            os.unlink(apk_path)

    def test_all_table_keys_present(self):
        ext, apk_path = self._make_extractor_with_results()
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            assert "decompiled_content" in export
            assert "decompiled_refs" in export
            assert "smali_content" in export
            assert "smali_refs" in export
            assert "method_similarity_metrics" in export
            assert "strings_raw" in export
            assert "analysis_errors" in export
        finally:
            os.unlink(apk_path)

    def test_decompiled_content_schema(self):
        ext, apk_path = self._make_extractor_with_results()
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            dc = export["decompiled_content"]
            assert dc["table"] == "code_apk_decompiled_methods_content"
            assert len(dc["column_names"]) == 7
            assert len(dc["column_type_names"]) == 7
            assert "decompiled_method_hash" in dc["column_names"]
            assert "decompiled_method" in dc["column_names"]
            assert "analysis_date" in dc["column_names"]
            assert len(dc["data"]) == 1
            assert len(dc["data"][0]) == 7
        finally:
            os.unlink(apk_path)

    def test_decompiled_refs_schema(self):
        ext, apk_path = self._make_extractor_with_results()
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            dr = export["decompiled_refs"]
            assert dr["table"] == "code_apk_decompiled_methods_references"
            assert len(dr["column_names"]) == 10
            assert len(dr["column_type_names"]) == 10
            assert "sha256" in dr["column_names"]
            assert "sha1" not in dr["column_names"]
            assert "md5" not in dr["column_names"]
            assert "functions_caller" in dr["column_names"]
            assert "functions_call" in dr["column_names"]
        finally:
            os.unlink(apk_path)

    def test_smali_content_schema(self):
        ext, apk_path = self._make_extractor_with_results()
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            sc = export["smali_content"]
            assert sc["table"] == "code_apk_smali_methods_content"
            assert len(sc["column_names"]) == 11
            assert len(sc["column_type_names"]) == 11
            assert "smali_instructions_count" in sc["column_names"]
            assert "smali_register_count" in sc["column_names"]
            assert "smali_flattened_score" in sc["column_names"]
            assert "smali_mba_score" in sc["column_names"]
        finally:
            os.unlink(apk_path)

    def test_smali_refs_schema(self):
        ext, apk_path = self._make_extractor_with_results()
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            sr = export["smali_refs"]
            assert sr["table"] == "code_apk_smali_methods_references"
            assert len(sr["column_names"]) == 7
            assert len(sr["column_type_names"]) == 7
            assert "sha1" not in sr["column_names"]
            assert "md5" not in sr["column_names"]
            assert "ssdeep_smali" not in sr["column_names"]
            assert "tlsh_smali" not in sr["column_names"]
        finally:
            os.unlink(apk_path)

    def test_similarity_metrics_schema(self):
        ext, apk_path = self._make_extractor_with_results()
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            sm = export["method_similarity_metrics"]
            assert sm["table"] == "code_apk_method_similarity_metrics"
            assert len(sm["column_names"]) == 7
            assert "minhash" in sm["column_names"]
            assert "ssdeep_smali_normalized" in sm["column_names"]
            assert "tlsh_smali_normalized" in sm["column_names"]
            # cyclomatic_complexity moved to cfg table
            assert "cyclomatic_complexity" not in sm["column_names"]
            assert "block_count" not in sm["column_names"]
            assert "loop_count" not in sm["column_names"]
        finally:
            os.unlink(apk_path)

    def test_analysis_errors_schema(self):
        ext, apk_path = self._make_extractor_with_results()
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            ae = export["analysis_errors"]
            assert ae["table"] == "code_apk_analysis_errors"
            assert len(ae["column_names"]) == 9
            assert "error_hash" in ae["column_names"]
            assert "status" in ae["column_names"]
        finally:
            os.unlink(apk_path)

    def test_sha256_propagated_to_refs(self):
        ext, apk_path = self._make_extractor_with_results()
        try:
            export = ext.prepare_export_data("ClickHouseExporter")
            # Check that sha256 from analysis_results appears in ref rows
            dr_row = export["decompiled_refs"]["data"][0]
            assert dr_row[0] == "a" * 64  # sha256
            # sha1 and md5 no longer included in refs
            assert "sha1" not in export["decompiled_refs"]["column_names"]
            assert "md5" not in export["decompiled_refs"]["column_names"]
        finally:
            os.unlink(apk_path)

    def test_empty_tables_not_included(self):
        from redb.extractors.decompiler.DecompileAPK import DecompileAPK
        apk_path = _create_fake_apk_file()
        try:
            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": [],
                "cfg": [],
                "strings": [],
                "analysis_errors": [],
            }
            export = ext.prepare_export_data("ClickHouseExporter")
            assert export == {"multi_table": True}
        finally:
            os.unlink(apk_path)

    def test_non_clickhouse_exporter_returns_none(self):
        ext, apk_path = self._make_extractor_with_results()
        try:
            result = ext.prepare_export_data("ElasticsearchExporter")
            assert result is None
        finally:
            os.unlink(apk_path)


# ============================================================================
# Dataclass Tests
# ============================================================================

class TestAPKCodeAnalysisDataclasses:
    """Tests for the new APK code analysis dataclasses."""

    def test_decompiled_method_content(self):
        from redb.models.dataclasses import APKDecompiledMethodContent
        dc = APKDecompiledMethodContent(
            decompiled_method_hash="a" * 64,
            decompiled_method="public void foo() {}",
            decompiled_method_type="USER",
        )
        assert dc.decompiled_has_string_encryption is False
        assert dc.decompiled_has_reflection_calls is False
        assert dc.decompiled_excessive_goto_count is False

    def test_decompiled_method_content_populated(self):
        from redb.models.dataclasses import APKDecompiledMethodContent
        dc = APKDecompiledMethodContent(
            decompiled_method_hash="a" * 64,
            decompiled_method="public void foo() {}",
            decompiled_method_type="USER",
            decompiled_has_string_encryption=True,
            decompiled_has_reflection_calls=True,
            decompiled_excessive_goto_count=True,
        )
        assert dc.decompiled_has_string_encryption is True
        d = asdict(dc)
        assert d["decompiled_method_hash"] == "a" * 64

    def test_decompiled_method_reference(self):
        from redb.models.dataclasses import APKDecompiledMethodReference
        dr = APKDecompiledMethodReference(
            sha256="a" * 64,
            sha1="b" * 40,
            md5="c" * 32,
            decompiled_method_hash="d" * 64,
        )
        assert dr.functions_caller == []
        assert dr.functions_call == []
        assert dr.smali_method_hash is None

    def test_smali_method_content(self):
        from redb.models.dataclasses import APKSmaliMethodContent
        sc = APKSmaliMethodContent(
            smali_method_hash="e" * 64,
            smali_method="invoke-virtual {p0}, Lfoo;->bar()V",
            smali_method_type="USER",
            smali_instructions_count=5,
            smali_register_count=3,
        )
        assert sc.smali_instructions_count == 5
        assert sc.smali_register_count == 3

    def test_smali_method_reference(self):
        from redb.models.dataclasses import APKSmaliMethodReference
        sr = APKSmaliMethodReference(
            sha256="a" * 64,
            sha1="b" * 40,
            md5="c" * 32,
            smali_method_hash="e" * 64,
        )
        assert sr.decompiled_method_hash is None
        assert sr.ssdeep_smali is None
        assert sr.tlsh_smali is None

    def test_method_similarity_metrics(self):
        from redb.models.dataclasses import APKMethodSimilarityMetrics
        ms = APKMethodSimilarityMetrics(smali_method_hash="e" * 64)
        assert ms.cyclomatic_complexity is None
        assert ms.ssdeep_smali_normalized is None
        assert ms.tlsh_smali_normalized is None
        assert ms.minhash == []

    def test_code_analysis_error(self):
        from redb.models.dataclasses import APKCodeAnalysisError
        err = APKCodeAnalysisError(
            sha256="a" * 64,
            error_location="jadx",
            error_message="timeout",
        )
        assert err.class_name is None
        assert err.method_name is None
        assert err.error_type is None


# ============================================================================
# Tag Enum Tests
# ============================================================================

class TestAPKDecompiledTag:
    """Tests for the APK_DECOMPILED tag enum."""

    def test_tag_exists(self):
        from redb.extractors.enum import Tag
        assert hasattr(Tag, "APK_DECOMPILED")

    def test_tag_value(self):
        from redb.extractors.enum import Tag
        assert Tag.APK_DECOMPILED.value == "apk_decompiled"


# ============================================================================
# Worker Integration Tests
# ============================================================================

class TestAPKWorkerDecompileIntegration:
    """Tests that DecompileAPK is registered in workers.py."""

    def test_module_registered(self):
        """Verify DecompileAPK is discoverable via the extractor registry."""
        from redb.extractor_registry import get_extractor_class
        cls = get_extractor_class("DecompileAPK")
        assert cls is not None, "DecompileAPK not found in extractor registry"
        assert cls.__name__ == "DecompileAPK"

    def test_worker_apk_dispatch_includes_decompile(self):
        import inspect
        import redb.workers as workers
        source = inspect.getsource(workers.process_binary_file)
        assert "DecompileAPK" in source