Ignacio Lacalle

27 papers B 1C 2Misc 3Journal 8Unranked 13
YearRankTypeTitle / Venue / Authors
2026 J jnl
CoRR
Mohammad Farhoudi, Hamidreza Mazandarani, Masoud Shokrnezhad, Tarik Taleb, Ignacio Lacalle
2025 conf
MECC@EuroSys
Rafael Vaño, Ignacio Lacalle, Carlos Enrique Palau
2025 conf
BDA (Astronomy, Science, and Engineering)
Katarzyna Wasielewska-Michniewska, Przemyslaw Holda, Marcin Paprzycki, Maria Ganzha, Ignacio Lacalle, Jorge Jiménez García
2025 Misc conf
CSR
Salvador Cuñnat Neguerole, Ioannis Makropodis, Lucía Cabanillas Rodríguez, Christos Xenakis, Ioannis Chouchoulis, Carlos Enrique Palau, Ignacio Lacalle
2024 J jnl
Future Gener. Comput. Syst.
Salvador Cuñat Negueroles, Raúl Reinosa Simón, Matilde Julián, Andreu Belsa, Ignacio Lacalle, Raúl S.-Julián, Carlos Enrique Palau
2024 conf
CAMAD
Ignacio Lacalle, Salvador Cuñat, Aristeidis Farao, Christos Xenakis, Dionysis Xenakis, Carlos Enrique Palau
2024 Misc conf
CSR
Raúl Reinosa Simón, Clara I. Valero, José A. Martínez Cadenas, Elisa R. Heymann, Ignacio Lacalle, Barton P. Miller, Carlos Enrique Palau
2024 B conf
ARES
Salvador Cuñat, Raúl Reinosa Simón, Ignacio Lacalle, Carlos Enrique Palau
2024 J jnl
CoRR
Piotr Sowinski, Ignacio Lacalle, Rafael Vaño, Carlos Enrique Palau, Maria Ganzha, Marcin Paprzycki
2024 conf
BDA (Astronomy, Science, and Engineering)
Piotr Sowinski, Ignacio Lacalle, Rafael Vaño, Carlos Enrique Palau, Maria Ganzha, Marcin Paprzycki
2023 conf
WF-IoT
Ignacio Lacalle, Salvador Cuñat, Andreu Belsa, Rafael Vaño, Raúl S.-Julián, Philippe Buschmann, José Fontalvo-Hernández, Korbinian Pfab, Renzo Bazan, Florian Gramß, Katarzyna Wasielewska-Michniewska, Carlos Enrique Palau
2023 conf
CloudNet
Piotr Sowinski, Ignacio Lacalle, Rafael Vaño, Carlos Enrique Palau
2023 J jnl
CoRR
Piotr Sowinski, Ignacio Lacalle, Rafael Vaño, Carlos Enrique Palau
2023 J jnl
Sensors
Rafael Vaño, Ignacio Lacalle, Piotr Sowinski, Raúl S.-Julián, Carlos Enrique Palau
2023 conf
WF-IoT
Alejandro Fornes-Leal, Francisco Mahedero Biot, Rafael Vaño, Raúl Reinosa Simón, Pawel Szmeja, Ignacio Lacalle, Carlos Enrique Palau
2023 J jnl
Sensors
Raúl S.-Julián, Ignacio Lacalle, Rafael Vaño, Fernando Boronat, Carlos Enrique Palau
2022 C conf
SoMeT
Alejandro Fornés-Leal, Ignacio Lacalle, Carlos Enrique Palau, Pawel Szmeja, Maria Ganzha, Marcin Paprzycki, Eduardo Garro, Francisco Blanquer
2022 conf
GIOTS
Andreu Belsa Pellicer, Matilde Julián Segui, Achilleas Marinakis, Anastasios Nikolakopoulos, Vrettos Moulos, Héctor Iturria, José Antonio Clemente, Xhulja Shahini, Tristan Kley, Andreas Metzger, Miguel Bravo, Paolo Calciati, Christos-Antonios Gizelis, Filippos Nikolopoulos-Gkamatsis, Konstantinos Nestorakis, Ignacio Lacalle, Carlos Enrique Palau, Santiago Cáceres Elvira
2022 C conf
SoMeT
Marek Bolanowski, Kamil Zak, Andrzej Paszkiewicz, Maria Ganzha, Marcin Paprzycki, Piotr Sowinski, Ignacio Lacalle, Carlos Enrique Palau
2022 J jnl
CoRR
Marek Bolanowski, Kamil Zak, Andrzej Paszkiewicz, Maria Ganzha, Marcin Paprzycki, Piotr Sowinski, Ignacio Lacalle, Carlos Enrique Palau
2021 Misc conf
IDC
Andreu Belsa, Rafael Vaño, Ignacio Lacalle, Matilde Julián, Fernando Boronat, Carlos Enrique Palau
2021 conf
MeditCom
Ignacio Lacalle, Rafael Vaño, Carlos Enrique Palau, Teodora Milosevic, Stjepan Pilicic, Matija Siroka, Eirina Tserga
2021 conf
WF-IoT
Rafael Vaño, Ignacio Lacalle, Benjamín Molina, Carlos Enrique Palau
2020 J jnl
Sensors
Ignacio Lacalle, Andreu Belsa, Rafael Vaño, Carlos Enrique Palau
2019 conf
WF-IoT
David Sarabia-Jacome, Ignacio Lacalle, Carlos Enrique Palau, Manuel Esteve
2019 conf
WF-IoT
David Sarabia-Jácome, Ignacio Lacalle, Carlos Enrique Palau, Manuel Esteve
2019 conf
IDCS
Ignacio Lacalle, Miguel Ángel Llorente, Carlos Enrique Palau
tests/unit/test_apk_apktool_wrapper.py
← Index tests/unit/test_apk_apktool_wrapper.py python
"""
Unit tests for apktool wrapper subprocess management and smali directory detection.

All subprocess calls are mocked — no apktool/Java installation required.
"""
import os
import tempfile

import pytest
from unittest.mock import MagicMock, patch

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


class TestApktoolDisassembler:
    """Tests for ApktoolDisassembler subprocess wrapper."""

    @patch.dict(os.environ, {}, clear=False)
    def test_init_defaults(self):
        os.environ.pop("APKTOOL_PATH", None)
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        a = ApktoolDisassembler()
        assert a.apktool_path == "apktool"
        assert a.timeout == 120

    def test_init_custom(self):
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        a = ApktoolDisassembler(apktool_path="/opt/apktool", timeout=120)
        assert a.apktool_path == "/opt/apktool"
        assert a.timeout == 120

    def test_init_from_env(self):
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        with patch.dict(os.environ, {"APKTOOL_PATH": "/usr/bin/apktool", "APKTOOL_TIMEOUT": "90"}):
            a = ApktoolDisassembler()
            assert a.apktool_path == "/usr/bin/apktool"
            assert a.timeout == 90

    @patch("subprocess.Popen")
    def test_disassemble_success(self, mock_popen):
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        mock_proc = MagicMock()
        mock_proc.communicate.return_value = ("output", "")
        mock_proc.returncode = 0
        mock_popen.return_value = mock_proc

        a = ApktoolDisassembler()
        result = a.disassemble("/test.apk", "/output")
        assert result is True

    @patch("subprocess.Popen")
    def test_disassemble_failure(self, mock_popen):
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        mock_proc = MagicMock()
        mock_proc.communicate.return_value = ("", "error")
        mock_proc.returncode = 1
        mock_popen.return_value = mock_proc

        a = ApktoolDisassembler(log=MagicMock())
        result = a.disassemble("/test.apk", "/output")
        assert result is False

    @patch("subprocess.Popen")
    def test_disassemble_timeout(self, mock_popen):
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        import subprocess
        mock_proc = MagicMock()
        mock_proc.communicate.side_effect = subprocess.TimeoutExpired(cmd="apktool", timeout=10)
        mock_proc.pid = 12345
        mock_popen.return_value = mock_proc

        with patch("os.getpgid", return_value=12345), \
             patch("os.killpg"):
            a = ApktoolDisassembler(timeout=10, log=MagicMock())
            result = a.disassemble("/test.apk", "/output")
            assert result is False

    @patch("subprocess.Popen", side_effect=FileNotFoundError)
    def test_disassemble_not_found(self, mock_popen):
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        a = ApktoolDisassembler(log=MagicMock())
        result = a.disassemble("/test.apk", "/output")
        assert result is False

    @patch("subprocess.Popen")
    def test_disassemble_command_args(self, mock_popen):
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        mock_proc = MagicMock()
        mock_proc.communicate.return_value = ("", "")
        mock_proc.returncode = 0
        mock_popen.return_value = mock_proc

        a = ApktoolDisassembler(apktool_path="/opt/apktool")
        a.disassemble("/test.apk", "/output")

        cmd = mock_popen.call_args[0][0]
        assert cmd[0] == "/opt/apktool"
        assert "d" in cmd
        assert "--no-res" in cmd
        assert "--force" in cmd
        assert "/test.apk" in cmd

    def test_get_smali_directories_single_dex(self):
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        with tempfile.TemporaryDirectory() as tmpdir:
            os.makedirs(os.path.join(tmpdir, "smali"))
            a = ApktoolDisassembler()
            dirs = a.get_smali_directories(tmpdir)
            assert len(dirs) == 1
            assert dirs[0].endswith("smali")

    def test_get_smali_directories_multi_dex(self):
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        with tempfile.TemporaryDirectory() as tmpdir:
            os.makedirs(os.path.join(tmpdir, "smali"))
            os.makedirs(os.path.join(tmpdir, "smali_classes2"))
            os.makedirs(os.path.join(tmpdir, "smali_classes3"))
            # Should not be included
            os.makedirs(os.path.join(tmpdir, "res"))
            os.makedirs(os.path.join(tmpdir, "original"))

            a = ApktoolDisassembler()
            dirs = a.get_smali_directories(tmpdir)
            assert len(dirs) == 3

    def test_get_smali_directories_empty(self):
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        with tempfile.TemporaryDirectory() as tmpdir:
            a = ApktoolDisassembler()
            dirs = a.get_smali_directories(tmpdir)
            assert dirs == []

    def test_get_smali_directories_nonexistent(self):
        from redb.extractors.decompiler.apk.apktool_wrapper import ApktoolDisassembler
        a = ApktoolDisassembler()
        dirs = a.get_smali_directories("/nonexistent/path")
        assert dirs == []